.IP \[bu]
Hard links, if supported by the filesystem.
.PP
-Note: encrypted files will be extracted as raw encrypted data if the filesystem
-does not support encryption. Compressed files and directories (with the
-compression attribute set) will be extracted as uncompressed if the filesystem
-does not support transparent compression.
-
-Additional note: files with names that cannot be represented on Windows will not
-be extracted by default; see \fB--including-invalid-names\fR.
+Additional notes about extracting files on Windows:
+.IP \[bu] 4
+Encrypted files will be extracted as raw encrypted data if the filesystem
+does not support encryption.
+.IP \[bu]
+Compressed files and directories (with the compression attribute set) will be
+extracted as uncompressed if the filesystem does not support transparent
+compression.
+.IP \[bu]
+Files with names that cannot be represented on Windows will not
+be extracted by default; see \fB--include-invalid-names\fR.
+.IP \[bu]
+Files with full paths over 260 characters (MAX_PATH) are extracted by using the
+\\\\?\\-prefixed path hack. But beware that such files will be inaccessible to
+most Windows software and may not be able to be deleted easily.
.SH SPLIT WIMS
You may use \fB@IMAGEX_PROGNAME@ apply\fR to apply images from a split WIM. The
\fIWIMFILE\fR argument is used to specify the first part of the split WIM, and
\fB--unix-data\fR, fail immediately if the UNIX owner, group, or file mode on an
extracted file cannot be set for any reason.
.TP
-\fB--including-invalid-names\fR
+\fB--include-invalid-names\fR
Extract files and directories with invalid names by replacing characters and
appending a suffix rather than ignoring them. The meaning of this is
platform-dependent.
image captured with \fB@IMAGEX_PROGNAME@\fR on UNIX could contain such files.
By default, invalid names will be ignored, and if there are multiple names
differing only in case, one will be chosen to extract arbitrarily; however,
-with \fB--including-invalid-names\fR, all names will be sanitized and
+with \fB--include-invalid-names\fR, all names will be sanitized and
extracted in some form.
.SH NOTES
\fB@IMAGEX_PROGNAME@ apply\fR calculates the SHA1 message digest of every file stream it
struct apply_args {
WIMStruct *w;
+
+ /* Directory to which we're extracting the WIM image or directory tree,
+ * in user-specified form (may be slightly altered) */
const tchar *target;
unsigned target_nchars;
- struct wim_dentry *extract_root;
- unsigned long invalid_sequence;
+
+#ifdef __WIN32__
+ /* \\?\-prefixed full path to the above directory; needed to work around
+ * lack of default support for long paths on Windoze. */
+ tchar *target_lowlevel_path;
+ unsigned target_lowlevel_path_nchars;
+#endif
+
+ /* Absolute path to the above directory; on UNIX this is simply a path
+ * beginning with /, while on Windoze this will be a path beginning with
+ * a drive letter followed by a backslash, but not with \\?\. */
tchar *target_realpath;
unsigned target_realpath_len;
+
+ struct wim_dentry *extract_root;
+ unsigned long invalid_sequence;
int extract_flags;
union wimlib_progress_info progress;
wimlib_progress_func_t progress_func;
unsigned vol_flags;
unsigned long num_hard_links_failed;
unsigned long num_soft_links_failed;
+ unsigned long num_long_paths;
bool have_vol_flags;
};
#else
# include "config.h"
#endif
+#ifdef __WIN32__
+# include "wimlib/win32_common.h" /* For GetFullPathName() */
+#endif
+
#include "wimlib/apply.h"
#include "wimlib/dentry.h"
#include "wimlib/encoding.h"
#include <sys/stat.h>
#include <unistd.h>
+#define MAX_LONG_PATH_WARNINGS 5
+
static int
do_apply_op(struct wim_dentry *dentry, struct apply_args *args,
int (*apply_dentry_func)(const tchar *, size_t,
size_t extraction_path_nchars;
struct wim_dentry *d;
LIST_HEAD(ancestor_list);
+ const tchar *target;
+ size_t target_nchars;
- extraction_path_nchars = args->target_nchars;
+#ifdef __WIN32__
+ if (args->target_lowlevel_path) {
+ target = args->target_lowlevel_path;
+ target_nchars = args->target_lowlevel_path_nchars;
+ } else
+#endif
+ {
+ target = args->target;
+ target_nchars = args->target_nchars;
+ }
+
+ extraction_path_nchars = target_nchars;
for (d = dentry; d != args->extract_root; d = d->parent) {
if (d->not_extracted)
}
tchar extraction_path[extraction_path_nchars + 1];
- p = tmempcpy(extraction_path, args->target, args->target_nchars);
+ p = tmempcpy(extraction_path, target, target_nchars);
+
list_for_each_entry(d, &ancestor_list, tmp_list) {
*p++ = OS_PREFERRED_PATH_SEPARATOR;
p = tmempcpy(p, d->extraction_name, d->extraction_name_nchars);
}
*p = T('\0');
+
+#ifdef __WIN32__
+ /* Warn the user if the path exceeds MAX_PATH */
+
+ /* + 1 for '\0', -4 for \\?\. */
+ if (extraction_path_nchars + 1 - 4 > MAX_PATH) {
+ if (dentry->needs_extraction &&
+ args->num_long_paths < MAX_LONG_PATH_WARNINGS)
+ {
+ WARNING("Path \"%ls\" exceeds MAX_PATH and will not be accessible "
+ "to most Windows software", extraction_path);
+ if (++args->num_long_paths == MAX_LONG_PATH_WARNINGS)
+ WARNING("Suppressing further warnings about long paths");
+ }
+ }
+#endif
return (*apply_dentry_func)(extraction_path, extraction_path_nchars,
dentry, args);
}
memset(&args, 0, sizeof(args));
+
args.w = wim;
args.target = target;
+ args.target_nchars = tstrlen(target);
args.extract_flags = extract_flags;
args.progress_func = progress_func;
- args.target_nchars = tstrlen(target);
+
+#ifdef __WIN32__
+ /* Work around defective behavior in Windows where paths longer than 260
+ * characters are not supported by default; instead they need to be
+ * turned into absolute paths and prefixed with "\\?\". */
+ args.target_lowlevel_path = MALLOC(32768 * sizeof(wchar_t));
+ if (!args.target_lowlevel_path)
+ {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out;
+ }
+ args.target_lowlevel_path[0] = L'\\';
+ args.target_lowlevel_path[1] = L'\\';
+ args.target_lowlevel_path[2] = L'?';
+ args.target_lowlevel_path[3] = L'\\';
+ args.target_lowlevel_path_nchars =
+ GetFullPathName(args.target, 32768 - 4,
+ &args.target_lowlevel_path[4], NULL);
+
+ if (args.target_lowlevel_path_nchars == 0 ||
+ args.target_lowlevel_path_nchars >= 32768 - 4)
+ {
+ WARNING("Can't get full path name for \"%ls\"", args.target);
+ FREE(args.target_lowlevel_path);
+ args.target_lowlevel_path = NULL;
+ } else {
+ args.target_lowlevel_path_nchars += 4;
+ }
+#endif
if (progress_func) {
args.progress.extract.wimfile_name = wim->filename;
ERROR_WITH_ERRNO("Failed to mount NTFS volume `%"TS"'",
target);
ret = WIMLIB_ERR_NTFS_3G;
- goto out;
+ goto out_free_target_lowlevel_path;
}
ops = &ntfs_apply_operations;
} else
}
}
#endif
+out_free_target_lowlevel_path:
+#ifdef __WIN32__
+ FREE(args.target_lowlevel_path);
+#endif
out:
return ret;
}