-static int write_wim_resource(struct lookup_table_entry *lte,
- FILE *out_fp, int out_ctype,
- struct resource_entry *out_res_entry)
-{
- u64 bytes_remaining;
- u64 original_size;
- u64 old_compressed_size;
- u64 new_compressed_size;
- u64 offset = 0;
- int ret = 0;
- struct chunk_table *chunk_tab = NULL;
- bool raw;
- off_t file_offset;
-
- original_size = wim_resource_size(lte);
- old_compressed_size = wim_resource_compressed_size(lte);
-
- file_offset = ftello(out_fp);
- if (file_offset == -1) {
- ERROR_WITH_ERRNO("Failed to get offset in output "
- "stream");
- return WIMLIB_ERR_WRITE;
- }
-
- raw = (wim_resource_compression_type(lte) == out_ctype);
- if (raw)
- bytes_remaining = old_compressed_size;
- else
- bytes_remaining = original_size;
-
- if (bytes_remaining == 0)
- return 0;
-
- char buf[min(WIM_CHUNK_SIZE, bytes_remaining)];
-
- if (out_ctype != WIM_COMPRESSION_TYPE_NONE && !raw) {
- ret = begin_wim_resource_chunk_tab(lte, out_fp, file_offset,
- &chunk_tab);
- if (ret != 0)
- goto out;
- }
- if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK
- && !lte->file_on_disk_fp)
- {
- wimlib_assert(lte->file_on_disk);
- lte->file_on_disk_fp = fopen(lte->file_on_disk, "rb");
- if (!lte->file_on_disk_fp) {
- ERROR_WITH_ERRNO("Failed to open the file `%s' for "
- "reading", lte->file_on_disk);
- ret = WIMLIB_ERR_OPEN;
- goto out;
- }
- }
-
- do {
- u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE);
- ret = __read_wim_resource(lte, buf, to_read, offset, raw);
- if (ret != 0)
- goto out_fclose;
- ret = write_wim_resource_chunk(buf, to_read, out_fp,
- out_ctype, chunk_tab);
- if (ret != 0)
- goto out_fclose;
- bytes_remaining -= to_read;
- offset += to_read;
- } while (bytes_remaining);
- if (out_ctype != WIM_COMPRESSION_TYPE_NONE && !raw) {
- ret = finish_wim_resource_chunk_tab(chunk_tab, out_fp,
- &new_compressed_size);
- if (ret != 0)
- goto out_fclose;
- } else {
- new_compressed_size = old_compressed_size;
- }
-
- if (new_compressed_size > original_size) {
- /* Oops! We compressed the resource to larger than the original
- * size. Write the resource uncompressed instead. */
- if (fseeko(out_fp, file_offset, SEEK_SET) != 0) {
- ERROR_WITH_ERRNO("Failed to seek to byte "PRIu64" "
- "of output WIM file", file_offset);
- ret = WIMLIB_ERR_WRITE;
- goto out_fclose;
- }
- ret = write_wim_resource(lte, out_fp, WIM_COMPRESSION_TYPE_NONE,
- out_res_entry);
- if (ret != 0)
- goto out_fclose;
- if (fflush(out_fp) != 0) {
- ERROR_WITH_ERRNO("Failed to flush output WIM file");
- ret = WIMLIB_ERR_WRITE;
- goto out_fclose;
- }
- if (ftruncate(fileno(out_fp), file_offset + out_res_entry->size) != 0) {
- ERROR_WITH_ERRNO("Failed to truncate output WIM file");
- ret = WIMLIB_ERR_WRITE;
- }
- goto out_fclose;
- }
- wimlib_assert(new_compressed_size <= original_size);
- if (out_res_entry) {
- out_res_entry->size = new_compressed_size;
- out_res_entry->original_size = original_size;
- out_res_entry->offset = file_offset;
- if (out_ctype == WIM_COMPRESSION_TYPE_NONE)
- out_res_entry->flags = 0;
- else
- out_res_entry->flags = WIM_RESHDR_FLAG_COMPRESSED;
- }
-out_fclose:
- if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK
- && lte->file_on_disk_fp) {
- fclose(lte->file_on_disk_fp);
- lte->file_on_disk_fp = NULL;
- }
-out:
- FREE(chunk_tab);
- return ret;
-}
-
-static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
- FILE *out_fp, int out_ctype,
- struct resource_entry *out_res_entry)
-{
- struct lookup_table_entry lte;
- lte.resource_entry.flags = 0;
- lte.resource_entry.original_size = buf_size;
- lte.resource_entry.size = buf_size;
- lte.resource_entry.offset = 0;
- lte.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
- lte.attached_buffer = (u8*)buf;
- return write_wim_resource(<e, out_fp, out_ctype, out_res_entry);
-}
-
-/*
- * Extracts the first @size bytes of the resource specified by @lte to the open
- * file @fd. Returns nonzero on error.
- */