Win32 apply: Delay setting FILE_ATTRIBUTE_READONLY
authorEric Biggers <ebiggers3@gmail.com>
Sun, 18 Aug 2013 00:50:24 +0000 (19:50 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 18 Aug 2013 00:50:24 +0000 (19:50 -0500)
include/wimlib/apply.h
src/extract.c
src/ntfs-3g_apply.c
src/win32_apply.c

index 1a2647d..31cda98 100644 (file)
@@ -89,7 +89,8 @@ struct apply_operations {
        /* OPTIONAL:  Set file attributes.  Calling code calls this if non-NULL.
         */
        int (*set_file_attributes)
-               (const tchar *path, u32 attributes, struct apply_ctx *ctx);
+               (const tchar *path, u32 attributes, struct apply_ctx *ctx,
+                unsigned pass);
 
        /* OPTIONAL:  Set reparse data.  In start_extract(), set
         * ctx->supported_features.reparse_data if supported.  */
@@ -167,6 +168,10 @@ struct apply_operations {
         * then be passed to callbacks taking a 'file_spec_t', rather than the
         * path.  */
        unsigned uses_cookies : 1;
+
+       /* OPTIONAL:  Set to 1 if set_file_attributes() needs to be called a
+        * second time towards the end of the extraction.  */
+       unsigned requires_final_set_attributes_pass : 1;
 };
 
 struct wim_features {
index 7ca0122..c9a1dca 100644 (file)
@@ -642,7 +642,7 @@ error:
  * extraction mode.  */
 static int
 extract_file_attributes(const tchar *path, struct apply_ctx *ctx,
-                       struct wim_dentry *dentry)
+                       struct wim_dentry *dentry, unsigned pass)
 {
        int ret;
 
@@ -664,7 +664,7 @@ extract_file_attributes(const tchar *path, struct apply_ctx *ctx,
                if (attributes == 0)
                        attributes = FILE_ATTRIBUTE_NORMAL;
 
-               ret = ctx->ops->set_file_attributes(path, attributes, ctx);
+               ret = ctx->ops->set_file_attributes(path, attributes, ctx, pass);
                if (ret) {
                        ERROR_WITH_ERRNO("Failed to set attributes on "
                                         "\"%"TS"\"", path);
@@ -1053,7 +1053,7 @@ do_dentry_extract_skeleton(tchar path[], struct wim_dentry *dentry,
        }
 
        /* Set file attributes (if supported).  */
-       ret = extract_file_attributes(path, ctx, dentry);
+       ret = extract_file_attributes(path, ctx, dentry, 0);
        if (ret)
                return ret;
 
@@ -1472,6 +1472,13 @@ dentry_extract_final(struct wim_dentry *dentry, void *_ctx)
        if (ret)
                return ret;
 
+       if (ctx->ops->requires_final_set_attributes_pass) {
+               /* Set file attributes (if supported).  */
+               ret = extract_file_attributes(path, ctx, dentry, 1);
+               if (ret)
+                       return ret;
+       }
+
        return extract_timestamps(path, ctx, dentry);
 }
 
index 2b0eff9..a1c6775 100644 (file)
@@ -299,7 +299,7 @@ ntfs_3g_extract_named_stream(file_spec_t file, const utf16lechar *stream_name,
 
 static int
 ntfs_3g_set_file_attributes(const char *path, u32 attributes,
-                           struct apply_ctx *ctx)
+                           struct apply_ctx *ctx, unsigned pass)
 {
        ntfs_inode *ni;
        int ret = 0;
index d08ea5d..ac7e375 100644 (file)
@@ -332,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 |
@@ -342,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))
@@ -560,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__ */