]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
wimlib-imagex, wimlib: Optimize appending new image as update of existing
[wimlib] / programs / imagex.c
index 9f3939c38550e9afbe6e4bbdc8367a92ef3f5269..be4b910eb024c55bd8917c27b265eda56c3456f0 100644 (file)
@@ -125,6 +125,7 @@ enum {
        IMAGEX_COMPRESS_OPTION,
        IMAGEX_CONFIG_OPTION,
        IMAGEX_DEBUG_OPTION,
+       IMAGEX_DELTA_FROM_OPTION,
        IMAGEX_DEREFERENCE_OPTION,
        IMAGEX_DEST_DIR_OPTION,
        IMAGEX_EXTRACT_XML_OPTION,
@@ -174,6 +175,8 @@ static const struct option apply_options[] = {
        {T("rpfix"),       no_argument,       NULL, IMAGEX_RPFIX_OPTION},
        {T("norpfix"),     no_argument,       NULL, IMAGEX_NORPFIX_OPTION},
        {T("include-invalid-names"), no_argument,       NULL, IMAGEX_INCLUDE_INVALID_NAMES_OPTION},
+
+       /* --resume is undocumented for now as it needs improvement.  */
        {T("resume"),      no_argument,       NULL, IMAGEX_RESUME_OPTION},
        {NULL, 0, NULL, 0},
 };
@@ -199,6 +202,7 @@ static const struct option capture_or_append_options[] = {
        {T("norpfix"),     no_argument,       NULL, IMAGEX_NORPFIX_OPTION},
        {T("pipable"),     no_argument,       NULL, IMAGEX_PIPABLE_OPTION},
        {T("not-pipable"), no_argument,       NULL, IMAGEX_NOT_PIPABLE_OPTION},
+       {T("delta-from"),  required_argument, NULL, IMAGEX_DELTA_FROM_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -419,29 +423,6 @@ file_get_size(const tchar *filename)
                return (off_t)-1;
 }
 
-tchar pat_ntfs_log[]                  = T("/$ntfs.log");
-tchar pat_hiberfil_sys[]              = T("/hiberfil.sys");
-tchar pat_pagefile_sys[]              = T("/pagefile.sys");
-tchar pat_system_volume_information[] = T("/System Volume Information");
-tchar pat_recycler[]                  = T("/RECYCLER");
-tchar pat_windows_csc[]               = T("/Windows/CSC");
-
-tchar *default_pats[] = {
-       pat_ntfs_log,
-       pat_hiberfil_sys,
-       pat_pagefile_sys,
-       pat_system_volume_information,
-       pat_recycler,
-       pat_windows_csc,
-};
-
-static struct wimlib_capture_config default_capture_config = {
-       .exclusion_pats = {
-               .num_pats = sizeof(default_pats) / sizeof(default_pats[0]),
-               .pats = default_pats,
-       },
-};
-
 enum {
        PARSE_STRING_SUCCESS = 0,
        PARSE_STRING_FAILURE = 1,
@@ -1269,15 +1250,15 @@ update_command_add_option(int op, const tchar *option,
        switch (op) {
        case WIMLIB_UPDATE_OP_ADD:
                if (!tstrcmp(option, T("--verbose")))
-                       cmd->add.add_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
+                       cmd->add.add_flags |= WIMLIB_ADD_FLAG_VERBOSE;
                else if (!tstrcmp(option, T("--unix-data")))
-                       cmd->add.add_flags |= WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA;
+                       cmd->add.add_flags |= WIMLIB_ADD_FLAG_UNIX_DATA;
                else if (!tstrcmp(option, T("--no-acls")) || !tstrcmp(option, T("--noacls")))
-                       cmd->add.add_flags |= WIMLIB_ADD_IMAGE_FLAG_NO_ACLS;
+                       cmd->add.add_flags |= WIMLIB_ADD_FLAG_NO_ACLS;
                else if (!tstrcmp(option, T("--strict-acls")))
-                       cmd->add.add_flags |= WIMLIB_ADD_IMAGE_FLAG_STRICT_ACLS;
+                       cmd->add.add_flags |= WIMLIB_ADD_FLAG_STRICT_ACLS;
                else if (!tstrcmp(option, T("--dereference")))
-                       cmd->add.add_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE;
+                       cmd->add.add_flags |= WIMLIB_ADD_FLAG_DEREFERENCE;
                else
                        recognized = false;
                break;
@@ -1637,7 +1618,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 {
        int c;
        int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS;
-       int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE;
+       int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE |
+                             WIMLIB_ADD_IMAGE_FLAG_WINCONFIG;
        int write_flags = 0;
        int compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
        const tchar *wimfile;
@@ -1645,6 +1627,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        const tchar *name;
        const tchar *desc;
        const tchar *flags_element = NULL;
+       const tchar *template_image_name_or_num = NULL;
+       int template_image;
        WIMStruct *wim;
        int ret;
        unsigned num_threads = 0;
@@ -1678,6 +1662,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        break;
                case IMAGEX_CONFIG_OPTION:
                        config_file = optarg;
+                       add_image_flags &= ~WIMLIB_ADD_IMAGE_FLAG_WINCONFIG;
                        break;
                case IMAGEX_COMPRESS_OPTION:
                        compression_type = get_compression_type(optarg);
@@ -1725,6 +1710,14 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                case IMAGEX_NOT_PIPABLE_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_NOT_PIPABLE;
                        break;
+               case IMAGEX_DELTA_FROM_OPTION:
+                       if (cmd == CMD_CAPTURE) {
+                               imagex_error(T("--delta-from=IMAGE is only "
+                                              "valid for append."));
+                               goto out_usage;
+                       }
+                       template_image_name_or_num = optarg;
+                       break;
                default:
                        goto out_usage;
                }
@@ -1739,6 +1732,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        wimfile = argv[1];
 
        if (!tstrcmp(wimfile, T("-"))) {
+               /* Writing captured WIM to standard output.  */
        #if 0
                if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) {
                        imagex_error("Can't write a non-pipable WIM to "
@@ -1758,6 +1752,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                wim_fd = STDOUT_FILENO;
                wimfile = NULL;
                imagex_info_file = stderr;
+               set_fd_to_binary_mode(wim_fd);
        }
 
        if (argc >= 3) {
@@ -1826,7 +1821,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                if (ret)
                        goto out_free_config;
        } else {
-               config = &default_capture_config;
+               config = NULL;
        }
 
        if (cmd == CMD_APPEND)
@@ -1871,6 +1866,30 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        tsprintf(name_end, T(" (%lu)"), conflict_idx);
                }
        }
+
+       if (template_image_name_or_num) {
+               template_image = wimlib_resolve_image(wim, template_image_name_or_num);
+               if (template_image_name_or_num[0] == T('-')) {
+                       tchar *tmp;
+                       unsigned long n;
+                       struct wimlib_wim_info info;
+
+                       wimlib_get_wim_info(wim, &info);
+                       n = tstrtoul(template_image_name_or_num + 1, &tmp, 10);
+                       if (n >= 1 && n <= info.image_count &&
+                           *tmp == T('\0') &&
+                           tmp != template_image_name_or_num + 1)
+                       {
+                               template_image = info.image_count - (n - 1);
+                       }
+               }
+               ret = verify_image_exists_and_is_single(template_image,
+                                                       template_image_name_or_num,
+                                                       wimfile);
+               if (ret)
+                       goto out_wimlib_free;
+       }
+
        ret = wimlib_add_image_multisource(wim,
                                           capture_sources,
                                           num_sources,
@@ -1881,10 +1900,11 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        if (ret)
                goto out_wimlib_free;
 
-       if (desc || flags_element) {
-               /* User provided <DESCRIPTION> or <FLAGS> element.  Get the
-                * index of the image we just added, then use it to call the
-                * appropriate functions.  */
+       if (desc || flags_element || template_image_name_or_num) {
+               /* User provided <DESCRIPTION> or <FLAGS> element, or an image
+                * on which the added one is to be based has been specified with
+                * --delta-from=IMAGE.  Get the index of the image we just
+                *  added, then use it to call the appropriate functions.  */
                struct wimlib_wim_info info;
 
                wimlib_get_wim_info(wim, &info);
@@ -1903,6 +1923,15 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        if (ret)
                                goto out_wimlib_free;
                }
+
+               if (template_image_name_or_num) {
+                       ret = wimlib_reference_template_image(wim,
+                                                             info.image_count,
+                                                             template_image,
+                                                             0, NULL);
+                       if (ret)
+                               goto out_wimlib_free;
+               }
        }
 
        /* Write the new WIM or overwrite the existing WIM with the new image
@@ -1922,7 +1951,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 out_wimlib_free:
        wimlib_free(wim);
 out_free_config:
-       if (config != &default_capture_config) {
+       if (config) {
                free(config->exclusion_pats.pats);
                free(config->exclusion_exception_pats.pats);
                free(config_str);
@@ -2197,6 +2226,7 @@ imagex_export(int argc, tchar **argv, int cmd)
                dest_wimfile = NULL;
                dest_wim_fd = STDOUT_FILENO;
                imagex_info_file = stderr;
+               set_fd_to_binary_mode(dest_wim_fd);
        }
        errno = ENOENT;
        if (dest_wimfile != NULL && tstat(dest_wimfile, &stbuf) == 0) {
@@ -3219,7 +3249,8 @@ imagex_update(int argc, tchar **argv, int cmd)
        int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS;
        int write_flags = 0;
        int update_flags = WIMLIB_UPDATE_FLAG_SEND_PROGRESS;
-       int default_add_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE;
+       int default_add_flags = WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE |
+                               WIMLIB_ADD_FLAG_WINCONFIG;
        int default_delete_flags = 0;
        unsigned num_threads = 0;
        int c;
@@ -3272,24 +3303,25 @@ imagex_update(int argc, tchar **argv, int cmd)
 
                /* Global add option */
                case IMAGEX_CONFIG_OPTION:
+                       default_add_flags &= ~WIMLIB_ADD_FLAG_WINCONFIG;
                        config_file = optarg;
                        break;
 
                /* Default add options */
                case IMAGEX_VERBOSE_OPTION:
-                       default_add_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
+                       default_add_flags |= WIMLIB_ADD_FLAG_VERBOSE;
                        break;
                case IMAGEX_DEREFERENCE_OPTION:
-                       default_add_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE;
+                       default_add_flags |= WIMLIB_ADD_FLAG_DEREFERENCE;
                        break;
                case IMAGEX_UNIX_DATA_OPTION:
-                       default_add_flags |= WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA;
+                       default_add_flags |= WIMLIB_ADD_FLAG_UNIX_DATA;
                        break;
                case IMAGEX_NO_ACLS_OPTION:
-                       default_add_flags |= WIMLIB_ADD_IMAGE_FLAG_NO_ACLS;
+                       default_add_flags |= WIMLIB_ADD_FLAG_NO_ACLS;
                        break;
                case IMAGEX_STRICT_ACLS_OPTION:
-                       default_add_flags |= WIMLIB_ADD_IMAGE_FLAG_STRICT_ACLS;
+                       default_add_flags |= WIMLIB_ADD_FLAG_STRICT_ACLS;
                        break;
                default:
                        goto out_usage;
@@ -3343,7 +3375,7 @@ imagex_update(int argc, tchar **argv, int cmd)
                if (ret)
                        goto out_free_config;
        } else {
-               config = &default_capture_config;
+               config = NULL;
        }
 
        /* Read update commands from standard input, or the command string if
@@ -3373,13 +3405,11 @@ imagex_update(int argc, tchar **argv, int cmd)
        }
 
        /* Set default flags and capture config on the update commands */
-       bool have_add_command = false;
        for (size_t i = 0; i < num_cmds; i++) {
                switch (cmds[i].op) {
                case WIMLIB_UPDATE_OP_ADD:
                        cmds[i].add.add_flags |= default_add_flags;
                        cmds[i].add.config = config;
-                       have_add_command = true;
                        break;
                case WIMLIB_UPDATE_OP_DELETE:
                        cmds[i].delete.delete_flags |= default_delete_flags;
@@ -3403,7 +3433,7 @@ out_free_cmds:
 out_free_cmd_file_contents:
        free(cmd_file_contents);
 out_free_config:
-       if (config != &default_capture_config) {
+       if (config) {
                free(config->exclusion_pats.pats);
                free(config->exclusion_exception_pats.pats);
                free(config_str);
@@ -3459,7 +3489,7 @@ T(
 "                    [--dereference] [--config=FILE] [--threads=NUM_THREADS]\n"
 "                    [--rebuild] [--unix-data] [--source-list] [--no-acls]\n"
 "                    [--strict-acls] [--rpfix] [--norpfix] [--pipable]\n"
-"                    [--not-pipable]\n"
+"                    [--not-pipable] [--delta-from=IMAGE]\n"
 ),
 [CMD_APPLY] =
 T(
@@ -3467,7 +3497,7 @@ T(
 "                    (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n"
 "                    [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n"
 "                    [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
-"                    [--include-invalid-names] [--resume]\n"
+"                    [--include-invalid-names]\n"
 ),
 [CMD_CAPTURE] =
 T(
@@ -3476,8 +3506,7 @@ T(
 "                    [--nocheck] [--compress=TYPE] [--flags EDITION_ID]\n"
 "                    [--verbose] [--dereference] [--config=FILE]\n"
 "                    [--threads=NUM_THREADS] [--unix-data] [--source-list]\n"
-"                    [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
-"                    [--pipable] [--not-pipable]\n"
+"                    [--no-acls] [--strict-acls] [--norpfix] [--pipable]\n"
 ),
 [CMD_DELETE] =
 T(
@@ -3552,24 +3581,25 @@ T(
 };
 
 static const tchar *invocation_name;
-static bool using_cmd_from_invocation_name = false;
+static int invocation_cmd = CMD_NONE;
 
 static const tchar *get_cmd_string(int cmd, bool nospace)
 {
-
-       if (using_cmd_from_invocation_name || cmd == CMD_NONE) {
-               return invocation_name;
+       static tchar buf[50];
+       if (cmd == CMD_NONE) {
+               tsprintf(buf, T("%"TS), T(IMAGEX_PROGNAME));
+       } else if (invocation_cmd != CMD_NONE) {
+               tsprintf(buf, T("wim%"TS), imagex_commands[cmd].name);
        } else {
                const tchar *format;
-               static tchar buf[50];
 
                if (nospace)
                        format = T("%"TS"-%"TS"");
                else
                        format = T("%"TS" %"TS"");
                tsprintf(buf, format, invocation_name, imagex_commands[cmd].name);
-               return buf;
        }
+       return buf;
 }
 
 static void
@@ -3710,7 +3740,7 @@ main(int argc, char **argv)
                        if (!tstrcmp(invocation_name + 3,
                                     imagex_commands[i].name))
                        {
-                               using_cmd_from_invocation_name = true;
+                               invocation_cmd = i;
                                cmd = i;
                                break;
                        }