X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=f8ffc7c1bce4190868f4aa88a79b852a792dfdec;hp=c5a653a68e002cd34ce32057defc4f55a1e49a82;hb=5d52d8c322857646dec623cedc35796dc135e2b9;hpb=bbe43744afc43b836e8c24250ea70e59b1ff137a diff --git a/programs/imagex.c b/programs/imagex.c index c5a653a6..f8ffc7c1 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -22,7 +22,10 @@ * along with this program. If not, see . */ -#include "config.h" +#ifdef HAVE_CONFIG_H +# include "config.h" /* Need for PACKAGE_VERSION, etc. */ +#endif + #include "wimlib.h" #include "wimlib_tchar.h" @@ -40,7 +43,7 @@ #include #ifdef HAVE_ALLOCA_H -#include +# include #endif #ifdef __WIN32__ @@ -80,7 +83,7 @@ enum imagex_op_type { }; static void usage(int cmd_type); -static void usage_all(); +static void usage_all(void); static bool imagex_be_quiet = false; @@ -101,6 +104,7 @@ IMAGEX_PROGNAME" apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" " (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" " [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n" " [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n" +" [--including-invalid-names]\n" ), [CAPTURE] = T( @@ -131,6 +135,7 @@ T( IMAGEX_PROGNAME" extract WIMFILE (IMAGE_NUM | IMAGE_NAME) [PATH...]\n" " [--check] [--ref=\"GLOB\"] [--verbose] [--unix-data]\n" " [--no-acls] [--strict-acls] [--to-stdout] [--dest-dir=DIR]\n" +" [--including-invalid-names]\n" ), [INFO] = T( @@ -165,13 +170,13 @@ IMAGEX_PROGNAME" split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n" ), [UNMOUNT] = T( -IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild]\n" +IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild] [--lazy]\n" ), [UPDATE] = T( IMAGEX_PROGNAME" update WIMFILE [IMAGE_NUM | IMAGE_NAME] [--check] [--rebuild]\n" " [--threads=NUM_THREADS] [DEFAULT_ADD_OPTIONS]\n" -" [DEFAULT_DELETE_OPTIONS] < CMDFILE\n" +" [DEFAULT_DELETE_OPTIONS] [--command=STRING] [< CMDFILE]\n" ), }; @@ -194,6 +199,7 @@ enum { IMAGEX_ALLOW_OTHER_OPTION, IMAGEX_BOOT_OPTION, IMAGEX_CHECK_OPTION, + IMAGEX_COMMAND_OPTION, IMAGEX_COMMIT_OPTION, IMAGEX_COMPRESS_OPTION, IMAGEX_CONFIG_OPTION, @@ -205,6 +211,8 @@ enum { IMAGEX_FORCE_OPTION, IMAGEX_HARDLINK_OPTION, IMAGEX_HEADER_OPTION, + IMAGEX_INCLUDING_INVALID_NAMES_OPTION, + IMAGEX_LAZY_OPTION, IMAGEX_LOOKUP_TABLE_OPTION, IMAGEX_METADATA_OPTION, IMAGEX_NORPFIX_OPTION, @@ -239,6 +247,7 @@ static const struct option apply_options[] = { {T("strict-acls"), no_argument, NULL, IMAGEX_STRICT_ACLS_OPTION}, {T("rpfix"), no_argument, NULL, IMAGEX_RPFIX_OPTION}, {T("norpfix"), no_argument, NULL, IMAGEX_NORPFIX_OPTION}, + {T("including-invalid-names"), no_argument, NULL, IMAGEX_INCLUDING_INVALID_NAMES_OPTION}, {NULL, 0, NULL, 0}, }; static const struct option capture_or_append_options[] = { @@ -286,6 +295,7 @@ static const struct option extract_options[] = { {T("strict-acls"), no_argument, NULL, IMAGEX_STRICT_ACLS_OPTION}, {T("dest-dir"), required_argument, NULL, IMAGEX_DEST_DIR_OPTION}, {T("to-stdout"), no_argument, NULL, IMAGEX_TO_STDOUT_OPTION}, + {T("including-invalid-names"), no_argument, NULL, IMAGEX_INCLUDING_INVALID_NAMES_OPTION}, {NULL, 0, NULL, 0}, }; @@ -332,6 +342,7 @@ static const struct option unmount_options[] = { {T("commit"), no_argument, NULL, IMAGEX_COMMIT_OPTION}, {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("rebuild"), no_argument, NULL, IMAGEX_REBUILD_OPTION}, + {T("lazy"), no_argument, NULL, IMAGEX_LAZY_OPTION}, {NULL, 0, NULL, 0}, }; @@ -343,6 +354,7 @@ static const struct option update_options[] = { {T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION}, {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("rebuild"), no_argument, NULL, IMAGEX_REBUILD_OPTION}, + {T("command"), required_argument, NULL, IMAGEX_COMMAND_OPTION}, /* Default delete options */ {T("force"), no_argument, NULL, IMAGEX_FORCE_OPTION}, @@ -358,6 +370,7 @@ static const struct option update_options[] = { {T("noacls"), no_argument, NULL, IMAGEX_NO_ACLS_OPTION}, {T("no-acls"), no_argument, NULL, IMAGEX_NO_ACLS_OPTION}, {T("strict-acls"), no_argument, NULL, IMAGEX_STRICT_ACLS_OPTION}, + {NULL, 0, NULL, 0}, }; @@ -994,16 +1007,41 @@ get_data_type(int ctype) return NULL; } +#define GIBIBYTE_MIN_NBYTES 10000000000ULL +#define MEBIBYTE_MIN_NBYTES 10000000ULL +#define KIBIBYTE_MIN_NBYTES 10000ULL + +static unsigned +get_unit(uint64_t total_bytes, const tchar **name_ret) +{ + if (total_bytes >= GIBIBYTE_MIN_NBYTES) { + *name_ret = T("GiB"); + return 30; + } else if (total_bytes >= MEBIBYTE_MIN_NBYTES) { + *name_ret = T("MiB"); + return 20; + } else if (total_bytes >= KIBIBYTE_MIN_NBYTES) { + *name_ret = T("KiB"); + return 10; + } else { + *name_ret = T("bytes"); + return 0; + } +} + /* Progress callback function passed to various wimlib functions. */ static int imagex_progress_func(enum wimlib_progress_msg msg, const union wimlib_progress_info *info) { unsigned percent_done; + unsigned unit_shift; + const tchar *unit_name; if (imagex_be_quiet) return 0; switch (msg) { case WIMLIB_PROGRESS_MSG_WRITE_STREAMS: + unit_shift = get_unit(info->write_streams.total_bytes, &unit_name); percent_done = TO_PERCENT(info->write_streams.completed_bytes, info->write_streams.total_bytes); if (info->write_streams.completed_streams == 0) { @@ -1014,10 +1052,12 @@ imagex_progress_func(enum wimlib_progress_msg msg, data_type, info->write_streams.num_threads, (info->write_streams.num_threads == 1) ? T("") : T("s")); } - tprintf(T("\r%"PRIu64" MiB of %"PRIu64" MiB (uncompressed) " + tprintf(T("\r%"PRIu64" %"TS" of %"PRIu64" %"TS" (uncompressed) " "written (%u%% done)"), - info->write_streams.completed_bytes >> 20, - info->write_streams.total_bytes >> 20, + info->write_streams.completed_bytes >> unit_shift, + unit_name, + info->write_streams.total_bytes >> unit_shift, + unit_name, percent_done); if (info->write_streams.completed_bytes >= info->write_streams.total_bytes) tputchar(T('\n')); @@ -1040,24 +1080,30 @@ imagex_progress_func(enum wimlib_progress_msg msg, /*case WIMLIB_PROGRESS_MSG_SCAN_END:*/ /*break;*/ case WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY: + unit_shift = get_unit(info->integrity.total_bytes, &unit_name); percent_done = TO_PERCENT(info->integrity.completed_bytes, info->integrity.total_bytes); - tprintf(T("\rVerifying integrity of \"%"TS"\": %"PRIu64" MiB " - "of %"PRIu64" MiB (%u%%) done"), + tprintf(T("\rVerifying integrity of \"%"TS"\": %"PRIu64" "TS" " + "of %"PRIu64" "TS" (%u%%) done"), info->integrity.filename, - info->integrity.completed_bytes >> 20, - info->integrity.total_bytes >> 20, + info->integrity.completed_bytes >> unit_shift, + unit_name, + info->integrity.total_bytes >> unit_shift, + unit_name, percent_done); if (info->integrity.completed_bytes == info->integrity.total_bytes) tputchar(T('\n')); break; case WIMLIB_PROGRESS_MSG_CALC_INTEGRITY: + unit_shift = get_unit(info->integrity.total_bytes, &unit_name); percent_done = TO_PERCENT(info->integrity.completed_bytes, info->integrity.total_bytes); - tprintf(T("\rCalculating integrity table for WIM: %"PRIu64" MiB " - "of %"PRIu64" MiB (%u%%) done"), - info->integrity.completed_bytes >> 20, - info->integrity.total_bytes >> 20, + tprintf(T("\rCalculating integrity table for WIM: %"PRIu64" %"TS" " + "of %"PRIu64" %"TS" (%u%%) done"), + info->integrity.completed_bytes >> unit_shift, + unit_name, + info->integrity.total_bytes >> unit_shift, + unit_name, percent_done); if (info->integrity.completed_bytes == info->integrity.total_bytes) tputchar(T('\n')); @@ -1088,10 +1134,13 @@ imagex_progress_func(enum wimlib_progress_msg msg, case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS: percent_done = TO_PERCENT(info->extract.completed_bytes, info->extract.total_bytes); + unit_shift = get_unit(info->extract.total_bytes, &unit_name); tprintf(T("\rExtracting files: " - "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done"), - info->extract.completed_bytes >> 20, - info->extract.total_bytes >> 20, + "%"PRIu64" %"TS" of %"PRIu64" %"TS" (%u%%) done"), + info->extract.completed_bytes >> unit_shift, + unit_name, + info->extract.total_bytes >> unit_shift, + unit_name, percent_done); if (info->extract.completed_bytes >= info->extract.total_bytes) tputchar(T('\n')); @@ -1112,23 +1161,29 @@ imagex_progress_func(enum wimlib_progress_msg msg, case WIMLIB_PROGRESS_MSG_JOIN_STREAMS: percent_done = TO_PERCENT(info->join.completed_bytes, info->join.total_bytes); + unit_shift = get_unit(info->join.total_bytes, &unit_name); tprintf(T("Writing resources from part %u of %u: " - "%"PRIu64 " MiB of %"PRIu64" MiB (%u%%) written\n"), + "%"PRIu64 " %"TS" of %"PRIu64" %"TS" (%u%%) written\n"), (info->join.completed_parts == info->join.total_parts) ? info->join.completed_parts : info->join.completed_parts + 1, info->join.total_parts, - info->join.completed_bytes >> 20, - info->join.total_bytes >> 20, + info->join.completed_bytes >> unit_shift, + unit_name, + info->join.total_bytes >> unit_shift, + unit_name, percent_done); break; case WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART: percent_done = TO_PERCENT(info->split.completed_bytes, info->split.total_bytes); - tprintf(T("Writing \"%"TS"\": %"PRIu64" MiB of " - "%"PRIu64" MiB (%u%%) written\n"), + unit_shift = get_unit(info->split.total_bytes, &unit_name); + tprintf(T("Writing \"%"TS"\": %"PRIu64" %"TS" of " + "%"PRIu64" %"TS" (%u%%) written\n"), info->split.part_name, - info->split.completed_bytes >> 20, - info->split.total_bytes >> 20, + info->split.completed_bytes >> unit_shift, + unit_name, + info->split.total_bytes >> unit_shift, + unit_name, percent_done); break; case WIMLIB_PROGRESS_MSG_SPLIT_END_PART: @@ -1481,6 +1536,10 @@ imagex_apply(int argc, tchar **argv) case IMAGEX_RPFIX_OPTION: extract_flags |= WIMLIB_EXTRACT_FLAG_RPFIX; break; + case IMAGEX_INCLUDING_INVALID_NAMES_OPTION: + extract_flags |= WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES; + extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS; + break; default: usage(APPLY); return -1; @@ -1514,7 +1573,7 @@ imagex_apply(int argc, tchar **argv) num_images = wimlib_get_num_images(w); if (argc == 2 && num_images != 1) { imagex_error(T("\"%"TS"\" contains %d images; Please select one " - "(or all)"), wimfile, num_images); + "(or all)."), wimfile, num_images); usage(APPLY); ret = -1; goto out; @@ -1923,7 +1982,7 @@ imagex_dir(int argc, tchar **argv) * choose that one; otherwise, print an error. */ num_images = wimlib_get_num_images(w); if (num_images != 1) { - imagex_error(T("The file \"%"TS"\" contains %d images; Please " + imagex_error(T("\"%"TS"\" contains %d images; Please " "select one."), wimfile, num_images); usage(DIR); ret = -1; @@ -2212,6 +2271,10 @@ imagex_extract(int argc, tchar **argv) extract_flags |= WIMLIB_EXTRACT_FLAG_TO_STDOUT; imagex_be_quiet = true; break; + case IMAGEX_INCLUDING_INVALID_NAMES_OPTION: + extract_flags |= WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES; + extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS; + break; default: goto out_usage; } @@ -2694,7 +2757,7 @@ imagex_mount_rw_or_ro(int argc, tchar **argv) image = 1; num_images = wimlib_get_num_images(w); if (num_images != 1) { - imagex_error(T("The file \"%"TS"\" contains %d images; Please " + imagex_error(T("\"%"TS"\" contains %d images; Please " "select one."), wimfile, num_images); usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) ? MOUNTRW : MOUNT); @@ -2781,9 +2844,13 @@ imagex_optimize(int argc, tchar **argv) wimfile = argv[0]; + ret = file_writable(wimfile); + if (ret) + return ret; + ret = wimlib_open_wim(wimfile, open_flags, &w, imagex_progress_func); - if (ret != 0) + if (ret) return ret; old_size = file_get_size(argv[0]); @@ -2881,6 +2948,9 @@ imagex_unmount(int argc, tchar **argv) case IMAGEX_REBUILD_OPTION: unmount_flags |= WIMLIB_UNMOUNT_FLAG_REBUILD; break; + case IMAGEX_LAZY_OPTION: + unmount_flags |= WIMLIB_UNMOUNT_FLAG_LAZY; + break; default: usage(UNMOUNT); return -1; @@ -2918,10 +2988,12 @@ imagex_update(int argc, tchar **argv) int default_delete_flags = 0; unsigned num_threads = 0; int c; - tchar *cmd_file_contents; + tchar *cmd_file_contents = NULL; size_t cmd_file_nchars; struct wimlib_update_command *cmds; size_t num_cmds; + int num_images; + tchar *command_str = NULL; const tchar *config_file = NULL; tchar *config_str; @@ -2944,7 +3016,22 @@ imagex_update(int argc, tchar **argv) case IMAGEX_REBUILD_OPTION: write_flags |= WIMLIB_WRITE_FLAG_REBUILD; break; - + case IMAGEX_COMMAND_OPTION: + if (command_str) { + imagex_error(T("--command may only be specified " + "one time. Please provide\n" + " the update commands " + "on standard input instead.")); + ret = -1; + goto out; + } + command_str = tstrdup(optarg); + if (!command_str) { + imagex_error(T("Out of memory!")); + ret = -1; + goto out; + } + break; /* Default delete options */ case IMAGEX_FORCE_OPTION: default_delete_flags |= WIMLIB_DELETE_FLAG_FORCE; @@ -2984,6 +3071,11 @@ imagex_update(int argc, tchar **argv) if (argc < 1 || argc > 2) goto out_usage; wimfile = argv[0]; + + ret = file_writable(wimfile); + if (ret) + goto out; + ret = wimlib_open_wim(wimfile, open_flags, &wim, imagex_progress_func); if (ret) goto out; @@ -3000,6 +3092,15 @@ imagex_update(int argc, tchar **argv) if (ret) goto out_wimlib_free; + num_images = wimlib_get_num_images(wim); + if (argc == 1 && num_images != 1) { + imagex_error(T("\"%"TS"\" contains %d images; Please select one."), + wimfile, num_images); + usage(UPDATE); + ret = -1; + goto out_wimlib_free; + } + /* Parse capture configuration file if specified */ if (config_file) { size_t config_len; @@ -3018,20 +3119,26 @@ imagex_update(int argc, tchar **argv) config = &default_capture_config; } - /* Read update commands from standard input */ - if (isatty(STDIN_FILENO)) { - tputs(T("Reading update commands from standard input...")); - recommend_man_page(T("update")); - } - cmd_file_contents = stdin_get_text_contents(&cmd_file_nchars); - if (!cmd_file_contents) { - ret = -1; - goto out_free_config; - } + /* Read update commands from standard input, or the command string if + * specified. */ + if (command_str) { + cmds = parse_update_command_file(&command_str, tstrlen(command_str), + &num_cmds); + } else { + if (isatty(STDIN_FILENO)) { + tputs(T("Reading update commands from standard input...")); + recommend_man_page(T("update")); + } + cmd_file_contents = stdin_get_text_contents(&cmd_file_nchars); + if (!cmd_file_contents) { + ret = -1; + goto out_free_config; + } - /* Parse the update commands */ - cmds = parse_update_command_file(&cmd_file_contents, cmd_file_nchars, - &num_cmds); + /* Parse the update commands */ + cmds = parse_update_command_file(&cmd_file_contents, cmd_file_nchars, + &num_cmds); + } if (!cmds) { ret = -1; goto out_free_cmd_file_contents; @@ -3052,15 +3159,23 @@ imagex_update(int argc, tchar **argv) } } +#ifdef __WIN32__ + win32_acquire_capture_privileges(); +#endif + /* Execute the update commands */ ret = wimlib_update_image(wim, image, cmds, num_cmds, update_flags, imagex_progress_func); if (ret) - goto out_free_cmds; + goto out_release_privs; /* Overwrite the updated WIM */ ret = wimlib_overwrite(wim, write_flags, num_threads, imagex_progress_func); +out_release_privs: +#ifdef __WIN32__ + win32_release_capture_privileges(); +#endif out_free_cmds: free(cmds); out_free_cmd_file_contents: @@ -3074,6 +3189,7 @@ out_free_config: out_wimlib_free: wimlib_free(wim); out: + free(command_str); return ret; out_usage: usage(UPDATE); @@ -3110,7 +3226,7 @@ static const struct imagex_command imagex_commands[] = { }; static void -version() +version(void) { static const tchar *s = T( @@ -3173,7 +3289,7 @@ usage(int cmd_type) } static void -usage_all() +usage_all(void) { tfputs(T("Usage:\n"), stdout); for (int i = 0; i < ARRAY_LEN(usage_strings); i++)