+static int
+imagex_export(int argc, tchar **argv)
+{
+ int c;
+ int open_flags = 0;
+ int export_flags = 0;
+ int write_flags = 0;
+ int compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
+ bool compression_type_specified = false;
+ const tchar *src_wimfile;
+ const tchar *src_image_num_or_name;
+ const tchar *dest_wimfile;
+ const tchar *dest_name;
+ const tchar *dest_desc;
+ WIMStruct *src_wim;
+ WIMStruct *dest_wim;
+ int ret;
+ int image;
+ struct stat stbuf;
+ bool wim_is_new;
+ const tchar *swm_glob = NULL;
+ WIMStruct **additional_swms = NULL;
+ unsigned num_additional_swms = 0;
+ unsigned num_threads = 0;
+
+ for_opt(c, export_options) {
+ switch (c) {
+ case IMAGEX_BOOT_OPTION:
+ export_flags |= WIMLIB_EXPORT_FLAG_BOOT;
+ break;
+ case IMAGEX_CHECK_OPTION:
+ open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+ write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
+ break;
+ case IMAGEX_COMPRESS_OPTION:
+ compression_type = get_compression_type(optarg);
+ if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
+ goto out_err;
+ compression_type_specified = true;
+ break;
+ case IMAGEX_REF_OPTION:
+ swm_glob = optarg;
+ break;
+ case IMAGEX_THREADS_OPTION:
+ num_threads = parse_num_threads(optarg);
+ if (num_threads == UINT_MAX)
+ goto out_err;
+ break;
+ case IMAGEX_REBUILD_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
+ break;
+ default:
+ goto out_usage;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 3 || argc > 5)
+ goto out_usage;
+ 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_wim,
+ imagex_progress_func);
+ if (ret)
+ goto out;
+
+ /* 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_free_src_wim;
+ }
+ ret = wimlib_open_wim(dest_wimfile, open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS,
+ &dest_wim, imagex_progress_func);
+ if (ret)
+ goto out_free_src_wim;
+
+ dest_ctype = wimlib_get_compression_type(dest_wim);
+ 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_free_dest_wim;
+ }
+ } else {
+ /* dest_wimfile is not an existing file, so create a new WIM. */
+ if (errno == ENOENT) {
+ wim_is_new = true;
+ if (!compression_type_specified)
+ compression_type = wimlib_get_compression_type(src_wim);
+ ret = wimlib_create_new_wim(compression_type, &dest_wim);
+ if (ret)
+ goto out_free_src_wim;
+ } else {
+ imagex_error_with_errno(T("Cannot stat file \"%"TS"\""),
+ dest_wimfile);
+ ret = -1;
+ goto out_free_src_wim;
+ }
+ }
+
+ image = wimlib_resolve_image(src_wim, src_image_num_or_name);
+ ret = verify_image_exists(image, src_image_num_or_name, src_wimfile);
+ if (ret)
+ goto out_free_dest_wim;
+
+ if (swm_glob) {
+ ret = open_swms_from_glob(swm_glob, src_wimfile, open_flags,
+ &additional_swms,
+ &num_additional_swms);
+ if (ret)
+ goto out_free_dest_wim;
+ }
+
+ ret = wimlib_export_image(src_wim, image, dest_wim, dest_name, dest_desc,
+ export_flags, additional_swms,
+ num_additional_swms, imagex_progress_func);
+ if (ret)
+ goto out_free_swms;
+
+
+ if (wim_is_new)
+ ret = wimlib_write(dest_wim, dest_wimfile, WIMLIB_ALL_IMAGES,
+ write_flags, num_threads,
+ imagex_progress_func);
+ else
+ ret = wimlib_overwrite(dest_wim, write_flags, num_threads,
+ imagex_progress_func);
+out_free_swms:
+ if (additional_swms) {
+ for (unsigned i = 0; i < num_additional_swms; i++)
+ wimlib_free(additional_swms[i]);
+ free(additional_swms);
+ }
+out_free_dest_wim:
+ wimlib_free(dest_wim);
+out_free_src_wim:
+ wimlib_free(src_wim);
+out:
+ return ret;
+
+out_usage:
+ usage(EXPORT);
+out_err:
+ ret = -1;
+ goto out;
+}
+
+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 **paths, unsigned num_paths,
+ int extract_flags, tchar *dest_dir,
+ size_t *num_cmds_ret)
+{
+ struct wimlib_extract_command *cmds;
+ size_t num_cmds;
+ tchar *emptystr = T("");
+
+ if (num_paths == 0) {
+ num_paths = 1;
+ paths = &emptystr;
+ }
+ num_cmds = num_paths;
+ 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 = paths[i];
+ if (is_root_wim_path(paths[i])) {
+ cmds[i].fs_dest_path = dest_dir;
+ } else {
+ size_t len = tstrlen(dest_dir) + 1 + tstrlen(paths[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""OS_PREFERRED_PATH_SEPARATOR_STRING"%"TS),
+ dest_dir, tbasename(paths[i]));
+ }
+ }
+ *num_cmds_ret = num_cmds;
+ return cmds;
+}
+
+/* Extract files or directories from a WIM image */
+static int
+imagex_extract(int argc, tchar **argv)