X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fblob_table.c;h=43ea4854b949bb7be932ca71ed36df4392f98dff;hb=f1c9d53eb97205b17092ba6de50f0967932861ed;hp=e93fce1ef2fb91a6f05458c841f3580f84abb756;hpb=fef476297d762fec1f4c1517895add6b4c342915;p=wimlib diff --git a/src/blob_table.c b/src/blob_table.c index e93fce1e..43ea4854 100644 --- a/src/blob_table.c +++ b/src/blob_table.c @@ -34,6 +34,7 @@ #include /* for unlink() */ #include "wimlib/assert.h" +#include "wimlib/bitops.h" #include "wimlib/blob_table.h" #include "wimlib/encoding.h" #include "wimlib/endianness.h" @@ -49,15 +50,25 @@ struct blob_table { struct hlist_head *array; size_t num_blobs; - size_t capacity; + size_t mask; /* capacity - 1; capacity is a power of 2 */ }; +static size_t +next_power_of_2(size_t n) +{ + if (n <= 1) + return 1; + return (size_t)1 << (1 + flsw(n - 1)); +} + struct blob_table * new_blob_table(size_t capacity) { struct blob_table *table; struct hlist_head *array; + capacity = next_power_of_2(capacity); + table = MALLOC(sizeof(struct blob_table)); if (table == NULL) goto oom; @@ -69,7 +80,7 @@ new_blob_table(size_t capacity) } table->num_blobs = 0; - table->capacity = capacity; + table->mask = capacity - 1; table->array = array; return table; @@ -287,7 +298,7 @@ blob_decrement_num_opened_fds(struct blob_descriptor *blob) static void blob_table_insert_raw(struct blob_table *table, struct blob_descriptor *blob) { - size_t i = blob->hash_short % table->capacity; + size_t i = blob->hash_short & table->mask; hlist_add_head(&blob->hash_list, &table->array[i]); } @@ -301,21 +312,18 @@ enlarge_blob_table(struct blob_table *table) struct hlist_node *tmp; size_t i; - old_capacity = table->capacity; + old_capacity = table->mask + 1; new_capacity = old_capacity * 2; new_array = CALLOC(new_capacity, sizeof(struct hlist_head)); if (new_array == NULL) return; old_array = table->array; table->array = new_array; - table->capacity = new_capacity; + table->mask = new_capacity - 1; - for (i = 0; i < old_capacity; i++) { - hlist_for_each_entry_safe(blob, tmp, &old_array[i], hash_list) { - hlist_del(&blob->hash_list); + for (i = 0; i < old_capacity; i++) + hlist_for_each_entry_safe(blob, tmp, &old_array[i], hash_list) blob_table_insert_raw(table, blob); - } - } FREE(old_array); } @@ -324,7 +332,7 @@ void blob_table_insert(struct blob_table *table, struct blob_descriptor *blob) { blob_table_insert_raw(table, blob); - if (++table->num_blobs > table->capacity) + if (table->num_blobs++ > table->mask) enlarge_blob_table(table); } @@ -347,7 +355,7 @@ lookup_blob(const struct blob_table *table, const u8 *hash) size_t i; struct blob_descriptor *blob; - i = load_size_t_unaligned(hash) % table->capacity; + i = load_size_t_unaligned(hash) & table->mask; hlist_for_each_entry(blob, &table->array[i], hash_list) if (hashes_equal(hash, blob->hash)) return blob; @@ -364,7 +372,7 @@ for_blob_in_table(struct blob_table *table, struct hlist_node *tmp; int ret; - for (size_t i = 0; i < table->capacity; i++) { + for (size_t i = 0; i <= table->mask; i++) { hlist_for_each_entry_safe(blob, tmp, &table->array[i], hash_list) { @@ -406,7 +414,7 @@ cmp_blobs_by_sequential_order(const void *p1, const void *p2) /* Different (possibly split) WIMs? */ if (wim1 != wim2) { - v = memcmp(wim1->hdr.guid, wim2->hdr.guid, WIM_GUID_LEN); + v = cmp_guids(wim1->hdr.guid, wim2->hdr.guid); if (v) return v; } @@ -611,7 +619,7 @@ do_load_solid_info(WIMStruct *wim, struct wim_resource_descriptor **rdescs, rdesc = rdescs[i]; - wim_res_hdr_to_desc(&reshdr, wim, rdesc); + wim_reshdr_to_desc(&reshdr, wim, rdesc); /* For solid resources, the uncompressed size, compression type, * and chunk size are stored in the resource itself, not in the @@ -635,17 +643,7 @@ do_load_solid_info(WIMStruct *wim, struct wim_resource_descriptor **rdescs, BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 2); BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3); rdesc->compression_type = le32_to_cpu(hdr.compression_format); - rdesc->chunk_size = le32_to_cpu(hdr.chunk_size); - - DEBUG("Solid resource %zu/%zu: %"PRIu64" => %"PRIu64" " - "(%"TS"/%"PRIu32") @ +%"PRIu64"", - i + 1, num_rdescs, - rdesc->uncompressed_size, - rdesc->size_in_wim, - wimlib_get_compression_type_string(rdesc->compression_type), - rdesc->chunk_size, - rdesc->offset_in_wim); } return 0; } @@ -856,13 +854,12 @@ read_blob_table(WIMStruct *wim) struct blob_table *table = NULL; struct blob_descriptor *cur_blob = NULL; size_t num_duplicate_blobs = 0; + size_t num_empty_blobs = 0; size_t num_wrong_part_blobs = 0; u32 image_index = 0; struct wim_resource_descriptor **cur_solid_rdescs = NULL; size_t cur_num_solid_rdescs = 0; - DEBUG("Reading blob table."); - /* Calculate the number of entries in the blob table. */ num_entries = wim->hdr.blob_table_reshdr.uncompressed_size / sizeof(struct blob_descriptor_disk); @@ -874,7 +871,7 @@ read_blob_table(WIMStruct *wim) /* Allocate a hash table to map SHA-1 message digests into blob * descriptors. This is the in-memory "blob table". */ - table = new_blob_table(num_entries * 2 + 1); + table = new_blob_table(num_entries); if (!table) goto oom; @@ -889,13 +886,6 @@ read_blob_table(WIMStruct *wim) /* Get the resource header */ get_wim_reshdr(&disk_entry->reshdr, &reshdr); - DEBUG("reshdr: size_in_wim=%"PRIu64", " - "uncompressed_size=%"PRIu64", " - "offset_in_wim=%"PRIu64", " - "flags=0x%02x", - reshdr.size_in_wim, reshdr.uncompressed_size, - reshdr.offset_in_wim, reshdr.flags); - /* Ignore SOLID flag if it isn't supposed to be used in this WIM * version. */ if (wim->hdr.wim_version == WIM_VERSION_DEFAULT) @@ -953,27 +943,13 @@ read_blob_table(WIMStruct *wim) goto out; } - /* How to handle an uncompressed resource with its - * uncompressed size different from its compressed size? - * - * Based on a simple test, WIMGAPI seems to handle this - * as follows: - * - * if (size_in_wim > uncompressed_size) { - * Ignore uncompressed_size; use size_in_wim - * instead. - * } else { - * Honor uncompressed_size, but treat the part of - * the file data above size_in_wim as all zeros. - * } - * - * So we will do the same. */ - if (unlikely(!(reshdr.flags & - WIM_RESHDR_FLAG_COMPRESSED) && - (reshdr.size_in_wim > - reshdr.uncompressed_size))) + if (unlikely(!(reshdr.flags & WIM_RESHDR_FLAG_COMPRESSED) && + (reshdr.size_in_wim != reshdr.uncompressed_size))) { - reshdr.uncompressed_size = reshdr.size_in_wim; + ERROR("Uncompressed resource has " + "size_in_wim != uncompressed_size"); + ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; + goto out; } /* Set up a resource descriptor for this blob. */ @@ -982,20 +958,24 @@ read_blob_table(WIMStruct *wim) if (!rdesc) goto oom; - wim_res_hdr_to_desc(&reshdr, wim, rdesc); - - blob_set_is_located_in_nonsolid_wim_resource(cur_blob, rdesc); + wim_reshdr_to_desc_and_blob(&reshdr, wim, rdesc, cur_blob); } /* cur_blob is now a blob bound to a resource. */ /* Ignore entries with all zeroes in the hash field. */ - if (is_zero_hash(cur_blob->hash)) + if (unlikely(is_zero_hash(cur_blob->hash))) + goto free_cur_blob_and_continue; + + /* Verify that the blob has nonzero size. */ + if (unlikely(cur_blob->size == 0)) { + num_empty_blobs++; goto free_cur_blob_and_continue; + } /* Verify that the part number matches that of the underlying * WIM file. */ - if (part_number != wim->hdr.part_number) { + if (unlikely(part_number != wim->hdr.part_number)) { num_wrong_part_blobs++; goto free_cur_blob_and_continue; } @@ -1022,6 +1002,13 @@ read_blob_table(WIMStruct *wim) goto out; } + if (reshdr.flags & WIM_RESHDR_FLAG_SOLID) { + ERROR("Image metadata in solid resources " + "is unsupported."); + ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; + goto out; + } + if (wim->hdr.part_number != 1) { WARNING("Ignoring metadata resource found in a " "non-first part of the split WIM"); @@ -1043,11 +1030,6 @@ read_blob_table(WIMStruct *wim) * this overrides the actual locations of the metadata * resources themselves in the WIM file as well as any * information written in the XML data. */ - DEBUG("Found metadata resource for image %"PRIu32" at " - "offset %"PRIu64".", - image_index + 1, - reshdr.offset_in_wim); - wim->image_metadata[image_index++]->metadata_blob = cur_blob; } else { /* Blob table entry for a non-metadata blob. */ @@ -1091,12 +1073,14 @@ read_blob_table(WIMStruct *wim) if (num_duplicate_blobs > 0) WARNING("Ignoring %zu duplicate blobs", num_duplicate_blobs); + if (num_empty_blobs > 0) + WARNING("Ignoring %zu empty blobs", num_empty_blobs); + if (num_wrong_part_blobs > 0) { WARNING("Ignoring %zu blobs with wrong part number", num_wrong_part_blobs); } - DEBUG("Done reading blob table."); wim->blob_table = table; ret = 0; goto out_free_buf; @@ -1156,9 +1140,6 @@ write_blob_table_from_blob_list(struct list_head *blob_list, } } - DEBUG("Writing WIM blob table (size=%zu, offset=%"PRIu64")", - table_size, out_fd->offset); - table_buf = MALLOC(table_size); if (table_buf == NULL) { ERROR("Failed to allocate %zu bytes for temporary blob table", @@ -1217,7 +1198,6 @@ write_blob_table_from_blob_list(struct list_head *blob_list, NULL, write_resource_flags); FREE(table_buf); - DEBUG("ret=%d", ret); return ret; }