]> wimlib.net Git - wimlib/blobdiff - src/extract.c
Win32 apply: Delay setting FILE_ATTRIBUTE_READONLY
[wimlib] / src / extract.c
index 9c460e968d43896176bd6d1f48bff07e290a527a..c9a1dca0275b4b68e6c89f4013235fdaafe1dfdb 100644 (file)
@@ -642,16 +642,29 @@ 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;
 
-       if (ctx->ops->set_file_attributes) {
-               if (dentry == ctx->extract_root && ctx->root_dentry_is_special)
-                       return 0;
-               ret = ctx->ops->set_file_attributes(path,
-                                                   dentry->d_inode->i_attributes,
-                                                   ctx);
+       if (ctx->ops->set_file_attributes &&
+           !(dentry == ctx->extract_root && ctx->root_dentry_is_special)) {
+               u32 attributes = dentry->d_inode->i_attributes;
+
+               /* Clear unsupported attributes.  */
+               attributes &= ctx->supported_attributes_mask;
+
+               if ((attributes & FILE_ATTRIBUTE_DIRECTORY &&
+                    !ctx->supported_features.encrypted_directories) ||
+                   (!(attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+                    !ctx->supported_features.encrypted_files))
+               {
+                       attributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
+               }
+
+               if (attributes == 0)
+                       attributes = FILE_ATTRIBUTE_NORMAL;
+
+               ret = ctx->ops->set_file_attributes(path, attributes, ctx, pass);
                if (ret) {
                        ERROR_WITH_ERRNO("Failed to set attributes on "
                                         "\"%"TS"\"", path);
@@ -804,12 +817,15 @@ dentry_is_supported(struct wim_dentry *dentry,
        struct wim_inode *inode = dentry->d_inode;
 
        if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-               if (supported_features->reparse_points)
-                       return true;
-               if (supported_features->symlink_reparse_points &&
-                   inode_is_symlink(inode))
-                       return true;
-               return false;
+               return supported_features->reparse_points ||
+                       (inode_is_symlink(inode) &&
+                        supported_features->symlink_reparse_points);
+       }
+       if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
+               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+                       return supported_features->encrypted_directories != 0;
+               else
+                       return supported_features->encrypted_files != 0;
        }
        return true;
 }
@@ -882,6 +898,11 @@ static unsigned
 get_num_path_components(const tchar *path, tchar path_separator)
 {
        unsigned num_components = 0;
+#ifdef __WIN32__
+       /* Ignore drive letter.  */
+       if (path[0] != L'\0' && path[1] == L':')
+               path += 2;
+#endif
 
        while (*path) {
                while (*path == path_separator)
@@ -924,7 +945,11 @@ extract_multiimage_symlink(const tchar *oldpath, const tchar *newpath,
                num_target_path_components--;
        }
 
-       p_old = oldpath;
+       p_old = oldpath + ctx->ops->path_prefix_nchars;
+#ifdef __WIN32__
+       if (p_old[0] != L'\0' && p_old[1] == ':')
+               p_old += 2;
+#endif
        while (*p_old == ctx->ops->path_separator)
                p_old++;
        while (--num_target_path_components) {
@@ -1028,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;
 
@@ -1447,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);
 }
 
@@ -1717,8 +1749,12 @@ dentry_tally_features(struct wim_dentry *dentry, void *_features)
                features->system_files++;
        if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED)
                features->compressed_files++;
-       if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
-               features->encrypted_files++;
+       if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
+               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+                       features->encrypted_directories++;
+               else
+                       features->encrypted_files++;
+       }
        if (inode->i_attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
                features->not_context_indexed_files++;
        if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE)
@@ -1760,6 +1796,35 @@ dentry_tree_get_features(struct wim_dentry *root, struct wim_features *features)
        for_dentry_in_tree(root, dentry_clear_inode_visited, NULL);
 }
 
+static u32
+compute_supported_attributes_mask(const struct wim_features *supported_features)
+{
+       u32 mask = ~(u32)0;
+
+       if (!supported_features->archive_files)
+               mask &= ~FILE_ATTRIBUTE_ARCHIVE;
+
+       if (!supported_features->hidden_files)
+               mask &= ~FILE_ATTRIBUTE_HIDDEN;
+
+       if (!supported_features->system_files)
+               mask &= ~FILE_ATTRIBUTE_SYSTEM;
+
+       if (!supported_features->not_context_indexed_files)
+               mask &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+
+       if (!supported_features->compressed_files)
+               mask &= ~FILE_ATTRIBUTE_COMPRESSED;
+
+       if (!supported_features->sparse_files)
+               mask &= ~FILE_ATTRIBUTE_SPARSE_FILE;
+
+       if (!supported_features->reparse_points)
+               mask &= ~FILE_ATTRIBUTE_REPARSE_POINT;
+
+       return mask;
+}
+
 static int
 do_feature_check(const struct wim_features *required_features,
                 const struct wim_features *supported_features,
@@ -1768,10 +1833,10 @@ do_feature_check(const struct wim_features *required_features,
                 const tchar *wim_source_path)
 {
        const tchar *loc;
-       const tchar *mode = "this extraction mode";
+       const tchar *mode = T("this extraction mode");
 
        if (wim_source_path[0] == '\0')
-               loc = "the WIM image";
+               loc = T("the WIM image");
        else
                loc = wim_source_path;
 
@@ -1818,10 +1883,20 @@ do_feature_check(const struct wim_features *required_features,
                WARNING(
           "%lu files in %"TS" are marked as being encrypted,\n"
 "           but encryption is not supported in %"TS".  These files\n"
-"           will be extracted as raw encrypted data instead.",
+"           will not be extracted.",
                        required_features->encrypted_files, loc, mode);
        }
 
+       if (required_features->encrypted_directories &&
+           !supported_features->encrypted_directories)
+       {
+               WARNING(
+          "%lu directories in %"TS" are marked as being encrypted,\n"
+"           but encryption is not supported in %"TS".\n"
+"           These directories will be extracted as unencrypted.",
+                       required_features->encrypted_directories, loc, mode);
+       }
+
        if (required_features->not_context_indexed_files &&
            !supported_features->not_context_indexed_files)
        {
@@ -1945,6 +2020,15 @@ do_feature_check(const struct wim_features *required_features,
                return WIMLIB_ERR_UNSUPPORTED;
        }
 
+       if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS) &&
+           required_features->symlink_reparse_points &&
+           !(supported_features->symlink_reparse_points ||
+             supported_features->reparse_points))
+       {
+               ERROR("Extracting symbolic links is not supported in %"TS, mode);
+               return WIMLIB_ERR_UNSUPPORTED;
+       }
+
        if ((extract_flags & WIMLIB_EXTRACT_FLAG_SYMLINK) &&
            !supported_features->symlink_reparse_points)
        {
@@ -2068,6 +2152,9 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
        if (ret)
                goto out_finish_or_abort_extract;
 
+       ctx.supported_attributes_mask =
+               compute_supported_attributes_mask(&ctx.supported_features);
+
        /* Figure out whether the root dentry is being extracted to the root of
         * a volume and therefore needs to be treated "specially", for example
         * not being explicitly created and not having attributes set.  */