if (!lte)
return 0;
- if (likely(!is_linked_extraction(ctx)) || (lte->out_refcnt == 0 &&
- lte->extracted_file == NULL))
+ /* Tally the size only for each extraction of the stream (not hard
+ * links). */
+ if (!(dentry->d_inode->i_visited &&
+ ctx->supported_features.hard_links) &&
+ (!is_linked_extraction(ctx) || (lte->out_refcnt == 0 &&
+ lte->extracted_file == NULL)))
{
ctx->progress.extract.total_bytes += wim_resource_size(lte);
ctx->progress.extract.num_streams++;
}
+ /* Add stream to the extraction_list only one time, even if it's going
+ * to be extracted to multiple locations. */
if (lte->out_refcnt == 0) {
list_add_tail(<e->extraction_list, &ctx->stream_list);
ctx->num_streams_remaining++;
* extracted (ctx->stream_list) if not already done so, and also update the
* progress information (ctx->progress) with the stream. Furthermore, if doing
* a sequential extraction, build a mapping from each the stream to the dentries
- * referencing it. */
+ * referencing it.
+ *
+ * This uses the i_visited member of the inodes (assumed to be 0 initially). */
static int
dentry_add_streams_to_extract(struct wim_dentry *dentry, void *_ctx)
{
if (dentry->extraction_skipped)
return 0;
- /* Don't process additional hard links. */
- if (inode->i_visited && ctx->supported_features.hard_links)
- return 0;
-
/* The unnamed data stream will always be extracted, except in an
* unlikely case. */
if (!inode_is_encrypted_directory(inode)) {
} else
#endif /* !__WIN32__ */
if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
- ret = ctx->ops->create_directory(path, ctx);
+ ret = ctx->ops->create_directory(path, ctx, &inode->extract_cookie);
if (ret) {
ERROR_WITH_ERRNO("Failed to create the directory "
"\"%"TS"\"", path);
}
+ } else if ((inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) &&
+ ctx->ops->extract_encrypted_stream_creates_file &&
+ ctx->supported_features.encrypted_files) {
+ ret = ctx->ops->extract_encrypted_stream(
+ path, inode_unnamed_lte_resolved(inode), ctx);
+ if (ret) {
+ ERROR_WITH_ERRNO("Failed to create and extract "
+ "encrypted file \"%"TS"\"", path);
+ }
} else {
- ret = ctx->ops->create_file(path, ctx);
+ ret = ctx->ops->create_file(path, ctx, &inode->extract_cookie);
if (ret) {
ERROR_WITH_ERRNO("Failed to create the file "
"\"%"TS"\"", path);
{
struct wim_inode *inode = dentry->d_inode;
struct wim_lookup_table_entry *lte;
+ file_spec_t file_spec;
int ret;
if (dentry->was_hardlinked)
}
#endif
+ if (ctx->ops->uses_cookies)
+ file_spec.cookie = inode->extract_cookie;
+ else
+ file_spec.path = path;
+
/* Unnamed data stream. */
lte = inode_unnamed_lte_resolved(inode);
if (lte && (!lte_spec || lte == lte_spec)) {
if (!(inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
FILE_ATTRIBUTE_REPARSE_POINT)))
{
- if ((inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) &&
- ctx->supported_features.encrypted_files)
- ret = ctx->ops->extract_encrypted_stream(path, lte, ctx);
- else
- ret = ctx->ops->extract_unnamed_stream(path, lte, ctx);
- if (ret)
- goto error;
+ if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED &&
+ ctx->supported_features.encrypted_files) {
+ if (!ctx->ops->extract_encrypted_stream_creates_file) {
+ ret = ctx->ops->extract_encrypted_stream(
+ path, lte, ctx);
+ if (ret)
+ goto error;
+ }
+ } else {
+ ret = ctx->ops->extract_unnamed_stream(
+ file_spec, lte, ctx);
+ if (ret)
+ goto error;
+ }
update_extract_progress(ctx, lte);
}
else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
continue;
if (lte_spec)
lte = lte_override;
- ret = ctx->ops->extract_named_stream(path, entry->stream_name,
+ ret = ctx->ops->extract_named_stream(file_spec, entry->stream_name,
entry->stream_name_nbytes / 2,
lte, ctx);
if (ret)
* extraction mode. */
static int
extract_file_attributes(const tchar *path, struct apply_ctx *ctx,
- struct wim_dentry *dentry)
+ struct wim_dentry *dentry, unsigned pass)
{
int ret;
- if (ctx->ops->set_file_attributes) {
- if (dentry == ctx->extract_root && ctx->root_dentry_is_special)
- return 0;
- ret = ctx->ops->set_file_attributes(path,
- dentry->d_inode->i_attributes,
- ctx);
+ if (ctx->ops->set_file_attributes &&
+ !(dentry == ctx->extract_root && ctx->root_dentry_is_special)) {
+ u32 attributes = dentry->d_inode->i_attributes;
+
+ /* Clear unsupported attributes. */
+ attributes &= ctx->supported_attributes_mask;
+
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY &&
+ !ctx->supported_features.encrypted_directories) ||
+ (!(attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ !ctx->supported_features.encrypted_files))
+ {
+ attributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
+ }
+
+ if (attributes == 0)
+ attributes = FILE_ATTRIBUTE_NORMAL;
+
+ ret = ctx->ops->set_file_attributes(path, attributes, ctx, pass);
if (ret) {
ERROR_WITH_ERRNO("Failed to set attributes on "
"\"%"TS"\"", path);
desc_size = sd->sizes[inode->i_security_id];
ret = ctx->ops->set_security_descriptor(path, desc,
- desc_size, ctx,
- !!(ctx->extract_flags &
- WIMLIB_EXTRACT_FLAG_STRICT_ACLS));
+ desc_size, ctx);
if (ret) {
if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS) {
ERROR_WITH_ERRNO("Failed to set security "
"descriptor on \"%"TS"\"", path);
return ret;
} else {
+ #if 0
if (errno != EACCES) {
WARNING_WITH_ERRNO("Failed to set "
"security descriptor "
"on \"%"TS"\"", path);
}
+ #endif
+ ctx->no_security_descriptors++;
}
}
}
struct wim_inode *inode = dentry->d_inode;
if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- if (supported_features->reparse_points)
- return true;
- if (supported_features->symlink_reparse_points &&
- inode_is_symlink(inode))
- return true;
- return false;
+ return supported_features->reparse_points ||
+ (inode_is_symlink(inode) &&
+ supported_features->symlink_reparse_points);
+ }
+ if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
+ if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+ return supported_features->encrypted_directories != 0;
+ else
+ return supported_features->encrypted_files != 0;
}
return true;
}
get_num_path_components(const tchar *path, tchar path_separator)
{
unsigned num_components = 0;
+#ifdef __WIN32__
+ /* Ignore drive letter. */
+ if (path[0] != L'\0' && path[1] == L':')
+ path += 2;
+#endif
while (*path) {
while (*path == path_separator)
num_target_path_components--;
}
- p_old = oldpath;
+ p_old = oldpath + ctx->ops->path_prefix_nchars;
+#ifdef __WIN32__
+ if (p_old[0] != L'\0' && p_old[1] == ':')
+ p_old += 2;
+#endif
while (*p_old == ctx->ops->path_separator)
p_old++;
while (--num_target_path_components) {
/* Create empty named data streams. */
if (can_extract_named_data_streams(ctx)) {
for (u16 i = 0; i < inode->i_num_ads; i++) {
+ file_spec_t file_spec;
struct wim_ads_entry *entry = &inode->i_ads_entries[i];
if (!ads_entry_is_named_stream(entry))
continue;
if (entry->lte)
continue;
- ret = ctx->ops->extract_named_stream(path,
+ if (ctx->ops->uses_cookies)
+ file_spec.cookie = inode->extract_cookie;
+ else
+ file_spec.path = path;
+ ret = ctx->ops->extract_named_stream(file_spec,
entry->stream_name,
entry->stream_name_nbytes / 2,
entry->lte, ctx);
}
/* Set file attributes (if supported). */
- ret = extract_file_attributes(path, ctx, dentry);
+ ret = extract_file_attributes(path, ctx, dentry, 0);
if (ret)
return ret;
return 0;
}
+/* This is a wrapper around do_dentry_extract_skeleton() that handles building
+ * the path, doing short name reordering. This is also idempotent; dentries
+ * already processed have skeleton_extracted set and no action is taken. See
+ * apply_operations.requires_short_name_reordering for more details about short
+ * name reordering. */
static int
dentry_extract_skeleton(struct wim_dentry *dentry, void *_ctx)
{
struct apply_ctx *ctx = _ctx;
tchar path[ctx->ops->path_max];
+ struct wim_dentry *orig_dentry;
+ struct wim_dentry *other_dentry;
+ int ret;
+
+ if (dentry->skeleton_extracted)
+ return 0;
+ orig_dentry = NULL;
+ if (ctx->supported_features.short_names
+ && ctx->ops->requires_short_name_reordering
+ && !dentry_has_short_name(dentry)
+ && !dentry->d_inode->i_dos_name_extracted)
+ {
+ inode_for_each_dentry(other_dentry, dentry->d_inode) {
+ if (dentry_has_short_name(other_dentry)
+ && !other_dentry->skeleton_extracted)
+ {
+ DEBUG("Creating %"TS" before %"TS" "
+ "to guarantee correct DOS name extraction",
+ dentry_full_path(other_dentry),
+ dentry_full_path(dentry));
+ orig_dentry = dentry;
+ dentry = other_dentry;
+ break;
+ }
+ }
+ }
+again:
if (!build_extraction_path(path, dentry, ctx))
return 0;
- return do_dentry_extract_skeleton(path, dentry, ctx);
+ ret = do_dentry_extract_skeleton(path, dentry, ctx);
+ if (ret)
+ return ret;
+
+ dentry->skeleton_extracted = 1;
+
+ if (orig_dentry) {
+ dentry = orig_dentry;
+ orig_dentry = NULL;
+ goto again;
+ }
+ dentry->d_inode->i_dos_name_extracted = 1;
+ return 0;
+}
+
+static int
+dentry_extract_dir_skeleton(struct wim_dentry *dentry, void *_ctx)
+{
+ if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+ return dentry_extract_skeleton(dentry, _ctx);
+ return 0;
}
/* Create a file or directory, then immediately extract all streams. This
tchar path[ctx->ops->path_max];
int ret;
- if (!build_extraction_path(path, dentry, ctx))
- return 0;
-
- ret = do_dentry_extract_skeleton(path, dentry, ctx);
+ ret = dentry_extract_skeleton(dentry, ctx);
if (ret)
return ret;
+ if (!build_extraction_path(path, dentry, ctx))
+ return 0;
+
return extract_streams(path, ctx, dentry, NULL, NULL);
}
return 0;
}
+#define PWM_ALLOW_WIM_HDR 0x00001
+#define PWM_SILENT_EOF 0x00002
+
/* Read the header from a stream in a pipable WIM. */
static int
read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte,
- bool allow_header)
+ int flags, struct wim_header_disk *hdr_ret)
{
- struct pwm_stream_hdr stream_hdr;
+ union {
+ struct pwm_stream_hdr stream_hdr;
+ struct wim_header_disk pwm_hdr;
+ } buf;
int ret;
- ret = full_read(&pwm->in_fd, &stream_hdr, sizeof(stream_hdr));
+ ret = full_read(&pwm->in_fd, &buf.stream_hdr, sizeof(buf.stream_hdr));
if (ret)
goto read_error;
- if (allow_header && stream_hdr.magic == PWM_MAGIC) {
- u8 buf[WIM_HEADER_DISK_SIZE - sizeof(stream_hdr)];
- ret = full_read(&pwm->in_fd, buf, sizeof(buf));
+ if ((flags & PWM_ALLOW_WIM_HDR) && buf.stream_hdr.magic == PWM_MAGIC) {
+ BUILD_BUG_ON(sizeof(buf.pwm_hdr) < sizeof(buf.stream_hdr));
+ ret = full_read(&pwm->in_fd, &buf.stream_hdr + 1,
+ sizeof(buf.pwm_hdr) - sizeof(buf.stream_hdr));
+
if (ret)
goto read_error;
lte->resource_location = RESOURCE_NONEXISTENT;
+ memcpy(hdr_ret, &buf.pwm_hdr, sizeof(buf.pwm_hdr));
return 0;
}
- if (stream_hdr.magic != PWM_STREAM_MAGIC) {
+ if (buf.stream_hdr.magic != PWM_STREAM_MAGIC) {
ERROR("Data read on pipe is invalid (expected stream header).");
return WIMLIB_ERR_INVALID_PIPABLE_WIM;
}
- lte->resource_entry.original_size = le64_to_cpu(stream_hdr.uncompressed_size);
- copy_hash(lte->hash, stream_hdr.hash);
- lte->resource_entry.flags = le32_to_cpu(stream_hdr.flags);
+ lte->resource_entry.original_size = le64_to_cpu(buf.stream_hdr.uncompressed_size);
+ copy_hash(lte->hash, buf.stream_hdr.hash);
+ lte->resource_entry.flags = le32_to_cpu(buf.stream_hdr.flags);
lte->resource_entry.offset = pwm->in_fd.offset;
lte->resource_location = RESOURCE_IN_WIM;
lte->wim = pwm;
return 0;
read_error:
- ERROR_WITH_ERRNO("Error reading pipable WIM from pipe");
+ if (ret != WIMLIB_ERR_UNEXPECTED_END_OF_FILE || !(flags & PWM_SILENT_EOF))
+ ERROR_WITH_ERRNO("Error reading pipable WIM from pipe");
return ret;
}
struct wim_lookup_table_entry *found_lte;
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();
goto out;
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) {
- ret = read_pwm_stream_header(ctx->wim, found_lte, true);
- if (ret)
+ ret = read_pwm_stream_header(ctx->wim, found_lte, 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->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
ret = skip_pwm_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);
+
+ if (part_number != ctx->progress.extract.part_number ||
+ total_parts != ctx->progress.extract.total_parts ||
+ memcmp(pwm_hdr.guid, ctx->progress.extract.guid,
+ WIM_GID_LEN))
+ {
+ ctx->progress.extract.part_number = part_number;
+ ctx->progress.extract.total_parts = total_parts;
+ memcpy(ctx->progress.extract.guid,
+ pwm_hdr.guid, WIM_GID_LEN);
+ if (ctx->progress_func) {
+ ctx->progress_func(
+ WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN,
+ &ctx->progress);
+ }
+
+ }
}
}
ret = 0;
free_lookup_table_entry(found_lte);
out:
return ret;
+
+resume_done:
+ /* TODO */
+ return 0;
}
/* Finish extracting a file, directory, or symbolic link by setting file
if (ret)
return ret;
+ if (ctx->ops->requires_final_set_attributes_pass) {
+ /* Set file attributes (if supported). */
+ ret = extract_file_attributes(path, ctx, dentry, 1);
+ if (ret)
+ return ret;
+ }
+
return extract_timestamps(path, ctx, dentry);
}
dentry->extraction_skipped = 0;
dentry->was_hardlinked = 0;
+ dentry->skeleton_extracted = 0;
inode->i_visited = 0;
FREE(inode->i_extracted_file);
inode->i_extracted_file = NULL;
+ inode->i_dos_name_extracted = 0;
if ((void*)dentry->extraction_name != (void*)dentry->file_name)
FREE(dentry->extraction_name);
dentry->extraction_name = NULL;
features->system_files++;
if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED)
features->compressed_files++;
- if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
- features->encrypted_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
+ if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+ features->encrypted_directories++;
+ else
+ features->encrypted_files++;
+ }
if (inode->i_attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
features->not_context_indexed_files++;
if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE)
return 0;
}
-static int
-dentry_clear_inode_visited(struct wim_dentry *dentry, void *_ignore)
-{
- dentry->d_inode->i_visited = 0;
- return 0;
-}
-
/* Tally the features necessary to extract a dentry tree. */
static void
dentry_tree_get_features(struct wim_dentry *root, struct wim_features *features)
{
memset(features, 0, sizeof(struct wim_features));
for_dentry_in_tree(root, dentry_tally_features, features);
- for_dentry_in_tree(root, dentry_clear_inode_visited, NULL);
+ dentry_tree_clear_inode_visited(root);
+}
+
+static u32
+compute_supported_attributes_mask(const struct wim_features *supported_features)
+{
+ u32 mask = ~(u32)0;
+
+ if (!supported_features->archive_files)
+ mask &= ~FILE_ATTRIBUTE_ARCHIVE;
+
+ if (!supported_features->hidden_files)
+ mask &= ~FILE_ATTRIBUTE_HIDDEN;
+
+ if (!supported_features->system_files)
+ mask &= ~FILE_ATTRIBUTE_SYSTEM;
+
+ if (!supported_features->not_context_indexed_files)
+ mask &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+
+ if (!supported_features->compressed_files)
+ mask &= ~FILE_ATTRIBUTE_COMPRESSED;
+
+ if (!supported_features->sparse_files)
+ mask &= ~FILE_ATTRIBUTE_SPARSE_FILE;
+
+ if (!supported_features->reparse_points)
+ mask &= ~FILE_ATTRIBUTE_REPARSE_POINT;
+
+ return mask;
}
static int
const tchar *wim_source_path)
{
const tchar *loc;
- const tchar *mode = "this extraction mode";
+ const tchar *mode = T("this extraction mode");
if (wim_source_path[0] == '\0')
- loc = "the WIM image";
+ loc = T("the WIM image");
else
loc = wim_source_path;
WARNING(
"%lu files in %"TS" are marked as being encrypted,\n"
" but encryption is not supported in %"TS". These files\n"
-" will be extracted as raw encrypted data instead.",
+" will not be extracted.",
required_features->encrypted_files, loc, mode);
}
+ if (required_features->encrypted_directories &&
+ !supported_features->encrypted_directories)
+ {
+ WARNING(
+ "%lu directories in %"TS" are marked as being encrypted,\n"
+" but encryption is not supported in %"TS".\n"
+" These directories will be extracted as unencrypted.",
+ required_features->encrypted_directories, loc, mode);
+ }
+
if (required_features->not_context_indexed_files &&
!supported_features->not_context_indexed_files)
{
return WIMLIB_ERR_UNSUPPORTED;
}
+ if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS) &&
+ required_features->symlink_reparse_points &&
+ !(supported_features->symlink_reparse_points ||
+ supported_features->reparse_points))
+ {
+ ERROR("Extracting symbolic links is not supported in %"TS, mode);
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+
if ((extract_flags & WIMLIB_EXTRACT_FLAG_SYMLINK) &&
!supported_features->symlink_reparse_points)
{
return 0;
}
+static void
+do_extract_warnings(struct apply_ctx *ctx)
+{
+ if (ctx->partial_security_descriptors == 0 &&
+ ctx->no_security_descriptors == 0)
+ return;
+
+ WARNING("Extraction of \"%"TS"\" complete, but with one or more warnings:",
+ ctx->target);
+ if (ctx->partial_security_descriptors != 0) {
+ WARNING("- Could only partially set the security descriptor\n"
+ " on %lu files or directories.",
+ ctx->partial_security_descriptors);
+ }
+ if (ctx->no_security_descriptors != 0) {
+ WARNING("- Could not set security descriptor at all\n"
+ " on %lu files or directories.",
+ ctx->no_security_descriptors);
+ }
+#ifdef __WIN32__
+ WARNING("To fully restore all security descriptors, run the program\n"
+ " with Administrator rights.");
+#endif
+}
+
/*
* extract_tree - Extract a file or directory tree from the currently selected
* WIM image.
if (ret)
goto out_finish_or_abort_extract;
+ ctx.supported_attributes_mask =
+ compute_supported_attributes_mask(&ctx.supported_features);
+
/* Figure out whether the root dentry is being extracted to the root of
* a volume and therefore needs to be treated "specially", for example
* not being explicitly created and not having attributes set. */
* However, we can get a reasonably accurate estimate by taking
* <TOTALBYTES> from the corresponding <IMAGE> in the WIM XML
* data. This does assume that a full image is being extracted,
- * but currently there is no API for doing otherwise. */
+ * but currently there is no API for doing otherwise. (Also,
+ * subtract <HARDLINKBYTES> from this if hard links are
+ * supported by the extraction mode.) */
ctx.progress.extract.total_bytes =
wim_info_get_image_total_bytes(wim->wim_info,
wim->current_image);
+ if (ctx.supported_features.hard_links) {
+ ctx.progress.extract.total_bytes -=
+ wim_info_get_image_hard_link_bytes(wim->wim_info,
+ wim->current_image);
+ }
}
/* Handle the special case of extracting a file to standard
ctx.realtarget_nchars = tstrlen(ctx.realtarget);
}
+ if (ctx.ops->requires_short_name_reordering) {
+ ret = for_dentry_in_tree(root, dentry_extract_dir_skeleton,
+ &ctx);
+ if (ret)
+ goto out_free_realtarget;
+ }
+
/* Finally, the important part: extract the tree of files. */
if (extract_flags & (WIMLIB_EXTRACT_FLAG_SEQUENTIAL |
WIMLIB_EXTRACT_FLAG_FROM_PIPE)) {
if (progress_func)
progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN,
&ctx.progress);
- ret = for_dentry_in_tree(root, dentry_extract_skeleton, &ctx);
- if (ret)
- goto out_free_realtarget;
+
+ if (!(extract_flags & WIMLIB_EXTRACT_FLAG_RESUME)) {
+ ret = for_dentry_in_tree(root, dentry_extract_skeleton, &ctx);
+ if (ret)
+ goto out_free_realtarget;
+ }
if (progress_func)
progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END,
&ctx.progress);
&ctx.progress);
}
+ do_extract_warnings(&ctx);
+
ret = 0;
out_free_realtarget:
FREE(ctx.realtarget);
WIMLIB_EXTRACT_FLAG_NORPFIX))
return WIMLIB_ERR_INVALID_PARAM;
+ if ((extract_flags &
+ (WIMLIB_EXTRACT_FLAG_RESUME |
+ WIMLIB_EXTRACT_FLAG_FROM_PIPE)) == WIMLIB_EXTRACT_FLAG_RESUME)
+ return WIMLIB_ERR_INVALID_PARAM;
+
if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
#ifndef WITH_NTFS_3G
ERROR("wimlib was compiled without support for NTFS-3g, so\n"
* WIMs.) */
{
struct wim_lookup_table_entry xml_lte;
- ret = read_pwm_stream_header(pwm, &xml_lte, false);
+ ret = read_pwm_stream_header(pwm, &xml_lte, 0, NULL);
if (ret)
goto out_wimlib_free;
goto out_wimlib_free;
}
- ret = read_pwm_stream_header(pwm, metadata_lte, false);
+ ret = read_pwm_stream_header(pwm, metadata_lte, 0, NULL);
imd = pwm->image_metadata[i - 1];
imd->metadata_lte = metadata_lte;
if (ret)