X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Flookup_table.c;h=815d576fe551177200b8b781c3a69621d7210530;hb=5c0846b71891c0c088de4f9ef4cc6ab545f5b64e;hp=a899bf9581abed3b4badb1c60a55c3a229222311;hpb=26c7f8bb32e4a32001d409f1693e0df016270ed5;p=wimlib diff --git a/src/lookup_table.c b/src/lookup_table.c index a899bf95..815d576f 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -212,6 +212,43 @@ free_lookup_table(struct wim_lookup_table *table) } } +static void +lookup_table_insert_raw(struct wim_lookup_table *table, + struct wim_lookup_table_entry *lte) +{ + size_t i = lte->hash_short % table->capacity; + + hlist_add_head(<e->hash_list, &table->array[i]); +} + +static void +enlarge_lookup_table(struct wim_lookup_table *table) +{ + size_t old_capacity, new_capacity; + struct hlist_head *old_array, *new_array; + struct wim_lookup_table_entry *lte; + struct hlist_node *cur, *tmp; + size_t i; + + old_capacity = table->capacity; + 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; + + for (i = 0; i < old_capacity; i++) { + hlist_for_each_entry_safe(lte, cur, tmp, &old_array[i], hash_list) { + hlist_del(<e->hash_list); + lookup_table_insert_raw(table, lte); + } + } + FREE(old_array); +} + + /* * Inserts an entry into the lookup table. * @@ -222,11 +259,9 @@ void lookup_table_insert(struct wim_lookup_table *table, struct wim_lookup_table_entry *lte) { - size_t i = lte->hash_short % table->capacity; - hlist_add_head(<e->hash_list, &table->array[i]); - - /* XXX Make the table grow when too many entries have been inserted. */ - table->num_entries++; + lookup_table_insert_raw(table, lte); + if (++table->num_entries > table->capacity) + enlarge_lookup_table(table); } static void @@ -288,7 +323,6 @@ for_lookup_table_entry(struct wim_lookup_table *table, hlist_for_each_entry_safe(lte, pos, tmp, &table->array[i], hash_list) { - wimlib_assert2(!(lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)); ret = visitor(lte, arg); if (ret) return ret; @@ -337,8 +371,11 @@ cmp_streams_by_sequential_order(const void *p1, const void *p2) if (v) return v; - return cmp_u64(lte1->rspec->offset_in_wim + lte1->offset_in_res, - lte2->rspec->offset_in_wim + lte2->offset_in_res); + if (lte1->rspec->offset_in_wim != lte2->rspec->offset_in_wim) + return cmp_u64(lte1->rspec->offset_in_wim, + lte2->rspec->offset_in_wim); + + return cmp_u64(lte1->offset_in_res, lte2->offset_in_res); case RESOURCE_IN_FILE_ON_DISK: #ifdef WITH_FUSE @@ -486,7 +523,8 @@ validate_resource(const struct wim_resource_spec *rspec) goto invalid; /* Verify that each stream in the resource has a valid offset and size, - * and that no streams overlap. */ + * and that no streams overlap, and that the streams were added in order + * of increasing offset. */ cur_offset = 0; list_for_each_entry(lte, &rspec->stream_list, rspec_node) { if (lte->offset_in_res + lte->size < lte->size || @@ -574,11 +612,14 @@ read_wim_lookup_table(WIMStruct *wim) reshdr.size_in_wim, reshdr.uncompressed_size, reshdr.offset_in_wim, reshdr.flags); + if (wim->hdr.wim_version == WIM_VERSION_DEFAULT) + reshdr.flags &= ~WIM_RESHDR_FLAG_PACKED_STREAMS; + cur_entry = new_lookup_table_entry(); if (cur_entry == NULL) { ERROR("Not enough memory to read lookup table!"); ret = WIMLIB_ERR_NOMEM; - goto out_free_lookup_table; + goto err; } part_number = le16_to_cpu(disk_entry->part_number); @@ -598,7 +639,7 @@ read_wim_lookup_table(WIMStruct *wim) if (reshdr.uncompressed_size != reshdr.size_in_wim) { ERROR("Invalid resource entry!"); ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; - goto out_free_cur_entry; + goto err; } } @@ -615,17 +656,18 @@ read_wim_lookup_table(WIMStruct *wim) * resource. */ struct wim_lookup_table_entry *prev_entry = NULL; - if (back_to_back_pack) { + if (back_to_back_pack && + !list_empty(&cur_rspec->stream_list)) + { prev_entry = list_entry(cur_rspec->stream_list.prev, struct wim_lookup_table_entry, rspec_node); lte_unbind_wim_resource_spec(prev_entry); - cur_rspec->uncompressed_size -= prev_entry->size; } if (cur_rspec != NULL) { ret = validate_resource(cur_rspec); if (ret) - goto out_free_cur_entry; + goto err; } /* Allocate the resource specification and initialize it @@ -634,24 +676,12 @@ read_wim_lookup_table(WIMStruct *wim) if (cur_rspec == NULL) { ERROR("Not enough memory to read lookup table!"); ret = WIMLIB_ERR_NOMEM; - goto out_free_cur_entry; + goto err; } 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->flags = WIM_RESHDR_FLAG_PACKED_STREAMS; - } - - if (prev_entry) { + if (prev_entry) lte_bind_wim_resource_spec(prev_entry, cur_rspec); - cur_rspec->uncompressed_size = prev_entry->size; - } } if ((reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) && @@ -661,11 +691,36 @@ read_wim_lookup_table(WIMStruct *wim) * Transfer the values to the `struct * wim_resource_spec', and discard the current stream * since this lookup table entry did not, in fact, - * correspond to a "stream". */ + * correspond to a "stream". + */ + + /* Uncompressed size of the resource pack is actually + * 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, + sizeof(hdr), reshdr.offset_in_wim); + if (ret) + goto err; + cur_rspec->uncompressed_size = le64_to_cpu(hdr.res_usize); 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, @@ -682,10 +737,10 @@ read_wim_lookup_table(WIMStruct *wim) if (reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) { /* Continuing the pack with another stream. */ - DEBUG("Continuing packed run with stream: " - "%"PRIu64" uncompressed bytes @ resource offset %"PRIu64")", + DEBUG("Continuing pack with stream: " + "%"PRIu64" uncompressed bytes @ " + "resource offset %"PRIu64")", reshdr.size_in_wim, reshdr.offset_in_wim); - cur_rspec->uncompressed_size += reshdr.size_in_wim; } lte_bind_wim_resource_spec(cur_entry, cur_rspec); @@ -723,7 +778,7 @@ read_wim_lookup_table(WIMStruct *wim) print_lookup_table_entry(cur_entry, stderr); } ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; - goto out_free_cur_entry; + goto err; } if (wim->hdr.part_number != 1) { @@ -777,12 +832,13 @@ read_wim_lookup_table(WIMStruct *wim) * its SHA1 message digest. */ lookup_table_insert(table, cur_entry); } + cur_entry = NULL; /* Validate the last resource. */ if (cur_rspec != NULL) { ret = validate_resource(cur_rspec); if (ret) - goto out_free_lookup_table; + goto err; } if (wim->hdr.part_number == 1 && wim->current_image != wim->hdr.image_count) { @@ -800,9 +856,10 @@ read_wim_lookup_table(WIMStruct *wim) ret = 0; goto out_free_buf; -out_free_cur_entry: - FREE(cur_entry); -out_free_lookup_table: +err: + if (cur_rspec && list_empty(&cur_rspec->stream_list)) + FREE(cur_rspec); + free_lookup_table_entry(cur_entry); free_lookup_table(table); out_free_buf: FREE(buf); @@ -827,8 +884,7 @@ write_wim_lookup_table_from_stream_list(struct list_head *stream_list, struct filedes *out_fd, u16 part_number, struct wim_reshdr *out_reshdr, - int write_resource_flags, - struct wimlib_lzx_context **comp_ctx) + int write_resource_flags) { size_t table_size; struct wim_lookup_table_entry *lte; @@ -908,8 +964,7 @@ write_wim_lookup_table_from_stream_list(struct list_head *stream_list, 0, out_reshdr, NULL, - write_resource_flags, - comp_ctx); + write_resource_flags); FREE(table_buf); DEBUG("ret=%d", ret); return ret; @@ -1037,7 +1092,7 @@ lte_to_wimlib_resource_entry(const struct wim_lookup_table_entry *lte, wentry->offset = lte->rspec->offset_in_wim; } wentry->raw_resource_offset_in_wim = lte->rspec->offset_in_wim; - wentry->raw_resource_uncompressed_size = lte->rspec->uncompressed_size; + /*wentry->raw_resource_uncompressed_size = lte->rspec->uncompressed_size;*/ wentry->raw_resource_compressed_size = lte->rspec->size_in_wim; } copy_hash(wentry->sha1_hash, lte->hash); @@ -1046,7 +1101,7 @@ lte_to_wimlib_resource_entry(const struct wim_lookup_table_entry *lte, wentry->is_metadata = (lte->flags & WIM_RESHDR_FLAG_METADATA) != 0; wentry->is_free = (lte->flags & WIM_RESHDR_FLAG_FREE) != 0; wentry->is_spanned = (lte->flags & WIM_RESHDR_FLAG_SPANNED) != 0; - wentry->is_packed_streams = (lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) != 0; + wentry->packed = (lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) != 0; } struct iterate_lte_context { @@ -1135,7 +1190,7 @@ wim_pathname_to_stream(WIMStruct *wim, } } - dentry = get_dentry(wim, path); + dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE); if (p) *p = T(':'); if (!dentry)