+ /* Checked for packed resource specification. */
+ if (unlikely((reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) &&
+ reshdr.uncompressed_size == WIM_PACK_MAGIC_NUMBER))
+ {
+ /* Found the specification for the packed resource.
+ * 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". */
+
+ /* The uncompressed size of the packed resource 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 out;
+
+ 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_XPRESS != 1);
+ BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 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,
+ cur_rspec->offset_in_wim,
+ cur_rspec->flags);
+ goto free_cur_entry_and_continue;
+ }
+
+ /* Ignore entries with all zeroes in the hash field. */
+ if (is_zero_hash(cur_entry->hash))
+ goto free_cur_entry_and_continue;
+
+ if (reshdr.flags & WIM_RESHDR_FLAG_METADATA) {
+
+ /* Lookup table entry for a metadata resource. */
+
+ /* Metadata entries with no references must be ignored.
+ * See, for example, the WinPE WIMs from the WAIK v2.1.
+ */
+ if (cur_entry->refcnt == 0)
+ goto free_cur_entry_and_continue;
+
+ if (cur_entry->refcnt != 1) {
+ /* We don't currently support this case due to
+ * the complications of multiple images sharing
+ * the same metadata resource or a metadata
+ * resource also being referenced by files.
+ */
+ ERROR("Found metadata resource with refcnt != 1");
+ 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");
+ goto free_cur_entry_and_continue;
+ }
+
+ /* The number of entries in the lookup table with
+ * WIM_RESHDR_FLAG_METADATA set should be the same as
+ * the image_count field in the WIM header. */
+ if (image_index == wim->hdr.image_count) {
+ WARNING("Found more metadata resources than images");
+ goto free_cur_entry_and_continue;
+ }
+
+ /* Notice very carefully: We are assigning the metadata
+ * resources to images in the same order in which their
+ * lookup table entries occur on disk. (This is also
+ * the behavior of Microsoft's software.) In
+ * particular, 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_lte = cur_entry;
+ } else {
+ /* Lookup table entry for a non-metadata stream. */
+
+ /* Ignore this stream if it's a duplicate. */
+ if (lookup_stream(table, cur_entry->hash)) {
+ num_duplicate_entries++;
+ goto free_cur_entry_and_continue;
+ }
+
+ /* Insert the stream into the in-memory lookup table,
+ * keyed by its SHA1 message digest. */
+ lookup_table_insert(table, cur_entry);
+ }
+
+ /* Add the stream to the current resource specification. */
+ lte_bind_wim_resource_spec(cur_entry, cur_rspec);
+ if (reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) {
+ /* In packed 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;
+ /* cur_rspec stays the same */