+
+ if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
+ /* Just extracting to temporary file for now. */
+ ret = full_write(&ctx->tmpfile_fd, chunk, size);
+ if (ret) {
+ ERROR_WITH_ERRNO("Error writing data to "
+ "temporary file \"%"TS"\"",
+ ctx->tmpfile_name);
+ }
+ return ret;
+ } else {
+ return (*ctx->saved_cbs->consume_chunk)(chunk, size,
+ ctx->saved_cbs->consume_chunk_ctx);
+ }
+}
+
+static int
+extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx)
+{
+ struct blob_descriptor tmpfile_blob;
+ struct blob_descriptor *orig_blob = ctx->cur_blob;
+ const struct read_blob_list_callbacks *cbs = ctx->saved_cbs;
+ int ret;
+ const u32 orig_refcnt = orig_blob->out_refcnt;
+
+ BUILD_BUG_ON(MAX_OPEN_FILES <
+ ARRAY_LEN(orig_blob->inline_blob_extraction_targets));
+
+ struct blob_extraction_target *targets = orig_blob->blob_extraction_targets;
+
+ /* Copy the blob's data from the temporary file to each of its targets.
+ *
+ * This is executed only in the very uncommon case that a blob is being
+ * extracted to more than MAX_OPEN_FILES targets! */
+
+ memcpy(&tmpfile_blob, orig_blob, sizeof(struct blob_descriptor));
+ tmpfile_blob.blob_location = BLOB_IN_FILE_ON_DISK;
+ tmpfile_blob.file_on_disk = ctx->tmpfile_name;
+ ret = 0;
+ for (u32 i = 0; i < orig_refcnt; i++) {
+
+ /* Note: it usually doesn't matter whether we pass the original
+ * blob descriptor to callbacks provided by the extraction
+ * backend as opposed to the tmpfile blob descriptor, since they
+ * shouldn't actually read data from the blob other than through
+ * the read_blob_prefix() call below. But for
+ * WIMLIB_EXTRACT_FLAG_WIMBOOT mode on Windows it does matter
+ * because it needs access to the original WIM resource
+ * descriptor in order to create the external backing reference.
+ */
+
+ orig_blob->out_refcnt = 1;
+ orig_blob->inline_blob_extraction_targets[0] = targets[i];
+
+ ret = (*cbs->begin_blob)(orig_blob, cbs->begin_blob_ctx);
+ if (ret)
+ break;
+
+ /* Extra SHA-1 isn't necessary here, but it shouldn't hurt as
+ * this case is very rare anyway. */
+ ret = extract_blob(&tmpfile_blob, tmpfile_blob.size,
+ cbs->consume_chunk,
+ cbs->consume_chunk_ctx);
+
+ ret = (*cbs->end_blob)(orig_blob, ret, cbs->end_blob_ctx);
+ if (ret)
+ break;
+ }
+ FREE(targets);
+ orig_blob->out_refcnt = 0;
+ return ret;
+}
+
+static int
+end_extract_blob_wrapper(struct blob_descriptor *blob, int status, void *_ctx)
+{
+ struct apply_ctx *ctx = _ctx;
+
+ if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
+ filedes_close(&ctx->tmpfile_fd);
+ if (!status)
+ status = extract_from_tmpfile(ctx->tmpfile_name, ctx);
+ filedes_invalidate(&ctx->tmpfile_fd);
+ tunlink(ctx->tmpfile_name);
+ FREE(ctx->tmpfile_name);
+ return status;
+ } else {
+ return (*ctx->saved_cbs->end_blob)(blob, status,
+ ctx->saved_cbs->end_blob_ctx);
+ }