]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
win32_apply.c: fix extraction of empty reparse points
[wimlib] / programs / imagex.c
index 82354feb7d47f3c24bb86e1a991dcb74eeed1c55..816ea4fb296046e71604f7e212cf91b42a3e076a 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
@@ -141,6 +141,7 @@ static FILE *imagex_info_file;
 
 enum {
        IMAGEX_ALLOW_OTHER_OPTION,
+       IMAGEX_BLOBS_OPTION,
        IMAGEX_BOOT_OPTION,
        IMAGEX_CHECK_OPTION,
        IMAGEX_CHUNK_SIZE_OPTION,
@@ -160,7 +161,6 @@ enum {
        IMAGEX_HEADER_OPTION,
        IMAGEX_INCLUDE_INVALID_NAMES_OPTION,
        IMAGEX_LAZY_OPTION,
-       IMAGEX_LOOKUP_TABLE_OPTION,
        IMAGEX_METADATA_OPTION,
        IMAGEX_NEW_IMAGE_OPTION,
        IMAGEX_NOCHECK_OPTION,
@@ -168,8 +168,9 @@ 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,
        IMAGEX_PATH_OPTION,
@@ -182,9 +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_SOLID_OPTION,
        IMAGEX_SOURCE_LIST_OPTION,
        IMAGEX_STAGING_DIR_OPTION,
        IMAGEX_STREAMS_INTERFACE_OPTION,
@@ -194,8 +195,8 @@ enum {
        IMAGEX_UNIX_DATA_OPTION,
        IMAGEX_UPDATE_OF_OPTION,
        IMAGEX_VERBOSE_OPTION,
-       IMAGEX_WIMBOOT_OPTION,
        IMAGEX_WIMBOOT_CONFIG_OPTION,
+       IMAGEX_WIMBOOT_OPTION,
        IMAGEX_XML_OPTION,
 };
 
@@ -232,6 +233,7 @@ static const struct option capture_or_append_options[] = {
        {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},
@@ -281,6 +283,7 @@ static const struct option export_options[] = {
        {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},
@@ -317,7 +320,8 @@ static const struct option info_options[] = {
        {T("no-check"),     no_argument,       NULL, IMAGEX_NOCHECK_OPTION},
        {T("extract-xml"),  required_argument, NULL, IMAGEX_EXTRACT_XML_OPTION},
        {T("header"),       no_argument,       NULL, IMAGEX_HEADER_OPTION},
-       {T("lookup-table"), no_argument,       NULL, IMAGEX_LOOKUP_TABLE_OPTION},
+       {T("lookup-table"), no_argument,       NULL, IMAGEX_BLOBS_OPTION},
+       {T("blobs"),        no_argument,       NULL, IMAGEX_BLOBS_OPTION},
        {T("metadata"),     no_argument,       NULL, IMAGEX_METADATA_OPTION},
        {T("xml"),          no_argument,       NULL, IMAGEX_XML_OPTION},
        {NULL, 0, NULL, 0},
@@ -354,6 +358,7 @@ static const struct option optimize_options[] = {
        {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},
@@ -407,6 +412,7 @@ static const struct option update_options[] = {
 
 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},
 };
@@ -1175,7 +1181,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,
@@ -1272,7 +1278,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,
@@ -1302,16 +1308,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;
 }
 
 
@@ -1712,10 +1739,10 @@ 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;
@@ -1755,7 +1782,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        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;
@@ -1766,7 +1793,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);
@@ -1792,13 +1819,16 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                goto out_err;
                        break;
                case IMAGEX_SOLID_OPTION:
-                       write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+                       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.  */
@@ -1812,22 +1842,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;
@@ -1866,7 +1896,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;
@@ -1887,12 +1917,12 @@ 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) {
+               } else if (write_flags & WIMLIB_WRITE_FLAG_SOLID) {
                        /* With --solid, default to LZMS compression.  (However,
-                        * this will not affect solid blocks!)  */
+                        * this will not affect solid resources!)  */
                        compression_type = WIMLIB_COMPRESSION_TYPE_LZMS;
                } else {
                        /* Otherwise, default to LZX compression.  */
@@ -2006,8 +2036,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 {
@@ -2022,7 +2055,7 @@ 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)
@@ -2049,7 +2082,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) {
@@ -2089,9 +2122,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;
 
@@ -2165,7 +2197,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;
 
@@ -2381,6 +2413,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);
@@ -2396,47 +2431,66 @@ 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
 print_resource(const struct wimlib_resource_entry *resource,
               void *_ignore)
 {
-       tprintf(T("Hash                = 0x"));
+       tprintf(T("Hash              = 0x"));
        print_byte_field(resource->sha1_hash, sizeof(resource->sha1_hash));
        tputchar(T('\n'));
 
        if (!resource->is_missing) {
-               tprintf(T("Uncompressed size   = %"PRIu64" bytes\n"),
+               tprintf(T("Uncompressed size = %"PRIu64" bytes\n"),
                        resource->uncompressed_size);
                if (resource->packed) {
-                       tprintf(T("Raw compressed size = %"PRIu64" bytes\n"),
-                               resource->raw_resource_compressed_size);
-
-                       tprintf(T("Raw offset in WIM   = %"PRIu64" bytes\n"),
+                       tprintf(T("Solid resource    = %"PRIu64" => %"PRIu64" "
+                                 "bytes @ offset %"PRIu64"\n"),
+                               resource->raw_resource_uncompressed_size,
+                               resource->raw_resource_compressed_size,
                                resource->raw_resource_offset_in_wim);
 
-                       tprintf(T("Offset in raw       = %"PRIu64" bytes\n"),
+                       tprintf(T("Solid offset      = %"PRIu64" bytes\n"),
                                resource->offset);
                } else {
-                       tprintf(T("Compressed size     = %"PRIu64" bytes\n"),
+                       tprintf(T("Compressed size   = %"PRIu64" bytes\n"),
                                resource->compressed_size);
 
-                       tprintf(T("Offset in WIM       = %"PRIu64" bytes\n"),
+                       tprintf(T("Offset in WIM     = %"PRIu64" bytes\n"),
                                resource->offset);
                }
 
-               tprintf(T("Part Number         = %u\n"), resource->part_number);
-               tprintf(T("Reference Count     = %u\n"), resource->reference_count);
+               tprintf(T("Part Number       = %u\n"), resource->part_number);
+               tprintf(T("Reference Count   = %u\n"), resource->reference_count);
 
-               tprintf(T("Flags               = "));
+               tprintf(T("Flags             = "));
                if (resource->is_compressed)
                        tprintf(T("WIM_RESHDR_FLAG_COMPRESSED  "));
                if (resource->is_metadata)
@@ -2446,7 +2500,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'));
@@ -2454,7 +2508,7 @@ print_resource(const struct wimlib_resource_entry *resource,
 }
 
 static void
-print_lookup_table(WIMStruct *wim)
+print_blobs(WIMStruct *wim)
 {
        wimlib_iterate_lookup_table(wim, 0, print_resource, NULL);
 }
@@ -2507,8 +2561,12 @@ print_dentry_detailed(const struct wimlib_dir_entry *dentry)
 
        for (uint32_t i = 0; i <= dentry->num_named_streams; i++) {
                if (dentry->streams[i].stream_name) {
-                       tprintf(T("\tData stream \"%"TS"\":\n"),
+                       tprintf(T("\tNamed data stream \"%"TS"\":\n"),
                                dentry->streams[i].stream_name);
+               } else if (dentry->attributes & WIMLIB_FILE_ATTRIBUTE_ENCRYPTED) {
+                       tprintf(T("\tRaw encrypted data stream:\n"));
+               } else if (dentry->attributes & WIMLIB_FILE_ATTRIBUTE_REPARSE_POINT) {
+                       tprintf(T("\tReparse point stream:\n"));
                } else {
                        tprintf(T("\tUnnamed data stream:\n"));
                }
@@ -2664,7 +2722,10 @@ imagex_export(int argc, tchar **argv, int cmd)
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
                        break;
                case IMAGEX_SOLID_OPTION:
-                       write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+                       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);
@@ -2799,7 +2860,7 @@ imagex_export(int argc, tchar **argv, int cmd)
                         * 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;
@@ -3085,7 +3146,7 @@ imagex_info(int argc, tchar **argv, int cmd)
        bool check        = false;
        bool nocheck      = false;
        bool header       = false;
-       bool lookup_table = false;
+       bool blobs        = false;
        bool xml          = false;
        bool short_header = true;
        const tchar *xml_out_file = NULL;
@@ -3114,8 +3175,8 @@ imagex_info(int argc, tchar **argv, int cmd)
                        header = true;
                        short_header = false;
                        break;
-               case IMAGEX_LOOKUP_TABLE_OPTION:
-                       lookup_table = true;
+               case IMAGEX_BLOBS_OPTION:
+                       blobs = true;
                        short_header = false;
                        break;
                case IMAGEX_XML_OPTION:
@@ -3210,13 +3271,13 @@ imagex_info(int argc, tchar **argv, int cmd)
                if (header)
                        wimlib_print_header(wim);
 
-               if (lookup_table) {
+               if (blobs) {
                        if (info.total_parts != 1) {
-                               tfprintf(stderr, T("Warning: Only showing the lookup table "
+                               tfprintf(stderr, T("Warning: Only showing the blobs "
                                                   "for part %d of a %d-part WIM.\n"),
                                         info.part_number, info.total_parts);
                        }
-                       print_lookup_table(wim);
+                       print_blobs(wim);
                }
 
                if (xml) {
@@ -3568,9 +3629,12 @@ imagex_optimize(int argc, tchar **argv, int cmd)
                                goto out_err;
                        break;
                case IMAGEX_SOLID_OPTION:
-                       write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+                       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)
@@ -4026,6 +4090,9 @@ imagex_verify(int argc, tchar **argv, int cmd)
                        if (ret)
                                goto out_free_refglobs;
                        break;
+               case IMAGEX_NOCHECK_OPTION:
+                       open_flags &= ~WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       break;
                default:
                        goto out_usage;
                }
@@ -4169,7 +4236,7 @@ T(
 "                        [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(
@@ -4183,7 +4250,7 @@ T(
 T(
 "    %"TS" WIMFILE [IMAGE [NEW_NAME [NEW_DESC]]]\n"
 "                    [--boot] [--check] [--nocheck] [--xml]\n"
-"                    [--extract-xml FILE] [--header] [--lookup-table]\n"
+"                    [--extract-xml FILE] [--header] [--blobs]\n"
 ),
 [CMD_JOIN] =
 T(
@@ -4206,8 +4273,8 @@ T(
 [CMD_OPTIMIZE] =
 T(
 "    %"TS" WIMFILE\n"
-"                    [--recompress] [--compress=TYPE]\n"
-"                    [--threads=NUM_THREADS] [--check] [--nocheck]\n"
+"                    [--recompress] [--compress=TYPE] [--threads=NUM_THREADS]\n"
+"                    [--check] [--nocheck] [--solid]\n"
 "\n"
 ),
 [CMD_SPLIT] =
@@ -4242,7 +4309,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 {
@@ -4262,8 +4329,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"
@@ -4413,7 +4480,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))