From b6034a5dd44709341c46d553b1c0294ec91f13e4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 7 Jan 2014 19:10:22 -0600 Subject: [PATCH 1/1] Cache compression format in 'struct wim_resource_spec' --- include/wimlib/resource.h | 7 ++++++ src/lookup_table.c | 26 ++++++++++++---------- src/resource.c | 46 +++++++++++++++++---------------------- src/write.c | 4 ++-- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/include/wimlib/resource.h b/include/wimlib/resource.h index 488ea6a9..38ce568c 100644 --- a/include/wimlib/resource.h +++ b/include/wimlib/resource.h @@ -52,6 +52,13 @@ struct wim_resource_spec { /* Temporary flag. */ u32 raw_copy_ok : 1; + + /* Compression type of this resource. */ + u32 compression_type : 22; + + /* Compression chunk size of this resource. Irrelevant if the resource + * is uncompressed. */ + u32 chunk_size; }; /* On-disk version of a WIM resource header. */ diff --git a/src/lookup_table.c b/src/lookup_table.c index 6ff8381d..815d576f 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -680,16 +680,6 @@ read_wim_lookup_table(WIMStruct *wim) } wim_res_hdr_to_spec(&reshdr, wim, cur_rspec); - /* If this is a packed run, the current stream entry may - * specify a stream within the resource, and not the - * resource itself. Zero possibly irrelevant data until - * it is read for certain. */ - if (reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) { - cur_rspec->size_in_wim = 0; - cur_rspec->uncompressed_size = 0; - cur_rspec->offset_in_wim = 0; - } - if (prev_entry) lte_bind_wim_resource_spec(prev_entry, cur_rspec); } @@ -705,7 +695,10 @@ read_wim_lookup_table(WIMStruct *wim) */ /* Uncompressed size of the resource pack is actually - * stored in the header of the resource itself. */ + * stored in the header of the resource itself. Read + * it, and also grab the chunk size and compression type + * (which are not necessarily the defaults from the WIM + * header). */ struct alt_chunk_table_header_disk hdr; ret = full_pread(&wim->in_fd, &hdr, @@ -717,6 +710,17 @@ read_wim_lookup_table(WIMStruct *wim) cur_rspec->offset_in_wim = reshdr.offset_in_wim; cur_rspec->size_in_wim = reshdr.size_in_wim; cur_rspec->flags = reshdr.flags; + + /* Compression format numbers must be the same as in + * WIMGAPI to be compatible here. */ + BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_NONE != 0); + BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 1); + BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 2); + BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3); + cur_rspec->compression_type = le32_to_cpu(hdr.compression_format); + + cur_rspec->chunk_size = le32_to_cpu(hdr.chunk_size); + DEBUG("Full pack is %"PRIu64" compressed bytes " "at file offset %"PRIu64" (flags 0x%02x)", cur_rspec->size_in_wim, diff --git a/src/resource.c b/src/resource.c index 6e47dff7..116873ff 100644 --- a/src/resource.c +++ b/src/resource.c @@ -175,37 +175,21 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, /* Get the maximum size of uncompressed chunks in this resource, which * we require be a power of 2. */ - u32 chunk_size = 0; u64 cur_read_offset = rspec->offset_in_wim; - int ctype = WIMLIB_COMPRESSION_TYPE_NONE; + int ctype = rspec->compression_type; + u32 chunk_size = rspec->chunk_size; if (alt_chunk_table) { /* Alternate chunk table format. Its header specifies the chunk - * size and compression format. */ - struct alt_chunk_table_header_disk hdr; - - ret = full_pread(in_fd, &hdr, sizeof(hdr), cur_read_offset); - if (ret) - goto read_error; - cur_read_offset += sizeof(hdr); - - chunk_size = le32_to_cpu(hdr.chunk_size); - ctype = le32_to_cpu(hdr.compression_format); - - /* Format numbers must be the same as in WIMGAPI to be - * compatible. */ - BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_NONE != 0); - BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 1); - BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 2); - BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3); - } else { - /* "Normal" format: the maximum uncompressed chunk size and the - * compression format default to those of the WIM itself. */ - chunk_size = rspec->wim->chunk_size; - ctype = rspec->wim->compression_type; + * size and compression format. Note: it could be read here; + * however, the relevant data was already loaded into @rspec by + * read_wim_lookup_table(). */ + cur_read_offset += sizeof(struct alt_chunk_table_header_disk); } + if (!is_power_of_2(chunk_size)) { ERROR("Invalid compressed resource: " - "expected power-of-2 chunk size (got %u)", chunk_size); + "expected power-of-2 chunk size (got %"PRIu32")", + chunk_size); ret = WIMLIB_ERR_INVALID_CHUNK_SIZE; goto out_free_memory; } @@ -1377,7 +1361,10 @@ sha1_stream(struct wim_lookup_table_entry *lte) } /* Convert a short WIM resource header to a stand-alone WIM resource - * specification. */ + * specification. + * + * Note: for packed 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) @@ -1389,6 +1376,13 @@ wim_res_hdr_to_spec(const struct wim_reshdr *reshdr, WIMStruct *wim, 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; + } else { + rspec->compression_type = WIMLIB_COMPRESSION_TYPE_NONE; + rspec->chunk_size = 0; + } } /* Convert a stand-alone resource specification to a WIM resource header. */ diff --git a/src/write.c b/src/write.c index 3fd1d045..b8d86e85 100644 --- a/src/write.c +++ b/src/write.c @@ -172,8 +172,8 @@ can_raw_copy(const struct wim_lookup_table_entry *lte, if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) { /* Normal compressed resource: Must use same compression type * and chunk size. */ - return (rspec->wim->compression_type == out_ctype && - rspec->wim->chunk_size == out_chunk_size); + return (rspec->compression_type == out_ctype && + rspec->chunk_size == out_chunk_size); } /* XXX: For compatibility, we can't allow multiple packed resources per -- 2.43.0