X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fresource.c;h=7a5d1718a631cae9b24c194b531850bacf7de8cb;hp=90e45ca1092db0eb3f0a65617734613beceab1c0;hb=062465170ddb4520ca6fbc64a0f6e27e786de101;hpb=9e2571b03cd9c71d11b3dad9ea5dcfa43f50deb4 diff --git a/src/resource.c b/src/resource.c index 90e45ca1..7a5d1718 100644 --- a/src/resource.c +++ b/src/resource.c @@ -537,6 +537,8 @@ read_partial_wim_resource(const struct wim_lookup_table_entry *lte, cb, ctx_or_buf); } else { + offset += lte->resource_entry.offset; + if (fseeko(wim_fp, offset, SEEK_SET)) { ERROR_WITH_ERRNO("Failed to seek to offset %"PRIu64 " in WIM", offset); @@ -544,9 +546,10 @@ read_partial_wim_resource(const struct wim_lookup_table_entry *lte, goto out_release_fp; } if (cb) { - char buf[min(32768, size)]; + /* Send data to callback function */ + u8 buf[min(WIM_CHUNK_SIZE, size)]; while (size) { - size_t bytes_to_read = min(32768, size); + size_t bytes_to_read = min(WIM_CHUNK_SIZE, size); size_t bytes_read = fread(buf, 1, bytes_to_read, wim_fp); if (bytes_read != bytes_to_read) @@ -554,8 +557,10 @@ read_partial_wim_resource(const struct wim_lookup_table_entry *lte, ret = cb(buf, bytes_read, ctx_or_buf); if (ret) goto out_release_fp; + size -= bytes_read; } } else { + /* Send data directly to a buffer */ if (fread(ctx_or_buf, 1, size, wim_fp) != size) goto read_error; } @@ -572,7 +577,6 @@ out: if (ret) { if (errno == 0) errno = EIO; - ret = -1; } return ret; } @@ -618,16 +622,17 @@ read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte, } if (cb) { /* Send data to callback function */ - char buf[min(32768, size)]; + u8 buf[min(WIM_CHUNK_SIZE, size)]; size_t bytes_to_read; while (size) { - bytes_to_read = min(32768, size); + bytes_to_read = min(WIM_CHUNK_SIZE, size); bytes_read = full_read(fd, buf, bytes_to_read); if (bytes_read != bytes_to_read) goto read_error; ret = cb(buf, bytes_read, ctx_or_buf); if (ret) goto out_close; + size -= bytes_read; } } else { /* Send data directly to a buffer */ @@ -651,12 +656,21 @@ read_buffer_prefix(const struct wim_lookup_table_entry *lte, void *ctx_or_buf, int _ignored_flags) { const void *inbuf = lte->attached_buffer; + int ret; + if (cb) { - return cb(inbuf, size, ctx_or_buf); + while (size) { + size_t chunk_size = min(WIM_CHUNK_SIZE, size); + ret = cb(inbuf, chunk_size, ctx_or_buf); + if (ret) + return ret; + size -= chunk_size; + inbuf += chunk_size; + } } else { memcpy(ctx_or_buf, inbuf, size); - return 0; } + return 0; } typedef int (*read_resource_prefix_handler_t)(const struct wim_lookup_table_entry *lte, @@ -665,6 +679,23 @@ typedef int (*read_resource_prefix_handler_t)(const struct wim_lookup_table_entr void *ctx_or_buf, int flags); +/* + * Read the first @size bytes from a generic "resource", which may be located in + * the WIM (compressed or uncompressed), in an external file, or directly in an + * in-memory buffer. + * + * Feed the data either to a callback function (cb != NULL, passing it + * ctx_or_buf), or write it directly into a buffer (cb == NULL, ctx_or_buf + * specifies the buffer, which must have room for @size bytes). + * + * When using a callback function, it is called with chunks up to 32768 bytes in + * size until the resource is exhausted. + * + * If the resource is located in a WIM file, @flags can be + * WIMLIB_RESOURCE_FLAG_MULTITHREADED if it must be safe to access the resource + * concurrently by multiple threads, or WIMLIB_RESOURCE_FLAG_RAW if the raw + * compressed data is to be supplied instead of the uncompressed data. + */ int read_resource_prefix(const struct wim_lookup_table_entry *lte, u64 size, consume_data_callback_t cb, void *ctx_or_buf, @@ -700,6 +731,22 @@ read_full_resource_into_buf(const struct wim_lookup_table_entry *lte, thread_safe ? WIMLIB_RESOURCE_FLAG_MULTITHREADED : 0); } +struct extract_ctx { + SHA_CTX sha_ctx; + consume_data_callback_t extract_chunk; + void *extract_chunk_arg; +}; + +static int +extract_chunk_sha1_wrapper(const void *chunk, size_t chunk_size, + void *_ctx) +{ + struct extract_ctx *ctx = _ctx; + + sha1_update(&ctx->sha_ctx, chunk, chunk_size); + return ctx->extract_chunk(chunk, chunk_size, ctx->extract_chunk_arg); +} + /* Extracts the first @size bytes of a WIM resource to somewhere. In the * process, the SHA1 message digest of the resource is checked if the full * resource is being extracted. @@ -712,8 +759,36 @@ extract_wim_resource(const struct wim_lookup_table_entry *lte, consume_data_callback_t extract_chunk, void *extract_chunk_arg) { - return read_resource_prefix(lte, size, extract_chunk, - extract_chunk_arg, 0); + int ret; + if (size == wim_resource_size(lte)) { + /* Do SHA1 */ + struct extract_ctx ctx; + ctx.extract_chunk = extract_chunk; + ctx.extract_chunk_arg = extract_chunk_arg; + sha1_init(&ctx.sha_ctx); + ret = read_resource_prefix(lte, size, + extract_chunk_sha1_wrapper, + &ctx, 0); + if (ret == 0) { + u8 hash[SHA1_HASH_SIZE]; + sha1_final(hash, &ctx.sha_ctx); + if (!hashes_equal(hash, lte->hash)) { + #ifdef ENABLE_ERROR_MESSAGES + ERROR_WITH_ERRNO("Invalid SHA1 message digest " + "on the following WIM resource:"); + print_lookup_table_entry(lte, stderr); + if (lte->resource_location == RESOURCE_IN_WIM) + ERROR("The WIM file appears to be corrupt!"); + ret = WIMLIB_ERR_INVALID_RESOURCE_HASH; + #endif + } + } + } else { + /* Don't do SHA1 */ + ret = read_resource_prefix(lte, size, extract_chunk, + extract_chunk_arg, 0); + } + return ret; } static int