+ args.w = wim;
+ args.target = target;
+ args.target_nchars = tstrlen(target);
+ args.extract_flags = extract_flags;
+ args.progress_func = progress_func;
+
+#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(WINDOWS_NT_MAX_PATH * sizeof(wchar_t));
+ if (!args.target_lowlevel_path)
+ {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out;
+ }
+ args.target_lowlevel_path_nchars =
+ GetFullPathName(args.target, WINDOWS_NT_MAX_PATH - 4,
+ &args.target_lowlevel_path[4], NULL);
+
+ if (args.target_lowlevel_path_nchars == 0 ||
+ args.target_lowlevel_path_nchars >= WINDOWS_NT_MAX_PATH - 4)
+ {
+ WARNING("Can't get full path name for \"%ls\"", args.target);
+ FREE(args.target_lowlevel_path);
+ args.target_lowlevel_path = NULL;
+ } else {
+ wmemcpy(args.target_lowlevel_path, L"\\\\?\\", 4);
+ args.target_lowlevel_path_nchars += 4;
+ }
+#endif
+
+ if (progress_func) {
+ args.progress.extract.wimfile_name = wim->filename;
+ args.progress.extract.image = wim->current_image;
+ args.progress.extract.extract_flags = (extract_flags &
+ WIMLIB_EXTRACT_MASK_PUBLIC);
+ args.progress.extract.image_name = wimlib_get_image_name(wim,
+ wim->current_image);
+ args.progress.extract.extract_root_wim_source_path = wim_source_path;
+ args.progress.extract.target = target;
+ }
+
+#ifdef WITH_NTFS_3G
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+ args.vol = ntfs_mount(target, 0);
+ if (!args.vol) {
+ ERROR_WITH_ERRNO("Failed to mount NTFS volume `%"TS"'",
+ target);
+ ret = WIMLIB_ERR_NTFS_3G;
+ goto out_free_target_lowlevel_path;
+ }
+ ops = &ntfs_apply_operations;
+ } else
+#endif
+ ops = &normal_apply_operations;
+
+ root = get_dentry(wim, wim_source_path);
+ if (!root) {
+ ERROR("Path \"%"TS"\" does not exist in WIM image %d",
+ wim_source_path, wim->current_image);
+ ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST;
+ goto out_ntfs_umount;
+ }
+ args.extract_root = root;
+
+ /* Calculate the actual filename component of each extracted dentry, and
+ * in the process set the dentry->needs_extraction flag on dentries that
+ * will be extracted. */
+ ret = for_dentry_in_tree(root, dentry_calculate_extraction_path, &args);
+ if (ret)
+ goto out_dentry_reset_needs_extraction;
+
+ /* Build a list of the streams that need to be extracted */
+ find_streams_for_extraction(root,
+ &stream_list,
+ wim->lookup_table, extract_flags);
+
+ /* Calculate the number of bytes of data that will be extracted */
+ calculate_bytes_to_extract(&stream_list, extract_flags,
+ &args.progress);
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
+ ret = extract_dentry_to_stdout(root);
+ goto out_dentry_reset_needs_extraction;
+ }
+
+ if (progress_func) {
+ progress_func(*wim_source_path ? WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN :
+ WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN,
+ &args.progress);
+ }
+
+ /* If a sequential extraction was specified, sort the streams to be
+ * extracted by their position in the WIM file, so that the WIM file can
+ * be read sequentially. */
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) {
+ ret = sort_stream_list_by_wim_position(&stream_list);
+ if (ret != 0) {
+ WARNING("Falling back to non-sequential extraction");
+ extract_flags &= ~WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
+ }
+ }
+
+ if (progress_func) {
+ progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN,
+ &args.progress);
+ }
+
+ /* Make the directory structure and extract empty files */
+ args.extract_flags |= WIMLIB_EXTRACT_FLAG_NO_STREAMS;
+ args.apply_dentry = ops->apply_dentry;
+ ret = for_dentry_in_tree(root, maybe_apply_dentry, &args);
+ args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_STREAMS;
+ if (ret)
+ goto out_dentry_reset_needs_extraction;
+
+ if (progress_func) {
+ progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END,
+ &args.progress);
+ }
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX) {
+ args.target_realpath = realpath(target, NULL);
+ if (!args.target_realpath) {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_dentry_reset_needs_extraction;
+ }
+ args.target_realpath_len = tstrlen(args.target_realpath);