]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
wimlib-imagex: add options to enable unsafe compaction
[wimlib] / programs / imagex.c
index b30802899dce24d19ea0a007f5eddb58f73d0f28..23f362b61f2beb524e3a53747cd34f94669cac2e 100644 (file)
@@ -141,11 +141,13 @@ static FILE *imagex_info_file;
 
 enum {
        IMAGEX_ALLOW_OTHER_OPTION,
+       IMAGEX_BLOBS_OPTION,
        IMAGEX_BOOT_OPTION,
        IMAGEX_CHECK_OPTION,
        IMAGEX_CHUNK_SIZE_OPTION,
        IMAGEX_COMMAND_OPTION,
        IMAGEX_COMMIT_OPTION,
+       IMAGEX_COMPACT_OPTION,
        IMAGEX_COMPRESS_OPTION,
        IMAGEX_COMPRESS_SLOW_OPTION,
        IMAGEX_CONFIG_OPTION,
@@ -160,7 +162,6 @@ enum {
        IMAGEX_HEADER_OPTION,
        IMAGEX_INCLUDE_INVALID_NAMES_OPTION,
        IMAGEX_LAZY_OPTION,
-       IMAGEX_BLOBS_OPTION,
        IMAGEX_METADATA_OPTION,
        IMAGEX_NEW_IMAGE_OPTION,
        IMAGEX_NOCHECK_OPTION,
@@ -168,8 +169,8 @@ enum {
        IMAGEX_NOT_PIPABLE_OPTION,
        IMAGEX_NO_ACLS_OPTION,
        IMAGEX_NO_ATTRIBUTES_OPTION,
-       IMAGEX_NO_REPLACE_OPTION,
        IMAGEX_NO_GLOBS_OPTION,
+       IMAGEX_NO_REPLACE_OPTION,
        IMAGEX_NO_SOLID_SORT_OPTION,
        IMAGEX_NULLGLOB_OPTION,
        IMAGEX_ONE_FILE_ONLY_OPTION,
@@ -183,9 +184,9 @@ enum {
        IMAGEX_RESUME_OPTION,
        IMAGEX_RPFIX_OPTION,
        IMAGEX_SOFT_OPTION,
-       IMAGEX_SOLID_OPTION,
        IMAGEX_SOLID_CHUNK_SIZE_OPTION,
        IMAGEX_SOLID_COMPRESS_OPTION,
+       IMAGEX_SOLID_OPTION,
        IMAGEX_SOURCE_LIST_OPTION,
        IMAGEX_STAGING_DIR_OPTION,
        IMAGEX_STREAMS_INTERFACE_OPTION,
@@ -193,10 +194,11 @@ enum {
        IMAGEX_THREADS_OPTION,
        IMAGEX_TO_STDOUT_OPTION,
        IMAGEX_UNIX_DATA_OPTION,
+       IMAGEX_UNSAFE_COMPACT_OPTION,
        IMAGEX_UPDATE_OF_OPTION,
        IMAGEX_VERBOSE_OPTION,
-       IMAGEX_WIMBOOT_OPTION,
        IMAGEX_WIMBOOT_CONFIG_OPTION,
+       IMAGEX_WIMBOOT_OPTION,
        IMAGEX_XML_OPTION,
 };
 
@@ -216,6 +218,7 @@ static const struct option apply_options[] = {
        /* --resume is undocumented for now as it needs improvement.  */
        {T("resume"),      no_argument,       NULL, IMAGEX_RESUME_OPTION},
        {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
+       {T("compact"),     required_argument, NULL, IMAGEX_COMPACT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -252,12 +255,14 @@ static const struct option capture_or_append_options[] = {
        {T("update-of"),   required_argument, NULL, IMAGEX_UPDATE_OF_OPTION},
        {T("delta-from"),  required_argument, NULL, IMAGEX_DELTA_FROM_OPTION},
        {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
+       {T("unsafe-compact"), no_argument,    NULL, IMAGEX_UNSAFE_COMPACT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
 static const struct option delete_options[] = {
        {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
        {T("soft"),  no_argument, NULL, IMAGEX_SOFT_OPTION},
+       {T("unsafe-compact"), no_argument, NULL, IMAGEX_UNSAFE_COMPACT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -265,6 +270,7 @@ static const struct option dir_options[] = {
        {T("path"),     required_argument, NULL, IMAGEX_PATH_OPTION},
        {T("detailed"), no_argument,       NULL, IMAGEX_DETAILED_OPTION},
        {T("one-file-only"), no_argument,  NULL, IMAGEX_ONE_FILE_ONLY_OPTION},
+       {T("ref"),      required_argument, NULL, IMAGEX_REF_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -290,6 +296,7 @@ static const struct option export_options[] = {
        {T("pipable"),     no_argument,       NULL, IMAGEX_PIPABLE_OPTION},
        {T("not-pipable"), no_argument,       NULL, IMAGEX_NOT_PIPABLE_OPTION},
        {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
+       {T("unsafe-compact"), no_argument,    NULL, IMAGEX_UNSAFE_COMPACT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -310,6 +317,7 @@ static const struct option extract_options[] = {
        {T("nullglob"),     no_argument,      NULL, IMAGEX_NULLGLOB_OPTION},
        {T("preserve-dir-structure"), no_argument, NULL, IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION},
        {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
+       {T("compact"),     required_argument, NULL, IMAGEX_COMPACT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -362,6 +370,7 @@ static const struct option optimize_options[] = {
        {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},
+       {T("unsafe-compact"), no_argument,    NULL, IMAGEX_UNSAFE_COMPACT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -406,6 +415,7 @@ static const struct option update_options[] = {
        {T("no-acls"),     no_argument,       NULL, IMAGEX_NO_ACLS_OPTION},
        {T("strict-acls"), no_argument,       NULL, IMAGEX_STRICT_ACLS_OPTION},
        {T("no-replace"),  no_argument,       NULL, IMAGEX_NO_REPLACE_OPTION},
+       {T("unsafe-compact"), no_argument,    NULL, IMAGEX_UNSAFE_COMPACT_OPTION},
 
        {NULL, 0, NULL, 0},
 };
@@ -547,6 +557,37 @@ get_compression_type(tchar *optarg)
        return ctype;
 }
 
+/* Parse the argument to --compact */
+static int
+set_compact_mode(const tchar *arg, int *extract_flags)
+{
+       int flag = 0;
+       if (!tstrcasecmp(arg, T("xpress4k")))
+               flag = WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS4K;
+       else if (!tstrcasecmp(arg, T("xpress8k")))
+               flag = WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS8K;
+       else if (!tstrcasecmp(arg, T("xpress16k")))
+               flag = WIMLIB_EXTRACT_FLAG_COMPACT_XPRESS16K;
+       else if (!tstrcasecmp(arg, T("lzx")))
+               flag = WIMLIB_EXTRACT_FLAG_COMPACT_LZX;
+
+       if (flag) {
+               *extract_flags |= flag;
+               return 0;
+       }
+
+       imagex_error(T(
+"\"%"TS"\" is not a recognized System Compression format.  The options are:"
+"\n"
+"    --compact=xpress4k\n"
+"    --compact=xpress8k\n"
+"    --compact=xpress16k\n"
+"    --compact=lzx\n"
+       ), arg);
+       return -1;
+}
+
+
 static void
 set_compress_slow(void)
 {
@@ -627,6 +668,17 @@ do_resource_not_found_warning(const tchar *wimfile,
        }
 }
 
+static void
+do_metadata_not_found_warning(const tchar *wimfile,
+                             const struct wimlib_wim_info *info)
+{
+       if (info->part_number != 1) {
+               imagex_error(T("\"%"TS"\" is not the first part of the split WIM.\n"
+                              "       You must specify the first part."),
+                              wimfile);
+       }
+}
+
 /* Returns the size of a file given its name, or -1 if the file does not exist
  * or its size cannot be determined.  */
 static off_t
@@ -1181,7 +1233,7 @@ imagex_progress_func(enum wimlib_progress_msg msg,
                percent_done = TO_PERCENT(info->extract.completed_bytes,
                                          info->extract.total_bytes);
                unit_shift = get_unit(info->extract.total_bytes, &unit_name);
-               imagex_printf(T("\rExtracting files: "
+               imagex_printf(T("\rExtracting file data: "
                          "%"PRIu64" %"TS" of %"PRIu64" %"TS" (%u%%) done"),
                        info->extract.completed_bytes >> unit_shift,
                        unit_name,
@@ -1278,7 +1330,7 @@ imagex_progress_func(enum wimlib_progress_msg msg,
                percent_done = TO_PERCENT(info->verify_streams.completed_bytes,
                                          info->verify_streams.total_bytes);
                unit_shift = get_unit(info->verify_streams.total_bytes, &unit_name);
-               imagex_printf(T("\rVerifying streams: "
+               imagex_printf(T("\rVerifying file data: "
                          "%"PRIu64" %"TS" of %"PRIu64" %"TS" (%u%%) done"),
                        info->verify_streams.completed_bytes >> unit_shift,
                        unit_name,
@@ -1611,6 +1663,11 @@ imagex_apply(int argc, tchar **argv, int cmd)
                case IMAGEX_WIMBOOT_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_WIMBOOT;
                        break;
+               case IMAGEX_COMPACT_OPTION:
+                       ret = set_compact_mode(optarg, &extract_flags);
+                       if (ret)
+                               goto out_free_refglobs;
+                       break;
                default:
                        goto out_usage;
                }
@@ -1718,6 +1775,8 @@ imagex_apply(int argc, tchar **argv, int cmd)
                                       "       make sure you have "
                                       "concatenated together all parts."));
                }
+       } else if (ret == WIMLIB_ERR_METADATA_NOT_FOUND && wim) {
+               do_metadata_not_found_warning(wimfile, &info);
        }
 out_wimlib_free:
        wimlib_free(wim);
@@ -1898,6 +1957,9 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                case IMAGEX_WIMBOOT_OPTION:
                        add_flags |= WIMLIB_ADD_FLAG_WIMBOOT;
                        break;
+               case IMAGEX_UNSAFE_COMPACT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -2300,6 +2362,9 @@ imagex_delete(int argc, tchar **argv, int cmd)
                case IMAGEX_SOFT_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_SOFT_DELETE;
                        break;
+               case IMAGEX_UNSAFE_COMPACT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -2413,6 +2478,9 @@ static void print_byte_field(const uint8_t field[], size_t len)
 static void
 print_wim_information(const tchar *wimfile, const struct wimlib_wim_info *info)
 {
+       tchar attr_string[256];
+       tchar *p;
+
        tputs(T("WIM Information:"));
        tputs(T("----------------"));
        tprintf(T("Path:           %"TS"\n"), wimfile);
@@ -2428,13 +2496,32 @@ print_wim_information(const tchar *wimfile, const struct wimlib_wim_info *info)
        tprintf(T("Part Number:    %d/%d\n"), info->part_number, info->total_parts);
        tprintf(T("Boot Index:     %d\n"), info->boot_index);
        tprintf(T("Size:           %"PRIu64" bytes\n"), info->total_bytes);
-       tprintf(T("Integrity Info: %"TS"\n"),
-               info->has_integrity_table ? T("yes") : T("no"));
-       tprintf(T("Relative path junction: %"TS"\n"),
-               info->has_rpfix ? T("yes") : T("no"));
-       tprintf(T("Pipable:        %"TS"\n"),
-               info->pipable ? T("yes") : T("no"));
-       tputchar(T('\n'));
+
+       attr_string[0] = T('\0');
+
+       if (info->pipable)
+               tstrcat(attr_string, T("Pipable, "));
+
+       if (info->has_integrity_table)
+               tstrcat(attr_string, T("Integrity info, "));
+
+       if (info->has_rpfix)
+               tstrcat(attr_string, T("Relative path junction, "));
+
+       if (info->resource_only)
+               tstrcat(attr_string, T("Resource only, "));
+
+       if (info->metadata_only)
+               tstrcat(attr_string, T("Metadata only, "));
+
+       if (info->is_marked_readonly)
+               tstrcat(attr_string, T("Readonly, "));
+
+       p = tstrchr(attr_string, T('\0'));
+       if (p >= &attr_string[2] && p[-1] == T(' ') && p[-2] == T(','))
+               p[-2] = T('\0');
+
+       tprintf(T("Attributes:     %"TS"\n\n"), attr_string);
 }
 
 static int
@@ -2578,6 +2665,8 @@ imagex_dir(int argc, tchar **argv, int cmd)
        };
        int iterate_flags = WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE;
 
+       STRING_SET(refglobs);
+
        for_opt(c, dir_options) {
                switch (c) {
                case IMAGEX_PATH_OPTION:
@@ -2589,6 +2678,11 @@ imagex_dir(int argc, tchar **argv, int cmd)
                case IMAGEX_ONE_FILE_ONLY_OPTION:
                        iterate_flags &= ~WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE;
                        break;
+               case IMAGEX_REF_OPTION:
+                       ret = string_set_append(&refglobs, optarg);
+                       if (ret)
+                               goto out_free_refglobs;
+                       break;
                default:
                        goto out_usage;
                }
@@ -2609,7 +2703,7 @@ imagex_dir(int argc, tchar **argv, int cmd)
        ret = wimlib_open_wim_with_progress(wimfile, 0, &wim,
                                            imagex_progress_func, NULL);
        if (ret)
-               goto out;
+               goto out_free_refglobs;
 
        if (argc >= 2) {
                image = wimlib_resolve_image(wim, argv[1]);
@@ -2633,17 +2727,30 @@ imagex_dir(int argc, tchar **argv, int cmd)
                image = 1;
        }
 
+       if (refglobs.num_strings) {
+               ret = wim_reference_globs(wim, &refglobs, 0);
+               if (ret)
+                       goto out_wimlib_free;
+       }
+
        ret = wimlib_iterate_dir_tree(wim, image, path, iterate_flags,
                                      print_dentry, &options);
+       if (ret == WIMLIB_ERR_METADATA_NOT_FOUND) {
+               struct wimlib_wim_info info;
+
+               wimlib_get_wim_info(wim, &info);
+               do_metadata_not_found_warning(wimfile, &info);
+       }
 out_wimlib_free:
        wimlib_free(wim);
-out:
+out_free_refglobs:
+       string_set_destroy(&refglobs);
        return ret;
 
 out_usage:
        usage(CMD_DIR, stderr);
        ret = -1;
-       goto out;
+       goto out_free_refglobs;
 }
 
 /* Exports one, or all, images from a WIM file to a new WIM file or an existing
@@ -2742,6 +2849,9 @@ imagex_export(int argc, tchar **argv, int cmd)
                case IMAGEX_WIMBOOT_OPTION:
                        export_flags |= WIMLIB_EXPORT_FLAG_WIMBOOT;
                        break;
+               case IMAGEX_UNSAFE_COMPACT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -2908,6 +3018,8 @@ imagex_export(int argc, tchar **argv, int cmd)
                if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND) {
                        do_resource_not_found_warning(src_wimfile,
                                                      &src_info, &refglobs);
+               } else if (ret == WIMLIB_ERR_METADATA_NOT_FOUND) {
+                       do_metadata_not_found_warning(src_wimfile, &src_info);
                }
                goto out_free_dest_wim;
        }
@@ -3007,6 +3119,11 @@ imagex_extract(int argc, tchar **argv, int cmd)
                case IMAGEX_WIMBOOT_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_WIMBOOT;
                        break;
+               case IMAGEX_COMPACT_OPTION:
+                       ret = set_compact_mode(optarg, &extract_flags);
+                       if (ret)
+                               goto out_free_refglobs;
+                       break;
                default:
                        goto out_usage;
                }
@@ -3100,6 +3217,11 @@ imagex_extract(int argc, tchar **argv, int cmd)
 
                wimlib_get_wim_info(wim, &info);
                do_resource_not_found_warning(wimfile, &info, &refglobs);
+       } else if (ret == WIMLIB_ERR_METADATA_NOT_FOUND) {
+               struct wimlib_wim_info info;
+
+               wimlib_get_wim_info(wim, &info);
+               do_metadata_not_found_warning(wimfile, &info);
        }
 out_wimlib_free:
        wimlib_free(wim);
@@ -3534,9 +3656,13 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
 
        ret = wimlib_mount_image(wim, image, dir, mount_flags, staging_dir);
        if (ret) {
-               imagex_error(T("Failed to mount image %d from \"%"TS"\" "
-                              "on \"%"TS"\""),
-                            image, wimfile, dir);
+               if (ret == WIMLIB_ERR_METADATA_NOT_FOUND) {
+                       do_metadata_not_found_warning(wimfile, &info);
+               } else {
+                       imagex_error(T("Failed to mount image %d from \"%"TS"\" "
+                                      "on \"%"TS"\""),
+                                    image, wimfile, dir);
+               }
        }
 out_free_wim:
        wimlib_free(wim);
@@ -3624,6 +3750,9 @@ imagex_optimize(int argc, tchar **argv, int cmd)
                case IMAGEX_NOT_PIPABLE_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_NOT_PIPABLE;
                        break;
+               case IMAGEX_UNSAFE_COMPACT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -3921,6 +4050,9 @@ imagex_update(int argc, tchar **argv, int cmd)
                case IMAGEX_NO_REPLACE_OPTION:
                        default_add_flags |= WIMLIB_ADD_FLAG_NO_REPLACE;
                        break;
+               case IMAGEX_UNSAFE_COMPACT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -4190,6 +4322,7 @@ T(
 "                    [--check] [--ref=\"GLOB\"] [--no-acls] [--strict-acls]\n"
 "                    [--no-attributes] [--rpfix] [--norpfix]\n"
 "                    [--include-invalid-names] [--wimboot] [--unix-data]\n"
+"                    [--compact=FORMAT]\n"
 ),
 [CMD_CAPTURE] =
 T(