From: Eric Biggers Date: Sun, 18 Aug 2013 21:09:17 +0000 (-0500) Subject: Add apply_ops.requires_short_name_reordering X-Git-Tag: v1.5.0~32 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=bb6773105af4072cf0ce7e6c8276632d6110b03b Add apply_ops.requires_short_name_reordering --- diff --git a/include/wimlib/apply.h b/include/wimlib/apply.h index 1019a48a..f8023a37 100644 --- a/include/wimlib/apply.h +++ b/include/wimlib/apply.h @@ -176,6 +176,11 @@ struct apply_operations { /* OPTIONAL: Set to 1 if extract_encrypted_stream() must be used to * create encrypted files. */ unsigned extract_encrypted_stream_creates_file : 1; + + /* OPTIONAL: Set to 1 if a link to a file with corresponding short name + * must be created before all links to the same file without + * corresponding short names. */ + unsigned requires_short_name_reordering : 1; }; struct wim_features { diff --git a/src/extract.c b/src/extract.c index 235d504c..1784cdf5 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1119,6 +1119,11 @@ hardlink: 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) { @@ -1128,32 +1133,18 @@ 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", @@ -1183,6 +1174,14 @@ again: 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. */ @@ -2322,6 +2321,13 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target, 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)) { diff --git a/src/ntfs-3g_apply.c b/src/ntfs-3g_apply.c index a1c67751..28589698 100644 --- a/src/ntfs-3g_apply.c +++ b/src/ntfs-3g_apply.c @@ -508,9 +508,42 @@ const struct apply_operations ntfs_3g_apply_ops = { .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 */ diff --git a/src/win32_apply.c b/src/win32_apply.c index e554b95d..48dd66d3 100644 --- a/src/win32_apply.c +++ b/src/win32_apply.c @@ -614,6 +614,7 @@ const struct apply_operations win32_apply_ops = { .root_directory_is_special = 1, .requires_final_set_attributes_pass = 1, .extract_encrypted_stream_creates_file = 1, + .requires_short_name_reordering = 1, /* TODO: check if this is really needed */ }; #endif /* __WIN32__ */