+ goto out_free_src_wim;
+ }
+
+ /* dest_wimfile is not an existing file, so create a new WIM. */
+
+ if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
+ /* The user did not specify a compression type; default
+ * to that of the source WIM. */
+
+ compression_type = src_info.compression_type;
+ }
+ ret = wimlib_create_new_wim(compression_type, &dest_wim);
+ if (ret)
+ 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 (refglobs.num_globs) {
+ ret = wim_reference_globs(src_wim, &refglobs, open_flags);
+ if (ret)
+ goto out_free_dest_wim;
+ }
+
+ if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
+ image == WIMLIB_ALL_IMAGES && src_info.boot_index == 0)
+ {
+ imagex_error(T("--boot specified for all-images export, but source WIM "
+ "has no bootable image."));
+ ret = -1;
+ goto out_free_dest_wim;
+ }
+
+ ret = wimlib_export_image(src_wim, image, dest_wim, dest_name,
+ dest_desc, export_flags, imagex_progress_func);
+ if (ret) {
+ if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND) {
+ do_resource_not_found_warning(src_wimfile,
+ &src_info, &refglobs);
+ }
+ goto out_free_dest_wim;
+ }
+
+ if (!wim_is_new)
+ ret = wimlib_overwrite(dest_wim, write_flags, num_threads,
+ imagex_progress_func);
+ else if (dest_wimfile)
+ ret = wimlib_write(dest_wim, dest_wimfile, WIMLIB_ALL_IMAGES,
+ write_flags, num_threads,
+ imagex_progress_func);
+ else
+ ret = wimlib_write_to_fd(dest_wim, dest_wim_fd,
+ WIMLIB_ALL_IMAGES, write_flags,
+ num_threads, imagex_progress_func);
+out_free_dest_wim:
+ wimlib_free(dest_wim);
+out_free_src_wim:
+ wimlib_free(src_wim);
+out_free_refglobs:
+ refglob_set_destroy(&refglobs);
+ return ret;
+
+out_usage:
+ usage(CMD_EXPORT, stderr);
+out_err:
+ ret = -1;
+ goto out_free_refglobs;
+}
+
+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, int cmd)
+{
+ 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;
+
+ REFGLOB_SET(refglobs);
+
+ 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:
+ ret = refglob_set_append(&refglobs, optarg);
+ if (ret)
+ goto out_free_refglobs;
+ 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_info_file = stderr;
+ imagex_be_quiet = true;
+ break;
+ case IMAGEX_INCLUDE_INVALID_NAMES_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES;
+ extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS;
+ break;
+ default:
+ goto out_usage;