*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
blob_hdr.flags = cpu_to_le32(reshdr_flags);
ret = full_write(out_fd, &blob_hdr, sizeof(blob_hdr));
if (ret)
- ERROR_WITH_ERRNO("Write error");
+ ERROR_WITH_ERRNO("Error writing blob header to WIM file");
return ret;
}
* @blobs_being_compressed only when writing a solid resource. */
struct list_head blobs_in_solid_resource;
- /* Current uncompressed offset in the blob being read. */
- u64 cur_read_blob_offset;
-
- /* Uncompressed size of the blob currently being read. */
- u64 cur_read_blob_size;
-
/* Current uncompressed offset in the blob being written. */
u64 cur_write_blob_offset;
reserve_size += sizeof(struct alt_chunk_table_header_disk);
memset(ctx->chunk_csizes, 0, reserve_size);
ret = full_write(ctx->out_fd, ctx->chunk_csizes, reserve_size);
- if (ret)
+ if (ret) {
+ ERROR_WITH_ERRNO("Error reserving space for chunk "
+ "table in WIM file");
return ret;
+ }
}
return 0;
}
return 0;
write_error:
- ERROR_WITH_ERRNO("Write error");
+ ERROR_WITH_ERRNO("Error writing chunk table to WIM file");
return ret;
}
{
int ret;
struct wim_inode *inode;
+ const tchar *path;
tchar *cookie1;
tchar *cookie2;
if (--inode->i_num_remaining_streams > 0)
return 0;
- cookie1 = progress_get_streamless_path(blob->file_on_disk);
- cookie2 = progress_get_win32_path(blob->file_on_disk);
+ path = blob_file_path(blob);
- ret = done_with_file(blob->file_on_disk, progfunc, progctx);
+ cookie1 = progress_get_streamless_path(path);
+ cookie2 = progress_get_win32_path(path);
+
+ ret = done_with_file(path, progfunc, progctx);
progress_put_win32_path(cookie2);
progress_put_streamless_path(cookie1);
wimlib_assert(blob->size > 0);
- ctx->cur_read_blob_offset = 0;
- ctx->cur_read_blob_size = blob->size;
-
/* As an optimization, we allow some blobs to be "unhashed", meaning
* their SHA-1 message digests are unknown. This is the case with blobs
* that are added by scanning a directory tree with wimlib_add_image(),
* Exception: if the compressed size happens to be *exactly* the same as
* the uncompressed size, then the blob *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_blob_uncompressed() prevents
completed_blob_count, false);
write_error:
- ERROR_WITH_ERRNO("Write error");
+ ERROR_WITH_ERRNO("Error writing chunk data to WIM file");
return ret;
}
/* Process the next chunk of data to be written to a WIM resource. */
static int
-write_blob_process_chunk(const void *chunk, size_t size, void *_ctx)
+write_blob_process_chunk(const struct blob_descriptor *blob, u64 offset,
+ const void *chunk, size_t size, void *_ctx)
{
struct write_blobs_ctx *ctx = _ctx;
int ret;
ret = write_chunk(ctx, chunk, size, size);
if (ret)
return ret;
- ctx->cur_read_blob_offset += size;
return 0;
}
} else {
needed_chunk_size = min(ctx->out_chunk_size,
ctx->cur_chunk_buf_filled +
- (ctx->cur_read_blob_size -
- ctx->cur_read_blob_offset));
+ (blob->size - offset));
}
bytes_consumed = min(chunkend - chunkptr,
chunkptr, bytes_consumed);
chunkptr += bytes_consumed;
- ctx->cur_read_blob_offset += bytes_consumed;
+ offset += bytes_consumed;
ctx->cur_chunk_buf_filled += bytes_consumed;
if (ctx->cur_chunk_buf_filled == needed_chunk_size) {
{
struct write_blobs_ctx *ctx = _ctx;
- wimlib_assert(ctx->cur_read_blob_offset == ctx->cur_read_blob_size || status);
-
if (!blob->will_be_in_output_wim) {
/* The blob was a duplicate. Now that its data has finished
* being read, it is being discarded in favor of the duplicate
ret = full_pread(in_fd, buf, bytes_to_read,
cur_read_offset);
- if (ret)
+ if (ret) {
+ ERROR_WITH_ERRNO("Error reading raw data "
+ "from WIM file");
return ret;
+ }
ret = full_write(out_fd, buf, bytes_to_read);
- if (ret)
+ if (ret) {
+ ERROR_WITH_ERRNO("Error writing raw data "
+ "to WIM file");
return ret;
+ }
cur_read_offset += bytes_to_read;
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;
struct read_blob_callbacks cbs = {
.begin_blob = write_blob_begin_read,
- .consume_chunk = write_blob_process_chunk,
+ .continue_blob = write_blob_process_chunk,
.end_blob = write_blob_end_read,
.ctx = &ctx,
};
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)
* 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 "
WIMLIB_WRITE_FLAG_UNSAFE_COMPACT))) {
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);
+ if (ftruncate(wim->out_fd.fd, old_wim_end))
+ WARNING_WITH_ERRNO("Failed to truncate WIM file!");
}
out_restore_hdr:
(void)write_wim_header_flags(wim->hdr.flags, &wim->out_fd);