From e0cb5f9264bdea9938e48a37ebe9007467c0dd46 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 17 Aug 2014 11:18:47 -0500 Subject: [PATCH] win32_apply.c: Adjust short name behavior - Try to enable short names on the volume if it seems to be necessary to set short names. - Without WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES, still warn about how many short names could not be set. --- include/wimlib/win32_common.h | 11 +++++ src/win32_apply.c | 76 ++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/include/wimlib/win32_common.h b/include/wimlib/win32_common.h index 8b4a48d4..7cd991ed 100644 --- a/include/wimlib/win32_common.h +++ b/include/wimlib/win32_common.h @@ -143,6 +143,17 @@ extern NTSTATUS (WINAPI *func_RtlDosPathNameToNtPathName_U_WithStatus) extern NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder) (PCUNICODE_STRING VolumeRootPath); +#define FSCTL_SET_PERSISTENT_VOLUME_STATE 0x90238 + +#define PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED 0x00000001 + +typedef struct _FILE_FS_PERSISTENT_VOLUME_INFORMATION { + ULONG VolumeFlags; + ULONG FlagMask; + ULONG Version; + ULONG Reserved; +} FILE_FS_PERSISTENT_VOLUME_INFORMATION, *PFILE_FS_PERSISTENT_VOLUME_INFORMATION; + extern int win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path); diff --git a/src/win32_apply.c b/src/win32_apply.c index f871f020..89ecd21c 100644 --- a/src/win32_apply.c +++ b/src/win32_apply.c @@ -124,6 +124,13 @@ struct win32_apply_ctx { /* Number of files for which we didn't have permission to set any part * of the security descriptor. */ unsigned long no_security_descriptors; + + /* Number of files for which we couldn't set the short name. */ + unsigned long num_short_name_failures; + + /* Have we tried to enable short name support on the target volume yet? + */ + bool tried_to_enable_short_names; }; /* Get the drive letter from a Windows path, or return the null character if the @@ -408,7 +415,7 @@ out_check_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=0x%08"PRIu32")", + "in registry hive \"%ls\" (err=%"PRIu32")", ctx->pathbuf.Buffer, (u32)res); } out: @@ -789,6 +796,32 @@ maybe_clear_encryption_attribute(HANDLE *h_ptr, const struct wim_dentry *dentry, 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 +try_to_enable_short_names(struct win32_apply_ctx *ctx) +{ + FILE_FS_PERSISTENT_VOLUME_INFORMATION info; + NTSTATUS status; + + info.VolumeFlags = 0; + info.FlagMask = PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED; + info.Version = 1; + info.Reserved = 0; + + status = (*func_NtFsControlFile)(ctx->h_target, NULL, NULL, NULL, + &ctx->iosb, + FSCTL_SET_PERSISTENT_VOLUME_STATE, + &info, sizeof(info), NULL, 0); + if (!NT_SUCCESS(status)) { + WARNING("Failed to enable short name support on target volume " + "(status=0x%08"PRIx32")", (u32)status); + return false; + } + + return true; +} + /* Set the short name on the open file @h which has been created at the location * indicated by @dentry. * @@ -803,6 +836,10 @@ static int set_short_name(HANDLE h, const struct wim_dentry *dentry, struct win32_apply_ctx *ctx) { + + if (!ctx->common.supported_features.short_names) + return 0; + size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) + dentry->short_name_nbytes; u8 buf[bufsize] _aligned_attribute(8); @@ -812,20 +849,32 @@ set_short_name(HANDLE h, const struct wim_dentry *dentry, info->FileNameLength = dentry->short_name_nbytes; memcpy(info->FileName, dentry->short_name, dentry->short_name_nbytes); + +retry: status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize, FileShortNameInformation); if (NT_SUCCESS(status)) return 0; + if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) { + if (dentry->short_name_nbytes == 0) + return 0; + if (!ctx->tried_to_enable_short_names) { + ctx->tried_to_enable_short_names = true; + if (try_to_enable_short_names(ctx)) + goto 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 (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES)) { + ctx->num_short_name_failures++; return 0; + } if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) { - if (dentry->short_name_nbytes == 0) - return 0; - ERROR("Can't extract short name when short " + 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")", @@ -2065,23 +2114,30 @@ static void do_warnings(const struct win32_apply_ctx *ctx) { if (ctx->partial_security_descriptors == 0 && - ctx->no_security_descriptors == 0) + ctx->no_security_descriptors == 0 && + ctx->num_short_name_failures == 0) return; WARNING("Extraction to \"%ls\" complete, but with one or more warnings:", ctx->common.target); - if (ctx->partial_security_descriptors != 0) { + if (ctx->num_short_name_failures) { + WARNING("- Could not set short names on %lu files or directories", + ctx->num_short_name_failures); + } + if (ctx->partial_security_descriptors) { WARNING("- Could only partially set the security descriptor\n" " on %lu files or directories.", ctx->partial_security_descriptors); } - if (ctx->no_security_descriptors != 0) { + if (ctx->no_security_descriptors) { WARNING("- Could not set security descriptor at all\n" " on %lu files or directories.", ctx->no_security_descriptors); } - WARNING("To fully restore all security descriptors, run the program\n" - " with Administrator rights."); + if (ctx->partial_security_descriptors || ctx->no_security_descriptors) { + WARNING("To fully restore all security descriptors, run the program\n" + " with Administrator rights."); + } } /* Extract files from a WIM image to a directory on Windows */ -- 2.43.0