+ case IMAGEX_REF_OPTION:
+ swm_glob = optarg;
+ break;
+ case IMAGEX_THREADS_OPTION:
+ num_threads = parse_num_threads(optarg);
+ if (num_threads == UINT_MAX)
+ return -1;
+ break;
+ case IMAGEX_REBUILD_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
+ break;
+ default:
+ usage(EXPORT);
+ return -1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 3 || argc > 5) {
+ usage(EXPORT);
+ return -1;
+ }
+ src_wimfile = argv[0];
+ src_image_num_or_name = argv[1];
+ dest_wimfile = argv[2];
+ dest_name = (argc >= 4) ? argv[3] : NULL;
+ dest_desc = (argc >= 5) ? argv[4] : NULL;
+ ret = wimlib_open_wim(src_wimfile,
+ open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_w,
+ imagex_progress_func);
+ if (ret != 0)
+ return ret;
+
+ /* Determine if the destination is an existing file or not.
+ * If so, we try to append the exported image(s) to it; otherwise, we
+ * create a new WIM containing the exported image(s). */
+ if (tstat(dest_wimfile, &stbuf) == 0) {
+ int dest_ctype;
+
+ wim_is_new = false;
+ /* Destination file exists. */
+
+ if (!S_ISREG(stbuf.st_mode)) {
+ imagex_error(T("\"%"TS"\" is not a regular file"),
+ dest_wimfile);
+ ret = -1;
+ goto out;
+ }
+ ret = wimlib_open_wim(dest_wimfile, open_flags, &dest_w,
+ imagex_progress_func);
+ if (ret != 0)
+ goto out;
+
+ ret = file_writable(dest_wimfile);
+ if (ret != 0)
+ goto out;
+
+ dest_ctype = wimlib_get_compression_type(dest_w);
+ if (compression_type_specified
+ && compression_type != dest_ctype)
+ {
+ imagex_error(T("Cannot specify a compression type that is "
+ "not the same as that used in the "
+ "destination WIM"));
+ ret = -1;
+ goto out;
+ }
+ } else {
+ wim_is_new = true;
+ /* dest_wimfile is not an existing file, so create a new WIM. */
+ if (!compression_type_specified)
+ compression_type = wimlib_get_compression_type(src_w);
+ if (errno == ENOENT) {
+ ret = wimlib_create_new_wim(compression_type, &dest_w);
+ if (ret != 0)
+ goto out;
+ } else {
+ imagex_error_with_errno(T("Cannot stat file \"%"TS"\""),
+ dest_wimfile);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ image = wimlib_resolve_image(src_w, src_image_num_or_name);
+ ret = verify_image_exists(image, src_image_num_or_name, src_wimfile);
+ if (ret != 0)
+ goto out;
+
+ if (swm_glob) {
+ ret = open_swms_from_glob(swm_glob, src_wimfile, open_flags,
+ &additional_swms,
+ &num_additional_swms);
+ if (ret != 0)
+ goto out;
+ }
+
+ ret = wimlib_export_image(src_w, image, dest_w, dest_name, dest_desc,
+ export_flags, additional_swms,
+ num_additional_swms, imagex_progress_func);
+ if (ret != 0)
+ goto out;
+
+
+ if (wim_is_new)
+ ret = wimlib_write(dest_w, dest_wimfile, WIMLIB_ALL_IMAGES,
+ write_flags, num_threads,
+ imagex_progress_func);
+ else
+ ret = wimlib_overwrite(dest_w, write_flags, num_threads,
+ imagex_progress_func);
+out:
+ if (ret == WIMLIB_ERR_REOPEN)
+ ret = 0;
+ wimlib_free(src_w);
+ wimlib_free(dest_w);
+ if (additional_swms) {
+ for (unsigned i = 0; i < num_additional_swms; i++)
+ wimlib_free(additional_swms[i]);
+ free(additional_swms);
+ }
+ return ret;
+}
+
+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 | WIMLIB_EXTRACT_FLAG_NORPFIX;
+
+ 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;