X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Flookup_table.c;h=496cc8ee078e23e91f606d5756f46e0c58dba45a;hp=d08498f8371328f356a01ca4d5764a95f909cc88;hb=45d7e8a4f1740974e1dacd221676f9ec38c6b272;hpb=f24f8409b041727329e980fdc81e84a7c9b00e5b diff --git a/src/lookup_table.c b/src/lookup_table.c index d08498f8..496cc8ee 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -464,6 +464,27 @@ struct wim_lookup_table_entry_disk { #define WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE 50 +static int +validate_resource(const struct wim_resource_spec *rspec) +{ + struct wim_lookup_table_entry *lte; + if (!list_is_singular(&rspec->lte_list)) { + list_for_each_entry(lte, &rspec->lte_list, wim_resource_list) { + if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) + lte->flags |= WIM_RESHDR_FLAG_COMPRESSED; + else + lte->flags &= ~WIM_RESHDR_FLAG_COMPRESSED; + + if (lte->offset_in_res + lte->size < lte->size || + lte->offset_in_res + lte->size > rspec->uncompressed_size) + { + return WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; + } + } + } + return 0; +} + /* * Reads the lookup table from a WIM file. * @@ -484,8 +505,8 @@ read_wim_lookup_table(WIMStruct *wim) size_t num_entries; struct wim_lookup_table *table; struct wim_lookup_table_entry *cur_entry, *duplicate_entry; + struct wim_resource_spec *cur_rspec; void *buf; - bool in_concat_run; BUILD_BUG_ON(sizeof(struct wim_lookup_table_entry_disk) != WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE); @@ -503,7 +524,7 @@ read_wim_lookup_table(WIMStruct *wim) /* Allocate hash table. */ table = new_lookup_table(num_entries * 2 + 1); - if (!table) { + if (table == NULL) { ERROR("Not enough memory to read lookup table."); ret = WIMLIB_ERR_NOMEM; goto out_free_buf; @@ -512,17 +533,29 @@ read_wim_lookup_table(WIMStruct *wim) /* Allocate and initalize `struct wim_lookup_table_entry's from the * on-disk lookup table. */ wim->current_image = 0; - in_concat_run = false; + cur_rspec = NULL; for (i = 0; i < num_entries; i++) { const struct wim_lookup_table_entry_disk *disk_entry = &((const struct wim_lookup_table_entry_disk*)buf)[i]; u16 part_number; struct wim_reshdr reshdr; - struct wim_resource_spec *cur_rspec; + + ret = get_wim_reshdr(&disk_entry->reshdr, &reshdr); + if (ret) { + ERROR("Resource header is invalid!"); + goto out_free_lookup_table; + } + + 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); cur_entry = new_lookup_table_entry(); if (cur_entry == NULL) { - ERROR("Not enough memory to read lookup table."); + ERROR("Not enough memory to read lookup table!"); ret = WIMLIB_ERR_NOMEM; goto out_free_lookup_table; } @@ -538,23 +571,75 @@ read_wim_lookup_table(WIMStruct *wim) free_lookup_table_entry(cur_entry); continue; } - if (is_zero_hash(cur_entry->hash)) { - WARNING("The WIM lookup table contains an entry with a " - "SHA1 message digest of all 0's (ignoring it)"); + + if (cur_rspec == NULL || + !(reshdr.flags & WIM_RESHDR_FLAG_CONCAT)) + { + /* Starting new run of stream entries that all share the + * same WIM resource (streams concatenated together); or + * simply a single normal entry by itself. */ + + if (cur_rspec != NULL) { + ret = validate_resource(cur_rspec); + if (ret) + goto out_free_cur_entry; + } + + cur_rspec = MALLOC(sizeof(struct wim_resource_spec)); + if (cur_rspec == NULL) { + ERROR("Not enough memory to read lookup table!"); + ret = WIMLIB_ERR_NOMEM; + goto out_free_cur_entry; + } + wim_res_hdr_to_spec(&reshdr, wim, cur_rspec); + if (reshdr.flags & WIM_RESHDR_FLAG_CONCAT) { + cur_rspec->size_in_wim = 0; + cur_rspec->uncompressed_size = 0; + } + } else if (is_zero_hash(cur_entry->hash)) { + /* Found the resource specification for the run. */ + cur_rspec->offset_in_wim = reshdr.offset_in_wim; + cur_rspec->size_in_wim = reshdr.size_in_wim; + cur_rspec->flags = reshdr.flags; + DEBUG("Full run is %"PRIu64" compressed bytes " + "at file offset %"PRIu64" (flags 0x%02x)", + cur_rspec->size_in_wim, + cur_rspec->offset_in_wim, + cur_rspec->flags); free_lookup_table_entry(cur_entry); continue; } - cur_rspec = MALLOC(sizeof(struct wim_resource_spec)); - if (cur_rspec == NULL) { - ERROR("Not enough memory to read lookup table."); - ret = WIMLIB_ERR_NOMEM; - goto out_free_cur_entry; + if (reshdr.flags & WIM_RESHDR_FLAG_CONCAT) { + /* Continuing the run with another stream. */ + DEBUG("Continuing concat run with stream: " + "%"PRIu64" uncompressed bytes @ resource offset %"PRIu64")", + reshdr.size_in_wim, reshdr.offset_in_wim); + cur_rspec->uncompressed_size += reshdr.size_in_wim; } - get_wim_reshdr(&disk_entry->reshdr, &reshdr); - wim_res_hdr_to_spec(&reshdr, wim, cur_rspec); lte_bind_wim_resource_spec(cur_entry, cur_rspec); + if (reshdr.flags & WIM_RESHDR_FLAG_CONCAT) { + /* In concatenation runs, the offset field is used for + * in-resource offset, not the in-WIM offset, and the + * size field is used for the uncompressed size, not the + * compressed size. */ + cur_entry->offset_in_res = reshdr.offset_in_wim; + cur_entry->size = reshdr.size_in_wim; + cur_entry->flags = reshdr.flags; + } else { + cur_entry->offset_in_res = 0; + cur_entry->size = reshdr.uncompressed_size; + cur_entry->flags = reshdr.flags; + cur_rspec = NULL; + } + + if (is_zero_hash(cur_entry->hash)) { + WARNING("The WIM lookup table contains an entry with a " + "SHA1 message digest of all 0's (ignoring it)"); + free_lookup_table_entry(cur_entry); + continue; + } if (cur_entry->flags & WIM_RESHDR_FLAG_METADATA) { /* Lookup table entry for a metadata resource */ @@ -623,6 +708,12 @@ read_wim_lookup_table(WIMStruct *wim) } } + if (cur_rspec != NULL) { + ret = validate_resource(cur_rspec); + if (ret) + goto out_free_cur_entry; + } + if (wim->hdr.part_number == 1 && wim->current_image != wim->hdr.image_count) { WARNING("The header of \"%"TS"\" says there are %u images in\n" " the WIM, but we only found %d metadata resources! Acting as if\n" @@ -829,27 +920,41 @@ print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out) return; } - tfprintf(out, T("Reference Count = %u\n"), lte->refcnt); - tfprintf(out, T("Uncompressed Size = %"PRIu64" bytes\n"), lte->size); - if (lte->resource_location == RESOURCE_IN_WIM) { - tfprintf(out, T("Offset in WIM = %"PRIu64" bytes\n"), - lte->rspec->offset_in_wim); + tprintf(T("Uncompressed size = %"PRIu64" bytes\n"), + lte->size); + if (lte_is_partial(lte)) { + tprintf(T("Offset = %"PRIu64" bytes\n"), + lte->offset_in_res); + + tprintf(T("Raw uncompressed size = %"PRIu64" bytes\n"), + lte->rspec->uncompressed_size); + + tprintf(T("Raw compressed size = %"PRIu64" bytes\n"), + lte->rspec->size_in_wim); + + tprintf(T("Raw offset = %"PRIu64" bytes\n"), + lte->rspec->offset_in_wim); + } else if (lte->resource_location == RESOURCE_IN_WIM) { + tprintf(T("Compressed size = %"PRIu64" bytes\n"), + lte->rspec->size_in_wim); - tfprintf(out, T("Size in WIM = %"PRIu64" bytes\n"), - lte->rspec->size_in_wim); + tprintf(T("Offset = %"PRIu64" bytes\n"), + lte->rspec->offset_in_wim); } + tfprintf(out, T("Reference Count = %u\n"), lte->refcnt); + if (lte->unhashed) { tfprintf(out, T("(Unhashed: inode %p, stream_id = %u)\n"), lte->back_inode, lte->back_stream_id); } else { - tfprintf(out, T("Hash = 0x")); + tfprintf(out, T("Hash = 0x")); print_hash(lte->hash, out); tputc(T('\n'), out); } - tfprintf(out, T("Flags = ")); + tfprintf(out, T("Flags = ")); u8 flags = lte->flags; if (flags & WIM_RESHDR_FLAG_COMPRESSED) tfputs(T("WIM_RESHDR_FLAG_COMPRESSED, "), out); @@ -865,7 +970,7 @@ print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out) switch (lte->resource_location) { case RESOURCE_IN_WIM: if (lte->rspec->wim->filename) { - tfprintf(out, T("WIM file = `%"TS"'\n"), + tfprintf(out, T("WIM file = `%"TS"'\n"), lte->rspec->wim->filename); } break; @@ -873,12 +978,12 @@ print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out) case RESOURCE_WIN32_ENCRYPTED: #endif case RESOURCE_IN_FILE_ON_DISK: - tfprintf(out, T("File on Disk = `%"TS"'\n"), + tfprintf(out, T("File on Disk = `%"TS"'\n"), lte->file_on_disk); break; #ifdef WITH_FUSE case RESOURCE_IN_STAGING_FILE: - tfprintf(out, T("Staging File = `%"TS"'\n"), + tfprintf(out, T("Staging File = `%"TS"'\n"), lte->staging_file_name); break; #endif @@ -892,16 +997,21 @@ void lte_to_wimlib_resource_entry(const struct wim_lookup_table_entry *lte, struct wimlib_resource_entry *wentry) { - wentry->uncompressed_size = lte->size; + memset(wentry, 0, sizeof(*wentry)); + wentry->uncompressed_size = lte->size; if (lte->resource_location == RESOURCE_IN_WIM) { - wentry->compressed_size = lte->rspec->size_in_wim; - wentry->offset = lte->rspec->offset_in_wim; wentry->part_number = lte->rspec->wim->hdr.part_number; - } else { - wentry->compressed_size = 0; - wentry->offset = 0; - wentry->part_number = 0; + if (lte_is_partial(lte)) { + wentry->compressed_size = 0; + wentry->offset = lte->offset_in_res; + } else { + wentry->compressed_size = lte->rspec->size_in_wim; + 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_compressed_size = lte->rspec->size_in_wim; } copy_hash(wentry->sha1_hash, lte->hash); wentry->reference_count = lte->refcnt; @@ -909,6 +1019,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_partial = lte_is_partial(lte); } struct iterate_lte_context { @@ -1291,7 +1402,7 @@ hash_unhashed_stream(struct wim_lookup_table_entry *lte, * the SHA1 has been calculated. */ back_ptr = retrieve_lte_pointer(lte); - ret = sha1_resource(lte); + ret = sha1_stream(lte); if (ret) return ret;