X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=ec383d6c47d00394b59516e66476d2add9f7e8b6;hp=e27f26470343389feecd811ea094a0ea4f82f613;hb=a031a8111ef53863c6ccdc838122cf5e12143375;hpb=7231431086332de22b2556477bcc5fc2c3e4bdcf diff --git a/programs/imagex.c b/programs/imagex.c index e27f2647..ec383d6c 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -31,13 +31,12 @@ #include #include #include +#include #include +#include #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) -#define swap(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); \ - a = __b; b = __a; }) - #define for_opt(c, opts) while ((c = getopt_long_only(argc, (char**)argv, "", \ opts, NULL)) != -1) @@ -62,44 +61,45 @@ static void usage_all(); static const char *usage_strings[] = { [APPEND] = -" imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" -" [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n" -" [--verbose] [--dereference] [--config=FILE]\n", +"imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" +" [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n" +" [--verbose] [--dereference] [--config=FILE]\n" +" [--threads=NUM_THREADS]\n", [APPLY] = -" imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" -" (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" -" [--symlink] [--verbose] [--ref=\"GLOB\"]\n", +"imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" +" (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" +" [--symlink] [--verbose] [--ref=\"GLOB\"]\n", [CAPTURE] = -" imagex capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" -" [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n" -" [--flags EDITION_ID] [--verbose] [--dereference]\n" -" [--config=FILE]\n", +"imagex capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" +" [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n" +" [--flags EDITION_ID] [--verbose] [--dereference]\n" +" [--config=FILE] [--threads=NUM_THREADS]\n", [DELETE] = -" imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check]\n", +"imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check]\n", [DIR] = -" imagex dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n", +"imagex dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n", [EXPORT] = -" imagex export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n" -" DEST_WIMFILE [DEST_IMAGE_NAME]\n" -" [DEST_IMAGE_DESCRIPTION] [--boot] [--check]\n" -" [--compress=TYPE] [--ref=\"GLOB\"]\n", +"imagex export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n" +" DEST_WIMFILE [DEST_IMAGE_NAME] [DEST_IMAGE_DESCRIPTION]\n" +" [--boot] [--check] [--compress=TYPE] [--ref=\"GLOB\"]\n" +" [--threads=NUM_THREADS]\n", [INFO] = -" imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n" -" [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n" -" [--xml] [--extract-xml FILE] [--metadata]\n", +"imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n" +" [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n" +" [--xml] [--extract-xml FILE] [--metadata]\n", [JOIN] = -" imagex join [--check] WIMFILE SPLIT_WIM...\n", +"imagex join [--check] WIMFILE SPLIT_WIM...\n", [MOUNT] = -" imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n" -" [--check] [--debug] [--streams-interface=INTERFACE]\n" -" [--ref=\"GLOB\"]\n", +"imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n" +" [--check] [--debug] [--streams-interface=INTERFACE]\n" +" [--ref=\"GLOB\"]\n", [MOUNTRW] = -" imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n" -" [--check] [--debug] [--streams-interface=INTERFACE]\n", +"imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n" +" [--check] [--debug] [--streams-interface=INTERFACE]\n", [SPLIT] = -" imagex split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n", +"imagex split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n", [UNMOUNT] = -" imagex unmount DIRECTORY [--commit] [--check]\n", +"imagex unmount DIRECTORY [--commit] [--check]\n", }; static const struct option common_options[] = { @@ -124,6 +124,7 @@ static const struct option capture_or_append_options[] = { {"dereference", no_argument, NULL, 'L'}, {"flags", required_argument, NULL, 'f'}, {"verbose", no_argument, NULL, 'v'}, + {"threads", required_argument, NULL, 't'}, {NULL, 0, NULL, 0}, }; static const struct option delete_options[] = { @@ -136,6 +137,7 @@ static const struct option export_options[] = { {"check", no_argument, NULL, 'c'}, {"compress", required_argument, NULL, 'x'}, {"ref", required_argument, NULL, 'r'}, + {"threads", required_argument, NULL, 't'}, {NULL, 0, NULL, 0}, }; @@ -199,11 +201,17 @@ static void imagex_error_with_errno(const char *format, ...) va_end(va); } -static int verify_image_exists(int image) +static int verify_image_exists(int image, const char *image_name, + const char *wim_name) { if (image == WIM_NO_IMAGE) { - imagex_error("Not a valid image"); - return WIMLIB_ERR_INVALID_IMAGE; + imagex_error("\"%s\" is not a valid image in `%s'!\n" + " Please specify a 1-based imagex index or " + "image name.\n" + " You may use `imagex info' to list the images " + "contained in a WIM.", + image_name, wim_name); + return -1; } return 0; } @@ -211,16 +219,17 @@ static int verify_image_exists(int image) static int verify_image_is_single(int image) { if (image == WIM_ALL_IMAGES) { - imagex_error("Cannot specify all images for this action"); - return WIMLIB_ERR_INVALID_IMAGE; + imagex_error("Cannot specify all images for this action!"); + return -1; } return 0; } -static int verify_image_exists_and_is_single(int image) +static int verify_image_exists_and_is_single(int image, const char *image_name, + const char *wim_name) { int ret; - ret = verify_image_exists(image); + ret = verify_image_exists(image, image_name, wim_name); if (ret == 0) ret = verify_image_is_single(image); return ret; @@ -280,6 +289,15 @@ out_fclose: return NULL; } +static int file_writable(const char *path) +{ + int ret; + ret = access(path, F_OK | W_OK); + if (ret != 0) + imagex_error_with_errno("Can't modify `%s'", path); + return ret; +} + static int open_swms_from_glob(const char *swm_glob, const char *first_part, int open_flags, @@ -337,6 +355,19 @@ out: } +static unsigned parse_num_threads(const char *optarg) +{ + char *tmp; + unsigned nthreads = strtoul(optarg, &tmp, 10); + if (nthreads == UINT_MAX || *tmp || tmp == optarg) { + imagex_error("Number of threads must be a non-negative integer!"); + return UINT_MAX; + } else { + return nthreads; + } +} + + /* Extract one image, or all images, from a WIM file into a directory. */ static int imagex_apply(int argc, const char **argv) { @@ -399,7 +430,7 @@ static int imagex_apply(int argc, const char **argv) return ret; image = wimlib_resolve_image(w, image_num_or_name); - ret = verify_image_exists(image); + ret = verify_image_exists(image, image_num_or_name, wimfile); if (ret != 0) goto out; @@ -449,9 +480,11 @@ static int imagex_apply(int argc, const char **argv) additional_swms, num_additional_swms); out: wimlib_free(w); - if (additional_swms) + if (additional_swms) { for (unsigned i = 0; i < num_additional_swms; i++) wimlib_free(additional_swms[i]); + free(additional_swms); + } return ret; } @@ -459,7 +492,7 @@ static int imagex_capture_or_append(int argc, const char **argv) { int c; int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS; - int add_image_flags = 0; + int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_SHOW_PROGRESS; int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS; int compression_type = WIM_COMPRESSION_TYPE_XPRESS; const char *dir; @@ -475,6 +508,7 @@ static int imagex_capture_or_append(int argc, const char **argv) int cur_image; char *default_name; int cmd = strcmp(argv[0], "append") ? CAPTURE : APPEND; + unsigned num_threads = 0; for_opt(c, capture_or_append_options) { switch (c) { @@ -503,6 +537,11 @@ static int imagex_capture_or_append(int argc, const char **argv) add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE; write_flags |= WIMLIB_WRITE_FLAG_VERBOSE; break; + case 't': + num_threads = parse_num_threads(optarg); + if (num_threads == UINT_MAX) + return -1; + break; default: usage(cmd); return -1; @@ -578,10 +617,12 @@ out_write: if (ret != 0) goto out; } - if (cmd == APPEND) - ret = wimlib_overwrite(w, write_flags); - else - ret = wimlib_write(w, wimfile, WIM_ALL_IMAGES, write_flags); + if (cmd == APPEND) { + ret = wimlib_overwrite(w, write_flags, num_threads); + } else { + ret = wimlib_write(w, wimfile, WIM_ALL_IMAGES, write_flags, + num_threads); + } if (ret != 0) imagex_error("Failed to write the WIM file `%s'", wimfile); out: @@ -627,13 +668,17 @@ static int imagex_delete(int argc, const char **argv) wimfile = argv[0]; image_num_or_name = argv[1]; + ret = file_writable(wimfile); + if (ret != 0) + return ret; + ret = wimlib_open_wim(wimfile, open_flags, &w); if (ret != 0) return ret; image = wimlib_resolve_image(w, image_num_or_name); - ret = verify_image_exists(image); + ret = verify_image_exists(image, image_num_or_name, wimfile); if (ret != 0) goto out; @@ -643,7 +688,7 @@ static int imagex_delete(int argc, const char **argv) goto out; } - ret = wimlib_overwrite(w, write_flags); + ret = wimlib_overwrite(w, write_flags, 0); if (ret != 0) { imagex_error("Failed to write the file `%s' with image " "deleted", wimfile); @@ -680,7 +725,7 @@ static int imagex_dir(int argc, const char **argv) if (argc == 3) { image = wimlib_resolve_image(w, argv[2]); - ret = verify_image_exists(image); + ret = verify_image_exists(image, argv[2], wimfile); if (ret != 0) goto out; } else { @@ -727,6 +772,7 @@ static int imagex_export(int argc, const char **argv) const char *swm_glob = NULL; WIMStruct **additional_swms = NULL; unsigned num_additional_swms = 0; + unsigned num_threads = 0; for_opt(c, export_options) { switch (c) { @@ -746,6 +792,11 @@ static int imagex_export(int argc, const char **argv) case 'r': swm_glob = optarg; break; + case 't': + num_threads = parse_num_threads(optarg); + if (num_threads == UINT_MAX) + return -1; + break; default: usage(EXPORT); return -1; @@ -785,6 +836,10 @@ static int imagex_export(int argc, const char **argv) if (ret != 0) goto out; + ret = file_writable(dest_wimfile); + if (ret != 0) + return ret; + dest_ctype = wimlib_get_compression_type(dest_w); if (compression_type_specified && compression_type != dest_ctype) @@ -814,7 +869,7 @@ static int imagex_export(int argc, const char **argv) } image = wimlib_resolve_image(src_w, src_image_num_or_name); - ret = verify_image_exists(image); + ret = verify_image_exists(image, src_image_num_or_name, src_wimfile); if (ret != 0) goto out; @@ -835,15 +890,17 @@ static int imagex_export(int argc, const char **argv) if (wim_is_new) ret = wimlib_write(dest_w, dest_wimfile, WIM_ALL_IMAGES, - write_flags); + write_flags, num_threads); else - ret = wimlib_overwrite(dest_w, write_flags); + ret = wimlib_overwrite(dest_w, write_flags, num_threads); out: wimlib_free(src_w); wimlib_free(dest_w); - if (additional_swms) + if (additional_swms) { for (unsigned i = 0; i < num_additional_swms; i++) wimlib_free(additional_swms[i]); + free(additional_swms); + } return ret; } @@ -1027,7 +1084,6 @@ static int imagex_info(int argc, const char **argv) } else { /* Modification operations */ - if (total_parts != 1) { imagex_error("Modifying a split WIM is not supported."); return -1; @@ -1088,6 +1144,10 @@ static int imagex_info(int argc, const char **argv) if (boot || new_name || new_desc || check != wimlib_has_integrity_table(w)) { + ret = file_writable(wimfile); + if (ret != 0) + return ret; + ret = wimlib_overwrite_xml_and_header(w, check ? WIMLIB_WRITE_FLAG_CHECK_INTEGRITY | WIMLIB_WRITE_FLAG_SHOW_PROGRESS : 0); @@ -1098,7 +1158,7 @@ static int imagex_info(int argc, const char **argv) } } out: - wimlib_free(w); + /*wimlib_free(w);*/ return ret; } @@ -1204,21 +1264,26 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) num_images = wimlib_get_num_images(w); if (num_images != 1) { imagex_error("The file `%s' contains %d images; Please " - "select one", wimfile, num_images); + "select one.", wimfile, num_images); usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) ? MOUNTRW : MOUNT); - ret = WIMLIB_ERR_INVALID_IMAGE; + ret = -1; goto out; } dir = argv[1]; } else { image = wimlib_resolve_image(w, argv[1]); dir = argv[2]; + ret = verify_image_exists_and_is_single(image, argv[1], wimfile); + if (ret != 0) + goto out; } - ret = verify_image_exists_and_is_single(image); - if (ret != 0) - goto out; + if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { + ret = file_writable(wimfile); + if (ret != 0) + return ret; + } ret = wimlib_mount(w, image, dir, mount_flags, additional_swms, num_additional_swms); @@ -1229,9 +1294,11 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) } out: wimlib_free(w); - if (additional_swms) + if (additional_swms) { for (unsigned i = 0; i < num_additional_swms; i++) wimlib_free(additional_swms[i]); + free(additional_swms); + } return ret; mount_usage: usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) @@ -1380,19 +1447,19 @@ static void help_or_version(int argc, const char **argv) static void usage(int cmd_type) { const struct imagex_command *cmd; - puts("IMAGEX: Usage:"); - fputs(usage_strings[cmd_type], stdout); - for_imagex_command(cmd) + printf("Usage: %s", usage_strings[cmd_type]); + for_imagex_command(cmd) { if (cmd->cmd == cmd_type) printf("\nTry `man imagex-%s' for more details.\n", cmd->name); + } } static void usage_all() { puts("IMAGEX: Usage:"); for (int i = 0; i < ARRAY_LEN(usage_strings); i++) - fputs(usage_strings[i], stdout); + printf(" %s", usage_strings[i]); static const char *extra = " imagex --help\n" " imagex --version\n"