X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwrite.c;h=f3c12ffe4cbc8ffacced2e635ff3a352c773a21f;hp=7da18891132f466374a1cd72766e27f7758ade82;hb=f18b7fc3361c4daac0ddd104af65a8eff8466fec;hpb=0275de680bf2c36769eba45822d5b85c7092da88 diff --git a/src/write.c b/src/write.c index 7da18891..f3c12ffe 100644 --- a/src/write.c +++ b/src/write.c @@ -32,6 +32,13 @@ # include #endif +#include +#include +#include +#include + +#include "wimlib/alloca.h" +#include "wimlib/assert.h" #include "wimlib/chunk_compressor.h" #include "wimlib/endianness.h" #include "wimlib/error.h" @@ -50,14 +57,6 @@ #include "wimlib/write.h" #include "wimlib/xml.h" -#include -#include -#include -#include - -#ifdef HAVE_ALLOCA_H -# include -#endif /* wimlib internal flags used when writing resources. */ #define WRITE_RESOURCE_FLAG_RECOMPRESS 0x00000001 @@ -517,8 +516,8 @@ end_chunk_table(struct write_streams_ctx *ctx, u64 res_actual_size, 0 != (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS)); - typedef le64 __attribute__((may_alias)) aliased_le64_t; - typedef le32 __attribute__((may_alias)) aliased_le32_t; + typedef le64 _may_alias_attribute aliased_le64_t; + typedef le32 _may_alias_attribute aliased_le32_t; if (chunk_entry_size == 4) { aliased_le32_t *entries = (aliased_le32_t*)ctx->chunk_csizes; @@ -882,7 +881,15 @@ should_rewrite_stream_uncompressed(const struct write_streams_ctx *ctx, * Exception: if the compressed size happens to be *exactly* the same as * the uncompressed size, then the stream *must* be written uncompressed * in order to remain compatible with the Windows Overlay Filesystem - * Filter Driver (WOF). */ + * Filter Driver (WOF). + * + * TODO: we are currently assuming that the optimization for + * single-chunk resources in maybe_rewrite_stream_uncompressed() + * prevents this case from being triggered too often. To fully prevent + * excessive decompressions in degenerate cases, we really should + * obtain the uncompressed data by decompressing the compressed data we + * wrote to the output file. + */ if ((lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) && (lte->out_reshdr.size_in_wim != lte->out_reshdr.uncompressed_size)) return false; @@ -890,6 +897,28 @@ should_rewrite_stream_uncompressed(const struct write_streams_ctx *ctx, return true; } +static int +maybe_rewrite_stream_uncompressed(struct write_streams_ctx *ctx, + struct wim_lookup_table_entry *lte) +{ + if (!should_rewrite_stream_uncompressed(ctx, lte)) + return 0; + + /* Regular (non-solid) WIM resources with exactly one chunk and + * compressed size equal to uncompressed size are exactly the same as + * the corresponding compressed data --- since there must be 0 entries + * in the chunk table and the only chunk must be stored uncompressed. + * In this case, there's no need to rewrite anything. */ + if (ctx->chunk_index == 1 && + lte->out_reshdr.size_in_wim == lte->out_reshdr.uncompressed_size) + { + lte->out_reshdr.flags &= ~WIM_RESHDR_FLAG_COMPRESSED; + return 0; + } + + return write_stream_uncompressed(lte, ctx->out_fd); +} + /* Write the next chunk of (typically compressed) data to the output WIM, * handling the writing of the chunk table. */ static int @@ -996,14 +1025,10 @@ write_chunk(struct write_streams_ctx *ctx, const void *cchunk, if (ctx->compressor != NULL) lte->out_reshdr.flags |= WIM_RESHDR_FLAG_COMPRESSED; - if (should_rewrite_stream_uncompressed(ctx, lte)) { - DEBUG("Stream of size %"PRIu64" did not compress to " - "less than original size; writing uncompressed.", - lte->size); - ret = write_stream_uncompressed(lte, ctx->out_fd); - if (ret) - return ret; - } + ret = maybe_rewrite_stream_uncompressed(ctx, lte); + if (ret) + return ret; + wimlib_assert(lte->out_reshdr.uncompressed_size == lte->size); ctx->cur_write_stream_offset = 0; @@ -3222,7 +3247,7 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads) * allow any file and metadata resources to appear without returning * WIMLIB_ERR_RESOURCE_ORDER (due to the fact that we would otherwise * overwrite these resources). */ - if (!wim->deletion_occurred && !any_images_modified(wim)) { + if (!wim->image_deletion_occurred && !any_images_modified(wim)) { /* If no images have been modified and no images have been * deleted, a new lookup table does not need to be written. We * shall write the new XML data and optional integrity table @@ -3379,8 +3404,9 @@ can_overwrite_wim_inplace(const WIMStruct *wim, int write_flags) if (write_flags & WIMLIB_WRITE_FLAG_REBUILD) return false; - /* Deletions cause full rebuild by default. */ - if (wim->deletion_occurred && !(write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)) + /* Image deletions cause full rebuild by default. */ + if (wim->image_deletion_occurred && + !(write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)) return false; /* Pipable WIMs cannot be updated in place, nor can a non-pipable WIM be