]> wimlib.net Git - wimlib/commitdiff
write: various cleanups
authorEric Biggers <ebiggers3@gmail.com>
Sat, 2 May 2015 21:54:38 +0000 (16:54 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 2 May 2015 23:13:39 +0000 (18:13 -0500)
- When writing or overwriting WIM file, fill in a new variable
  wim->out_hdr instead of overwriting wim->hdr which was subject to bugs
- When writing WIM file, create new header from scratch instead of
  copying old one
- Remove redundant private flags
- Remove debug statements (they are rarely used, outdated, and now
  missing from most parts of the library)

include/wimlib/wim.h
include/wimlib/write.h
src/header.c
src/integrity.c
src/wim.c
src/write.c

index 09c65123770c6da76a9f9a33d2cc44ecce076beb..011ecc345be1b051e35bc54b6b41eaddbc201b59 100644 (file)
@@ -42,10 +42,14 @@ struct WIMStruct {
 
        /* Information from the header of the WIM file.
         *
 
        /* Information from the header of the WIM file.
         *
-        * This is also maintained for a WIMStruct not backed by a file, but the
-        * 'reshdr' fields have no meaning.  */
+        * This is also maintained for a WIMStruct not backed by a file, but in
+        * that case the 'reshdr' fields are left zeroed.  */
        struct wim_header hdr;
 
        struct wim_header hdr;
 
+       /* If the library is currently writing this WIMStruct out to a file,
+        * then this is the header being created for that file.  */
+       struct wim_header out_hdr;
+
        /* Array of image metadata, one for each image in the WIM (array length
         * hdr.image_count).  Or, this will be NULL if this WIM does not contain
         * metadata, which implies that this WIMStruct either represents part of
        /* Array of image metadata, one for each image in the WIM (array length
         * hdr.image_count).  Or, this will be NULL if this WIM does not contain
         * metadata, which implies that this WIMStruct either represents part of
@@ -185,22 +189,12 @@ static inline bool wim_is_pipable(const WIMStruct *wim)
 extern bool
 wim_has_solid_resources(const WIMStruct *wim);
 
 extern bool
 wim_has_solid_resources(const WIMStruct *wim);
 
-extern void
-set_wim_hdr_cflags(enum wimlib_compression_type ctype, struct wim_header *hdr);
-
-extern void
-init_wim_header(struct wim_header *hdr,
-               enum wimlib_compression_type ctype, u32 chunk_size);
-
 extern int
 read_wim_header(WIMStruct *wim, struct wim_header *hdr);
 
 extern int
 extern int
 read_wim_header(WIMStruct *wim, struct wim_header *hdr);
 
 extern int
-write_wim_header(const struct wim_header *hdr, struct filedes *out_fd);
-
-extern int
-write_wim_header_at_offset(const struct wim_header *hdr, struct filedes *out_fd,
-                          off_t offset);
+write_wim_header(const struct wim_header *hdr, struct filedes *out_fd,
+                off_t offset);
 
 extern int
 write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd);
 
 extern int
 write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd);
index 82e5576b17074fb98bb950a238cf17fd6b9c48f1..008c36412980d2a04b6880d3758ce53131bd6898 100644 (file)
@@ -5,13 +5,11 @@
 #include "wimlib/types.h"
 
 /* Internal use only */
 #include "wimlib/types.h"
 
 /* Internal use only */
-#define WIMLIB_WRITE_FLAG_NO_BLOB_TABLE                        0x80000000
-#define WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML         0x40000000
-#define WIMLIB_WRITE_FLAG_HEADER_AT_END                        0x20000000
-#define WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR              0x10000000
-#define WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES      0x08000000
-#define WIMLIB_WRITE_FLAG_NO_METADATA                  0x04000000
-#define WIMLIB_WRITE_FLAG_OVERWRITE                    0x02000000
+#define WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR              0x80000000
+#define WIMLIB_WRITE_FLAG_OVERWRITE                    0x40000000
+#define WIMLIB_WRITE_FLAG_NO_NEW_BLOBS                 0x20000000
+#define WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES      0x10000000
+#define WIMLIB_WRITE_FLAG_NO_METADATA                  0x08000000
 
 /* Keep in sync with wimlib.h  */
 #define WIMLIB_WRITE_MASK_PUBLIC (                       \
 
 /* Keep in sync with wimlib.h  */
 #define WIMLIB_WRITE_MASK_PUBLIC (                       \
index cbb1419978b663c5382a90d709039f95a5eff91c..a88c9272f452f51c1836bf650f5ec8e3b6ec3ba8 100644 (file)
@@ -160,8 +160,8 @@ read_error:
  * specified is the current one, the position is advanced by the size of the
  * header.  */
 int
  * specified is the current one, the position is advanced by the size of the
  * header.  */
 int
-write_wim_header_at_offset(const struct wim_header *hdr, struct filedes *out_fd,
-                          off_t offset)
+write_wim_header(const struct wim_header *hdr, struct filedes *out_fd,
+                off_t offset)
 {
        struct wim_header_disk disk_hdr _aligned_attribute(8);
        int ret;
 {
        struct wim_header_disk disk_hdr _aligned_attribute(8);
        int ret;
@@ -199,14 +199,6 @@ write_wim_header_at_offset(const struct wim_header *hdr, struct filedes *out_fd,
        return ret;
 }
 
        return ret;
 }
 
-/* Writes the header for a WIM file at the output file descriptor's current
- * offset.  */
-int
-write_wim_header(const struct wim_header *hdr, struct filedes *out_fd)
-{
-       return write_wim_header_at_offset(hdr, out_fd, out_fd->offset);
-}
-
 /* Update just the wim_flags field. */
 int
 write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd)
 /* Update just the wim_flags field. */
 int
 write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd)
@@ -217,49 +209,6 @@ write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd)
                           offsetof(struct wim_header_disk, wim_flags));
 }
 
                           offsetof(struct wim_header_disk, wim_flags));
 }
 
-void
-set_wim_hdr_cflags(enum wimlib_compression_type ctype, struct wim_header *hdr)
-{
-       hdr->flags &= ~(WIM_HDR_FLAG_COMPRESSION |
-                       WIM_HDR_FLAG_COMPRESS_RESERVED |
-                       WIM_HDR_FLAG_COMPRESS_XPRESS |
-                       WIM_HDR_FLAG_COMPRESS_LZX |
-                       WIM_HDR_FLAG_COMPRESS_LZMS |
-                       WIM_HDR_FLAG_COMPRESS_XPRESS_2);
-       switch (ctype) {
-       case WIMLIB_COMPRESSION_TYPE_NONE:
-               return;
-       case WIMLIB_COMPRESSION_TYPE_XPRESS:
-               hdr->flags |= WIM_HDR_FLAG_COMPRESSION | WIM_HDR_FLAG_COMPRESS_XPRESS;
-               return;
-       case WIMLIB_COMPRESSION_TYPE_LZX:
-               hdr->flags |= WIM_HDR_FLAG_COMPRESSION | WIM_HDR_FLAG_COMPRESS_LZX;
-               return;
-       case WIMLIB_COMPRESSION_TYPE_LZMS:
-               hdr->flags |= WIM_HDR_FLAG_COMPRESSION | WIM_HDR_FLAG_COMPRESS_LZMS;
-               return;
-       }
-       wimlib_assert(0);
-}
-
-/* Initialize the header for a WIM file.  */
-void
-init_wim_header(struct wim_header *hdr,
-               enum wimlib_compression_type ctype, u32 chunk_size)
-{
-       memset(hdr, 0, sizeof(struct wim_header));
-       hdr->magic = WIM_MAGIC;
-       if (ctype == WIMLIB_COMPRESSION_TYPE_LZMS)
-               hdr->wim_version = WIM_VERSION_SOLID;
-       else
-               hdr->wim_version = WIM_VERSION_DEFAULT;
-       set_wim_hdr_cflags(ctype, hdr);
-       hdr->chunk_size = chunk_size;
-       hdr->total_parts = 1;
-       hdr->part_number = 1;
-       randomize_byte_array(hdr->guid, sizeof(hdr->guid));
-}
-
 static const struct {
        u32 flag;
        const char *name;
 static const struct {
        u32 flag;
        const char *name;
index 0d1e13782ffad783e44c2e8b26ec944a6ef50c92..2806708975ee41aad67137281ec96a19045268b0 100644 (file)
@@ -281,15 +281,13 @@ out_free_new_table:
  * This function can optionally re-use entries from an older integrity table.
  * To do this, specify old_blob_table_end and old_table.
  *
  * This function can optionally re-use entries from an older integrity table.
  * To do this, specify old_blob_table_end and old_table.
  *
+ * On success, @wim->out_hdr.integrity_table_reshdr will be filled in with
+ * information about the integrity table that was written.
+ *
  * @wim:
  *     WIMStruct for the WIM file.  @wim->out_fd must be a seekable descriptor
  *     to the new WIM file, opened read-write, positioned at the location at
  * @wim:
  *     WIMStruct for the WIM file.  @wim->out_fd must be a seekable descriptor
  *     to the new WIM file, opened read-write, positioned at the location at
- *     which the integrity table is to be written.  Furthermore,
- *     @wim->hdr.integrity is expected to be a resource entry which will be set
- *     to the integrity table information on success.  In addition, if
- *     @old_blob_table_end != 0, @wim->hdr.integrity must initially contain
- *     information about the old integrity table, and @wim->in_fd must be a
- *     seekable descriptor to the original WIM file opened for reading.
+ *     which the integrity table is to be written.
  *
  * @new_blob_table_end:
  *     The offset of the byte directly following the blob table in the WIM
  *
  * @new_blob_table_end:
  *     The offset of the byte directly following the blob table in the WIM
@@ -337,7 +335,7 @@ write_integrity_table(WIMStruct *wim,
                                             &wim->out_fd,
                                             WIMLIB_COMPRESSION_TYPE_NONE,
                                             0,
                                             &wim->out_fd,
                                             WIMLIB_COMPRESSION_TYPE_NONE,
                                             0,
-                                            &wim->hdr.integrity_table_reshdr,
+                                            &wim->out_hdr.integrity_table_reshdr,
                                             NULL,
                                             0);
        FREE(new_table);
                                             NULL,
                                             0);
        FREE(new_table);
index 6ebe87313dbdf405ee9764d9fd7f7e26c75acebf..600176e698841f56a3c1bbe4f0d81ec2fe3f3ee7 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -184,12 +184,23 @@ wimlib_create_new_wim(enum wimlib_compression_type ctype, WIMStruct **wim_ret)
                return WIMLIB_ERR_NOMEM;
        }
 
                return WIMLIB_ERR_NOMEM;
        }
 
-       init_wim_header(&wim->hdr, ctype,
-                       wim_default_nonsolid_chunk_size(ctype));
-       wim->compression_type = ctype;
-       wim->out_compression_type = ctype;
+       /* Fill in wim->hdr with default values  */
+       wim->hdr.magic = WIM_MAGIC;
+       wim->hdr.wim_version = WIM_VERSION_DEFAULT;
+       wim->hdr.flags = 0;
+       wim->hdr.chunk_size = 0;
+       randomize_byte_array(wim->hdr.guid, WIMLIB_GUID_LEN);
+       wim->hdr.part_number = 1;
+       wim->hdr.total_parts = 1;
+       wim->hdr.image_count = 0;
+       wim->hdr.boot_idx = 0;
+
+       wim->compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
        wim->chunk_size = wim->hdr.chunk_size;
        wim->chunk_size = wim->hdr.chunk_size;
-       wim->out_chunk_size = wim->hdr.chunk_size;
+
+       /* Set the output compression type  */
+       wim->out_compression_type = ctype;
+       wim->out_chunk_size = wim_default_nonsolid_chunk_size(ctype);
 
        *wim_ret = wim;
        return 0;
 
        *wim_ret = wim;
        return 0;
index c19d6fcbfc174a4cab3eb548928f38268776b041..a71359420aed78ade13a05b0f2523c645974e1c2 100644 (file)
@@ -628,8 +628,6 @@ end_write_resource(struct write_blobs_ctx *ctx, struct wim_reshdr *out_reshdr)
        out_reshdr->uncompressed_size = res_uncompressed_size;
        out_reshdr->size_in_wim = res_size_in_wim;
        out_reshdr->offset_in_wim = res_offset_in_wim;
        out_reshdr->uncompressed_size = res_uncompressed_size;
        out_reshdr->size_in_wim = res_size_in_wim;
        out_reshdr->offset_in_wim = res_offset_in_wim;
-       DEBUG("Finished writing resource: %"PRIu64" => %"PRIu64" @ %"PRIu64"",
-             res_uncompressed_size, res_size_in_wim, res_offset_in_wim);
        return 0;
 }
 
        return 0;
 }
 
@@ -749,8 +747,6 @@ write_blob_begin_read(struct blob_descriptor *blob, void *_ctx)
                                 * (and reading it again) entirely, passing its
                                 * output reference count to the duplicate blob
                                 * in the former case.  */
                                 * (and reading it again) entirely, passing its
                                 * output reference count to the duplicate blob
                                 * in the former case.  */
-                               DEBUG("Discarding duplicate blob of "
-                                     "length %"PRIu64, blob->size);
                                ret = do_write_blobs_progress(&ctx->progress_data,
                                                              blob->size, 1, true);
                                list_del(&blob->write_blobs_list);
                                ret = do_write_blobs_progress(&ctx->progress_data,
                                                              blob->size, 1, true);
                                list_del(&blob->write_blobs_list);
@@ -773,8 +769,6 @@ write_blob_begin_read(struct blob_descriptor *blob, void *_ctx)
                                 * blob descriptor must wait until
                                 * read_blob_list() has finished reading its
                                 * data.  */
                                 * blob descriptor must wait until
                                 * read_blob_list() has finished reading its
                                 * data.  */
-                               DEBUG("Blob duplicate, but not already "
-                                     "selected for writing.");
                                list_replace(&blob->write_blobs_list,
                                             &new_blob->write_blobs_list);
                                list_replace(&blob->blob_table_list,
                                list_replace(&blob->write_blobs_list,
                                             &new_blob->write_blobs_list);
                                list_replace(&blob->blob_table_list,
@@ -924,8 +918,6 @@ write_chunk(struct write_blobs_ctx *ctx, const void *cchunk,
                /* Starting to write a new blob in non-solid mode.  */
 
                if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
                /* Starting to write a new blob in non-solid mode.  */
 
                if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
-                       DEBUG("Writing pipable WIM blob header "
-                             "(offset=%"PRIu64")", ctx->out_fd->offset);
                        ret = write_pwm_blob_header(blob, ctx->out_fd,
                                                    ctx->compressor != NULL);
                        if (ret)
                        ret = write_pwm_blob_header(blob, ctx->out_fd,
                                                    ctx->compressor != NULL);
                        if (ret)
@@ -1243,10 +1235,6 @@ write_raw_copy_resource(struct wim_resource_descriptor *in_rdesc,
        struct blob_descriptor *blob;
        u64 out_offset_in_wim;
 
        struct blob_descriptor *blob;
        u64 out_offset_in_wim;
 
-       DEBUG("Copying raw compressed data (size_in_wim=%"PRIu64", "
-             "uncompressed_size=%"PRIu64")",
-             in_rdesc->size_in_wim, in_rdesc->uncompressed_size);
-
        /* Copy the raw data.  */
        cur_read_offset = in_rdesc->offset_in_wim;
        end_read_offset = cur_read_offset + in_rdesc->size_in_wim;
        /* Copy the raw data.  */
        cur_read_offset = in_rdesc->offset_in_wim;
        end_read_offset = cur_read_offset + in_rdesc->size_in_wim;
@@ -1520,10 +1508,8 @@ write_blob_list(struct list_head *blob_list,
 
        remove_empty_blobs(blob_list);
 
 
        remove_empty_blobs(blob_list);
 
-       if (list_empty(blob_list)) {
-               DEBUG("No blobs to write.");
+       if (list_empty(blob_list))
                return 0;
                return 0;
-       }
 
        /* If needed, set auxiliary information so that we can detect when the
         * library has finished using each external file.  */
 
        /* If needed, set auxiliary information so that we can detect when the
         * library has finished using each external file.  */
@@ -1575,19 +1561,8 @@ write_blob_list(struct list_head *blob_list,
                                                        out_chunk_size,
                                                        &raw_copy_blobs);
 
                                                        out_chunk_size,
                                                        &raw_copy_blobs);
 
-       DEBUG("Writing blob list "
-             "(offset = %"PRIu64", write_resource_flags=0x%08x, "
-             "out_ctype=%d, out_chunk_size=%u, num_threads=%u, "
-             "total_bytes=%"PRIu64", num_bytes_to_compress=%"PRIu64")",
-             out_fd->offset, write_resource_flags,
-             out_ctype, out_chunk_size, num_threads,
-             ctx.progress_data.progress.write_streams.total_bytes,
-             ctx.num_bytes_to_compress);
-
-       if (ctx.num_bytes_to_compress == 0) {
-               DEBUG("No compression needed; skipping to raw copy!");
+       if (ctx.num_bytes_to_compress == 0)
                goto out_write_raw_copy_resources;
                goto out_write_raw_copy_resources;
-       }
 
        /* Unless uncompressed output was required, allocate a chunk_compressor
         * to do compression.  There are serial and parallel implementations of
 
        /* Unless uncompressed output was required, allocate a chunk_compressor
         * to do compression.  There are serial and parallel implementations of
@@ -1623,9 +1598,6 @@ write_blob_list(struct list_head *blob_list,
        else
                ctx.progress_data.progress.write_streams.num_threads = 1;
 
        else
                ctx.progress_data.progress.write_streams.num_threads = 1;
 
-       DEBUG("Actually using %u threads",
-             ctx.progress_data.progress.write_streams.num_threads);
-
        INIT_LIST_HEAD(&ctx.blobs_being_compressed);
        INIT_LIST_HEAD(&ctx.blobs_in_solid_resource);
 
        INIT_LIST_HEAD(&ctx.blobs_being_compressed);
        INIT_LIST_HEAD(&ctx.blobs_in_solid_resource);
 
@@ -1677,11 +1649,6 @@ write_blob_list(struct list_head *blob_list,
                if (ret)
                        goto out_destroy_context;
 
                if (ret)
                        goto out_destroy_context;
 
-               DEBUG("Ending solid resource: %lu %lu %lu.",
-                     reshdr.offset_in_wim,
-                     reshdr.size_in_wim,
-                     reshdr.uncompressed_size);
-
                offset_in_res = 0;
                list_for_each_entry(blob, &ctx.blobs_in_solid_resource, write_blobs_list) {
                        blob->out_reshdr.size_in_wim = blob->size;
                offset_in_res = 0;
                list_for_each_entry(blob, &ctx.blobs_in_solid_resource, write_blobs_list) {
                        blob->out_reshdr.size_in_wim = blob->size;
@@ -1707,7 +1674,6 @@ out_destroy_context:
        FREE(ctx.chunk_csizes);
        if (ctx.compressor)
                ctx.compressor->destroy(ctx.compressor);
        FREE(ctx.chunk_csizes);
        if (ctx.compressor)
                ctx.compressor->destroy(ctx.compressor);
-       DEBUG("Done (ret=%d)", ret);
        return ret;
 }
 
        return ret;
 }
 
@@ -1729,7 +1695,7 @@ write_file_data_blobs(WIMStruct *wim,
         * has been set to WIM_VERSION_SOLID and at least one blob in the WIM's
         * blob table is located in a solid resource (may be the same WIM, or a
         * different one in the case of export).  */
         * has been set to WIM_VERSION_SOLID and at least one blob in the WIM's
         * blob table is located in a solid resource (may be the same WIM, or a
         * different one in the case of export).  */
-       if (wim->hdr.wim_version == WIM_VERSION_SOLID &&
+       if (wim->out_hdr.wim_version == WIM_VERSION_SOLID &&
            wim_has_solid_resources(wim))
        {
                write_resource_flags |= WRITE_RESOURCE_FLAG_SOLID;
            wim_has_solid_resources(wim))
        {
                write_resource_flags |= WRITE_RESOURCE_FLAG_SOLID;
@@ -2204,18 +2170,13 @@ write_metadata_resources(WIMStruct *wim, int image, int write_flags)
        int end_image;
        int write_resource_flags;
 
        int end_image;
        int write_resource_flags;
 
-       if (write_flags & WIMLIB_WRITE_FLAG_NO_METADATA) {
-               DEBUG("Not writing any metadata resources.");
+       if (write_flags & WIMLIB_WRITE_FLAG_NO_METADATA)
                return 0;
                return 0;
-       }
 
        write_resource_flags = write_flags_to_resource_flags(write_flags);
 
        write_resource_flags &= ~WRITE_RESOURCE_FLAG_SOLID;
 
 
        write_resource_flags = write_flags_to_resource_flags(write_flags);
 
        write_resource_flags &= ~WRITE_RESOURCE_FLAG_SOLID;
 
-       DEBUG("Writing metadata resources (offset=%"PRIu64")",
-             wim->out_fd.offset);
-
        ret = call_progress(wim->progfunc,
                            WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN,
                            NULL, wim->progctx);
        ret = call_progress(wim->progfunc,
                            WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN,
                            NULL, wim->progctx);
@@ -2238,18 +2199,12 @@ write_metadata_resources(WIMStruct *wim, int image, int write_flags)
                 * the original (or was newly added).  Otherwise just copy the
                 * existing one.  */
                if (imd->modified) {
                 * the original (or was newly added).  Otherwise just copy the
                 * existing one.  */
                if (imd->modified) {
-                       DEBUG("Image %u was modified; building and writing new "
-                             "metadata resource", i);
                        ret = write_metadata_resource(wim, i,
                                                      write_resource_flags);
                } else if (write_flags & WIMLIB_WRITE_FLAG_OVERWRITE) {
                        ret = write_metadata_resource(wim, i,
                                                      write_resource_flags);
                } else if (write_flags & WIMLIB_WRITE_FLAG_OVERWRITE) {
-                       DEBUG("Image %u was not modified; re-using existing "
-                             "metadata resource.", i);
                        blob_set_out_reshdr_for_reuse(imd->metadata_blob);
                        ret = 0;
                } else {
                        blob_set_out_reshdr_for_reuse(imd->metadata_blob);
                        ret = 0;
                } else {
-                       DEBUG("Image %u was not modified; copying existing "
-                             "metadata resource.", i);
                        ret = write_wim_resource(imd->metadata_blob,
                                                 &wim->out_fd,
                                                 wim->out_compression_type,
                        ret = write_wim_resource(imd->metadata_blob,
                                                 &wim->out_fd,
                                                 wim->out_compression_type,
@@ -2268,10 +2223,7 @@ write_metadata_resources(WIMStruct *wim, int image, int write_flags)
 static int
 open_wim_writable(WIMStruct *wim, const tchar *path, int open_flags)
 {
 static int
 open_wim_writable(WIMStruct *wim, const tchar *path, int open_flags)
 {
-       int raw_fd;
-       DEBUG("Opening \"%"TS"\" for writing.", path);
-
-       raw_fd = topen(path, open_flags | O_BINARY, 0644);
+       int raw_fd = topen(path, open_flags | O_BINARY, 0644);
        if (raw_fd < 0) {
                ERROR_WITH_ERRNO("Failed to open \"%"TS"\" for writing", path);
                return WIMLIB_ERR_OPEN;
        if (raw_fd < 0) {
                ERROR_WITH_ERRNO("Failed to open \"%"TS"\" for writing", path);
                return WIMLIB_ERR_OPEN;
@@ -2285,12 +2237,10 @@ close_wim_writable(WIMStruct *wim, int write_flags)
 {
        int ret = 0;
 
 {
        int ret = 0;
 
-       if (!(write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)) {
-               DEBUG("Closing WIM file.");
+       if (!(write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR))
                if (filedes_valid(&wim->out_fd))
                        if (filedes_close(&wim->out_fd))
                                ret = WIMLIB_ERR_WRITE;
                if (filedes_valid(&wim->out_fd))
                        if (filedes_close(&wim->out_fd))
                                ret = WIMLIB_ERR_WRITE;
-       }
        filedes_invalidate(&wim->out_fd);
        return ret;
 }
        filedes_invalidate(&wim->out_fd);
        return ret;
 }
@@ -2321,7 +2271,6 @@ cmp_blobs_by_out_rdesc(const void *p1, const void *p2)
 
 static int
 write_blob_table(WIMStruct *wim, int image, int write_flags,
 
 static int
 write_blob_table(WIMStruct *wim, int image, int write_flags,
-                struct wim_reshdr *out_reshdr,
                 struct list_head *blob_table_list)
 {
        int ret;
                 struct list_head *blob_table_list)
 {
        int ret;
@@ -2372,68 +2321,28 @@ write_blob_table(WIMStruct *wim, int image, int write_flags,
 
        return write_blob_table_from_blob_list(blob_table_list,
                                               &wim->out_fd,
 
        return write_blob_table_from_blob_list(blob_table_list,
                                               &wim->out_fd,
-                                              wim->hdr.part_number,
-                                              out_reshdr,
+                                              wim->out_hdr.part_number,
+                                              &wim->out_hdr.blob_table_reshdr,
                                               write_flags_to_resource_flags(write_flags));
 }
 
 /*
                                               write_flags_to_resource_flags(write_flags));
 }
 
 /*
- * finish_write():
- *
  * Finish writing a WIM file: write the blob table, xml data, and integrity
  * Finish writing a WIM file: write the blob table, xml data, and integrity
- * table, then overwrite the WIM header.  By default, closes the WIM file
- * descriptor (@wim->out_fd) if successful.
- *
- * write_flags is a bitwise OR of the following:
- *
- *     (public) WIMLIB_WRITE_FLAG_CHECK_INTEGRITY:
- *             Include an integrity table.
- *
- *     (public) WIMLIB_WRITE_FLAG_FSYNC:
- *             fsync() the output file before closing it.
- *
- *     (public) WIMLIB_WRITE_FLAG_PIPABLE:
- *             Writing a pipable WIM, possibly to a pipe; include pipable WIM
- *             blob headers before the blob table and XML data, and also write
- *             the WIM header at the end instead of seeking to the beginning.
- *             Can't be combined with WIMLIB_WRITE_FLAG_CHECK_INTEGRITY.
- *
- *     (private) WIMLIB_WRITE_FLAG_NO_BLOB_TABLE:
- *             Don't write the blob table.
- *
- *     (private) WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML:
- *             After writing the XML data but before writing the integrity
- *             table, write a temporary WIM header and flush the file
- *             descriptor so that the WIM is less likely to become corrupted
- *             upon abrupt program termination.
- *     (private) WIMLIB_WRITE_FLAG_HEADER_AT_END:
- *             Instead of overwriting the WIM header at the beginning of the
- *             file, simply append it to the end of the file.  (Used when
- *             writing to pipe.)
- *     (private) WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR:
- *             Do not close the file descriptor @wim->out_fd on either success
- *             on failure.
- *     (private) WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES:
- *             Use the existing <TOTALBYTES> stored in the in-memory XML
- *             information, rather than setting it to the offset of the XML
- *             data being written.
- *     (private) WIMLIB_WRITE_FLAG_OVERWRITE
- *             The existing WIM file is being updated in-place.  The entries
- *             from its integrity table may be re-used.
+ * table, then overwrite the WIM header.
+ *
+ * The output file descriptor is closed on success, except when writing to a
+ * user-specified file descriptor (WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR set).
  */
 static int
 finish_write(WIMStruct *wim, int image, int write_flags,
             struct list_head *blob_table_list)
 {
  */
 static int
 finish_write(WIMStruct *wim, int image, int write_flags,
             struct list_head *blob_table_list)
 {
-       int ret;
-       off_t hdr_offset;
        int write_resource_flags;
        off_t old_blob_table_end = 0;
        int write_resource_flags;
        off_t old_blob_table_end = 0;
+       struct integrity_table *old_integrity_table = NULL;
        off_t new_blob_table_end;
        u64 xml_totalbytes;
        off_t new_blob_table_end;
        u64 xml_totalbytes;
-       struct integrity_table *old_integrity_table = NULL;
-
-       DEBUG("image=%d, write_flags=%08x", image, write_flags);
+       int ret;
 
        write_resource_flags = write_flags_to_resource_flags(write_flags);
 
 
        write_resource_flags = write_flags_to_resource_flags(write_flags);
 
@@ -2441,13 +2350,13 @@ finish_write(WIMStruct *wim, int image, int write_flags,
         * metadata resource labeled as the "boot metadata".  This entry should
         * be zeroed out if there is no bootable image (boot_idx 0).  Otherwise,
         * it should be a copy of the resource entry for the image that is
         * metadata resource labeled as the "boot metadata".  This entry should
         * be zeroed out if there is no bootable image (boot_idx 0).  Otherwise,
         * it should be a copy of the resource entry for the image that is
-        * marked as bootable.  This is not well documented...  */
-       if (wim->hdr.boot_idx == 0) {
-               zero_reshdr(&wim->hdr.boot_metadata_reshdr);
+        * marked as bootable.  */
+       if (wim->out_hdr.boot_idx == 0) {
+               zero_reshdr(&wim->out_hdr.boot_metadata_reshdr);
        } else {
        } else {
-               copy_reshdr(&wim->hdr.boot_metadata_reshdr,
+               copy_reshdr(&wim->out_hdr.boot_metadata_reshdr,
                            &wim->image_metadata[
                            &wim->image_metadata[
-                               wim->hdr.boot_idx - 1]->metadata_blob->out_reshdr);
+                               wim->out_hdr.boot_idx - 1]->metadata_blob->out_reshdr);
        }
 
        /* If overwriting the WIM file containing an integrity table in-place,
        }
 
        /* If overwriting the WIM file containing an integrity table in-place,
@@ -2471,10 +2380,9 @@ finish_write(WIMStruct *wim, int image, int write_flags,
                 * ignoring of the return value.  */
        }
 
                 * ignoring of the return value.  */
        }
 
-       /* Write blob table.  */
-       if (!(write_flags & WIMLIB_WRITE_FLAG_NO_BLOB_TABLE)) {
+       /* Write blob table if needed.  */
+       if (!(write_flags & WIMLIB_WRITE_FLAG_NO_NEW_BLOBS)) {
                ret = write_blob_table(wim, image, write_flags,
                ret = write_blob_table(wim, image, write_flags,
-                                      &wim->hdr.blob_table_reshdr,
                                       blob_table_list);
                if (ret) {
                        free_integrity_table(old_integrity_table);
                                       blob_table_list);
                if (ret) {
                        free_integrity_table(old_integrity_table);
@@ -2487,30 +2395,33 @@ finish_write(WIMStruct *wim, int image, int write_flags,
        if (write_flags & WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES)
                xml_totalbytes = WIM_TOTALBYTES_USE_EXISTING;
        ret = write_wim_xml_data(wim, image, xml_totalbytes,
        if (write_flags & WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES)
                xml_totalbytes = WIM_TOTALBYTES_USE_EXISTING;
        ret = write_wim_xml_data(wim, image, xml_totalbytes,
-                                &wim->hdr.xml_data_reshdr,
+                                &wim->out_hdr.xml_data_reshdr,
                                 write_resource_flags);
        if (ret) {
                free_integrity_table(old_integrity_table);
                return ret;
        }
 
                                 write_resource_flags);
        if (ret) {
                free_integrity_table(old_integrity_table);
                return ret;
        }
 
-       /* Write integrity table (optional).  */
+       /* Write integrity table if needed.  */
        if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
        if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
-               if (write_flags & WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML) {
+               if (write_flags & WIMLIB_WRITE_FLAG_NO_NEW_BLOBS) {
+                       /* The XML data we wrote may have overwritten part of
+                        * the old integrity table, so while calculating the new
+                        * integrity table we should temporarily update the WIM
+                        * header to remove the integrity table reference.   */
                        struct wim_header checkpoint_hdr;
                        struct wim_header checkpoint_hdr;
-                       memcpy(&checkpoint_hdr, &wim->hdr, sizeof(struct wim_header));
+                       memcpy(&checkpoint_hdr, &wim->out_hdr, sizeof(struct wim_header));
                        zero_reshdr(&checkpoint_hdr.integrity_table_reshdr);
                        checkpoint_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
                        zero_reshdr(&checkpoint_hdr.integrity_table_reshdr);
                        checkpoint_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
-                       ret = write_wim_header_at_offset(&checkpoint_hdr,
-                                                        &wim->out_fd, 0);
+                       ret = write_wim_header(&checkpoint_hdr, &wim->out_fd, 0);
                        if (ret) {
                                free_integrity_table(old_integrity_table);
                                return ret;
                        }
                }
 
                        if (ret) {
                                free_integrity_table(old_integrity_table);
                                return ret;
                        }
                }
 
-               new_blob_table_end = wim->hdr.blob_table_reshdr.offset_in_wim +
-                                    wim->hdr.blob_table_reshdr.size_in_wim;
+               new_blob_table_end = wim->out_hdr.blob_table_reshdr.offset_in_wim +
+                                    wim->out_hdr.blob_table_reshdr.size_in_wim;
 
                ret = write_integrity_table(wim,
                                            new_blob_table_end,
 
                ret = write_integrity_table(wim,
                                            new_blob_table_end,
@@ -2521,19 +2432,18 @@ finish_write(WIMStruct *wim, int image, int write_flags,
                        return ret;
        } else {
                /* No integrity table.  */
                        return ret;
        } else {
                /* No integrity table.  */
-               zero_reshdr(&wim->hdr.integrity_table_reshdr);
+               zero_reshdr(&wim->out_hdr.integrity_table_reshdr);
        }
 
        /* Now that all information in the WIM header has been determined, the
         * preliminary header written earlier can be overwritten, the header of
         * the existing WIM file can be overwritten, or the final header can be
         * written to the end of the pipable WIM.  */
        }
 
        /* Now that all information in the WIM header has been determined, the
         * preliminary header written earlier can be overwritten, the header of
         * the existing WIM file can be overwritten, or the final header can be
         * written to the end of the pipable WIM.  */
-       wim->hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
-       hdr_offset = 0;
-       if (write_flags & WIMLIB_WRITE_FLAG_HEADER_AT_END)
-               hdr_offset = wim->out_fd.offset;
-       DEBUG("Writing new header @ %"PRIu64".", hdr_offset);
-       ret = write_wim_header_at_offset(&wim->hdr, &wim->out_fd, hdr_offset);
+       wim->out_hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
+       if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
+               ret = write_wim_header(&wim->out_hdr, &wim->out_fd, wim->out_fd.offset);
+       else
+               ret = write_wim_header(&wim->out_hdr, &wim->out_fd, 0);
        if (ret)
                return ret;
 
        if (ret)
                return ret;
 
@@ -2544,7 +2454,6 @@ finish_write(WIMStruct *wim, int image, int write_flags,
         * operation has been written to disk, but the new file data has not.
         */
        if (write_flags & WIMLIB_WRITE_FLAG_FSYNC) {
         * operation has been written to disk, but the new file data has not.
         */
        if (write_flags & WIMLIB_WRITE_FLAG_FSYNC) {
-               DEBUG("Syncing WIM file.");
                if (fsync(wim->out_fd.fd)) {
                        ERROR_WITH_ERRNO("Error syncing data to WIM file");
                        return WIMLIB_ERR_WRITE;
                if (fsync(wim->out_fd.fd)) {
                        ERROR_WITH_ERRNO("Error syncing data to WIM file");
                        return WIMLIB_ERR_WRITE;
@@ -2732,87 +2641,8 @@ write_wim_part(WIMStruct *wim,
               const u8 *guid)
 {
        int ret;
               const u8 *guid)
 {
        int ret;
-       struct wim_header hdr_save;
        struct list_head blob_table_list;
 
        struct list_head blob_table_list;
 
-       if (total_parts == 1)
-               DEBUG("Writing standalone WIM.");
-       else
-               DEBUG("Writing split WIM part %u/%u", part_number, total_parts);
-       if (image == WIMLIB_ALL_IMAGES)
-               DEBUG("Including all images.");
-       else
-               DEBUG("Including image %d only.", image);
-       if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
-               DEBUG("File descriptor: %d", *(const int*)path_or_fd);
-       else
-               DEBUG("Path: \"%"TS"\"", (const tchar*)path_or_fd);
-       DEBUG("Write flags: 0x%08x", write_flags);
-
-       if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY)
-               DEBUG("\tCHECK_INTEGRITY");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)
-               DEBUG("\tNO_CHECK_INTEGRITY");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
-               DEBUG("\tPIPABLE");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_NOT_PIPABLE)
-               DEBUG("\tNOT_PIPABLE");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
-               DEBUG("\tRECOMPRESS");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_FSYNC)
-               DEBUG("\tFSYNC");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_REBUILD)
-               DEBUG("\tREBUILD");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)
-               DEBUG("\tSOFT_DELETE");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_IGNORE_READONLY_FLAG)
-               DEBUG("\tIGNORE_READONLY_FLAG");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS)
-               DEBUG("\tSKIP_EXTERNAL_WIMS");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_STREAMS_OK)
-               DEBUG("\tSTREAMS_OK");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_RETAIN_GUID)
-               DEBUG("\tRETAIN_GUID");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_SOLID)
-               DEBUG("\tSOLID");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES)
-               DEBUG("\tSEND_DONE_WITH_FILE_MESSAGES");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_NO_SOLID_SORT)
-               DEBUG("\tNO_SOLID_SORT");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
-               DEBUG("\tFILE_DESCRIPTOR");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_NO_METADATA)
-               DEBUG("\tNO_METADATA");
-
-       if (write_flags & WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES)
-               DEBUG("\tUSE_EXISTING_TOTALBYTES");
-
-       if (num_threads == 0)
-               DEBUG("Number of threads: autodetect");
-       else
-               DEBUG("Number of threads: %u", num_threads);
-       DEBUG("Progress function: %s", (wim->progfunc ? "yes" : "no"));
-       DEBUG("Blob list:         %s", (blob_list_override ? "specified" : "autodetect"));
-       DEBUG("GUID:              %s", (write_flags &
-                                       WIMLIB_WRITE_FLAG_RETAIN_GUID) ? "retain"
-                                               : guid ? "explicit" : "generate new");
-
        /* Internally, this is always called with a valid part number and total
         * parts.  */
        wimlib_assert(total_parts >= 1);
        /* Internally, this is always called with a valid part number and total
         * parts.  */
        wimlib_assert(total_parts >= 1);
@@ -2843,93 +2673,98 @@ write_wim_part(WIMStruct *wim,
                                    WIMLIB_WRITE_FLAG_NOT_PIPABLE))
                return WIMLIB_ERR_INVALID_PARAM;
 
                                    WIMLIB_WRITE_FLAG_NOT_PIPABLE))
                return WIMLIB_ERR_INVALID_PARAM;
 
-       /* Save previous header, then start initializing the new one.  */
-       memcpy(&hdr_save, &wim->hdr, sizeof(struct wim_header));
+       /* Include an integrity table by default if no preference was given and
+        * the WIM already had an integrity table.  */
+       if (!(write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
+                            WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY))) {
+               if (wim_has_integrity_table(wim))
+                       write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
+       }
 
 
-       /* Set default integrity, pipable, and solid flags.  */
+       /* Write a pipable WIM by default if no preference was given and the WIM
+        * was already pipable.  */
        if (!(write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
        if (!(write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
-                            WIMLIB_WRITE_FLAG_NOT_PIPABLE)))
-               if (wim_is_pipable(wim)) {
-                       DEBUG("WIM is pipable; default to PIPABLE.");
+                            WIMLIB_WRITE_FLAG_NOT_PIPABLE))) {
+               if (wim_is_pipable(wim))
                        write_flags |= WIMLIB_WRITE_FLAG_PIPABLE;
                        write_flags |= WIMLIB_WRITE_FLAG_PIPABLE;
-               }
-
-       if (!(write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
-                            WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)))
-               if (wim_has_integrity_table(wim)) {
-                       DEBUG("Integrity table present; default to CHECK_INTEGRITY.");
-                       write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
-               }
+       }
 
        if ((write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
                            WIMLIB_WRITE_FLAG_SOLID))
                                    == (WIMLIB_WRITE_FLAG_PIPABLE |
                                        WIMLIB_WRITE_FLAG_SOLID))
        {
 
        if ((write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
                            WIMLIB_WRITE_FLAG_SOLID))
                                    == (WIMLIB_WRITE_FLAG_PIPABLE |
                                        WIMLIB_WRITE_FLAG_SOLID))
        {
-               ERROR("Cannot specify both PIPABLE and SOLID!");
+               ERROR("Solid compression is unsupported in pipable WIMs");
                return WIMLIB_ERR_INVALID_PARAM;
        }
 
                return WIMLIB_ERR_INVALID_PARAM;
        }
 
-       /* Set appropriate magic number.  */
+       /* Start initializing the new file header.  */
+       memset(&wim->out_hdr, 0, sizeof(wim->out_hdr));
+
+       /* Set the magic number.  */
        if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
        if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
-               wim->hdr.magic = PWM_MAGIC;
+               wim->out_hdr.magic = PWM_MAGIC;
        else
        else
-               wim->hdr.magic = WIM_MAGIC;
+               wim->out_hdr.magic = WIM_MAGIC;
 
 
-       /* Set appropriate version number.  */
+       /* Set the version number.  */
        if ((write_flags & WIMLIB_WRITE_FLAG_SOLID) ||
            wim->out_compression_type == WIMLIB_COMPRESSION_TYPE_LZMS)
        if ((write_flags & WIMLIB_WRITE_FLAG_SOLID) ||
            wim->out_compression_type == WIMLIB_COMPRESSION_TYPE_LZMS)
-               wim->hdr.wim_version = WIM_VERSION_SOLID;
+               wim->out_hdr.wim_version = WIM_VERSION_SOLID;
        else
        else
-               wim->hdr.wim_version = WIM_VERSION_DEFAULT;
-
-       /* Clear header flags that will be set automatically.  */
-       wim->hdr.flags &= ~(WIM_HDR_FLAG_METADATA_ONLY          |
-                           WIM_HDR_FLAG_RESOURCE_ONLY          |
-                           WIM_HDR_FLAG_SPANNED                |
-                           WIM_HDR_FLAG_WRITE_IN_PROGRESS);
+               wim->out_hdr.wim_version = WIM_VERSION_DEFAULT;
 
 
-       /* Set SPANNED header flag if writing part of a split WIM.  */
+       /* Set the header flags.  */
+       wim->out_hdr.flags = (wim->hdr.flags & (WIM_HDR_FLAG_RP_FIX |
+                                               WIM_HDR_FLAG_READONLY));
        if (total_parts != 1)
        if (total_parts != 1)
-               wim->hdr.flags |= WIM_HDR_FLAG_SPANNED;
+               wim->out_hdr.flags |= WIM_HDR_FLAG_SPANNED;
+       if (wim->out_compression_type != WIMLIB_COMPRESSION_TYPE_NONE) {
+               wim->out_hdr.flags |= WIM_HDR_FLAG_COMPRESSION;
+               switch (wim->out_compression_type) {
+               case WIMLIB_COMPRESSION_TYPE_XPRESS:
+                       wim->out_hdr.flags |= WIM_HDR_FLAG_COMPRESS_XPRESS;
+                       break;
+               case WIMLIB_COMPRESSION_TYPE_LZX:
+                       wim->out_hdr.flags |= WIM_HDR_FLAG_COMPRESS_LZX;
+                       break;
+               case WIMLIB_COMPRESSION_TYPE_LZMS:
+                       wim->out_hdr.flags |= WIM_HDR_FLAG_COMPRESS_LZMS;
+                       break;
+               }
+       }
 
 
-       /* Set part number and total parts of split WIM.  This will be 1 and 1
-        * if the WIM is standalone.  */
-       wim->hdr.part_number = part_number;
-       wim->hdr.total_parts = total_parts;
+       /* Set the chunk size.  */
+       wim->out_hdr.chunk_size = wim->out_chunk_size;
 
 
-       /* Set the compression type and chunk size.  */
-       set_wim_hdr_cflags(wim->out_compression_type, &wim->hdr);
-       wim->hdr.chunk_size = wim->out_chunk_size;
+       /* Set the GUID.  */
+       if (write_flags & WIMLIB_WRITE_FLAG_RETAIN_GUID)
+               guid = wim->hdr.guid;
+       if (guid)
+               memcpy(wim->out_hdr.guid, guid, WIMLIB_GUID_LEN);
+       else
+               randomize_byte_array(wim->out_hdr.guid, WIMLIB_GUID_LEN);
 
 
-       /* Set GUID.  */
-       if (!(write_flags & WIMLIB_WRITE_FLAG_RETAIN_GUID)) {
-               if (guid)
-                       memcpy(wim->hdr.guid, guid, WIMLIB_GUID_LEN);
-               else
-                       randomize_byte_array(wim->hdr.guid, WIMLIB_GUID_LEN);
-       }
+       /* Set the part number and total parts.  */
+       wim->out_hdr.part_number = part_number;
+       wim->out_hdr.total_parts = total_parts;
 
 
-       /* Clear references to resources that have not been written yet.  */
-       zero_reshdr(&wim->hdr.blob_table_reshdr);
-       zero_reshdr(&wim->hdr.xml_data_reshdr);
-       zero_reshdr(&wim->hdr.boot_metadata_reshdr);
-       zero_reshdr(&wim->hdr.integrity_table_reshdr);
+       /* Set the image count.  */
+       if (image == WIMLIB_ALL_IMAGES)
+               wim->out_hdr.image_count = wim->hdr.image_count;
+       else
+               wim->out_hdr.image_count = 1;
 
 
-       /* Set image count and boot index correctly for single image writes.  */
-       if (image != WIMLIB_ALL_IMAGES) {
-               wim->hdr.image_count = 1;
-               if (wim->hdr.boot_idx == image)
-                       wim->hdr.boot_idx = 1;
-               else
-                       wim->hdr.boot_idx = 0;
+       /* Set the boot index.  */
+       wim->out_hdr.boot_idx = 0;
+       if (total_parts == 1) {
+               if (image == WIMLIB_ALL_IMAGES)
+                       wim->out_hdr.boot_idx = wim->hdr.boot_idx;
+               else if (image == wim->hdr.boot_idx)
+                       wim->out_hdr.boot_idx = 1;
        }
 
        }
 
-       /* Split WIMs can't be bootable.  */
-       if (total_parts != 1)
-               wim->hdr.boot_idx = 0;
-
-       /* Set up output file descriptor.  */
+       /* Set up the output file descriptor.  */
        if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR) {
                /* File descriptor was explicitly provided.  */
                filedes_init(&wim->out_fd, *(const int *)path_or_fd);
        if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR) {
                /* File descriptor was explicitly provided.  */
                filedes_init(&wim->out_fd, *(const int *)path_or_fd);
@@ -2937,32 +2772,31 @@ write_wim_part(WIMStruct *wim,
                        /* The file descriptor is a pipe.  */
                        ret = WIMLIB_ERR_INVALID_PARAM;
                        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
                        /* The file descriptor is a pipe.  */
                        ret = WIMLIB_ERR_INVALID_PARAM;
                        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
-                               goto out_restore_hdr;
+                               goto out_cleanup;
                        if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
                                ERROR("Can't include integrity check when "
                                      "writing pipable WIM to pipe!");
                        if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
                                ERROR("Can't include integrity check when "
                                      "writing pipable WIM to pipe!");
-                               goto out_restore_hdr;
+                               goto out_cleanup;
                        }
                }
                        }
                }
-
        } else {
                /* Filename of WIM to write was provided; open file descriptor
                 * to it.  */
                ret = open_wim_writable(wim, (const tchar*)path_or_fd,
                                        O_TRUNC | O_CREAT | O_RDWR);
                if (ret)
        } else {
                /* Filename of WIM to write was provided; open file descriptor
                 * to it.  */
                ret = open_wim_writable(wim, (const tchar*)path_or_fd,
                                        O_TRUNC | O_CREAT | O_RDWR);
                if (ret)
-                       goto out_restore_hdr;
+                       goto out_cleanup;
        }
 
        /* Write initial header.  This is merely a "dummy" header since it
        }
 
        /* Write initial header.  This is merely a "dummy" header since it
-        * doesn't have all the information yet, so it will be overwritten later
-        * (unless writing a pipable WIM).  */
+        * doesn't have resource entries filled in yet, so it will be
+        * overwritten later (unless writing a pipable WIM).  */
        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
-               wim->hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
-       ret = write_wim_header(&wim->hdr, &wim->out_fd);
-       wim->hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
+               wim->out_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
+       ret = write_wim_header(&wim->out_hdr, &wim->out_fd, wim->out_fd.offset);
+       wim->out_hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
        if (ret)
        if (ret)
-               goto out_restore_hdr;
+               goto out_cleanup;
 
        /* Write file data and metadata resources.  */
        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) {
 
        /* Write file data and metadata resources.  */
        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) {
@@ -2972,28 +2806,24 @@ write_wim_part(WIMStruct *wim,
                                      blob_list_override,
                                      &blob_table_list);
                if (ret)
                                      blob_list_override,
                                      &blob_table_list);
                if (ret)
-                       goto out_restore_hdr;
+                       goto out_cleanup;
 
                ret = write_metadata_resources(wim, image, write_flags);
                if (ret)
 
                ret = write_metadata_resources(wim, image, write_flags);
                if (ret)
-                       goto out_restore_hdr;
+                       goto out_cleanup;
        } else {
                /* Non-default case: create pipable WIM.  */
                ret = write_pipable_wim(wim, image, write_flags, num_threads,
                                        blob_list_override,
                                        &blob_table_list);
                if (ret)
        } else {
                /* Non-default case: create pipable WIM.  */
                ret = write_pipable_wim(wim, image, write_flags, num_threads,
                                        blob_list_override,
                                        &blob_table_list);
                if (ret)
-                       goto out_restore_hdr;
-               write_flags |= WIMLIB_WRITE_FLAG_HEADER_AT_END;
+                       goto out_cleanup;
        }
 
        }
 
-
        /* Write blob table, XML data, and (optional) integrity table.  */
        ret = finish_write(wim, image, write_flags, &blob_table_list);
        /* Write blob table, XML data, and (optional) integrity table.  */
        ret = finish_write(wim, image, write_flags, &blob_table_list);
-out_restore_hdr:
-       memcpy(&wim->hdr, &hdr_save, sizeof(struct wim_header));
+out_cleanup:
        (void)close_wim_writable(wim, write_flags);
        (void)close_wim_writable(wim, write_flags);
-       DEBUG("ret=%d", ret);
        return ret;
 }
 
        return ret;
 }
 
@@ -3096,11 +2926,10 @@ check_resource_offsets(WIMStruct *wim, off_t end_offset)
  * header.  This operation is potentially unsafe if the program is abruptly
  * terminated while the XML data or integrity table are being overwritten, but
  * before the new header has been written.  To partially alleviate this problem,
  * header.  This operation is potentially unsafe if the program is abruptly
  * terminated while the XML data or integrity table are being overwritten, but
  * before the new header has been written.  To partially alleviate this problem,
- * a special flag (WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML) is passed to
- * finish_write() to cause a temporary WIM header to be written after the XML
- * data has been written.  This may prevent the WIM from becoming corrupted if
- * the program is terminated while the integrity table is being calculated (but
- * no guarantees, due to write re-ordering...).
+ * we write a temporary header after the XML data has been written.  This may
+ * prevent the WIM from becoming corrupted if the program is terminated while
+ * the integrity table is being calculated (but no guarantees, due to write
+ * re-ordering...).
  *
  * If we are adding new blobs, including new file data as well as any metadata
  * for any new images, then the blob table needs to be changed, and those blobs
  *
  * If we are adding new blobs, including new file data as well as any metadata
  * for any new images, then the blob table needs to be changed, and those blobs
@@ -3143,25 +2972,24 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
        int ret;
        off_t old_wim_end;
        u64 old_blob_table_end, old_xml_begin, old_xml_end;
        int ret;
        off_t old_wim_end;
        u64 old_blob_table_end, old_xml_begin, old_xml_end;
-       struct wim_header hdr_save;
        struct list_head blob_list;
        struct list_head blob_table_list;
        struct filter_context filter_ctx;
 
        struct list_head blob_list;
        struct list_head blob_table_list;
        struct filter_context filter_ctx;
 
-       DEBUG("Overwriting `%"TS"' in-place", wim->filename);
-
-       /* Save original header so it can be restored in case of error  */
-       memcpy(&hdr_save, &wim->hdr, sizeof(struct wim_header));
-
-       /* Set default integrity flag.  */
+       /* Include an integrity table by default if no preference was given and
+        * the WIM already had an integrity table.  */
        if (!(write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
                             WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)))
                if (wim_has_integrity_table(wim))
                        write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
 
        if (!(write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
                             WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)))
                if (wim_has_integrity_table(wim))
                        write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
 
-       /* Set WIM version if writing solid resources.  */
+       /* Start preparing the updated file header.  */
+       memcpy(&wim->out_hdr, &wim->hdr, sizeof(wim->out_hdr));
+
+       /* If using solid compression, the version number must be set to
+        * WIM_VERSION_SOLID.  */
        if (write_flags & WIMLIB_WRITE_FLAG_SOLID)
        if (write_flags & WIMLIB_WRITE_FLAG_SOLID)
-               wim->hdr.wim_version = WIM_VERSION_SOLID;
+               wim->out_hdr.wim_version = WIM_VERSION_SOLID;
 
        /* Set additional flags for overwrite.  */
        write_flags |= WIMLIB_WRITE_FLAG_OVERWRITE |
 
        /* Set additional flags for overwrite.  */
        write_flags |= WIMLIB_WRITE_FLAG_OVERWRITE |
@@ -3174,17 +3002,17 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
        old_xml_end = old_xml_begin + wim->hdr.xml_data_reshdr.size_in_wim;
        old_blob_table_end = wim->hdr.blob_table_reshdr.offset_in_wim +
                             wim->hdr.blob_table_reshdr.size_in_wim;
        old_xml_end = old_xml_begin + wim->hdr.xml_data_reshdr.size_in_wim;
        old_blob_table_end = wim->hdr.blob_table_reshdr.offset_in_wim +
                             wim->hdr.blob_table_reshdr.size_in_wim;
-       if (wim->hdr.integrity_table_reshdr.offset_in_wim != 0 &&
+       if (wim_has_integrity_table(wim) &&
            wim->hdr.integrity_table_reshdr.offset_in_wim < old_xml_end) {
                WARNING("Didn't expect the integrity table to be before the XML data");
                ret = WIMLIB_ERR_RESOURCE_ORDER;
            wim->hdr.integrity_table_reshdr.offset_in_wim < old_xml_end) {
                WARNING("Didn't expect the integrity table to be before the XML data");
                ret = WIMLIB_ERR_RESOURCE_ORDER;
-               goto out_restore_memory_hdr;
+               goto out;
        }
 
        if (old_blob_table_end > old_xml_begin) {
                WARNING("Didn't expect the blob table to be after the XML data");
                ret = WIMLIB_ERR_RESOURCE_ORDER;
        }
 
        if (old_blob_table_end > old_xml_begin) {
                WARNING("Didn't expect the blob table to be after the XML data");
                ret = WIMLIB_ERR_RESOURCE_ORDER;
-               goto out_restore_memory_hdr;
+               goto out;
        }
 
        /* Set @old_wim_end, which indicates the point beyond which we don't
        }
 
        /* Set @old_wim_end, which indicates the point beyond which we don't
@@ -3197,12 +3025,9 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
                 * shall write the new XML data and optional integrity table
                 * immediately after the blob table.  Note that this may
                 * overwrite an existing integrity table. */
                 * shall write the new XML data and optional integrity table
                 * immediately after the blob table.  Note that this may
                 * overwrite an existing integrity table. */
-               DEBUG("Skipping writing blob table "
-                     "(no images modified or deleted)");
                old_wim_end = old_blob_table_end;
                old_wim_end = old_blob_table_end;
-               write_flags |= WIMLIB_WRITE_FLAG_NO_BLOB_TABLE |
-                              WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML;
-       } else if (wim->hdr.integrity_table_reshdr.offset_in_wim != 0) {
+               write_flags |= WIMLIB_WRITE_FLAG_NO_NEW_BLOBS;
+       } else if (wim_has_integrity_table(wim)) {
                /* Old WIM has an integrity table; begin writing new blobs after
                 * it. */
                old_wim_end = wim->hdr.integrity_table_reshdr.offset_in_wim +
                /* Old WIM has an integrity table; begin writing new blobs after
                 * it. */
                old_wim_end = wim->hdr.integrity_table_reshdr.offset_in_wim +
@@ -3215,17 +3040,20 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
 
        ret = check_resource_offsets(wim, old_wim_end);
        if (ret)
 
        ret = check_resource_offsets(wim, old_wim_end);
        if (ret)
-               goto out_restore_memory_hdr;
+               goto out;
 
        ret = prepare_blob_list_for_write(wim, WIMLIB_ALL_IMAGES, write_flags,
                                          &blob_list, &blob_table_list,
                                          &filter_ctx);
        if (ret)
 
        ret = prepare_blob_list_for_write(wim, WIMLIB_ALL_IMAGES, write_flags,
                                          &blob_list, &blob_table_list,
                                          &filter_ctx);
        if (ret)
-               goto out_restore_memory_hdr;
+               goto out;
+
+       if (write_flags & WIMLIB_WRITE_FLAG_NO_NEW_BLOBS)
+               wimlib_assert(list_empty(&blob_list));
 
        ret = open_wim_writable(wim, wim->filename, O_RDWR);
        if (ret)
 
        ret = open_wim_writable(wim, wim->filename, O_RDWR);
        if (ret)
-               goto out_restore_memory_hdr;
+               goto out;
 
        ret = lock_wim_for_append(wim);
        if (ret)
 
        ret = lock_wim_for_append(wim);
        if (ret)
@@ -3234,6 +3062,7 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
        /* Set WIM_HDR_FLAG_WRITE_IN_PROGRESS flag in header. */
        wim->hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
        ret = write_wim_header_flags(wim->hdr.flags, &wim->out_fd);
        /* Set WIM_HDR_FLAG_WRITE_IN_PROGRESS flag in header. */
        wim->hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
        ret = write_wim_header_flags(wim->hdr.flags, &wim->out_fd);
+       wim->hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
        if (ret) {
                ERROR_WITH_ERRNO("Error updating WIM header flags");
                goto out_unlock_wim;
        if (ret) {
                ERROR_WITH_ERRNO("Error updating WIM header flags");
                goto out_unlock_wim;
@@ -3242,7 +3071,7 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
        if (filedes_seek(&wim->out_fd, old_wim_end) == -1) {
                ERROR_WITH_ERRNO("Can't seek to end of WIM");
                ret = WIMLIB_ERR_WRITE;
        if (filedes_seek(&wim->out_fd, old_wim_end) == -1) {
                ERROR_WITH_ERRNO("Can't seek to end of WIM");
                ret = WIMLIB_ERR_WRITE;
-               goto out_restore_physical_hdr;
+               goto out_restore_hdr;
        }
 
        ret = write_file_data_blobs(wim, &blob_list, write_flags,
        }
 
        ret = write_file_data_blobs(wim, &blob_list, write_flags,
@@ -3263,21 +3092,20 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
        return 0;
 
 out_truncate:
        return 0;
 
 out_truncate:
-       if (!(write_flags & WIMLIB_WRITE_FLAG_NO_BLOB_TABLE)) {
-               WARNING("Truncating `%"TS"' to its original size (%"PRIu64" bytes)",
-                       wim->filename, old_wim_end);
+       if (!(write_flags & WIMLIB_WRITE_FLAG_NO_NEW_BLOBS)) {
+               WARNING("Truncating \"%"TS"\" to its original size "
+                       "(%"PRIu64" bytes)", wim->filename, old_wim_end);
                /* Return value of ftruncate() is ignored because this is
                 * already an error path.  */
                (void)ftruncate(wim->out_fd.fd, old_wim_end);
        }
                /* Return value of ftruncate() is ignored because this is
                 * already an error path.  */
                (void)ftruncate(wim->out_fd.fd, old_wim_end);
        }
-out_restore_physical_hdr:
-       (void)write_wim_header_flags(hdr_save.flags, &wim->out_fd);
+out_restore_hdr:
+       (void)write_wim_header_flags(wim->hdr.flags, &wim->out_fd);
 out_unlock_wim:
        unlock_wim_for_append(wim);
 out_close_wim:
        (void)close_wim_writable(wim, write_flags);
 out_unlock_wim:
        unlock_wim_for_append(wim);
 out_close_wim:
        (void)close_wim_writable(wim, write_flags);
-out_restore_memory_hdr:
-       memcpy(&wim->hdr, &hdr_save, sizeof(struct wim_header));
+out:
        return ret;
 }
 
        return ret;
 }
 
@@ -3287,8 +3115,6 @@ overwrite_wim_via_tmpfile(WIMStruct *wim, int write_flags, unsigned num_threads)
        size_t wim_name_len;
        int ret;
 
        size_t wim_name_len;
        int ret;
 
-       DEBUG("Overwriting `%"TS"' via a temporary file", wim->filename);
-
        /* Write the WIM to a temporary file in the same directory as the
         * original WIM. */
        wim_name_len = tstrlen(wim->filename);
        /* Write the WIM to a temporary file in the same directory as the
         * original WIM. */
        wim_name_len = tstrlen(wim->filename);
@@ -3315,7 +3141,6 @@ overwrite_wim_via_tmpfile(WIMStruct *wim, int write_flags, unsigned num_threads)
        /* Rename the new WIM file to the original WIM file.  Note: on Windows
         * this actually calls win32_rename_replacement(), not _wrename(), so
         * that removing the existing destination file can be handled.  */
        /* Rename the new WIM file to the original WIM file.  Note: on Windows
         * this actually calls win32_rename_replacement(), not _wrename(), so
         * that removing the existing destination file can be handled.  */
-       DEBUG("Renaming `%"TS"' to `%"TS"'", tmpfile, wim->filename);
        ret = trename(tmpfile, wim->filename);
        if (ret) {
                ERROR_WITH_ERRNO("Failed to rename `%"TS"' to `%"TS"'",
        ret = trename(tmpfile, wim->filename);
        if (ret) {
                ERROR_WITH_ERRNO("Failed to rename `%"TS"' to `%"TS"'",