X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwin32_common.c;h=514965b869091c8741519cedaad8f412afba0942;hp=30f7d6238c9f8b20835debeebe2171b0491e6548;hb=5260cf0b5649fc25b9d69a97f9604a3be257e13e;hpb=873a86a1a5097f2a161494341d8d962453a30465 diff --git a/src/win32_common.c b/src/win32_common.c index 30f7d623..514965b8 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) @@ -88,108 +90,6 @@ win32_release_capture_and_apply_privileges(void) /* Pointers to dynamically loaded functions */ -/* ntdll.dll */ - -NTSTATUS (WINAPI *func_NtCreateFile)(PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocationSize, - ULONG FileAttributes, - ULONG ShareAccess, - ULONG CreateDisposition, - ULONG CreateOptions, - PVOID EaBuffer, - ULONG EaLength); - -NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, - ULONG OpenOptions); - -NTSTATUS (WINAPI *func_NtReadFile) (HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID Buffer, - ULONG Length, - PLARGE_INTEGER ByteOffset, - PULONG Key); - -NTSTATUS (WINAPI *func_NtWriteFile) (HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID Buffer, - ULONG Length, - PLARGE_INTEGER ByteOffset, - PULONG Key); - -NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass); - -NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle, - SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR SecurityDescriptor, - ULONG Length, - PULONG LengthNeeded); - -NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle, - HANDLE Event, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING FileName, - BOOLEAN RestartScan); - -NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FsInformation, - ULONG Length, - FS_INFORMATION_CLASS FsInformationClass); - -NTSTATUS (WINAPI *func_NtSetInformationFile)(HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass); - -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); - -NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle); - -DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status); - -BOOLEAN (WINAPI *func_RtlDosPathNameToNtPathName_U) - (IN PCWSTR DosName, - OUT PUNICODE_STRING NtName, - OUT PCWSTR *PartName, - OUT PRTL_RELATIVE_NAME_U RelativeName); - NTSTATUS (WINAPI *func_RtlDosPathNameToNtPathName_U_WithStatus) (IN PCWSTR DosName, OUT PUNICODE_STRING NtName, @@ -201,87 +101,26 @@ NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder) static bool acquired_privileges = false; -struct dll_sym { - void **func_ptr; - const char *name; - bool required; -}; - -#define DLL_SYM(name, required) { (void **)&func_##name, #name, required } - -#define for_each_sym(sym, spec) \ - for ((sym) = (spec)->syms; (sym)->name; (sym)++) - -struct dll_spec { - const wchar_t *name; - HMODULE handle; - const struct dll_sym syms[]; -}; - -struct dll_spec ntdll_spec = { - .name = L"ntdll.dll", - .syms = { - DLL_SYM(NtCreateFile, true), - DLL_SYM(NtOpenFile, true), - DLL_SYM(NtReadFile, true), - DLL_SYM(NtWriteFile, true), - DLL_SYM(NtQueryInformationFile, true), - DLL_SYM(NtQuerySecurityObject, true), - DLL_SYM(NtQueryDirectoryFile, true), - DLL_SYM(NtQueryVolumeInformationFile, true), - DLL_SYM(NtSetInformationFile, true), - DLL_SYM(NtSetSecurityObject, true), - DLL_SYM(NtFsControlFile, true), - DLL_SYM(NtClose, true), - DLL_SYM(RtlNtStatusToDosError, true), - DLL_SYM(RtlCreateSystemVolumeInformationFolder, false), - DLL_SYM(RtlDosPathNameToNtPathName_U, true), - DLL_SYM(RtlDosPathNameToNtPathName_U_WithStatus, false), /* Not present on XP */ - {NULL, NULL}, - }, -}; +static HMODULE ntdll_handle = NULL; static int -init_dll(struct dll_spec *spec) +init_ntdll(void) { - const struct dll_sym *sym; - void *addr; - - if (!spec->handle) - spec->handle = LoadLibrary(spec->name); - if (!spec->handle) { - for_each_sym(sym, spec) { - if (sym->required) { - ERROR("%ls could not be loaded!", spec->name); - return WIMLIB_ERR_UNSUPPORTED; - } - } - return 0; - } - for_each_sym(sym, spec) { - addr = (void *)GetProcAddress(spec->handle, sym->name); - if (addr) { - *(sym->func_ptr) = addr; - } else if (sym->required) { - ERROR("Can't find %s in %ls", sym->name, spec->name); - return WIMLIB_ERR_UNSUPPORTED; - } - } - return 0; -} + ntdll_handle = LoadLibrary(L"ntdll.dll"); -static void -cleanup_dll(struct dll_spec *spec) -{ - const struct dll_sym *sym; + if (!ntdll_handle) { + ERROR("Unable to load ntdll.dll"); + return WIMLIB_ERR_UNSUPPORTED; + } - if (spec->handle) { - FreeLibrary(spec->handle); - spec->handle = NULL; + func_RtlDosPathNameToNtPathName_U_WithStatus = + (void *)GetProcAddress(ntdll_handle, + "RtlDosPathNameToNtPathName_U_WithStatus"); - for_each_sym(sym, spec) - *(sym->func_ptr) = NULL; - } + func_RtlCreateSystemVolumeInformationFolder = + (void *)GetProcAddress(ntdll_handle, + "RtlCreateSystemVolumeInformationFolder"); + return 0; } /* One-time initialization for Windows capture/apply code. */ @@ -302,7 +141,7 @@ win32_global_init(int init_flags) acquired_privileges = true; } - ret = init_dll(&ntdll_spec); + ret = init_ntdll(); if (ret) goto out_drop_privs; @@ -316,10 +155,13 @@ out_drop_privs: void win32_global_cleanup(void) { + vss_global_cleanup(); + if (acquired_privileges) win32_release_capture_and_apply_privileges(); - cleanup_dll(&ntdll_spec); + FreeLibrary(ntdll_handle); + ntdll_handle = NULL; } /* @@ -342,8 +184,7 @@ win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path) nt_path, NULL, NULL); } else { - if ((*func_RtlDosPathNameToNtPathName_U)(win32_path, nt_path, - NULL, NULL)) + if (RtlDosPathNameToNtPathName_U(win32_path, nt_path, NULL, NULL)) status = STATUS_SUCCESS; else status = STATUS_NO_MEMORY; @@ -379,7 +220,7 @@ 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 +/* Try to attach an instance of the Windows Overlay Filesystem filter driver to * the specified drive (such as C:) */ bool win32_try_to_attach_wof(const wchar_t *drive) @@ -449,9 +290,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_handle : NULL), + code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &buf[n], buflen - n, @@ -526,4 +369,39 @@ 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 = 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 = 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__ */