]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
wimoptimize: make --recompress-slow imply --compress=maximum
[wimlib] / programs / imagex.c
index fc932857dc8a0f1eebbc289fbf8d0ca5a8e5293f..06ddeddd4060730ad083fcff690629d413583ffe 100644 (file)
@@ -123,6 +123,7 @@ enum {
        IMAGEX_COMMAND_OPTION,
        IMAGEX_COMMIT_OPTION,
        IMAGEX_COMPRESS_OPTION,
+       IMAGEX_COMPRESS_SLOW_OPTION,
        IMAGEX_CONFIG_OPTION,
        IMAGEX_DEBUG_OPTION,
        IMAGEX_DELTA_FROM_OPTION,
@@ -188,6 +189,7 @@ static const struct option capture_or_append_options[] = {
        {T("no-check"),    no_argument,       NULL, IMAGEX_NOCHECK_OPTION},
        {T("nocheck"),     no_argument,       NULL, IMAGEX_NOCHECK_OPTION},
        {T("compress"),    required_argument, NULL, IMAGEX_COMPRESS_OPTION},
+       {T("compress-slow"), no_argument,     NULL, IMAGEX_COMPRESS_SLOW_OPTION},
        {T("config"),      required_argument, NULL, IMAGEX_CONFIG_OPTION},
        {T("dereference"), no_argument,       NULL, IMAGEX_DEREFERENCE_OPTION},
        {T("flags"),       required_argument, NULL, IMAGEX_FLAGS_OPTION},
@@ -280,7 +282,10 @@ 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("compress"),    required_argument, NULL, IMAGEX_COMPRESS_OPTION},
        {T("recompress"),  no_argument,       NULL, IMAGEX_RECOMPRESS_OPTION},
+       {T("compress-slow"), no_argument,     NULL, IMAGEX_COMPRESS_SLOW_OPTION},
+       {T("recompress-slow"), no_argument,     NULL, IMAGEX_COMPRESS_SLOW_OPTION},
        {T("threads"),     required_argument, NULL, IMAGEX_THREADS_OPTION},
        {T("pipable"),     no_argument,       NULL, IMAGEX_PIPABLE_OPTION},
        {T("not-pipable"), no_argument,       NULL, IMAGEX_NOT_PIPABLE_OPTION},
@@ -415,6 +420,32 @@ get_compression_type(const tchar *optarg)
        }
 }
 
+static int
+set_compress_slow(void)
+{
+       int ret;
+       static const struct wimlib_lzx_params slow_params = {
+               .size_of_this = sizeof(struct wimlib_lzx_params),
+               .algorithm = WIMLIB_LZX_ALGORITHM_SLOW,
+               .alg_params = {
+                       .slow = {
+                               .use_len2_matches = 1,
+                               .num_fast_bytes = 96,
+                               .num_optim_passes = 4,
+                               .max_search_depth = 100,
+                               .max_matches_per_pos = 10,
+                               .main_nostat_cost = 15,
+                               .len_nostat_cost = 15,
+                               .aligned_nostat_cost = 7,
+                       },
+               },
+       };
+       ret = wimlib_lzx_set_default_params(&slow_params);
+       if (ret)
+               imagex_error(T("Couldn't set slow compression parameters.!"));
+       return ret;
+}
+
 struct string_set {
        const tchar **strings;
        unsigned num_strings;
@@ -482,7 +513,7 @@ do_resource_not_found_warning(const tchar *wimfile,
                }
        } else {
                imagex_error(T("If this is a delta WIM, use the --ref argument "
-                              "to specify the WIM on which it is based."));
+                              "to specify the WIM(s) on which it is based."));
        }
 }
 
@@ -1639,7 +1670,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        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;
+       int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
        const tchar *wimfile;
        int wim_fd;
        const tchar *name;
@@ -1647,8 +1678,9 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        const tchar *flags_element = NULL;
 
        WIMStruct *wim;
-       WIMStruct *base_wim;
-       const tchar *base_wimfile = NULL;
+       STRING_SET(base_wimfiles);
+       WIMStruct **base_wims;
+
        WIMStruct *template_wim;
        const tchar *template_wimfile = NULL;
        const tchar *template_image_name_or_num = NULL;
@@ -1693,6 +1725,12 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
                                goto out_err;
                        break;
+               case IMAGEX_COMPRESS_SLOW_OPTION:
+                       ret = set_compress_slow();
+                       if (ret)
+                               goto out_err;
+                       compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
+                       break;
                case IMAGEX_FLAGS_OPTION:
                        flags_element = optarg;
                        break;
@@ -1759,12 +1797,9 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                               "valid for capture!"));
                                goto out_usage;
                        }
-                       if (base_wimfile) {
-                               imagex_error(T("'--delta-from' can only be "
-                                              "specified one time!"));
-                               goto out_err;
-                       }
-                       base_wimfile = optarg;
+                       ret = string_set_append(&base_wimfiles, optarg);
+                       if (ret)
+                               goto out_free_base_wimfiles;
                        write_flags |= WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS;
                        break;
                default:
@@ -1780,6 +1815,18 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        source = argv[0];
        wimfile = argv[1];
 
+       /* Set default compression type.  */
+       if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
+               struct wimlib_lzx_params params;
+               memset(&params, 0, sizeof(params));
+               params.size_of_this = sizeof(params);
+               params.algorithm = WIMLIB_LZX_ALGORITHM_FAST;
+               params.use_defaults = 1;
+
+               wimlib_lzx_set_default_params(&params);
+               compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
+       }
+
        if (!tstrcmp(wimfile, T("-"))) {
                /* Writing captured WIM to standard output.  */
        #if 0
@@ -1807,9 +1854,10 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        /* If template image was specified using --update-of=IMAGE rather
         * than --update-of=WIMFILE:IMAGE, set the default WIMFILE.  */
        if (template_image_name_or_num && !template_wimfile) {
-               if (base_wimfile) {
-                       /* Capturing delta WIM:  default to base WIM.  */
-                       template_wimfile = base_wimfile;
+               if (base_wimfiles.num_strings == 1) {
+                       /* Capturing delta WIM based on single WIM:  default to
+                        * base WIM.  */
+                       template_wimfile = base_wimfiles.strings[0];
                } else if (cmd == CMD_APPEND) {
                        /* Appending to WIM:  default to WIM being appended to.
                         */
@@ -1817,9 +1865,17 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                } else {
                        /* Capturing a normal (non-delta) WIM, so the WIM file
                         * *must* be explicitly specified.  */
-                       imagex_error(T("For capture of non-delta WIM, "
-                                      "'--update-of' must specify "
-                                      "WIMFILE:IMAGE!"));
+                       if (base_wimfiles.num_strings > 1) {
+                               imagex_error(T("For capture of delta WIM "
+                                              "based on multiple existing "
+                                              "WIMs,\n"
+                                              "      '--update-of' must "
+                                              "specify WIMFILE:IMAGE!"));
+                       } else {
+                               imagex_error(T("For capture of non-delta WIM, "
+                                              "'--update-of' must specify "
+                                              "WIMFILE:IMAGE!"));
+                       }
                        goto out_usage;
                }
        }
@@ -1942,22 +1998,41 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                }
        }
 
-       /* If capturing a delta WIM, reference resources from the base WIM
+       /* If capturing a delta WIM, reference resources from the base WIMs
         * before adding the new image.  */
-       if (base_wimfile) {
-               ret = wimlib_open_wim(base_wimfile, open_flags,
-                                     &base_wim, imagex_progress_func);
-               if (ret)
+       if (base_wimfiles.num_strings) {
+               base_wims = calloc(base_wimfiles.num_strings,
+                                  sizeof(base_wims[0]));
+               if (base_wims == NULL) {
+                       imagex_error(T("Out of memory!"));
+                       ret = -1;
                        goto out_free_wim;
+               }
 
-               imagex_printf(T("Capturing delta WIM based on \"%"TS"\"\n"),
-                             base_wimfile);
+               for (size_t i = 0; i < base_wimfiles.num_strings; i++) {
+                       ret = wimlib_open_wim(base_wimfiles.strings[i],
+                                             open_flags, &base_wims[i],
+                                             imagex_progress_func);
+                       if (ret)
+                               goto out_free_base_wims;
+
+               }
 
-               ret = wimlib_reference_resources(wim, &base_wim, 1, 0);
+               ret = wimlib_reference_resources(wim, base_wims,
+                                                base_wimfiles.num_strings, 0);
                if (ret)
-                       goto out_free_base_wim;
+                       goto out_free_base_wims;
+
+               if (base_wimfiles.num_strings == 1) {
+                       imagex_printf(T("Capturing delta WIM based on \"%"TS"\"\n"),
+                                     base_wimfiles.strings[0]);
+               } else {
+                       imagex_printf(T("Capturing delta WIM based on %u WIMs\n"),
+                                     base_wimfiles.num_strings);
+               }
+
        } else {
-               base_wim = NULL;
+               base_wims = NULL;
        }
 
        /* If capturing or appending as an update of an existing (template) image,
@@ -1965,15 +2040,16 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        if (template_image_name_or_num) {
 
 
-               if (template_wimfile == base_wimfile) {
-                       template_wim = base_wim;
+               if (base_wimfiles.num_strings == 1 &&
+                   template_wimfile == base_wimfiles.strings[0]) {
+                       template_wim = base_wims[0];
                } else if (template_wimfile == wimfile) {
                        template_wim = wim;
                } else {
                        ret = wimlib_open_wim(template_wimfile, open_flags,
                                              &template_wim, imagex_progress_func);
                        if (ret)
-                               goto out_free_base_wim;
+                               goto out_free_base_wims;
                }
 
                template_image = wimlib_resolve_image(template_wim,
@@ -2066,11 +2142,14 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                         imagex_progress_func);
        }
 out_free_template_wim:
-       /* template_wim may alias base_wim or wim.  */
-       if (template_wim != base_wim && template_wim != 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);
-out_free_base_wim:
-       wimlib_free(base_wim);
+out_free_base_wims:
+       for (size_t i = 0; i < base_wimfiles.num_strings; i++)
+               wimlib_free(base_wims[i]);
+       free(base_wims);
 out_free_wim:
        wimlib_free(wim);
 out_free_config:
@@ -2084,14 +2163,15 @@ out_free_capture_sources:
                free(capture_sources);
 out_free_source_list_contents:
        free(source_list_contents);
-out:
+out_free_base_wimfiles:
+       string_set_destroy(&base_wimfiles);
        return ret;
 
 out_usage:
        usage(cmd, stderr);
 out_err:
        ret = -1;
-       goto out;
+       goto out_free_base_wimfiles;
 }
 
 /* Remove image(s) from a WIM. */
@@ -3167,6 +3247,7 @@ imagex_optimize(int argc, tchar **argv, int cmd)
        int c;
        int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS;
        int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
+       int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
        int ret;
        WIMStruct *wim;
        const tchar *wimfile;
@@ -3183,9 +3264,22 @@ imagex_optimize(int argc, tchar **argv, int cmd)
                case IMAGEX_NOCHECK_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY;
                        break;
+               case IMAGEX_COMPRESS_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+                       compression_type = get_compression_type(optarg);
+                       if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
+                               goto out_err;
+                       break;
                case IMAGEX_RECOMPRESS_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
                        break;
+               case IMAGEX_COMPRESS_SLOW_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+                       compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
+                       ret = set_compress_slow();
+                       if (ret)
+                               goto out_err;
+                       break;
                case IMAGEX_THREADS_OPTION:
                        num_threads = parse_num_threads(optarg);
                        if (num_threads == UINT_MAX)
@@ -3213,6 +3307,12 @@ imagex_optimize(int argc, tchar **argv, int cmd)
        if (ret)
                goto out;
 
+       if (compression_type != WIMLIB_COMPRESSION_TYPE_INVALID) {
+               ret = wimlib_set_output_compression_type(wim, compression_type);
+               if (ret)
+                       goto out_wimlib_free;
+       }
+
        old_size = file_get_size(wimfile);
        tprintf(T("\"%"TS"\" original size: "), wimfile);
        if (old_size == -1)
@@ -3599,12 +3699,12 @@ static const tchar *usage_strings[] = {
 [CMD_APPEND] =
 T(
 "    %"TS" (DIRECTORY | NTFS_VOLUME) WIMFILE\n"
-"                    [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot] [--check]\n"
-"                    [--nocheck] [--flags EDITION_ID] [--verbose]\n"
+"                    [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot]\n"
+"                    [--check] [--nocheck] [--flags EDITION_ID] [--verbose]\n"
 "                    [--dereference] [--config=FILE] [--threads=NUM_THREADS]\n"
-"                    [--rebuild] [--unix-data] [--source-list] [--no-acls]\n"
-"                    [--strict-acls] [--rpfix] [--norpfix] [--pipable]\n"
-"                    [--not-pipable] [--update-of=[WIMFILE:]IMAGE]\n"
+"                    [--source-list] [--no-acls] [--strict-acls] [--rpfix]\n"
+"                    [--norpfix] [--unix-data] [--pipable]\n"
+"                    [--update-of=[WIMFILE:]IMAGE]\n"
 ),
 [CMD_APPLY] =
 T(
@@ -3617,12 +3717,13 @@ T(
 [CMD_CAPTURE] =
 T(
 "    %"TS" (DIRECTORY | NTFS_VOLUME) WIMFILE\n"
-"                   [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot] [--check]\n"
-"                    [--nocheck] [--compress=TYPE] [--flags EDITION_ID]\n"
-"                    [--verbose] [--dereference] [--config=FILE]\n"
-"                    [--threads=NUM_THREADS] [--unix-data] [--source-list]\n"
-"                    [--no-acls] [--strict-acls] [--norpfix] [--pipable]\n"
-"                    [--update-of=[WIMFILE:]IMAGE] [--delta-from=WIMFILE]\n"
+"                   [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot]\n"
+"                    [--check] [--nocheck] [--compress=TYPE]\n"
+"                    [--flags EDITION_ID] [--verbose] [--dereference]\n"
+"                    [--config=FILE] [--threads=NUM_THREADS] [--source-list]\n"
+"                    [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
+"                    [--unix-data] [--pipable] [--update-of=[WIMFILE:]IMAGE]\n"
+"                    [--delta-from=WIMFILE]\n"
 ),
 [CMD_DELETE] =
 T(
@@ -3676,6 +3777,7 @@ T(
 [CMD_OPTIMIZE] =
 T(
 "    %"TS" WIMFILE [--check] [--nocheck] [--recompress]\n"
+"                    [--recompress-slow] [--compress=TYPE]\n"
 "                    [--threads=NUM_THREADS] [--pipable] [--not-pipable]\n"
 ),
 [CMD_SPLIT] =