+/* Rewrite a stream that was just written compressed as uncompressed instead.
+ * This function is optional, but if a stream did not compress to less than its
+ * original size, it might as well be written uncompressed. */
+static int
+write_stream_uncompressed(struct wim_lookup_table_entry *lte,
+ struct filedes *out_fd)
+{
+ int ret;
+ u64 begin_offset = lte->out_reshdr.offset_in_wim;
+ u64 end_offset = out_fd->offset;
+
+ if (filedes_seek(out_fd, begin_offset) == -1)
+ return 0;
+
+ ret = extract_full_stream_to_fd(lte, out_fd);
+ if (ret) {
+ /* Error reading the uncompressed data. */
+ if (out_fd->offset == begin_offset &&
+ filedes_seek(out_fd, end_offset) != -1)
+ {
+ /* Nothing was actually written yet, and we successfully
+ * seeked to the end of the compressed resource, so
+ * don't issue a hard error; just keep the compressed
+ * resource instead. */
+ WARNING("Recovered compressed stream of "
+ "size %"PRIu64", continuing on.",
+ lte->size);
+ return 0;
+ }
+ return ret;
+ }
+
+ wimlib_assert(out_fd->offset - begin_offset == lte->size);
+
+ if (out_fd->offset < end_offset &&
+ 0 != ftruncate(out_fd->fd, out_fd->offset))
+ {
+ ERROR_WITH_ERRNO("Can't truncate output file to "
+ "offset %"PRIu64, out_fd->offset);
+ return WIMLIB_ERR_WRITE;
+ }
+
+ lte->out_reshdr.size_in_wim = lte->size;
+ lte->out_reshdr.flags &= ~(WIM_RESHDR_FLAG_COMPRESSED |
+ WIM_RESHDR_FLAG_PACKED_STREAMS);
+ return 0;
+}
+
+/* Returns true if the specified stream should be truncated from the WIM file
+ * and re-written as uncompressed. lte->out_reshdr must be filled in from the
+ * initial write of the stream. */
+static bool
+should_rewrite_stream_uncompressed(const struct write_streams_ctx *ctx,
+ const struct wim_lookup_table_entry *lte)
+{
+ /* If the compressed data is smaller than the uncompressed data, prefer
+ * the compressed data. */
+ if (lte->out_reshdr.size_in_wim < lte->out_reshdr.uncompressed_size)
+ return false;
+
+ /* If we're not actually writing compressed data, then there's no need
+ * for re-writing. */
+ if (!ctx->compressor)
+ return false;
+
+ /* If writing a pipable WIM, everything we write to the output is final
+ * (it might actually be a pipe!). */
+ if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE)
+ return false;
+
+ /* If the stream that would need to be re-read is located in a solid
+ * block in another WIM file, then re-reading it would be costly. So
+ * don't do it.
+ *
+ * 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).
+ *
+ * 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;
+
+ 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);
+}
+