X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwin32_common.c;h=628f1f0bb7ebd8284b81876970c2c258f2b8580e;hp=6d75c47e26b44c12e79c1576d6b588b9ec99fea2;hb=686c407415c8e6ec022bd64678db65004631b194;hpb=a92076249aa233d18ecc378062e654729e27c0d8 diff --git a/src/win32_common.c b/src/win32_common.c index 6d75c47e..628f1f0b 100644 --- a/src/win32_common.c +++ b/src/win32_common.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2013, 2014, 2015 Eric Biggers + * Copyright (C) 2013-2016 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 @@ -27,8 +27,10 @@ #include "wimlib/win32_common.h" +#include "wimlib/assert.h" #include "wimlib/error.h" #include "wimlib/util.h" +#include "wimlib/win32_vss.h" static bool win32_modify_privilege(const wchar_t *privilege, bool enable) @@ -62,16 +64,21 @@ out: static bool win32_modify_capture_privileges(bool enable) { - return win32_modify_privilege(SE_BACKUP_NAME, enable) - && win32_modify_privilege(SE_SECURITY_NAME, enable); + bool ok = true; + ok &= win32_modify_privilege(SE_BACKUP_NAME, enable); + ok &= win32_modify_privilege(SE_SECURITY_NAME, enable); + return ok; } static bool win32_modify_apply_privileges(bool enable) { - return win32_modify_privilege(SE_RESTORE_NAME, enable) - && win32_modify_privilege(SE_SECURITY_NAME, enable) - && win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable); + bool ok = true; + ok &= win32_modify_privilege(SE_RESTORE_NAME, enable); + ok &= win32_modify_privilege(SE_SECURITY_NAME, enable); + ok &= win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable); + ok &= win32_modify_privilege(SE_MANAGE_VOLUME_NAME, enable); + return ok; } static void @@ -164,16 +171,20 @@ NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor); -NTSTATUS (WINAPI *func_NtFsControlFile) (HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG FsControlCode, - PVOID InputBuffer, - ULONG InputBufferLength, - PVOID OutputBuffer, - ULONG OutputBufferLength); +static NTSTATUS (WINAPI *func_NtFsControlFile) (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG FsControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength); + +static NTSTATUS (WINAPI *func_NtWaitForSingleObject) (HANDLE Handle, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout); NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle); @@ -227,6 +238,7 @@ struct dll_spec ntdll_spec = { DLL_SYM(NtSetInformationFile, true), DLL_SYM(NtSetSecurityObject, true), DLL_SYM(NtFsControlFile, true), + DLL_SYM(NtWaitForSingleObject, true), DLL_SYM(NtClose, true), DLL_SYM(RtlNtStatusToDosError, true), DLL_SYM(RtlCreateSystemVolumeInformationFolder, false), @@ -311,6 +323,8 @@ out_drop_privs: void win32_global_cleanup(void) { + vss_global_cleanup(); + if (acquired_privileges) win32_release_capture_and_apply_privileges(); @@ -350,8 +364,7 @@ win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path) if (status == STATUS_NO_MEMORY) return WIMLIB_ERR_NOMEM; - ERROR("\"%ls\": invalid path name (status=0x%08"PRIx32")", - win32_path, (u32)status); + winnt_error(status, L"\"%ls\": invalid path name", win32_path); return WIMLIB_ERR_INVALID_PARAM; } @@ -375,6 +388,51 @@ win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7]) return 0; } +/* Try to attach an instance of the Windows Overlay File System Filter Driver to + * the specified drive (such as C:) */ +bool +win32_try_to_attach_wof(const wchar_t *drive) +{ + HMODULE fltlib; + bool retval = false; + + /* Use FilterAttach() from Fltlib.dll. */ + + fltlib = LoadLibrary(L"Fltlib.dll"); + + if (!fltlib) { + WARNING("Failed to load Fltlib.dll"); + return retval; + } + + HRESULT (WINAPI *func_FilterAttach)(LPCWSTR lpFilterName, + LPCWSTR lpVolumeName, + LPCWSTR lpInstanceName, + DWORD dwCreatedInstanceNameLength, + LPWSTR lpCreatedInstanceName); + + func_FilterAttach = (void *)GetProcAddress(fltlib, "FilterAttach"); + + if (func_FilterAttach) { + HRESULT res; + + res = (*func_FilterAttach)(L"wof", drive, NULL, 0, NULL); + + if (res != S_OK) + res = (*func_FilterAttach)(L"wofadk", drive, NULL, 0, NULL); + + if (res == S_OK) + retval = true; + } else { + WARNING("FilterAttach() does not exist in Fltlib.dll"); + } + + FreeLibrary(fltlib); + + return retval; +} + + static void windows_msg(u32 code, const wchar_t *format, va_list va, bool is_ntstatus, bool is_error) @@ -400,9 +458,11 @@ retry: if (n >= buflen) goto realloc; - ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - is_ntstatus ? (*func_RtlNtStatusToDosError)(code) : code, + ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + (is_ntstatus ? FORMAT_MESSAGE_FROM_HMODULE : 0), + (is_ntstatus ? ntdll_spec.handle : NULL), + code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &buf[n], buflen - n, @@ -477,4 +537,40 @@ winnt_error(NTSTATUS status, const wchar_t *format, ...) va_end(va); } +/* + * Synchronously execute a filesystem control method. This is a wrapper around + * NtFsControlFile() that handles STATUS_PENDING. Note that SYNCHRONIZE + * permission is, in general, required on the handle. + */ +NTSTATUS +winnt_fsctl(HANDLE h, u32 code, const void *in, u32 in_size, + void *out, u32 out_size_avail, u32 *actual_out_size_ret) +{ + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + status = (*func_NtFsControlFile)(h, NULL, NULL, NULL, &iosb, code, + (void *)in, in_size, + out, out_size_avail); + if (status == STATUS_PENDING) { + /* Beware: this case is often encountered with remote + * filesystems, but rarely with local filesystems. */ + + status = (*func_NtWaitForSingleObject)(h, FALSE, NULL); + if (NT_SUCCESS(status)) { + status = iosb.Status; + } else { + /* We shouldn't be issuing ioctls on a handle to which + * we don't have SYNCHRONIZE access. Otherwise we have + * no way to wait for them to complete. */ + wimlib_assert(status != STATUS_ACCESS_DENIED); + } + } + + if (NT_SUCCESS(status) && actual_out_size_ret != NULL) + *actual_out_size_ret = (u32)iosb.Information; + + return status; +} + #endif /* __WIN32__ */