return 0;
}
+/* This is a wrapper around do_dentry_extract_skeleton() that handles building
+ * the path, doing short name reordering. This is also idempotent; dentries
+ * already processed have skeleton_extracted set and no action is taken. See
+ * apply_operations.requires_short_name_reordering for more details about short
+ * name reordering. */
static int
dentry_extract_skeleton(struct wim_dentry *dentry, void *_ctx)
{
struct wim_dentry *other_dentry;
int ret;
- /* Here we may re-order the extraction of multiple names (hard links)
- * for the same file in the same directory in order to ensure the short
- * (DOS) name is set correctly. A short name is always associated with
- * exactly one long name, and at least on NTFS, only one long name for a
- * file can have a short name associated with it. (More specifically,
- * there can be unlimited names in the POSIX namespace, but only one
- * name can be in the Win32+DOS namespace, or one name in the Win32
- * namespace with a corresponding name in the DOS namespace.) To ensure
- * the short name of a file is associated with the correct long name in
- * a directory, we extract the long name with a corresponding short name
- * before any additional names. This can affect NTFS-3g extraction
- * (which uses ntfs_set_ntfs_dos_name(), which doesn't allow specifying
- * the long name to associate with a short name) and may affect Win32
- * extraction as well (which uses SetFileShortName()). */
-
if (dentry->skeleton_extracted)
return 0;
+
orig_dentry = NULL;
if (ctx->supported_features.short_names
+ && ctx->ops->requires_short_name_reordering
&& !dentry_has_short_name(dentry)
&& !dentry->d_inode->i_dos_name_extracted)
{
inode_for_each_dentry(other_dentry, dentry->d_inode) {
if (dentry_has_short_name(other_dentry)
- && !other_dentry->skeleton_extracted
- && other_dentry->parent == dentry->parent)
+ && !other_dentry->skeleton_extracted)
{
DEBUG("Creating %"TS" before %"TS" "
"to guarantee correct DOS name extraction",
return 0;
}
+static int
+dentry_extract_dir_skeleton(struct wim_dentry *dentry, void *_ctx)
+{
+ if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+ return dentry_extract_skeleton(dentry, _ctx);
+ return 0;
+}
+
/* Create a file or directory, then immediately extract all streams. This
* assumes that WIMLIB_EXTRACT_FLAG_SEQUENTIAL is not specified, since the WIM
* may not be read sequentially by this function. */
ctx.realtarget_nchars = tstrlen(ctx.realtarget);
}
+ if (ctx.ops->requires_short_name_reordering) {
+ ret = for_dentry_in_tree(root, dentry_extract_dir_skeleton,
+ &ctx);
+ if (ret)
+ goto out_free_realtarget;
+ }
+
/* Finally, the important part: extract the tree of files. */
if (extract_flags & (WIMLIB_EXTRACT_FLAG_SEQUENTIAL |
WIMLIB_EXTRACT_FLAG_FROM_PIPE)) {
.path_separator = '/',
.path_max = 32768,
+ /* By default, NTFS-3g creates names in the NTFS POSIX namespace, which
+ * is case-sensitive. */
.supports_case_sensitive_filenames = 1,
+
+ /* The root directory of the NTFS volume should not be created
+ * explicitly. */
.root_directory_is_special = 1,
+
+ /* NTFS-3g can open files by MFT reference. */
.uses_cookies = 1,
+
+ /*
+ * With NTFS-3g, the extraction order of the names of a file that has a
+ * short name needs to be:
+ *
+ * 1. Create file using the long name that has an associated short name.
+ * This long name is temporarily placed in the POSIX namespace.
+ * 2. Set the short name on the file. This will either change the POSIX
+ * name to Win32 and create a new DOS name, or replace the POSIX name
+ * with a Win32+DOS name.
+ * 3. Create additional long names (links) of the file, which are placed
+ * in the POSIX namespace.
+ *
+ * The reason for this is that two issues can come up when the
+ * extraction is done otherwise:
+ *
+ * - If a DOS name is set on a file in a directory with several long
+ * names, it is ambiguous which long name to use (at least with the
+ * exported ntfs_set_ntfs_dos_name() function).
+ * - NTFS-3g 2013.1.13 will no longer allow even setting the DOS name on
+ * a file with multiple existing long names, even if those long names
+ * are in different directories and the ntfs_set_ntfs_dos_name() call
+ * is therefore unambiguous. (This was apparently changed with the
+ * FUSE interface in mind.)
+ */
+ .requires_short_name_reordering = 1,
};
#endif /* WITH_NTFS_3G */