#include "wimlib/reparse.h"
#include "wimlib/resource.h"
#include "wimlib/security.h"
-#include "wimlib/swm.h"
#ifdef __WIN32__
# include "wimlib/win32.h" /* for realpath() equivalent */
#endif
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.total_bytes += lte->size;
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)) {
wimlib_progress_func_t progress_func = ctx->progress_func;
union wimlib_progress_info *progress = &ctx->progress;
- progress->extract.completed_bytes += wim_resource_size(lte);
+ progress->extract.completed_bytes += lte->size;
if (progress_func &&
progress->extract.completed_bytes >= ctx->next_progress)
{
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, &inode->extract_cookie);
if (ret) {
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(file_spec, lte, ctx);
- else
- ret = ctx->ops->extract_unnamed_stream(file_spec, 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)
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 wim_dentry *other_dentry;
int ret;
- /* Here we may re-order the extraction of multiple names (hard links)
- * for the same file in the same directory in order to ensure the short
- * (DOS) name is set correctly. A short name is always associated with
- * exactly one long name, and at least on NTFS, only one long name for a
- * file can have a short name associated with it. (More specifically,
- * there can be unlimited names in the POSIX namespace, but only one
- * name can be in the Win32+DOS namespace, or one name in the Win32
- * namespace with a corresponding name in the DOS namespace.) To ensure
- * the short name of a file is associated with the correct long name in
- * a directory, we extract the long name with a corresponding short name
- * before any additional names. This can affect NTFS-3g extraction
- * (which uses ntfs_set_ntfs_dos_name(), which doesn't allow specifying
- * the long name to associate with a short name) and may affect Win32
- * extraction as well (which uses SetFileShortName()). */
-
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
- && other_dentry->parent == dentry->parent)
+ && other_dentry->in_extraction_tree)
{
DEBUG("Creating %"TS" before %"TS" "
"to guarantee correct DOS name extraction",
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
* assumes that WIMLIB_EXTRACT_FLAG_SEQUENTIAL is not specified, since the WIM
* may not be read sequentially by this function. */
goto out_free_lte_tmp;
}
filedes_init(&fd, raw_fd);
- ret = extract_wim_resource_to_fd(lte, &fd,
- wim_resource_size(lte));
+ ret = extract_wim_resource_to_fd(lte, &fd, lte->size);
if (filedes_close(&fd) && !ret)
ret = WIMLIB_ERR_WRITE;
if (ret)
/* Read the header from a stream in a pipable WIM. */
static int
read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte,
+ struct wim_resource_spec *rspec,
int flags, struct wim_header_disk *hdr_ret)
{
union {
struct pwm_stream_hdr stream_hdr;
struct wim_header_disk pwm_hdr;
} buf;
+ struct wim_reshdr reshdr;
int ret;
ret = full_read(&pwm->in_fd, &buf.stream_hdr, sizeof(buf.stream_hdr));
return WIMLIB_ERR_INVALID_PIPABLE_WIM;
}
- 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;
- if (lte->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED) {
- lte->compression_type = pwm->compression_type;
- lte->resource_entry.size = 0;
- } else {
- lte->compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
- lte->resource_entry.size = lte->resource_entry.original_size;
- }
- lte->is_pipable = 1;
+
+ reshdr.size_in_wim = 0;
+ reshdr.flags = le32_to_cpu(buf.stream_hdr.flags);
+ reshdr.offset_in_wim = pwm->in_fd.offset;
+ reshdr.uncompressed_size = le64_to_cpu(buf.stream_hdr.uncompressed_size);
+ wim_res_hdr_to_spec(&reshdr, pwm, rspec);
+ lte_bind_wim_resource_spec(lte, rspec);
+ lte->flags = rspec->flags;
+ lte->size = rspec->uncompressed_size;
+ lte->offset_in_res = 0;
return 0;
read_error:
return ret;
}
+static int
+skip_pwm_chunk_cb(const void *chunk, size_t chunk_size, void *_ctx)
+{
+ return 0;
+}
+
/* Skip over an unneeded stream in a pipable WIM being read from a pipe. */
static int
skip_pwm_stream(struct wim_lookup_table_entry *lte)
{
- return read_partial_wim_resource(lte, wim_resource_size(lte),
- NULL, NULL,
- WIMLIB_READ_RESOURCE_FLAG_SEEK_ONLY,
+ return read_partial_wim_resource(lte,
+ lte->size,
+ skip_pwm_chunk_cb,
+ lte_cchunk_size(lte),
+ NULL,
+ WIMLIB_READ_RESOURCE_FLAG_RAW_CHUNKS,
0);
}
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;
ret = WIMLIB_ERR_NOMEM;
found_lte = new_lookup_table_entry();
- if (!found_lte)
+ 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))
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, pwm_flags,
- &pwm_hdr);
+ 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))
}
if ((found_lte->resource_location != RESOURCE_NONEXISTENT)
- && !(found_lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
- && (needed_lte = __lookup_resource(lookup_table, found_lte->hash))
+ && !(found_lte->flags & WIM_RESHDR_FLAG_METADATA)
+ && (needed_lte = lookup_resource(lookup_table, found_lte->hash))
&& (needed_lte->out_refcnt))
{
- copy_resource_entry(&needed_lte->resource_entry,
- &found_lte->resource_entry);
- needed_lte->resource_location = found_lte->resource_location;
- needed_lte->wim = found_lte->wim;
- needed_lte->compression_type = found_lte->compression_type;
- needed_lte->is_pipable = found_lte->is_pipable;
-
+ lte_unbind_wim_resource_spec(found_lte);
+ lte_bind_wim_resource_spec(needed_lte, rspec);
ret = extract_stream_instances(needed_lte, ctx, false);
+ lte_unbind_wim_resource_spec(needed_lte);
+
if (ret)
goto out_free_found_lte;
ctx->num_streams_remaining--;
}
ret = 0;
out_free_found_lte:
+ if (found_lte->resource_location != RESOURCE_IN_WIM)
+ FREE(rspec);
free_lookup_table_entry(found_lte);
out:
return ret;
if (lte) {
struct filedes _stdout;
filedes_init(&_stdout, STDOUT_FILENO);
- ret = extract_wim_resource_to_fd(lte, &_stdout,
- wim_resource_size(lte));
+ ret = extract_wim_resource_to_fd(lte, &_stdout, lte->size);
}
}
return ret;
struct apply_ctx *ctx = _args;
int ret;
+ dentry->in_extraction_tree = 1;
+
if (dentry == ctx->extract_root || dentry->extraction_skipped)
return 0;
{
struct wim_inode *inode = dentry->d_inode;
+ dentry->in_extraction_tree = 0;
dentry->extraction_skipped = 0;
dentry->was_hardlinked = 0;
dentry->skeleton_extracted = 0;
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
ctx->no_security_descriptors == 0)
return;
- WARNING("Extraction of \"%"TS"\" complete, but with one or more warnings:",
+ WARNING("Extraction to \"%"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"
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)) {
const struct wimlib_extract_command *cmds,
size_t num_cmds,
int default_extract_flags,
- WIMStruct **additional_swms,
- unsigned num_additional_swms,
wimlib_progress_func_t progress_func)
{
int ret;
default_extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
- ret = verify_swm_set(wim, additional_swms, num_additional_swms);
- if (ret)
- goto out;
-
if (num_cmds == 0)
- goto out;
-
- if (num_additional_swms)
- merge_lookup_tables(wim, additional_swms, num_additional_swms);
+ return 0;
cmds_copy = CALLOC(num_cmds, sizeof(cmds[0]));
- if (!cmds_copy) {
- ret = WIMLIB_ERR_NOMEM;
- goto out_restore_lookup_table;
- }
+ if (!cmds_copy)
+ return WIMLIB_ERR_NOMEM;
for (size_t i = 0; i < num_cmds; i++) {
cmds_copy[i].extract_flags = (default_extract_flags |
FREE(cmds_copy[i].fs_dest_path);
}
FREE(cmds_copy);
-out_restore_lookup_table:
- if (num_additional_swms)
- unmerge_lookup_table(wim);
-out:
return ret;
}
{
int ret;
tchar *target_copy = canonicalize_fs_path(target);
- if (!target_copy)
+ if (target_copy == NULL)
return WIMLIB_ERR_NOMEM;
struct wimlib_extract_command cmd = {
.wim_source_path = T(""),
int image,
const tchar *target,
int extract_flags,
- WIMStruct **additional_swms,
- unsigned num_additional_swms,
wimlib_progress_func_t progress_func)
{
int ret;
- if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
- wimlib_assert(wim->hdr.part_number == 1);
- wimlib_assert(num_additional_swms == 0);
- } else {
- ret = verify_swm_set(wim, additional_swms, num_additional_swms);
- if (ret)
- return ret;
-
- if (num_additional_swms)
- merge_lookup_tables(wim, additional_swms, num_additional_swms);
- }
-
if (image == WIMLIB_ALL_IMAGES) {
ret = extract_all_images(wim, target, extract_flags,
progress_func);
lte_free_extracted_file,
NULL);
}
- if (num_additional_swms)
- unmerge_lookup_table(wim);
return ret;
}
* wimlib_open_wim(), getting a WIMStruct in this way will result in
* an empty lookup table, no XML data read, and no filename set. */
ret = open_wim_as_WIMStruct(&pipe_fd,
- WIMLIB_OPEN_FLAG_FROM_PIPE |
- WIMLIB_OPEN_FLAG_SPLIT_OK,
+ WIMLIB_OPEN_FLAG_FROM_PIPE,
&pwm, progress_func);
if (ret)
return ret;
* WIMs.) */
{
struct wim_lookup_table_entry xml_lte;
- ret = read_pwm_stream_header(pwm, &xml_lte, 0, NULL);
+ struct wim_resource_spec xml_rspec;
+ ret = read_pwm_stream_header(pwm, &xml_lte, &xml_rspec, 0, NULL);
if (ret)
goto out_wimlib_free;
- if (!(xml_lte.resource_entry.flags & WIM_RESHDR_FLAG_METADATA))
+ if (!(xml_lte.flags & WIM_RESHDR_FLAG_METADATA))
{
ERROR("Expected XML data, but found non-metadata "
"stream.");
goto out_wimlib_free;
}
- copy_resource_entry(&pwm->hdr.xml_res_entry,
- &xml_lte.resource_entry);
+ wim_res_spec_to_hdr(&xml_rspec, &pwm->hdr.xml_data_reshdr);
ret = read_wim_xml_data(pwm);
if (ret)
goto out_wimlib_free;
+
if (wim_info_get_num_images(pwm->wim_info) != pwm->hdr.image_count) {
ERROR("Image count in XML data is not the same as in WIM header.");
ret = WIMLIB_ERR_XML;
for (i = 1; i <= pwm->hdr.image_count; i++) {
struct wim_lookup_table_entry *metadata_lte;
struct wim_image_metadata *imd;
+ struct wim_resource_spec *metadata_rspec;
metadata_lte = new_lookup_table_entry();
- if (!metadata_lte) {
+ if (metadata_lte == NULL) {
ret = WIMLIB_ERR_NOMEM;
goto out_wimlib_free;
}
+ metadata_rspec = MALLOC(sizeof(struct wim_resource_spec));
+ if (metadata_rspec == NULL) {
+ ret = WIMLIB_ERR_NOMEM;
+ free_lookup_table_entry(metadata_lte);
+ goto out_wimlib_free;
+ }
- ret = read_pwm_stream_header(pwm, metadata_lte, 0, NULL);
+ ret = read_pwm_stream_header(pwm, metadata_lte, metadata_rspec, 0, NULL);
imd = pwm->image_metadata[i - 1];
imd->metadata_lte = metadata_lte;
- if (ret)
+ if (ret) {
+ FREE(metadata_rspec);
goto out_wimlib_free;
+ }
- if (!(metadata_lte->resource_entry.flags &
- WIM_RESHDR_FLAG_METADATA))
- {
+ if (!(metadata_lte->flags & WIM_RESHDR_FLAG_METADATA)) {
ERROR("Expected metadata resource, but found "
"non-metadata stream.");
ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
/* Extract the image. */
extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
ret = do_wimlib_extract_image(pwm, image, target,
- extract_flags, NULL, 0, progress_func);
+ extract_flags, progress_func);
/* Clean up and return. */
out_wimlib_free:
wimlib_free(pwm);
int image,
const tchar *target,
int extract_flags,
- WIMStruct **additional_swms,
- unsigned num_additional_swms,
wimlib_progress_func_t progress_func)
{
extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
return do_wimlib_extract_image(wim, image, target, extract_flags,
- additional_swms, num_additional_swms,
progress_func);
}