ntfs_3g_apply.c: work around EOPNOTSUPP when setting short name of reparse point...
authorEric Biggers <ebiggers3@gmail.com>
Sun, 1 Nov 2015 00:00:39 +0000 (19:00 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 7 Nov 2015 20:52:02 +0000 (14:52 -0600)
src/ntfs-3g_apply.c

index d0f3bb6..9f06bbe 100644 (file)
@@ -331,6 +331,19 @@ ntfs_3g_restore_reparse_point(ntfs_inode *ni, const struct wim_inode *inode,
        return 0;
 }
 
+static bool
+ntfs_3g_has_empty_attributes(const struct wim_inode *inode)
+{
+       for (unsigned i = 0; i < inode->i_num_streams; i++) {
+               const struct wim_inode_stream *strm = &inode->i_streams[i];
+
+               if (stream_blob_resolved(strm) == NULL &&
+                   (strm->stream_type == STREAM_TYPE_REPARSE_POINT ||
+                    stream_is_named_data_stream(strm)))
+                       return true;
+       }
+       return false;
+}
 
 /*
  * Create empty attributes (named data streams and potentially a reparse point)
@@ -338,13 +351,14 @@ ntfs_3g_restore_reparse_point(ntfs_inode *ni, const struct wim_inode *inode,
  *
  * Since these won't have blob descriptors, they won't show up in the call to
  * extract_blob_list().  Hence the need for the special case.
+ *
+ * Keep this in sync with ntfs_3g_has_empty_attributes()!
  */
 static int
 ntfs_3g_create_empty_attributes(ntfs_inode *ni,
                                const struct wim_inode *inode,
                                struct ntfs_3g_apply_ctx *ctx)
 {
-
        for (unsigned i = 0; i < inode->i_num_streams; i++) {
 
                const struct wim_inode_stream *strm = &inode->i_streams[i];
@@ -480,8 +494,6 @@ ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir,
                ret = report_file_created(&ctx->common);
                if (!ret)
                        ret = ntfs_3g_set_metadata(ni, child->d_inode, ctx);
-               if (!ret)
-                       ret = ntfs_3g_create_empty_attributes(ni, child->d_inode, ctx);
                if (!ret)
                        ret = ntfs_3g_create_dirs_recursive(ni, child, ctx);
 
@@ -518,8 +530,6 @@ ntfs_3g_create_directories(struct wim_dentry *root,
        root->d_inode->i_mft_no = FILE_root;
 
        ret = ntfs_3g_set_metadata(root_ni, root->d_inode, ctx);
-       if (!ret)
-               ret = ntfs_3g_create_empty_attributes(root_ni, root->d_inode, ctx);
        if (!ret)
                ret = ntfs_3g_create_dirs_recursive(root_ni, root, ctx);
 
@@ -530,18 +540,44 @@ ntfs_3g_create_directories(struct wim_dentry *root,
        if (ret)
                return ret;
 
-       /* Set the DOS name of any directory that has one.  */
+       /* Set the DOS name of any directory that has one.  In addition, create
+        * empty attributes for directories that have them.  Note that creating
+        * an empty reparse point attribute must happen *after* setting the
+        * DOS name in order to work around a case where
+        * ntfs_set_ntfs_dos_name() fails with EOPNOTSUPP.  */
        list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
-               if (!(dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
-                       continue;
-               if (!dentry_has_short_name(dentry))
+               const struct wim_inode *inode = dentry->d_inode;
+
+               if (!(inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
                        continue;
-               ret = ntfs_3g_restore_dos_name(NULL, NULL, dentry, ctx->vol);
-               if (ret)
-                       return ret;
-               ret = report_file_created(&ctx->common);
-               if (ret)
-                       return ret;
+               if (dentry_has_short_name(dentry)) {
+                       ret = ntfs_3g_restore_dos_name(NULL, NULL, dentry,
+                                                      ctx->vol);
+                       if (ret)
+                               return ret;
+                       ret = report_file_created(&ctx->common);
+                       if (ret)
+                               return ret;
+               }
+               if (ntfs_3g_has_empty_attributes(inode)) {
+                       ntfs_inode *ni;
+
+                       ret = WIMLIB_ERR_NTFS_3G;
+                       ni = ntfs_inode_open(ctx->vol, inode->i_mft_no);
+                       if (ni) {
+                               ret = ntfs_3g_create_empty_attributes(ni, inode,
+                                                                     ctx);
+                               if (ntfs_inode_close(ni) && !ret)
+                                       ret = WIMLIB_ERR_NTFS_3G;
+                       }
+                       if (ret) {
+                               ERROR_WITH_ERRNO("Failed to create empty "
+                                                "attributes of directory "
+                                                "\"%s\" in NTFS volume",
+                                                dentry_full_path(dentry));
+                               return ret;
+                       }
+               }
        }
        return 0;
 }