X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=f07b11833cf0484951de4776c2d690137e2db52a;hp=883b1e0527a55fc34f957995aec314790671582d;hb=88f30aa4a33ff4d175cd4749e84d8d373eed795f;hpb=9b9a502863318d6208da2818b1d522346e5eee9e diff --git a/programs/imagex.c b/programs/imagex.c index 883b1e05..f07b1183 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -22,26 +22,27 @@ * along with this program. If not, see . */ -#include "wimlib.h" #include "config.h" + +#include "wimlib.h" + +#include #include -#include -#include #include -#include -#include +#include #include #include +#include +#include +#include #include #include -#include #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) #define for_opt(c, opts) while ((c = getopt_long_only(argc, (char**)argv, "", \ opts, NULL)) != -1) - enum imagex_op_type { APPEND, APPLY, @@ -66,16 +67,16 @@ static const char *usage_strings[] = { "imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" " [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n" " [--verbose] [--dereference] [--config=FILE]\n" -" [--threads=NUM_THREADS] [--rebuild]\n", +" [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n", [APPLY] = "imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" " (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" -" [--symlink] [--verbose] [--ref=\"GLOB\"]\n", +" [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\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] [--threads=NUM_THREADS]\n", +" [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n", [DELETE] = "imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n", [DIR] = @@ -94,16 +95,17 @@ static const char *usage_strings[] = { [MOUNT] = "imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n" " [--check] [--debug] [--streams-interface=INTERFACE]\n" -" [--ref=\"GLOB\"]\n", +" [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n", [MOUNTRW] = "imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n" -" [--check] [--debug] [--streams-interface=INTERFACE]\n", +" [--check] [--debug] [--streams-interface=INTERFACE]\n" +" [--staging-dir=DIR] [--unix-data] [--allow-other]\n", [OPTIMIZE] = -"imagex optimize WIMFILE [--check] [--recompress]\n", +"imagex optimize WIMFILE [--check] [--recompress] [--compress=TYPE]\n", [SPLIT] = "imagex split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n", [UNMOUNT] = -"imagex unmount DIRECTORY [--commit] [--check]\n", +"imagex unmount DIRECTORY [--commit] [--check] [--rebuild]\n", }; static const struct option common_options[] = { @@ -113,11 +115,12 @@ static const struct option common_options[] = { }; static const struct option apply_options[] = { - {"check", no_argument, NULL, 'c'}, - {"hardlink", no_argument, NULL, 'h'}, - {"symlink", no_argument, NULL, 's'}, - {"verbose", no_argument, NULL, 'v'}, - {"ref", required_argument, NULL, 'r'}, + {"check", no_argument, NULL, 'c'}, + {"hardlink", no_argument, NULL, 'h'}, + {"symlink", no_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {"ref", required_argument, NULL, 'r'}, + {"unix-data", no_argument, NULL, 'U'}, {NULL, 0, NULL, 0}, }; static const struct option capture_or_append_options[] = { @@ -130,6 +133,7 @@ static const struct option capture_or_append_options[] = { {"verbose", no_argument, NULL, 'v'}, {"threads", required_argument, NULL, 't'}, {"rebuild", no_argument, NULL, 'R'}, + {"unix-data", no_argument, NULL, 'U'}, {NULL, 0, NULL, 0}, }; static const struct option delete_options[] = { @@ -165,10 +169,13 @@ static const struct option join_options[] = { }; static const struct option mount_options[] = { - {"check", no_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'd'}, + {"check", no_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, {"streams-interface", required_argument, NULL, 's'}, - {"ref", required_argument, NULL, 'r'}, + {"ref", required_argument, NULL, 'r'}, + {"staging-dir", required_argument, NULL, 'D'}, + {"unix-data", no_argument, NULL, 'U'}, + {"allow-other", no_argument, NULL, 'A'}, {NULL, 0, NULL, 0}, }; @@ -184,8 +191,9 @@ static const struct option split_options[] = { }; static const struct option unmount_options[] = { - {"commit", no_argument, NULL, 'c'}, - {"check", no_argument, NULL, 'C'}, + {"commit", no_argument, NULL, 'c'}, + {"check", no_argument, NULL, 'C'}, + {"rebuild", no_argument, NULL, 'R'}, {NULL, 0, NULL, 0}, }; @@ -272,6 +280,21 @@ static off_t file_get_size(const char *filename) return (off_t)-1; } +static const char *default_capture_config = +"[ExclusionList]\n" +"\\$ntfs.log\n" +"\\hiberfil.sys\n" +"\\pagefile.sys\n" +"\\System Volume Information\n" +"\\RECYCLER\n" +"\\Windows\\CSC\n" +"\n" +"[CompressionExclusionList]\n" +"*.mp3\n" +"*.zip\n" +"*.cab\n" +"\\WINDOWS\\inf\\*.pnf\n"; + static char *file_get_contents(const char *filename, size_t *len_ret) { struct stat stbuf; @@ -314,7 +337,7 @@ out_fclose: static int file_writable(const char *path) { int ret; - ret = access(path, F_OK | W_OK); + ret = access(path, W_OK); if (ret != 0) imagex_error_with_errno("Can't modify `%s'", path); return ret; @@ -357,12 +380,18 @@ static int imagex_progress_func(enum wimlib_progress_msg msg, info->write_streams.completed_bytes >> 20, info->write_streams.total_bytes >> 20, percent_done); - if (info->write_streams.completed_bytes == info->write_streams.total_bytes) + if (info->write_streams.completed_bytes >= info->write_streams.total_bytes) putchar('\n'); break; case WIMLIB_PROGRESS_MSG_SCAN_BEGIN: printf("Scanning `%s'...\n", info->scan.source); break; + case WIMLIB_PROGRESS_MSG_SCAN_DENTRY: + if (info->scan.excluded) + printf("Excluding `%s' from capture\n", info->scan.cur_path); + else + printf("Scanning `%s'\n", info->scan.cur_path); + break; /*case WIMLIB_PROGRESS_MSG_SCAN_END:*/ /*break;*/ case WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY: @@ -389,15 +418,14 @@ static int imagex_progress_func(enum wimlib_progress_msg msg, putchar('\n'); break; case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN: - /*printf("Applying image %d (%s) to `%s'\n",*/ - /*info->extract.image,*/ - /*info->extract.image_name,*/ - /*info->extract.target);*/ + printf("Applying image %d (%s) from `%s' to %s `%s'\n", + info->extract.image, + info->extract.image_name, + info->extract.wimfile_name, + ((info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) ? + "NTFS volume" : "directory"), + info->extract.target); break; - /*case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END:*/ - /*printf("Done applying image %d!\n",*/ - /*info->extract.image);*/ - /*break;*/ /*case WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN:*/ /*printf("Applying directory structure to %s\n",*/ /*info->extract.target);*/ @@ -410,9 +438,21 @@ static int imagex_progress_func(enum wimlib_progress_msg msg, info->extract.completed_bytes >> 20, info->extract.total_bytes >> 20, percent_done); - if (info->extract.completed_bytes == info->extract.total_bytes) + if (info->extract.completed_bytes >= info->extract.total_bytes) putchar('\n'); break; + case WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY: + puts(info->extract.cur_path); + break; + case WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS: + printf("Setting timestamps on all extracted files...\n"); + break; + case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END: + if (info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) { + printf("Unmounting NTFS volume `%s'...\n", + info->extract.target); + } + break; case WIMLIB_PROGRESS_MSG_JOIN_STREAMS: percent_done = TO_PERCENT(info->join.completed_bytes, info->join.total_bytes); @@ -554,6 +594,9 @@ static int imagex_apply(int argc, const char **argv) case 'r': swm_glob = optarg; break; + case 'U': + extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA; + break; default: usage(APPLY); return -1; @@ -601,16 +644,12 @@ static int imagex_apply(int argc, const char **argv) goto out; } -#ifdef WITH_NTFS_3G struct stat stbuf; ret = stat(target, &stbuf); if (ret == 0) { - if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) { + if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) extract_flags |= WIMLIB_EXTRACT_FLAG_NTFS; - printf("Applying `%s' image %d to NTFS volume `%s'\n", - wimfile, image, target); - } } else { if (errno != ENOENT) { imagex_error_with_errno("Failed to stat `%s'", target); @@ -618,11 +657,12 @@ static int imagex_apply(int argc, const char **argv) goto out; } } -#endif ret = wimlib_extract_image(w, image, target, extract_flags, additional_swms, num_additional_swms, imagex_progress_func); + if (ret == 0) + printf("Done applying WIM image.\n"); out: wimlib_free(w); if (additional_swms) { @@ -689,6 +729,9 @@ static int imagex_capture_or_append(int argc, const char **argv) case 'R': write_flags |= WIMLIB_WRITE_FLAG_REBUILD; break; + case 'U': + add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA; + break; default: usage(cmd); return -1; @@ -724,7 +767,6 @@ static int imagex_capture_or_append(int argc, const char **argv) if (ret != 0) goto out; -#ifdef WITH_NTFS_3G struct stat stbuf; ret = stat(source, &stbuf); @@ -741,8 +783,10 @@ static int imagex_capture_or_append(int argc, const char **argv) goto out; } } -#endif - ret = wimlib_add_image(w, source, name, config_str, config_len, + + ret = wimlib_add_image(w, source, name, + (config_str ? config_str : default_capture_config), + (config_str ? config_len : strlen(default_capture_config)), add_image_flags, imagex_progress_func); if (ret != 0) @@ -994,7 +1038,7 @@ static int imagex_export(int argc, const char **argv) ret = file_writable(dest_wimfile); if (ret != 0) - return ret; + goto out; dest_ctype = wimlib_get_compression_type(dest_w); if (compression_type_specified @@ -1006,7 +1050,6 @@ static int imagex_export(int argc, const char **argv) ret = -1; goto out; } - compression_type = dest_ctype; } else { wim_is_new = true; /* dest_wimfile is not an existing file, so create a new WIM. */ @@ -1088,6 +1131,7 @@ static int imagex_info(int argc, const char **argv) int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK; int part_number; int total_parts; + int num_images; for_opt(c, info_options) { switch (c) { @@ -1153,7 +1197,7 @@ static int imagex_info(int argc, const char **argv) image = wimlib_resolve_image(w, image_num_or_name); if (image == WIMLIB_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) { imagex_error("The image `%s' does not exist", - image_num_or_name); + image_num_or_name); if (boot) imagex_error("If you would like to set the boot " "index to 0, specify image \"0\" with " @@ -1162,7 +1206,18 @@ static int imagex_info(int argc, const char **argv) goto out; } - if (image == WIMLIB_ALL_IMAGES && wimlib_get_num_images(w) > 1) { + num_images = wimlib_get_num_images(w); + + if (num_images == 0) { + if (boot) { + imagex_error("--boot is meaningless on a WIM with no " + "images"); + ret = WIMLIB_ERR_INVALID_IMAGE; + goto out; + } + } + + if (image == WIMLIB_ALL_IMAGES && num_images > 1) { if (boot) { imagex_error("Cannot specify the --boot flag " "without specifying a specific " @@ -1220,13 +1275,14 @@ static int imagex_info(int argc, const char **argv) "file `%s' for " "writing ", xml_out_file); + ret = -1; goto out; } ret = wimlib_extract_xml_data(w, fp); if (fclose(fp) != 0) { imagex_error("Failed to close the file `%s'", xml_out_file); - goto out; + ret = -1; } if (ret != 0) @@ -1246,7 +1302,8 @@ static int imagex_info(int argc, const char **argv) /* Modification operations */ if (total_parts != 1) { imagex_error("Modifying a split WIM is not supported."); - return -1; + ret = -1; + goto out; } if (image == WIMLIB_ALL_IMAGES) image = 1; @@ -1254,7 +1311,8 @@ static int imagex_info(int argc, const char **argv) if (image == WIMLIB_NO_IMAGE && new_name) { imagex_error("Cannot specify new_name (`%s') when " "using image 0", new_name); - return -1; + ret = -1; + goto out; } if (boot) { @@ -1302,18 +1360,18 @@ static int imagex_info(int argc, const char **argv) /* Only call wimlib_overwrite() if something actually needs to * be changed. */ if (boot || new_name || new_desc || - check != wimlib_has_integrity_table(w)) { + (check && !wimlib_has_integrity_table(w))) + { + int write_flags; ret = file_writable(wimfile); if (ret != 0) return ret; - int write_flags; - if (check) { + if (check) write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; - } else { + else write_flags = 0; - } ret = wimlib_overwrite(w, write_flags, 1, imagex_progress_func); @@ -1321,7 +1379,7 @@ static int imagex_info(int argc, const char **argv) ret = 0; } else { printf("The file `%s' was not modified because nothing " - "needed to be done.\n", wimfile); + "needed to be done.\n", wimfile); ret = 0; } } @@ -1379,12 +1437,16 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) const char *swm_glob = NULL; WIMStruct **additional_swms = NULL; unsigned num_additional_swms = 0; + const char *staging_dir = NULL; if (strcmp(argv[0], "mountrw") == 0) mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE; for_opt(c, mount_options) { switch (c) { + case 'A': + mount_flags |= WIMLIB_MOUNT_FLAG_ALLOW_OTHER; + break; case 'c': open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; break; @@ -1406,6 +1468,12 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) case 'r': swm_glob = optarg; break; + case 'D': + staging_dir = optarg; + break; + case 'U': + mount_flags |= WIMLIB_MOUNT_FLAG_UNIX_DATA; + break; default: goto mount_usage; } @@ -1453,11 +1521,11 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { ret = file_writable(wimfile); if (ret != 0) - return ret; + goto out; } ret = wimlib_mount_image(w, image, dir, mount_flags, additional_swms, - num_additional_swms); + num_additional_swms, staging_dir); if (ret != 0) { imagex_error("Failed to mount image %d from `%s' on `%s'", image, wimfile, dir); @@ -1526,19 +1594,21 @@ static int imagex_optimize(int argc, const char **argv) ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func); - new_size = file_get_size(argv[0]); - printf("`%s' optimized size: ", wimfile); - if (new_size == -1) - puts("Unknown"); - else - printf("%"PRIu64" KiB\n", new_size >> 10); + if (ret == 0) { + new_size = file_get_size(argv[0]); + printf("`%s' optimized size: ", wimfile); + if (new_size == -1) + puts("Unknown"); + else + printf("%"PRIu64" KiB\n", new_size >> 10); - fputs("Space saved: ", stdout); - if (new_size != -1 && old_size != -1) { - printf("%lld KiB\n", - ((long long)old_size - (long long)new_size) >> 10); - } else { - puts("Unknown"); + fputs("Space saved: ", stdout); + if (new_size != -1 && old_size != -1) { + printf("%lld KiB\n", + ((long long)old_size - (long long)new_size) >> 10); + } else { + puts("Unknown"); + } } wimlib_free(w); @@ -1603,6 +1673,9 @@ static int imagex_unmount(int argc, const char **argv) case 'C': unmount_flags |= WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY; break; + case 'R': + unmount_flags |= WIMLIB_UNMOUNT_FLAG_REBUILD; + break; default: usage(UNMOUNT); return -1; @@ -1615,7 +1688,8 @@ static int imagex_unmount(int argc, const char **argv) return -1; } - ret = wimlib_unmount_image(argv[0], unmount_flags); + ret = wimlib_unmount_image(argv[0], unmount_flags, + imagex_progress_func); if (ret != 0) imagex_error("Failed to unmount `%s'", argv[0]); return ret; @@ -1737,22 +1811,28 @@ int main(int argc, const char **argv) argv++; wimlib_set_print_errors(true); + ret = wimlib_global_init(); + if (ret) + goto out; for_imagex_command(cmd) { if (strcmp(cmd->name, *argv) == 0) { ret = cmd->func(argc, argv); - if (ret > 0) { - 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; + goto out; } } imagex_error("Unrecognized command: `%s'", argv[0]); usage_all(); return 1; +out: + if (ret > 0) { + imagex_error("Exiting with error code %d:\n" + " %s.", ret, + wimlib_get_error_string(ret)); + if (ret == WIMLIB_ERR_NTFS_3G && errno != 0) + imagex_error_with_errno("errno"); + } + wimlib_global_cleanup(); + return ret; }