X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=12bfbc6201e888c839073c2611adc0266e7674af;hp=134ff29de19604ff56e938fb7712d39ff8e0ebfa;hb=35dd893208119869db6a90b1d1663f9aea88a3f7;hpb=491079f27a268fb9e5bc7f54a7cbe3fbb9fa2d94 diff --git a/programs/imagex.c b/programs/imagex.c index 134ff29d..12bfbc62 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -27,15 +27,11 @@ #include #include #include +#include #include #include #include -#ifdef WITH_NTFS_3G -#include -#include -#endif - #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) #define swap(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); \ @@ -80,25 +76,27 @@ static const char *path_basename(const char *path) static const char *usage_strings[] = { [APPEND] = -" imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [\"IMAGE_NAME\"]\n" -" [\"DESCRIPTION\"] [--boot] [--check] [--flags EDITIONID]\n" -" [--dereference]\n", +" imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" +" [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n" +" [--verbose] [--dereference] [--config=FILE]\n", [APPLY] = " imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" " (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" " [--symlink] [--verbose]\n", [CAPTURE] = -" imagex capture (DIRECTORY | NTFS_VOLUME) WIMFILE [\"IMAGE_NAME\"]\n" -" [\"DESCRIPTION\"] [--boot] [--check] [--compress[=TYPE]]\n" -" [--flags \"EditionID\"] [--verbose] [--dereference]\n", +" imagex capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" +" [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n" +" [--flags EDITION_ID] [--verbose] [--dereference]\n" +" [--config=FILE]\n", [DELETE] = " 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\"] [\"DEST_IMAGE_DESCRIPTION\"]\n" -" [--boot] [--check] [--compress[=TYPE]]\n", +" DEST_WIMFILE [DEST_IMAGE_NAME]\n" +" [DEST_IMAGE_DESCRIPTION] [--boot] [--check]\n" +" [--compress=TYPE]\n", [INFO] = " imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n" " [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n" @@ -107,12 +105,12 @@ static const char *usage_strings[] = { " imagex join [--check] WIMFILE SPLIT_WIM...\n", [MOUNT] = " imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n" -" [--check] [--debug] [--stream-interface=INTERFACE]\n", +" [--check] [--debug] [--streams-interface=INTERFACE]\n", [MOUNTRW] = " imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n" -" [--check] [--debug] [--stream-interface=INTERFACE]\n", +" [--check] [--debug] [--streams-interface=INTERFACE]\n", [SPLIT] = -" imagex split WIMFILE SPLIT_WIMFILE PART_SIZE [--check]\n", +" imagex split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n", [UNMOUNT] = " imagex unmount DIRECTORY [--commit] [--check]\n", }; @@ -124,10 +122,12 @@ static const struct option common_options[] = { }; static const struct option append_options[] = { - {"boot", no_argument, NULL, 'b'}, - {"check", no_argument, NULL, 'c'}, - {"flags", required_argument, NULL, 'f'}, - {"dereference", no_argument, NULL, 'L'}, + {"boot", no_argument, NULL, 'b'}, + {"check", no_argument, NULL, 'c'}, + {"config", required_argument, NULL, 'C'}, + {"dereference", no_argument, NULL, 'L'}, + {"flags", required_argument, NULL, 'f'}, + {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0}, }; static const struct option apply_options[] = { @@ -135,15 +135,17 @@ static const struct option apply_options[] = { {"hardlink", no_argument, NULL, 'h'}, {"symlink", no_argument, NULL, 's'}, {"verbose", no_argument, NULL, 'v'}, + {"ref", required_argument, NULL, 'r'}, {NULL, 0, NULL, 0}, }; static const struct option capture_options[] = { - {"boot", no_argument, NULL, 'b'}, - {"check", no_argument, NULL, 'c'}, - {"compress", optional_argument, NULL, 'x'}, - {"flags", required_argument, NULL, 'f'}, - {"verbose", no_argument, NULL,'v'}, - {"dereference", no_argument, NULL, 'L'}, + {"boot", no_argument, NULL, 'b'}, + {"check", no_argument, NULL, 'c'}, + {"compress", required_argument, NULL, 'x'}, + {"config", required_argument, NULL, 'C'}, + {"dereference", no_argument, NULL, 'L'}, + {"flags", required_argument, NULL, 'f'}, + {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0}, }; static const struct option delete_options[] = { @@ -152,20 +154,20 @@ static const struct option delete_options[] = { }; static const struct option export_options[] = { - {"boot", no_argument, NULL, 'b'}, - {"check", no_argument , NULL, 'c'}, - {"compress", optional_argument, NULL, 'x'}, + {"boot", no_argument, NULL, 'b'}, + {"check", no_argument, NULL, 'c'}, + {"compress", required_argument, NULL, 'x'}, {NULL, 0, NULL, 0}, }; static const struct option info_options[] = { {"boot", no_argument, NULL, 'b'}, {"check", no_argument, NULL, 'c'}, + {"extract-xml", required_argument, NULL, 'X'}, {"header", no_argument, NULL, 'h'}, {"lookup-table", no_argument, NULL, 'l'}, - {"xml", no_argument, NULL, 'x'}, - {"extract-xml", required_argument, NULL, 'X'}, {"metadata", no_argument, NULL, 'm'}, + {"xml", no_argument, NULL, 'x'}, {NULL, 0, NULL, 0}, }; @@ -177,7 +179,7 @@ static const struct option join_options[] = { static const struct option mount_options[] = { {"check", no_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, - {"stream-interface", required_argument, NULL, 's'}, + {"streams-interface", required_argument, NULL, 's'}, {NULL, 0, NULL, 0}, }; @@ -279,8 +281,6 @@ static int verify_image_exists_and_is_single(int image) static int get_compression_type(const char *optarg) { - if (!optarg) - return WIM_COMPRESSION_TYPE_XPRESS; if (strcasecmp(optarg, "maximum") == 0 || strcasecmp(optarg, "lzx") == 0) return WIM_COMPRESSION_TYPE_LZX; else if (strcasecmp(optarg, "fast") == 0 || strcasecmp(optarg, "xpress") == 0) @@ -294,6 +294,45 @@ static int get_compression_type(const char *optarg) } } +static const char *file_get_contents(const char *filename, size_t *len_ret) +{ + struct stat stbuf; + char *buf; + size_t len; + FILE *fp; + + if (stat(filename, &stbuf) != 0) { + imagex_error_with_errno("Failed to stat the file `%s'", filename); + return NULL; + } + len = stbuf.st_size; + + fp = fopen(filename, "rb"); + if (!fp) { + imagex_error_with_errno("Failed to open the file `%s'", filename); + return NULL; + } + + buf = malloc(len); + if (!buf) { + imagex_error("Failed to allocate buffer of %zu bytes to hold " + "contents of file `%s'", len, filename); + goto out_fclose; + } + if (fread(buf, 1, len, fp) != len) { + imagex_error_with_errno("Failed to read %lu bytes from the " + "file `%s'", len, filename); + goto out_free_buf; + } + *len_ret = len; + return buf; +out_free_buf: + free(buf); +out_fclose: + fclose(fp); + return NULL; +} + static int imagex_append(int argc, const char **argv) { int c; @@ -305,8 +344,12 @@ static int imagex_append(int argc, const char **argv) const char *wimfile; const char *name; const char *desc; + const char *config_file = NULL; + const char *config_str = NULL; + size_t config_len = 0; WIMStruct *w; int ret; + int cur_image; for_opt(c, append_options) { switch (c) { @@ -317,12 +360,18 @@ static int imagex_append(int argc, const char **argv) open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; + case 'C': + config_file = optarg; + break; case 'f': flags_element = optarg; break; case 'L': add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE; break; + case 'v': + add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE; + break; default: usage(APPEND); return -1; @@ -339,6 +388,12 @@ static int imagex_append(int argc, const char **argv) name = (argc >= 3) ? argv[2] : path_basename(dir); desc = (argc >= 4) ? argv[3] : NULL; + if (config_file) { + config_str = file_get_contents(config_file, &config_len); + if (!config_str) + return -1; + } + ret = wimlib_open_wim(wimfile, open_flags, &w); if (ret != 0) return ret; @@ -353,22 +408,34 @@ static int imagex_append(int argc, const char **argv) printf("Capturing WIM image NTFS filesystem on `%s'\n", ntfs_device); ret = wimlib_add_image_from_ntfs_volume(w, ntfs_device, - name, desc, - flags_element, + name, + config_str, + config_len, add_image_flags); goto out_write; } } else { - if (errno != -ENOENT) + if (errno != ENOENT) imagex_error_with_errno("Failed to stat `%s'", dir); } #endif - ret = wimlib_add_image(w, dir, name, desc, - flags_element, add_image_flags); + ret = wimlib_add_image(w, dir, name, config_str, config_len, + add_image_flags); out_write: if (ret != 0) goto out; + cur_image = wimlib_get_num_images(w); + if (desc) { + ret = wimlib_set_image_descripton(w, cur_image, desc); + if (ret != 0) + goto out; + } + if (flags_element) { + ret = wimlib_set_image_flags(w, cur_image, flags_element); + if (ret != 0) + goto out; + } ret = wimlib_overwrite(w, write_flags); out: wimlib_free(w); @@ -379,7 +446,8 @@ out: static int imagex_apply(int argc, const char **argv) { int c; - int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS; + int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS | + WIMLIB_OPEN_FLAG_SPLIT_OK; int image; int num_images; WIMStruct *w; @@ -389,6 +457,11 @@ static int imagex_apply(int argc, const char **argv) const char *image_num_or_name; int extract_flags = 0; + const char *swm_glob = NULL; + WIMStruct **additional_swms = NULL; + size_t num_additional_swms = 0; + glob_t globbuf; + for_opt(c, apply_options) { switch (c) { case 'c': @@ -403,6 +476,9 @@ static int imagex_apply(int argc, const char **argv) case 'v': extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE; break; + case 'r': + swm_glob = optarg; + break; default: usage(APPLY); return -1; @@ -426,7 +502,7 @@ static int imagex_apply(int argc, const char **argv) ret = wimlib_open_wim(wimfile, open_flags, &w); if (ret != 0) - goto out; + return ret; image = wimlib_resolve_image(w, image_num_or_name); ret = verify_image_exists(image); @@ -442,6 +518,36 @@ static int imagex_apply(int argc, const char **argv) goto out; } + if (swm_glob) { + ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); + if (ret != 0) { + imagex_error_with_errno("Failed to process glob " + "\"%s\"", swm_glob); + ret = -1; + goto out; + } + num_additional_swms = globbuf.gl_pathc; + additional_swms = calloc(num_additional_swms, sizeof(additional_swms[0])); + if (!additional_swms) { + imagex_error("Out of memory"); + ret = -1; + goto out; + } + size_t offset = 0; + for (size_t i = 0; i < num_additional_swms; i++) { + if (strcmp(globbuf.gl_pathv[i], wimfile) == 0) { + offset++; + continue; + } + ret = wimlib_open_wim(globbuf.gl_pathv[i], + open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, + &additional_swms[i - offset]); + if (ret != 0) + goto out; + } + num_additional_swms -= offset; + } + #ifdef WITH_NTFS_3G struct stat stbuf; @@ -453,18 +559,24 @@ static int imagex_apply(int argc, const char **argv) image, wimfile, ntfs_device); ret = wimlib_apply_image_to_ntfs_volume(w, image, ntfs_device, - extract_flags); + extract_flags, + additional_swms, + num_additional_swms); goto out; } } else { - if (errno != -ENOENT) + if (errno != ENOENT) imagex_error_with_errno("Failed to stat `%s'", dir); } #endif - ret = wimlib_extract_image(w, image, dir, extract_flags); + ret = wimlib_extract_image(w, image, dir, extract_flags, + additional_swms, num_additional_swms); out: wimlib_free(w); + if (additional_swms) + for (size_t i = 0; i < num_additional_swms; i++) + wimlib_free(additional_swms[i]); return ret; } @@ -481,7 +593,11 @@ static int imagex_capture(int argc, const char **argv) const char *wimfile; const char *name; const char *desc; + const char *config_file = NULL; + const char *config_str = NULL; + size_t config_len = 0; WIMStruct *w; + int cur_image; int ret; for_opt(c, capture_options) { @@ -492,6 +608,9 @@ static int imagex_capture(int argc, const char **argv) case 'c': write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; + case 'C': + config_file = optarg; + break; case 'x': compression_type = get_compression_type(optarg); if (compression_type == WIM_COMPRESSION_TYPE_INVALID) @@ -524,6 +643,12 @@ static int imagex_capture(int argc, const char **argv) name = (argc >= 3) ? argv[2] : dir; desc = (argc >= 4) ? argv[3] : NULL; + if (config_file) { + config_str = file_get_contents(config_file, &config_len); + if (!config_str) + return -1; + } + ret = wimlib_create_new_wim(compression_type, &w); if (ret != 0) return ret; @@ -538,24 +663,36 @@ static int imagex_capture(int argc, const char **argv) printf("Capturing WIM image NTFS filesystem on `%s'\n", ntfs_device); ret = wimlib_add_image_from_ntfs_volume(w, ntfs_device, - name, desc, - flags_element, + name, + config_str, + config_len, add_image_flags); goto out_write; } } else { - if (errno != -ENOENT) + if (errno != ENOENT) imagex_error_with_errno("Failed to stat `%s'", dir); } #endif - ret = wimlib_add_image(w, dir, name, desc, flags_element, - add_image_flags); + ret = wimlib_add_image(w, dir, name, config_str, + config_len, add_image_flags); out_write: if (ret != 0) { imagex_error("Failed to add the image `%s'", dir); goto out; } + cur_image = wimlib_get_num_images(w); + if (desc) { + ret = wimlib_set_image_descripton(w, cur_image, desc); + if (ret != 0) + goto out; + } + if (flags_element) { + ret = wimlib_set_image_flags(w, cur_image, flags_element); + if (ret != 0) + goto out; + } ret = wimlib_write(w, wimfile, WIM_ALL_IMAGES, write_flags); if (ret != 0)