+ int ret;
+ struct list_head *cur, *next;
+ struct wim_lookup_table_entry *lte;
+ struct hasher_context *hasher_ctx;
+ struct read_stream_list_callbacks *sink_cbs;
+
+ if (!(flags & STREAM_LIST_ALREADY_SORTED)) {
+ ret = sort_stream_list_by_sequential_order(stream_list, list_head_offset);
+ if (ret)
+ return ret;
+ }
+
+ if (flags & (VERIFY_STREAM_HASHES | COMPUTE_MISSING_STREAM_HASHES)) {
+ hasher_ctx = alloca(sizeof(*hasher_ctx));
+ *hasher_ctx = (struct hasher_context) {
+ .flags = flags,
+ .cbs = *cbs,
+ };
+ sink_cbs = alloca(sizeof(*sink_cbs));
+ *sink_cbs = (struct read_stream_list_callbacks) {
+ .begin_stream = hasher_begin_stream,
+ .begin_stream_ctx = hasher_ctx,
+ .consume_chunk = hasher_consume_chunk,
+ .consume_chunk_ctx = hasher_ctx,
+ .end_stream = hasher_end_stream,
+ .end_stream_ctx = hasher_ctx,
+ };
+ } else {
+ sink_cbs = (struct read_stream_list_callbacks*)cbs;
+ }
+
+ for (cur = stream_list->next, next = cur->next;
+ cur != stream_list;
+ cur = next, next = cur->next)
+ {
+ lte = (struct wim_lookup_table_entry*)((u8*)cur - list_head_offset);
+
+ if (lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS &&
+ lte->size != lte->rspec->uncompressed_size)
+ {
+
+ struct wim_lookup_table_entry *lte_next, *lte_last;
+ struct list_head *next2;
+ u64 stream_count;
+
+ /* The next stream is a proper sub-sequence of a WIM
+ * resource. See if there are other streams in the same
+ * resource that need to be read. Since
+ * sort_stream_list_by_sequential_order() sorted the
+ * streams by offset in the WIM, this can be determined
+ * by simply scanning forward in the list. */
+
+ lte_last = lte;
+ stream_count = 1;
+ for (next2 = next;
+ next2 != stream_list
+ && (lte_next = (struct wim_lookup_table_entry*)
+ ((u8*)next2 - list_head_offset),
+ lte_next->resource_location == RESOURCE_IN_WIM
+ && lte_next->rspec == lte->rspec);
+ next2 = next2->next)
+ {
+ lte_last = lte_next;
+ stream_count++;
+ }
+ if (stream_count > 1) {
+ /* Reading multiple streams combined into a
+ * single WIM resource. They are in the stream
+ * list, sorted by offset; @lte specifies the
+ * first stream in the resource that needs to be
+ * read and @lte_last specifies the last stream
+ * in the resource that needs to be read. */
+ next = next2;
+ ret = read_packed_streams(lte, lte_last,
+ stream_count,
+ list_head_offset,
+ sink_cbs);
+ if (ret)
+ return ret;
+ continue;
+ }
+ }
+
+ ret = read_full_stream_with_cbs(lte, sink_cbs);
+ if (ret && ret != BEGIN_STREAM_STATUS_SKIP_STREAM)
+ return ret;
+ }
+ return 0;