- int ret;
- struct wim_lookup_table_entry *lte, *tmp;
-
- list_for_each_entry_safe(lte, tmp, my_resources, staging_list) {
- ret = write_wim_resource(lte,
- out_fp,
- out_ctype,
- <e->output_resource_entry,
- write_resource_flags);
- if (ret != 0)
- return ret;
- list_del(<e->staging_list);
- progress->write_streams.completed_bytes +=
- wim_resource_size(lte);
- progress->write_streams.completed_streams++;
- if (progress_func) {
- progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
- progress);
+ int ret = 0;
+ struct wim_lookup_table_entry *lte;
+ bool stream_discarded;
+
+ /* For each stream in @stream_list ... */
+ while (!list_empty(stream_list)) {
+ stream_discarded = false;
+ lte = container_of(stream_list->next,
+ struct wim_lookup_table_entry,
+ write_streams_list);
+ list_del(<e->write_streams_list);
+ if (lte->unhashed && !lte->unique_size) {
+ /* Unhashed stream that shares a size with some other
+ * stream in the WIM we are writing. The stream must be
+ * checksummed to know if we need to write it or not. */
+ struct wim_lookup_table_entry *tmp;
+ u32 orig_refcnt = lte->out_refcnt;
+
+ ret = hash_unhashed_stream(lte, lookup_table, &tmp);
+ if (ret)
+ break;
+ if (tmp != lte) {
+ lte = tmp;
+ /* We found a duplicate stream. */
+ if (orig_refcnt != tmp->out_refcnt) {
+ /* We have already written, or are going
+ * to write, the duplicate stream. So
+ * just skip to the next stream. */
+ DEBUG("Discarding duplicate stream of length %"PRIu64,
+ wim_resource_size(lte));
+ lte->no_progress = 0;
+ stream_discarded = true;
+ goto skip_to_progress;
+ }
+ }
+ }
+
+ /* Here, @lte is either a hashed stream or an unhashed stream
+ * with a unique size. In either case we know that the stream
+ * has to be written. In either case the SHA1 message digest
+ * will be calculated over the stream while writing it; however,
+ * in the former case this is done merely to check the data,
+ * while in the latter case this is done because we do not have
+ * the SHA1 message digest yet. */
+ wimlib_assert(lte->out_refcnt != 0);
+ lte->deferred = 0;
+ lte->no_progress = 0;
+ ret = (*write_stream_cb)(lte, write_stream_ctx);
+ if (ret)
+ break;
+ /* In parallel mode, some streams are deferred for later,
+ * serialized processing; ignore them here. */
+ if (lte->deferred)
+ continue;
+ if (lte->unhashed) {
+ list_del(<e->unhashed_list);
+ lookup_table_insert(lookup_table, lte);
+ lte->unhashed = 0;
+ }
+ skip_to_progress:
+ if (!lte->no_progress) {
+ do_write_streams_progress(progress,
+ progress_func,
+ wim_resource_size(lte),
+ stream_discarded);