X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=2d407fac422b885dd6a4882b51abe25f93aec54c;hp=28f0266356429b91879b6d1e59f421f435bcecf5;hb=50a62891f75afdbfde97031125fbaccd4ed0419c;hpb=e3cbda91f4a1a844bc8edb5b5240b18f8261a6df diff --git a/programs/imagex.c b/programs/imagex.c index 28f02663..2d407fac 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2012-2017 Eric Biggers + * Copyright (C) 2012-2018 Eric Biggers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,6 +58,10 @@ static inline void set_fd_to_binary_mode(int fd) { } +/* NetBSD is missing getopt_long_only() but has getopt_long() */ +#ifndef HAVE_GETOPT_LONG_ONLY +# define getopt_long_only getopt_long +#endif #endif /* !__WIN32 */ /* Don't confuse the user by presenting the mounting commands on Windows when @@ -167,6 +171,7 @@ enum { IMAGEX_COMPACT_OPTION, IMAGEX_COMPRESS_OPTION, IMAGEX_CONFIG_OPTION, + IMAGEX_CREATE_OPTION, IMAGEX_DEBUG_OPTION, IMAGEX_DELTA_FROM_OPTION, IMAGEX_DEREFERENCE_OPTION, @@ -177,6 +182,7 @@ enum { IMAGEX_FORCE_OPTION, IMAGEX_HEADER_OPTION, IMAGEX_IMAGE_PROPERTY_OPTION, + IMAGEX_INCLUDE_INTEGRITY_OPTION, IMAGEX_INCLUDE_INVALID_NAMES_OPTION, IMAGEX_LAZY_OPTION, IMAGEX_METADATA_OPTION, @@ -241,6 +247,7 @@ static const struct option capture_or_append_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, {T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION}, {T("chunk-size"), required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION}, {T("solid"), no_argument, NULL, IMAGEX_SOLID_OPTION}, @@ -268,11 +275,13 @@ static const struct option capture_or_append_options[] = { {T("wimboot"), no_argument, NULL, IMAGEX_WIMBOOT_OPTION}, {T("unsafe-compact"), no_argument, NULL, IMAGEX_UNSAFE_COMPACT_OPTION}, {T("snapshot"), no_argument, NULL, IMAGEX_SNAPSHOT_OPTION}, + {T("create"), no_argument, NULL, IMAGEX_CREATE_OPTION}, {NULL, 0, NULL, 0}, }; static const struct option delete_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {T("soft"), no_argument, NULL, IMAGEX_SOFT_OPTION}, {T("unsafe-compact"), no_argument, NULL, IMAGEX_UNSAFE_COMPACT_OPTION}, {NULL, 0, NULL, 0}, @@ -291,6 +300,7 @@ static const struct option export_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, {T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION}, {T("recompress"), no_argument, NULL, IMAGEX_RECOMPRESS_OPTION}, {T("chunk-size"), required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION}, @@ -334,6 +344,7 @@ static const struct option info_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, {T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {T("extract-xml"), required_argument, NULL, IMAGEX_EXTRACT_XML_OPTION}, {T("header"), no_argument, NULL, IMAGEX_HEADER_OPTION}, {T("lookup-table"), no_argument, NULL, IMAGEX_BLOBS_OPTION}, @@ -345,6 +356,7 @@ static const struct option info_options[] = { static const struct option join_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {NULL, 0, NULL, 0}, }; @@ -365,6 +377,7 @@ static const struct option optimize_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, {T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION}, {T("recompress"), no_argument, NULL, IMAGEX_RECOMPRESS_OPTION}, {T("chunk-size"), required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION}, @@ -381,6 +394,7 @@ static const struct option optimize_options[] = { static const struct option split_options[] = { {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {NULL, 0, NULL, 0}, }; @@ -403,6 +417,7 @@ static const struct option update_options[] = { * update_command_add_option(). */ {T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION}, {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, + {T("include-integrity"), no_argument, NULL, IMAGEX_INCLUDE_INTEGRITY_OPTION}, {T("rebuild"), no_argument, NULL, IMAGEX_REBUILD_OPTION}, {T("command"), required_argument, NULL, IMAGEX_COMMAND_OPTION}, {T("wimboot-config"), required_argument, NULL, IMAGEX_WIMBOOT_CONFIG_OPTION}, @@ -1840,14 +1855,18 @@ out_usage: goto out_free_refglobs; } -/* Create a WIM image from a directory tree, NTFS volume, or multiple files or - * directory trees. 'wimlib-imagex capture': create a new WIM file containing - * the desired image. 'wimlib-imagex append': add a new image to an existing - * WIM file. */ +/* + * Create a WIM image from a directory tree, NTFS volume, or multiple files or + * directory trees. 'wimcapture': create a new WIM file containing the desired + * image. 'wimappend': add a new image to an existing WIM file; or, with + * '--create' behave like 'wimcapture' if the WIM file doesn't exist. + */ static int imagex_capture_or_append(int argc, tchar **argv, int cmd) { int c; + bool create = false; + bool appending = (cmd == CMD_APPEND); int open_flags = 0; int add_flags = WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE | WIMLIB_ADD_FLAG_WINCONFIG | @@ -1867,7 +1886,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) STRING_LIST(base_wimfiles); WIMStruct **base_wims; - WIMStruct *template_wim; + WIMStruct *template_wim = NULL; const tchar *template_wimfile = NULL; const tchar *template_image_name_or_num = NULL; int template_image = WIMLIB_NO_IMAGE; @@ -1895,6 +1914,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) break; case IMAGEX_CHECK_OPTION: open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case IMAGEX_NOCHECK_OPTION: @@ -1999,6 +2020,9 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) template_image_name_or_num = optarg; } } + #ifdef __WIN32__ + imagex_printf(T("[WARNING] '--update-of' is unreliable on Windows!\n")); + #endif break; case IMAGEX_DELTA_FROM_OPTION: ret = string_list_append(&base_wimfiles, optarg); @@ -2010,16 +2034,18 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) add_flags |= WIMLIB_ADD_FLAG_WIMBOOT; break; case IMAGEX_UNSAFE_COMPACT_OPTION: - if (cmd != CMD_APPEND) { - imagex_error(T("'--unsafe-compact' is only " - "valid for append!")); - goto out_err; - } write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT; break; case IMAGEX_SNAPSHOT_OPTION: add_flags |= WIMLIB_ADD_FLAG_SNAPSHOT; break; + case IMAGEX_CREATE_OPTION: + if (cmd == CMD_CAPTURE) { + imagex_error(T("'--create' is only valid for 'wimappend', not 'wimcapture'")); + goto out_err; + } + create = true; + break; default: goto out_usage; } @@ -2054,6 +2080,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) if (!tstrcmp(wimfile, T("-"))) { /* Writing captured WIM to standard output. */ + if (create) + appending = false; #if 0 if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) { imagex_error("Can't write a non-pipable WIM to " @@ -2065,7 +2093,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) #else write_flags |= WIMLIB_WRITE_FLAG_PIPABLE; #endif - if (cmd == CMD_APPEND) { + if (appending) { imagex_error(T("Using standard output for append does " "not make sense.")); goto out_err; @@ -2074,6 +2102,28 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) wimfile = NULL; imagex_output_to_stderr(); set_fd_to_binary_mode(wim_fd); + } else { + struct stat stbuf; + + /* Check for 'wimappend --create' acting as wimcapture */ + if (create && tstat(wimfile, &stbuf) != 0 && errno == ENOENT) { + + appending = false; + + /* Ignore '--update-of' for the target WIMFILE */ + if (template_image_name_or_num && + (!template_wimfile || + !tstrcmp(template_wimfile, wimfile))) + { + template_image_name_or_num = NULL; + template_wimfile = NULL; + } + } + } + + if ((write_flags & WIMLIB_WRITE_FLAG_UNSAFE_COMPACT) && !appending) { + imagex_error(T("'--unsafe-compact' is only valid for append!")); + goto out_err; } /* If template image was specified using --update-of=IMAGE rather @@ -2083,7 +2133,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) /* Capturing delta WIM based on single WIM: default to * base WIM. */ template_wimfile = base_wimfiles.strings[0]; - } else if (cmd == CMD_APPEND) { + } else if (appending) { /* Appending to WIM: default to WIM being appended to. */ template_wimfile = wimfile; @@ -2161,7 +2211,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) } /* Open the existing WIM, or create a new one. */ - if (cmd == CMD_APPEND) { + if (appending) { ret = wimlib_open_wim_with_progress(wimfile, open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS, &wim, @@ -2185,7 +2235,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) int ctype = compression_type; - if (cmd == CMD_APPEND) { + if (appending) { struct wimlib_wim_info info; wimlib_get_wim_info(wim, &info); ctype = info.compression_type; @@ -2234,7 +2284,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) /* If the user did not specify an image name, and the basename of the * source already exists as an image name in the WIM file, append a * suffix to make it unique. */ - if (cmd == CMD_APPEND && name_defaulted) { + if (appending && name_defaulted) { unsigned long conflict_idx; tchar *name_end = tstrchr(name, T('\0')); for (conflict_idx = 1; @@ -2286,13 +2336,19 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) * open the WIM if needed and parse the image index. */ if (template_image_name_or_num) { - - if (base_wimfiles.num_strings == 1 && - template_wimfile == base_wimfiles.strings[0]) { - template_wim = base_wims[0]; - } else if (template_wimfile == wimfile) { + if (appending && !tstrcmp(template_wimfile, wimfile)) { template_wim = wim; } else { + for (size_t i = 0; i < base_wimfiles.num_strings; i++) { + if (!tstrcmp(template_wimfile, + base_wimfiles.strings[i])) { + template_wim = base_wims[i]; + break; + } + } + } + + if (!template_wim) { ret = wimlib_open_wim_with_progress(template_wimfile, open_flags, &template_wim, @@ -2324,8 +2380,6 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) template_wimfile); if (ret) goto out_free_template_wim; - } else { - template_wim = NULL; } ret = wimlib_add_image_multisource(wim, @@ -2367,7 +2421,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) /* Write the new WIM or overwrite the existing WIM with the new image * appended. */ - if (cmd == CMD_APPEND) { + if (appending) { ret = wimlib_overwrite(wim, write_flags, num_threads); } else if (wimfile) { ret = wimlib_write(wim, wimfile, WIMLIB_ALL_IMAGES, @@ -2377,10 +2431,13 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) write_flags, num_threads); } out_free_template_wim: - /* template_wim may alias base_wims[0] or wim. */ - if ((base_wimfiles.num_strings != 1 || template_wim != base_wims[0]) && - template_wim != wim) - wimlib_free(template_wim); + /* 'template_wim' may alias 'wim' or any of the 'base_wims' */ + if (template_wim == wim) + goto out_free_base_wims; + for (size_t i = 0; i < base_wimfiles.num_strings; i++) + if (template_wim == base_wims[i]) + goto out_free_base_wims; + wimlib_free(template_wim); out_free_base_wims: for (size_t i = 0; i < base_wimfiles.num_strings; i++) wimlib_free(base_wims[i]); @@ -2421,6 +2478,8 @@ imagex_delete(int argc, tchar **argv, int cmd) switch (c) { case IMAGEX_CHECK_OPTION: open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case IMAGEX_SOFT_OPTION: @@ -2882,6 +2941,8 @@ imagex_export(int argc, tchar **argv, int cmd) break; case IMAGEX_CHECK_OPTION: open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case IMAGEX_NOCHECK_OPTION: @@ -3282,9 +3343,15 @@ imagex_extract(int argc, tchar **argv, int cmd) argc -= num_paths; argv += num_paths; } else { + const tchar *listfile = argv[0] + 1; + + if (!tstrcmp(listfile, T("-"))) { + tputs(T("Reading pathlist file from standard input...")); + listfile = NULL; + } + ret = wimlib_extract_pathlist(wim, image, dest_dir, - argv[0] + 1, - extract_flags); + listfile, extract_flags); argc--; argv++; } @@ -3337,8 +3404,6 @@ imagex_info(int argc, tchar **argv, int cmd) { int c; bool boot = false; - bool check = false; - bool nocheck = false; bool header = false; bool blobs = false; bool xml = false; @@ -3351,6 +3416,7 @@ imagex_info(int argc, tchar **argv, int cmd) int image; int ret; int open_flags = 0; + int write_flags = 0; struct wimlib_wim_info info; for_opt(c, info_options) { @@ -3359,10 +3425,13 @@ imagex_info(int argc, tchar **argv, int cmd) boot = true; break; case IMAGEX_CHECK_OPTION: - check = true; + open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: + write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case IMAGEX_NOCHECK_OPTION: - nocheck = true; + write_flags |= WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY; break; case IMAGEX_HEADER_OPTION: header = true; @@ -3416,14 +3485,6 @@ imagex_info(int argc, tchar **argv, int cmd) goto out; } - if (check && nocheck) { - imagex_error(T("Can't specify both --check and --nocheck")); - goto out_err; - } - - if (check) - open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; - ret = wimlib_open_wim_with_progress(wimfile, open_flags, &wim, imagex_progress_func, NULL); if (ret) @@ -3561,15 +3622,11 @@ imagex_info(int argc, tchar **argv, int cmd) /* Only call wimlib_overwrite() if something actually needs to * be changed. */ if (boot || any_property_changes || - (check && !info.has_integrity_table) || - (nocheck && info.has_integrity_table)) + ((write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) && + !info.has_integrity_table) || + ((write_flags & WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY) && + info.has_integrity_table)) { - int write_flags = 0; - - if (check) - write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; - if (nocheck) - write_flags |= WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY; ret = wimlib_overwrite(wim, write_flags, 1); } else { imagex_printf(T("The file \"%"TS"\" was not modified " @@ -3586,7 +3643,6 @@ out: out_usage: usage(CMD_INFO, stderr); -out_err: ret = -1; goto out; } @@ -3605,6 +3661,8 @@ imagex_join(int argc, tchar **argv, int cmd) switch (c) { case IMAGEX_CHECK_OPTION: swm_open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: wim_write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; default: @@ -3785,6 +3843,8 @@ imagex_optimize(int argc, tchar **argv, int cmd) switch (c) { case IMAGEX_CHECK_OPTION: open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case IMAGEX_NOCHECK_OPTION: @@ -3932,6 +3992,8 @@ imagex_split(int argc, tchar **argv, int cmd) switch (c) { case IMAGEX_CHECK_OPTION: open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; default: @@ -4077,6 +4139,8 @@ imagex_update(int argc, tchar **argv, int cmd) break; case IMAGEX_CHECK_OPTION: open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY; + /* fall-through */ + case IMAGEX_INCLUDE_INTEGRITY_OPTION: write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; break; case IMAGEX_REBUILD_OPTION: @@ -4397,7 +4461,7 @@ T( " [--threads=NUM_THREADS] [--no-acls] [--strict-acls]\n" " [--rpfix] [--norpfix] [--update-of=[WIMFILE:]IMAGE]\n" " [--delta-from=WIMFILE] [--wimboot] [--unix-data]\n" -" [--dereference] [--snapshot]\n" +" [--dereference] [--snapshot] [--create]\n" ), [CMD_APPLY] = T( @@ -4520,23 +4584,19 @@ static const tchar *get_cmd_string(int cmd, bool only_short_form) static void version(void) { - uint32_t vers = wimlib_get_version(); - static const tchar * const fmt = T( -"wimlib-imagex " PACKAGE_VERSION " (using wimlib %u.%u.%u)\n" -"Copyright (C) 2012-2017 Eric Biggers\n" +"wimlib-imagex " PACKAGE_VERSION " (using wimlib %"TS")\n" +"Copyright (C) 2012-2018 Eric Biggers\n" "License GPLv3+; GNU GPL version 3 or later .\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n" "\n" "Report bugs to "PACKAGE_BUGREPORT".\n" ); - tfprintf(stdout, fmt, - vers >> 20, (vers >> 10) & 0x3ff, vers & 0x3ff); + tfprintf(stdout, fmt, wimlib_get_version_string()); } - static void do_common_options(int *argc_p, tchar **argv, int cmd) {