X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fextract.c;h=a5be7d1b333486bc21cdf4e24626b4e61b6ca124;hb=0f4054ebfa380de7c85edfabf215599a8ff63143;hp=fb96f13f8723bf26d0e24f9acfd4e9d051bb22c6;hpb=24f13cb8e265b848c4633e0adb91d4f25a618743;p=wimlib diff --git a/src/extract.c b/src/extract.c index fb96f13f..a5be7d1b 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/. */ /* @@ -41,7 +39,13 @@ # include "config.h" #endif +#include +#include +#include +#include + #include "wimlib/apply.h" +#include "wimlib/assert.h" #include "wimlib/dentry.h" #include "wimlib/encoding.h" #include "wimlib/endianness.h" @@ -61,12 +65,6 @@ #include "wimlib/wildcard.h" #include "wimlib/wim.h" -#include -#include -#include -#include -#include - #define WIMLIB_EXTRACT_FLAG_FROM_PIPE 0x80000000 #define WIMLIB_EXTRACT_FLAG_IMAGEMODE 0x40000000 @@ -95,10 +93,49 @@ int do_file_extract_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg) { - ctx->count_until_file_progress = 512; /* Arbitrary value to limit calls */ + 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, @@ -107,16 +144,22 @@ dentry_is_supported(struct wim_dentry *dentry, struct wim_inode *inode = dentry->d_inode; if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { - return supported_features->reparse_points || - (inode_is_symlink(inode) && - supported_features->symlink_reparse_points); + if (!(supported_features->reparse_points || + (inode_is_symlink(inode) && + supported_features->symlink_reparse_points))) + return false; } + 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; + if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) { + if (!supported_features->encrypted_directories) + return false; + } else { + if (!supported_features->encrypted_files) + return false; + } } + return true; } @@ -700,6 +743,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; @@ -770,7 +814,7 @@ dentry_calculate_extraction_name(struct wim_dentry *dentry, { int ret; - if (!dentry_is_supported(dentry, &ctx->supported_features)) + if (unlikely(!dentry_is_supported(dentry, &ctx->supported_features))) goto skip_dentry; if (dentry_is_root(dentry)) @@ -970,7 +1014,7 @@ dentry_list_resolve_streams(struct list_head *dentry_list, } static int -ref_stream(struct wim_lookup_table_entry *lte, u32 stream_idx, +ref_stream(struct wim_lookup_table_entry *lte, unsigned stream_idx, struct wim_dentry *dentry, struct apply_ctx *ctx) { struct wim_inode *inode = dentry->d_inode; @@ -1041,29 +1085,46 @@ 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; + unsigned 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; - - 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. */ if (ctx->supported_features.named_data_streams) { - for (u16 i = 0; i < inode->i_num_ads; i++) { - if (!ads_entry_is_named_stream(&inode->i_ads_entries[i])) + for (unsigned i = 0; i < inode->i_num_ads; i++) { + if (!inode->i_ads_entries[i].stream_name_nbytes) continue; ret = ref_stream(inode->i_ads_entries[i].lte, i + 1, dentry, ctx); @@ -1394,6 +1455,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) @@ -1414,16 +1476,21 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees, if (ret) goto out_cleanup; + if (unlikely(list_empty(&dentry_list))) { + WARNING("There is nothing to extract!"); + goto out_cleanup; + } + ret = dentry_list_resolve_streams(&dentry_list, ctx); 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 @@ -1481,23 +1548,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. */ @@ -1961,7 +2025,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;