]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
wimlib-imagex: list --solid in help for more commands
[wimlib] / programs / imagex.c
index 1c077b7f2fae1afb1db12fc53cf0c99b8894c4a1..9334623d55c414981cee6d2893770cdc96b90ac0 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012, 2013, 2014, 2015 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
@@ -124,6 +124,7 @@ enum {
        CMD_UNMOUNT,
 #endif
        CMD_UPDATE,
+       CMD_VERIFY,
        CMD_MAX,
 };
 
@@ -169,11 +170,9 @@ enum {
        IMAGEX_NO_ATTRIBUTES_OPTION,
        IMAGEX_NO_REPLACE_OPTION,
        IMAGEX_NO_GLOBS_OPTION,
+       IMAGEX_NO_SOLID_SORT_OPTION,
        IMAGEX_NULLGLOB_OPTION,
        IMAGEX_ONE_FILE_ONLY_OPTION,
-       IMAGEX_PACK_CHUNK_SIZE_OPTION,
-       IMAGEX_PACK_COMPRESS_OPTION,
-       IMAGEX_PACK_STREAMS_OPTION,
        IMAGEX_PATH_OPTION,
        IMAGEX_PIPABLE_OPTION,
        IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION,
@@ -184,6 +183,9 @@ enum {
        IMAGEX_RESUME_OPTION,
        IMAGEX_RPFIX_OPTION,
        IMAGEX_SOFT_OPTION,
+       IMAGEX_SOLID_OPTION,
+       IMAGEX_SOLID_CHUNK_SIZE_OPTION,
+       IMAGEX_SOLID_COMPRESS_OPTION,
        IMAGEX_SOURCE_LIST_OPTION,
        IMAGEX_STAGING_DIR_OPTION,
        IMAGEX_STREAMS_INTERFACE_OPTION,
@@ -225,12 +227,13 @@ static const struct option capture_or_append_options[] = {
        {T("compress"),    required_argument, NULL, IMAGEX_COMPRESS_OPTION},
        {T("compress-slow"), no_argument,     NULL, IMAGEX_COMPRESS_SLOW_OPTION},
        {T("chunk-size"),  required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION},
-       {T("pack-chunk-size"), required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
-       {T("solid-chunk-size"),required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
-       {T("pack-compress"), required_argument, NULL, IMAGEX_PACK_COMPRESS_OPTION},
-       {T("solid-compress"),required_argument, NULL, IMAGEX_PACK_COMPRESS_OPTION},
-       {T("pack-streams"), no_argument,      NULL, IMAGEX_PACK_STREAMS_OPTION},
-       {T("solid"),       no_argument,      NULL, IMAGEX_PACK_STREAMS_OPTION},
+       {T("solid"),       no_argument,      NULL, IMAGEX_SOLID_OPTION},
+       {T("pack-streams"), no_argument,      NULL, IMAGEX_SOLID_OPTION},
+       {T("solid-compress"),required_argument, NULL, IMAGEX_SOLID_COMPRESS_OPTION},
+       {T("pack-compress"), required_argument, NULL, IMAGEX_SOLID_COMPRESS_OPTION},
+       {T("solid-chunk-size"),required_argument, NULL, IMAGEX_SOLID_CHUNK_SIZE_OPTION},
+       {T("pack-chunk-size"), required_argument, NULL, IMAGEX_SOLID_CHUNK_SIZE_OPTION},
+       {T("no-solid-sort"), no_argument,     NULL, IMAGEX_NO_SOLID_SORT_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},
@@ -273,13 +276,14 @@ static const struct option export_options[] = {
        {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("pack-streams"),no_argument,       NULL, IMAGEX_PACK_STREAMS_OPTION},
-       {T("solid"),       no_argument,       NULL, IMAGEX_PACK_STREAMS_OPTION},
        {T("chunk-size"),  required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION},
-       {T("pack-chunk-size"), required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
-       {T("solid-chunk-size"),required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
-       {T("pack-compress"), required_argument, NULL, IMAGEX_PACK_COMPRESS_OPTION},
-       {T("solid-compress"),required_argument, NULL, IMAGEX_PACK_COMPRESS_OPTION},
+       {T("solid"),       no_argument,       NULL, IMAGEX_SOLID_OPTION},
+       {T("pack-streams"),no_argument,       NULL, IMAGEX_SOLID_OPTION},
+       {T("solid-compress"),required_argument, NULL, IMAGEX_SOLID_COMPRESS_OPTION},
+       {T("pack-compress"), required_argument, NULL, IMAGEX_SOLID_COMPRESS_OPTION},
+       {T("solid-chunk-size"),required_argument, NULL, IMAGEX_SOLID_CHUNK_SIZE_OPTION},
+       {T("pack-chunk-size"), required_argument, NULL, IMAGEX_SOLID_CHUNK_SIZE_OPTION},
+       {T("no-solid-sort"), no_argument,     NULL, IMAGEX_NO_SOLID_SORT_OPTION},
        {T("ref"),         required_argument, NULL, IMAGEX_REF_OPTION},
        {T("threads"),     required_argument, NULL, IMAGEX_THREADS_OPTION},
        {T("rebuild"),     no_argument,       NULL, IMAGEX_REBUILD_OPTION},
@@ -345,14 +349,15 @@ static const struct option optimize_options[] = {
        {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("recompress-slow"), no_argument,   NULL, IMAGEX_COMPRESS_SLOW_OPTION},
        {T("chunk-size"),  required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION},
-       {T("pack-chunk-size"), required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
-       {T("solid-chunk-size"),required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
-       {T("pack-compress"), required_argument, NULL, IMAGEX_PACK_COMPRESS_OPTION},
-       {T("solid-compress"),required_argument, NULL, IMAGEX_PACK_COMPRESS_OPTION},
-       {T("pack-streams"),no_argument,       NULL, IMAGEX_PACK_STREAMS_OPTION},
-       {T("solid"),       no_argument,       NULL, IMAGEX_PACK_STREAMS_OPTION},
+       {T("solid"),       no_argument,       NULL, IMAGEX_SOLID_OPTION},
+       {T("pack-streams"),no_argument,       NULL, IMAGEX_SOLID_OPTION},
+       {T("solid-compress"),required_argument, NULL, IMAGEX_SOLID_COMPRESS_OPTION},
+       {T("pack-compress"), required_argument, NULL, IMAGEX_SOLID_COMPRESS_OPTION},
+       {T("solid-chunk-size"),required_argument, NULL, IMAGEX_SOLID_CHUNK_SIZE_OPTION},
+       {T("pack-chunk-size"), required_argument, NULL, IMAGEX_SOLID_CHUNK_SIZE_OPTION},
+       {T("no-solid-sort"), no_argument,     NULL, IMAGEX_NO_SOLID_SORT_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},
@@ -404,6 +409,13 @@ static const struct option update_options[] = {
        {NULL, 0, NULL, 0},
 };
 
+static const struct option verify_options[] = {
+       {T("ref"), required_argument, NULL, IMAGEX_REF_OPTION},
+       {T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
+
+       {NULL, 0, NULL, 0},
+};
+
 #if 0
 #      define _format_attribute(type, format_str, args_start) \
                        __attribute__((format(type, format_str, args_start)))
@@ -474,64 +486,74 @@ verify_image_exists_and_is_single(int image, const tchar *image_name,
        return ret;
 }
 
+static void
+print_available_compression_types(FILE *fp)
+{
+       static const tchar *s =
+       T(
+       "Available compression types:\n"
+       "\n"
+       "    none\n"
+       "    xpress (alias: \"fast\")\n"
+       "    lzx    (alias: \"maximum\") (default for capture)\n"
+       "    lzms   (alias: \"recovery\")\n"
+       "\n"
+       );
+       tfputs(s, fp);
+}
+
 /* Parse the argument to --compress */
 static int
-get_compression_type(const tchar *optarg)
+get_compression_type(tchar *optarg)
 {
+       int ctype;
+       unsigned int compression_level = 0;
+       tchar *plevel;
+
+       plevel = tstrchr(optarg, T(':'));
+       if (plevel) {
+               tchar *ptmp;
+               unsigned long ultmp;
+
+               *plevel++ = T('\0');
+               ultmp = tstrtoul(plevel, &ptmp, 10);
+               if (ultmp >= UINT_MAX || ultmp == 0 || *ptmp || ptmp == plevel) {
+                       imagex_error(T("Compression level must be a positive integer! "
+                                      "e.g. --compress=lzx:80"));
+                       return WIMLIB_COMPRESSION_TYPE_INVALID;
+               }
+               compression_level = ultmp;
+       }
+
        if (!tstrcasecmp(optarg, T("maximum")) ||
            !tstrcasecmp(optarg, T("lzx")) ||
            !tstrcasecmp(optarg, T("max")))
-               return WIMLIB_COMPRESSION_TYPE_LZX;
+               ctype = WIMLIB_COMPRESSION_TYPE_LZX;
        else if (!tstrcasecmp(optarg, T("fast")) || !tstrcasecmp(optarg, T("xpress")))
-               return WIMLIB_COMPRESSION_TYPE_XPRESS;
+               ctype = WIMLIB_COMPRESSION_TYPE_XPRESS;
        else if (!tstrcasecmp(optarg, T("recovery")) || !tstrcasecmp(optarg, T("lzms")))
-               return WIMLIB_COMPRESSION_TYPE_LZMS;
+               ctype = WIMLIB_COMPRESSION_TYPE_LZMS;
        else if (!tstrcasecmp(optarg, T("none")))
-               return WIMLIB_COMPRESSION_TYPE_NONE;
+               ctype = WIMLIB_COMPRESSION_TYPE_NONE;
        else {
-               imagex_error(T("Invalid compression type \"%"TS"\"! Must be "
-                            "\"maximum\", \"fast\", or \"none\"."), optarg);
+               imagex_error(T("Invalid compression type \"%"TS"\"!"), optarg);
+               print_available_compression_types(stderr);
                return WIMLIB_COMPRESSION_TYPE_INVALID;
        }
+
+       if (compression_level != 0)
+               wimlib_set_default_compression_level(ctype, compression_level);
+       return ctype;
 }
 
 static void
 set_compress_slow(void)
 {
-       static const struct wimlib_lzx_compressor_params lzx_slow_params = {
-               .hdr = {
-                       .size = sizeof(struct wimlib_lzx_compressor_params),
-               },
-               .algorithm = WIMLIB_LZX_ALGORITHM_SLOW,
-               .alg_params = {
-                       .slow = {
-                               .use_len2_matches = 1,
-                               .nice_match_length = 96,
-                               .num_optim_passes = 4,
-                               .max_search_depth = 100,
-                               .main_nostat_cost = 15,
-                               .len_nostat_cost = 15,
-                               .aligned_nostat_cost = 7,
-                       },
-               },
-       };
-
-       static const struct wimlib_lzms_compressor_params lzms_slow_params = {
-               .hdr = {
-                       .size = sizeof(struct wimlib_lzms_compressor_params),
-               },
-               .min_match_length = 2,
-               .max_match_length = UINT32_MAX,
-               .nice_match_length = 96,
-               .max_search_depth = 100,
-               .optim_array_length = 1024,
-       };
-
-       wimlib_set_default_compressor_params(WIMLIB_COMPRESSION_TYPE_LZX,
-                                            &lzx_slow_params.hdr);
-
-       wimlib_set_default_compressor_params(WIMLIB_COMPRESSION_TYPE_LZMS,
-                                            &lzms_slow_params.hdr);
+#if 0
+       fprintf(stderr, "WARNING: the '--compress-slow' option is deprecated.\n"
+                       "         Use the '--compress=TYPE:LEVEL' option instead.\n");
+#endif
+       wimlib_set_default_compression_level(-1, 100);
 }
 
 struct string_set {
@@ -1143,6 +1165,17 @@ imagex_progress_func(enum wimlib_progress_msg msg,
                         T("NTFS volume") : T("directory")),
                        info->extract.target);
                break;
+       case WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE:
+               if (info->extract.end_file_count >= 2000) {
+                       percent_done = TO_PERCENT(info->extract.current_file_count,
+                                                 info->extract.end_file_count);
+                       imagex_printf(T("\rCreating files: %"PRIu64" of %"PRIu64" (%u%%) done"),
+                                     info->extract.current_file_count,
+                                     info->extract.end_file_count, percent_done);
+                       if (info->extract.current_file_count == info->extract.end_file_count)
+                               imagex_printf(T("\n"));
+               }
+               break;
        case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
                percent_done = TO_PERCENT(info->extract.completed_bytes,
                                          info->extract.total_bytes);
@@ -1157,6 +1190,17 @@ imagex_progress_func(enum wimlib_progress_msg msg,
                if (info->extract.completed_bytes >= info->extract.total_bytes)
                        imagex_printf(T("\n"));
                break;
+       case WIMLIB_PROGRESS_MSG_EXTRACT_METADATA:
+               if (info->extract.end_file_count >= 2000) {
+                       percent_done = TO_PERCENT(info->extract.current_file_count,
+                                                 info->extract.end_file_count);
+                       imagex_printf(T("\rApplying metadata to files: %"PRIu64" of %"PRIu64" (%u%%) done"),
+                                     info->extract.current_file_count,
+                                     info->extract.end_file_count, percent_done);
+                       if (info->extract.current_file_count == info->extract.end_file_count)
+                               imagex_printf(T("\n"));
+               }
+               break;
        case WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN:
                if (info->extract.total_parts != 1) {
                        imagex_printf(T("\nReading split pipable WIM part %u of %u\n"),
@@ -1224,6 +1268,25 @@ imagex_progress_func(enum wimlib_progress_msg msg,
                        }
                }
                break;
+       case WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE:
+               imagex_printf(T("Verifying metadata for image %"PRIu32" of %"PRIu32"\n"),
+                             info->verify_image.current_image,
+                             info->verify_image.total_images);
+               break;
+       case WIMLIB_PROGRESS_MSG_VERIFY_STREAMS:
+               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: "
+                         "%"PRIu64" %"TS" of %"PRIu64" %"TS" (%u%%) done"),
+                       info->verify_streams.completed_bytes >> unit_shift,
+                       unit_name,
+                       info->verify_streams.total_bytes >> unit_shift,
+                       unit_name,
+                       percent_done);
+               if (info->verify_streams.completed_bytes == info->verify_streams.total_bytes)
+                       imagex_printf(T("\n"));
+               break;
        default:
                break;
        }
@@ -1244,16 +1307,37 @@ parse_num_threads(const tchar *optarg)
        }
 }
 
-static uint32_t parse_chunk_size(const tchar *optarg)
+static uint32_t
+parse_chunk_size(const tchar *optarg)
 {
-       tchar *tmp;
-       unsigned long chunk_size = tstrtoul(optarg, &tmp, 10);
-       if (chunk_size >= UINT32_MAX || *tmp || tmp == optarg) {
-               imagex_error(T("Chunk size must be a non-negative integer!"));
-               return UINT32_MAX;
-       } else {
-               return chunk_size;
-       }
+       tchar *tmp;
+       uint64_t chunk_size = tstrtoul(optarg, &tmp, 10);
+       if (chunk_size == 0) {
+               imagex_error(T("Invalid chunk size specification; must be a positive integer\n"
+                              "       with optional K, M, or G suffix"));
+               return UINT32_MAX;
+       }
+       if (*tmp) {
+               if (*tmp == T('k') || *tmp == T('K')) {
+                       chunk_size <<= 10;
+                       tmp++;
+               } else if (*tmp == T('m') || *tmp == T('M')) {
+                       chunk_size <<= 20;
+                       tmp++;
+               } else if (*tmp == T('g') || *tmp == T('G')) {
+                       chunk_size <<= 30;
+                       tmp++;
+               }
+               if (*tmp && !(*tmp == T('i') && *(tmp + 1) == T('B'))) {
+                       imagex_error(T("Invalid chunk size specification; suffix must be K, M, or G"));
+                       return UINT32_MAX;
+               }
+       }
+       if (chunk_size >= UINT32_MAX) {
+               imagex_error(T("Invalid chunk size specification; the value is too large!"));
+               return UINT32_MAX;
+       }
+       return chunk_size;
 }
 
 
@@ -1654,15 +1738,15 @@ static int
 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 |
-                             WIMLIB_ADD_IMAGE_FLAG_WINCONFIG |
-                             WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
+       int open_flags = 0;
+       int add_flags = WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE |
+                       WIMLIB_ADD_FLAG_WINCONFIG |
+                       WIMLIB_ADD_FLAG_VERBOSE;
        int write_flags = 0;
        int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
        uint32_t chunk_size = UINT32_MAX;
-       uint32_t pack_chunk_size = UINT32_MAX;
-       int pack_ctype = WIMLIB_COMPRESSION_TYPE_INVALID;
+       uint32_t solid_chunk_size = UINT32_MAX;
+       int solid_ctype = WIMLIB_COMPRESSION_TYPE_INVALID;
        const tchar *wimfile;
        int wim_fd;
        const tchar *name;
@@ -1693,12 +1777,11 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        struct wimlib_capture_source *capture_sources;
        size_t num_sources;
        bool name_defaulted;
-       bool compress_slow = false;
 
        for_opt(c, capture_or_append_options) {
                switch (c) {
                case IMAGEX_BOOT_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_BOOT;
+                       add_flags |= WIMLIB_ADD_FLAG_BOOT;
                        break;
                case IMAGEX_CHECK_OPTION:
                        open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
@@ -1709,7 +1792,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;
+                       add_flags &= ~WIMLIB_ADD_FLAG_WINCONFIG;
                        break;
                case IMAGEX_COMPRESS_OPTION:
                        compression_type = get_compression_type(optarg);
@@ -1717,31 +1800,34 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                goto out_err;
                        break;
                case IMAGEX_COMPRESS_SLOW_OPTION:
-                       compress_slow = true;
+                       set_compress_slow();
                        break;
                case IMAGEX_CHUNK_SIZE_OPTION:
                        chunk_size = parse_chunk_size(optarg);
                        if (chunk_size == UINT32_MAX)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_CHUNK_SIZE_OPTION:
-                       pack_chunk_size = parse_chunk_size(optarg);
-                       if (pack_chunk_size == UINT32_MAX)
+               case IMAGEX_SOLID_CHUNK_SIZE_OPTION:
+                       solid_chunk_size = parse_chunk_size(optarg);
+                       if (solid_chunk_size == UINT32_MAX)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_COMPRESS_OPTION:
-                       pack_ctype = get_compression_type(optarg);
-                       if (pack_ctype == WIMLIB_COMPRESSION_TYPE_INVALID)
+               case IMAGEX_SOLID_COMPRESS_OPTION:
+                       solid_ctype = get_compression_type(optarg);
+                       if (solid_ctype == WIMLIB_COMPRESSION_TYPE_INVALID)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_STREAMS_OPTION:
-                       write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+               case IMAGEX_SOLID_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_SOLID;
+                       break;
+               case IMAGEX_NO_SOLID_SORT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_NO_SOLID_SORT;
                        break;
                case IMAGEX_FLAGS_OPTION:
                        flags_element = optarg;
                        break;
                case IMAGEX_DEREFERENCE_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE;
+                       add_flags |= WIMLIB_ADD_FLAG_DEREFERENCE;
                        break;
                case IMAGEX_VERBOSE_OPTION:
                        /* No longer does anything.  */
@@ -1755,22 +1841,22 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
                        break;
                case IMAGEX_UNIX_DATA_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA;
+                       add_flags |= WIMLIB_ADD_FLAG_UNIX_DATA;
                        break;
                case IMAGEX_SOURCE_LIST_OPTION:
                        source_list = true;
                        break;
                case IMAGEX_NO_ACLS_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NO_ACLS;
+                       add_flags |= WIMLIB_ADD_FLAG_NO_ACLS;
                        break;
                case IMAGEX_STRICT_ACLS_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_STRICT_ACLS;
+                       add_flags |= WIMLIB_ADD_FLAG_STRICT_ACLS;
                        break;
                case IMAGEX_RPFIX_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+                       add_flags |= WIMLIB_ADD_FLAG_RPFIX;
                        break;
                case IMAGEX_NORPFIX_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NORPFIX;
+                       add_flags |= WIMLIB_ADD_FLAG_NORPFIX;
                        break;
                case IMAGEX_PIPABLE_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_PIPABLE;
@@ -1809,7 +1895,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        write_flags |= WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS;
                        break;
                case IMAGEX_WIMBOOT_OPTION:
-                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_WIMBOOT;
+                       add_flags |= WIMLIB_ADD_FLAG_WIMBOOT;
                        break;
                default:
                        goto out_usage;
@@ -1830,33 +1916,19 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
                /* No compression type specified.  Use the default.  */
 
-               if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_WIMBOOT) {
+               if (add_flags & WIMLIB_ADD_FLAG_WIMBOOT) {
                        /* With --wimboot, default to XPRESS compression.  */
                        compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
-               } else if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS) {
-                       /* With --pack-streams or --solid, default to LZMS
-                        * compression.  (However, this will not affect packed
-                        * resources!)  */
+               } else if (write_flags & WIMLIB_WRITE_FLAG_SOLID) {
+                       /* With --solid, default to LZMS compression.  (However,
+                        * this will not affect solid resources!)  */
                        compression_type = WIMLIB_COMPRESSION_TYPE_LZMS;
                } else {
-                       /* Otherwise, default to LZX compression in fast mode.
-                        */
+                       /* Otherwise, default to LZX compression.  */
                        compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
-                       if (!compress_slow && pack_ctype != WIMLIB_COMPRESSION_TYPE_LZX) {
-                               struct wimlib_lzx_compressor_params params = {
-                                       .hdr.size = sizeof(params),
-                                       .algorithm = WIMLIB_LZX_ALGORITHM_FAST,
-                                       .use_defaults = 1,
-                               };
-                               wimlib_set_default_compressor_params(WIMLIB_COMPRESSION_TYPE_LZX,
-                                                                    &params.hdr);
-                       }
                }
        }
 
-       if (compress_slow)
-               set_compress_slow();
-
        if (!tstrcmp(wimfile, T("-"))) {
                /* Writing captured WIM to standard output.  */
        #if 0
@@ -1963,8 +2035,11 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 
        /* Open the existing WIM, or create a new one.  */
        if (cmd == CMD_APPEND) {
-               ret = wimlib_open_wim_with_progress(wimfile, open_flags, &wim,
-                                                   imagex_progress_func, NULL);
+               ret = wimlib_open_wim_with_progress(wimfile,
+                                                   open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS,
+                                                   &wim,
+                                                   imagex_progress_func,
+                                                   NULL);
                if (ret)
                        goto out_free_capture_sources;
        } else {
@@ -1979,19 +2054,19 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                ret = wimlib_set_output_chunk_size(wim, chunk_size);
                if (ret)
                        goto out_free_wim;
-       } else if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_WIMBOOT) &&
+       } else if ((add_flags & WIMLIB_ADD_FLAG_WIMBOOT) &&
                   compression_type == WIMLIB_COMPRESSION_TYPE_XPRESS) {
                ret = wimlib_set_output_chunk_size(wim, 4096);
                if (ret)
                        goto out_free_wim;
        }
-       if (pack_ctype != WIMLIB_COMPRESSION_TYPE_INVALID) {
-               ret = wimlib_set_output_pack_compression_type(wim, pack_ctype);
+       if (solid_ctype != WIMLIB_COMPRESSION_TYPE_INVALID) {
+               ret = wimlib_set_output_pack_compression_type(wim, solid_ctype);
                if (ret)
                        goto out_free_wim;
        }
-       if (pack_chunk_size != UINT32_MAX) {
-               ret = wimlib_set_output_pack_chunk_size(wim, pack_chunk_size);
+       if (solid_chunk_size != UINT32_MAX) {
+               ret = wimlib_set_output_pack_chunk_size(wim, solid_chunk_size);
                if (ret)
                        goto out_free_wim;
        }
@@ -2006,7 +2081,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) {
                                imagex_printf(T("Capturing WIM image from NTFS "
                                          "filesystem on \"%"TS"\"\n"), source);
-                               add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NTFS;
+                               add_flags |= WIMLIB_ADD_FLAG_NTFS;
                        }
                } else {
                        if (errno != ENOENT) {
@@ -2046,9 +2121,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 
                for (size_t i = 0; i < base_wimfiles.num_strings; i++) {
                        ret = wimlib_open_wim_with_progress(
-                                   base_wimfiles.strings[i],
-                                   open_flags, &base_wims[i],
-                                   imagex_progress_func, NULL);
+                                   base_wimfiles.strings[i], open_flags,
+                                   &base_wims[i], imagex_progress_func, NULL);
                        if (ret)
                                goto out_free_base_wims;
 
@@ -2122,7 +2196,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                           num_sources,
                                           name,
                                           config_file,
-                                          add_image_flags);
+                                          add_flags);
        if (ret)
                goto out_free_template_wim;
 
@@ -2403,7 +2477,7 @@ print_resource(const struct wimlib_resource_entry *resource,
                if (resource->is_spanned)
                        tprintf(T("WIM_RESHDR_FLAG_SPANNED  "));
                if (resource->packed)
-                       tprintf(T("WIM_RESHDR_FLAG_PACKED_STREAMS  "));
+                       tprintf(T("WIM_RESHDR_FLAG_SOLID  "));
                tputchar(T('\n'));
        }
        tputchar(T('\n'));
@@ -2593,8 +2667,8 @@ imagex_export(int argc, tchar **argv, int cmd)
        STRING_SET(refglobs);
        unsigned num_threads = 0;
        uint32_t chunk_size = UINT32_MAX;
-       uint32_t pack_chunk_size = UINT32_MAX;
-       int pack_ctype = WIMLIB_COMPRESSION_TYPE_INVALID;
+       uint32_t solid_chunk_size = UINT32_MAX;
+       int solid_ctype = WIMLIB_COMPRESSION_TYPE_INVALID;
 
        for_opt(c, export_options) {
                switch (c) {
@@ -2613,29 +2687,32 @@ imagex_export(int argc, tchar **argv, int cmd)
                        if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
                                goto out_err;
                        break;
-               case IMAGEX_RECOMPRESS_OPTION:
+               case IMAGEX_COMPRESS_SLOW_OPTION:
+                       set_compress_slow();
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
                        break;
-               case IMAGEX_COMPRESS_SLOW_OPTION:
+               case IMAGEX_RECOMPRESS_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
-                       set_compress_slow();
                        break;
-               case IMAGEX_PACK_STREAMS_OPTION:
-                       write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+               case IMAGEX_SOLID_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_SOLID;
+                       break;
+               case IMAGEX_NO_SOLID_SORT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_NO_SOLID_SORT;
                        break;
                case IMAGEX_CHUNK_SIZE_OPTION:
                        chunk_size = parse_chunk_size(optarg);
                        if (chunk_size == UINT32_MAX)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_CHUNK_SIZE_OPTION:
-                       pack_chunk_size = parse_chunk_size(optarg);
-                       if (pack_chunk_size == UINT32_MAX)
+               case IMAGEX_SOLID_CHUNK_SIZE_OPTION:
+                       solid_chunk_size = parse_chunk_size(optarg);
+                       if (solid_chunk_size == UINT32_MAX)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_COMPRESS_OPTION:
-                       pack_ctype = get_compression_type(optarg);
-                       if (pack_ctype == WIMLIB_COMPRESSION_TYPE_INVALID)
+               case IMAGEX_SOLID_COMPRESS_OPTION:
+                       solid_ctype = get_compression_type(optarg);
+                       if (solid_ctype == WIMLIB_COMPRESSION_TYPE_INVALID)
                                goto out_err;
                        break;
                case IMAGEX_REF_OPTION:
@@ -2753,10 +2830,10 @@ imagex_export(int argc, tchar **argv, int cmd)
 
                if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
                        /* The user did not specify a compression type; default
-                        * to that of the source WIM, unless --pack-streams,
-                        * --solid, or --wimboot was specified.   */
+                        * to that of the source WIM, unless --solid or
+                        * --wimboot was specified.   */
 
-                       if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS)
+                       if (write_flags & WIMLIB_WRITE_FLAG_SOLID)
                                compression_type = WIMLIB_COMPRESSION_TYPE_LZMS;
                        else if (export_flags & WIMLIB_EXPORT_FLAG_WIMBOOT)
                                compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
@@ -2789,13 +2866,13 @@ imagex_export(int argc, tchar **argv, int cmd)
                if (ret)
                        goto out_free_dest_wim;
        }
-       if (pack_ctype != WIMLIB_COMPRESSION_TYPE_INVALID) {
-               ret = wimlib_set_output_pack_compression_type(dest_wim, pack_ctype);
+       if (solid_ctype != WIMLIB_COMPRESSION_TYPE_INVALID) {
+               ret = wimlib_set_output_pack_compression_type(dest_wim, solid_ctype);
                if (ret)
                        goto out_free_dest_wim;
        }
-       if (pack_chunk_size != UINT32_MAX) {
-               ret = wimlib_set_output_pack_chunk_size(dest_wim, pack_chunk_size);
+       if (solid_chunk_size != UINT32_MAX) {
+               ret = wimlib_set_output_pack_chunk_size(dest_wim, solid_chunk_size);
                if (ret)
                        goto out_free_dest_wim;
        }
@@ -3478,8 +3555,8 @@ imagex_optimize(int argc, tchar **argv, int cmd)
        int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
        int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
        uint32_t chunk_size = UINT32_MAX;
-       uint32_t pack_chunk_size = UINT32_MAX;
-       int pack_ctype = WIMLIB_COMPRESSION_TYPE_INVALID;
+       uint32_t solid_chunk_size = UINT32_MAX;
+       int solid_ctype = WIMLIB_COMPRESSION_TYPE_INVALID;
        int ret;
        WIMStruct *wim;
        const tchar *wimfile;
@@ -3502,32 +3579,35 @@ imagex_optimize(int argc, tchar **argv, int cmd)
                        if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
                                goto out_err;
                        break;
-               case IMAGEX_RECOMPRESS_OPTION:
+               case IMAGEX_COMPRESS_SLOW_OPTION:
+                       set_compress_slow();
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
                        break;
-               case IMAGEX_COMPRESS_SLOW_OPTION:
+               case IMAGEX_RECOMPRESS_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
-                       set_compress_slow();
                        break;
                case IMAGEX_CHUNK_SIZE_OPTION:
                        chunk_size = parse_chunk_size(optarg);
                        if (chunk_size == UINT32_MAX)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_CHUNK_SIZE_OPTION:
-                       pack_chunk_size = parse_chunk_size(optarg);
-                       if (pack_chunk_size == UINT32_MAX)
+               case IMAGEX_SOLID_CHUNK_SIZE_OPTION:
+                       solid_chunk_size = parse_chunk_size(optarg);
+                       if (solid_chunk_size == UINT32_MAX)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_COMPRESS_OPTION:
-                       pack_ctype = get_compression_type(optarg);
-                       if (pack_ctype == WIMLIB_COMPRESSION_TYPE_INVALID)
+               case IMAGEX_SOLID_COMPRESS_OPTION:
+                       solid_ctype = get_compression_type(optarg);
+                       if (solid_ctype == WIMLIB_COMPRESSION_TYPE_INVALID)
                                goto out_err;
                        break;
-               case IMAGEX_PACK_STREAMS_OPTION:
-                       write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+               case IMAGEX_SOLID_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_SOLID;
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
                        break;
+               case IMAGEX_NO_SOLID_SORT_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_NO_SOLID_SORT;
+                       break;
                case IMAGEX_THREADS_OPTION:
                        num_threads = parse_num_threads(optarg);
                        if (num_threads == UINT_MAX)
@@ -3569,13 +3649,13 @@ imagex_optimize(int argc, tchar **argv, int cmd)
                if (ret)
                        goto out_wimlib_free;
        }
-       if (pack_ctype != WIMLIB_COMPRESSION_TYPE_INVALID) {
-               ret = wimlib_set_output_pack_compression_type(wim, pack_ctype);
+       if (solid_ctype != WIMLIB_COMPRESSION_TYPE_INVALID) {
+               ret = wimlib_set_output_pack_compression_type(wim, solid_ctype);
                if (ret)
                        goto out_wimlib_free;
        }
-       if (pack_chunk_size != UINT32_MAX) {
-               ret = wimlib_set_output_pack_chunk_size(wim, pack_chunk_size);
+       if (solid_chunk_size != UINT32_MAX) {
+               ret = wimlib_set_output_pack_chunk_size(wim, solid_chunk_size);
                if (ret)
                        goto out_wimlib_free;
        }
@@ -3964,7 +4044,85 @@ out_err:
        goto out_free_command_str;
 }
 
+/* Verify a WIM file.  */
+static int
+imagex_verify(int argc, tchar **argv, int cmd)
+{
+       int ret;
+       const tchar *wimfile;
+       WIMStruct *wim;
+       int open_flags = WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+       int verify_flags = 0;
+       STRING_SET(refglobs);
+       int c;
 
+       for_opt(c, verify_options) {
+               switch (c) {
+               case IMAGEX_REF_OPTION:
+                       ret = string_set_append(&refglobs, optarg);
+                       if (ret)
+                               goto out_free_refglobs;
+                       break;
+               case IMAGEX_NOCHECK_OPTION:
+                       open_flags &= ~WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       break;
+               default:
+                       goto out_usage;
+               }
+       }
+
+       argv += optind;
+       argc -= optind;
+
+       if (argc != 1) {
+               if (argc == 0)
+                       imagex_error(T("Must specify a WIM file!"));
+               else
+                       imagex_error(T("At most one WIM file can be specified!"));
+               goto out_usage;
+       }
+
+       wimfile = argv[0];
+
+       ret = wimlib_open_wim_with_progress(wimfile,
+                                           open_flags,
+                                           &wim,
+                                           imagex_progress_func,
+                                           NULL);
+       if (ret)
+               goto out_free_refglobs;
+
+       ret = wim_reference_globs(wim, &refglobs, open_flags);
+       if (ret)
+               goto out_wimlib_free;
+
+       ret = wimlib_verify_wim(wim, verify_flags);
+       if (ret) {
+               tputc(T('\n'), stderr);
+               imagex_error(T("\"%"TS"\" failed verification!"),
+                            wimfile);
+               if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND &&
+                   refglobs.num_strings == 0)
+               {
+                       imagex_printf(T("Note: if this WIM file is not standalone, "
+                                       "use the --ref option to specify the other parts.\n"));
+               }
+       } else {
+               imagex_printf(T("\n\"%"TS"\" was successfully verified.\n"),
+                             wimfile);
+       }
+
+out_wimlib_free:
+       wimlib_free(wim);
+out_free_refglobs:
+       string_set_destroy(&refglobs);
+       return ret;
+
+out_usage:
+       usage(CMD_VERIFY, stderr);
+       ret = -1;
+       goto out_free_refglobs;
+}
 
 struct imagex_command {
        const tchar *name;
@@ -3991,56 +4149,71 @@ static const struct imagex_command imagex_commands[] = {
        [CMD_UNMOUNT]  = {T("unmount"),  imagex_unmount},
 #endif
        [CMD_UPDATE]   = {T("update"),   imagex_update},
+       [CMD_VERIFY]   = {T("verify"),   imagex_verify},
 };
 
+#ifdef __WIN32__
+
+   /* Can be a directory or source list file.  But source list file is probably
+    * a rare use case, so just say directory.  */
+#  define SOURCE_STR T("DIRECTORY")
+
+   /* Can only be a directory  */
+#  define TARGET_STR T("DIRECTORY")
+
+#else
+   /* Can be a directory, NTFS volume, or source list file. */
+#  define SOURCE_STR T("SOURCE")
+
+   /* Can be a directory or NTFS volume.  */
+#  define TARGET_STR T("TARGET")
+
+#endif
+
 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] [--dereference]\n"
-"                    [--config=FILE] [--threads=NUM_THREADS] [--source-list]\n"
-"                    [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
-"                    [--update-of=[WIMFILE:]IMAGE] [--wimboot]\n"
+"    %"TS" " SOURCE_STR " WIMFILE [IMAGE_NAME [IMAGE_DESC]]\n"
+"                    [--boot] [--check] [--nocheck] [--config=FILE]\n"
+"                    [--threads=NUM_THREADS] [--no-acls] [--strict-acls]\n"
+"                    [--rpfix] [--norpfix] [--update-of=[WIMFILE:]IMAGE]\n"
+"                    [--wimboot] [--unix-data] [--dereference]\n"
 ),
 [CMD_APPLY] =
 T(
-"    %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME | all)]\n"
-"                    (DIRECTORY | NTFS_VOLUME) [--check] [--ref=\"GLOB\"]\n"
-"                    [--no-acls] [--strict-acls] [--no-attributes]\n"
-"                    [--rpfix] [--norpfix] [--include-invalid-names]\n"
-"                    [--wimboot] [--unix-data]\n"
+"    %"TS" WIMFILE [IMAGE] " TARGET_STR "\n"
+"                    [--check] [--ref=\"GLOB\"] [--no-acls] [--strict-acls]\n"
+"                    [--no-attributes] [--rpfix] [--norpfix]\n"
+"                    [--include-invalid-names] [--wimboot] [--unix-data]\n"
 ),
 [CMD_CAPTURE] =
 T(
-"    %"TS" (DIRECTORY | NTFS_VOLUME) WIMFILE\n"
-"                   [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot] [--check]\n"
-"                    [--nocheck] [--compress=TYPE] [--flags EDITION_ID]\n"
-"                    [--dereference] [--config=FILE] [--threads=NUM_THREADS]\n"
-"                    [--source-list] [--no-acls] [--strict-acls] [--rpfix]\n"
-"                    [--norpfix] [--update-of=[WIMFILE:]IMAGE]\n"
-"                    [--delta-from=WIMFILE] [--wimboot] [--unix-data]\n"
+"    %"TS" " SOURCE_STR " WIMFILE [IMAGE_NAME [IMAGE_DESC]]\n"
+"                    [--compress=TYPE] [--boot] [--check] [--nocheck]\n"
+"                    [--config=FILE] [--threads=NUM_THREADS]\n"
+"                    [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
+"                    [--update-of=[WIMFILE:]IMAGE] [--delta-from=WIMFILE]\n"
+"                    [--wimboot] [--unix-data] [--dereference] [--solid]\n"
 ),
 [CMD_DELETE] =
 T(
-"    %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n"
-"                    [--check] [--soft]\n"
+"    %"TS" WIMFILE IMAGE [--check] [--soft]\n"
 ),
 [CMD_DIR] =
 T(
-"    %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--path=PATH] [--detailed]\n"
+"    %"TS" WIMFILE IMAGE [--path=PATH] [--detailed]\n"
 ),
 [CMD_EXPORT] =
 T(
-"    %"TS" SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
-"                    DEST_WIMFILE [DEST_IMAGE_NAME [DEST_IMAGE_DESCRIPTION]]\n"
+"    %"TS" SRC_WIMFILE SRC_IMAGE DEST_WIMFILE\n"
+"                        [DEST_IMAGE_NAME [DEST_IMAGE_DESC]]\n"
 "                    [--boot] [--check] [--nocheck] [--compress=TYPE]\n"
 "                    [--ref=\"GLOB\"] [--threads=NUM_THREADS] [--rebuild]\n"
-"                    [--wimboot]\n"
+"                    [--wimboot] [--solid]\n"
 ),
 [CMD_EXTRACT] =
 T(
-"    %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME) [(PATH | @LISTFILE)...]\n"
+"    %"TS" WIMFILE IMAGE [(PATH | @LISTFILE)...]\n"
 "                    [--check] [--ref=\"GLOB\"] [--dest-dir=CMD_DIR]\n"
 "                    [--to-stdout] [--no-acls] [--strict-acls]\n"
 "                    [--no-attributes] [--include-invalid-names]\n"
@@ -4048,8 +4221,8 @@ T(
 ),
 [CMD_INFO] =
 T(
-"    %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME) [NEW_NAME\n"
-"                    [NEW_DESC]]] [--boot] [--check] [--nocheck] [--xml]\n"
+"    %"TS" WIMFILE [IMAGE [NEW_NAME [NEW_DESC]]]\n"
+"                    [--boot] [--check] [--nocheck] [--xml]\n"
 "                    [--extract-xml FILE] [--header] [--lookup-table]\n"
 ),
 [CMD_JOIN] =
@@ -4059,22 +4232,23 @@ T(
 #if WIM_MOUNTING_SUPPORTED
 [CMD_MOUNT] =
 T(
-"    %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME)] DIRECTORY\n"
+"    %"TS" WIMFILE [IMAGE] DIRECTORY\n"
 "                    [--check] [--streams-interface=INTERFACE]\n"
 "                    [--ref=\"GLOB\"] [--allow-other] [--unix-data]\n"
 ),
 [CMD_MOUNTRW] =
 T(
-"    %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME)] DIRECTORY\n"
+"    %"TS" WIMFILE [IMAGE] DIRECTORY\n"
 "                    [--check] [--streams-interface=INTERFACE]\n"
 "                    [--staging-dir=CMD_DIR] [--allow-other] [--unix-data]\n"
 ),
 #endif
 [CMD_OPTIMIZE] =
 T(
-"    %"TS" WIMFILE [--check] [--nocheck] [--recompress]\n"
-"                    [--recompress-slow] [--compress=TYPE]\n"
-"                    [--threads=NUM_THREADS]\n"
+"    %"TS" WIMFILE\n"
+"                    [--recompress] [--compress=TYPE] [--threads=NUM_THREADS]\n"
+"                    [--check] [--nocheck] [--solid]\n"
+"\n"
 ),
 [CMD_SPLIT] =
 T(
@@ -4083,16 +4257,21 @@ T(
 #if WIM_MOUNTING_SUPPORTED
 [CMD_UNMOUNT] =
 T(
-"    %"TS" DIRECTORY [--commit] [--force] [--new-image]\n"
-"                         [--check] [--rebuild]\n"
+"    %"TS" DIRECTORY\n"
+"                    [--commit] [--force] [--new-image] [--check] [--rebuild]\n"
 ),
 #endif
 [CMD_UPDATE] =
 T(
-"    %"TS" WIMFILE [IMAGE_NUM | IMAGE_NAME] [--check] [--rebuild]\n"
-"                    [--threads=NUM_THREADS] [DEFAULT_ADD_OPTIONS]\n"
-"                    [DEFAULT_DELETE_OPTIONS] [--command=STRING]\n"
-"                    [--wimboot-config=FILE| [< CMDFILE]\n"
+"    %"TS" WIMFILE [IMAGE]\n"
+"                    [--check] [--rebuild] [--threads=NUM_THREADS]\n"
+"                    [DEFAULT_ADD_OPTIONS] [DEFAULT_DELETE_OPTIONS]\n"
+"                    [--command=STRING] [--wimboot-config=FILE]\n"
+"                    [< CMDFILE]\n"
+),
+[CMD_VERIFY] =
+T(
+"    %"TS" WIMFILE [--ref=\"GLOB\"]\n"
 ),
 };
 
@@ -4103,7 +4282,7 @@ static const tchar *get_cmd_string(int cmd, bool nospace)
 {
        static tchar buf[50];
        if (cmd == CMD_NONE) {
-               tsprintf(buf, T("%"TS), T(IMAGEX_PROGNAME));
+               return T("wimlib-imagex");
        } else if (invocation_cmd != CMD_NONE) {
                tsprintf(buf, T("wim%"TS), imagex_commands[cmd].name);
        } else {
@@ -4123,8 +4302,8 @@ version(void)
 {
        static const tchar *s =
        T(
-IMAGEX_PROGNAME " (distributed with " PACKAGE " " PACKAGE_VERSION ")\n"
-"Copyright (C) 2012, 2013, 2014 Eric Biggers\n"
+"wimlib-imagex (distributed with " PACKAGE " " PACKAGE_VERSION ")\n"
+"Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers\n"
 "License GPLv3+; GNU GPL version 3 or later <http://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"
@@ -4170,10 +4349,10 @@ recommend_man_page(int cmd, FILE *fp)
 {
        const tchar *format_str;
 #ifdef __WIN32__
-       format_str = T("Uncommon options are not listed;\n"
+       format_str = T("Some uncommon options are not listed;\n"
                       "See %"TS".pdf in the doc directory for more details.\n");
 #else
-       format_str = T("Uncommon options are not listed;\n"
+       format_str = T("Some uncommon options are not listed;\n"
                       "Try `man %"TS"' for more details.\n");
 #endif
        tfprintf(fp, format_str, get_cmd_string(cmd, true));
@@ -4200,11 +4379,14 @@ usage_all(FILE *fp)
        T(
 "    %"TS" --help\n"
 "    %"TS" --version\n"
-"\n"
-"    The compression TYPE may be \"maximum\", \"fast\", or \"none\".\n"
 "\n"
        );
        tfprintf(fp, extra, invocation_name, invocation_name);
+       tfprintf(fp,
+                T("IMAGE can be the 1-based index or name of an image in the WIM file.\n"
+                  "For some commands IMAGE is optional if the WIM file only contains one image.\n"
+                  "For some commands IMAGE may be \"all\".\n"
+                  "\n"));
        recommend_man_page(CMD_NONE, fp);
 }
 
@@ -4271,7 +4453,7 @@ main(int argc, char **argv)
        /* Allow being invoked as wimCOMMAND (e.g. wimapply).  */
        cmd = CMD_NONE;
        if (!tstrncmp(invocation_name, T("wim"), 3) &&
-           tstrcmp(invocation_name, T(IMAGEX_PROGNAME))) {
+           tstrcmp(invocation_name, T("wimlib-imagex"))) {
                for (int i = 0; i < CMD_MAX; i++) {
                        if (!tstrcmp(invocation_name + 3,
                                     imagex_commands[i].name))