-static int
-extract_streams_from_pipe(struct apply_ctx *ctx)
-{
- struct wim_lookup_table_entry *found_lte;
- struct wim_resource_spec *rspec;
- struct wim_lookup_table_entry *needed_lte;
- struct wim_lookup_table *lookup_table;
- struct wim_header_disk pwm_hdr;
- int ret;
- int pwm_flags;
-
- ret = WIMLIB_ERR_NOMEM;
- found_lte = new_lookup_table_entry();
- if (found_lte == NULL)
- goto out;
-
- rspec = MALLOC(sizeof(struct wim_resource_spec));
- if (rspec == NULL)
- goto out_free_found_lte;
-
- lookup_table = ctx->wim->lookup_table;
- pwm_flags = PWM_ALLOW_WIM_HDR;
- if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RESUME))
- pwm_flags |= PWM_SILENT_EOF;
- memcpy(ctx->progress.extract.guid, ctx->wim->hdr.guid, WIM_GID_LEN);
- ctx->progress.extract.part_number = ctx->wim->hdr.part_number;
- ctx->progress.extract.total_parts = ctx->wim->hdr.total_parts;
- if (ctx->progress_func)
- ctx->progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN,
- &ctx->progress);
- while (ctx->num_streams_remaining) {
- if (found_lte->resource_location != RESOURCE_NONEXISTENT)
- lte_unbind_wim_resource_spec(found_lte);
- ret = read_pwm_stream_header(ctx->wim, found_lte, rspec,
- pwm_flags, &pwm_hdr);
- if (ret) {
- if (ret == WIMLIB_ERR_UNEXPECTED_END_OF_FILE &&
- (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RESUME))
- {
- goto resume_done;
- }
- goto out_free_found_lte;
- }
-
- if ((found_lte->resource_location != RESOURCE_NONEXISTENT)
- && !(found_lte->flags & WIM_RESHDR_FLAG_METADATA)
- && (needed_lte = lookup_stream(lookup_table, found_lte->hash))
- && (needed_lte->out_refcnt))
- {
- tchar *tmpfile_name = NULL;
- struct wim_lookup_table_entry *lte_override;
- struct wim_lookup_table_entry tmpfile_lte;
-
- needed_lte->offset_in_res = found_lte->offset_in_res;
- needed_lte->flags = found_lte->flags;
- needed_lte->size = found_lte->size;
-
- lte_unbind_wim_resource_spec(found_lte);
- lte_bind_wim_resource_spec(needed_lte, rspec);
-
- if (needed_lte->out_refcnt > 1) {
-
- struct filedes tmpfile_fd;
-
- /* Extract stream to temporary file. */
- ret = create_temporary_file(&tmpfile_fd, &tmpfile_name);
- if (ret) {
- lte_unbind_wim_resource_spec(needed_lte);
- goto out_free_found_lte;
- }
-
- ret = extract_full_stream_to_fd(needed_lte,
- &tmpfile_fd);
- if (ret) {
- filedes_close(&tmpfile_fd);
- goto delete_tmpfile;
- }
-
- if (filedes_close(&tmpfile_fd)) {
- ERROR_WITH_ERRNO("Error writing to temporary "
- "file \"%"TS"\"", tmpfile_name);
- ret = WIMLIB_ERR_WRITE;
- goto delete_tmpfile;
- }
- memcpy(&tmpfile_lte, needed_lte,
- sizeof(struct wim_lookup_table_entry));
- tmpfile_lte.resource_location = RESOURCE_IN_FILE_ON_DISK;
- tmpfile_lte.file_on_disk = tmpfile_name;
- lte_override = &tmpfile_lte;
- } else {
- lte_override = needed_lte;
- }
-
- ret = extract_stream_instances(needed_lte, lte_override, ctx);
- delete_tmpfile:
- lte_unbind_wim_resource_spec(needed_lte);
- if (tmpfile_name) {
- tunlink(tmpfile_name);
- FREE(tmpfile_name);
- }
- if (ret)
- goto out_free_found_lte;
- ctx->num_streams_remaining--;
- } else if (found_lte->resource_location != RESOURCE_NONEXISTENT) {
- ret = skip_wim_stream(found_lte);
- if (ret)
- goto out_free_found_lte;
- } else {
- u16 part_number = le16_to_cpu(pwm_hdr.part_number);
- u16 total_parts = le16_to_cpu(pwm_hdr.total_parts);
+/*
+ * Read the list of blobs to extract and feed their data into the specified
+ * callback functions.
+ *
+ * This handles checksumming each blob.
+ *
+ * This also handles sending WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS.
+ *
+ * This also works if the WIM is being read from a pipe.
+ *
+ * This also will split up blobs that will need to be extracted to more than
+ * MAX_OPEN_FILES locations, as measured by the 'out_refcnt' of each blob.
+ * Therefore, the apply_operations implementation need not worry about running
+ * out of file descriptors, unless it might open more than one file descriptor
+ * per 'blob_extraction_target' (e.g. Win32 currently might because the
+ * destination file system might not support hard links).
+ */
+int
+extract_blob_list(struct apply_ctx *ctx, const struct read_blob_callbacks *cbs)
+{
+ struct read_blob_callbacks wrapper_cbs = {
+ .begin_blob = begin_extract_blob,
+ .continue_blob = extract_chunk,
+ .end_blob = end_extract_blob,
+ .ctx = ctx,
+ };
+ ctx->saved_cbs = cbs;
+ if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
+ return read_blobs_from_pipe(ctx, &wrapper_cbs);
+ } else {
+ int flags = VERIFY_BLOB_HASHES;