out_ctype, out_chunk_size,
&raw_copy_blobs);
- /* Copy any compressed resources for which the raw data can be reused
- * without decompression. */
- ret = write_raw_copy_resources(&raw_copy_blobs, ctx.out_fd,
- &ctx.progress_data);
-
- if (ret || num_nonraw_bytes == 0)
- goto out_destroy_context;
-
- /* Unless uncompressed output was required, allocate a chunk_compressor
- * to do compression. There are serial and parallel implementations of
- * the chunk_compressor interface. We default to parallel using the
+ /* Unless no data needs to be compressed, allocate a chunk_compressor to
+ * do compression. There are serial and parallel implementations of the
+ * chunk_compressor interface. We default to parallel using the
* specified number of threads, unless the upper bound on the number
* bytes needing to be compressed is less than a heuristic value. */
- if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
-
+ if (num_nonraw_bytes != 0 && out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
#ifdef ENABLE_MULTITHREADED_COMPRESSION
if (num_nonraw_bytes > max(2000000, out_chunk_size)) {
ret = new_parallel_chunk_compressor(out_ctype,
else
ctx.progress_data.progress.write_streams.num_threads = 1;
- INIT_LIST_HEAD(&ctx.blobs_being_compressed);
- INIT_LIST_HEAD(&ctx.blobs_in_solid_resource);
-
ret = call_progress(ctx.progress_data.progfunc,
WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
&ctx.progress_data.progress,
if (ret)
goto out_destroy_context;
+ /* Copy any compressed resources for which the raw data can be reused
+ * without decompression. */
+ ret = write_raw_copy_resources(&raw_copy_blobs, ctx.out_fd,
+ &ctx.progress_data);
+
+ if (ret || num_nonraw_bytes == 0)
+ goto out_destroy_context;
+
+ INIT_LIST_HEAD(&ctx.blobs_being_compressed);
+
if (write_resource_flags & WRITE_RESOURCE_FLAG_SOLID) {
+
+ INIT_LIST_HEAD(&ctx.blobs_in_solid_resource);
+
ret = begin_write_resource(&ctx, num_nonraw_bytes);
if (ret)
goto out_destroy_context;
if (!(write_flags & WIMLIB_WRITE_FLAG_NO_NEW_BLOBS)) {
ret = write_blob_table(wim, image, write_flags,
blob_table_list);
- if (ret) {
- free_integrity_table(old_integrity_table);
- return ret;
- }
+ if (ret)
+ goto out;
}
/* Write XML data. */
ret = write_wim_xml_data(wim, image, xml_totalbytes,
&wim->out_hdr.xml_data_reshdr,
write_resource_flags);
- if (ret) {
- free_integrity_table(old_integrity_table);
- return ret;
- }
+ if (ret)
+ goto out;
/* Write integrity table if needed. */
- if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
+ if ((write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) &&
+ wim->out_hdr.blob_table_reshdr.offset_in_wim != 0)
+ {
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
zero_reshdr(&checkpoint_hdr.integrity_table_reshdr);
checkpoint_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
ret = write_wim_header(&checkpoint_hdr, &wim->out_fd, 0);
- if (ret) {
- free_integrity_table(old_integrity_table);
- return ret;
- }
+ if (ret)
+ goto out;
}
new_blob_table_end = wim->out_hdr.blob_table_reshdr.offset_in_wim +
new_blob_table_end,
old_blob_table_end,
old_integrity_table);
- free_integrity_table(old_integrity_table);
if (ret)
- return ret;
+ goto out;
} else {
/* No integrity table. */
zero_reshdr(&wim->out_hdr.integrity_table_reshdr);
else
ret = write_wim_header(&wim->out_hdr, &wim->out_fd, 0);
if (ret)
- return ret;
+ goto out;
+ ret = WIMLIB_ERR_WRITE;
if (unlikely(write_flags & WIMLIB_WRITE_FLAG_UNSAFE_COMPACT)) {
/* Truncate any data the compaction freed up. */
- if (ftruncate(wim->out_fd.fd, wim->out_fd.offset)) {
+ if (ftruncate(wim->out_fd.fd, wim->out_fd.offset) &&
+ errno != EINVAL) /* allow compaction on untruncatable files,
+ e.g. block devices */
+ {
ERROR_WITH_ERRNO("Failed to truncate the output WIM file");
- return WIMLIB_ERR_WRITE;
+ goto out;
}
}
* the system is abruptly terminated when the metadata for the rename
* operation has been written to disk, but the new file data has not.
*/
+ ret = WIMLIB_ERR_WRITE;
if (write_flags & WIMLIB_WRITE_FLAG_FSYNC) {
if (fsync(wim->out_fd.fd)) {
ERROR_WITH_ERRNO("Error syncing data to WIM file");
- return WIMLIB_ERR_WRITE;
+ goto out;
}
}
+ ret = WIMLIB_ERR_WRITE;
if (close_wim_writable(wim, write_flags)) {
ERROR_WITH_ERRNO("Failed to close the output WIM file");
- return WIMLIB_ERR_WRITE;
+ goto out;
}
- return 0;
+ ret = 0;
+out:
+ free_integrity_table(old_integrity_table);
+ return ret;
}
#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
return 0;
}
+static int
+free_blob_if_invalidated(struct blob_descriptor *blob, void *_wim)
+{
+ const WIMStruct *wim = _wim;
+
+ if (!blob->will_be_in_output_wim &&
+ blob->blob_location == BLOB_IN_WIM && blob->rdesc->wim == wim)
+ {
+ blob_table_unlink(wim->blob_table, blob);
+ free_blob_descriptor(blob);
+ }
+ return 0;
+}
+
/*
* Overwrite a WIM, possibly appending new resources to it.
*
if (ret)
goto out;
+ /* Prevent new files from being deduplicated with existing blobs
+ * in the WIM that we haven't decided to write. Such blobs will
+ * be overwritten during the compaction. */
+ for_blob_in_table(wim->blob_table, free_blob_if_invalidated, wim);
+
if (wim_has_metadata(wim)) {
/* Add existing metadata resources to be compacted along
* with the file resources. */
* this data would be overwritten. */
old_xml_begin = wim->hdr.xml_data_reshdr.offset_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.blob_table_reshdr.offset_in_wim == 0)
+ old_blob_table_end = WIM_HEADER_DISK_SIZE;
+ else
+ old_blob_table_end = wim->hdr.blob_table_reshdr.offset_in_wim +
+ wim->hdr.blob_table_reshdr.size_in_wim;
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 "