X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fextract.c;h=39899c4094e2c5eb80b296bc93d6e09161123de0;hp=0663edd75ba92d4f736b8249d572b292e0adc04b;hb=69f07a55f05919a15ff1ec77b963b48f5f6a5d04;hpb=4c532e2a9f1a40e1c1a6ed44a50025cfbfab6e4f diff --git a/src/extract.c b/src/extract.c index 0663edd7..39899c40 100644 --- a/src/extract.c +++ b/src/extract.c @@ -8,20 +8,18 @@ /* * Copyright (C) 2012, 2013, 2014 Eric Biggers * - * This file is part of wimlib, a library for working with WIM files. + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * - * You should have received a copy of the GNU General Public License - * along with wimlib; if not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. */ /* @@ -90,6 +88,54 @@ 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 = 500; /* Arbitrary value to limit calls */ + return extract_progress(ctx, msg); +} + +static int +start_file_phase(struct apply_ctx *ctx, uint64_t end_file_count, enum wimlib_progress_msg msg) +{ + ctx->progress.extract.current_file_count = 0; + ctx->progress.extract.end_file_count = end_file_count; + return do_file_extract_progress(ctx, msg); +} + +int +start_file_structure_phase(struct apply_ctx *ctx, uint64_t end_file_count) +{ + return start_file_phase(ctx, end_file_count, WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE); +} + +int +start_file_metadata_phase(struct apply_ctx *ctx, uint64_t end_file_count) +{ + return start_file_phase(ctx, end_file_count, WIMLIB_PROGRESS_MSG_EXTRACT_METADATA); +} + +static int +end_file_phase(struct apply_ctx *ctx, enum wimlib_progress_msg msg) +{ + ctx->progress.extract.current_file_count = ctx->progress.extract.end_file_count; + return do_file_extract_progress(ctx, msg); +} + +int +end_file_structure_phase(struct apply_ctx *ctx) +{ + return end_file_phase(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE); +} + +int +end_file_metadata_phase(struct apply_ctx *ctx) +{ + return end_file_phase(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_METADATA); +} + /* Check whether the extraction of a dentry should be skipped completely. */ static bool dentry_is_supported(struct wim_dentry *dentry, @@ -260,7 +306,7 @@ load_streams_from_pipe(struct apply_ctx *ctx, } 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; @@ -401,9 +447,13 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx) { struct wim_lookup_table_entry tmpfile_lte; struct wim_lookup_table_entry *orig_lte = ctx->cur_stream; - const struct stream_owner *owners = stream_owners(orig_lte); 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. @@ -415,10 +465,8 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx) 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; - - for (u32 i = 0; i < orig_lte->out_refcnt; i++) { - tmpfile_lte.inline_stream_owners[0] = owners[i]; + 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 @@ -429,9 +477,12 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx) * because it needs the original stream location in order to * create the external backing reference. */ + 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. */ @@ -439,10 +490,13 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx) cbs->consume_chunk, cbs->consume_chunk_ctx); - return (*cbs->end_stream)(orig_lte, ret, - cbs->end_stream_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 @@ -683,6 +737,7 @@ destroy_dentry_list(struct list_head *dentry_list) inode = dentry->d_inode; dentry_reset_extraction_list_node(dentry); inode->i_visited = 0; + inode->i_can_externally_back = 0; if ((void *)dentry->d_extraction_name != (void *)dentry->file_name) FREE(dentry->d_extraction_name); dentry->d_extraction_name = NULL; @@ -1024,23 +1079,43 @@ ref_stream(struct wim_lookup_table_entry *lte, u32 stream_idx, } static int -dentry_ref_streams(struct wim_dentry *dentry, struct apply_ctx *ctx) +ref_unnamed_stream(struct wim_dentry *dentry, struct apply_ctx *ctx) { struct wim_inode *inode = dentry->d_inode; int ret; + u16 stream_idx; + struct wim_lookup_table_entry *stream; - /* The unnamed data stream will always be extracted, except in an - * unlikely case. */ - if (!inode_is_encrypted_directory(inode)) { - u16 stream_idx; - struct wim_lookup_table_entry *stream; + if (unlikely(inode_is_encrypted_directory(inode))) + return 0; - stream = inode_unnamed_stream_resolved(inode, &stream_idx); - ret = ref_stream(stream, stream_idx, dentry, ctx); - if (ret) - return ret; + if (unlikely(ctx->apply_ops->will_externally_back)) { + ret = (*ctx->apply_ops->will_externally_back)(dentry, ctx); + if (ret >= 0) { + if (ret) /* Error */ + return ret; + /* Will externally back */ + return 0; + } + /* Won't externally back */ } + stream = inode_unnamed_stream_resolved(inode, &stream_idx); + return ref_stream(stream, stream_idx, dentry, ctx); +} + +static int +dentry_ref_streams(struct wim_dentry *dentry, struct apply_ctx *ctx) +{ + struct wim_inode *inode = dentry->d_inode; + int ret; + + /* The unnamed data stream will almost always be extracted, but there + * exist cases in which it won't be. */ + ret = ref_unnamed_stream(dentry, ctx); + if (ret) + return ret; + /* Named data streams will be extracted only if supported in the current * extraction mode and volume, and to avoid complications, if not doing * a linked extraction. */ @@ -1377,6 +1452,7 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees, } INIT_LIST_HEAD(&ctx->stream_list); filedes_invalidate(&ctx->tmpfile_fd); + ctx->apply_ops = ops; ret = (*ops->get_supported_features)(target, &ctx->supported_features); if (ret) @@ -1401,12 +1477,12 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees, if (ret) goto out_cleanup; + dentry_list_build_inode_alias_lists(&dentry_list); + ret = dentry_list_ref_streams(&dentry_list, ctx); if (ret) goto out_cleanup; - dentry_list_build_inode_alias_lists(&dentry_list); - if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) { /* When extracting from a pipe, the number of bytes of data to * extract can't be determined in the normal way (examining the @@ -1464,23 +1540,20 @@ out: static int mkdir_if_needed(const tchar *target) { - struct stat stbuf; - if (tstat(target, &stbuf)) { - if (errno == ENOENT) { - if (tmkdir(target, 0755)) { - ERROR_WITH_ERRNO("Failed to create directory " - "\"%"TS"\"", target); - return WIMLIB_ERR_MKDIR; - } - } else { - ERROR_WITH_ERRNO("Failed to stat \"%"TS"\"", target); - return WIMLIB_ERR_STAT; - } - } else if (!S_ISDIR(stbuf.st_mode)) { - ERROR("\"%"TS"\" is not a directory", target); - return WIMLIB_ERR_NOTDIR; - } - return 0; + if (!tmkdir(target, 0755)) + return 0; + + if (errno == EEXIST) + return 0; + +#ifdef __WIN32__ + /* _wmkdir() fails with EACCES if called on a drive root directory. */ + if (errno == EACCES) + return 0; +#endif + + ERROR_WITH_ERRNO("Failed to create directory \"%"TS"\"", target); + return WIMLIB_ERR_MKDIR; } /* Make sure the extraction flags make sense, and update them if needed. */ @@ -1511,12 +1584,16 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p) } #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 | @@ -1940,7 +2017,7 @@ wimlib_extract_image_from_pipe_with_progress(int pipe_fd, if (i == image) { /* Metadata resource is for the image being extracted. * Parse it and save the metadata in memory. */ - ret = read_metadata_resource(pwm, imd); + ret = read_metadata_resource(imd); if (ret) goto out_wimlib_free; imd->modified = 1;