X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=programs%2Fimagex.c;h=a10ac488fdfbc4bb66949fdeae18a3193f253890;hb=HEAD;hp=809836cd70b09558937600aae4a5547e87ee6e3b;hpb=eaccd7008cc9b7a976de87d30a7f64ccd421148a;p=wimlib diff --git a/programs/imagex.c b/programs/imagex.c index 809836cd..54e50bfc 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2012-2021 Eric Biggers + * Copyright 2012-2023 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 @@ -19,7 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H @@ -48,10 +48,10 @@ #define WIMLIB_COMPRESSION_TYPE_INVALID (-1) -#ifdef __WIN32__ +#ifdef _WIN32 # include "imagex-win32.h" # define print_security_descriptor win32_print_security_descriptor -#else /* __WIN32__ */ +#else /* _WIN32 */ # include # include # define print_security_descriptor default_print_security_descriptor @@ -62,13 +62,13 @@ static inline void set_fd_to_binary_mode(int fd) #ifndef HAVE_GETOPT_LONG_ONLY # define getopt_long_only getopt_long #endif -#endif /* !__WIN32 */ +#endif /* !_WIN32 */ /* Don't confuse the user by presenting the mounting commands on Windows when * they will never work. However on UNIX-like systems we always present them, * even if WITH_FUSE is not defined at this point, as to not tie the build of * wimlib-imagex to a specific build of wimlib. */ -#ifdef __WIN32__ +#ifdef _WIN32 # define WIM_MOUNTING_SUPPORTED 0 #else # define WIM_MOUNTING_SUPPORTED 1 @@ -416,14 +416,14 @@ static const struct option unmount_options[] = { static const struct option update_options[] = { /* Careful: some of the options here set the defaults for update * commands, but the flags given to an actual update command (and not to - * `imagex update' itself are also handled in - * update_command_add_option(). */ + * wimupdate itself) are also handled in 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}, + {T("ref"), required_argument, NULL, IMAGEX_REF_OPTION}, /* Default delete options */ {T("force"), no_argument, NULL, IMAGEX_FORCE_OPTION}, @@ -968,152 +968,6 @@ parse_source_list(tchar **source_list_contents_p, size_t source_list_nchars, return sources; } -/* Reads the contents of a file into memory. */ -static char * -file_get_contents(const tchar *filename, size_t *len_ret) -{ - struct stat stbuf; - void *buf = NULL; - size_t len; - FILE *fp; - - if (tstat(filename, &stbuf) != 0) { - imagex_error_with_errno(T("Failed to stat the file \"%"TS"\""), filename); - goto out; - } - len = stbuf.st_size; - - fp = tfopen(filename, T("rb")); - if (!fp) { - imagex_error_with_errno(T("Failed to open the file \"%"TS"\""), filename); - goto out; - } - - buf = malloc(len ? len : 1); - if (!buf) { - imagex_error(T("Failed to allocate buffer of %zu bytes to hold " - "contents of file \"%"TS"\""), len, filename); - goto out_fclose; - } - if (fread(buf, 1, len, fp) != len) { - imagex_error_with_errno(T("Failed to read %zu bytes from the " - "file \"%"TS"\""), len, filename); - goto out_free_buf; - } - *len_ret = len; - goto out_fclose; -out_free_buf: - free(buf); - buf = NULL; -out_fclose: - fclose(fp); -out: - return buf; -} - -/* Read standard input until EOF and return the full contents in a malloc()ed - * buffer and the number of bytes of data in @len_ret. Returns NULL on read - * error. */ -static char * -stdin_get_contents(size_t *len_ret) -{ - /* stdin can, of course, be a pipe or other non-seekable file, so the - * total length of the data cannot be pre-determined */ - char *buf = NULL; - size_t newlen = 1024; - size_t pos = 0; - size_t inc = 1024; - for (;;) { - char *p = realloc(buf, newlen); - size_t bytes_read, bytes_to_read; - if (!p) { - imagex_error(T("out of memory while reading stdin")); - break; - } - buf = p; - bytes_to_read = newlen - pos; - bytes_read = fread(&buf[pos], 1, bytes_to_read, stdin); - pos += bytes_read; - if (bytes_read != bytes_to_read) { - if (feof(stdin)) { - *len_ret = pos; - return buf; - } else { - imagex_error_with_errno(T("error reading stdin")); - break; - } - } - newlen += inc; - inc *= 3; - inc /= 2; - } - free(buf); - return NULL; -} - - -static tchar * -translate_text_to_tstr(char *text, size_t num_bytes, size_t *num_tchars_ret) -{ -#ifndef __WIN32__ - /* On non-Windows, assume an ASCII-compatible encoding, such as UTF-8. - * */ - *num_tchars_ret = num_bytes; - return text; -#else /* !__WIN32__ */ - /* On Windows, translate the text to UTF-16LE */ - wchar_t *text_wstr; - size_t num_wchars; - - if (num_bytes >= 2 && - (((unsigned char)text[0] == 0xff && (unsigned char)text[1] == 0xfe) || - ((unsigned char)text[0] <= 0x7f && (unsigned char)text[1] == 0x00))) - { - /* File begins with 0xfeff, the BOM for UTF-16LE, or it begins - * with something that looks like an ASCII character encoded as - * a UTF-16LE code unit. Assume the file is encoded as - * UTF-16LE. This is not a 100% reliable check. */ - num_wchars = num_bytes / 2; - text_wstr = (wchar_t*)text; - } else { - /* File does not look like UTF-16LE. Assume it is encoded in - * the current Windows code page. I think these are always - * ASCII-compatible, so any so-called "plain-text" (ASCII) files - * should work as expected. */ - text_wstr = win32_mbs_to_wcs(text, - num_bytes, - &num_wchars); - free(text); - } - *num_tchars_ret = num_wchars; - return text_wstr; -#endif /* __WIN32__ */ -} - -static tchar * -file_get_text_contents(const tchar *filename, size_t *num_tchars_ret) -{ - char *contents; - size_t num_bytes; - - contents = file_get_contents(filename, &num_bytes); - if (!contents) - return NULL; - return translate_text_to_tstr(contents, num_bytes, num_tchars_ret); -} - -static tchar * -stdin_get_text_contents(size_t *num_tchars_ret) -{ - char *contents; - size_t num_bytes; - - contents = stdin_get_contents(&num_bytes); - if (!contents) - return NULL; - return translate_text_to_tstr(contents, num_bytes, num_tchars_ret); -} - #define TO_PERCENT(numerator, denominator) \ (((denominator) == 0) ? 0 : ((numerator) * 100 / (denominator))) @@ -1265,7 +1119,7 @@ imagex_progress_func(enum wimlib_progress_msg msg, * default installation. On UNIX-like systems, warn the * user when fixing the target of an absolute symbolic * link, so they know to disable this if they want. */ - #ifndef __WIN32__ + #ifndef _WIN32 imagex_printf(T("\nWARNING: Adjusted target of " "absolute symbolic link \"%"TS"\"\n" " (Use --norpfix to capture " @@ -1529,7 +1383,7 @@ update_command_add_option(int op, const tchar *option, return recognized; } -/* How many nonoption arguments each `imagex update' command expects */ +/* How many nonoption arguments each wimupdate command expects */ static const unsigned update_command_num_nonoptions[] = { [WIMLIB_UPDATE_OP_ADD] = 2, [WIMLIB_UPDATE_OP_DELETE] = 1, @@ -1561,7 +1415,7 @@ update_command_add_nonoption(int op, const tchar *nonoption, } /* - * Parse a command passed on stdin to `imagex update'. + * Parse a command passed on stdin to wimupdate. * * @line: Text of the command. * @len: Length of the line, including a null terminator @@ -1817,7 +1671,7 @@ imagex_apply(int argc, tchar **argv, int cmd) goto out_wimlib_free; } -#ifndef __WIN32__ +#ifndef _WIN32 { /* Interpret a regular file or block device target as an NTFS * volume. */ @@ -2040,7 +1894,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) template_image_name_or_num = optarg; } } - #ifdef __WIN32__ + #ifdef _WIN32 imagex_printf(T("[WARNING] '--update-of' is unreliable on Windows!\n")); #endif break; @@ -2202,13 +2056,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) if (source_list) { /* Set up capture sources in source list mode */ - if (source[0] == T('-') && source[1] == T('\0')) { - source_list_contents = stdin_get_text_contents(&source_list_nchars); - } else { - source_list_contents = file_get_text_contents(source, - &source_list_nchars); - } - if (!source_list_contents) + if (wimlib_load_text_file(source, &source_list_contents, + &source_list_nchars) != 0) goto out_err; capture_sources = parse_source_list(&source_list_contents, @@ -2278,7 +2127,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd) goto out_free_wim; } -#ifndef __WIN32__ +#ifndef _WIN32 /* Detect if source is regular file or block device and set NTFS volume * capture mode. */ if (!source_list) { @@ -2721,7 +2570,7 @@ print_blobs(WIMStruct *wim) wimlib_iterate_lookup_table(wim, 0, print_resource, NULL); } -#ifndef __WIN32__ +#ifndef _WIN32 static void default_print_security_descriptor(const uint8_t *sd, size_t size) { @@ -3857,6 +3706,7 @@ imagex_optimize(int argc, tchar **argv, int cmd) int solid_ctype = WIMLIB_COMPRESSION_TYPE_INVALID; int ret; WIMStruct *wim; + struct wimlib_wim_info info; const tchar *wimfile; off_t old_size; off_t new_size; @@ -3900,6 +3750,9 @@ imagex_optimize(int argc, tchar **argv, int cmd) case IMAGEX_SOLID_OPTION: write_flags |= WIMLIB_WRITE_FLAG_SOLID; write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS; + /* Reset the non-solid compression type to LZMS. */ + if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) + compression_type = WIMLIB_COMPRESSION_TYPE_LZMS; break; case IMAGEX_NO_SOLID_SORT_OPTION: write_flags |= WIMLIB_WRITE_FLAG_NO_SOLID_SORT; @@ -3935,11 +3788,18 @@ imagex_optimize(int argc, tchar **argv, int cmd) if (ret) goto out; - if (compression_type != WIMLIB_COMPRESSION_TYPE_INVALID) { + wimlib_get_wim_info(wim, &info); + + if (compression_type != WIMLIB_COMPRESSION_TYPE_INVALID && + compression_type != info.compression_type) { /* Change compression type. */ ret = wimlib_set_output_compression_type(wim, compression_type); if (ret) goto out_wimlib_free; + + /* Reset the chunk size. */ + if (chunk_size == UINT32_MAX) + chunk_size = 0; } if (chunk_size != UINT32_MAX) { @@ -4006,7 +3866,7 @@ imagex_split(int argc, tchar **argv, int cmd) int c; int open_flags = 0; int write_flags = 0; - unsigned long part_size; + uint64_t part_size; tchar *tmp; int ret; WIMStruct *wim; @@ -4145,6 +4005,7 @@ imagex_update(int argc, tchar **argv, int cmd) WIMLIB_ADD_FLAG_WINCONFIG; int default_delete_flags = 0; unsigned num_threads = 0; + STRING_LIST(refglobs); int c; tchar *cmd_file_contents; size_t cmd_file_nchars; @@ -4188,6 +4049,13 @@ imagex_update(int argc, tchar **argv, int cmd) case IMAGEX_WIMBOOT_CONFIG_OPTION: wimboot_config = optarg; break; + case IMAGEX_REF_OPTION: + ret = string_list_append(&refglobs, optarg); + if (ret) + goto out; + /* assume delta WIM */ + write_flags |= WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS; + break; /* Default delete options */ case IMAGEX_FORCE_OPTION: default_delete_flags |= WIMLIB_DELETE_FLAG_FORCE; @@ -4238,7 +4106,7 @@ imagex_update(int argc, tchar **argv, int cmd) ret = wimlib_open_wim_with_progress(wimfile, open_flags, &wim, imagex_progress_func, NULL); if (ret) - goto out_free_command_str; + goto out; if (argc >= 2) { /* Image explicitly specified. */ @@ -4262,6 +4130,10 @@ imagex_update(int argc, tchar **argv, int cmd) image = 1; } + ret = wim_reference_globs(wim, &refglobs, open_flags); + if (ret) + goto out_wimlib_free; + /* Read update commands from standard input, or the command string if * specified. */ if (command_str) { @@ -4277,8 +4149,8 @@ imagex_update(int argc, tchar **argv, int cmd) tputs(T("Reading update commands from standard input...")); recommend_man_page(CMD_UPDATE, stdout); } - cmd_file_contents = stdin_get_text_contents(&cmd_file_nchars); - if (!cmd_file_contents) { + if (wimlib_load_text_file(NULL, &cmd_file_contents, + &cmd_file_nchars) != 0) { ret = -1; goto out_wimlib_free; } @@ -4341,15 +4213,16 @@ out_free_cmd_file_contents: free(cmd_file_contents); out_wimlib_free: wimlib_free(wim); -out_free_command_str: +out: free(command_str); + string_list_destroy(&refglobs); return ret; out_usage: usage(CMD_UPDATE, stderr); out_err: ret = -1; - goto out_free_command_str; + goto out; } /* Verify a WIM file. */ @@ -4460,7 +4333,7 @@ static const struct imagex_command imagex_commands[] = { [CMD_VERIFY] = {T("verify"), imagex_verify}, }; -#ifdef __WIN32__ +#ifdef _WIN32 /* Can be a directory or source list file. But source list file is probably * a rare use case, so just say directory. */ @@ -4612,8 +4485,8 @@ version(void) static const tchar * const fmt = T( "wimlib-imagex " PACKAGE_VERSION " (using wimlib %"TS")\n" -"Copyright (C) 2012-2021 Eric Biggers\n" -"License GPLv3+; GNU GPL version 3 or later .\n" +"Copyright 2012-2023 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" @@ -4666,7 +4539,7 @@ static void recommend_man_page(int cmd, FILE *fp) { const tchar *format_str; -#ifdef __WIN32__ +#ifdef _WIN32 format_str = T("Some uncommon options are not listed;\n" "See %"TS".pdf in the doc directory for more details.\n"); #else @@ -4707,8 +4580,8 @@ usage_all(FILE *fp) recommend_man_page(CMD_NONE, fp); } -#ifdef __WIN32__ -extern int wmain(int argc, wchar_t **argv); +#ifdef _WIN32 +int wmain(int argc, wchar_t **argv); #define main wmain #endif