#include "wimlib/reparse.h"
#include "wimlib/resource.h"
#include "wimlib/security.h"
+#include "wimlib/unix_data.h"
#ifdef __WIN32__
# include "wimlib/win32.h" /* for realpath() equivalent */
#endif
#include <sys/stat.h>
#include <unistd.h>
-#define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000
-#define WIMLIB_EXTRACT_FLAG_FROM_PIPE 0x40000000
-#define WIMLIB_EXTRACT_FLAG_IMAGEMODE 0x20000000
+#define WIMLIB_EXTRACT_FLAG_FROM_PIPE 0x80000000
+#define WIMLIB_EXTRACT_FLAG_IMAGEMODE 0x40000000
/* Keep in sync with wimlib.h */
#define WIMLIB_EXTRACT_MASK_PUBLIC \
(WIMLIB_EXTRACT_FLAG_NTFS | \
+ WIMLIB_EXTRACT_FLAG_UNIX_DATA | \
WIMLIB_EXTRACT_FLAG_NO_ACLS | \
WIMLIB_EXTRACT_FLAG_STRICT_ACLS | \
WIMLIB_EXTRACT_FLAG_RPFIX | \
#define PWM_ALLOW_WIM_HDR 0x00001
-#define PWM_SILENT_EOF 0x00002
/* Read the header from a stream in a pipable WIM. */
static int
if (ret)
goto read_error;
- if ((flags & PWM_ALLOW_WIM_HDR) && buf.stream_hdr.magic == PWM_MAGIC) {
+ if ((flags & PWM_ALLOW_WIM_HDR) &&
+ le64_to_cpu(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));
return 0;
read_error:
- if (ret != WIMLIB_ERR_UNEXPECTED_END_OF_FILE || !(flags & PWM_SILENT_EOF))
- ERROR_WITH_ERRNO("Error reading pipable WIM from pipe");
+ ERROR_WITH_ERRNO("Error reading pipable WIM from pipe");
return ret;
}
memcpy(ctx->progress.extract.guid, ctx->wim->hdr.guid, WIM_GUID_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);
- }
+ ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN);
+ if (ret)
+ goto out;
+
while (ctx->num_streams_remaining) {
struct wim_header_disk pwm_hdr;
struct wim_lookup_table_entry *needed_lte;
ctx->progress.extract.total_parts = total_parts;
memcpy(ctx->progress.extract.guid,
pwm_hdr.guid, WIM_GUID_LEN);
- if (ctx->progress_func) {
- ctx->progress_func(
- WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN,
- &ctx->progress);
- }
+ ret = extract_progress(ctx,
+ WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN);
+ if (ret)
+ goto out;
}
}
}
consume_chunk_with_progress(const void *chunk, size_t size, void *_ctx)
{
struct apply_ctx *ctx = _ctx;
- wimlib_progress_func_t progress_func = ctx->progress_func;
union wimlib_progress_info *progress = &ctx->progress;
- u32 num_copies = ctx->cur_stream->out_refcnt;
+ int ret;
- progress->extract.completed_bytes += size * num_copies;
+ if (likely(ctx->supported_features.hard_links)) {
+ progress->extract.completed_bytes +=
+ (u64)size * 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++) {
+ const struct wim_inode *inode = owners[i].inode;
+ const struct wim_dentry *dentry;
+
+ list_for_each_entry(dentry,
+ &inode->i_extraction_aliases,
+ d_extraction_alias_node)
+ {
+ progress->extract.completed_bytes += size;
+ }
+ }
+ }
if (progress->extract.completed_bytes >= ctx->next_progress) {
- progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS, progress);
+
+ ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS);
+ if (ret)
+ return ret;
+
if (progress->extract.completed_bytes >=
progress->extract.total_bytes)
{
.end_stream = cbs->end_stream,
.end_stream_ctx = cbs->end_stream_ctx,
};
- if (ctx->progress_func) {
+ if (ctx->progfunc) {
ctx->saved_cbs = cbs;
cbs = &wrapper_cbs;
}
for (i = 0; i < num_trees; i++) {
struct wim_dentry *d = trees[i];
while (!dentry_is_root(d)) {
- d = d->parent;
+ d = d->d_parent;
if (d->tmp_flag)
goto tree_contained;
}
place_after = dentry_list;
ancestor = dentry;
do {
- ancestor = ancestor->parent;
+ ancestor = ancestor->d_parent;
if (will_extract_dentry(ancestor)) {
place_after = &ancestor->d_extraction_list_node;
break;
ancestor = dentry;
do {
- ancestor = ancestor->parent;
+ ancestor = ancestor->d_parent;
if (will_extract_dentry(ancestor))
break;
list_add(&ancestor->d_extraction_list_node, place_after);
if (dentry_is_root(dentry))
return 0;
+#ifdef WITH_NTFS_3G
if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
dentry->d_extraction_name = dentry->file_name;
dentry->d_extraction_name_nchars = dentry->file_name_nbytes /
sizeof(utf16lechar);
return 0;
}
+#endif
if (!ctx->supported_features.case_sensitive_filenames) {
struct wim_dentry *other;
return WIMLIB_ERR_UNSUPPORTED;
}
+ if (required_features->unix_data &&
+ !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA))
+ {
+ WARNING("Ignoring UNIX metadata of %lu files",
+ required_features->unix_data);
+ }
+
/* DOS Names. */
if (required_features->short_names &&
!supported_features->short_names)
static int
extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
- const tchar *target, int extract_flags,
- wimlib_progress_func_t progress_func)
+ const tchar *target, int extract_flags)
{
const struct apply_operations *ops;
struct apply_ctx *ctx;
ctx->target = target;
ctx->target_nchars = tstrlen(target);
ctx->extract_flags = extract_flags;
- if (progress_func) {
- ctx->progress_func = progress_func;
+ if (ctx->wim->progfunc) {
+ ctx->progfunc = ctx->wim->progfunc;
+ ctx->progctx = ctx->wim->progctx;
ctx->progress.extract.image = wim->current_image;
ctx->progress.extract.extract_flags = (extract_flags &
WIMLIB_EXTRACT_MASK_PUBLIC);
}
}
- if (ctx->progress_func) {
- int msg;
- if (extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE)
- msg = WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN;
- else
- msg = WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN;
- (*ctx->progress_func)(msg, &ctx->progress);
- }
+ ret = extract_progress(ctx,
+ ((extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE) ?
+ WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN :
+ WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN));
+ if (ret)
+ goto out_cleanup;
ret = (*ops->extract)(&dentry_list, ctx);
if (ret)
goto out_cleanup;
- if (ctx->progress_func &&
- ctx->progress.extract.completed_bytes <
- ctx->progress.extract.total_bytes)
+ if (ctx->progress.extract.completed_bytes <
+ ctx->progress.extract.total_bytes)
{
ctx->progress.extract.completed_bytes =
ctx->progress.extract.total_bytes;
- (*ctx->progress_func)(WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS,
- &ctx->progress);
+ ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS);
+ if (ret)
+ goto out_cleanup;
}
- if (ctx->progress_func) {
- int msg;
- if (extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE)
- msg = WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END;
- else
- msg = WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END;
- (*ctx->progress_func)(msg, &ctx->progress);
- }
- ret = 0;
+ ret = extract_progress(ctx,
+ ((extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE) ?
+ WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END :
+ WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END));
out_cleanup:
destroy_stream_list(&ctx->stream_list);
destroy_dentry_list(&dentry_list);
static int
do_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 extract_flags)
{
int ret;
struct wim_dentry **trees;
goto out_free_trees;
}
- ret = extract_trees(wim, trees, num_trees,
- target, extract_flags, progress_func);
+ ret = extract_trees(wim, trees, num_trees, target, extract_flags);
out_free_trees:
FREE(trees);
return ret;
static int
extract_single_image(WIMStruct *wim, int image,
- const tchar *target, int extract_flags,
- wimlib_progress_func_t progress_func)
+ const tchar *target, int extract_flags)
{
const tchar *path = WIMLIB_WIM_ROOT_PATH;
extract_flags |= WIMLIB_EXTRACT_FLAG_IMAGEMODE;
- return do_wimlib_extract_paths(wim, image, target, &path, 1,
- extract_flags, progress_func);
+ return do_wimlib_extract_paths(wim, image, target, &path, 1, extract_flags);
}
static const tchar * const filename_forbidden_chars =
/* Extracts all images from the WIM to the directory @target, with the images
* placed in subdirectories named by their image names. */
static int
-extract_all_images(WIMStruct *wim,
- const tchar *target,
- int extract_flags,
- wimlib_progress_func_t progress_func)
+extract_all_images(WIMStruct *wim, const tchar *target, int extract_flags)
{
size_t image_name_max_len = max(xml_get_max_image_name_len(wim), 20);
size_t output_path_len = tstrlen(target);
int image;
const tchar *image_name;
- extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
-
if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
ERROR("Cannot extract multiple images in NTFS extraction mode.");
return WIMLIB_ERR_INVALID_PARAM;
* Use image number instead. */
tsprintf(buf + output_path_len + 1, T("%d"), image);
}
- ret = extract_single_image(wim, image, buf, extract_flags,
- progress_func);
+ ret = extract_single_image(wim, image, buf, extract_flags);
if (ret)
return ret;
}
}
static int
-do_wimlib_extract_image(WIMStruct *wim,
- int image,
- const tchar *target,
- int extract_flags,
- wimlib_progress_func_t progress_func)
+do_wimlib_extract_image(WIMStruct *wim, int image, const tchar *target,
+ int extract_flags)
{
if (extract_flags & (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE |
WIMLIB_EXTRACT_FLAG_TO_STDOUT |
return WIMLIB_ERR_INVALID_PARAM;
if (image == WIMLIB_ALL_IMAGES)
- return extract_all_images(wim, target, extract_flags,
- progress_func);
+ return extract_all_images(wim, target, extract_flags);
else
- return extract_single_image(wim, image, target, extract_flags,
- progress_func);
+ return extract_single_image(wim, image, target, extract_flags);
}
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 extract_flags)
{
if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
return WIMLIB_ERR_INVALID_PARAM;
return do_wimlib_extract_paths(wim, image, target, paths, num_paths,
- extract_flags, progress_func);
+ extract_flags);
}
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)
+ const tchar *path_list_file, int extract_flags)
{
int ret;
tchar **paths;
ret = wimlib_extract_paths(wim, image, target,
(const tchar * const *)paths, num_paths,
- extract_flags, progress_func);
+ extract_flags);
FREE(paths);
FREE(mem);
return ret;
}
WIMLIBAPI int
-wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name,
- const tchar *target, int extract_flags,
- wimlib_progress_func_t progress_func)
+wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
+ const tchar *image_num_or_name,
+ const tchar *target,
+ int extract_flags,
+ wimlib_progress_func_t progfunc,
+ void *progctx)
{
int ret;
WIMStruct *pwm;
* the pipable WIM. Caveats: Unlike getting a WIMStruct with
* 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,
- &pwm, progress_func);
+ ret = open_wim_as_WIMStruct(&pipe_fd, WIMLIB_OPEN_FLAG_FROM_PIPE, &pwm,
+ progfunc, progctx);
if (ret)
return ret;
}
/* Extract the image. */
extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
- ret = do_wimlib_extract_image(pwm, image, target,
- extract_flags, progress_func);
+ ret = do_wimlib_extract_image(pwm, image, target, extract_flags);
/* Clean up and return. */
out_wimlib_free:
wimlib_free(pwm);
return ret;
}
+
+WIMLIBAPI int
+wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name,
+ const tchar *target, int extract_flags)
+{
+ return wimlib_extract_image_from_pipe_with_progress(pipe_fd,
+ image_num_or_name,
+ target,
+ extract_flags,
+ NULL,
+ NULL);
+}
+
WIMLIBAPI int
wimlib_extract_image(WIMStruct *wim, int image, const tchar *target,
- int extract_flags, wimlib_progress_func_t progress_func)
+ int extract_flags)
{
if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
return WIMLIB_ERR_INVALID_PARAM;
- return do_wimlib_extract_image(wim, image, target, extract_flags,
- progress_func);
+ return do_wimlib_extract_image(wim, image, target, extract_flags);
}