X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fextract.c;h=a574f7c5af374d77f0cde3740f5743b0eb93b05a;hb=06b7241e194674d56c970fc56441beb84bc258bb;hp=6512917c0c5ed9df4afe7c0addf23243151033c2;hpb=ccdd5a74123ebf14353a9569bf014fb2e7774d1e;p=wimlib diff --git a/src/extract.c b/src/extract.c index 6512917c..a574f7c5 100644 --- a/src/extract.c +++ b/src/extract.c @@ -26,9 +26,9 @@ /* * This file provides the API functions wimlib_extract_image(), - * wimlib_extract_image_from_pipe(), wimlib_extract_files(), - * wimlib_extract_paths(), and wimlib_extract_pathlist(). Internally, all end - * up calling do_wimlib_extract_paths() and extract_trees(). + * wimlib_extract_image_from_pipe(), wimlib_extract_paths(), and + * wimlib_extract_pathlist(). Internally, all end up calling + * do_wimlib_extract_paths() and extract_trees(). * * Although wimlib supports multiple extraction modes/backends (NTFS-3g, UNIX, * Win32), this file does not itself have code to extract files or directories @@ -68,8 +68,7 @@ #define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000 #define WIMLIB_EXTRACT_FLAG_FROM_PIPE 0x40000000 -#define WIMLIB_EXTRACT_FLAG_FILEMODE 0x20000000 -#define WIMLIB_EXTRACT_FLAG_IMAGEMODE 0x10000000 +#define WIMLIB_EXTRACT_FLAG_IMAGEMODE 0x20000000 /* Keep in sync with wimlib.h */ #define WIMLIB_EXTRACT_MASK_PUBLIC \ @@ -495,7 +494,8 @@ extract_streams(const tchar *path, struct apply_ctx *ctx, } } else { ret = ctx->ops->extract_unnamed_stream( - file_spec, lte, ctx); + file_spec, lte, ctx, + dentry); if (ret) goto error; } @@ -658,11 +658,11 @@ extract_security(const tchar *path, struct apply_ctx *ctx, if (ctx->supported_features.security_descriptors && inode->i_security_id != -1) { - const struct wim_security_data *sd; + struct wim_security_data *sd; const u8 *desc; size_t desc_size; - sd = wim_const_security_data(ctx->wim); + sd = wim_get_current_security_data(ctx->wim); desc = sd->descriptors[inode->i_security_id]; desc_size = sd->sizes[inode->i_security_id]; @@ -1171,6 +1171,7 @@ create_temporary_file(struct filedes *fd_ret, tchar **name_ret) { tchar *name; int raw_fd; + int open_flags; retry: name = ttempnam(NULL, T("wimlib")); @@ -1179,7 +1180,11 @@ retry: return WIMLIB_ERR_NOMEM; } - raw_fd = topen(name, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600); + open_flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY; +#ifdef __WIN32__ + open_flags |= _O_SHORT_LIVED; +#endif + raw_fd = topen(name, open_flags, 0600); if (raw_fd < 0) { if (errno == EEXIST) { @@ -1268,14 +1273,23 @@ need_tmpfile_to_extract(struct wim_lookup_table_entry *lte, } static int -begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte, - bool is_partial_res, - void *_ctx) +begin_extract_stream(struct wim_lookup_table_entry *lte, + u32 flags, void *_ctx) { struct apply_ctx *ctx = _ctx; int ret; - if (!need_tmpfile_to_extract(lte, is_partial_res)) { + if (flags & BEGIN_STREAM_FLAG_WHOLE_STREAM) { + DEBUG("Whole stream (size=%"PRIu64") will be read into memory", + lte->size); + ctx->cur_stream = lte; + filedes_invalidate(&ctx->tmpfile_fd); + return 0; + } + + if (!need_tmpfile_to_extract(lte, + (flags & BEGIN_STREAM_FLAG_PARTIAL_RESOURCE))) + { DEBUG("Temporary file not needed " "for stream (size=%"PRIu64")", lte->size); ret = extract_stream_instances(lte, lte, ctx); @@ -1290,14 +1304,42 @@ begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte, } static int -end_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte, - int status, void *_ctx) +extract_chunk(const void *chunk, size_t size, void *_ctx) +{ + struct apply_ctx *ctx = _ctx; + int ret; + + if (filedes_valid(&ctx->tmpfile_fd)) { + ret = full_write(&ctx->tmpfile_fd, chunk, size); + if (ret) + ERROR_WITH_ERRNO("Error writing to file descriptor"); + } else { + struct wim_lookup_table_entry lte_override; + + memcpy(<e_override, ctx->cur_stream, + sizeof(struct wim_lookup_table_entry)); + + lte_override.resource_location = RESOURCE_IN_ATTACHED_BUFFER; + lte_override.size = size; + lte_override.attached_buffer = (void *)chunk; + + ret = extract_stream_instances(ctx->cur_stream, <e_override, ctx); + } + return ret; +} + +static int +end_extract_stream(struct wim_lookup_table_entry *lte, + int status, void *_ctx) { struct apply_ctx *ctx = _ctx; struct wim_lookup_table_entry lte_override; int ret; int errno_save = errno; + if (!filedes_valid(&ctx->tmpfile_fd)) + return status; + ret = filedes_close(&ctx->tmpfile_fd); if (status) { @@ -1337,11 +1379,11 @@ static int extract_stream_list(struct apply_ctx *ctx) { struct read_stream_list_callbacks cbs = { - .begin_stream = begin_extract_stream_to_tmpfile, + .begin_stream = begin_extract_stream, .begin_stream_ctx = ctx, - .consume_chunk = extract_chunk_to_fd, - .consume_chunk_ctx = &ctx->tmpfile_fd, - .end_stream = end_extract_stream_to_tmpfile, + .consume_chunk = extract_chunk, + .consume_chunk_ctx = ctx, + .end_stream = end_extract_stream, .end_stream_ctx = ctx, }; return read_stream_list(&ctx->stream_list, @@ -1429,7 +1471,7 @@ extract_streams_from_pipe(struct apply_ctx *ctx) pwm_flags = PWM_ALLOW_WIM_HDR; if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RESUME)) pwm_flags |= PWM_SILENT_EOF; - memcpy(ctx->progress.extract.guid, ctx->wim->hdr.guid, WIM_GID_LEN); + 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) @@ -1519,12 +1561,12 @@ extract_streams_from_pipe(struct apply_ctx *ctx) if (part_number != ctx->progress.extract.part_number || total_parts != ctx->progress.extract.total_parts || memcmp(pwm_hdr.guid, ctx->progress.extract.guid, - WIM_GID_LEN)) + WIM_GUID_LEN)) { ctx->progress.extract.part_number = part_number; ctx->progress.extract.total_parts = total_parts; memcpy(ctx->progress.extract.guid, - pwm_hdr.guid, WIM_GID_LEN); + pwm_hdr.guid, WIM_GUID_LEN); if (ctx->progress_func) { ctx->progress_func( WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN, @@ -1816,16 +1858,12 @@ dentry_calculate_extraction_name(struct wim_dentry *dentry, } if (file_name_valid(dentry->file_name, dentry->file_name_nbytes / 2, false)) { -#if TCHAR_IS_UTF16LE - dentry->extraction_name = dentry->file_name; - dentry->extraction_name_nchars = dentry->file_name_nbytes / 2; - return 0; -#else - return utf16le_to_tstr(dentry->file_name, + ret = utf16le_get_tstr(dentry->file_name, dentry->file_name_nbytes, - &dentry->extraction_name, + (const tchar **)&dentry->extraction_name, &dentry->extraction_name_nchars); -#endif + dentry->extraction_name_nchars /= sizeof(tchar); + return ret; } else { if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES) { @@ -1849,18 +1887,17 @@ out_replace: memcpy(utf16_name_copy, dentry->file_name, dentry->file_name_nbytes); file_name_valid(utf16_name_copy, dentry->file_name_nbytes / 2, true); - tchar *tchar_name; + const tchar *tchar_name; size_t tchar_nchars; - #if TCHAR_IS_UTF16LE - tchar_name = utf16_name_copy; - tchar_nchars = dentry->file_name_nbytes / 2; - #else - ret = utf16le_to_tstr(utf16_name_copy, - dentry->file_name_nbytes, - &tchar_name, &tchar_nchars); + + ret = utf16le_get_tstr(utf16_name_copy, + dentry->file_name_nbytes, + &tchar_name, &tchar_nchars); if (ret) return ret; - #endif + + tchar_nchars /= sizeof(tchar); + size_t fixed_name_num_chars = tchar_nchars; tchar fixed_name[tchar_nchars + 50]; @@ -1868,9 +1905,9 @@ out_replace: fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars, T(" (invalid filename #%lu)"), ++ctx->invalid_sequence); - #if !TCHAR_IS_UTF16LE - FREE(tchar_name); - #endif + + utf16le_put_tstr(tchar_name); + dentry->extraction_name = memdup(fixed_name, 2 * fixed_name_num_chars + 2); if (!dentry->extraction_name) @@ -2435,21 +2472,7 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees, ctx.progress.extract.target = target; } - if (extract_flags & WIMLIB_EXTRACT_FLAG_FILEMODE) { - /* Called from wimlib_extract_files(). There should be only 1 - * tree, and directory structure should not be preserved. */ - wimlib_assert(num_trees == 1); - wimlib_assert(extract_flags & - WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE); - ret = calculate_dentry_full_path(trees[0]); - if (ret) - return ret; - ctx.progress.extract.extract_root_wim_source_path = trees[0]->_full_path; - ctx.target_dentry = trees[0]; - } else { - ctx.progress.extract.extract_root_wim_source_path = T(""); - ctx.target_dentry = wim_root_dentry(wim); - } + ctx.target_dentry = wim_get_current_root_dentry(wim); /* Note: ctx.target_dentry represents the dentry that gets extracted to * @target. There may be none, in which case it gets set to the image * root and never matches any of the dentries actually being extracted. @@ -2543,6 +2566,18 @@ extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees, goto out_destroy_stream_list; } ctx.realtarget_nchars = tstrlen(ctx.realtarget); + #ifdef __WIN32__ + /* Strip trailing slashes. If we don't do this, we may create a + * path with multiple consecutive backslashes, which for some + * reason causes Windows to report that the file cannot be found. + */ + while (ctx.realtarget_nchars >= 2 + && ctx.realtarget[ctx.realtarget_nchars - 1] == L'\\' + && ctx.realtarget[ctx.realtarget_nchars - 2] != L':') + { + ctx.realtarget[--ctx.realtarget_nchars] = L'\0'; + } + #endif } if (progress_func) { @@ -2740,7 +2775,7 @@ check_extract_flags(const WIMStruct *wim, int *extract_flags_p) #ifndef WITH_NTFS_3G if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) { ERROR("wimlib was compiled without support for NTFS-3g, so\n" - " it cannot apply a WIM image directly to a NTFS volume."); + " it cannot apply a WIM image directly to an NTFS volume."); return WIMLIB_ERR_UNSUPPORTED; } #endif @@ -2857,8 +2892,7 @@ do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target, return ret; if ((extract_flags & (WIMLIB_EXTRACT_FLAG_NTFS | - WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE | - WIMLIB_EXTRACT_FLAG_FILEMODE)) == + WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE)) == (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE)) { ret = mkdir_if_needed(target); @@ -2939,7 +2973,7 @@ extract_single_image(WIMStruct *wim, int image, const tchar *target, int extract_flags, wimlib_progress_func_t progress_func) { - const tchar *path = T(""); + 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); @@ -3048,67 +3082,6 @@ do_wimlib_extract_image(WIMStruct *wim, * Extraction API * ****************************************************************************/ -/* Note: new code should use wimlib_extract_paths() instead of - * wimlib_extract_files() if possible. */ -WIMLIBAPI int -wimlib_extract_files(WIMStruct *wim, int image, - const struct wimlib_extract_command *cmds, size_t num_cmds, - int default_extract_flags, - wimlib_progress_func_t progress_func) -{ - int all_flags = 0; - int link_flags; - int ret; - - if (num_cmds == 0) - return 0; - - default_extract_flags |= WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE; - - for (size_t i = 0; i < num_cmds; i++) { - int cmd_flags = (cmds[i].extract_flags | - default_extract_flags); - - if (cmd_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC) - return WIMLIB_ERR_INVALID_PARAM; - - int cmd_link_flags = (cmd_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | - WIMLIB_EXTRACT_FLAG_HARDLINK)); - if (i == 0) { - link_flags = cmd_link_flags; - } else { - if (cmd_link_flags != link_flags) { - ERROR("The same symlink or hardlink extraction mode " - "must be set on all extraction commands!"); - return WIMLIB_ERR_INVALID_PARAM; - } - } - all_flags |= cmd_flags; - } - if (all_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) { - ERROR("Glob paths not supported for wimlib_extract_files(). " - "Use wimlib_extract_paths() instead."); - return WIMLIB_ERR_INVALID_PARAM; - } - - for (size_t i = 0; i < num_cmds; i++) { - int extract_flags = (cmds[i].extract_flags | - default_extract_flags); - const tchar *target = cmds[i].fs_dest_path; - const tchar *wim_source_path = cmds[i].wim_source_path; - - ret = do_wimlib_extract_paths(wim, image, target, - &wim_source_path, 1, - extract_flags | WIMLIB_EXTRACT_FLAG_FILEMODE, - progress_func); - if (ret) - break; - } - - clear_lte_extracted_file(wim, all_flags); - return ret; -} - WIMLIBAPI int wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target, const tchar * const *paths, size_t num_paths,