- args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_STREAMS;
- if (ret == 0) {
- struct lookup_table_entry *lte;
- struct lookup_table_entry *tmp;
- struct dentry *dentry;
- u64 total_size;
- u64 cur_size;
- u64 next_size;
- u64 one_percent;
- unsigned cur_percent;
-
- total_size = calculate_bytes_to_extract(&stream_list, args.extract_flags);
- one_percent = total_size / 100;
- cur_size = 0;
- next_size = 0;
- cur_percent = 0;
- puts("Extracting files...");
- list_for_each_entry_safe(lte, tmp, &stream_list, staging_list) {
- list_del(<e->staging_list);
- list_for_each_entry(dentry, <e->dentry_list, tmp_list) {
- if ((!dentry->d_inode->extracted_file) &&
- (args.extract_flags & WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS))
- {
- show_stream_op_progress(&cur_size, &next_size,
- total_size, one_percent,
- &cur_percent, lte,
- "extracted");
- }
- ret = extract_dentry(dentry, &args);
- if (ret != 0)
- return ret;
- }
- }
- finish_stream_op_progress(total_size, "extracted");
- } else {
- WARNING("Falling back to non-sequential image extraction");
- ret = for_dentry_in_tree(root, extract_dentry, &args);
- if (ret != 0)
- return ret;
+ 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);
+ }
+
+ /* Extract non-empty files */
+ ret = apply_stream_list(&stream_list, &args, ops, progress_func);
+ if (ret)
+ goto out_free_target_realpath;
+
+ if (progress_func) {
+ progress_func(WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS,
+ &args.progress);
+ }
+
+ /* Apply timestamps */
+ ret = for_dentry_in_tree_depth(root,
+ ops->apply_dentry_timestamps, &args);
+ if (ret)
+ goto out_free_target_realpath;
+
+ if (progress_func) {
+ progress_func(*wim_source_path ? WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END :
+ WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END,
+ &args.progress);
+ }
+out_free_target_realpath:
+ FREE(args.target_realpath);
+out_dentry_reset_needs_extraction:
+ for_dentry_in_tree(root, dentry_reset_needs_extraction, NULL);
+out_ntfs_umount:
+#ifdef WITH_NTFS_3G
+ /* Unmount the NTFS volume */
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+ if (ntfs_umount(args.vol, FALSE) != 0) {
+ ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%"TS"'",
+ args.target);
+ if (ret == 0)
+ ret = WIMLIB_ERR_NTFS_3G;
+ }
+ }
+#endif
+out_free_target_lowlevel_path:
+#ifdef __WIN32__
+ FREE(args.target_lowlevel_path);
+#endif
+out:
+ return ret;
+}
+
+/* Validates a single wimlib_extract_command, mostly checking to make sure the
+ * extract flags make sense. */
+static int
+check_extract_command(struct wimlib_extract_command *cmd, int wim_header_flags)
+{
+ int extract_flags;
+ bool is_entire_image = (cmd->wim_source_path[0] == T('\0'));
+
+ /* Empty destination path? */
+ if (cmd->fs_dest_path[0] == T('\0'))
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ extract_flags = cmd->extract_flags;
+
+ /* Specified both symlink and hardlink modes? */
+ if ((extract_flags &
+ (WIMLIB_EXTRACT_FLAG_SYMLINK |
+ WIMLIB_EXTRACT_FLAG_HARDLINK)) == (WIMLIB_EXTRACT_FLAG_SYMLINK |
+ WIMLIB_EXTRACT_FLAG_HARDLINK))
+ return WIMLIB_ERR_INVALID_PARAM;
+
+#ifdef __WIN32__
+ /* Wanted UNIX data on Windows? */
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
+ ERROR("Extracting UNIX data is not supported on Windows");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ /* Wanted linked extraction on Windows? (XXX This is possible, just not
+ * implemented yet.) */
+ if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
+ WIMLIB_EXTRACT_FLAG_HARDLINK))
+ {
+ ERROR("Linked extraction modes are not supported on Windows");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+#endif
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+ /* NTFS-3g extraction mode requested */
+#ifdef WITH_NTFS_3G
+ if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
+ WIMLIB_EXTRACT_FLAG_HARDLINK))) {
+ ERROR("Cannot specify symlink or hardlink flags when applying\n"
+ " directly to a NTFS volume");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ if (!is_entire_image &&
+ (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS))
+ {
+ ERROR("When applying directly to a NTFS volume you can "
+ "only extract a full image, not part of one");
+ return WIMLIB_ERR_INVALID_PARAM;