]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / programs / imagex.c
index e44ff276b49414526d827b1d40d7b3e2bb4a1ff6..54e50bfcdd06fe68015b8a23c2ac81c36be80097 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>.
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -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)))
 
@@ -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
@@ -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,
@@ -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) {
@@ -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.  */
@@ -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 <http://gnu.org/licenses/gpl.html>.\n"
+"Copyright 2012-2023 Eric Biggers\n"
+"License GPLv3+; GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\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"
@@ -4708,7 +4581,7 @@ usage_all(FILE *fp)
 }
 
 #ifdef _WIN32
-extern int wmain(int argc, wchar_t **argv);
+int wmain(int argc, wchar_t **argv);
 #define main wmain
 #endif