X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fresource.c;h=a49507f3778df55b652b54df4c0e00b5e480cf3a;hp=116873ffc16b68d9be4c590631a4f2167964722a;hb=3abe6501c7ebb20a0ead1cd69ebd93cbe6b917e1;hpb=b6034a5dd44709341c46d553b1c0294ec91f13e4 diff --git a/src/resource.c b/src/resource.c index 116873ff..a49507f3 100644 --- a/src/resource.c +++ b/src/resource.c @@ -1,56 +1,55 @@ /* * resource.c * - * Code for reading streams and resources, including compressed WIM resources. + * Code for reading blobs and resources, including compressed WIM resources. */ /* - * Copyright (C) 2012, 2013 Eric Biggers + * Copyright (C) 2012, 2013, 2015 Eric Biggers * - * This file is part of wimlib, a library for working with WIM files. + * 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 + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation; either version 3 of the License, or (at your option) any later - * version. + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * wimlib; if not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "wimlib.h" +#include +#include +#include + +#include "wimlib/alloca.h" +#include "wimlib/assert.h" +#include "wimlib/bitops.h" +#include "wimlib/blob_table.h" #include "wimlib/endianness.h" #include "wimlib/error.h" #include "wimlib/file_io.h" -#include "wimlib/lookup_table.h" #include "wimlib/resource.h" #include "wimlib/sha1.h" +#include "wimlib/wim.h" #ifdef __WIN32__ -/* for read_win32_file_prefix(), read_win32_encrypted_file_prefix() */ +/* for read_winnt_stream_prefix(), read_win32_encrypted_file_prefix() */ # include "wimlib/win32.h" #endif #ifdef WITH_NTFS_3G -/* for read_ntfs_file_prefix() */ +/* for read_ntfs_attribute_prefix() */ # include "wimlib/ntfs_3g.h" #endif -#ifdef HAVE_ALLOCA_H -# include -#endif -#include -#include -#include -#include /* * Compressed WIM resources @@ -72,7 +71,7 @@ * little-endian integers. * * - The chunk table is included in the compressed size of the resource provided - * in the corresponding entry in the WIM's stream lookup table. + * in the corresponding entry in the WIM's blob table. * * - The compressed size of a chunk is never greater than the uncompressed size. * From the compressor's point of view, chunks that would have compressed to a @@ -100,8 +99,8 @@ struct data_range { * * Read data from a compressed WIM resource. * - * @rspec - * Specification of the compressed WIM resource to read from. + * @rdesc + * Description of the compressed WIM resource to read from. * @ranges * Nonoverlapping, nonempty ranges of the uncompressed resource data to * read, sorted by increasing offset. @@ -126,7 +125,7 @@ struct data_range { * or other error code returned by the @cb function. */ static int -read_compressed_wim_resource(const struct wim_resource_spec * const rspec, +read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc, const struct data_range * const ranges, const size_t num_ranges, const consume_data_callback_t cb, @@ -144,17 +143,17 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, struct wimlib_decompressor *decompressor = NULL; /* Sanity checks */ - wimlib_assert(rspec != NULL); - wimlib_assert(resource_is_compressed(rspec)); + wimlib_assert(rdesc != NULL); + wimlib_assert(resource_is_compressed(rdesc)); wimlib_assert(cb != NULL); wimlib_assert(num_ranges != 0); for (size_t i = 0; i < num_ranges; i++) { DEBUG("Range %zu/%zu: %"PRIu64"@+%"PRIu64" / %"PRIu64, i + 1, num_ranges, ranges[i].size, ranges[i].offset, - rspec->uncompressed_size); + rdesc->uncompressed_size); wimlib_assert(ranges[i].size != 0); wimlib_assert(ranges[i].offset + ranges[i].size >= ranges[i].size); - wimlib_assert(ranges[i].offset + ranges[i].size <= rspec->uncompressed_size); + wimlib_assert(ranges[i].offset + ranges[i].size <= rdesc->uncompressed_size); } for (size_t i = 0; i < num_ranges - 1; i++) wimlib_assert(ranges[i].offset + ranges[i].size <= ranges[i + 1].offset); @@ -164,25 +163,25 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, const u64 last_offset = ranges[num_ranges - 1].offset + ranges[num_ranges - 1].size - 1; /* Get the file descriptor for the WIM. */ - struct filedes * const in_fd = &rspec->wim->in_fd; + struct filedes * const in_fd = &rdesc->wim->in_fd; /* Determine if we're reading a pipable resource from a pipe or not. */ - const bool is_pipe_read = !filedes_is_seekable(in_fd); + const bool is_pipe_read = (rdesc->is_pipable && !filedes_is_seekable(in_fd)); - /* Determine if the chunk table is in an altenate format. */ - const bool alt_chunk_table = (rspec->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) + /* Determine if the chunk table is in an alternate format. */ + const bool alt_chunk_table = (rdesc->flags & WIM_RESHDR_FLAG_SOLID) && !is_pipe_read; /* Get the maximum size of uncompressed chunks in this resource, which * we require be a power of 2. */ - u64 cur_read_offset = rspec->offset_in_wim; - int ctype = rspec->compression_type; - u32 chunk_size = rspec->chunk_size; + u64 cur_read_offset = rdesc->offset_in_wim; + int ctype = rdesc->compression_type; + u32 chunk_size = rdesc->chunk_size; if (alt_chunk_table) { /* Alternate chunk table format. Its header specifies the chunk * size and compression format. Note: it could be read here; - * however, the relevant data was already loaded into @rspec by - * read_wim_lookup_table(). */ + * however, the relevant data was already loaded into @rdesc by + * read_blob_table(). */ cur_read_offset += sizeof(struct alt_chunk_table_header_disk); } @@ -191,28 +190,32 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, "expected power-of-2 chunk size (got %"PRIu32")", chunk_size); ret = WIMLIB_ERR_INVALID_CHUNK_SIZE; + errno = EINVAL; goto out_free_memory; } /* Get valid decompressor. */ - if (ctype == rspec->wim->decompressor_ctype && - chunk_size == rspec->wim->decompressor_max_block_size) + if (ctype == rdesc->wim->decompressor_ctype && + chunk_size == rdesc->wim->decompressor_max_block_size) { /* Cached decompressor. */ - decompressor = rspec->wim->decompressor; - rspec->wim->decompressor_ctype = WIMLIB_COMPRESSION_TYPE_NONE; - rspec->wim->decompressor = NULL; + decompressor = rdesc->wim->decompressor; + rdesc->wim->decompressor_ctype = WIMLIB_COMPRESSION_TYPE_NONE; + rdesc->wim->decompressor = NULL; } else { - ret = wimlib_create_decompressor(ctype, chunk_size, NULL, + ret = wimlib_create_decompressor(ctype, chunk_size, &decompressor); - if (ret) + if (ret) { + if (ret != WIMLIB_ERR_NOMEM) + errno = EINVAL; goto out_free_memory; + } } - const u32 chunk_order = bsr32(chunk_size); + const u32 chunk_order = fls32(chunk_size); /* Calculate the total number of chunks the resource is divided into. */ - const u64 num_chunks = (rspec->uncompressed_size + chunk_size - 1) >> chunk_order; + const u64 num_chunks = (rdesc->uncompressed_size + chunk_size - 1) >> chunk_order; /* Calculate the 0-based indices of the first and last chunks containing * data that needs to be passed to the callback. */ @@ -238,7 +241,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, /* Set the size of each chunk table entry based on the resource's * uncompressed size. */ - const u64 chunk_entry_size = get_chunk_entry_size(rspec->uncompressed_size, + const u64 chunk_entry_size = get_chunk_entry_size(rdesc->uncompressed_size, alt_chunk_table); /* Calculate the size of the chunk table in bytes. */ @@ -306,7 +309,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, const u64 file_offset_of_needed_chunk_entries = cur_read_offset + (first_chunk_entry_to_read * chunk_entry_size) - + (rspec->is_pipable ? (rspec->size_in_wim - chunk_table_size) : 0); + + (rdesc->is_pipable ? (rdesc->size_in_wim - chunk_table_size) : 0); void * const chunk_table_data = (u8*)chunk_offsets + @@ -321,8 +324,8 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, /* Now fill in chunk_offsets from the entries we have read in * chunk_tab_data. We break aliasing rules here to avoid having * to allocate yet another array. */ - typedef le64 __attribute__((may_alias)) aliased_le64_t; - typedef le32 __attribute__((may_alias)) aliased_le32_t; + typedef le64 _may_alias_attribute aliased_le64_t; + typedef le32 _may_alias_attribute aliased_le32_t; u64 * chunk_offsets_p = chunk_offsets; if (alt_chunk_table) { @@ -354,7 +357,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, /* Set offset to beginning of first chunk to read. */ cur_read_offset += chunk_offsets[0]; - if (rspec->is_pipable) + if (rdesc->is_pipable) cur_read_offset += read_start_chunk * sizeof(struct pwm_chunk_hdr); else cur_read_offset += chunk_table_size; @@ -394,8 +397,8 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, /* Calculate uncompressed size of next chunk. */ u32 chunk_usize; - if ((i == num_chunks - 1) && (rspec->uncompressed_size & (chunk_size - 1))) - chunk_usize = (rspec->uncompressed_size & (chunk_size - 1)); + if ((i == num_chunks - 1) && (rdesc->uncompressed_size & (chunk_size - 1))) + chunk_usize = (rdesc->uncompressed_size & (chunk_size - 1)); else chunk_usize = chunk_size; @@ -411,10 +414,10 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, chunk_csize = le32_to_cpu(chunk_hdr.compressed_size); } else { if (i == num_chunks - 1) { - chunk_csize = rspec->size_in_wim - + chunk_csize = rdesc->size_in_wim - chunk_table_full_size - chunk_offsets[i - read_start_chunk]; - if (rspec->is_pipable) + if (rdesc->is_pipable) chunk_csize -= num_chunks * sizeof(struct pwm_chunk_hdr); } else { chunk_csize = chunk_offsets[i + 1 - read_start_chunk] - @@ -427,7 +430,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, ret = WIMLIB_ERR_DECOMPRESSION; goto out_free_memory; } - if (rspec->is_pipable) + if (rdesc->is_pipable) cur_read_offset += sizeof(struct pwm_chunk_hdr); /* Offsets in the uncompressed resource at which this chunk @@ -516,7 +519,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, } if (is_pipe_read && - last_offset == rspec->uncompressed_size - 1 && + last_offset == rdesc->uncompressed_size - 1 && chunk_table_size) { u8 dummy; @@ -534,10 +537,10 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, out_free_memory: errno_save = errno; if (decompressor) { - wimlib_free_decompressor(rspec->wim->decompressor); - rspec->wim->decompressor = decompressor; - rspec->wim->decompressor_ctype = ctype; - rspec->wim->decompressor_max_block_size = chunk_size; + wimlib_free_decompressor(rdesc->wim->decompressor); + rdesc->wim->decompressor = decompressor; + rdesc->wim->decompressor_ctype = ctype; + rdesc->wim->decompressor_max_block_size = chunk_size; } if (chunk_offsets_malloced) FREE(chunk_offsets); @@ -560,6 +563,28 @@ read_error: goto out_free_memory; } +static int +fill_zeroes(u64 size, consume_data_callback_t cb, void *cb_ctx) +{ + if (unlikely(size)) { + u8 buf[min(size, BUFFER_SIZE)]; + + memset(buf, 0, sizeof(buf)); + + do { + size_t len; + int ret; + + len = min(size, BUFFER_SIZE); + ret = cb(buf, len, cb_ctx); + if (ret) + return ret; + size -= len; + } while (size); + } + return 0; +} + /* Read raw data from a file descriptor at the specified offset, feeding the * data it in chunks into the specified callback function. */ static int @@ -603,8 +628,8 @@ bufferer_cb(const void *chunk, size_t size, void *_ctx) * Read a range of data from an uncompressed or compressed resource in a WIM * file. * - * @rspec - * Specification of the WIM resource to read from. + * @rdesc + * Description of the WIM resource to read from. * @offset * Offset within the uncompressed resource at which to start reading. * @size @@ -627,51 +652,77 @@ bufferer_cb(const void *chunk, size_t size, void *_ctx) * or other error code returned by the @cb function. */ static int -read_partial_wim_resource(const struct wim_resource_spec *rspec, +read_partial_wim_resource(const struct wim_resource_descriptor *rdesc, u64 offset, u64 size, consume_data_callback_t cb, void *cb_ctx) { /* Sanity checks. */ wimlib_assert(offset + size >= offset); - wimlib_assert(offset + size <= rspec->uncompressed_size); + wimlib_assert(offset + size <= rdesc->uncompressed_size); DEBUG("Reading %"PRIu64" @ %"PRIu64" from WIM resource " "%"PRIu64" => %"PRIu64" @ %"PRIu64, - size, offset, rspec->uncompressed_size, - rspec->size_in_wim, rspec->offset_in_wim); + size, offset, rdesc->uncompressed_size, + rdesc->size_in_wim, rdesc->offset_in_wim); /* Trivial case. */ if (size == 0) return 0; - if (resource_is_compressed(rspec)) { + if (resource_is_compressed(rdesc)) { struct data_range range = { .offset = offset, .size = size, }; - return read_compressed_wim_resource(rspec, &range, 1, + return read_compressed_wim_resource(rdesc, &range, 1, cb, cb_ctx); } else { - return read_raw_file_data(&rspec->wim->in_fd, - rspec->offset_in_wim + offset, - size, - cb, - cb_ctx); + /* Reading uncompressed resource. For completeness, handle the + * weird case where size_in_wim < uncompressed_size. */ + + u64 read_size; + u64 zeroes_size; + int ret; + + if (likely(offset + size <= rdesc->size_in_wim) || + rdesc->is_pipable) + { + read_size = size; + zeroes_size = 0; + } else { + if (offset >= rdesc->size_in_wim) { + read_size = 0; + zeroes_size = size; + } else { + read_size = rdesc->size_in_wim - offset; + zeroes_size = offset + size - rdesc->size_in_wim; + } + } + + ret = read_raw_file_data(&rdesc->wim->in_fd, + rdesc->offset_in_wim + offset, + read_size, + cb, + cb_ctx); + if (ret) + return ret; + + return fill_zeroes(zeroes_size, cb, cb_ctx); } } -/* Read the specified range of uncompressed data from the specified stream, - * which must be located into a WIM file, into the specified buffer. */ +/* Read the specified range of uncompressed data from the specified blob, which + * must be located into a WIM file, into the specified buffer. */ int -read_partial_wim_stream_into_buf(const struct wim_lookup_table_entry *lte, - size_t size, u64 offset, void *_buf) +read_partial_wim_blob_into_buf(const struct blob_descriptor *blob, + size_t size, u64 offset, void *_buf) { u8 *buf = _buf; - wimlib_assert(lte->resource_location == RESOURCE_IN_WIM); + wimlib_assert(blob->blob_location == BLOB_IN_WIM); - return read_partial_wim_resource(lte->rspec, - lte->offset_in_res + offset, + return read_partial_wim_resource(blob->rdesc, + blob->offset_in_res + offset, size, bufferer_cb, &buf); @@ -685,53 +736,46 @@ skip_chunk_cb(const void *chunk, size_t size, void *_ctx) return 0; } -/* Skip over the data of the specified stream, which must correspond to a full - * WIM resource. */ +/* Skip over the data of the specified WIM resource. */ int -skip_wim_stream(struct wim_lookup_table_entry *lte) +skip_wim_resource(struct wim_resource_descriptor *rdesc) { - wimlib_assert(lte->resource_location == RESOURCE_IN_WIM); - wimlib_assert(!(lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS)); - DEBUG("Skipping stream (size=%"PRIu64")", lte->size); - return read_partial_wim_resource(lte->rspec, - 0, - lte->rspec->uncompressed_size, - skip_chunk_cb, - NULL); + DEBUG("Skipping resource (size=%"PRIu64")", rdesc->uncompressed_size); + return read_partial_wim_resource(rdesc, 0, rdesc->uncompressed_size, + skip_chunk_cb, NULL); } static int -read_wim_stream_prefix(const struct wim_lookup_table_entry *lte, u64 size, - consume_data_callback_t cb, void *cb_ctx) +read_wim_blob_prefix(const struct blob_descriptor *blob, u64 size, + consume_data_callback_t cb, void *cb_ctx) { - return read_partial_wim_resource(lte->rspec, lte->offset_in_res, size, + return read_partial_wim_resource(blob->rdesc, blob->offset_in_res, size, cb, cb_ctx); } -#ifndef __WIN32__ -/* This function handles reading stream data that is located in an external - * file, such as a file that has been added to the WIM image through execution - * of a wimlib_add_command. +/* This function handles reading blob data that is located in an external file, + * such as a file that has been added to the WIM image through execution of a + * wimlib_add_command. * * This assumes the file can be accessed using the standard POSIX open(), * read(), and close(). On Windows this will not necessarily be the case (since * the file may need FILE_FLAG_BACKUP_SEMANTICS to be opened, or the file may be * encrypted), so Windows uses its own code for its equivalent case. */ static int -read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte, u64 size, +read_file_on_disk_prefix(const struct blob_descriptor *blob, u64 size, consume_data_callback_t cb, void *cb_ctx) { int ret; int raw_fd; struct filedes fd; - wimlib_assert(size <= lte->size); + wimlib_assert(size <= blob->size); - DEBUG("Reading %"PRIu64" bytes from \"%"TS"\"", size, lte->file_on_disk); + DEBUG("Reading %"PRIu64" bytes from \"%"TS"\"", size, blob->file_on_disk); - raw_fd = open(lte->file_on_disk, O_BINARY | O_RDONLY); + raw_fd = topen(blob->file_on_disk, O_BINARY | O_RDONLY); if (raw_fd < 0) { - ERROR_WITH_ERRNO("Can't open \"%"TS"\"", lte->file_on_disk); + ERROR_WITH_ERRNO("Can't open \"%"TS"\"", blob->file_on_disk); return WIMLIB_ERR_OPEN; } filedes_init(&fd, raw_fd); @@ -739,27 +783,54 @@ read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte, u64 size, filedes_close(&fd); return ret; } -#endif /* !__WIN32__ */ -/* This function handles the trivial case of reading stream data that is, in - * fact, already located in an in-memory buffer. */ +#ifdef WITH_FUSE static int -read_buffer_prefix(const struct wim_lookup_table_entry *lte, +read_staging_file_prefix(const struct blob_descriptor *blob, u64 size, + consume_data_callback_t cb, void *cb_ctx) +{ + int raw_fd; + struct filedes fd; + int ret; + + wimlib_assert(size <= blob->size); + + DEBUG("Reading %"PRIu64" bytes from staging file \"%s\"", + size, blob->staging_file_name); + + raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name, + O_RDONLY | O_NOFOLLOW); + if (raw_fd < 0) { + ERROR_WITH_ERRNO("Can't open staging file \"%s\"", + blob->staging_file_name); + return WIMLIB_ERR_OPEN; + } + filedes_init(&fd, raw_fd); + ret = read_raw_file_data(&fd, 0, size, cb, cb_ctx); + filedes_close(&fd); + return ret; +} +#endif + +/* This function handles the trivial case of reading blob data that is, in fact, + * already located in an in-memory buffer. */ +static int +read_buffer_prefix(const struct blob_descriptor *blob, u64 size, consume_data_callback_t cb, void *cb_ctx) { - wimlib_assert(size <= lte->size); - return (*cb)(lte->attached_buffer, size, cb_ctx); + wimlib_assert(size <= blob->size); + return (*cb)(blob->attached_buffer, size, cb_ctx); } -typedef int (*read_stream_prefix_handler_t)(const struct wim_lookup_table_entry *lte, - u64 size, - consume_data_callback_t cb, - void *cb_ctx); +typedef int (*read_blob_prefix_handler_t)(const struct blob_descriptor *blob, + u64 size, + consume_data_callback_t cb, + void *cb_ctx); /* - * read_stream_prefix()- + * read_blob_prefix()- * - * Reads the first @size bytes from a generic "stream", which may be located in + * Reads the first @size bytes from a generic "blob", which may be located in * any one of several locations, such as in a WIM file (compressed or * uncompressed), in an external file, or directly in an in-memory buffer. * @@ -767,66 +838,61 @@ typedef int (*read_stream_prefix_handler_t)(const struct wim_lookup_table_entry * unspecified size. * * Returns 0 on success; nonzero on error. A nonzero value will be returned if - * the stream data cannot be successfully read (for a number of different - * reasons, depending on the stream location), or if @cb returned nonzero in - * which case that error code will be returned. + * the blob data cannot be successfully read (for a number of different reasons, + * depending on the blob location), or if @cb returned nonzero in which case + * that error code will be returned. */ static int -read_stream_prefix(const struct wim_lookup_table_entry *lte, u64 size, - consume_data_callback_t cb, void *cb_ctx) +read_blob_prefix(const struct blob_descriptor *blob, u64 size, + consume_data_callback_t cb, void *cb_ctx) { - static const read_stream_prefix_handler_t handlers[] = { - [RESOURCE_IN_WIM] = read_wim_stream_prefix, - #ifdef __WIN32__ - [RESOURCE_IN_FILE_ON_DISK] = read_win32_file_prefix, - #else - [RESOURCE_IN_FILE_ON_DISK] = read_file_on_disk_prefix, - #endif - [RESOURCE_IN_ATTACHED_BUFFER] = read_buffer_prefix, + static const read_blob_prefix_handler_t handlers[] = { + [BLOB_IN_WIM] = read_wim_blob_prefix, + [BLOB_IN_FILE_ON_DISK] = read_file_on_disk_prefix, + [BLOB_IN_ATTACHED_BUFFER] = read_buffer_prefix, #ifdef WITH_FUSE - [RESOURCE_IN_STAGING_FILE] = read_file_on_disk_prefix, + [BLOB_IN_STAGING_FILE] = read_staging_file_prefix, #endif #ifdef WITH_NTFS_3G - [RESOURCE_IN_NTFS_VOLUME] = read_ntfs_file_prefix, + [BLOB_IN_NTFS_VOLUME] = read_ntfs_attribute_prefix, #endif #ifdef __WIN32__ - [RESOURCE_WIN32_ENCRYPTED] = read_win32_encrypted_file_prefix, + [BLOB_IN_WINNT_FILE_ON_DISK] = read_winnt_stream_prefix, + [BLOB_WIN32_ENCRYPTED] = read_win32_encrypted_file_prefix, #endif }; - wimlib_assert(lte->resource_location < ARRAY_LEN(handlers) - && handlers[lte->resource_location] != NULL); - return handlers[lte->resource_location](lte, size, cb, cb_ctx); + wimlib_assert(blob->blob_location < ARRAY_LEN(handlers) + && handlers[blob->blob_location] != NULL); + return handlers[blob->blob_location](blob, size, cb, cb_ctx); } -/* Read the full uncompressed data of the specified stream into the specified - * buffer, which must have space for at least lte->size bytes. */ +/* Read the full uncompressed data of the specified blob into the specified + * buffer, which must have space for at least blob->size bytes. */ int -read_full_stream_into_buf(const struct wim_lookup_table_entry *lte, void *_buf) +read_full_blob_into_buf(const struct blob_descriptor *blob, void *_buf) { u8 *buf = _buf; - return read_stream_prefix(lte, lte->size, bufferer_cb, &buf); + return read_blob_prefix(blob, blob->size, bufferer_cb, &buf); } -/* Retrieve the full uncompressed data of the specified stream. A buffer large +/* Retrieve the full uncompressed data of the specified blob. A buffer large * enough hold the data is allocated and returned in @buf_ret. */ int -read_full_stream_into_alloc_buf(const struct wim_lookup_table_entry *lte, - void **buf_ret) +read_full_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret) { int ret; void *buf; - if ((size_t)lte->size != lte->size) { - ERROR("Can't read %"PRIu64" byte stream into " - "memory", lte->size); + if ((size_t)blob->size != blob->size) { + ERROR("Can't read %"PRIu64" byte blob into memory", blob->size); return WIMLIB_ERR_NOMEM; } - buf = MALLOC(lte->size); + buf = MALLOC(blob->size); if (buf == NULL) return WIMLIB_ERR_NOMEM; - ret = read_full_stream_into_buf(lte, buf); + ret = read_full_blob_into_buf(blob, buf); if (ret) { FREE(buf); return ret; @@ -836,85 +902,80 @@ read_full_stream_into_alloc_buf(const struct wim_lookup_table_entry *lte, return 0; } -/* Retrieve the full uncompressed data of the specified WIM resource. A buffer - * large enough hold the data is allocated and returned in @buf_ret. */ -static int -wim_resource_spec_to_data(struct wim_resource_spec *rspec, void **buf_ret) +/* Retrieve the full uncompressed data of a WIM resource specified as a raw + * `wim_reshdr' and the corresponding WIM file. A buffer large enough hold the + * data is allocated and returned in @buf_ret. */ +int +wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_ret) { - int ret; - struct wim_lookup_table_entry *lte; - - lte = new_lookup_table_entry(); - if (lte == NULL) - return WIMLIB_ERR_NOMEM; + struct wim_resource_descriptor rdesc; + struct blob_descriptor blob; - lte_bind_wim_resource_spec(lte, rspec); - lte->flags = rspec->flags; - lte->size = rspec->uncompressed_size; - lte->offset_in_res = 0; + wim_res_hdr_to_desc(reshdr, wim, &rdesc); + blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc); - ret = read_full_stream_into_alloc_buf(lte, buf_ret); - - lte_unbind_wim_resource_spec(lte); - free_lookup_table_entry(lte); - return ret; + return read_full_blob_into_alloc_buf(&blob, buf_ret); } -/* Retrieve the full uncompressed data of a WIM resource specified as a raw - * `wim_reshdr' and the corresponding WIM file. A large enough hold the data is - * allocated and returned in @buf_ret. */ int -wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_ret) +wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim, + u8 hash[SHA1_HASH_SIZE]) { - DEBUG("offset_in_wim=%"PRIu64", size_in_wim=%"PRIu64", " - "uncompressed_size=%"PRIu64, - reshdr->offset_in_wim, reshdr->size_in_wim, - reshdr->uncompressed_size); - - struct wim_resource_spec rspec; - wim_res_hdr_to_spec(reshdr, wim, &rspec); - return wim_resource_spec_to_data(&rspec, buf_ret); + struct wim_resource_descriptor rdesc; + struct blob_descriptor blob; + int ret; + + wim_res_hdr_to_desc(reshdr, wim, &rdesc); + blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc); + blob.unhashed = 1; + + ret = sha1_blob(&blob); + if (ret) + return ret; + copy_hash(hash, blob.hash); + return 0; } -struct streamifier_context { - struct read_stream_list_callbacks cbs; - struct wim_lookup_table_entry *cur_stream; - struct wim_lookup_table_entry *next_stream; - u64 cur_stream_offset; - struct wim_lookup_table_entry *final_stream; +struct blobifier_context { + struct read_blob_list_callbacks cbs; + struct blob_descriptor *cur_blob; + struct blob_descriptor *next_blob; + u64 cur_blob_offset; + struct blob_descriptor *final_blob; size_t list_head_offset; }; -static struct wim_lookup_table_entry * -next_stream(struct wim_lookup_table_entry *lte, size_t list_head_offset) +static struct blob_descriptor * +next_blob(struct blob_descriptor *blob, size_t list_head_offset) { struct list_head *cur; - cur = (struct list_head*)((u8*)lte + list_head_offset); + cur = (struct list_head*)((u8*)blob + list_head_offset); - return (struct wim_lookup_table_entry*)((u8*)cur->next - list_head_offset); + return (struct blob_descriptor*)((u8*)cur->next - list_head_offset); } /* A consume_data_callback_t implementation that translates raw resource data - * into streams, calling the begin_stream, consume_chunk, and end_stream - * callback functions as appropriate. */ + * into blobs, calling the begin_blob, consume_chunk, and end_blob callback + * functions as appropriate. */ static int -streamifier_cb(const void *chunk, size_t size, void *_ctx) +blobifier_cb(const void *chunk, size_t size, void *_ctx) { - struct streamifier_context *ctx = _ctx; + struct blobifier_context *ctx = _ctx; int ret; - DEBUG("%zu bytes passed to streamifier", size); + DEBUG("%zu bytes passed to blobifier", size); - wimlib_assert(ctx->cur_stream != NULL); - wimlib_assert(size <= ctx->cur_stream->size - ctx->cur_stream_offset); + wimlib_assert(ctx->cur_blob != NULL); + wimlib_assert(size <= ctx->cur_blob->size - ctx->cur_blob_offset); - if (ctx->cur_stream_offset == 0) { - /* Starting a new stream. */ - DEBUG("Begin new stream (size=%"PRIu64").", - ctx->cur_stream->size); - ret = (*ctx->cbs.begin_stream)(ctx->cur_stream, true, - ctx->cbs.begin_stream_ctx); + if (ctx->cur_blob_offset == 0) { + + /* Starting a new blob. */ + DEBUG("Begin new blob (size=%"PRIu64").", ctx->cur_blob->size); + + ret = (*ctx->cbs.begin_blob)(ctx->cur_blob, + ctx->cbs.begin_blob_ctx); if (ret) return ret; } @@ -922,29 +983,29 @@ streamifier_cb(const void *chunk, size_t size, void *_ctx) /* Consume the chunk. */ ret = (*ctx->cbs.consume_chunk)(chunk, size, ctx->cbs.consume_chunk_ctx); + ctx->cur_blob_offset += size; if (ret) return ret; - ctx->cur_stream_offset += size; - if (ctx->cur_stream_offset == ctx->cur_stream->size) { - /* Finished reading all the data for a stream. */ + if (ctx->cur_blob_offset == ctx->cur_blob->size) { + /* Finished reading all the data for a blob. */ - ctx->cur_stream_offset = 0; + ctx->cur_blob_offset = 0; - DEBUG("End stream (size=%"PRIu64").", ctx->cur_stream->size); - ret = (*ctx->cbs.end_stream)(ctx->cur_stream, 0, - ctx->cbs.end_stream_ctx); + DEBUG("End blob (size=%"PRIu64").", ctx->cur_blob->size); + ret = (*ctx->cbs.end_blob)(ctx->cur_blob, 0, + ctx->cbs.end_blob_ctx); if (ret) return ret; - /* Advance to next stream. */ - ctx->cur_stream = ctx->next_stream; - if (ctx->cur_stream != NULL) { - if (ctx->cur_stream != ctx->final_stream) - ctx->next_stream = next_stream(ctx->cur_stream, - ctx->list_head_offset); + /* Advance to next blob. */ + ctx->cur_blob = ctx->next_blob; + if (ctx->cur_blob != NULL) { + if (ctx->cur_blob != ctx->final_blob) + ctx->next_blob = next_blob(ctx->cur_blob, + ctx->list_head_offset); else - ctx->next_stream = NULL; + ctx->next_blob = NULL; } } return 0; @@ -953,30 +1014,28 @@ streamifier_cb(const void *chunk, size_t size, void *_ctx) struct hasher_context { SHA_CTX sha_ctx; int flags; - struct read_stream_list_callbacks cbs; + struct read_blob_list_callbacks cbs; }; -/* Callback for starting to read a stream while calculating its SHA1 message +/* Callback for starting to read a blob while calculating its SHA-1 message * digest. */ static int -hasher_begin_stream(struct wim_lookup_table_entry *lte, bool is_partial_res, - void *_ctx) +hasher_begin_blob(struct blob_descriptor *blob, void *_ctx) { struct hasher_context *ctx = _ctx; sha1_init(&ctx->sha_ctx); - if (ctx->cbs.begin_stream == NULL) + if (ctx->cbs.begin_blob == NULL) return 0; else - return (*ctx->cbs.begin_stream)(lte, is_partial_res, - ctx->cbs.begin_stream_ctx); + return (*ctx->cbs.begin_blob)(blob, ctx->cbs.begin_blob_ctx); } -/* A consume_data_callback_t implementation that continues calculating the SHA1 - * message digest of the stream being read, then optionally passes the data on - * to another consume_data_callback_t implementation. This allows checking the - * SHA1 message digest of a stream being extracted, for example. */ +/* A consume_data_callback_t implementation that continues calculating the SHA-1 + * message digest of the blob being read, then optionally passes the data on to + * another consume_data_callback_t implementation. This allows checking the + * SHA-1 message digest of a blob being extracted, for example. */ static int hasher_consume_chunk(const void *chunk, size_t size, void *_ctx) { @@ -989,122 +1048,127 @@ hasher_consume_chunk(const void *chunk, size_t size, void *_ctx) return (*ctx->cbs.consume_chunk)(chunk, size, ctx->cbs.consume_chunk_ctx); } -/* Callback for finishing reading a stream while calculating its SHA1 message +/* Callback for finishing reading a blob while calculating its SHA-1 message * digest. */ static int -hasher_end_stream(struct wim_lookup_table_entry *lte, int status, void *_ctx) +hasher_end_blob(struct blob_descriptor *blob, int status, void *_ctx) { struct hasher_context *ctx = _ctx; u8 hash[SHA1_HASH_SIZE]; int ret; if (status) { - /* Error occurred; the full stream may not have been read. */ + /* Error occurred; the full blob may not have been read. */ ret = status; goto out_next_cb; } - /* Retrieve the final SHA1 message digest. */ + /* Retrieve the final SHA-1 message digest. */ sha1_final(hash, &ctx->sha_ctx); - if (lte->unhashed) { - if (ctx->flags & COMPUTE_MISSING_STREAM_HASHES) { - /* No SHA1 message digest was previously present for the - * stream. Set it to the one just calculated. */ - DEBUG("Set SHA1 message digest for stream " - "(size=%"PRIu64").", lte->size); - copy_hash(lte->hash, hash); + if (blob->unhashed) { + if (ctx->flags & COMPUTE_MISSING_BLOB_HASHES) { + /* No SHA-1 message digest was previously present for the + * blob. Set it to the one just calculated. */ + DEBUG("Set SHA-1 message digest for blob " + "(size=%"PRIu64").", blob->size); + copy_hash(blob->hash, hash); } } else { - if (ctx->flags & VERIFY_STREAM_HASHES) { - /* The stream already had a SHA1 message digest present. Verify - * that it is the same as the calculated value. */ - if (!hashes_equal(hash, lte->hash)) { + if (ctx->flags & VERIFY_BLOB_HASHES) { + /* The blob already had a SHA-1 message digest present. + * Verify that it is the same as the calculated value. + */ + if (!hashes_equal(hash, blob->hash)) { if (wimlib_print_errors) { - ERROR("Invalid SHA1 message digest " - "on the following WIM stream:"); - print_lookup_table_entry(lte, stderr); + tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1]; + tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1]; + sprint_hash(blob->hash, expected_hashstr); + sprint_hash(hash, actual_hashstr); + ERROR("The blob is corrupted!\n" + " (Expected SHA-1=%"TS",\n" + " got SHA-1=%"TS")", + expected_hashstr, actual_hashstr); } ret = WIMLIB_ERR_INVALID_RESOURCE_HASH; errno = EINVAL; goto out_next_cb; } - DEBUG("SHA1 message digest okay for " - "stream (size=%"PRIu64").", lte->size); + DEBUG("SHA-1 message digest okay for " + "blob (size=%"PRIu64").", blob->size); } } ret = 0; out_next_cb: - if (ctx->cbs.end_stream == NULL) + if (ctx->cbs.end_blob == NULL) return ret; else - return (*ctx->cbs.end_stream)(lte, ret, ctx->cbs.end_stream_ctx); + return (*ctx->cbs.end_blob)(blob, ret, ctx->cbs.end_blob_ctx); } static int -read_full_stream_with_cbs(struct wim_lookup_table_entry *lte, - const struct read_stream_list_callbacks *cbs) +read_full_blob_with_cbs(struct blob_descriptor *blob, + const struct read_blob_list_callbacks *cbs) { int ret; - ret = (*cbs->begin_stream)(lte, false, cbs->begin_stream_ctx); + ret = (*cbs->begin_blob)(blob, cbs->begin_blob_ctx); if (ret) return ret; - ret = read_stream_prefix(lte, lte->size, cbs->consume_chunk, - cbs->consume_chunk_ctx); + ret = read_blob_prefix(blob, blob->size, cbs->consume_chunk, + cbs->consume_chunk_ctx); - return (*cbs->end_stream)(lte, ret, cbs->end_stream_ctx); + return (*cbs->end_blob)(blob, ret, cbs->end_blob_ctx); } -/* Read the full data of the specified stream, passing the data into the - * specified callbacks (all of which are optional) and either checking or - * computing the SHA1 message digest of the stream. */ +/* Read the full data of the specified blob, passing the data into the specified + * callbacks (all of which are optional) and either checking or computing the + * SHA-1 message digest of the blob. */ static int -read_full_stream_with_sha1(struct wim_lookup_table_entry *lte, - const struct read_stream_list_callbacks *cbs) +read_full_blob_with_sha1(struct blob_descriptor *blob, + const struct read_blob_list_callbacks *cbs) { struct hasher_context hasher_ctx = { - .flags = VERIFY_STREAM_HASHES | COMPUTE_MISSING_STREAM_HASHES, + .flags = VERIFY_BLOB_HASHES | COMPUTE_MISSING_BLOB_HASHES, .cbs = *cbs, }; - struct read_stream_list_callbacks hasher_cbs = { - .begin_stream = hasher_begin_stream, - .begin_stream_ctx = &hasher_ctx, + struct read_blob_list_callbacks hasher_cbs = { + .begin_blob = hasher_begin_blob, + .begin_blob_ctx = &hasher_ctx, .consume_chunk = hasher_consume_chunk, .consume_chunk_ctx = &hasher_ctx, - .end_stream = hasher_end_stream, - .end_stream_ctx = &hasher_ctx, - + .end_blob = hasher_end_blob, + .end_blob_ctx = &hasher_ctx, }; - return read_full_stream_with_cbs(lte, &hasher_cbs); + return read_full_blob_with_cbs(blob, &hasher_cbs); } static int -read_packed_streams(struct wim_lookup_table_entry *first_stream, - struct wim_lookup_table_entry *last_stream, - u64 stream_count, - size_t list_head_offset, - const struct read_stream_list_callbacks *sink_cbs) +read_blobs_in_solid_resource(struct blob_descriptor *first_blob, + struct blob_descriptor *last_blob, + u64 blob_count, + size_t list_head_offset, + const struct read_blob_list_callbacks *sink_cbs) { struct data_range *ranges; bool ranges_malloced; - struct wim_lookup_table_entry *cur_stream; + struct blob_descriptor *cur_blob; size_t i; int ret; u64 ranges_alloc_size; - DEBUG("Reading %"PRIu64" streams combined in same WIM resource", - stream_count); + DEBUG("Reading %"PRIu64" blobs combined in same WIM resource", + blob_count); - /* Setup data ranges array (one range per stream to read); this way - * read_compressed_wim_resource() does not need to be aware of streams. + /* Setup data ranges array (one range per blob to read); this way + * read_compressed_wim_resource() does not need to be aware of blobs. */ - ranges_alloc_size = stream_count * sizeof(ranges[0]); + ranges_alloc_size = blob_count * sizeof(ranges[0]); if (unlikely((size_t)ranges_alloc_size != ranges_alloc_size)) { - ERROR("Too many streams in one resource!"); + ERROR("Too many blobs in one resource!"); return WIMLIB_ERR_NOMEM; } if (likely(ranges_alloc_size <= STACK_MAX)) { @@ -1113,82 +1177,81 @@ read_packed_streams(struct wim_lookup_table_entry *first_stream, } else { ranges = MALLOC(ranges_alloc_size); if (ranges == NULL) { - ERROR("Too many streams in one resource!"); + ERROR("Too many blobs in one resource!"); return WIMLIB_ERR_NOMEM; } ranges_malloced = true; } - for (i = 0, cur_stream = first_stream; - i < stream_count; - i++, cur_stream = next_stream(cur_stream, list_head_offset)) + for (i = 0, cur_blob = first_blob; + i < blob_count; + i++, cur_blob = next_blob(cur_blob, list_head_offset)) { - ranges[i].offset = cur_stream->offset_in_res; - ranges[i].size = cur_stream->size; + ranges[i].offset = cur_blob->offset_in_res; + ranges[i].size = cur_blob->size; } - struct streamifier_context streamifier_ctx = { + struct blobifier_context blobifier_ctx = { .cbs = *sink_cbs, - .cur_stream = first_stream, - .next_stream = next_stream(first_stream, list_head_offset), - .cur_stream_offset = 0, - .final_stream = last_stream, + .cur_blob = first_blob, + .next_blob = next_blob(first_blob, list_head_offset), + .cur_blob_offset = 0, + .final_blob = last_blob, .list_head_offset = list_head_offset, }; - ret = read_compressed_wim_resource(first_stream->rspec, + ret = read_compressed_wim_resource(first_blob->rdesc, ranges, - stream_count, - streamifier_cb, - &streamifier_ctx); + blob_count, + blobifier_cb, + &blobifier_ctx); if (ranges_malloced) FREE(ranges); if (ret) { - if (streamifier_ctx.cur_stream_offset != 0) { - ret = (*streamifier_ctx.cbs.end_stream) - (streamifier_ctx.cur_stream, + if (blobifier_ctx.cur_blob_offset != 0) { + ret = (*blobifier_ctx.cbs.end_blob) + (blobifier_ctx.cur_blob, ret, - streamifier_ctx.cbs.end_stream_ctx); + blobifier_ctx.cbs.end_blob_ctx); } } return ret; } /* - * Read a list of streams, each of which may be in any supported location (e.g. - * in a WIM or in an external file). Unlike read_stream_prefix() or the - * functions which call it, this function optimizes the case where multiple - * streams are packed into a single compressed WIM resource and reads them all - * consecutively, only decompressing the data one time. + * Read a list of blobs, each of which may be in any supported location (e.g. + * in a WIM or in an external file). This function optimizes the case where + * multiple blobs are combined into a single solid compressed WIM resource by + * reading the blobs in sequential order, only decompressing the solid resource + * one time. * - * @stream_list - * List of streams (represented as `struct wim_lookup_table_entry's) to - * read. + * @blob_list + * List of blobs to read. * @list_head_offset - * Offset of the `struct list_head' within each `struct - * wim_lookup_table_entry' that makes up the @stream_list. + * Offset of the `struct list_head' within each `struct blob_descriptor' that makes up + * the @blob_list. * @cbs - * Callback functions to accept the stream data. + * Callback functions to accept the blob data. * @flags * Bitwise OR of zero or more of the following flags: * - * VERIFY_STREAM_HASHES: - * For all streams being read that have already had SHA1 message - * digests computed, calculate the SHA1 message digest of the read + * VERIFY_BLOB_HASHES: + * For all blobs being read that have already had SHA-1 message + * digests computed, calculate the SHA-1 message digest of the read * data and compare it with the previously computed value. If they * do not match, return WIMLIB_ERR_INVALID_RESOURCE_HASH. * - * COMPUTE_MISSING_STREAM_HASHES - * For all streams being read that have not yet had their SHA1 - * message digests computed, calculate and save their SHA1 message + * COMPUTE_MISSING_BLOB_HASHES + * For all blobs being read that have not yet had their SHA-1 + * message digests computed, calculate and save their SHA-1 message * digests. * - * STREAM_LIST_ALREADY_SORTED - * @stream_list is already sorted in sequential order for reading. + * BLOB_LIST_ALREADY_SORTED + * @blob_list is already sorted in sequential order for reading. * - * The callback functions are allowed to delete the current stream from the list + * The callback functions are allowed to delete the current blob from the list * if necessary. * * Returns 0 on success; a nonzero error code on failure. Failure can occur due @@ -1196,130 +1259,131 @@ read_packed_streams(struct wim_lookup_table_entry *first_stream, * of the callback functions. */ int -read_stream_list(struct list_head *stream_list, - size_t list_head_offset, - const struct read_stream_list_callbacks *cbs, - int flags) +read_blob_list(struct list_head *blob_list, + size_t list_head_offset, + const struct read_blob_list_callbacks *cbs, + int flags) { int ret; struct list_head *cur, *next; - struct wim_lookup_table_entry *lte; + struct blob_descriptor *blob; struct hasher_context *hasher_ctx; - struct read_stream_list_callbacks *sink_cbs; + struct read_blob_list_callbacks *sink_cbs; - if (!(flags & STREAM_LIST_ALREADY_SORTED)) { - ret = sort_stream_list_by_sequential_order(stream_list, list_head_offset); + if (!(flags & BLOB_LIST_ALREADY_SORTED)) { + ret = sort_blob_list_by_sequential_order(blob_list, list_head_offset); if (ret) return ret; } - if (flags & (VERIFY_STREAM_HASHES | COMPUTE_MISSING_STREAM_HASHES)) { + if (flags & (VERIFY_BLOB_HASHES | COMPUTE_MISSING_BLOB_HASHES)) { hasher_ctx = alloca(sizeof(*hasher_ctx)); *hasher_ctx = (struct hasher_context) { .flags = flags, .cbs = *cbs, }; sink_cbs = alloca(sizeof(*sink_cbs)); - *sink_cbs = (struct read_stream_list_callbacks) { - .begin_stream = hasher_begin_stream, - .begin_stream_ctx = hasher_ctx, + *sink_cbs = (struct read_blob_list_callbacks) { + .begin_blob = hasher_begin_blob, + .begin_blob_ctx = hasher_ctx, .consume_chunk = hasher_consume_chunk, .consume_chunk_ctx = hasher_ctx, - .end_stream = hasher_end_stream, - .end_stream_ctx = hasher_ctx, + .end_blob = hasher_end_blob, + .end_blob_ctx = hasher_ctx, }; } else { - sink_cbs = (struct read_stream_list_callbacks*)cbs; + sink_cbs = (struct read_blob_list_callbacks*)cbs; } - for (cur = stream_list->next, next = cur->next; - cur != stream_list; + for (cur = blob_list->next, next = cur->next; + cur != blob_list; cur = next, next = cur->next) { - lte = (struct wim_lookup_table_entry*)((u8*)cur - list_head_offset); + blob = (struct blob_descriptor*)((u8*)cur - list_head_offset); - if (lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS && - lte->size != lte->rspec->uncompressed_size) + if (blob->blob_location == BLOB_IN_WIM && + blob->size != blob->rdesc->uncompressed_size) { - - struct wim_lookup_table_entry *lte_next, *lte_last; + struct blob_descriptor *blob_next, *blob_last; struct list_head *next2; - u64 stream_count; + u64 blob_count; - /* The next stream is a proper sub-sequence of a WIM - * resource. See if there are other streams in the same + /* The next blob is a proper sub-sequence of a WIM + * resource. See if there are other blobs in the same * resource that need to be read. Since - * sort_stream_list_by_sequential_order() sorted the - * streams by offset in the WIM, this can be determined - * by simply scanning forward in the list. */ + * sort_blob_list_by_sequential_order() sorted the blobs + * by offset in the WIM, this can be determined by + * simply scanning forward in the list. */ - lte_last = lte; - stream_count = 1; + blob_last = blob; + blob_count = 1; for (next2 = next; - next2 != stream_list - && (lte_next = (struct wim_lookup_table_entry*) + next2 != blob_list + && (blob_next = (struct blob_descriptor*) ((u8*)next2 - list_head_offset), - lte_next->resource_location == RESOURCE_IN_WIM - && lte_next->rspec == lte->rspec); + blob_next->blob_location == BLOB_IN_WIM + && blob_next->rdesc == blob->rdesc); next2 = next2->next) { - lte_last = lte_next; - stream_count++; + blob_last = blob_next; + blob_count++; } - if (stream_count > 1) { - /* Reading multiple streams combined into a - * single WIM resource. They are in the stream - * list, sorted by offset; @lte specifies the - * first stream in the resource that needs to be - * read and @lte_last specifies the last stream - * in the resource that needs to be read. */ + if (blob_count > 1) { + /* Reading multiple blobs combined into a single + * WIM resource. They are in the blob list, + * sorted by offset; @blob specifies the first + * blob in the resource that needs to be read + * and @blob_last specifies the last blob in the + * resource that needs to be read. */ next = next2; - ret = read_packed_streams(lte, lte_last, - stream_count, - list_head_offset, - sink_cbs); + ret = read_blobs_in_solid_resource(blob, blob_last, + blob_count, + list_head_offset, + sink_cbs); if (ret) return ret; continue; } } - ret = read_full_stream_with_cbs(lte, sink_cbs); - if (ret && ret != BEGIN_STREAM_STATUS_SKIP_STREAM) + ret = read_full_blob_with_cbs(blob, sink_cbs); + if (ret && ret != BEGIN_BLOB_STATUS_SKIP_BLOB) return ret; } return 0; } -/* Extract the first @size bytes of the specified stream. +/* + * Extract the first @size bytes of the specified blob. * - * If @size specifies the full uncompressed size of the stream, then the SHA1 - * message digest of the uncompressed stream is checked while being extracted. + * If @size specifies the full uncompressed size of the blob, then the SHA-1 + * message digest of the uncompressed blob is checked while being extracted. * - * The uncompressed data of the resource is passed in chunks of unspecified size - * to the @extract_chunk function, passing it @extract_chunk_arg. */ + * The uncompressed data of the blob is passed in chunks of unspecified size to + * the @extract_chunk function, passing it @extract_chunk_arg. + */ int -extract_stream(struct wim_lookup_table_entry *lte, u64 size, - consume_data_callback_t extract_chunk, void *extract_chunk_arg) +extract_blob(struct blob_descriptor *blob, u64 size, + consume_data_callback_t extract_chunk, void *extract_chunk_arg) { - wimlib_assert(size <= lte->size); - if (size == lte->size) { - /* Do SHA1. */ - struct read_stream_list_callbacks cbs = { + wimlib_assert(size <= blob->size); + if (size == blob->size) { + /* Do SHA-1. */ + struct read_blob_list_callbacks cbs = { .consume_chunk = extract_chunk, .consume_chunk_ctx = extract_chunk_arg, }; - return read_full_stream_with_sha1(lte, &cbs); + return read_full_blob_with_sha1(blob, &cbs); } else { - /* Don't do SHA1. */ - return read_stream_prefix(lte, size, extract_chunk, - extract_chunk_arg); + /* Don't do SHA-1. */ + return read_blob_prefix(blob, size, extract_chunk, + extract_chunk_arg); } } /* A consume_data_callback_t implementation that writes the chunk of data to a * file descriptor. */ -int +static int extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p) { struct filedes *fd = _fd_p; @@ -1332,68 +1396,66 @@ extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p) return 0; } -/* Extract the first @size bytes of the specified stream to the specified file +/* Extract the first @size bytes of the specified blob to the specified file * descriptor. */ int -extract_stream_to_fd(struct wim_lookup_table_entry *lte, - struct filedes *fd, u64 size) +extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd, u64 size) { - return extract_stream(lte, size, extract_chunk_to_fd, fd); + return extract_blob(blob, size, extract_chunk_to_fd, fd); } -/* Extract the full uncompressed contents of the specified stream to the - * specified file descriptor. */ +/* Extract the full uncompressed contents of the specified blob to the specified + * file descriptor. */ int -extract_full_stream_to_fd(struct wim_lookup_table_entry *lte, - struct filedes *fd) +extract_full_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd) { - return extract_stream_to_fd(lte, fd, lte->size); + return extract_blob_to_fd(blob, fd, blob->size); } -/* Calculate the SHA1 message digest of a stream and store it in @lte->hash. */ +/* Calculate the SHA-1 message digest of a blob and store it in @blob->hash. */ int -sha1_stream(struct wim_lookup_table_entry *lte) +sha1_blob(struct blob_descriptor *blob) { - wimlib_assert(lte->unhashed); - struct read_stream_list_callbacks cbs = { + wimlib_assert(blob->unhashed); + struct read_blob_list_callbacks cbs = { }; - return read_full_stream_with_sha1(lte, &cbs); + return read_full_blob_with_sha1(blob, &cbs); } -/* Convert a short WIM resource header to a stand-alone WIM resource - * specification. +/* + * Convert a short WIM resource header to a stand-alone WIM resource descriptor. * - * Note: for packed resources some fields still need to be overridden. + * Note: for solid resources some fields still need to be overridden. */ void -wim_res_hdr_to_spec(const struct wim_reshdr *reshdr, WIMStruct *wim, - struct wim_resource_spec *rspec) +wim_res_hdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim, + struct wim_resource_descriptor *rdesc) { - rspec->wim = wim; - rspec->offset_in_wim = reshdr->offset_in_wim; - rspec->size_in_wim = reshdr->size_in_wim; - rspec->uncompressed_size = reshdr->uncompressed_size; - INIT_LIST_HEAD(&rspec->stream_list); - rspec->flags = reshdr->flags; - rspec->is_pipable = wim_is_pipable(wim); - if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) { - rspec->compression_type = wim->compression_type; - rspec->chunk_size = wim->chunk_size; + rdesc->wim = wim; + rdesc->offset_in_wim = reshdr->offset_in_wim; + rdesc->size_in_wim = reshdr->size_in_wim; + rdesc->uncompressed_size = reshdr->uncompressed_size; + INIT_LIST_HEAD(&rdesc->blob_list); + rdesc->flags = reshdr->flags; + rdesc->is_pipable = wim_is_pipable(wim); + if (rdesc->flags & WIM_RESHDR_FLAG_COMPRESSED) { + rdesc->compression_type = wim->compression_type; + rdesc->chunk_size = wim->chunk_size; } else { - rspec->compression_type = WIMLIB_COMPRESSION_TYPE_NONE; - rspec->chunk_size = 0; + rdesc->compression_type = WIMLIB_COMPRESSION_TYPE_NONE; + rdesc->chunk_size = 0; } } -/* Convert a stand-alone resource specification to a WIM resource header. */ +/* Convert a stand-alone resource descriptor to a WIM resource header. */ void -wim_res_spec_to_hdr(const struct wim_resource_spec *rspec, +wim_res_desc_to_hdr(const struct wim_resource_descriptor *rdesc, struct wim_reshdr *reshdr) { - reshdr->offset_in_wim = rspec->offset_in_wim; - reshdr->size_in_wim = rspec->size_in_wim; - reshdr->flags = rspec->flags; - reshdr->uncompressed_size = rspec->uncompressed_size; + reshdr->offset_in_wim = rdesc->offset_in_wim; + reshdr->size_in_wim = rdesc->size_in_wim; + reshdr->flags = rdesc->flags; + reshdr->uncompressed_size = rdesc->uncompressed_size; } /* Translates a WIM resource header from the on-disk format into an in-memory