X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=fe7f3be9866de20ee66888a4c6ab3e89f59bad0f;hp=2d664084606ae10c8e2d09eb99e2e76ea820bafa;hb=1dde5fb0d809f2f5e032e4d5241d1cb15ff3eb65;hpb=53d4db68e30bf45b983c59f91e5e2a3e039e1426 diff --git a/programs/imagex.c b/programs/imagex.c index 2d664084..fe7f3be9 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -31,6 +31,11 @@ #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); \ @@ -39,6 +44,7 @@ #define for_opt(c, opts) while ((c = getopt_long_only(argc, (char**)argv, "", \ opts, NULL)) != -1) + enum imagex_op_type { APPEND, APPLY, @@ -74,37 +80,41 @@ static const char *path_basename(const char *path) static const char *usage_strings[] = { [APPEND] = -" imagex append DIRECTORY WIMFILE [\"IMAGE_NAME\"] [\"DESCRIPTION\"] [--boot]\n" -" [--check] [--config CONFIG_FILE] [--flags EDITIONID] [--verify]\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] DIRECTORY [--check]\n" -" [--verify] [--hardlink] [--symlink] [--verbose]\n", +" imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" +" (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" +" [--symlink] [--verbose]\n", [CAPTURE] = -" imagex capture DIRECTORY WIMFILE [\"IMAGE_NAME\"] [\"DESCRIPTION\"]\n" -" [--boot] [--check] [--compress[=TYPE]] [--config CONFIG_FILE]\n" -" [--flags \"EditionID\"] [--norpfix] [--verify] [--verbose]\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" -" [--xml] [--extract-xml FILE] [--metadata]\n", +" [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n" +" [--xml] [--extract-xml FILE] [--metadata]\n", [JOIN] = " imagex join [--check] WIMFILE SPLIT_WIM...\n", [MOUNT] = " imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n" -" [--check] [--debug]\n", +" [--check] [--debug] [--streams-interface=INTERFACE]\n", [MOUNTRW] = " imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n" -" [--check] [--debug]\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", }; @@ -116,30 +126,29 @@ static const struct option common_options[] = { }; static const struct option append_options[] = { - {"boot", no_argument, NULL, 'b'}, - {"check", no_argument, NULL, 'c'}, - {"config", required_argument, NULL, 'C'}, - {"flags", required_argument, NULL, 'f'}, - {"verify", no_argument, NULL, 'V'}, + {"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[] = { {"check", no_argument, NULL, 'c'}, - {"verify", no_argument, NULL, 'V'}, {"hardlink", no_argument, NULL, 'h'}, {"symlink", no_argument, NULL, 's'}, {"verbose", no_argument, NULL, 'v'}, {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'}, - {"config", required_argument, NULL, 'C'}, - {"flags", required_argument, NULL, 'f'}, - {"norpfix", no_argument, NULL, 'n'}, - {"verify", no_argument, NULL, 'V'}, - {"verbose", no_argument, NULL, 'v'}, + {"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[] = { @@ -148,20 +157,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}, }; @@ -173,6 +182,7 @@ static const struct option join_options[] = { static const struct option mount_options[] = { {"check", no_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, + {"streams-interface", required_argument, NULL, 's'}, {NULL, 0, NULL, 0}, }; @@ -195,6 +205,19 @@ static void imagex_error(const char *format, ...) va_start(va, format); fputs("ERROR: ", stderr); vfprintf(stderr, format, va); + putc('\n', stderr); + va_end(va); +} + +/* Print formatted error message to stderr. */ +static void imagex_error_with_errno(const char *format, ...) +{ + int errno_save = errno; + va_list va; + va_start(va, format); + fputs("ERROR: ", stderr); + vfprintf(stderr, format, va); + fprintf(stderr, ": %s\n", strerror(errno_save)); va_end(va); } @@ -235,7 +258,7 @@ static void usage_all() static int verify_image_exists(int image) { if (image == WIM_NO_IMAGE) { - imagex_error("Not a valid image!\n"); + imagex_error("Not a valid image"); return WIMLIB_ERR_INVALID_IMAGE; } return 0; @@ -244,7 +267,7 @@ 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!\n"); + imagex_error("Cannot specify all images for this action"); return WIMLIB_ERR_INVALID_IMAGE; } return 0; @@ -261,8 +284,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_LZX; if (strcasecmp(optarg, "maximum") == 0 || strcasecmp(optarg, "lzx") == 0) return WIM_COMPRESSION_TYPE_LZX; else if (strcasecmp(optarg, "fast") == 0 || strcasecmp(optarg, "xpress") == 0) @@ -271,12 +292,50 @@ static int get_compression_type(const char *optarg) return WIM_COMPRESSION_TYPE_NONE; else { imagex_error("Invalid compression type `%s'! Must be " - "\"maximum\", \"fast\", or \"none\".\n", - optarg); + "\"maximum\", \"fast\", or \"none\".", optarg); return WIM_COMPRESSION_TYPE_INVALID; } } +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; @@ -288,8 +347,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) { @@ -301,13 +364,16 @@ static int imagex_append(int argc, const char **argv) write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case 'C': - /*config = optarg;*/ + config_file = optarg; break; case 'f': flags_element = optarg; break; - case 'V': - /* verify */ + 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); @@ -325,16 +391,56 @@ 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; - ret = wimlib_add_image(w, dir, name, desc, - flags_element, add_image_flags); +#ifdef WITH_NTFS_3G + struct stat stbuf; + + ret = stat(dir, &stbuf); + if (ret == 0) { + if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) { + const char *ntfs_device = dir; + printf("Capturing WIM image NTFS filesystem on `%s'\n", + ntfs_device); + ret = wimlib_add_image_from_ntfs_volume(w, ntfs_device, + name, + config_str, + config_len, + add_image_flags); + goto out_write; + } + } else { + if (errno != -ENOENT) + imagex_error_with_errno("Failed to stat `%s'", dir); + } +#endif + ret = wimlib_add_image(w, dir, name, config_str, config_len, + add_image_flags); + +out_write: if (ret != 0) - goto done; + 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); -done: +out: wimlib_free(w); return ret; } @@ -343,9 +449,7 @@ done: static int imagex_apply(int argc, const char **argv) { int c; - int link_type = WIM_LINK_TYPE_NONE; int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS; - bool verbose = false; int image; int num_images; WIMStruct *w; @@ -353,23 +457,21 @@ static int imagex_apply(int argc, const char **argv) const char *wimfile; const char *dir; const char *image_num_or_name; + int extract_flags = 0; for_opt(c, apply_options) { switch (c) { case 'c': open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; break; - case 'V': - /* verify */ - break; case 'h': - link_type = WIM_LINK_TYPE_HARD; + extract_flags |= WIMLIB_EXTRACT_FLAG_HARDLINK; break; case 's': - link_type = WIM_LINK_TYPE_SYMBOLIC; + extract_flags |= WIMLIB_EXTRACT_FLAG_SYMLINK; break; case 'v': - verbose = true; + extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE; break; default: usage(APPLY); @@ -394,28 +496,44 @@ static int imagex_apply(int argc, const char **argv) ret = wimlib_open_wim(wimfile, open_flags, &w); if (ret != 0) - return ret; + goto out; image = wimlib_resolve_image(w, image_num_or_name); ret = verify_image_exists(image); if (ret != 0) - goto done; + goto out; num_images = wimlib_get_num_images(w); if (argc == 2 && num_images != 1) { imagex_error("`%s' contains %d images; Please select one " - "(or all).\n", wimfile, num_images); + "(or all)", wimfile, num_images); usage(APPLY); ret = -1; - goto done; + goto out; } - ret = wimlib_set_output_dir(w, dir); - if (ret != 0) - goto done; - wimlib_set_verbose(w, verbose); - wimlib_set_link_type(w, link_type); - ret = wimlib_extract_image(w, image); -done: + +#ifdef WITH_NTFS_3G + struct stat stbuf; + + ret = stat(dir, &stbuf); + if (ret == 0) { + if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) { + const char *ntfs_device = dir; + printf("Applying image %d of `%s' to NTFS filesystem on `%s'\n", + image, wimfile, ntfs_device); + ret = wimlib_apply_image_to_ntfs_volume(w, image, + ntfs_device, + extract_flags); + goto out; + } + } else { + if (errno != -ENOENT) + imagex_error_with_errno("Failed to stat `%s'", dir); + } +#endif + + ret = wimlib_extract_image(w, image, dir, extract_flags); +out: wimlib_free(w); return ret; } @@ -427,14 +545,17 @@ static int imagex_capture(int argc, const char **argv) int c; int add_image_flags = 0; int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS; - int compression_type = WIM_COMPRESSION_TYPE_NONE; - const char *flags_element = NULL; - bool verbose = false; + int compression_type = WIM_COMPRESSION_TYPE_XPRESS; + const char *flags_element = NULL; const char *dir; 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) { @@ -445,25 +566,23 @@ 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) return -1; break; - case 'C': - /*config = optarg;*/ - break; case 'f': flags_element = optarg; break; - case 'n': - /*norpfix = true;*/ - break; case 'v': - verbose = true; + add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE; + write_flags |= WIMLIB_WRITE_FLAG_VERBOSE; break; - case 'V': - /*verify = true;*/ + case 'L': + add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE; break; default: usage(CAPTURE); @@ -482,23 +601,61 @@ 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; - wimlib_set_verbose(w, verbose); +#ifdef WITH_NTFS_3G + struct stat stbuf; - ret = wimlib_add_image(w, dir, name, desc, flags_element, - add_image_flags); + ret = stat(dir, &stbuf); + if (ret == 0) { + if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) { + const char *ntfs_device = dir; + printf("Capturing WIM image NTFS filesystem on `%s'\n", + ntfs_device); + ret = wimlib_add_image_from_ntfs_volume(w, ntfs_device, + name, + config_str, + config_len, + add_image_flags); + goto out_write; + } + } else { + if (errno != -ENOENT) + imagex_error_with_errno("Failed to stat `%s'", dir); + } +#endif + 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'!\n", dir); - goto done; + 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) - imagex_error("Failed to write the WIM file `%s'!\n", wimfile); -done: + imagex_error("Failed to write the WIM file `%s'", wimfile); +out: wimlib_free(w); return ret; } @@ -531,9 +688,9 @@ static int imagex_delete(int argc, const char **argv) if (argc != 2) { if (argc < 1) - imagex_error("Must specify a WIM file!\n"); + imagex_error("Must specify a WIM file"); if (argc < 2) - imagex_error("Must specify an image!\n"); + imagex_error("Must specify an image"); usage(DELETE); return -1; } @@ -552,15 +709,14 @@ static int imagex_delete(int argc, const char **argv) ret = wimlib_delete_image(w, image); if (ret != 0) { - imagex_error("Failed to delete image from `%s'!\n", - wimfile); + imagex_error("Failed to delete image from `%s'", wimfile); goto done; } ret = wimlib_overwrite(w, write_flags); if (ret != 0) { imagex_error("Failed to write the file `%s' with image " - "deleted!\n", wimfile); + "deleted", wimfile); } done: wimlib_free(w); @@ -578,12 +734,12 @@ static int imagex_dir(int argc, const char **argv) int part_number; if (argc < 2) { - imagex_error("Must specify a WIM file!\n"); + imagex_error("Must specify a WIM file"); usage(DIR); return -1; } if (argc > 3) { - imagex_error("Too many arguments!\n"); + imagex_error("Too many arguments"); usage(DIR); return -1; } @@ -595,9 +751,9 @@ static int imagex_dir(int argc, const char **argv) part_number = wimlib_get_part_number(w, NULL); if (part_number != 1) { - imagex_error("`%s' is part %d of a split WIM! Specify the first part " - "to see the files.\n", - wimfile, part_number); + imagex_error("`%s' is part %d of a split WIM! Specify the " + "first part to see the files", + wimfile, part_number); ret = WIMLIB_ERR_SPLIT_UNSUPPORTED; goto done; } @@ -613,7 +769,7 @@ static int imagex_dir(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.\n", wimfile, num_images); + "select one.", wimfile, num_images); usage(DIR); ret = -1; goto done; @@ -635,7 +791,7 @@ static int imagex_export(int argc, const char **argv) int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS; int export_flags = 0; int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS; - int compression_type = WIM_COMPRESSION_TYPE_NONE; + int compression_type = WIM_COMPRESSION_TYPE_XPRESS; bool compression_type_specified = false; const char *src_wimfile; const char *src_image_num_or_name; @@ -690,8 +846,8 @@ static int imagex_export(int argc, const char **argv) if (stat(dest_wimfile, &stbuf) == 0) { wim_is_new = false; /* Destination file exists. */ - if (!S_ISREG(stbuf.st_mode)) { - imagex_error("`%s' is not a regular file!\n", + if (!S_ISREG(stbuf.st_mode) && !S_ISLNK(stbuf.st_mode)) { + imagex_error("`%s' is not a regular file", dest_wimfile); goto done; } @@ -702,8 +858,9 @@ static int imagex_export(int argc, const char **argv) if (compression_type_specified && compression_type != wimlib_get_compression_type(dest_w)) { imagex_error("Cannot specify a compression type that is " - "not the same as that used in the " - "destination WIM!\n"); + "not the same as that used in the " + "destination WIM"); + ret = -1; goto done; } compression_type = wimlib_get_compression_type(dest_w); @@ -715,7 +872,7 @@ static int imagex_export(int argc, const char **argv) if (ret != 0) goto done; } else { - imagex_error("Cannot stat file `%s': %m\n", + imagex_error_with_errno("Cannot stat file `%s'", dest_wimfile); goto done; } @@ -838,12 +995,12 @@ static int imagex_info(int argc, const char **argv) image = wimlib_resolve_image(w, image_num_or_name); if (image == WIM_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) { - imagex_error("The image `%s' does not exist!\n", + imagex_error("The image `%s' does not exist", image_num_or_name); if (boot) imagex_error("If you would like to set the boot " - "index to 0, specify image \"0\" with " - "the --boot flag.\n"); + "index to 0, specify image \"0\" with " + "the --boot flag."); ret = WIMLIB_ERR_INVALID_IMAGE; goto done; } @@ -851,15 +1008,15 @@ static int imagex_info(int argc, const char **argv) if (image == WIM_ALL_IMAGES && wimlib_get_num_images(w) > 1) { if (boot) { imagex_error("Cannot specify the --boot flag " - "without specifying a specific " - "image in a multi-image WIM!\n"); + "without specifying a specific " + "image in a multi-image WIM"); ret = WIMLIB_ERR_INVALID_IMAGE; goto done; } if (new_name) { imagex_error("Cannot specify the NEW_NAME " - "without specifying a specific " - "image in a multi-image WIM!\n"); + "without specifying a specific " + "image in a multi-image WIM"); ret = WIMLIB_ERR_INVALID_IMAGE; goto done; } @@ -870,8 +1027,8 @@ static int imagex_info(int argc, const char **argv) if (!new_name && !boot) { if (image == WIM_NO_IMAGE) { - imagex_error("`%s' is not a valid image!\n", - image_num_or_name); + imagex_error("`%s' is not a valid image", + image_num_or_name); ret = WIMLIB_ERR_INVALID_IMAGE; goto done; } @@ -885,8 +1042,8 @@ static int imagex_info(int argc, const char **argv) if (lookup_table) { if (total_parts != 1) { printf("Warning: Only showing the lookup table " - "for part %d of a %d-part WIM.\n", - part_number, total_parts); + "for part %d of a %d-part WIM.\n", + part_number, total_parts); } wimlib_print_lookup_table(w); } @@ -900,15 +1057,16 @@ static int imagex_info(int argc, const char **argv) if (xml_out_file) { fp = fopen(xml_out_file, "wb"); if (!fp) { - imagex_error("Failed to open the file `%s' for " - "writing: %m\n", xml_out_file); + imagex_error_with_errno("Failed to open the " + "file `%s' for " + "writing ", + xml_out_file); goto done; } ret = wimlib_extract_xml_data(w, fp); if (fclose(fp) != 0) { - imagex_error("Failed to close the " - "file `%s': %m\n", - xml_out_file); + imagex_error("Failed to close the file `%s'", + xml_out_file); goto done; } @@ -922,8 +1080,8 @@ static int imagex_info(int argc, const char **argv) if (metadata) { if (total_parts != 1 && part_number != 1) { imagex_error("Select part 1 of this %d-part WIM " - "to see the image metadata.\n", - total_parts); + "to see the image metadata", + total_parts); return WIMLIB_ERR_SPLIT_UNSUPPORTED; } ret = wimlib_print_metadata(w, image); @@ -932,7 +1090,7 @@ static int imagex_info(int argc, const char **argv) } } else { if (total_parts != 1) { - imagex_error("Modifying a split WIM is not supported.\n"); + imagex_error("Modifying a split WIM is not supported."); return -1; } if (image == WIM_ALL_IMAGES) @@ -940,18 +1098,18 @@ static int imagex_info(int argc, const char **argv) if (image == WIM_NO_IMAGE && new_name) { imagex_error("Cannot specify new_name (`%s') when " - "using image 0!\n"); + "using image 0", new_name); return -1; } if (boot) { if (image == wimlib_get_boot_idx(w)) { printf("Image %d is already marked as " - "bootable.\n", image); + "bootable.\n", image); boot = false; } else { - printf("Marking image %d as bootable.\n", - image); + printf("Marking image %d as bootable.\n", + image); wimlib_set_boot_idx(w, image); } } @@ -959,11 +1117,11 @@ static int imagex_info(int argc, const char **argv) if (strcmp(wimlib_get_image_name(w, image), new_name) == 0) { printf("Image %d is already named \"%s\".\n", - image, new_name); + image, new_name); new_name = NULL; } else { - printf("Changing the name of image %d to \"%s\".\n", - image, new_name); + printf("Changing the name of image %d to " + "\"%s\".\n", image, new_name); ret = wimlib_set_image_name(w, image, new_name); if (ret != 0) goto done; @@ -974,11 +1132,11 @@ static int imagex_info(int argc, const char **argv) old_desc = wimlib_get_image_description(w, image); if (old_desc && strcmp(old_desc, new_desc) == 0) { printf("The description of image %d is already " - "\"%s\".\n", image, new_desc); + "\"%s\".\n", image, new_desc); new_desc = NULL; } else { printf("Changing the description of image %d " - "to \"%s\".\n", image, new_desc); + "to \"%s\".\n", image, new_desc); ret = wimlib_set_image_descripton(w, image, new_desc); if (ret != 0) @@ -1026,8 +1184,8 @@ static int imagex_join(int argc, const char **argv) argv += optind; if (argc < 2) { - imagex_error("Must specify at least one split WIM " - "(.swm) parts to join!\n"); + imagex_error("Must specify at least one split WIM (.swm) parts " + "to join"); goto err; } output_path = argv[0]; @@ -1060,19 +1218,26 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) case 'd': mount_flags |= WIMLIB_MOUNT_FLAG_DEBUG; break; + case 's': + if (strcasecmp(optarg, "none") == 0) + mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE; + else if (strcasecmp(optarg, "xattr") == 0) + mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR; + else if (strcasecmp(optarg, "windows") == 0) + mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS; + else { + imagex_error("Unknown stream interface \"%s\"", optarg); + goto mount_usage; + } + break; default: - usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) - ? MOUNTRW : MOUNT); - return -1; + goto mount_usage; } } argc -= optind; argv += optind; - if (argc != 2 && argc != 3) { - usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) - ? MOUNTRW : MOUNT); - return -1; - } + if (argc != 2 && argc != 3) + goto mount_usage; wimfile = argv[0]; @@ -1085,7 +1250,7 @@ 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.\n", wimfile, num_images); + "select one", wimfile, num_images); usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) ? MOUNTRW : MOUNT); ret = WIMLIB_ERR_INVALID_IMAGE; @@ -1103,13 +1268,17 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) ret = wimlib_mount(w, image, dir, mount_flags); if (ret != 0) { - imagex_error("Failed to mount image %d from `%s' on `%s'!\n", - image, wimfile, dir); + imagex_error("Failed to mount image %d from `%s' on `%s'", + image, wimfile, dir); } done: wimlib_free(w); return ret; +mount_usage: + usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) + ? MOUNTRW : MOUNT); + return -1; } /* Split a WIM into a spanned set */ @@ -1169,7 +1338,7 @@ static int imagex_unmount(int argc, const char **argv) ret = wimlib_unmount(argv[0], unmount_flags); if (ret != 0) - imagex_error("Failed to unmount `%s'!\n", argv[0]); + imagex_error("Failed to unmount `%s'", argv[0]); return ret; } @@ -1235,7 +1404,7 @@ int main(int argc, const char **argv) int ret; if (argc < 2) { - imagex_error("No command specified!\n"); + imagex_error("No command specified"); usage_all(); return 1; } @@ -1251,14 +1420,23 @@ int main(int argc, const char **argv) ret = cmd->func(argc, argv); if (ret > 0) { imagex_error("Exiting with error code %d:\n" - " %s.\n", ret, - wimlib_get_error_string(ret)); + " %s.", ret, + wimlib_get_error_string(ret)); + if (ret == WIMLIB_ERR_NTFS_3G) + imagex_error_with_errno("errno"); } return ret; } } - imagex_error("Unrecognized command: `%s'\n", argv[0]); + imagex_error("Unrecognized command: `%s'", argv[0]); usage_all(); return 1; } +/*#ifndef WITH_NTFS_3G*/ + /*ERROR("wimlib was not compiled with support for NTFS-3g, so we cannot extract");*/ + /*ERROR("a WIM to a NTFS filesystem while preserving NTFS-specific metadata.");*/ + /*ERROR("Please apply the WIM to a directory rather than a block device, ");*/ + /*ERROR("and without the NTFS flag; or compile in support for NTFS-3g.");*/ + /*return WIMLIB_ERR_UNSUPPORTED;*/ +/*#endif*/