- struct write_resource_ctx *ctx = _ctx;
- const void *out_chunk;
- unsigned out_chunk_size;
- int ret;
- void *compressed_chunk = NULL;
- unsigned compressed_size;
- bool compressed_chunk_malloced = false;
- size_t stack_max = 32768;
-
- if (ctx->doing_sha)
- sha1_update(&ctx->sha_ctx, chunk, chunk_size);
-
- out_chunk = chunk;
- out_chunk_size = chunk_size;
- if (ctx->out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
-
- /* Compress the chunk. */
- if (chunk_size <= stack_max) {
- compressed_chunk = alloca(chunk_size);
- } else {
- compressed_chunk = MALLOC(chunk_size);
- if (compressed_chunk == NULL)
- return WIMLIB_ERR_NOMEM;
- compressed_chunk_malloced = true;
- }
-
- compressed_size = compress_chunk(chunk, chunk_size,
- compressed_chunk,
- ctx->out_ctype,
- ctx->comp_ctx);
- /* Use compressed data if compression to less than input size
- * was successful. */
- if (compressed_size) {
- out_chunk = compressed_chunk;
- out_chunk_size = compressed_size;
- }
- }
-
- if (ctx->chunk_tab) {
- /* Update chunk table accounting. */
- chunk_tab_record_chunk(ctx->chunk_tab, out_chunk_size);
-
- /* If writing compressed chunks to a pipable WIM, before the
- * chunk data write a chunk header that provides the compressed
- * chunk size. */
- if (ctx->resource_flags & WIMLIB_WRITE_RESOURCE_FLAG_PIPABLE) {
- struct pwm_chunk_hdr chunk_hdr = {
- .compressed_size = cpu_to_le32(out_chunk_size),
- };
- ret = full_write(ctx->out_fd, &chunk_hdr,
- sizeof(chunk_hdr));
- if (ret)
- goto error;
- }
- }
-
- /* Write the chunk data. */
- ret = full_write(ctx->out_fd, out_chunk, out_chunk_size);
- if (ret)
- goto error;
-
-out_free_memory:
- if (compressed_chunk_malloced)
- FREE(compressed_chunk);
- return ret;
-
-error:
- ERROR_WITH_ERRNO("Failed to write WIM resource chunk");
- goto out_free_memory;
-}
-
-/*
- * write_wim_resource()-
- *
- * Write a resource to an output WIM.
- *
- * @lte:
- * Lookup table entry for the resource, which could be in another WIM, in
- * an external file, or in another location.
- *
- * @out_fd:
- * File descriptor opened to the output WIM.
- *
- * @out_ctype:
- * One of the WIMLIB_COMPRESSION_TYPE_* constants to indicate which
- * compression algorithm to use.
- *
- * @out_chunk_size:
- * Compressed chunk size to use.
- *
- * @out_res_entry:
- * On success, this is filled in with the offset, flags, compressed size,
- * and uncompressed size of the resource in the output WIM.
- *
- * @resource_flags:
- * * WIMLIB_WRITE_RESOURCE_FLAG_RECOMPRESS to force data to be recompressed even
- * if it could otherwise be copied directly from the input;
- * * WIMLIB_WRITE_RESOURCE_FLAG_PIPABLE if writing a resource for a pipable WIM
- * (and the output file descriptor may be a pipe).
- *
- * @comp_ctx:
- * Location of LZX compression context pointer, which will be allocated or
- * updated if needed. (Initialize to NULL.)
- *
- * Additional notes: The SHA1 message digest of the uncompressed data is
- * calculated (except when doing a raw copy --- see below). If the @unhashed
- * flag is set on the lookup table entry, this message digest is simply copied
- * to it; otherwise, the message digest is compared with the existing one, and
- * this function will fail if they do not match.
- */
-static int
-write_wim_resource(struct wim_lookup_table_entry *lte,
- struct filedes *out_fd, int out_ctype,
- u32 out_chunk_size,
- struct resource_entry *out_res_entry,
- int resource_flags,
- struct wimlib_lzx_context **comp_ctx)
-{
- struct write_resource_ctx write_ctx;
- off_t res_start_offset;
- u32 in_chunk_size;
- u64 read_size;
- int ret;
-
- /* Mask out any irrelevant flags, since this function also uses this
- * variable to store WIMLIB_READ_RESOURCE flags. */
- resource_flags &= WIMLIB_WRITE_RESOURCE_MASK;
-
- /* Get current position in output WIM. */
- res_start_offset = out_fd->offset;
-
- /* If we are not forcing the data to be recompressed, and the input
- * resource is located in a WIM with a compression mode compatible with
- * the output, we can simply copy the compressed data without
- * recompressing it. This also means we must skip calculating the SHA1,
- * as we never will see the uncompressed data. */
- if (can_raw_copy(lte, resource_flags, out_ctype, out_chunk_size)) {
- /* Normally, for raw copies we can request a RAW_FULL read, but
- * if we're reading from a pipable resource and writing a
- * non-pipable resource or vice versa, then a RAW_CHUNKS read
- * needs to be requested so that the written resource can be
- * appropriately formatted. However, in neither case is any
- * actual decompression needed. */
- if (lte->is_pipable == !!(resource_flags &
- WIMLIB_WRITE_RESOURCE_FLAG_PIPABLE))
- {
- resource_flags |= WIMLIB_READ_RESOURCE_FLAG_RAW_FULL;
- read_size = lte->resource_entry.size;
- } else {
- resource_flags |= WIMLIB_READ_RESOURCE_FLAG_RAW_CHUNKS;
- read_size = lte->resource_entry.original_size;
- }
- write_ctx.doing_sha = false;
- } else {
- write_ctx.doing_sha = true;
- sha1_init(&write_ctx.sha_ctx);
- read_size = lte->resource_entry.original_size;
- }
-
- /* Set the output compression mode and initialize chunk table if needed.
- */
- write_ctx.out_ctype = WIMLIB_COMPRESSION_TYPE_NONE;
- write_ctx.out_chunk_size = out_chunk_size;
- write_ctx.chunk_tab = NULL;
- if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
- wimlib_assert(out_chunk_size > 0);
- if (!(resource_flags & WIMLIB_READ_RESOURCE_FLAG_RAW)) {
- /* Compression needed. */
- write_ctx.out_ctype = out_ctype;
- if (out_ctype == WIMLIB_COMPRESSION_TYPE_LZX) {
- ret = wimlib_lzx_alloc_context(out_chunk_size,
- NULL, comp_ctx);
- if (ret)
- goto out;
- }
- write_ctx.comp_ctx = *comp_ctx;
- }
- if (!(resource_flags & WIMLIB_READ_RESOURCE_FLAG_RAW_FULL)) {
- /* Chunk table needed. */
- ret = begin_wim_resource_chunk_tab(lte, out_fd,
- out_chunk_size,
- &write_ctx.chunk_tab,
- resource_flags);
- if (ret)
- goto out;
- }
- }
-
- /* If writing a pipable resource, write the stream header and update
- * @res_start_offset to be the end of the stream header. */
- if (resource_flags & WIMLIB_WRITE_RESOURCE_FLAG_PIPABLE) {
- int reshdr_flags = 0;
- if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE)
- reshdr_flags |= WIM_RESHDR_FLAG_COMPRESSED;
- ret = write_pwm_stream_header(lte, out_fd, reshdr_flags);
- if (ret)
- goto out_free_chunk_tab;
- res_start_offset = out_fd->offset;
- }