#include "wimlib/error.h"
#include "wimlib/lookup_table.h"
#include "wimlib/metadata.h"
+#include "wimlib/pathlist.h"
#include "wimlib/paths.h"
#include "wimlib/reparse.h"
#include "wimlib/resource.h"
# include "wimlib/win32.h" /* for realpath() equivalent */
#endif
#include "wimlib/xml.h"
+#include "wimlib/wildcard.h"
#include "wimlib/wim.h"
#include <errno.h>
#define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000
#define WIMLIB_EXTRACT_FLAG_FROM_PIPE 0x40000000
-#define WIMLIB_EXTRACT_MASK_PUBLIC 0x3fffffff
+#define WIMLIB_EXTRACT_FLAG_PATHMODE 0x20000000
+#define WIMLIB_EXTRACT_MASK_PUBLIC 0x1fffffff
/* Given a WIM dentry in the tree to be extracted, resolve all streams in the
* corresponding inode and set 'out_refcnt' in each to 0. */
ctx->num_streams_remaining++;
}
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) {
+ if (!(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER)) {
struct wim_dentry **lte_dentries;
/* Append dentry to this stream's array of dentries referencing
* This function operates slightly differently depending on whether @lte_spec is
* NULL or not. When @lte_spec is NULL, the behavior is to extract the default
* file contents (unnamed stream), and, if named data streams are supported in
- * the extract mode and volume, any named data streams. When @lte_spec is NULL,
- * the behavior is to extract only all copies of the stream @lte_spec, and in
- * addition use @lte_spec to set the reparse data or create the symbolic link if
- * appropriate.
+ * the extract mode and volume, any named data streams. When @lte_spec is not
+ * NULL, the behavior is to extract only all copies of the stream @lte_spec, and
+ * in addition use @lte_spec to set the reparse data or create the symbolic link
+ * if appropriate.
*
* @path
* Path to file to extract (as can be passed to apply_operations
return 0;
}
-/* Create a file or directory, then immediately extract all streams. This
- * assumes that WIMLIB_EXTRACT_FLAG_SEQUENTIAL is not specified, since the WIM
+/* Create a file or directory, then immediately extract all streams. The WIM
* may not be read sequentially by this function. */
static int
dentry_extract(struct wim_dentry *dentry, void *_ctx)
raw_fd = topen(name, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600);
if (raw_fd < 0) {
- int errno_save = errno;
- FREE(name);
- if (errno_save == EEXIST)
+ if (errno == EEXIST) {
+ FREE(name);
goto retry;
+ }
ERROR_WITH_ERRNO("Failed to open temporary file \"%"TS"\"", name);
+ FREE(name);
return WIMLIB_ERR_OPEN;
}
static int
begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
- bool is_partial_res, void *_ctx)
+ bool is_partial_res,
+ void *_ctx)
{
struct apply_ctx *ctx = _ctx;
int ret;
if (ret)
return ret;
- /* Negative return value here means the function was successful,
- * but the consume_chunk and end_chunk callbacks need not be
- * called. */
- return -1;
+ return BEGIN_STREAM_STATUS_SKIP_STREAM;
}
DEBUG("Temporary file needed for stream (size=%"PRIu64")", lte->size);
static int
extract_stream_list(struct apply_ctx *ctx)
{
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) {
+ if (!(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER)) {
/* Sequential extraction: read the streams in the order in which
* they appear in the WIM file. */
struct read_stream_list_callbacks cbs = {
};
return read_stream_list(&ctx->stream_list,
offsetof(struct wim_lookup_table_entry, extraction_list),
- 0, &cbs);
+ &cbs, VERIFY_STREAM_HASHES);
} else {
/* Extract the streams in unsorted order. */
struct wim_lookup_table_entry *lte;
return 0;
}
- if (buf.stream_hdr.magic != PWM_STREAM_MAGIC) {
+ if (le64_to_cpu(buf.stream_hdr.magic) != PWM_STREAM_MAGIC) {
ERROR("Data read on pipe is invalid (expected stream header).");
return WIMLIB_ERR_INVALID_PIPABLE_WIM;
}
&& (needed_lte = lookup_resource(lookup_table, found_lte->hash))
&& (needed_lte->out_refcnt))
{
- char *tmpfile_name = NULL;
+ tchar *tmpfile_name = NULL;
struct wim_lookup_table_entry *lte_override;
struct wim_lookup_table_entry tmpfile_lte;
struct apply_ctx *ctx = _args;
int ret;
- dentry->in_extraction_tree = 1;
-
if (dentry == ctx->extract_root || dentry->extraction_skipped)
return 0;
goto skip_dentry;
}
-#ifdef __WIN32__
if (!ctx->ops->supports_case_sensitive_filenames)
{
struct wim_dentry *other;
list_for_each_entry(other, &dentry->case_insensitive_conflict_list,
case_insensitive_conflict_list)
{
- if (ctx->extract_flags &
- WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS) {
- WARNING("\"%"TS"\" has the same "
- "case-insensitive name as "
- "\"%"TS"\"; extracting "
- "dummy name instead",
- dentry_full_path(dentry),
- dentry_full_path(other));
- goto out_replace;
- } else {
- WARNING("Not extracting \"%"TS"\": "
- "has same case-insensitive "
- "name as \"%"TS"\"",
- dentry_full_path(dentry),
- dentry_full_path(other));
- goto skip_dentry;
+ if (!other->extraction_skipped) {
+ if (ctx->extract_flags &
+ WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS) {
+ WARNING("\"%"TS"\" has the same "
+ "case-insensitive name as "
+ "\"%"TS"\"; extracting "
+ "dummy name instead",
+ dentry_full_path(dentry),
+ dentry_full_path(other));
+ goto out_replace;
+ } else {
+ WARNING("Not extracting \"%"TS"\": "
+ "has same case-insensitive "
+ "name as \"%"TS"\"",
+ dentry_full_path(dentry),
+ dentry_full_path(other));
+ goto skip_dentry;
+ }
}
}
}
-#else /* __WIN32__ */
- wimlib_assert(ctx->ops->supports_case_sensitive_filenames);
-#endif /* !__WIN32__ */
if (file_name_valid(dentry->file_name, dentry->file_name_nbytes / 2, false)) {
-#ifdef __WIN32__
+#if TCHAR_IS_UTF16LE
dentry->extraction_name = dentry->file_name;
dentry->extraction_name_nchars = dentry->file_name_nbytes / 2;
return 0;
tchar *tchar_name;
size_t tchar_nchars;
- #ifdef __WIN32__
+ #if TCHAR_IS_UTF16LE
tchar_name = utf16_name_copy;
tchar_nchars = dentry->file_name_nbytes / 2;
#else
fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars,
T(" (invalid filename #%lu)"),
++ctx->invalid_sequence);
- #ifndef __WIN32__
+ #if !TCHAR_IS_UTF16LE
FREE(tchar_name);
#endif
dentry->extraction_name = memdup(fixed_name,
struct wim_features *features = _features;
struct wim_inode *inode = dentry->d_inode;
+ if (dentry->extraction_skipped)
+ return 0;
+
if (inode->i_attributes & FILE_ATTRIBUTE_ARCHIVE)
features->archive_files++;
if (inode->i_attributes & FILE_ATTRIBUTE_HIDDEN)
const struct wim_features *supported_features,
int extract_flags,
const struct apply_operations *ops,
- const tchar *wim_source_path)
+ const tchar *wim_source_path,
+ bool warn)
{
const tchar *loc;
const tchar *mode = T("this extraction mode");
else
loc = wim_source_path;
- /* We're an archive program, so theoretically we can do what we want
- * with FILE_ATTRIBUTE_ARCHIVE (which is a dumb flag anyway). Don't
- * bother the user about it. */
+ if (warn) {
+ /* We're an archive program, so theoretically we can do what we want
+ * with FILE_ATTRIBUTE_ARCHIVE (which is a dumb flag anyway). Don't
+ * bother the user about it. */
#if 0
- if (required_features->archive_files && !supported_features->archive_files)
- {
- WARNING(
- "%lu files in %"TS" are marked as archived, but this attribute\n"
-" is not supported in %"TS".",
- required_features->archive_files, loc, mode);
- }
+ if (required_features->archive_files && !supported_features->archive_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as archived, but this attribute\n"
+ " is not supported in %"TS".",
+ required_features->archive_files, loc, mode);
+ }
#endif
- if (required_features->hidden_files && !supported_features->hidden_files)
- {
- WARNING(
- "%lu files in %"TS" are marked as hidden, but this\n"
-" attribute is not supported in %"TS".",
- required_features->hidden_files, loc, mode);
- }
+ if (required_features->hidden_files && !supported_features->hidden_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as hidden, but this\n"
+ " attribute is not supported in %"TS".",
+ required_features->hidden_files, loc, mode);
+ }
- if (required_features->system_files && !supported_features->system_files)
- {
- WARNING(
- "%lu files in %"TS" are marked as system files,\n"
-" but this attribute is not supported in %"TS".",
- required_features->system_files, loc, mode);
- }
+ if (required_features->system_files && !supported_features->system_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as system files,\n"
+ " but this attribute is not supported in %"TS".",
+ required_features->system_files, loc, mode);
+ }
- if (required_features->compressed_files && !supported_features->compressed_files)
- {
- WARNING(
- "%lu files in %"TS" are marked as being transparently\n"
-" compressed, but transparent compression is not supported in\n"
-" %"TS". These files will be extracted as uncompressed.",
- required_features->compressed_files, loc, mode);
- }
+ if (required_features->compressed_files && !supported_features->compressed_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as being transparently\n"
+ " compressed, but transparent compression is not supported in\n"
+ " %"TS". These files will be extracted as uncompressed.",
+ required_features->compressed_files, loc, mode);
+ }
- if (required_features->encrypted_files && !supported_features->encrypted_files)
- {
- WARNING(
- "%lu files in %"TS" are marked as being encrypted,\n"
-" but encryption is not supported in %"TS". These files\n"
-" will not be extracted.",
- required_features->encrypted_files, loc, mode);
- }
+ if (required_features->encrypted_files && !supported_features->encrypted_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as being encrypted,\n"
+ " but encryption is not supported in %"TS". These files\n"
+ " 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->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)
- {
- WARNING(
- "%lu files in %"TS" are marked as not content indexed,\n"
-" but this attribute is not supported in %"TS".",
- required_features->not_context_indexed_files, loc, mode);
- }
+ if (required_features->not_context_indexed_files &&
+ !supported_features->not_context_indexed_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as not content indexed,\n"
+ " but this attribute is not supported in %"TS".",
+ required_features->not_context_indexed_files, loc, mode);
+ }
- if (required_features->sparse_files && !supported_features->sparse_files)
- {
- WARNING(
- "%lu files in %"TS" are marked as sparse, but creating\n"
-" sparse files is not supported in %"TS". These files\n"
-" will be extracted as non-sparse.",
- required_features->sparse_files, loc, mode);
- }
+ if (required_features->sparse_files && !supported_features->sparse_files)
+ {
+ WARNING(
+ "%lu files in %"TS" are marked as sparse, but creating\n"
+ " sparse files is not supported in %"TS". These files\n"
+ " will be extracted as non-sparse.",
+ required_features->sparse_files, loc, mode);
+ }
- if (required_features->named_data_streams &&
- !supported_features->named_data_streams)
- {
- WARNING(
- "%lu files in %"TS" contain one or more alternate (named)\n"
-" data streams, which are not supported in %"TS".\n"
-" Alternate data streams will NOT be extracted.",
- required_features->named_data_streams, loc, mode);
- }
+ if (required_features->named_data_streams &&
+ !supported_features->named_data_streams)
+ {
+ WARNING(
+ "%lu files in %"TS" contain one or more alternate (named)\n"
+ " data streams, which are not supported in %"TS".\n"
+ " Alternate data streams will NOT be extracted.",
+ required_features->named_data_streams, loc, mode);
+ }
- if (unlikely(extract_flags & (WIMLIB_EXTRACT_FLAG_HARDLINK |
- WIMLIB_EXTRACT_FLAG_SYMLINK)) &&
- required_features->named_data_streams &&
- supported_features->named_data_streams)
- {
- WARNING(
- "%lu files in %"TS" contain one or more alternate (named)\n"
-" data streams, which are not supported in linked extraction mode.\n"
-" Alternate data streams will NOT be extracted.",
- required_features->named_data_streams, loc);
- }
+ if (unlikely(extract_flags & (WIMLIB_EXTRACT_FLAG_HARDLINK |
+ WIMLIB_EXTRACT_FLAG_SYMLINK)) &&
+ required_features->named_data_streams &&
+ supported_features->named_data_streams)
+ {
+ WARNING(
+ "%lu files in %"TS" contain one or more alternate (named)\n"
+ " data streams, which are not supported in linked extraction mode.\n"
+ " Alternate data streams will NOT be extracted.",
+ required_features->named_data_streams, loc);
+ }
- if (required_features->hard_links && !supported_features->hard_links)
- {
- WARNING(
- "%lu files in %"TS" are hard links, but hard links are\n"
-" not supported in %"TS". Hard links will be extracted as\n"
-" duplicate copies of the linked files.",
- required_features->hard_links, loc, mode);
- }
+ if (required_features->hard_links && !supported_features->hard_links)
+ {
+ WARNING(
+ "%lu files in %"TS" are hard links, but hard links are\n"
+ " not supported in %"TS". Hard links will be extracted as\n"
+ " duplicate copies of the linked files.",
+ required_features->hard_links, loc, mode);
+ }
- if (required_features->reparse_points && !supported_features->reparse_points)
- {
- if (supported_features->symlink_reparse_points) {
- if (required_features->other_reparse_points) {
+ if (required_features->reparse_points && !supported_features->reparse_points)
+ {
+ if (supported_features->symlink_reparse_points) {
+ if (required_features->other_reparse_points) {
+ WARNING(
+ "%lu files in %"TS" are reparse points that are neither\n"
+ " symbolic links nor junction points and are not supported in\n"
+ " %"TS". These reparse points will not be extracted.",
+ required_features->other_reparse_points, loc,
+ mode);
+ }
+ } else {
WARNING(
- "%lu files in %"TS" are reparse points that are neither\n"
-" symbolic links nor junction points and are not supported in\n"
-" %"TS". These reparse points will not be extracted.",
- required_features->other_reparse_points, loc,
- mode);
+ "%lu files in %"TS" are reparse points, which are\n"
+ " not supported in %"TS" and will not be extracted.",
+ required_features->reparse_points, loc, mode);
}
- } else {
- WARNING(
- "%lu files in %"TS" are reparse points, which are\n"
-" not supported in %"TS" and will not be extracted.",
- required_features->reparse_points, loc, mode);
}
- }
- if (required_features->security_descriptors &&
- !supported_features->security_descriptors)
- {
- WARNING(
- "%lu files in %"TS" have Windows NT security descriptors,\n"
-" but extracting security descriptors is not supported in\n"
-" %"TS". No security descriptors will be extracted.",
- required_features->security_descriptors, loc, mode);
- }
+ if (required_features->security_descriptors &&
+ !supported_features->security_descriptors)
+ {
+ WARNING(
+ "%lu files in %"TS" have Windows NT security descriptors,\n"
+ " but extracting security descriptors is not supported in\n"
+ " %"TS". No security descriptors will be extracted.",
+ required_features->security_descriptors, loc, mode);
+ }
- if (required_features->short_names && !supported_features->short_names)
- {
- WARNING(
- "%lu files in %"TS" have short (DOS) names, but\n"
-" extracting short names is not supported in %"TS".\n"
-" Short names will not be extracted.\n",
- required_features->short_names, loc, mode);
+ if (required_features->short_names && !supported_features->short_names)
+ {
+ WARNING(
+ "%lu files in %"TS" have short (DOS) names, but\n"
+ " extracting short names is not supported in %"TS".\n"
+ " Short names will not be extracted.\n",
+ required_features->short_names, loc, mode);
+ }
}
if ((extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
#endif
}
-/*
- * extract_tree - Extract a file or directory tree from the currently selected
- * WIM image.
- *
- * @wim: WIMStruct for the WIM file, with the desired image selected
- * (as wim->current_image).
- *
- * @wim_source_path:
- * "Canonical" (i.e. no leading or trailing slashes, path
- * separators WIM_PATH_SEPARATOR) path inside the WIM image to
- * extract. An empty string means the full image.
- *
- * @target:
- * Filesystem path to extract the file or directory tree to.
- * (Or, with WIMLIB_EXTRACT_FLAG_NTFS: the name of a NTFS volume.)
- *
- * @extract_flags:
- * WIMLIB_EXTRACT_FLAG_*. Also, the private flag
- * WIMLIB_EXTRACT_FLAG_MULTI_IMAGE will be set if this is being
- * called through wimlib_extract_image() with WIMLIB_ALL_IMAGES as
- * the image.
- *
- * @progress_func:
- * If non-NULL, progress function for the extraction. The messages
- * that may be sent in this function are:
- *
- * WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN or
- * WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN;
- * WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN;
- * WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END;
- * WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY;
- * WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS;
- * WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS;
- * WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END or
- * WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END.
- *
- * Returns 0 on success; a positive WIMLIB_ERR_* code on failure.
- */
static int
-extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
- int extract_flags, wimlib_progress_func_t progress_func)
+dentry_set_skipped(struct wim_dentry *dentry, void *_ignore)
+{
+ dentry->in_extraction_tree = 1;
+ dentry->extraction_skipped = 1;
+ return 0;
+}
+
+static int
+dentry_set_not_skipped(struct wim_dentry *dentry, void *_ignore)
+{
+ dentry->in_extraction_tree = 1;
+ dentry->extraction_skipped = 0;
+ return 0;
+}
+
+static int
+extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
+ const tchar *wim_source_path, const tchar *target,
+ int extract_flags, wimlib_progress_func_t progress_func)
{
- struct wim_dentry *root;
struct wim_features required_features;
struct apply_ctx ctx;
int ret;
struct wim_lookup_table_entry *lte;
+ wimlib_assert(num_trees != 0);
+ wimlib_assert(target != NULL);
+
+ if (num_trees > 1)
+ wimlib_assert((extract_flags & WIMLIB_EXTRACT_FLAG_PATHMODE));
+
/* Start initializing the apply_ctx. */
memset(&ctx, 0, sizeof(struct apply_ctx));
ctx.wim = wim;
}
INIT_LIST_HEAD(&ctx.stream_list);
- /* Translate the path to extract into the corresponding
- * `struct wim_dentry', which will be the root of the
- * "dentry tree" to extract. */
- root = get_dentry(wim, wim_source_path);
- if (!root) {
- ERROR("Path \"%"TS"\" does not exist in WIM image %d",
- wim_source_path, wim->current_image);
- ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST;
- goto out;
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_PATHMODE) {
+ /* Path mode --- there may be multiple trees, and targets are
+ * set relative to the root of the image.
+ *
+ * Consider all dentries to be in the extraction tree, but
+ * assume all to be skipped unless in one of the subtrees being
+ * extracted or one of the ancestors of the subtrees up to the
+ * image root. */
+ ctx.extract_root = wim_root_dentry(wim);
+ for_dentry_in_tree(ctx.extract_root, dentry_set_skipped, NULL);
+
+ for (size_t i = 0; i < num_trees; i++) {
+ struct wim_dentry *d;
+
+ for_dentry_in_tree(trees[i], dentry_set_not_skipped, NULL);
+ d = trees[i];
+ while (d != ctx.extract_root) {
+ d = d->parent;
+ dentry_set_not_skipped(d, NULL);
+ }
+ }
+ } else {
+ ctx.extract_root = trees[0];
+ for_dentry_in_tree(ctx.extract_root, dentry_set_not_skipped, NULL);
}
- ctx.extract_root = root;
-
/* Select the appropriate apply_operations based on the
* platform and extract_flags. */
#ifdef __WIN32__
*/
ret = ctx.ops->start_extract(target, &ctx);
if (ret)
- goto out;
+ goto out_dentry_reset_needs_extraction;
- dentry_tree_get_features(root, &required_features);
+ /* Get and check the features required to extract the dentry tree. */
+ dentry_tree_get_features(ctx.extract_root, &required_features);
ret = do_feature_check(&required_features, &ctx.supported_features,
- extract_flags, ctx.ops, wim_source_path);
+ extract_flags, ctx.ops,
+ wim_source_path,
+ !(extract_flags & WIMLIB_EXTRACT_FLAG_PATHMODE));
if (ret)
goto out_finish_or_abort_extract;
/* Calculate the actual filename component of each extracted dentry. In
* the process, set the dentry->extraction_skipped flag on dentries that
- * are being skipped for some reason (e.g. invalid filename). */
- ret = for_dentry_in_tree(root, dentry_calculate_extraction_path, &ctx);
+ * are being skipped because of filename or supported features problems. */
+ ret = for_dentry_in_tree(ctx.extract_root,
+ dentry_calculate_extraction_path, &ctx);
if (ret)
goto out_dentry_reset_needs_extraction;
* directory tree. (If not, extract_dentry_to_stdout() will
* return an error.) */
if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
- ret = extract_dentry_to_stdout(root);
+ ret = extract_dentry_to_stdout(ctx.extract_root);
goto out_teardown_stream_list;
}
if (!ctx.root_dentry_is_special)
{
tchar path[ctx.ops->path_max];
- if (build_extraction_path(path, root, &ctx))
+ if (build_extraction_path(path, ctx.extract_root, &ctx))
{
- ret = extract_inode(path, &ctx, root->d_inode);
+ ret = extract_inode(path, &ctx, ctx.extract_root->d_inode);
if (ret)
goto out_free_realtarget;
}
}
if (ctx.ops->requires_short_name_reordering) {
- ret = for_dentry_in_tree(root, dentry_extract_dir_skeleton,
+ ret = for_dentry_in_tree(ctx.extract_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 (!(extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER)) {
/* Sequential extraction requested, so two passes are needed
* (one for directory structure, one for streams.) */
if (progress_func)
&ctx.progress);
if (!(extract_flags & WIMLIB_EXTRACT_FLAG_RESUME)) {
- ret = for_dentry_in_tree(root, dentry_extract_skeleton, &ctx);
+ ret = for_dentry_in_tree(ctx.extract_root, dentry_extract_skeleton, &ctx);
if (ret)
goto out_free_realtarget;
}
if (progress_func)
progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN,
&ctx.progress);
- ret = for_dentry_in_tree(root, dentry_extract, &ctx);
+ ret = for_dentry_in_tree(ctx.extract_root, dentry_extract, &ctx);
if (ret)
goto out_free_realtarget;
if (progress_func)
if (progress_func)
progress_func(WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS,
&ctx.progress);
- ret = for_dentry_in_tree_depth(root, dentry_extract_final, &ctx);
+ ret = for_dentry_in_tree_depth(ctx.extract_root, dentry_extract_final, &ctx);
if (ret)
goto out_free_realtarget;
out_teardown_stream_list:
/* Free memory allocated as part of the mapping from each
* wim_lookup_table_entry to the dentries that reference it. */
- if (ctx.extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL)
+ if (!(ctx.extract_flags & WIMLIB_EXTRACT_FLAG_FILE_ORDER))
list_for_each_entry(lte, &ctx.stream_list, extraction_list)
if (lte->out_refcnt > ARRAY_LEN(lte->inline_lte_dentries))
FREE(lte->lte_dentries);
-out_dentry_reset_needs_extraction:
- for_dentry_in_tree(root, dentry_reset_needs_extraction, NULL);
out_finish_or_abort_extract:
if (ret) {
if (ctx.ops->abort_extract)
if (ctx.ops->finish_extract)
ret = ctx.ops->finish_extract(&ctx);
}
-out:
+out_dentry_reset_needs_extraction:
+ for_dentry_in_tree(ctx.extract_root, dentry_reset_needs_extraction, NULL);
return ret;
}
+/*
+ * extract_tree - Extract a file or directory tree from the currently selected
+ * WIM image.
+ *
+ * @wim: WIMStruct for the WIM file, with the desired image selected
+ * (as wim->current_image).
+ *
+ * @wim_source_path:
+ * "Canonical" (i.e. no leading or trailing slashes, path
+ * separators WIM_PATH_SEPARATOR) path inside the WIM image to
+ * extract. An empty string means the full image.
+ *
+ * @target:
+ * Filesystem path to extract the file or directory tree to.
+ * (Or, with WIMLIB_EXTRACT_FLAG_NTFS: the name of a NTFS volume.)
+ *
+ * @extract_flags:
+ * WIMLIB_EXTRACT_FLAG_*. Also, the private flag
+ * WIMLIB_EXTRACT_FLAG_MULTI_IMAGE will be set if this is being
+ * called through wimlib_extract_image() with WIMLIB_ALL_IMAGES as
+ * the image.
+ *
+ * @progress_func:
+ * If non-NULL, progress function for the extraction. The messages
+ * that may be sent in this function are:
+ *
+ * WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN or
+ * WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN;
+ * WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN;
+ * WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END;
+ * WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY;
+ * WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS;
+ * WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS;
+ * WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END or
+ * WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END.
+ *
+ * Returns 0 on success; a positive WIMLIB_ERR_* code on failure.
+ */
+static int
+extract_tree(WIMStruct *wim, const tchar *wim_source_path,
+ const tchar *target, int extract_flags,
+ wimlib_progress_func_t progress_func)
+{
+ struct wim_dentry *root;
+
+ root = get_dentry(wim, wim_source_path, WIMLIB_CASE_PLATFORM_DEFAULT);
+
+ if (root == NULL) {
+ ERROR("Path \"%"TS"\" does not exist in WIM image %d",
+ wim_source_path, wim->current_image);
+ return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
+ }
+ return extract_trees(wim, &root, 1, wim_source_path,
+ target, extract_flags, progress_func);
+}
+
/* Validates a single wimlib_extract_command, mostly checking to make sure the
* extract flags make sense. */
static int
WIMLIB_EXTRACT_FLAG_HARDLINK))
return WIMLIB_ERR_INVALID_PARAM;
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS)
+ return WIMLIB_ERR_INVALID_PARAM;
+
if ((extract_flags &
(WIMLIB_EXTRACT_FLAG_NO_ACLS |
WIMLIB_EXTRACT_FLAG_STRICT_ACLS)) == (WIMLIB_EXTRACT_FLAG_NO_ACLS |
* corresponding file or symbolic link data. This needs to be handled
* better. */
if ((extract_flags & (WIMLIB_EXTRACT_FLAG_UNIX_DATA |
- WIMLIB_EXTRACT_FLAG_SEQUENTIAL))
- == (WIMLIB_EXTRACT_FLAG_UNIX_DATA |
- WIMLIB_EXTRACT_FLAG_SEQUENTIAL))
+ WIMLIB_EXTRACT_FLAG_FILE_ORDER))
+ == WIMLIB_EXTRACT_FLAG_UNIX_DATA)
{
if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
WARNING("Setting UNIX file/owner group may "
" symbolic links "
"when applying from a pipe.");
} else {
- extract_flags &= ~WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
+ extract_flags |= WIMLIB_EXTRACT_FLAG_FILE_ORDER;
WARNING("Disabling sequential extraction for "
"UNIX data mode");
}
if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT)
return WIMLIB_ERR_INVALID_PARAM;
- extract_flags |= WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
-
/* Read the WIM header from the pipe and get a WIMStruct to represent
* the pipable WIM. Caveats: Unlike getting a WIMStruct with
* wimlib_open_wim(), getting a WIMStruct in this way will result in
return do_wimlib_extract_image(wim, image, target, extract_flags,
progress_func);
}
+
+/* API function documented in wimlib.h */
+WIMLIBAPI int
+wimlib_extract_pathlist(WIMStruct *wim, int image,
+ const tchar *target,
+ const tchar *path_list_file,
+ int extract_flags,
+ wimlib_progress_func_t progress_func)
+{
+ int ret;
+ tchar **paths;
+ size_t num_paths;
+ void *mem;
+
+ ret = read_path_list_file(path_list_file, &paths, &num_paths, &mem);
+ if (ret)
+ return ret;
+
+ ret = wimlib_extract_paths(wim, image, target,
+ (const tchar * const *)paths, num_paths,
+ extract_flags, progress_func);
+ FREE(paths);
+ FREE(mem);
+ return ret;
+}
+
+struct append_dentry_ctx {
+ struct wim_dentry **dentries;
+ size_t num_dentries;
+ size_t num_alloc_dentries;
+};
+
+static int
+append_dentry_cb(struct wim_dentry *dentry, void *_ctx)
+{
+ struct append_dentry_ctx *ctx = _ctx;
+
+ if (ctx->num_dentries == ctx->num_alloc_dentries) {
+ struct wim_dentry **new_dentries;
+ size_t new_length;
+
+ new_length = max(ctx->num_alloc_dentries + 8,
+ ctx->num_alloc_dentries * 3 / 2);
+ new_dentries = REALLOC(ctx->dentries,
+ new_length * sizeof(ctx->dentries[0]));
+ if (new_dentries == NULL)
+ return WIMLIB_ERR_NOMEM;
+ ctx->dentries = new_dentries;
+ ctx->num_alloc_dentries = new_length;
+ }
+ ctx->dentries[ctx->num_dentries++] = dentry;
+ return 0;
+}
+
+/* API function documented in wimlib.h */
+WIMLIBAPI int
+wimlib_extract_paths(WIMStruct *wim,
+ int image,
+ const tchar *target,
+ const tchar * const *paths,
+ size_t num_paths,
+ int extract_flags,
+ wimlib_progress_func_t progress_func)
+{
+ int ret;
+ struct append_dentry_ctx append_dentry_ctx = {
+ .dentries = NULL,
+ .num_dentries = 0,
+ .num_alloc_dentries = 0,
+ };
+ struct wim_dentry **trees;
+ size_t num_trees;
+
+ extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
+
+ if (target == NULL || (num_paths != 0 && paths == NULL))
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ ret = select_wim_image(wim, image);
+ if (ret)
+ return ret;
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
+ u32 wildcard_flags = 0;
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB)
+ wildcard_flags |= WILDCARD_FLAG_ERROR_IF_NO_MATCH;
+ else
+ wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH;
+
+ if (default_ignore_case)
+ wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
+
+ for (size_t i = 0; i < num_paths; i++) {
+ ret = expand_wildcard(wim, paths[i],
+ append_dentry_cb,
+ &append_dentry_ctx,
+ wildcard_flags);
+ if (ret) {
+ trees = append_dentry_ctx.dentries;
+ goto out_free_trees;
+ }
+ }
+ trees = append_dentry_ctx.dentries;
+ num_trees = append_dentry_ctx.num_dentries;
+ } else {
+ trees = MALLOC(num_paths * sizeof(trees[0]));
+ if (trees == NULL)
+ return WIMLIB_ERR_NOMEM;
+
+ for (size_t i = 0; i < num_paths; i++) {
+ trees[i] = get_dentry(wim, paths[i],
+ WIMLIB_CASE_PLATFORM_DEFAULT);
+ if (trees[i] == NULL) {
+ ERROR("Path \"%"TS"\" does not exist "
+ "in WIM image %d",
+ paths[i], wim->current_image);
+ ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST;
+ goto out_free_trees;
+ }
+ }
+ num_trees = num_paths;
+ }
+
+ if (num_trees == 0) {
+ ret = 0;
+ goto out_free_trees;
+ }
+
+ ret = extract_trees(wim, trees, num_trees,
+ T(""), target,
+ ((extract_flags &
+ ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS)
+ | WIMLIB_EXTRACT_FLAG_PATHMODE),
+ progress_func);
+out_free_trees:
+ FREE(trees);
+ return ret;
+}