]> wimlib.net Git - wimlib/blobdiff - src/write.c
write.c: Do not raw-copy packed resources
[wimlib] / src / write.c
index e495cb5b29721c21aa7a1526b0d8d604453348f5..3895088ee2c408e5d990a073512100f3bb0bc309 100644 (file)
@@ -176,6 +176,9 @@ can_raw_copy(const struct wim_lookup_table_entry *lte,
                        rspec->wim->chunk_size == out_chunk_size);
        }
 
+       /* XXX: For compatibility, we can't allow multiple packed resources per
+        * WIM.  */
+#if 0
        if ((rspec->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) &&
            (write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS))
        {
@@ -198,6 +201,8 @@ can_raw_copy(const struct wim_lookup_table_entry *lte,
 
                return (write_size > rspec->uncompressed_size / 2);
        }
+#endif
+
        return false;
 }
 
@@ -268,20 +273,6 @@ write_pwm_stream_header(const struct wim_lookup_table_entry *lte,
        return ret;
 }
 
-#if 0
-static int
-seek_and_truncate(struct filedes *out_fd, off_t offset)
-{
-       if (filedes_seek(out_fd, offset) == -1 ||
-           ftruncate(out_fd->fd, offset))
-       {
-               ERROR_WITH_ERRNO("Failed to truncate output WIM file");
-               return WIMLIB_ERR_WRITE;
-       }
-       return 0;
-}
-#endif
-
 struct write_streams_progress_data {
        wimlib_progress_func_t progress_func;
        union wimlib_progress_info progress;
@@ -718,6 +709,33 @@ write_stream_begin_read(struct wim_lookup_table_entry *lte,
        return 0;
 }
 
+static int
+write_stream_uncompressed(struct wim_lookup_table_entry *lte,
+                         struct filedes *out_fd)
+{
+       int ret;
+
+       if (-1 == lseek(out_fd->fd, lte->out_reshdr.offset_in_wim, SEEK_SET) ||
+           0 != ftruncate(out_fd->fd, lte->out_reshdr.offset_in_wim))
+       {
+               ERROR_WITH_ERRNO("Can't truncate output file to "
+                                "offset %"PRIu64, lte->out_reshdr.offset_in_wim);
+               return WIMLIB_ERR_WRITE;
+       }
+
+       out_fd->offset = lte->out_reshdr.offset_in_wim;
+
+       ret = extract_stream_to_fd(lte, out_fd, lte->size);
+       if (ret)
+               return ret;
+
+       wimlib_assert(out_fd->offset - lte->out_reshdr.offset_in_wim == lte->size);
+       lte->out_reshdr.size_in_wim = lte->size;
+       lte->out_reshdr.flags &= ~(WIM_RESHDR_FLAG_COMPRESSED |
+                                  WIM_RESHDR_FLAG_PACKED_STREAMS);
+       return 0;
+}
+
 /* Write the next chunk of (typically compressed) data to the output WIM,
  * handling the writing of the chunk table.  */
 static int
@@ -798,12 +816,32 @@ write_chunk(struct write_streams_ctx *ctx, const void *cchunk,
                if (ret)
                        return ret;
 
-               wimlib_assert(lte->out_reshdr.uncompressed_size == lte->size);
-
                lte->out_reshdr.flags = filter_resource_flags(lte->flags);
                if (ctx->compressor != NULL)
                        lte->out_reshdr.flags |= WIM_RESHDR_FLAG_COMPRESSED;
 
+               if (ctx->compressor != NULL &&
+                   lte->out_reshdr.size_in_wim >= lte->out_reshdr.uncompressed_size &&
+                   !(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) &&
+                   !(lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS))
+               {
+                       /* Stream did not compress to less than its original
+                        * size.  If we're not writing a pipable WIM (which
+                        * could mean the output file descriptor is
+                        * non-seekable), and the stream isn't located in a
+                        * resource pack (which would make reading it again
+                        * costly), truncate the file to the start of the stream
+                        * and write it uncompressed instead.  */
+                       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;
+               }
+
+               wimlib_assert(lte->out_reshdr.uncompressed_size == lte->size);
+
                list_del(&lte->write_streams_list);
                ctx->cur_write_res_offset = 0;
        }
@@ -1343,12 +1381,7 @@ write_stream_list(struct list_head *stream_list,
         * bytes needing to be compressed is less 2000000 (heuristic value).  */
        if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
 
-               if (out_ctype == WIMLIB_COMPRESSION_TYPE_LZMS &&
-                   ctx.lookup_table != NULL) {
-                       WARNING("LZMS compression not implemented; data will "
-                               "actually be written uncompressed.");
-               }
-
+       #ifdef ENABLE_MULTITHREADED_COMPRESSION
                if (ctx.num_bytes_to_compress >= 2000000) {
                        ret = new_parallel_chunk_compressor(out_ctype,
                                                            out_chunk_size,
@@ -1359,6 +1392,7 @@ write_stream_list(struct list_head *stream_list,
                                      "(status %d)", ret);
                        }
                }
+       #endif
 
                if (ctx.compressor == NULL) {
                        ret = new_serial_chunk_compressor(out_ctype, out_chunk_size,
@@ -1460,6 +1494,39 @@ out_destroy_context:
        return ret;
 }
 
+static int
+wim_write_stream_list(WIMStruct *wim,
+                     struct list_head *stream_list,
+                     int write_flags,
+                     unsigned num_threads,
+                     struct filter_context *filter_ctx,
+                     wimlib_progress_func_t progress_func)
+{
+       int out_ctype;
+       u32 out_chunk_size;
+       int write_resource_flags;
+
+       write_resource_flags = write_flags_to_resource_flags(write_flags);
+
+       if (write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
+               out_chunk_size = wim->out_pack_chunk_size;
+               out_ctype = wim->out_pack_compression_type;
+       } else {
+               out_chunk_size = wim->out_chunk_size;
+               out_ctype = wim->out_compression_type;
+       }
+
+       return write_stream_list(stream_list,
+                                &wim->out_fd,
+                                write_resource_flags,
+                                out_ctype,
+                                out_chunk_size,
+                                num_threads,
+                                wim->lookup_table,
+                                filter_ctx,
+                                progress_func);
+}
+
 static int
 write_wim_resource(struct wim_lookup_table_entry *lte,
                   struct filedes *out_fd,
@@ -1912,15 +1979,12 @@ write_wim_streams(WIMStruct *wim, int image, int write_flags,
                }
        }
 
-       return write_stream_list(stream_list,
-                                &wim->out_fd,
-                                write_flags_to_resource_flags(write_flags),
-                                wim->out_compression_type,
-                                wim->out_chunk_size,
-                                num_threads,
-                                wim->lookup_table,
-                                filter_ctx,
-                                progress_func);
+       return wim_write_stream_list(wim,
+                                    stream_list,
+                                    write_flags,
+                                    num_threads,
+                                    filter_ctx,
+                                    progress_func);
 }
 
 static int
@@ -2576,7 +2640,8 @@ write_wim_part(WIMStruct *wim,
                wim->hdr.magic = WIM_MAGIC;
 
        /* Set appropriate version number.  */
-       if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS)
+       if ((write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS) ||
+           wim->out_compression_type == WIMLIB_COMPRESSION_TYPE_LZMS)
                wim->hdr.wim_version = WIM_VERSION_PACKED_STREAMS;
        else
                wim->hdr.wim_version = WIM_VERSION_DEFAULT;
@@ -2964,15 +3029,12 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags,
                goto out_restore_physical_hdr;
        }
 
-       ret = write_stream_list(&stream_list,
-                               &wim->out_fd,
-                               write_flags_to_resource_flags(write_flags),
-                               wim->compression_type,
-                               wim->chunk_size,
-                               num_threads,
-                               wim->lookup_table,
-                               &filter_ctx,
-                               progress_func);
+       ret = wim_write_stream_list(wim,
+                                   &stream_list,
+                                   write_flags,
+                                   num_threads,
+                                   &filter_ctx,
+                                   progress_func);
        if (ret)
                goto out_truncate;