*/
/*
- * 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
#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)
/* 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,
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. */
acquired_privileges = true;
}
- ret = init_dll(&ntdll_spec);
+ ret = init_ntdll();
if (ret)
goto 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;
}
/*
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;
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,
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__ */