*/
/*
- * Copyright (C) 2013, 2014 Eric Biggers
+ * Copyright (C) 2013, 2014, 2015 Eric Biggers
*
* 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
vol_flags_ret, filesystem_name,
ARRAY_LEN(filesystem_name)))
{
- DWORD err = GetLastError();
- set_errno_from_win32_error(err);
- WARNING_WITH_ERRNO("Failed to get volume information for "
- "\"%ls\" (err=%"PRIu32")",
- target, (u32)err);
+ win32_warning(GetLastError(),
+ L"Failed to get volume information for \"%ls\"",
+ target);
return;
}
const DWORD err = GetLastError();
build_extraction_path(inode_first_extraction_dentry(inode), ctx);
- set_errno_from_win32_error(err);
- ERROR_WITH_ERRNO("\"%ls\": Couldn't set WIMBoot "
- "pointer data (err=%"PRIu32")",
- current_path(ctx), (u32)err);
+ win32_error(err, L"\"%ls\": Couldn't set WIMBoot pointer data",
+ current_path(ctx));
return WIMLIB_ERR_WIMBOOT;
}
return 0;
out_check_res:
if (res) {
/* Warning only. */
- set_errno_from_win32_error(res);
- WARNING_WITH_ERRNO("Failed to set \\Setup: dword \"WimBoot\"=1 value "
- "in registry hive \"%ls\" (err=%"PRIu32")",
- ctx->pathbuf.Buffer, (u32)res);
+ win32_warning(res, L"Failed to set \\Setup: dword \"WimBoot\"=1 "
+ "value in registry hive \"%ls\"",
+ ctx->pathbuf.Buffer);
}
out:
return 0;
return ctx->print_buffer;
}
-/*
- * Ensures the target directory exists and opens a handle to it, in preparation
- * of using paths relative to it.
- */
+/* Open handle to the target directory if it is not already open. If the target
+ * directory does not exist, this creates it. */
static int
-prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
+open_target_directory(struct win32_apply_ctx *ctx)
{
- int ret;
NTSTATUS status;
- size_t path_max;
- /* Open handle to the target directory (possibly creating it). */
-
- ret = win32_path_to_nt_path(ctx->common.target, &ctx->target_ntpath);
- if (ret)
- return ret;
+ if (ctx->h_target)
+ return 0;
ctx->attr.Length = sizeof(ctx->attr);
+ ctx->attr.RootDirectory = NULL;
ctx->attr.ObjectName = &ctx->target_ntpath;
-
status = (*func_NtCreateFile)(&ctx->h_target,
FILE_TRAVERSE,
&ctx->attr,
FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0);
-
if (!NT_SUCCESS(status)) {
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't open or create directory \"%ls\" "
- "(status=0x%08"PRIx32")",
- ctx->common.target, (u32)status);
+ winnt_error(status, L"Can't open or create directory \"%ls\"",
+ ctx->common.target);
return WIMLIB_ERR_OPENDIR;
}
+ ctx->attr.RootDirectory = ctx->h_target;
+ ctx->attr.ObjectName = &ctx->pathbuf;
+ return 0;
+}
- path_max = compute_path_max(dentry_list);
+static void
+close_target_directory(struct win32_apply_ctx *ctx)
+{
+ if (ctx->h_target) {
+ (*func_NtClose)(ctx->h_target);
+ ctx->h_target = NULL;
+ ctx->attr.RootDirectory = NULL;
+ }
+}
+/*
+ * Ensures the target directory exists and opens a handle to it, in preparation
+ * of using paths relative to it.
+ */
+static int
+prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
+{
+ int ret;
+ size_t path_max;
+
+ ret = win32_path_to_nt_path(ctx->common.target, &ctx->target_ntpath);
+ if (ret)
+ return ret;
+
+ ret = open_target_directory(ctx);
+ if (ret)
+ return ret;
+
+ path_max = compute_path_max(dentry_list);
/* Add some extra for building Win32 paths for the file encryption APIs,
* and ensure we have at least enough to potentially use a 8.3 name for
* the last component. */
if (!ctx->pathbuf.Buffer)
return WIMLIB_ERR_NOMEM;
- ctx->attr.RootDirectory = ctx->h_target;
- ctx->attr.ObjectName = &ctx->pathbuf;
-
ctx->print_buffer = MALLOC((ctx->common.target_nchars + 1 + path_max + 1) *
sizeof(wchar_t));
if (!ctx->print_buffer)
if (NT_SUCCESS(status))
return 0;
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't %s compression attribute on \"%ls\" "
- "(status=0x%08"PRIx32")",
- (compressed ? "set" : "clear"),
- current_path(ctx), status);
+ winnt_error(status, L"Can't %s compression attribute on \"%ls\"",
+ (compressed ? "set" : "clear"), current_path(ctx));
return WIMLIB_ERR_SET_ATTRIBUTES;
}
-/*
- * Clear FILE_ATTRIBUTE_ENCRYPTED if the file or directory is not supposed to be
- * encrypted.
- *
- * You can provide FILE_ATTRIBUTE_ENCRYPTED to NtCreateFile() to set it on the
- * created file. However, the file or directory will otherwise default to the
- * encryption state of the parent directory. This function works around this
- * limitation by using DecryptFile() to remove FILE_ATTRIBUTE_ENCRYPTED on files
- * (and directories) that are not supposed to have it set.
- *
- * Regardless of whether it succeeds or fails, this function may close the
- * handle to the file. If it does, it sets it to NULL.
- */
-static int
-maybe_clear_encryption_attribute(HANDLE *h_ptr, const struct wim_dentry *dentry,
- struct win32_apply_ctx *ctx)
-{
- if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
- return 0;
-
- if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
- return 0;
-
- if (!ctx->common.supported_features.encrypted_files)
- return 0;
-
- FILE_BASIC_INFORMATION info;
- NTSTATUS status;
- BOOL bret;
-
- /* Get current attributes */
- status = (*func_NtQueryInformationFile)(*h_ptr, &ctx->iosb,
- &info, sizeof(info),
- FileBasicInformation);
- if (NT_SUCCESS(status) &&
- !(info.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED))
- {
- /* Nothing needs to be done. */
- return 0;
- }
-
- /* Set the new encryption state */
-
- /* Due to Windows' crappy file encryption APIs, we need to close the
- * handle to the file so we don't get ERROR_SHARING_VIOLATION. We also
- * hack together a Win32 path, although we will use the \\?\ prefix so
- * it will actually be a NT path in disguise... */
- (*func_NtClose)(*h_ptr);
- *h_ptr = NULL;
-
- build_win32_extraction_path(dentry, ctx);
-
- bret = DecryptFile(ctx->pathbuf.Buffer, 0);
-
- /* Restore the NT namespace path */
- build_extraction_path(dentry, ctx);
-
- if (!bret) {
- DWORD err = GetLastError();
- set_errno_from_win32_error(err);
- ERROR_WITH_ERRNO("Can't decrypt file \"%ls\" (err=%"PRIu32")",
- current_path(ctx), (u32)err);
- return WIMLIB_ERR_SET_ATTRIBUTES;
- }
- return 0;
-}
-
/* Try to enable short name support on the target volume. If successful, return
* true. If unsuccessful, issue a warning and return false. */
static bool
return true;
fail:
- WARNING("Failed to enable short name support on %ls "
- "(err=%"PRIu32")", volume + 4, (u32)GetLastError());
+ win32_warning(GetLastError(),
+ L"Failed to enable short name support on %ls",
+ volume + 4);
return false;
}
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(status)) {
- WARNING("Can't open \"%ls\" (status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_warning(status, L"Can't open \"%ls\"", current_path(ctx));
goto out;
}
return 0;
}
- if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) {
- ERROR("Can't set short name when short "
- "names are not enabled on the volume!");
- } else {
- ERROR("Can't set short name on \"%ls\" (status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
- }
+ winnt_error(status, L"Can't set short name on \"%ls\"", current_path(ctx));
return WIMLIB_ERR_SET_SHORT_NAME;
}
ctx);
}
+static int
+delete_file_or_stream(struct win32_apply_ctx *ctx)
+{
+ NTSTATUS status;
+ HANDLE h;
+ FILE_DISPOSITION_INFORMATION disposition_info;
+ FILE_BASIC_INFORMATION basic_info;
+ bool retried = false;
+
+ status = do_create_file(&h,
+ DELETE,
+ NULL,
+ 0,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE,
+ ctx);
+ if (unlikely(!NT_SUCCESS(status))) {
+ winnt_error(status, L"Can't open \"%ls\" for deletion",
+ current_path(ctx));
+ return WIMLIB_ERR_OPEN;
+ }
+
+retry:
+ disposition_info.DoDeleteFile = TRUE;
+ status = (*func_NtSetInformationFile)(h, &ctx->iosb,
+ &disposition_info,
+ sizeof(disposition_info),
+ FileDispositionInformation);
+ (*func_NtClose)(h);
+ if (likely(NT_SUCCESS(status)))
+ return 0;
+
+ if (status == STATUS_CANNOT_DELETE && !retried) {
+ /* Clear file attributes and try again. This is necessary for
+ * FILE_ATTRIBUTE_READONLY files. */
+ status = do_create_file(&h,
+ FILE_WRITE_ATTRIBUTES | DELETE,
+ NULL,
+ 0,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE,
+ ctx);
+ if (!NT_SUCCESS(status)) {
+ winnt_error(status,
+ L"Can't open \"%ls\" to reset attributes",
+ current_path(ctx));
+ return WIMLIB_ERR_OPEN;
+ }
+ memset(&basic_info, 0, sizeof(basic_info));
+ basic_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ status = (*func_NtSetInformationFile)(h, &ctx->iosb,
+ &basic_info,
+ sizeof(basic_info),
+ FileBasicInformation);
+ if (!NT_SUCCESS(status)) {
+ winnt_error(status,
+ L"Can't reset file attributes on \"%ls\"",
+ current_path(ctx));
+ (*func_NtClose)(h);
+ return WIMLIB_ERR_SET_ATTRIBUTES;
+ }
+ retried = true;
+ goto retry;
+ }
+ winnt_error(status, L"Can't delete \"%ls\"", current_path(ctx));
+ return WIMLIB_ERR_OPEN;
+}
+
+/*
+ * Create a nondirectory file or named data stream at the current path,
+ * superseding any that already exists at that path. If successful, return an
+ * open handle to the file or named data stream.
+ */
+static int
+supersede_file_or_stream(struct win32_apply_ctx *ctx, HANDLE *h_ret)
+{
+ NTSTATUS status;
+ bool retried = false;
+
+ /* FILE_ATTRIBUTE_SYSTEM is needed to ensure that
+ * FILE_ATTRIBUTE_ENCRYPTED doesn't get set before we want it to be. */
+retry:
+ status = do_create_file(h_ret,
+ GENERIC_READ | GENERIC_WRITE | DELETE,
+ NULL,
+ FILE_ATTRIBUTE_SYSTEM,
+ FILE_CREATE,
+ FILE_NON_DIRECTORY_FILE,
+ ctx);
+ if (likely(NT_SUCCESS(status)))
+ return 0;
+
+ /* STATUS_OBJECT_NAME_COLLISION means that the file or stream already
+ * exists. Delete the existing file or stream, then try again.
+ *
+ * Note: we don't use FILE_OVERWRITE_IF or FILE_SUPERSEDE because of
+ * problems with certain file attributes, especially
+ * FILE_ATTRIBUTE_ENCRYPTED. FILE_SUPERSEDE is also broken in the
+ * Windows PE ramdisk. */
+ if (status == STATUS_OBJECT_NAME_COLLISION && !retried) {
+ int ret = delete_file_or_stream(ctx);
+ if (ret)
+ return ret;
+ retried = true;
+ goto retry;
+ }
+ winnt_error(status, L"Can't create \"%ls\"", current_path(ctx));
+ return WIMLIB_ERR_OPEN;
+}
+
/* Create empty named data streams.
*
* Since these won't have 'struct wim_lookup_table_entry's, they won't show up
struct win32_apply_ctx *ctx)
{
const struct wim_inode *inode = dentry->d_inode;
- LARGE_INTEGER allocation_size;
bool path_modified = false;
int ret = 0;
for (u16 i = 0; i < inode->i_num_ads; i++) {
const struct wim_ads_entry *entry;
- NTSTATUS status;
HANDLE h;
- bool retried;
- DWORD disposition;
entry = &inode->i_ads_entries[i];
if (entry->lte)
continue;
- /* Probably setting the allocation size to 0 has no effect, but
- * we might as well try. */
- allocation_size.QuadPart = 0;
-
build_extraction_path_with_ads(dentry, ctx,
entry->stream_name,
entry->stream_name_nbytes /
sizeof(wchar_t));
path_modified = true;
-
- retried = false;
- disposition = FILE_SUPERSEDE;
- retry:
- status = do_create_file(&h, FILE_WRITE_DATA, &allocation_size,
- 0, disposition, 0, ctx);
- if (unlikely(!NT_SUCCESS(status))) {
- if (status == STATUS_OBJECT_NAME_NOT_FOUND && !retried) {
- /* Workaround for defect in the Windows PE
- * in-memory filesystem implementation:
- * FILE_SUPERSEDE does not create the file, as
- * expected and documented, when the named file
- * does not exist. */
- retried = true;
- disposition = FILE_CREATE;
- goto retry;
- }
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't create \"%ls\" "
- "(status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
- ret = WIMLIB_ERR_OPEN;
+ ret = supersede_file_or_stream(ctx, &h);
+ if (ret)
break;
- }
(*func_NtClose)(h);
}
/* Restore the path to the dentry itself */
HANDLE h;
NTSTATUS status;
int ret;
- ULONG attrib;
- /* Special attributes:
- *
- * Use FILE_ATTRIBUTE_ENCRYPTED if the directory needs to have it set.
- * This doesn't work for FILE_ATTRIBUTE_COMPRESSED (unfortunately).
+ /* DELETE is needed for set_short_name(); GENERIC_READ and GENERIC_WRITE
+ * are needed for adjust_compression_attribute().
*
- * Don't specify FILE_ATTRIBUTE_DIRECTORY; it gets set anyway as a
- * result of the FILE_DIRECTORY_FILE option. */
- attrib = (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED);
-
- /* DELETE is needed for set_short_name().
- * GENERIC_READ and GENERIC_WRITE are needed for
- * adjust_compression_attribute(). */
+ * FILE_ATTRIBUTE_SYSTEM is needed to ensure that
+ * FILE_ATTRIBUTE_ENCRYPTED doesn't get set before we want it to be. */
status = create_file(&h, GENERIC_READ | GENERIC_WRITE | DELETE, NULL,
- attrib, FILE_OPEN_IF, FILE_DIRECTORY_FILE,
+ FILE_ATTRIBUTE_SYSTEM, FILE_OPEN_IF, FILE_DIRECTORY_FILE,
dentry, ctx);
if (!NT_SUCCESS(status)) {
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't create directory \"%ls\" "
- "(status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status, L"Can't create directory \"%ls\"",
+ current_path(ctx));
return WIMLIB_ERR_MKDIR;
}
if (!ret)
ret = adjust_compression_attribute(h, dentry, ctx);
- if (!ret)
- ret = maybe_clear_encryption_attribute(&h, dentry, ctx);
- /* May close the handle!!! */
-
- if (h)
- (*func_NtClose)(h);
+ (*func_NtClose)(h);
return ret;
}
*
* On success, returns an open handle to the file in @h_ret, with GENERIC_READ,
* GENERIC_WRITE, and DELETE access. Also, the path to the file will be saved
- * in ctx->pathbuf. On failure, returns WIMLIB_ERR_OPEN.
+ * in ctx->pathbuf. On failure, returns an error code.
*/
static int
create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry,
struct win32_apply_ctx *ctx)
{
- const struct wim_inode *inode;
- ULONG attrib;
- NTSTATUS status;
- bool retried = false;
- DWORD disposition;
-
- inode = dentry->d_inode;
+ int ret;
+ HANDLE h;
- /* If the file already exists and has FILE_ATTRIBUTE_SYSTEM and/or
- * FILE_ATTRIBUTE_HIDDEN, these must be specified in order to supersede
- * the file.
- *
- * Normally the user shouldn't be trying to overwrite such files anyway,
- * but we at least provide FILE_ATTRIBUTE_SYSTEM and
- * FILE_ATTRIBUTE_HIDDEN if the WIM inode has those attributes so that
- * we catch the case where the user extracts the same files to the same
- * location more than one time.
- *
- * Also specify FILE_ATTRIBUTE_ENCRYPTED if the file needs to be
- * encrypted.
- *
- * In NO_ATTRIBUTES mode just don't specify any attributes at all.
- */
- if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES) {
- attrib = 0;
- } else {
- attrib = (inode->i_attributes & (FILE_ATTRIBUTE_SYSTEM |
- FILE_ATTRIBUTE_HIDDEN |
- FILE_ATTRIBUTE_ENCRYPTED));
- }
build_extraction_path(dentry, ctx);
- disposition = FILE_SUPERSEDE;
-retry:
- status = do_create_file(h_ret, GENERIC_READ | GENERIC_WRITE | DELETE,
- NULL, attrib, disposition,
- FILE_NON_DIRECTORY_FILE, ctx);
- if (likely(NT_SUCCESS(status))) {
- int ret;
-
- ret = adjust_compression_attribute(*h_ret, dentry, ctx);
- if (ret) {
- (*func_NtClose)(*h_ret);
- return ret;
- }
-
- ret = maybe_clear_encryption_attribute(h_ret, dentry, ctx);
- /* May close the handle!!! */
-
- if (ret) {
- if (*h_ret)
- (*func_NtClose)(*h_ret);
- return ret;
- }
-
- if (!*h_ret) {
- /* Re-open the handle so that we can return it on
- * success. */
- status = do_create_file(h_ret,
- GENERIC_READ |
- GENERIC_WRITE | DELETE,
- NULL, 0, FILE_OPEN,
- FILE_NON_DIRECTORY_FILE, ctx);
- if (!NT_SUCCESS(status))
- goto fail;
- }
-
- ret = create_any_empty_ads(dentry, ctx);
- if (ret) {
- (*func_NtClose)(*h_ret);
- return ret;
- }
- return 0;
- }
- if (status == STATUS_OBJECT_NAME_NOT_FOUND && !retried) {
- /* Workaround for defect in the Windows PE in-memory filesystem
- * implementation: FILE_SUPERSEDE does not create the file, as
- * expected and documented, when the named file does not exist.
- */
- retried = true;
- disposition = FILE_CREATE;
- goto retry;
- }
-
- if (status == STATUS_ACCESS_DENIED && !retried) {
- /* We also can't supersede an existing file that has
- * FILE_ATTRIBUTE_READONLY set; doing so causes NtCreateFile()
- * to return STATUS_ACCESS_DENIED . The only workaround seems
- * to be to explicitly remove FILE_ATTRIBUTE_READONLY on the
- * existing file, then try again. */
+ ret = supersede_file_or_stream(ctx, &h);
+ if (ret)
+ goto out;
- FILE_BASIC_INFORMATION info;
- HANDLE h;
+ ret = adjust_compression_attribute(h, dentry, ctx);
+ if (ret)
+ goto out_close;
- status = do_create_file(&h, FILE_WRITE_ATTRIBUTES, NULL, 0,
- FILE_OPEN, FILE_NON_DIRECTORY_FILE, ctx);
- if (!NT_SUCCESS(status))
- goto fail;
+ ret = create_any_empty_ads(dentry, ctx);
+ if (ret)
+ goto out_close;
- memset(&info, 0, sizeof(info));
- info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ *h_ret = h;
+ return 0;
- status = (*func_NtSetInformationFile)(h, &ctx->iosb,
- &info, sizeof(info),
- FileBasicInformation);
- (*func_NtClose)(h);
- if (!NT_SUCCESS(status))
- goto fail;
- retried = true;
- goto retry;
- }
-fail:
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't create file \"%ls\" (status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
- return WIMLIB_ERR_OPEN;
+out_close:
+ (*func_NtClose)(h);
+out:
+ return ret;
}
/* Creates a hard link at the location named by @dentry to the file represented
FileLinkInformation);
if (NT_SUCCESS(status))
return 0;
- ERROR("Failed to create link \"%ls\" (status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status, L"Failed to create link \"%ls\"",
+ current_path(ctx));
return WIMLIB_ERR_LINK;
} else {
HANDLE h2;
FILE_SYNCHRONOUS_IO_NONALERT,
ctx);
if (!NT_SUCCESS(status)) {
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't open \"%ls\" for writing "
- "(status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status, L"Can't open \"%ls\" for writing",
+ current_path(ctx));
return WIMLIB_ERR_OPEN;
}
}
fail:
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't set reparse data on \"%ls\" "
- "(status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status, L"Can't set reparse data on \"%ls\"",
+ current_path(ctx));
return WIMLIB_ERR_SET_REPARSE_DATA;
}
return ERROR_SUCCESS;
}
-/* Write the raw encrypted data to the already-created file corresponding to
- * @dentry.
+/*
+ * Write the raw encrypted data to the already-created file (or directory)
+ * corresponding to @dentry.
*
* The raw encrypted data is provided in ctx->data_buffer, and its size is
- * ctx->encrypted_size. */
+ * ctx->encrypted_size.
+ *
+ * This function may close the target directory, in which case the caller needs
+ * to re-open it if needed.
+ */
static int
extract_encrypted_file(const struct wim_dentry *dentry,
struct win32_apply_ctx *ctx)
{
void *rawctx;
DWORD err;
+ ULONG flags;
+ bool retried;
/* Temporarily build a Win32 path for OpenEncryptedFileRaw() */
build_win32_extraction_path(dentry, ctx);
- err = OpenEncryptedFileRaw(ctx->pathbuf.Buffer,
- CREATE_FOR_IMPORT, &rawctx);
+ flags = CREATE_FOR_IMPORT | OVERWRITE_HIDDEN;
+ if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+ flags |= CREATE_FOR_DIR;
+
+ retried = false;
+retry:
+ err = OpenEncryptedFileRaw(ctx->pathbuf.Buffer, flags, &rawctx);
+ if (err == ERROR_SHARING_VIOLATION && !retried) {
+ /* This can be caused by the handle we have open to the target
+ * directory. Try closing it temporarily. */
+ close_target_directory(ctx);
+ retried = true;
+ goto retry;
+ }
/* Restore the NT namespace path */
build_extraction_path(dentry, ctx);
if (err != ERROR_SUCCESS) {
- set_errno_from_win32_error(err);
- ERROR_WITH_ERRNO("Can't open \"%ls\" for encrypted import "
- "(err=%"PRIu32")", current_path(ctx), (u32)err);
+ win32_error(err, L"Can't open \"%ls\" for encrypted import",
+ current_path(ctx));
return WIMLIB_ERR_OPEN;
}
CloseEncryptedFileRaw(rawctx);
if (err != ERROR_SUCCESS) {
- set_errno_from_win32_error(err);
- ERROR_WITH_ERRNO("Can't import encrypted file \"%ls\" "
- "(err=%"PRIu32")", current_path(ctx), (u32)err);
+ win32_error(err, L"Can't import encrypted file \"%ls\"",
+ current_path(ctx));
return WIMLIB_ERR_WRITE;
}
&ctx->iosb, bufptr, count,
NULL, NULL);
if (!NT_SUCCESS(status)) {
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Error writing data to target "
- "volume (status=0x%08"PRIx32")",
- (u32)status);
+ winnt_error(status, L"Error writing data to target volume");
return WIMLIB_ERR_WRITE;
}
bufptr += ctx->iosb.Information;
ret = check_apply_error(dentry, ctx, ret);
if (ret)
return ret;
+ /* Re-open the target directory if needed. */
+ ret = open_target_directory(ctx);
+ if (ret)
+ return ret;
}
}
if (!NT_SUCCESS(status) &&
(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
{
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't set security descriptor "
- "on \"%ls\" (status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status,
+ L"Can't set security descriptor on \"%ls\"",
+ current_path(ctx));
return WIMLIB_ERR_SET_SECURITY;
}
}
info.LastAccessTime.QuadPart = inode->i_last_access_time;
info.LastWriteTime.QuadPart = inode->i_last_write_time;
info.ChangeTime.QuadPart = 0;
- if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
- info.FileAttributes = 0;
- else
+ if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES) {
+ info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ } else {
info.FileAttributes = inode->i_attributes & ~SPECIAL_ATTRIBUTES;
+ if (info.FileAttributes == 0)
+ info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ }
status = (*func_NtSetInformationFile)(h, &ctx->iosb,
&info, sizeof(info),
&& !(status == STATUS_INVALID_PARAMETER &&
dentry_is_root(inode_first_extraction_dentry(inode))))
{
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't set basic metadata on \"%ls\" "
- "(status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status, L"Can't set basic metadata on \"%ls\"",
+ current_path(ctx));
return WIMLIB_ERR_SET_ATTRIBUTES;
}
continue;
}
}
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("Can't open \"%ls\" to set metadata "
- "(status=0x%08"PRIx32")",
- current_path(ctx), (u32)status);
+ winnt_error(status, L"Can't open \"%ls\" to set metadata",
+ current_path(ctx));
return WIMLIB_ERR_OPEN;
}
do_warnings(ctx);
out:
- if (ctx->h_target)
- (*func_NtClose)(ctx->h_target);
+ close_target_directory(ctx);
if (ctx->target_ntpath.Buffer)
HeapFree(GetProcessHeap(), 0, ctx->target_ntpath.Buffer);
FREE(ctx->pathbuf.Buffer);