wimlib-imagex: Add --wimboot options
authorEric Biggers <ebiggers3@gmail.com>
Fri, 18 Apr 2014 06:00:48 +0000 (01:00 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 18 Apr 2014 06:23:11 +0000 (01:23 -0500)
doc/imagex-apply.1.in
doc/imagex-capture.1.in
doc/imagex-extract.1.in
programs/imagex.c

index ab9efcd..e869174 100644 (file)
@@ -392,6 +392,13 @@ default, invalid names will be ignored, and if there are multiple names
 differing only in case, one will be chosen to extract arbitrarily; however, with
 \fB--include-invalid-names\fR, all names will be sanitized and extracted in some
 form.
+.TP
+\fB--wimboot\fR
+Windows only: Instead of extracting the files themselves, extract "pointer
+files" back to the original WIM.  This is only expected to work on Windows 8.1
+and later, since only those versions of Windows contain the Windows Overlay File
+System Filter Driver that is necessary for this feature.  See Microsoft's
+documentation for "WIMBoot" for more information.
 .SH NOTES
 \fIData integrity\fR:  WIM files include SHA1 message digests for file data.
 \fB@IMAGEX_PROGNAME@ apply\fR calculates the SHA1 message digest of every file
index 2521229..a6d93b0 100644 (file)
@@ -485,6 +485,16 @@ metadata, but this is typically only a small fraction of a WIM's total size.
 .IP ""
 This option can be specified multiple times, in which case the resulting delta
 WIM will only contain streams not present in any of the specified base
+.TP
+\fB--wimboot\fR
+Windows only: mark the image as WIMBoot-compatible.  See Microsoft's
+documentation for more information about WIMBoot.  This option will, by default,
+change the compression type to XPRESS and the chunk size to 4096 bytes; these
+can, however, still be overridden through the \fB--compress\fR and
+\fB--chunk-size\fR parameters, respectively.  In addition, this option will, by
+default, set the configuration file to
+\fISOURCE\fR\\Windows\\System32\\WimBootCompress.ini if present and accessible;
+however, this may still be overridden through the \fB--config\fR parameter.
 \fIWIMFILE\fRs.
 .IP ""
 To operate on the resulting delta WIM using other commands such as
index e8cdb52..309430b 100644 (file)
@@ -140,6 +140,9 @@ extracting the file or directory tree named by each path directly to the
 destination directory.  Note: \fB--preserve-dir-structure\fR is already the
 default behavior for paths in listfiles, but not paths directly specified on the
 command line.
+.TP
+\fB--wimboot\fR
+See the documentation for this option in \fB@IMAGEX_PROGNAME@-apply\fR (1).
 .SH NOTES
 See the documentation \fB@IMAGEX_PROGNAME@ apply\fR (1) for documentation about
 what data and metadata are extracted on UNIX-like systems versus on Windows.
index 6a95b04..e80d3e6 100644 (file)
@@ -198,6 +198,7 @@ enum {
        IMAGEX_UNIX_DATA_OPTION,
        IMAGEX_UPDATE_OF_OPTION,
        IMAGEX_VERBOSE_OPTION,
+       IMAGEX_WIMBOOT_OPTION,
        IMAGEX_XML_OPTION,
 };
 
@@ -218,6 +219,7 @@ static const struct option apply_options[] = {
 
        /* --resume is undocumented for now as it needs improvement.  */
        {T("resume"),      no_argument,       NULL, IMAGEX_RESUME_OPTION},
+       {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -250,6 +252,7 @@ static const struct option capture_or_append_options[] = {
        {T("not-pipable"), no_argument,       NULL, IMAGEX_NOT_PIPABLE_OPTION},
        {T("update-of"),   required_argument, NULL, IMAGEX_UPDATE_OF_OPTION},
        {T("delta-from"),  required_argument, NULL, IMAGEX_DELTA_FROM_OPTION},
+       {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -301,6 +304,7 @@ static const struct option extract_options[] = {
        {T("no-wildcards"), no_argument,      NULL, IMAGEX_NO_WILDCARDS_OPTION},
        {T("nullglob"),     no_argument,      NULL, IMAGEX_NULLGLOB_OPTION},
        {T("preserve-dir-structure"), no_argument, NULL, IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION},
+       {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -413,6 +417,17 @@ imagex_error(const tchar *format, ...)
        va_end(va);
 }
 
+static void _format_attribute(printf, 1, 2)
+imagex_warning(const tchar *format, ...)
+{
+       va_list va;
+       va_start(va, format);
+       tfputs(T("WARNING: "), stderr);
+       tvfprintf(stderr, format, va);
+       tputc(T('\n'), stderr);
+       va_end(va);
+}
+
 /* Print formatted error message to stderr. */
 static void _format_attribute(printf, 1, 2)
 imagex_error_with_errno(const tchar *format, ...)
@@ -714,7 +729,7 @@ static bool
 is_comment_line(const tchar *line, size_t len)
 {
        for (;;) {
-               if (*line == T('#'))
+               if (*line == T('#') || *line == T(';'))
                        return true;
                if (!istspace(*line) && *line != T('\0'))
                        return false;
@@ -856,8 +871,8 @@ check_config_section(tchar *line, size_t len,
                         "of capture config file\n"),
                       stderr);
        } else {
-               imagex_error(T("Invalid capture config file section \"%"TS"\""),
-                            line - 1);
+               imagex_warning(T("Unknown capture config file section \"%"TS"\""),
+                              line - 1);
                return CAPTURE_CONFIG_INVALID_SECTION;
        }
        return CAPTURE_CONFIG_CHANGED_SECTION;
@@ -894,9 +909,8 @@ parse_capture_config_line(tchar *line, size_t len,
        int ret;
 
        ret = check_config_section(line, len, cur_section);
-       if (ret == CAPTURE_CONFIG_INVALID_SECTION)
-               return false;
-       if (ret == CAPTURE_CONFIG_CHANGED_SECTION)
+       if (ret == CAPTURE_CONFIG_CHANGED_SECTION ||
+           ret == CAPTURE_CONFIG_INVALID_SECTION)
                return true;
 
        switch (*cur_section) {
@@ -941,6 +955,10 @@ parse_capture_config(tchar **contents_p, size_t nchars,
                tchar *endp = tmemchr(p, T('\n'), nchars);
                size_t len = endp - p + 1;
                *endp = T('\0');
+               if (p != endp && *(endp - 1) == T('\r')) {
+                       *(endp - 1) = '\0';
+                       len--;
+               }
                if (!is_comment_line(p, len))
                        if (!parse_capture_config_line(p, len, &cur_section, config))
                                return -1;
@@ -1665,6 +1683,9 @@ imagex_apply(int argc, tchar **argv, int cmd)
                case IMAGEX_RESUME_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_RESUME;
                        break;
+               case IMAGEX_WIMBOOT_OPTION:
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_WIMBOOT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -1820,7 +1841,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        tchar *source;
        tchar *source_copy;
 
-       const tchar *config_file = NULL;
+       tchar *config_file = NULL;
        tchar *config_str;
        struct wimlib_capture_config *config;
 
@@ -1941,6 +1962,9 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                goto out_free_base_wimfiles;
                        write_flags |= WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS;
                        break;
+               case IMAGEX_WIMBOOT_OPTION:
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_WIMBOOT;
+                       break;
                default:
                        goto out_usage;
                }
@@ -1958,22 +1982,46 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 
 
        if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
-               compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
-
-               if (!compress_slow) {
-                       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 (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_WIMBOOT) {
+                       compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
+               } else {
+                       compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
+                       if (!compress_slow) {
+                               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();
 
+       /* Set default configuration file  */
+#ifdef __WIN32__
+       if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_WIMBOOT) && !config) {
+               struct stat st;
+
+               config_file = alloca(wcslen(source) * sizeof(wchar_t) + 100);
+               swprintf(config_file, L"%ls\\%ls",
+                        source,  L"Windows\\System32\\WimBootCompress.ini");
+
+               if (tstat(config_file, &st)) {
+                       imagex_printf(L"\"%ls\" does not exist; using "
+                                     "default configuration\n",
+                                     config_file);
+                       config_file = NULL;
+               } else {
+                       add_image_flags &= ~WIMLIB_ADD_IMAGE_FLAG_WINCONFIG;
+               }
+       }
+#endif
+
        if (!tstrcmp(wimfile, T("-"))) {
                /* Writing captured WIM to standard output.  */
        #if 0
@@ -2113,6 +2161,11 @@ 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) &&
+                  compression_type == WIMLIB_COMPRESSION_TYPE_XPRESS) {
+               ret = wimlib_set_output_chunk_size(wim, 4096);
+               if (ret)
+                       goto out_free_wim;
        }
        if (pack_chunk_size != UINT32_MAX) {
                ret = wimlib_set_output_pack_chunk_size(wim, pack_chunk_size);
@@ -3009,6 +3062,9 @@ imagex_extract(int argc, tchar **argv, int cmd)
                case IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION:
                        notlist_extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE;
                        break;
+               case IMAGEX_WIMBOOT_OPTION:
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_WIMBOOT;
+                       break;
                default:
                        goto out_usage;
                }