Allow changing WIM compression type
authorEric Biggers <ebiggers3@gmail.com>
Sun, 8 Dec 2013 09:10:25 +0000 (03:10 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 8 Dec 2013 09:10:25 +0000 (03:10 -0600)
NEWS
doc/imagex-optimize.1.in
doc/imagex.1.in
include/wimlib.h
include/wimlib/wim.h
programs/imagex.c
src/header.c
src/lzx-compress.c
src/metadata_resource.c
src/wim.c
src/write.c

diff --git a/NEWS b/NEWS
index 435a3f7..5dc3802 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,11 @@ Version 1.5.3:
        produce an even better compression ratio at the cost of more time spent
        compressing.
 
+       `wimlib-imagex optimize' now supports the '--compress=TYPE' option,
+       which recompresses the WIM file using the specified compression TYPE.
+       The new library API function used for this is
+       wimlib_set_output_compression_type().
+
        Added the wimlib_get_xml_data() function to allow library clients to
        easily retrieve the raw XML data from a WIM file if needed.
 
index 9f3856a..0009d92 100644 (file)
@@ -42,6 +42,10 @@ compression ratio.  This only affects LZX-compressed WIM files.  Compared to the
 default \fB--recompress\fR, this will make compression about twice as slow and
 will increase the compression ratio by maybe 1%, depending on the data.
 .TP
+\fB--compress\fR=\fITYPE\fR
+Recompress the WIM file using the specified compression type.  \fITYPE\fR may be
+"none", "fast", or "maximum".  This implies \fB--recompress\fR.
+.TP
 \fB--threads\fR=\fINUM_THREADS\fR
 Number of threads to use for compressing data.  Default: autodetect (number of
 processors).  This parameter is only meaningful when \fB--recompress\fR is also
index 8ada205..2950875 100644 (file)
@@ -97,14 +97,17 @@ Combine split WIMs into one standalone WIM (\fB@IMAGEX_PROGNAME@ join\fR)
 .IP \[bu]
 Split a standalone WIM into multiple parts (\fB@IMAGEX_PROGNAME@ split\fR)
 .IP \[bu]
+Easily remove wasted space in a WIM file and optionally recompress it (\fB
+@IMAGEX_PROGNAME@ optimize\fR)
+.IP \[bu]
 Support for all WIM compression types, both compression and decompression (LZX,
 XPRESS, and none)
 .IP \[bu]
 WIM integrity table is supported (\fB--check\fR option to many commands)
 .SH DIFFERENCES FROM MICROSOFT IMAGEX
 Although \fB@IMAGEX_PROGNAME@\fR shares some similarities with Microsoft's
-implementation of ImageX, this section lists some noteworthy differences between
-the two programs:
+implementation of ImageX, this section lists some of the many noteworthy
+differences between the two programs:
 .IP \[bu] 4
 \fB@IMAGEX_PROGNAME@\fR is supported on both UNIX-like systems and Windows;
 thus, some functionality was designed around this.
@@ -131,7 +134,8 @@ files from or make changes to a WIM image without mounting it.
 .IP \[bu]
 \fB@IMAGEX_PROGNAME@\fR offers the extra command \fB@IMAGEX_PROGNAME@
 optimize\fR, which lets you easily remove wasted space in a WIM (which can arise
-after a WIM image is appended or mounted read-write).
+after a WIM image is appended or mounted read-write).  It also makes it easy to
+recompress a WIM file at the highest compression level.
 .IP \[bu]
 \fB@IMAGEX_PROGNAME@\fR also offers the command \fB@IMAGEX_PROGNAME@ join\fR,
 which lets you easily join the parts of a split WIM.
@@ -165,10 +169,6 @@ wimlib (and \fB@IMAGEX_PROGNAME@\fR via \fB@IMAGEX_PROGNAME@ mount\fR) support
 mounting an image from a split WIM, but Microsoft's software does not.  (Note:
 this functionality is not available in Windows builds of wimlib and
 \fB@IMAGEX_PROGNAME@\fR.)
-.IP \[bu]
-\fB@IMAGEX_PROGNAME@ capture\fR supports a special mode where UNIX file modes,
-owners, and groups are stored.  (Note: this functionality is only available in
-builds of wimlib for UNIX-like systems.)
 .SH LOCALES AND CHARACTER ENCODINGS
 On Windows, wimlib works in UTF-16LE, and there should be no problems with
 character encodings.
index 692ef77..f4b0dc5 100644 (file)
@@ -3357,6 +3357,27 @@ wimlib_set_image_descripton(WIMStruct *wim, int image,
                            const wimlib_tchar *description);
 
 /**
+ * @ingroup G_writing_and_overwriting_wims
+ *
+ * Set the compression type of a WIM to use in subsequent calls to
+ * wimlib_write() or wimlib_overwrite().
+ *
+ * @return 0 on success; nonzero on error.
+ *
+ * @param wim
+ *     ::WIMStruct for a WIM.
+ * @param ctype
+ *     The compression type to set (one of ::wimlib_compression_type).
+ *
+ * @return 0 on success; nonzero on error.
+ *
+ * @retval ::WIMLIB_ERR_INVALID_PARAM
+ *     @p ctype did not specify a valid compression type.
+ */
+extern int
+wimlib_set_output_compression_type(WIMStruct *wim, int ctype);
+
+/**
  * @ingroup G_modifying_wims
  *
  * Set basic information about a WIM.
index d1e0971..b6cf84a 100644 (file)
@@ -70,6 +70,12 @@ struct WIMStruct {
 
        /* One of WIMLIB_COMPRESSION_TYPE_*, cached from the header flags. */
        u8 compression_type : 2;
+
+       /* Overwritten compression type for wimlib_overwrite() or
+        * wimlib_write().  Can be changed by
+        * wimlib_set_output_compression_type(); otherwise is the same as
+        * compression_type.  */
+       u8 out_compression_type : 2;
 };
 
 static inline bool wim_is_pipable(const WIMStruct *wim)
@@ -90,6 +96,9 @@ static inline bool wim_has_metadata(const WIMStruct *wim)
 extern void
 wim_recalculate_refcnts(WIMStruct *wim);
 
+extern u32
+get_wim_hdr_cflags(int ctype);
+
 extern int
 init_wim_header(struct wim_header *hdr, int ctype);
 
index 6790325..2564b4c 100644 (file)
@@ -282,6 +282,7 @@ static const struct option optimize_options[] = {
        {T("check"),       no_argument,       NULL, IMAGEX_CHECK_OPTION},
        {T("nocheck"),     no_argument,       NULL, IMAGEX_NOCHECK_OPTION},
        {T("no-check"),    no_argument,       NULL, IMAGEX_NOCHECK_OPTION},
+       {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},
@@ -419,9 +420,10 @@ get_compression_type(const tchar *optarg)
        }
 }
 
-static void
+static int
 set_compress_slow(void)
 {
+       int ret;
        static const struct wimlib_lzx_params slow_params = {
                .size_of_this = sizeof(struct wimlib_lzx_params),
                .algorithm = WIMLIB_LZX_ALGORITHM_SLOW,
@@ -438,8 +440,10 @@ set_compress_slow(void)
                        },
                },
        };
-       if (wimlib_lzx_set_default_params(&slow_params))
+       ret = wimlib_lzx_set_default_params(&slow_params);
+       if (ret)
                imagex_error(T("Couldn't set slow compression parameters.!"));
+       return ret;
 }
 
 struct string_set {
@@ -1722,7 +1726,10 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                goto out_err;
                        break;
                case IMAGEX_COMPRESS_SLOW_OPTION:
-                       set_compress_slow();
+                       ret = set_compress_slow();
+                       if (ret)
+                               goto out_err;
+                       compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
                        break;
                case IMAGEX_FLAGS_OPTION:
                        flags_element = optarg;
@@ -3240,6 +3247,7 @@ imagex_optimize(int argc, tchar **argv, int cmd)
        int c;
        int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS;
        int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
+       int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
        int ret;
        WIMStruct *wim;
        const tchar *wimfile;
@@ -3256,12 +3264,20 @@ imagex_optimize(int argc, tchar **argv, int cmd)
                case IMAGEX_NOCHECK_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY;
                        break;
+               case IMAGEX_COMPRESS_OPTION:
+                       write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+                       compression_type = get_compression_type(optarg);
+                       if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
+                               goto out_err;
+                       break;
                case IMAGEX_RECOMPRESS_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
                        break;
                case IMAGEX_COMPRESS_SLOW_OPTION:
                        write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
-                       set_compress_slow();
+                       ret = set_compress_slow();
+                       if (ret)
+                               goto out_err;
                        break;
                case IMAGEX_THREADS_OPTION:
                        num_threads = parse_num_threads(optarg);
@@ -3290,6 +3306,12 @@ imagex_optimize(int argc, tchar **argv, int cmd)
        if (ret)
                goto out;
 
+       if (compression_type != WIMLIB_COMPRESSION_TYPE_INVALID) {
+               ret = wimlib_set_output_compression_type(wim, compression_type);
+               if (ret)
+                       goto out_wimlib_free;
+       }
+
        old_size = file_get_size(wimfile);
        tprintf(T("\"%"TS"\" original size: "), wimfile);
        if (old_size == -1)
@@ -3754,8 +3776,8 @@ T(
 [CMD_OPTIMIZE] =
 T(
 "    %"TS" WIMFILE [--check] [--nocheck] [--recompress]\n"
-"                    [--recompress-slow] [--threads=NUM_THREADS] [--pipable]\n"
-"                    [--not-pipable]\n"
+"                    [--recompress-slow] [--compress=TYPE]\n"
+"                    [--threads=NUM_THREADS] [--pipable] [--not-pipable]\n"
 ),
 [CMD_SPLIT] =
 T(
index ad7f3ce..9492e7f 100644 (file)
@@ -229,6 +229,22 @@ write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd)
                           offsetof(struct wim_header_disk, wim_flags));
 }
 
+u32
+get_wim_hdr_cflags(int ctype)
+{
+       switch (ctype) {
+       case WIMLIB_COMPRESSION_TYPE_NONE:
+               return 0;
+       case WIMLIB_COMPRESSION_TYPE_LZX:
+               return WIM_HDR_FLAG_COMPRESSION | WIM_HDR_FLAG_COMPRESS_LZX;
+       case WIMLIB_COMPRESSION_TYPE_XPRESS:
+               return WIM_HDR_FLAG_COMPRESSION | WIM_HDR_FLAG_COMPRESS_XPRESS;
+       case WIMLIB_COMPRESSION_TYPE_INVALID:
+               break;
+       }
+       return (u32)~0U;
+}
+
 /*
  * Initializes the header for a WIM file.
  */
@@ -236,19 +252,8 @@ int
 init_wim_header(struct wim_header *hdr, int ctype)
 {
        memset(hdr, 0, sizeof(struct wim_header));
-       switch (ctype) {
-       case WIMLIB_COMPRESSION_TYPE_NONE:
-               hdr->flags = 0;
-               break;
-       case WIMLIB_COMPRESSION_TYPE_LZX:
-               hdr->flags = WIM_HDR_FLAG_COMPRESSION |
-                            WIM_HDR_FLAG_COMPRESS_LZX;
-               break;
-       case WIMLIB_COMPRESSION_TYPE_XPRESS:
-               hdr->flags = WIM_HDR_FLAG_COMPRESSION |
-                            WIM_HDR_FLAG_COMPRESS_XPRESS;
-               break;
-       default:
+       hdr->flags = get_wim_hdr_cflags(ctype);
+       if (hdr->flags == (u32)~0U) {
                ERROR("Invalid compression type specified (%d)", ctype);
                return WIMLIB_ERR_INVALID_COMPRESSION_TYPE;
        }
index 20a3580..4c0e6ce 100644 (file)
@@ -2388,6 +2388,7 @@ lzx_params_valid(const struct wimlib_lzx_params *params)
        return true;
 }
 
+/* API function documented in wimlib.h  */
 WIMLIBAPI int
 wimlib_lzx_set_default_params(const struct wimlib_lzx_params * params)
 {
index 006871c..d69ad82 100644 (file)
@@ -296,7 +296,7 @@ write_metadata_resource(WIMStruct *wim, int image, int write_resource_flags)
         * the metadata resource.  */
        ret = write_wim_resource_from_buffer(buf, len, WIM_RESHDR_FLAG_METADATA,
                                             &wim->out_fd,
-                                            wim->compression_type,
+                                            wim->out_compression_type,
                                             &imd->metadata_lte->output_resource_entry,
                                             imd->metadata_lte->hash,
                                             write_resource_flags,
index bf6ebbf..2a6ac12 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -139,6 +139,7 @@ wimlib_create_new_wim(int ctype, WIMStruct **wim_ret)
        wim->lookup_table = table;
        wim->refcnts_ok = 1;
        wim->compression_type = ctype;
+       wim->out_compression_type = ctype;
        *wim_ret = wim;
        return 0;
 out_free:
@@ -482,6 +483,7 @@ begin_read(WIMStruct *wim, const void *wim_filename_or_fd,
        } else {
                wim->compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
        }
+       wim->out_compression_type = wim->compression_type;
 
        if (open_flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY) {
                ret = check_wim_integrity(wim, progress_func);
index ca5a230..a127a99 100644 (file)
@@ -2029,7 +2029,7 @@ write_wim_streams(WIMStruct *wim, int image, int write_flags,
        return write_stream_list(stream_list,
                                 wim->lookup_table,
                                 &wim->out_fd,
-                                wim->compression_type,
+                                wim->out_compression_type,
                                 &wim->lzx_context,
                                 write_flags,
                                 num_threads,
@@ -2089,7 +2089,7 @@ write_wim_metadata_resources(WIMStruct *wim, int image, int write_flags,
                              "metadata resource.", i);
                        ret = write_wim_resource(imd->metadata_lte,
                                                 &wim->out_fd,
-                                                wim->compression_type,
+                                                wim->out_compression_type,
                                                 &imd->metadata_lte->output_resource_entry,
                                                 write_resource_flags,
                                                 &wim->lzx_context);
@@ -2447,6 +2447,22 @@ write_pipable_wim(WIMStruct *wim, int image, int write_flags,
         * finish_write().  */
 }
 
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_set_output_compression_type(WIMStruct *wim, int ctype)
+{
+       switch (ctype) {
+       case WIMLIB_COMPRESSION_TYPE_INVALID:
+               break;
+       case WIMLIB_COMPRESSION_TYPE_NONE:
+       case WIMLIB_COMPRESSION_TYPE_LZX:
+       case WIMLIB_COMPRESSION_TYPE_XPRESS:
+               wim->out_compression_type = ctype;
+               return 0;
+       }
+       return WIMLIB_ERR_INVALID_PARAM;
+}
+
 /* Write a standalone WIM or split WIM (SWM) part to a new file or to a file
  * descriptor.  */
 int
@@ -2572,6 +2588,10 @@ write_wim_part(WIMStruct *wim,
        wim->hdr.part_number = part_number;
        wim->hdr.total_parts = total_parts;
 
+       /* Set compression type if different.  */
+       if (wim->compression_type != wim->out_compression_type)
+               wim->hdr.flags = get_wim_hdr_cflags(wim->out_compression_type);
+
        /* Use GUID if specified; otherwise generate a new one.  */
        if (guid)
                memcpy(wim->hdr.guid, guid, WIMLIB_GUID_LEN);
@@ -3045,7 +3065,8 @@ wimlib_overwrite(WIMStruct *wim, int write_flags,
        if ((!wim->deletion_occurred || (write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE))
            && !(write_flags & (WIMLIB_WRITE_FLAG_REBUILD |
                                WIMLIB_WRITE_FLAG_PIPABLE))
-           && !(wim_is_pipable(wim)))
+           && !(wim_is_pipable(wim))
+           && wim->compression_type == wim->out_compression_type)
        {
                ret = overwrite_wim_inplace(wim, write_flags, num_threads,
                                            progress_func);