X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fextract.c;h=a8864af0cdccf97f7e355175f252311db7a1c49d;hp=e599ffffda65cf775c73bd7d40cea424c8543b8b;hb=e08e0d6d920e1f3f154270efc4849d51efd65593;hpb=34ed0b6497707b151adea37586c63a395cee589c diff --git a/src/extract.c b/src/extract.c index e599ffff..a8864af0 100644 --- a/src/extract.c +++ b/src/extract.c @@ -740,9 +740,7 @@ extract_security(const tchar *path, struct apply_ctx *ctx, desc_size = sd->sizes[inode->i_security_id]; ret = ctx->ops->set_security_descriptor(path, desc, - desc_size, ctx, - !!(ctx->extract_flags & - WIMLIB_EXTRACT_FLAG_STRICT_ACLS)); + desc_size, ctx); if (ret) { if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS) { ERROR_WITH_ERRNO("Failed to set security " @@ -1067,10 +1065,63 @@ dentry_extract_skeleton(struct wim_dentry *dentry, void *_ctx) { struct apply_ctx *ctx = _ctx; tchar path[ctx->ops->path_max]; + struct wim_dentry *orig_dentry; + 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 + && !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) + { + DEBUG("Creating %"TS" before %"TS" " + "to guarantee correct DOS name extraction", + dentry_full_path(other_dentry), + dentry_full_path(dentry)); + orig_dentry = dentry; + dentry = other_dentry; + break; + } + } + } +again: if (!build_extraction_path(path, dentry, ctx)) return 0; - return do_dentry_extract_skeleton(path, dentry, ctx); + ret = do_dentry_extract_skeleton(path, dentry, ctx); + if (ret) + return ret; + + dentry->skeleton_extracted = 1; + + if (orig_dentry) { + dentry = orig_dentry; + orig_dentry = NULL; + goto again; + } + dentry->d_inode->i_dos_name_extracted = 1; + return 0; } /* Create a file or directory, then immediately extract all streams. This @@ -1083,13 +1134,13 @@ dentry_extract(struct wim_dentry *dentry, void *_ctx) tchar path[ctx->ops->path_max]; int ret; - if (!build_extraction_path(path, dentry, ctx)) - return 0; - - ret = do_dentry_extract_skeleton(path, dentry, ctx); + ret = dentry_extract_skeleton(dentry, ctx); if (ret) return ret; + if (!build_extraction_path(path, dentry, ctx)) + return 0; + return extract_streams(path, ctx, dentry, NULL, NULL); } @@ -1212,10 +1263,13 @@ extract_stream_list(struct apply_ctx *ctx) return 0; } +#define PWM_ALLOW_WIM_HDR 0x00001 +#define PWM_SILENT_EOF 0x00002 + /* Read the header from a stream in a pipable WIM. */ static int read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte, - bool allow_header) + int flags) { struct pwm_stream_hdr stream_hdr; int ret; @@ -1224,7 +1278,7 @@ read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte, if (ret) goto read_error; - if (allow_header && stream_hdr.magic == PWM_MAGIC) { + if ((flags & PWM_ALLOW_WIM_HDR) && stream_hdr.magic == PWM_MAGIC) { u8 buf[WIM_HEADER_DISK_SIZE - sizeof(stream_hdr)]; ret = full_read(&pwm->in_fd, buf, sizeof(buf)); if (ret) @@ -1255,7 +1309,8 @@ read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte, return 0; read_error: - ERROR_WITH_ERRNO("Error reading pipable WIM from pipe"); + if (ret != WIMLIB_ERR_UNEXPECTED_END_OF_FILE || !(flags & PWM_SILENT_EOF)) + ERROR_WITH_ERRNO("Error reading pipable WIM from pipe"); return ret; } @@ -1276,6 +1331,7 @@ extract_streams_from_pipe(struct apply_ctx *ctx) struct wim_lookup_table_entry *needed_lte; struct wim_lookup_table *lookup_table; int ret; + int pwm_flags; ret = WIMLIB_ERR_NOMEM; found_lte = new_lookup_table_entry(); @@ -1283,11 +1339,19 @@ extract_streams_from_pipe(struct apply_ctx *ctx) goto out; lookup_table = ctx->wim->lookup_table; - + pwm_flags = PWM_ALLOW_WIM_HDR; + if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RESUME)) + pwm_flags |= PWM_SILENT_EOF; while (ctx->num_streams_remaining) { - ret = read_pwm_stream_header(ctx->wim, found_lte, true); - if (ret) + ret = read_pwm_stream_header(ctx->wim, found_lte, pwm_flags); + if (ret) { + if (ret == WIMLIB_ERR_UNEXPECTED_END_OF_FILE && + (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RESUME)) + { + goto resume_done; + } goto out_free_found_lte; + } if ((found_lte->resource_location != RESOURCE_NONEXISTENT) && !(found_lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) @@ -1316,6 +1380,10 @@ out_free_found_lte: free_lookup_table_entry(found_lte); out: return ret; + +resume_done: + /* TODO */ + return 0; } /* Finish extracting a file, directory, or symbolic link by setting file @@ -1578,9 +1646,11 @@ dentry_reset_needs_extraction(struct wim_dentry *dentry, void *_ignore) dentry->extraction_skipped = 0; dentry->was_hardlinked = 0; + dentry->skeleton_extracted = 0; inode->i_visited = 0; FREE(inode->i_extracted_file); inode->i_extracted_file = NULL; + inode->i_dos_name_extracted = 0; if ((void*)dentry->extraction_name != (void*)dentry->file_name) FREE(dentry->extraction_name); dentry->extraction_name = NULL; @@ -1986,10 +2056,17 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target, * However, we can get a reasonably accurate estimate by taking * from the corresponding in the WIM XML * data. This does assume that a full image is being extracted, - * but currently there is no API for doing otherwise. */ + * but currently there is no API for doing otherwise. (Also, + * subtract from this if hard links are + * supported by the extraction mode.) */ ctx.progress.extract.total_bytes = wim_info_get_image_total_bytes(wim->wim_info, wim->current_image); + if (ctx.supported_features.hard_links) { + ctx.progress.extract.total_bytes -= + wim_info_get_image_hard_link_bytes(wim->wim_info, + wim->current_image); + } } /* Handle the special case of extracting a file to standard @@ -2073,9 +2150,12 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target, if (progress_func) progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN, &ctx.progress); - ret = for_dentry_in_tree(root, dentry_extract_skeleton, &ctx); - if (ret) - goto out_free_realtarget; + + if (!(extract_flags & WIMLIB_EXTRACT_FLAG_RESUME)) { + ret = for_dentry_in_tree(root, dentry_extract_skeleton, &ctx); + if (ret) + goto out_free_realtarget; + } if (progress_func) progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END, &ctx.progress); @@ -2190,6 +2270,11 @@ check_extract_command(struct wimlib_extract_command *cmd, int wim_header_flags) WIMLIB_EXTRACT_FLAG_NORPFIX)) return WIMLIB_ERR_INVALID_PARAM; + if ((extract_flags & + (WIMLIB_EXTRACT_FLAG_RESUME | + WIMLIB_EXTRACT_FLAG_FROM_PIPE)) == WIMLIB_EXTRACT_FLAG_RESUME) + return WIMLIB_ERR_INVALID_PARAM; + if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) { #ifndef WITH_NTFS_3G ERROR("wimlib was compiled without support for NTFS-3g, so\n" @@ -2575,7 +2660,7 @@ wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name, * WIMs.) */ { struct wim_lookup_table_entry xml_lte; - ret = read_pwm_stream_header(pwm, &xml_lte, false); + ret = read_pwm_stream_header(pwm, &xml_lte, 0); if (ret) goto out_wimlib_free; @@ -2635,7 +2720,7 @@ wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name, goto out_wimlib_free; } - ret = read_pwm_stream_header(pwm, metadata_lte, false); + ret = read_pwm_stream_header(pwm, metadata_lte, 0); imd = pwm->image_metadata[i - 1]; imd->metadata_lte = metadata_lte; if (ret)