WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE | \
WIMLIB_EXTRACT_FLAG_WIMBOOT)
+/* Send WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE or
+ * WIMLIB_PROGRESS_MSG_EXTRACT_METADATA. */
+int
+do_file_extract_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg)
+{
+ ctx->count_until_file_progress = 512; /* Arbitrary value to limit calls */
+ return extract_progress(ctx, msg);
+}
+
/* Check whether the extraction of a dentry should be skipped completely. */
static bool
dentry_is_supported(struct wim_dentry *dentry,
lte_unbind_wim_resource_spec(found_lte);
lte_bind_wim_resource_spec(needed_lte, rspec);
- ret = (*cbs->begin_stream)(needed_lte, 0,
+ ret = (*cbs->begin_stream)(needed_lte,
cbs->begin_stream_ctx);
if (ret) {
lte_unbind_wim_resource_spec(needed_lte);
}
ret = 0;
out:
- if (found_lte->resource_location != RESOURCE_IN_WIM)
+ if (found_lte && found_lte->resource_location != RESOURCE_IN_WIM)
FREE(rspec);
free_lookup_table_entry(found_lte);
return ret;
}
static int
-begin_extract_stream_wrapper(struct wim_lookup_table_entry *lte,
- u32 flags, void *_ctx)
+begin_extract_stream_wrapper(struct wim_lookup_table_entry *lte, void *_ctx)
{
struct apply_ctx *ctx = _ctx;
ctx->cur_stream = lte;
+ ctx->cur_stream_offset = 0;
if (unlikely(lte->out_refcnt > MAX_OPEN_STREAMS))
return create_temporary_file(&ctx->tmpfile_fd, &ctx->tmpfile_name);
else
- return (*ctx->saved_cbs->begin_stream)(lte, flags,
- ctx->saved_cbs->begin_stream_ctx);
+ return (*ctx->saved_cbs->begin_stream)(lte, ctx->saved_cbs->begin_stream_ctx);
}
static int
union wimlib_progress_info *progress = &ctx->progress;
int ret;
+ ctx->cur_stream_offset += size;
+
if (likely(ctx->supported_features.hard_links)) {
progress->extract.completed_bytes +=
(u64)size * ctx->cur_stream->out_refcnt;
+ if (ctx->cur_stream_offset == ctx->cur_stream->size)
+ progress->extract.completed_streams += ctx->cur_stream->out_refcnt;
} else {
const struct stream_owner *owners = stream_owners(ctx->cur_stream);
for (u32 i = 0; i < ctx->cur_stream->out_refcnt; i++) {
d_extraction_alias_node)
{
progress->extract.completed_bytes += size;
+ if (ctx->cur_stream_offset == ctx->cur_stream->size)
+ progress->extract.completed_streams++;
}
}
}
{
ctx->next_progress = UINT64_MAX;
} else {
- ctx->next_progress += progress->extract.total_bytes / 128;
- if (ctx->next_progress > progress->extract.total_bytes)
+ /* Send new message as soon as another 1/128 of the
+ * total has been extracted. (Arbitrary number.) */
+ ctx->next_progress =
+ progress->extract.completed_bytes +
+ progress->extract.total_bytes / 128;
+
+ /* ... Unless that would be more than 5000000 bytes, in
+ * which case send the next after the next 5000000
+ * bytes. (Another arbitrary number.) */
+ if (progress->extract.completed_bytes + 5000000 <
+ ctx->next_progress)
+ ctx->next_progress =
+ progress->extract.completed_bytes + 5000000;
+
+ /* ... But always send a message as soon as we're
+ * completely done. */
+ if (progress->extract.total_bytes < ctx->next_progress)
ctx->next_progress = progress->extract.total_bytes;
}
}
}
static int
-extract_from_tmpfile(const tchar *tmpfile_name,
- struct wim_lookup_table_entry *orig_lte,
- struct apply_ctx *ctx)
+extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx)
{
struct wim_lookup_table_entry tmpfile_lte;
- const struct stream_owner *owners = stream_owners(orig_lte);
+ struct wim_lookup_table_entry *orig_lte = ctx->cur_stream;
+ const struct read_stream_list_callbacks *cbs = ctx->saved_cbs;
int ret;
+ const u32 orig_refcnt = orig_lte->out_refcnt;
+
+ BUILD_BUG_ON(MAX_OPEN_STREAMS < ARRAY_LEN(orig_lte->inline_stream_owners));
+
+ struct stream_owner *owners = orig_lte->stream_owners;
/* Copy the stream's data from the temporary file to each of its
* destinations.
memcpy(&tmpfile_lte, orig_lte, sizeof(struct wim_lookup_table_entry));
tmpfile_lte.resource_location = RESOURCE_IN_FILE_ON_DISK;
tmpfile_lte.file_on_disk = ctx->tmpfile_name;
- tmpfile_lte.out_refcnt = 1;
+ ret = 0;
+ for (u32 i = 0; i < orig_refcnt; i++) {
+
+ /* Note: it usually doesn't matter whether we pass the original
+ * stream entry to callbacks provided by the extraction backend
+ * as opposed to the tmpfile stream entry, since they shouldn't
+ * actually read data from the stream other than through the
+ * read_stream_prefix() call below. But for
+ * WIMLIB_EXTRACT_FLAG_WIMBOOT mode on Windows it does matter
+ * because it needs the original stream location in order to
+ * create the external backing reference. */
- for (u32 i = 0; i < orig_lte->out_refcnt; i++) {
- tmpfile_lte.inline_stream_owners[0] = owners[i];
- ret = read_full_stream_with_cbs(&tmpfile_lte, ctx->saved_cbs);
+ orig_lte->out_refcnt = 1;
+ orig_lte->inline_stream_owners[0] = owners[i];
+
+ ret = (*cbs->begin_stream)(orig_lte, cbs->begin_stream_ctx);
if (ret)
- return ret;
+ break;
+
+ /* Extra SHA-1 isn't necessary here, but it shouldn't hurt as
+ * this case is very rare anyway. */
+ ret = extract_stream(&tmpfile_lte, tmpfile_lte.size,
+ cbs->consume_chunk,
+ cbs->consume_chunk_ctx);
+
+ ret = (*cbs->end_stream)(orig_lte, ret, cbs->end_stream_ctx);
+ if (ret)
+ break;
}
- return 0;
+ FREE(owners);
+ orig_lte->out_refcnt = 0;
+ return ret;
}
static int
if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
filedes_close(&ctx->tmpfile_fd);
if (!status)
- status = extract_from_tmpfile(ctx->tmpfile_name,
- stream, ctx);
+ status = extract_from_tmpfile(ctx->tmpfile_name, ctx);
filedes_invalidate(&ctx->tmpfile_fd);
tunlink(ctx->tmpfile_name);
FREE(ctx->tmpfile_name);
return 0;
ctx->progress.extract.total_bytes += lte->size;
- ctx->progress.extract.num_streams++;
+ ctx->progress.extract.total_streams++;
if (inode->i_visited)
return 0;
}
#endif
-#ifndef __WIN32__
if (extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
+#ifdef __WIN32__
+ if (!wim->filename)
+ return WIMLIB_ERR_NO_FILENAME;
+#else
ERROR("WIMBoot extraction is only supported on Windows!");
return WIMLIB_ERR_UNSUPPORTED;
- }
#endif
+ }
+
if ((extract_flags & (WIMLIB_EXTRACT_FLAG_RPFIX |
WIMLIB_EXTRACT_FLAG_NORPFIX |