if (rspec->is_pipable != !!(write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE))
return false;
-
if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) {
/* Normal compressed resource: Must use same compression type
* and chunk size. */
rspec->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))
{
/* Packed resource: Such resources may contain multiple streams,
* and in general only a subset of them need to be written. As
- * a heuristic, re-use the raw data if at least half the
+ * a heuristic, re-use the raw data if more than two-thirds the
* uncompressed size is being written. */
/* Note: packed resources contain a header that specifies the
if (res_stream->will_be_in_output_wim)
write_size += res_stream->size;
- return (write_size > rspec->uncompressed_size / 2);
+ return (write_size > rspec->uncompressed_size * 2 / 3);
}
-#endif
return false;
}
lte->out_res_offset_in_wim = rspec->offset_in_wim;
lte->out_res_size_in_wim = rspec->size_in_wim;
- /*lte->out_res_uncompressed_size = rspec->uncompressed_size;*/
+ lte->out_res_uncompressed_size = rspec->uncompressed_size;
} else {
wimlib_assert(!(lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS));
wimlib_progress_func_t progress_func;
union wimlib_progress_info progress;
uint64_t next_progress;
- WIMStruct *prev_wim_part;
};
static void
bool discarded)
{
union wimlib_progress_info *progress = &progress_data->progress;
- bool new_wim_part;
if (discarded) {
progress->write_streams.total_bytes -= complete_size;
progress->write_streams.completed_streams += complete_count;
}
- new_wim_part = false;
- if (cur_stream->resource_location == RESOURCE_IN_WIM &&
- cur_stream->rspec->wim != progress_data->prev_wim_part)
- {
- if (progress_data->prev_wim_part) {
- new_wim_part = true;
- progress->write_streams.completed_parts++;
- }
- progress_data->prev_wim_part = cur_stream->rspec->wim;
- }
-
if (progress_data->progress_func
- && (progress->write_streams.completed_bytes >= progress_data->next_progress
- || new_wim_part))
+ && (progress->write_streams.completed_bytes >= progress_data->next_progress))
{
progress_data->progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
progress);
hdr.chunk_size = cpu_to_le32(ctx->out_chunk_size);
hdr.compression_format = cpu_to_le32(ctx->out_ctype);
- BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 1);
- BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 2);
+ BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 1);
+ BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 2);
BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3);
ret = full_pwrite(ctx->out_fd, &hdr, sizeof(hdr),
/* Begin processing a stream for writing. */
static int
write_stream_begin_read(struct wim_lookup_table_entry *lte,
- bool is_partial_res, void *_ctx)
+ u32 flags, void *_ctx)
{
struct write_streams_ctx *ctx = _ctx;
int ret;
ctx->stream_was_duplicate = false;
if (ctx->lookup_table != NULL && lte->unhashed && !lte->unique_size) {
- wimlib_assert(!is_partial_res);
+ wimlib_assert(!(flags & BEGIN_STREAM_FLAG_PARTIAL_RESOURCE));
struct wim_lookup_table_entry *lte_new;
* compressed chunk. */
while (!ctx->compressor->submit_chunk(ctx->compressor, chunk, size)) {
const void *cchunk;
- unsigned csize;
- unsigned usize;
+ u32 csize;
+ u32 usize;
bool bret;
int ret;
ctx->progress_data.progress.write_streams.total_parts = total_parts;
ctx->progress_data.progress.write_streams.completed_parts = 0;
ctx->progress_data.next_progress = 0;
- ctx->progress_data.prev_wim_part = NULL;
}
/* Find streams in @stream_list that can be copied to the output WIM in raw form
- * rather than compressed. Delete these streams from @stream_list, and move one
- * per resource to @raw_copy_resources. Return the total uncompressed size of
- * the streams that need to be compressed. */
+ * rather than compressed. Delete these streams from @stream_list and move them
+ * to @raw_copy_streams. Return the total uncompressed size of the streams that
+ * need to be compressed. */
static u64
-find_raw_copy_resources(struct list_head *stream_list,
- int write_resource_flags,
- int out_ctype,
- u32 out_chunk_size,
- struct list_head *raw_copy_resources)
+find_raw_copy_streams(struct list_head *stream_list,
+ int write_resource_flags,
+ int out_ctype,
+ u32 out_chunk_size,
+ struct list_head *raw_copy_streams)
{
struct wim_lookup_table_entry *lte, *tmp;
u64 num_bytes_to_compress = 0;
- INIT_LIST_HEAD(raw_copy_resources);
+ INIT_LIST_HEAD(raw_copy_streams);
/* Initialize temporary raw_copy_ok flag. */
list_for_each_entry(lte, stream_list, write_streams_list)
if (lte->resource_location == RESOURCE_IN_WIM &&
lte->rspec->raw_copy_ok)
{
- list_del(<e->write_streams_list);
+ list_move_tail(<e->write_streams_list,
+ raw_copy_streams);
} else if (can_raw_copy(lte, write_resource_flags,
out_ctype, out_chunk_size))
{
lte->rspec->raw_copy_ok = 1;
list_move_tail(<e->write_streams_list,
- raw_copy_resources);
+ raw_copy_streams);
} else {
num_bytes_to_compress += lte->size;
}
return 0;
}
-/* Copy a list of raw compressed resources located other WIM file(s) to the WIM
- * file being written. */
+/* Copy a list of raw compressed resources located in other WIM file(s) to the
+ * WIM file being written. */
static int
-write_raw_copy_resources(struct list_head *raw_copy_resources,
+write_raw_copy_resources(struct list_head *raw_copy_streams,
struct filedes *out_fd,
struct write_streams_progress_data *progress_data)
{
struct wim_lookup_table_entry *lte;
int ret;
- list_for_each_entry(lte, raw_copy_resources, write_streams_list) {
- ret = write_raw_copy_resource(lte->rspec, out_fd);
- if (ret)
- return ret;
+ list_for_each_entry(lte, raw_copy_streams, write_streams_list)
+ lte->rspec->raw_copy_ok = 1;
+
+ list_for_each_entry(lte, raw_copy_streams, write_streams_list) {
+ if (lte->rspec->raw_copy_ok) {
+ /* Write each packed resource only one time, no matter
+ * how many streams reference it. */
+ ret = write_raw_copy_resource(lte->rspec, out_fd);
+ if (ret)
+ return ret;
+ lte->rspec->raw_copy_ok = 0;
+ }
do_write_streams_progress(progress_data, lte, lte->size,
1, false);
}
finish_remaining_chunks(struct write_streams_ctx *ctx)
{
const void *cdata;
- unsigned csize;
- unsigned usize;
+ u32 csize;
+ u32 usize;
int ret;
if (ctx->compressor == NULL)
{
int ret;
struct write_streams_ctx ctx;
- struct list_head raw_copy_resources;
+ struct list_head raw_copy_streams;
wimlib_assert((write_resource_flags &
(WRITE_RESOURCE_FLAG_PACK_STREAMS |
ctx.progress_data.progress_func = progress_func;
- ctx.num_bytes_to_compress = find_raw_copy_resources(stream_list,
- write_resource_flags,
- out_ctype,
- out_chunk_size,
- &raw_copy_resources);
+ ctx.num_bytes_to_compress = find_raw_copy_streams(stream_list,
+ write_resource_flags,
+ out_ctype,
+ out_chunk_size,
+ &raw_copy_streams);
DEBUG("Writing stream list "
"(offset = %"PRIu64", write_resource_flags=0x%08x, "
lte->out_reshdr.offset_in_wim = offset_in_res;
lte->out_res_offset_in_wim = reshdr.offset_in_wim;
lte->out_res_size_in_wim = reshdr.size_in_wim;
- /*lte->out_res_uncompressed_size = reshdr.uncompressed_size;*/
+ lte->out_res_uncompressed_size = reshdr.uncompressed_size;
offset_in_res += lte->size;
}
wimlib_assert(offset_in_res == reshdr.uncompressed_size);
out_write_raw_copy_resources:
/* Copy any compressed resources for which the raw data can be reused
* without decompression. */
- ret = write_raw_copy_resources(&raw_copy_resources, ctx.out_fd,
+ ret = write_raw_copy_resources(&raw_copy_streams, ctx.out_fd,
&ctx.progress_data);
out_destroy_context:
return ret;
}
+static int
+is_stream_packed(struct wim_lookup_table_entry *lte, void *_ignore)
+{
+ return lte_is_partial(lte);
+}
+
+static bool
+wim_has_packed_streams(WIMStruct *wim)
+{
+ return for_lookup_table_entry(wim->lookup_table, is_stream_packed, NULL);
+}
+
static int
wim_write_stream_list(WIMStruct *wim,
struct list_head *stream_list,
write_resource_flags = write_flags_to_resource_flags(write_flags);
+ /* wimlib v1.6.3: pack streams by default if the WIM version has been
+ * set to WIM_VERSION_PACKED_STREAMS and at least one stream in the
+ * WIM's lookup table is located in a packed resource (may be the same
+ * WIM, or a different one in the case of export). */
+ if (wim->hdr.wim_version == WIM_VERSION_PACKED_STREAMS &&
+ wim_has_packed_streams(wim))
+ {
+ write_resource_flags |= WRITE_RESOURCE_FLAG_PACK_STREAMS;
+ }
+
if (write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
out_chunk_size = wim->out_pack_chunk_size;
out_ctype = wim->out_pack_compression_type;
* @stream_list_ret.
*
* SKIP_EXTERNAL_WIMS: Streams already present in a WIM file, but not
- * @wim, shall be be returned in neither @stream_list_ret nor
+ * @wim, shall be returned in neither @stream_list_ret nor
* @lookup_table_list_ret.
*
* @stream_list_ret
if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY)
DEBUG("\tCHECK_INTEGRITY");
- if (write_flags & WIMLIB_WRITE_FLAG_REBUILD)
- DEBUG("\tREBUILD");
+ if (write_flags & WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)
+ DEBUG("\tNO_CHECK_INTEGRITY");
+
+ if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
+ DEBUG("\tPIPABLE");
+
+ if (write_flags & WIMLIB_WRITE_FLAG_NOT_PIPABLE)
+ DEBUG("\tNOT_PIPABLE");
if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
DEBUG("\tRECOMPRESS");
if (write_flags & WIMLIB_WRITE_FLAG_FSYNC)
DEBUG("\tFSYNC");
+ if (write_flags & WIMLIB_WRITE_FLAG_REBUILD)
+ DEBUG("\tREBUILD");
+
if (write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)
- DEBUG("\tFSYNC");
+ DEBUG("\tSOFT_DELETE");
if (write_flags & WIMLIB_WRITE_FLAG_IGNORE_READONLY_FLAG)
DEBUG("\tIGNORE_READONLY_FLAG");
- if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
- DEBUG("\tPIPABLE");
+ if (write_flags & WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS)
+ DEBUG("\tSKIP_EXTERNAL_WIMS");
- if (write_flags & WIMLIB_WRITE_FLAG_NOT_PIPABLE)
- DEBUG("\tNOT_PIPABLE");
+ if (write_flags & WIMLIB_WRITE_FLAG_STREAMS_OK)
+ DEBUG("\tSTREAMS_OK");
+
+ if (write_flags & WIMLIB_WRITE_FLAG_RETAIN_GUID)
+ DEBUG("\tRETAIN_GUID");
if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS)
DEBUG("\tPACK_STREAMS");
DEBUG("Number of threads: %u", num_threads);
DEBUG("Progress function: %s", (progress_func ? "yes" : "no"));
DEBUG("Stream list: %s", (stream_list_override ? "specified" : "autodetect"));
- DEBUG("GUID: %s", ((guid || wim->guid_set_explicitly) ?
- "specified" : "generate new"));
+ DEBUG("GUID: %s", (write_flags &
+ WIMLIB_WRITE_FLAG_RETAIN_GUID) ? "retain"
+ : guid ? "explicit" : "generate new");
/* Internally, this is always called with a valid part number and total
* parts. */
/* Set chunk size if different. */
wim->hdr.chunk_size = wim->out_chunk_size;
- /* Use GUID if specified; otherwise generate a new one. */
- if (guid)
- memcpy(wim->hdr.guid, guid, WIMLIB_GUID_LEN);
- else if (!wim->guid_set_explicitly)
- randomize_byte_array(wim->hdr.guid, WIMLIB_GUID_LEN);
+ /* Set GUID. */
+ if (!(write_flags & WIMLIB_WRITE_FLAG_RETAIN_GUID)) {
+ if (guid)
+ memcpy(wim->hdr.guid, guid, WIMLIB_GUID_LEN);
+ else
+ randomize_byte_array(wim->hdr.guid, WIMLIB_GUID_LEN);
+ }
/* Clear references to resources that have not been written yet. */
zero_reshdr(&wim->hdr.lookup_table_reshdr);
int image, int write_flags, unsigned num_threads,
wimlib_progress_func_t progress_func)
{
- if (!path)
+ if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
return WIMLIB_ERR_INVALID_PARAM;
- write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
+ if (path == NULL || path[0] == T('\0'))
+ return WIMLIB_ERR_INVALID_PARAM;
return write_standalone_wim(wim, path, image, write_flags,
num_threads, progress_func);
int image, int write_flags, unsigned num_threads,
wimlib_progress_func_t progress_func)
{
+ if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
+ return WIMLIB_ERR_INVALID_PARAM;
+
if (fd < 0)
return WIMLIB_ERR_INVALID_PARAM;
- write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
write_flags |= WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR;
return write_standalone_wim(wim, &fd, image, write_flags,
* Integrity table (optional) (variable size)
*
* This method allows an image to be appended to a large WIM very quickly, and
- * is is crash-safe except in the case of write re-ordering, but the
+ * is crash-safe except in the case of write re-ordering, but the
* disadvantage is that a small hole is left in the WIM where the old lookup
* table, xml data, and integrity table were. (These usually only take up a
* small amount of space compared to the streams, however.)
tmpfile[wim_name_len + 9] = T('\0');
ret = wimlib_write(wim, tmpfile, WIMLIB_ALL_IMAGES,
- write_flags | WIMLIB_WRITE_FLAG_FSYNC,
+ write_flags |
+ WIMLIB_WRITE_FLAG_FSYNC |
+ WIMLIB_WRITE_FLAG_RETAIN_GUID,
num_threads, progress_func);
if (ret) {
tunlink(tmpfile);
if (wim_is_pipable(wim) || (write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
return false;
- /* wimlib allows multiple packs in a single WIM, but they don't seem to
- * be compatible with WIMGAPI, so force all streams to be repacked if
- * the WIM already may have contained a pack and PACK_STREAMS was
- * requested. */
- if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS &&
- wim->hdr.wim_version == WIM_VERSION_PACKED_STREAMS)
- return false;
-
/* The default compression type and compression chunk size selected for
* the output WIM must be the same as those currently used for the WIM.
*/
int ret;
u32 orig_hdr_flags;
- write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
-
- if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
+ if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
return WIMLIB_ERR_INVALID_PARAM;
if (!wim->filename)