]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
wimlib-imagex: forbid --unsafe-compact when it doesn't make sense
[wimlib] / programs / imagex.c
index 762459e84ebc36cd42399c4308dea96b2d6604c1..feb363043d527c55f5c917a7fbc2306b1e12fb61 100644 (file)
@@ -147,6 +147,7 @@ enum {
        IMAGEX_CHUNK_SIZE_OPTION,
        IMAGEX_COMMAND_OPTION,
        IMAGEX_COMMIT_OPTION,
+       IMAGEX_COMPACT_OPTION,
        IMAGEX_COMPRESS_OPTION,
        IMAGEX_COMPRESS_SLOW_OPTION,
        IMAGEX_CONFIG_OPTION,
@@ -193,6 +194,7 @@ 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_CONFIG_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,
@@ -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,14 @@ 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:
+                       if (cmd != CMD_APPEND) {
+                               imagex_error(T("'--unsafe-compact' is only "
+                                              "valid for append!"));
+                               goto out_err;
+                       }
+                       write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -2300,6 +2367,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;
                }
@@ -2435,26 +2505,26 @@ print_wim_information(const tchar *wimfile, const struct wimlib_wim_info *info)
        attr_string[0] = T('\0');
 
        if (info->pipable)
-               tstrcat(attr_string, "Pipable, ");
+               tstrcat(attr_string, T("Pipable, "));
 
        if (info->has_integrity_table)
-               tstrcat(attr_string, "Integrity info, ");
+               tstrcat(attr_string, T("Integrity info, "));
 
        if (info->has_rpfix)
-               tstrcat(attr_string, "Relative path junction, ");
+               tstrcat(attr_string, T("Relative path junction, "));
 
        if (info->resource_only)
-               tstrcat(attr_string, "Resource only, ");
+               tstrcat(attr_string, T("Resource only, "));
 
        if (info->metadata_only)
-               tstrcat(attr_string, "Metadata only, ");
+               tstrcat(attr_string, T("Metadata only, "));
 
        if (info->is_marked_readonly)
-               tstrcat(attr_string, "Readonly, ");
+               tstrcat(attr_string, T("Readonly, "));
 
-       p = tstrchr(attr_string, '\0');
+       p = tstrchr(attr_string, T('\0'));
        if (p >= &attr_string[2] && p[-1] == T(' ') && p[-2] == T(','))
-               p[-2] = '\0';
+               p[-2] = T('\0');
 
        tprintf(T("Attributes:     %"TS"\n\n"), attr_string);
 }
@@ -2600,6 +2670,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:
@@ -2611,6 +2683,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;
                }
@@ -2631,7 +2708,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]);
@@ -2655,17 +2732,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
@@ -2764,6 +2854,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;
                }
@@ -2853,6 +2946,13 @@ imagex_export(int argc, tchar **argv, int cmd)
                        goto out_free_src_wim;
                }
 
+               if (write_flags & WIMLIB_WRITE_FLAG_UNSAFE_COMPACT) {
+                       imagex_error(T("'--unsafe-compact' is only valid when "
+                                      "exporting to an existing WIM file!"));
+                       ret = -1;
+                       goto out_free_src_wim;
+               }
+
                /* dest_wimfile is not an existing file, so create a new WIM. */
 
                if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
@@ -2930,6 +3030,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;
        }
@@ -3029,6 +3131,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;
                }
@@ -3122,6 +3229,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);
@@ -3556,9 +3668,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);
@@ -3646,6 +3762,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;
                }
@@ -3943,6 +4062,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;
                }
@@ -4212,6 +4334,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(