]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
win32_apply.c: fix extraction of empty reparse points
[wimlib] / programs / imagex.c
index d567371ae1227a549a0f4233aab14de458a1a071..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},
@@ -1176,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,
@@ -1273,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,
@@ -1303,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;
 }
 
 
@@ -1793,7 +1819,10 @@ 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;
@@ -1891,9 +1920,9 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                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.  */
@@ -2384,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);
@@ -2399,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)
@@ -2449,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'));
@@ -2457,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);
 }
@@ -2510,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"));
                }
@@ -2667,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);
@@ -2802,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;
@@ -3088,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;
@@ -3117,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:
@@ -3213,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) {
@@ -3571,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)
@@ -4175,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(
@@ -4189,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(
@@ -4212,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] =
@@ -4269,7 +4330,7 @@ version(void)
        static const tchar *s =
        T(
 "wimlib-imagex (distributed with " PACKAGE " " PACKAGE_VERSION ")\n"
-"Copyright (C) 2012, 2013, 2014 Eric Biggers\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"