X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwin32_apply.c;h=49e25d4b50bd30d156b6a669cd0f6a9f6ab0d0a1;hp=7bacac9d50b42a742f92f39a6da386cf4fef7d1b;hb=a8d148d9b2a765ba7fcbce927ea2546f917afe53;hpb=5538002965b9a7f08aef62c7b03194aa40bb0751 diff --git a/src/win32_apply.c b/src/win32_apply.c index 7bacac9d..49e25d4b 100644 --- a/src/win32_apply.c +++ b/src/win32_apply.c @@ -36,10 +36,10 @@ #include "wimlib/error.h" #include "wimlib/metadata.h" #include "wimlib/paths.h" +#include "wimlib/pattern.h" #include "wimlib/reparse.h" #include "wimlib/textfile.h" #include "wimlib/xml.h" -#include "wimlib/wildcard.h" #include "wimlib/wimboot.h" struct win32_apply_ctx { @@ -122,12 +122,12 @@ struct win32_apply_ctx { * beginning of the array) */ unsigned num_open_handles; - /* List of dentries, joined by @tmp_list, that need to have reparse data - * extracted as soon as the whole blob has been read into @data_buffer. - * */ + /* List of dentries, joined by @d_tmp_list, that need to have reparse + * data extracted as soon as the whole blob has been read into + * @data_buffer. */ struct list_head reparse_dentries; - /* List of dentries, joined by @tmp_list, that need to have raw + /* List of dentries, joined by @d_tmp_list, that need to have raw * encrypted data extracted as soon as the whole blob has been read into * @data_buffer. */ struct list_head encrypted_dentries; @@ -341,28 +341,15 @@ load_prepopulate_pats(struct win32_apply_ctx *ctx) return 0; } -/* Returns %true if the specified absolute path to a file in the WIM image - * matches a pattern in [PrepopulateList] of WimBootCompress.ini. Otherwise - * returns %false. */ -static bool -in_prepopulate_list(const wchar_t *path, size_t path_nchars, - const struct win32_apply_ctx *ctx) -{ - const struct string_set *pats = ctx->wimboot.prepopulate_pats; - - if (!pats || !pats->num_strings) - return false; - - return match_pattern_list(path, path_nchars, pats); -} - /* Returns %true if the specified absolute path to a file in the WIM image can * be subject to external backing when extracted. Otherwise returns %false. */ static bool -can_externally_back_path(const wchar_t *path, size_t path_nchars, - const struct win32_apply_ctx *ctx) +can_externally_back_path(const wchar_t *path, const struct win32_apply_ctx *ctx) { - if (in_prepopulate_list(path, path_nchars, ctx)) + /* Does the path match a pattern given in the [PrepopulateList] section + * of WimBootCompress.ini? */ + if (ctx->wimboot.prepopulate_pats && + match_pattern_list(path, ctx->wimboot.prepopulate_pats)) return false; /* Since we attempt to modify the SYSTEM registry after it's extracted @@ -374,8 +361,7 @@ can_externally_back_path(const wchar_t *path, size_t path_nchars, * However, a WIM that wasn't specifically captured in "WIMBoot mode" * may contain SYSTEM.* files. So to make things "just work", hard-code * the pattern. */ - if (match_path(path, path_nchars, L"\\Windows\\System32\\config\\SYSTEM*", - OS_PREFERRED_PATH_SEPARATOR, false)) + if (match_path(path, L"\\Windows\\System32\\config\\SYSTEM*", false)) return false; return true; @@ -458,7 +444,6 @@ static int will_externally_back_inode(struct wim_inode *inode, struct win32_apply_ctx *ctx, const struct wim_dentry **excluded_dentry_ret) { - struct list_head *next; struct wim_dentry *dentry; struct blob_descriptor *blob; int ret; @@ -486,24 +471,19 @@ will_externally_back_inode(struct wim_inode *inode, struct win32_apply_ctx *ctx, * We need to check the patterns in [PrepopulateList] against every name * of the inode, in case any of them match. */ - next = inode->i_extraction_aliases.next; - do { - dentry = list_entry(next, struct wim_dentry, - d_extraction_alias_node); + + inode_for_each_extraction_alias(dentry, inode) { ret = calculate_dentry_full_path(dentry); if (ret) return ret; - if (!can_externally_back_path(dentry->_full_path, - wcslen(dentry->_full_path), ctx)) - { + if (!can_externally_back_path(dentry->d_full_path, ctx)) { if (excluded_dentry_ret) *excluded_dentry_ret = dentry; return WIM_BACKING_EXCLUDED; } - next = next->next; - } while (next != &inode->i_extraction_aliases); + } inode->i_can_externally_back = 1; return 0; @@ -561,7 +541,7 @@ set_external_backing(HANDLE h, struct wim_inode *inode, struct win32_apply_ctx * build_extraction_path(excluded_dentry, ctx); - info.wimboot_exclude.path_in_wim = excluded_dentry->_full_path; + info.wimboot_exclude.path_in_wim = excluded_dentry->d_full_path; info.wimboot_exclude.extraction_path = current_path(ctx); return call_progress(ctx->common.progfunc, @@ -1028,17 +1008,12 @@ prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx) static struct wim_dentry * first_extraction_alias(const struct wim_inode *inode) { - struct list_head *next = inode->i_extraction_aliases.next; struct wim_dentry *dentry; - do { - dentry = list_entry(next, struct wim_dentry, - d_extraction_alias_node); + inode_for_each_extraction_alias(dentry, inode) if (dentry_has_short_name(dentry)) - break; - next = next->next; - } while (next != &inode->i_extraction_aliases); - return dentry; + return dentry; + return inode_first_extraction_dentry(inode); } /* @@ -1158,7 +1133,7 @@ remove_conflicting_short_name(const struct wim_dentry *dentry, struct win32_appl name = &ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)]; while (name != ctx->pathbuf.Buffer && *(name - 1) != L'\\') name--; - end = mempcpy(name, dentry->short_name, dentry->short_name_nbytes); + end = mempcpy(name, dentry->d_short_name, dentry->d_short_name_nbytes); ctx->pathbuf.Length = ((u8 *)end - (u8 *)ctx->pathbuf.Buffer); /* Open the conflicting file (by short name). */ @@ -1235,7 +1210,7 @@ set_short_name(HANDLE h, const struct wim_dentry *dentry, */ size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) + - max(dentry->short_name_nbytes, sizeof(wchar_t)) + + max(dentry->d_short_name_nbytes, sizeof(wchar_t)) + sizeof(wchar_t); u8 buf[bufsize] _aligned_attribute(8); FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf; @@ -1244,8 +1219,8 @@ set_short_name(HANDLE h, const struct wim_dentry *dentry, memset(buf, 0, bufsize); - info->FileNameLength = dentry->short_name_nbytes; - memcpy(info->FileName, dentry->short_name, dentry->short_name_nbytes); + info->FileNameLength = dentry->d_short_name_nbytes; + memcpy(info->FileName, dentry->d_short_name, dentry->d_short_name_nbytes); retry: status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize, @@ -1254,7 +1229,7 @@ retry: return 0; if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) { - if (dentry->short_name_nbytes == 0) + if (dentry->d_short_name_nbytes == 0) return 0; if (!ctx->tried_to_enable_short_names) { wchar_t volume[7]; @@ -1288,7 +1263,7 @@ retry: * from files. */ if (unlikely(status == STATUS_OBJECT_NAME_COLLISION) && - dentry->short_name_nbytes && !tried_to_remove_existing) + dentry->d_short_name_nbytes && !tried_to_remove_existing) { tried_to_remove_existing = true; status = remove_conflicting_short_name(dentry, ctx); @@ -1299,7 +1274,7 @@ retry: /* By default, failure to set short names is not an error (since short * names aren't too important anymore...). */ if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES)) { - if (dentry->short_name_nbytes) + if (dentry->d_short_name_nbytes) ctx->num_set_short_name_failures++; else ctx->num_remove_short_name_failures++; @@ -1473,44 +1448,104 @@ retry: return WIMLIB_ERR_OPEN; } +/* Set the reparse point @rpbuf of length @rpbuflen on the extracted file + * corresponding to the WIM dentry @dentry. */ +static int +do_set_reparse_point(const struct wim_dentry *dentry, + const struct reparse_buffer_disk *rpbuf, u16 rpbuflen, + struct win32_apply_ctx *ctx) +{ + NTSTATUS status; + HANDLE h; + + status = create_file(&h, GENERIC_WRITE, NULL, + 0, FILE_OPEN, 0, dentry, ctx); + if (!NT_SUCCESS(status)) + goto fail; + + status = (*func_NtFsControlFile)(h, NULL, NULL, NULL, + &ctx->iosb, FSCTL_SET_REPARSE_POINT, + (void *)rpbuf, rpbuflen, + NULL, 0); + (*func_NtClose)(h); + + if (NT_SUCCESS(status)) + return 0; + + /* On Windows, by default only the Administrator can create symbolic + * links for some reason. By default we just issue a warning if this + * appears to be the problem. Use WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS + * to get a hard error. */ + if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS) + && (status == STATUS_PRIVILEGE_NOT_HELD || + status == STATUS_ACCESS_DENIED) + && (dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK || + dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT)) + { + WARNING("Can't create symbolic link \"%ls\"! \n" + " (Need Administrator rights, or at least " + "the\n" + " SeCreateSymbolicLink privilege.)", + current_path(ctx)); + return 0; + } + +fail: + winnt_error(status, L"Can't set reparse data on \"%ls\"", + current_path(ctx)); + return WIMLIB_ERR_SET_REPARSE_DATA; +} + /* - * Create empty named data streams for the specified file, if there are any. + * Create empty named data streams and potentially a reparse point for the + * specified file, if any. * * Since these won't have blob descriptors, they won't show up in the call to * extract_blob_list(). Hence the need for the special case. */ static int -create_empty_named_data_streams(const struct wim_dentry *dentry, - struct win32_apply_ctx *ctx) +create_empty_streams(const struct wim_dentry *dentry, + struct win32_apply_ctx *ctx) { const struct wim_inode *inode = dentry->d_inode; - bool path_modified = false; - int ret = 0; - - if (!ctx->common.supported_features.named_data_streams) - return 0; + int ret; for (unsigned i = 0; i < inode->i_num_streams; i++) { const struct wim_inode_stream *strm = &inode->i_streams[i]; - HANDLE h; - if (!stream_is_named_data_stream(strm) || - stream_blob_resolved(strm) != NULL) + if (stream_blob_resolved(strm) != NULL) continue; - build_extraction_path_with_ads(dentry, ctx, - strm->stream_name, - utf16le_len_chars(strm->stream_name)); - path_modified = true; - ret = supersede_file_or_stream(ctx, &h); - if (ret) - break; - (*func_NtClose)(h); + if (strm->stream_type == STREAM_TYPE_REPARSE_POINT && + ctx->common.supported_features.reparse_points) + { + u8 buf[REPARSE_DATA_OFFSET] _aligned_attribute(8); + struct reparse_buffer_disk *rpbuf = + (struct reparse_buffer_disk *)buf; + complete_reparse_point(rpbuf, inode, 0); + ret = do_set_reparse_point(dentry, rpbuf, + REPARSE_DATA_OFFSET, ctx); + if (ret) + return ret; + } else if (stream_is_named_data_stream(strm) && + ctx->common.supported_features.named_data_streams) + { + HANDLE h; + + build_extraction_path_with_ads(dentry, ctx, + strm->stream_name, + utf16le_len_chars(strm->stream_name)); + ret = supersede_file_or_stream(ctx, &h); + + build_extraction_path(dentry, ctx); + + if (ret) + return ret; + (*func_NtClose)(h); + } } - /* Restore the path to the dentry itself */ - if (path_modified) - build_extraction_path(dentry, ctx); - return ret; + + return 0; } /* @@ -1596,7 +1631,7 @@ create_directories(struct list_head *dentry_list, ret = create_directory(dentry, ctx); if (!ret) - ret = create_empty_named_data_streams(dentry, ctx); + ret = create_empty_streams(dentry, ctx); ret = check_apply_error(dentry, ctx, ret); if (ret) @@ -1633,7 +1668,7 @@ create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry, if (ret) goto out_close; - ret = create_empty_named_data_streams(dentry, ctx); + ret = create_empty_streams(dentry, ctx); if (ret) goto out_close; @@ -1706,23 +1741,17 @@ static int create_links(HANDLE h, const struct wim_dentry *first_dentry, struct win32_apply_ctx *ctx) { - const struct wim_inode *inode; - const struct list_head *next; + const struct wim_inode *inode = first_dentry->d_inode; const struct wim_dentry *dentry; int ret; - inode = first_dentry->d_inode; - next = inode->i_extraction_aliases.next; - do { - dentry = list_entry(next, struct wim_dentry, - d_extraction_alias_node); + inode_for_each_extraction_alias(dentry, inode) { if (dentry != first_dentry) { ret = create_link(h, dentry, ctx); if (ret) return ret; } - next = next->next; - } while (next != &inode->i_extraction_aliases); + } return 0; } @@ -1830,7 +1859,7 @@ begin_extract_blob_instance(const struct blob_descriptor *blob, * data be available. So, stage the data in a buffer. */ if (!prepare_data_buffer(ctx, blob->size)) return WIMLIB_ERR_NOMEM; - list_add_tail(&dentry->tmp_list, &ctx->reparse_dentries); + list_add_tail(&dentry->d_tmp_list, &ctx->reparse_dentries); return 0; } @@ -1848,7 +1877,7 @@ begin_extract_blob_instance(const struct blob_descriptor *blob, * such files... */ if (!prepare_data_buffer(ctx, blob->size)) return WIMLIB_ERR_NOMEM; - list_add_tail(&dentry->tmp_list, &ctx->encrypted_dentries); + list_add_tail(&dentry->d_tmp_list, &ctx->encrypted_dentries); return 0; } @@ -1896,54 +1925,6 @@ begin_extract_blob_instance(const struct blob_descriptor *blob, return 0; } -/* Set the reparse point @rpbuf of length @rpbuflen on the extracted file - * corresponding to the WIM dentry @dentry. */ -static int -do_set_reparse_point(const struct wim_dentry *dentry, - const struct reparse_buffer_disk *rpbuf, u16 rpbuflen, - struct win32_apply_ctx *ctx) -{ - NTSTATUS status; - HANDLE h; - - status = create_file(&h, GENERIC_WRITE, NULL, - 0, FILE_OPEN, 0, dentry, ctx); - if (!NT_SUCCESS(status)) - goto fail; - - status = (*func_NtFsControlFile)(h, NULL, NULL, NULL, - &ctx->iosb, FSCTL_SET_REPARSE_POINT, - (void *)rpbuf, rpbuflen, - NULL, 0); - (*func_NtClose)(h); - - if (NT_SUCCESS(status)) - return 0; - - /* On Windows, by default only the Administrator can create symbolic - * links for some reason. By default we just issue a warning if this - * appears to be the problem. Use WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS - * to get a hard error. */ - if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS) - && (status == STATUS_PRIVILEGE_NOT_HELD || - status == STATUS_ACCESS_DENIED) - && (dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK || - dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT)) - { - WARNING("Can't create symbolic link \"%ls\"! \n" - " (Need Administrator rights, or at least " - "the\n" - " SeCreateSymbolicLink privilege.)", - current_path(ctx)); - return 0; - } - -fail: - winnt_error(status, L"Can't set reparse data on \"%ls\"", - current_path(ctx)); - return WIMLIB_ERR_SET_REPARSE_DATA; -} - /* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a * pointer to the suffix of the path that begins with the device directly, such * as e:\Windows\System32. */ @@ -2178,18 +2159,12 @@ begin_extract_blob(struct blob_descriptor *blob, void *_ctx) } else { /* Hard links not supported. Extract the blob * separately to each alias of the inode. */ - struct list_head *next; - - next = inode->i_extraction_aliases.next; - do { - dentry = list_entry(next, struct wim_dentry, - d_extraction_alias_node); + inode_for_each_extraction_alias(dentry, inode) { ret = begin_extract_blob_instance(blob, dentry, strm, ctx); ret = check_apply_error(dentry, ctx, ret); if (ret) goto fail; - next = next->next; - } while (next != &inode->i_extraction_aliases); + } } } @@ -2254,7 +2229,7 @@ end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx) if (!list_empty(&ctx->reparse_dentries)) { if (blob->size > REPARSE_DATA_MAX_SIZE) { dentry = list_first_entry(&ctx->reparse_dentries, - struct wim_dentry, tmp_list); + struct wim_dentry, d_tmp_list); build_extraction_path(dentry, ctx); ERROR("Reparse data of \"%ls\" has size " "%"PRIu64" bytes (exceeds %u bytes)", @@ -2266,7 +2241,7 @@ end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx) /* Reparse data */ memcpy(ctx->rpbuf.rpdata, ctx->data_buffer, blob->size); - list_for_each_entry(dentry, &ctx->reparse_dentries, tmp_list) { + list_for_each_entry(dentry, &ctx->reparse_dentries, d_tmp_list) { /* Reparse point header */ complete_reparse_point(&ctx->rpbuf, dentry->d_inode, @@ -2283,7 +2258,7 @@ end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx) if (!list_empty(&ctx->encrypted_dentries)) { ctx->encrypted_size = blob->size; - list_for_each_entry(dentry, &ctx->encrypted_dentries, tmp_list) { + list_for_each_entry(dentry, &ctx->encrypted_dentries, d_tmp_list) { ret = extract_encrypted_file(dentry, ctx); ret = check_apply_error(dentry, ctx, ret); if (ret) @@ -2451,7 +2426,7 @@ do_apply_metadata_to_file(HANDLE h, const struct wim_inode *inode, NTSTATUS status; /* Set security descriptor if present and not in NO_ACLS mode */ - if (inode->i_security_id >= 0 && + if (inode_has_security_descriptor(inode) && !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS)) { const struct wim_security_data *sd;