#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 {
* 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;
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
* 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;
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;
* 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;
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,
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);
}
/*
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). */
*/
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;
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,
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];
* 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);
/* 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++;
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;
}
/*
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)
if (ret)
goto out_close;
- ret = create_empty_named_data_streams(dentry, ctx);
+ ret = create_empty_streams(dentry, ctx);
if (ret)
goto out_close;
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;
}
* 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;
}
* 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;
}
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. */
} 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);
+ }
}
}
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)",
/* 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,
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)
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;