X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=d41964a22ba384b9bd514b3c7209c8eae8546df9;hp=a1b9cea29654fce6423005309277ba4ee73f0056;hb=5d1e60d65eed94e7d2acae5dc4e9e95563e571ab;hpb=6f7956a06fcf92a304fae93e393e8eaee34e92d5 diff --git a/programs/imagex.c b/programs/imagex.c index a1b9cea2..d41964a2 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 EDITIONID]\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 \"EditionID\"] [--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", [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}, }; @@ -274,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) @@ -289,6 +297,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; @@ -300,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) { @@ -313,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); @@ -337,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; } @@ -355,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; @@ -365,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); @@ -406,12 +496,12 @@ 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) { @@ -419,15 +509,31 @@ static int imagex_apply(int argc, const char **argv) "(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; } @@ -439,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) { @@ -457,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); @@ -494,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'", dir); - 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_write(w, wimfile, WIM_ALL_IMAGES, write_flags); if (ret != 0) imagex_error("Failed to write the WIM file `%s'", wimfile); -done: +out: wimlib_free(w); return ret; } @@ -646,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; @@ -701,7 +846,7 @@ 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)) { + if (!S_ISREG(stbuf.st_mode) && !S_ISLNK(stbuf.st_mode)) { imagex_error("`%s' is not a regular file", dest_wimfile); goto done; @@ -715,6 +860,7 @@ static int imagex_export(int argc, const char **argv) imagex_error("Cannot specify a compression type that is " "not the same as that used in the " "destination WIM"); + ret = -1; goto done; } compression_type = wimlib_get_compression_type(dest_w); @@ -1072,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]; @@ -1122,6 +1275,10 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) 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 */ @@ -1265,6 +1422,8 @@ int main(int argc, const char **argv) imagex_error("Exiting with error code %d:\n" " %s.", ret, wimlib_get_error_string(ret)); + if (ret == WIMLIB_ERR_NTFS_3G) + imagex_error_with_errno("errno"); } return ret; } @@ -1274,3 +1433,10 @@ int main(int argc, const char **argv) 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*/