+static bool
+is_root_wim_path(const tchar *path)
+{
+ const tchar *p;
+ for (p = path; *p; p++)
+ if (*p != T('\\') && *p != T('/'))
+ return false;
+ return true;
+}
+
+static void
+free_extract_commands(struct wimlib_extract_command *cmds, size_t num_cmds,
+ const tchar *dest_dir)
+{
+ for (size_t i = 0; i < num_cmds; i++)
+ if (cmds[i].fs_dest_path != dest_dir)
+ free(cmds[i].fs_dest_path);
+ free(cmds);
+}
+
+static struct wimlib_extract_command *
+prepare_extract_commands(tchar **argv, int argc, int extract_flags,
+ tchar *dest_dir, size_t *num_cmds_ret)
+{
+ struct wimlib_extract_command *cmds;
+ size_t num_cmds;
+ tchar *emptystr = T("");
+
+ if (argc == 0) {
+ argc = 1;
+ argv = &emptystr;
+ }
+ num_cmds = argc;
+ cmds = calloc(num_cmds, sizeof(cmds[0]));
+ if (!cmds) {
+ imagex_error(T("Out of memory!"));
+ return NULL;
+ }
+
+ for (size_t i = 0; i < num_cmds; i++) {
+ cmds[i].extract_flags = extract_flags;
+ cmds[i].wim_source_path = argv[i];
+ if (is_root_wim_path(argv[i])) {
+ cmds[i].fs_dest_path = dest_dir;
+ } else {
+ size_t len = tstrlen(dest_dir) + 1 + tstrlen(argv[i]);
+ cmds[i].fs_dest_path = malloc((len + 1) * sizeof(tchar));
+ if (!cmds[i].fs_dest_path) {
+ free_extract_commands(cmds, num_cmds, dest_dir);
+ return NULL;
+ }
+ tsprintf(cmds[i].fs_dest_path, T("%"TS"/%"TS), dest_dir,
+ tbasename(argv[i]));
+ }
+ }
+ *num_cmds_ret = num_cmds;
+ return cmds;
+}
+
+/* Extract files or directories from a WIM image */
+static int
+imagex_extract(int argc, tchar **argv)
+{
+ int c;
+ int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+ int image;
+ WIMStruct *wim;
+ int ret;
+ const tchar *wimfile;
+ const tchar *image_num_or_name;
+ tchar *dest_dir = T(".");
+ int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
+
+ const tchar *swm_glob = NULL;
+ WIMStruct **additional_swms = NULL;
+ unsigned num_additional_swms = 0;
+
+ struct wimlib_extract_command *cmds;
+ size_t num_cmds;
+
+ for_opt(c, extract_options) {
+ switch (c) {
+ case IMAGEX_CHECK_OPTION:
+ open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+ break;
+ case IMAGEX_VERBOSE_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
+ break;
+ case IMAGEX_REF_OPTION:
+ swm_glob = optarg;
+ break;
+ case IMAGEX_UNIX_DATA_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
+ break;
+ case IMAGEX_NO_ACLS_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_NO_ACLS;
+ break;
+ case IMAGEX_STRICT_ACLS_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_STRICT_ACLS;
+ break;
+ case IMAGEX_DEST_DIR_OPTION:
+ dest_dir = optarg;
+ break;
+ case IMAGEX_TO_STDOUT_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_TO_STDOUT;
+ imagex_be_quiet = true;
+ break;
+ default:
+ usage(EXTRACT);
+ ret = -1;
+ goto out;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ usage(EXTRACT);
+ ret = -1;
+ goto out;
+ }
+ wimfile = argv[0];
+ image_num_or_name = argv[1];
+
+ argc -= 2;
+ argv += 2;
+
+ cmds = prepare_extract_commands(argv, argc, extract_flags, dest_dir,
+ &num_cmds);
+ if (!cmds) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = wimlib_open_wim(wimfile, open_flags, &wim, imagex_progress_func);
+ if (ret)
+ goto out_free_cmds;
+
+ image = wimlib_resolve_image(wim, image_num_or_name);
+ ret = verify_image_exists_and_is_single(image,
+ image_num_or_name,
+ wimfile);
+ if (ret)
+ goto out_wimlib_free;
+
+ if (swm_glob) {
+ ret = open_swms_from_glob(swm_glob, wimfile, open_flags,
+ &additional_swms,
+ &num_additional_swms);
+ if (ret)
+ goto out_wimlib_free;
+ }
+
+#ifdef __WIN32__
+ win32_acquire_restore_privileges();
+#endif
+
+ ret = wimlib_extract_files(wim, image, 0, cmds, num_cmds,
+ additional_swms, num_additional_swms,
+ imagex_progress_func);
+ if (ret == 0) {
+ if (!imagex_be_quiet)
+ tprintf(T("Done extracting files.\n"));
+ } else if (ret == WIMLIB_ERR_PATH_DOES_NOT_EXIST) {
+ tfprintf(stderr, T("Note: You can use `"IMAGEX_PROGNAME" dir' to see what "
+ "files and directories\n"
+ " are in the WIM image.\n"));
+ }
+#ifdef __WIN32__
+ win32_release_restore_privileges();
+#endif
+ if (additional_swms) {
+ for (unsigned i = 0; i < num_additional_swms; i++)
+ wimlib_free(additional_swms[i]);
+ free(additional_swms);
+ }
+out_wimlib_free:
+ wimlib_free(wim);
+out_free_cmds:
+ free_extract_commands(cmds, num_cmds, dest_dir);
+out:
+ return ret;
+}
+