]> wimlib.net Git - wimlib/blobdiff - src/win32_apply.c
Win32 apply: Delay setting FILE_ATTRIBUTE_READONLY
[wimlib] / src / win32_apply.c
index bce897a46344860ed42ce0b82b6ef086140b81c9..ac7e37537e5456b0f9a3125df8d27b79c88ca813 100644 (file)
@@ -44,23 +44,45 @@ win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
        if (ret)
                return ret;
 
-       ctx->supported_features.archive_files             = 1;
-       ctx->supported_features.hidden_files              = 1;
-       ctx->supported_features.system_files              = 1;
-       ctx->supported_features.compressed_files          = !!(vol_flags & FILE_FILE_COMPRESSION);
-       ctx->supported_features.encrypted_files           = !!(vol_flags & FILE_SUPPORTS_ENCRYPTION);
+       ctx->supported_features.archive_files = 1;
+       ctx->supported_features.hidden_files = 1;
+       ctx->supported_features.system_files = 1;
+
+       if (vol_flags & FILE_FILE_COMPRESSION)
+               ctx->supported_features.compressed_files = 1;
+
+       if (vol_flags & FILE_SUPPORTS_ENCRYPTION) {
+               ctx->supported_features.encrypted_files = 1;
+               ctx->supported_features.encrypted_directories = 1;
+       }
+
        ctx->supported_features.not_context_indexed_files = 1;
-       ctx->supported_features.sparse_files              = !!(vol_flags & FILE_SUPPORTS_SPARSE_FILES);
-       ctx->supported_features.named_data_streams        = !!(vol_flags & FILE_NAMED_STREAMS);
-       ctx->supported_features.hard_links                = !!(vol_flags & FILE_SUPPORTS_HARD_LINKS);
-       ctx->supported_features.reparse_points            = !!(vol_flags & FILE_SUPPORTS_REPARSE_POINTS);
-       ctx->supported_features.security_descriptors      = !!(vol_flags & FILE_PERSISTENT_ACLS);
-       ctx->supported_features.short_names               = !!supports_SetFileShortName;
+
+       if (vol_flags & FILE_SUPPORTS_SPARSE_FILES)
+               ctx->supported_features.sparse_files = 1;
+
+       if (vol_flags & FILE_NAMED_STREAMS)
+               ctx->supported_features.named_data_streams = 1;
+
+       if (vol_flags & FILE_SUPPORTS_HARD_LINKS)
+               ctx->supported_features.hard_links = 1;
+
+       if (vol_flags & FILE_SUPPORTS_REPARSE_POINTS) {
+               ctx->supported_features.reparse_points = 1;
+               if (win32func_CreateSymbolicLinkW)
+                       ctx->supported_features.symlink_reparse_points = 1;
+       }
+
+       if (vol_flags & FILE_PERSISTENT_ACLS)
+               ctx->supported_features.security_descriptors = 1;
+
+       if (supports_SetFileShortName)
+               ctx->supported_features.short_names = 1;
        return 0;
 }
 
 static int
-win32_create_file(const wchar_t *path, struct apply_ctx *ctx)
+win32_create_file(const wchar_t *path, struct apply_ctx *ctx, u64 *cookie_ret)
 {
        HANDLE h;
 
@@ -77,7 +99,8 @@ error:
 }
 
 static int
-win32_create_directory(const wchar_t *path, struct apply_ctx *ctx)
+win32_create_directory(const wchar_t *path, struct apply_ctx *ctx,
+                      u64 *cookie_ret)
 {
        if (!CreateDirectory(path, NULL))
                if (GetLastError() != ERROR_ALREADY_EXISTS)
@@ -93,8 +116,33 @@ static int
 win32_create_hardlink(const wchar_t *oldpath, const wchar_t *newpath,
                      struct apply_ctx *ctx)
 {
-       if (!CreateHardLink(newpath, oldpath, NULL))
-               goto error;
+       if (!CreateHardLink(newpath, oldpath, NULL)) {
+               if (GetLastError() != ERROR_ALREADY_EXISTS)
+                       goto error;
+               if (!DeleteFile(newpath))
+                       goto error;
+               if (!CreateHardLink(newpath, oldpath, NULL))
+                       goto error;
+       }
+       return 0;
+
+error:
+       set_errno_from_GetLastError();
+       return WIMLIB_ERR_LINK;
+}
+
+static int
+win32_create_symlink(const wchar_t *oldpath, const wchar_t *newpath,
+                    struct apply_ctx *ctx)
+{
+       if (!(*win32func_CreateSymbolicLinkW)(newpath, oldpath, 0)) {
+               if (GetLastError() != ERROR_ALREADY_EXISTS)
+                       goto error;
+               if (!DeleteFile(newpath))
+                       goto error;
+               if (!(*win32func_CreateSymbolicLinkW)(newpath, oldpath, 0))
+                       goto error;
+       }
        return 0;
 
 error:
@@ -162,19 +210,19 @@ error:
 }
 
 static int
-win32_extract_unnamed_stream(const wchar_t *path,
+win32_extract_unnamed_stream(file_spec_t file,
                             struct wim_lookup_table_entry *lte,
                             struct apply_ctx *ctx)
 {
-       return win32_extract_stream(path, NULL, 0, lte, ctx);
+       return win32_extract_stream(file.path, NULL, 0, lte, ctx);
 }
 
 static int
-win32_extract_named_stream(const wchar_t *path, const wchar_t *stream_name,
+win32_extract_named_stream(file_spec_t file, const wchar_t *stream_name,
                           size_t stream_name_nchars,
                           struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
 {
-       return win32_extract_stream(path, stream_name,
+       return win32_extract_stream(file.path, stream_name,
                                    stream_name_nchars, lte, ctx);
 }
 
@@ -202,10 +250,11 @@ win32_encrypted_import_cb(unsigned char *data, void *_import_ctx,
 }
 
 static int
-win32_extract_encrypted_stream(const wchar_t *path,
+win32_extract_encrypted_stream(file_spec_t file,
                               struct wim_lookup_table_entry *lte,
                               struct apply_ctx *ctx)
 {
+       const tchar *path = file.path;
        void *file_ctx;
        DWORD err;
        int ret;
@@ -283,7 +332,7 @@ error:
 
 static int
 win32_set_file_attributes(const wchar_t *path, u32 attributes,
-                         struct apply_ctx *ctx)
+                         struct apply_ctx *ctx, unsigned pass)
 {
        u32 special_attributes =
                FILE_ATTRIBUTE_REPARSE_POINT |
@@ -293,9 +342,19 @@ win32_set_file_attributes(const wchar_t *path, u32 attributes,
                FILE_ATTRIBUTE_ENCRYPTED;
        u32 actual_attributes;
 
+       /* On FAT filesystems we can't set FILE_ATTRIBUTE_READONLY on the
+        * initial pass (when files are created, but data not extracted);
+        * otherwise the system will refuse access to the file even if the
+        * process has SeRestorePrivilege.  */
+       if (pass == 0)
+               attributes &= ~FILE_ATTRIBUTE_READONLY;
+
        if (!SetFileAttributes(path, attributes & ~special_attributes))
                goto error;
 
+       if (pass != 0)
+               return 0;
+
        if (attributes & (FILE_ATTRIBUTE_SPARSE_FILE |
                          FILE_ATTRIBUTE_ENCRYPTED |
                          FILE_ATTRIBUTE_COMPRESSED))
@@ -342,7 +401,6 @@ win32_set_file_attributes(const wchar_t *path, u32 attributes,
                        goto error;
        }
 
-success:
        return 0;
 
 error:
@@ -494,6 +552,7 @@ const struct apply_operations win32_apply_ops = {
        .create_file              = win32_create_file,
        .create_directory         = win32_create_directory,
        .create_hardlink          = win32_create_hardlink,
+       .create_symlink           = win32_create_symlink,
        .extract_unnamed_stream   = win32_extract_unnamed_stream,
        .extract_named_stream     = win32_extract_named_stream,
        .extract_encrypted_stream = win32_extract_encrypted_stream,
@@ -511,6 +570,7 @@ const struct apply_operations win32_apply_ops = {
        .requires_realtarget_in_paths = 1,
        .realpath_works_on_nonexisting_files = 1,
        .root_directory_is_special = 1,
+       .requires_final_set_attributes_pass = 1,
 };
 
 #endif /* __WIN32__ */