From 09ad941a0566e04f2bd76ab69aa56056df800aff Mon Sep 17 00:00:00 2001 From: Leo Yuriev Date: Tue, 12 Jun 2018 22:56:26 +0300 Subject: [PATCH] mdbx: Windows XP compatibility. Change-Id: Iafe3a83110610071e42a168ef9fc5f8d3131854f --- mdbx.h | 7 +- src/bits.h | 3 + src/defs.h | 4 -- src/lck-windows.c | 43 ++++++++--- src/mdbx.c | 2 +- src/osal.c | 178 +++++++++++++++++++++++++--------------------- src/osal.h | 32 +++++++++ test/base.h | 4 ++ 8 files changed, 173 insertions(+), 100 deletions(-) diff --git a/mdbx.h b/mdbx.h index a02e4254..3aa5cd87 100644 --- a/mdbx.h +++ b/mdbx.h @@ -204,11 +204,14 @@ extern LIBMDBX_API const mdbx_version_info mdbx_version; extern LIBMDBX_API const mdbx_build_info mdbx_build; #if defined(_WIN32) || defined(_WIN64) -/* Dll initialization callback for old Windows NT versions. This function MUST - * be called once from DllMain() for each reason (DLL_PROCESS_ATTACH, + +/* Dll initialization callback for ability to dynamically load MDBX DLL by + * LoadLibrary() on Windows versions before Windows Vista. This function MUST be + * called once from DllMain() for each reason (DLL_PROCESS_ATTACH, * DLL_PROCESS_DETACH, DLL_THREAD_ATTACH and DLL_THREAD_DETACH). Do this * carefully and ONLY when actual Windows version don't support initialization * via "TLS Directory" (e.g .CRT$XL[A-Z] sections in executable or dll file). */ + #ifndef MDBX_CONFIG_MANUAL_TLS_CALLBACK #define MDBX_CONFIG_MANUAL_TLS_CALLBACK 0 #endif diff --git a/src/bits.h b/src/bits.h index 35abd8d7..599dee6f 100644 --- a/src/bits.h +++ b/src/bits.h @@ -34,6 +34,9 @@ #endif #ifdef _MSC_VER +# if _MSC_VER < 1400 +# error "Microsoft Visual C++ 8.0 (Visual Studio 2005) or later version is required" +# endif # ifndef _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS # endif diff --git a/src/defs.h b/src/defs.h index 6da5a963..b6076cc1 100644 --- a/src/defs.h +++ b/src/defs.h @@ -103,10 +103,6 @@ /*----------------------------------------------------------------------------*/ -#if !defined(__thread) && (defined(_MSC_VER) || defined(__DMC__)) -# define __thread __declspec(thread) -#endif /* __thread */ - #ifndef __alwaysinline # if defined(__GNUC__) || __has_attribute(always_inline) # define __alwaysinline __inline __attribute__((always_inline)) diff --git a/src/lck-windows.c b/src/lck-windows.c index 24afcaac..9167626a 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -654,20 +654,25 @@ MDBX_srwlock_function mdbx_srwlock_Init, mdbx_srwlock_AcquireShared, /*----------------------------------------------------------------------------*/ +MDBX_GetFileInformationByHandleEx mdbx_GetFileInformationByHandleEx; +MDBX_GetVolumeInformationByHandleW mdbx_GetVolumeInformationByHandleW; +MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW; +MDBX_NtFsControlFile mdbx_NtFsControlFile; + static void mdbx_winnt_import(void) { - HINSTANCE hInst = GetModuleHandleA("kernel32.dll"); - MDBX_srwlock_function init = - (MDBX_srwlock_function)GetProcAddress(hInst, "InitializeSRWLock"); + const HINSTANCE hKernel32dll = GetModuleHandleA("kernel32.dll"); + const MDBX_srwlock_function init = + (MDBX_srwlock_function)GetProcAddress(hKernel32dll, "InitializeSRWLock"); if (init != NULL) { mdbx_srwlock_Init = init; - mdbx_srwlock_AcquireShared = - (MDBX_srwlock_function)GetProcAddress(hInst, "AcquireSRWLockShared"); - mdbx_srwlock_ReleaseShared = - (MDBX_srwlock_function)GetProcAddress(hInst, "ReleaseSRWLockShared"); - mdbx_srwlock_AcquireExclusive = - (MDBX_srwlock_function)GetProcAddress(hInst, "AcquireSRWLockExclusive"); - mdbx_srwlock_ReleaseExclusive = - (MDBX_srwlock_function)GetProcAddress(hInst, "ReleaseSRWLockExclusive"); + mdbx_srwlock_AcquireShared = (MDBX_srwlock_function)GetProcAddress( + hKernel32dll, "AcquireSRWLockShared"); + mdbx_srwlock_ReleaseShared = (MDBX_srwlock_function)GetProcAddress( + hKernel32dll, "ReleaseSRWLockShared"); + mdbx_srwlock_AcquireExclusive = (MDBX_srwlock_function)GetProcAddress( + hKernel32dll, "AcquireSRWLockExclusive"); + mdbx_srwlock_ReleaseExclusive = (MDBX_srwlock_function)GetProcAddress( + hKernel32dll, "ReleaseSRWLockExclusive"); } else { mdbx_srwlock_Init = stub_srwlock_Init; mdbx_srwlock_AcquireShared = stub_srwlock_AcquireShared; @@ -675,4 +680,20 @@ static void mdbx_winnt_import(void) { mdbx_srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive; mdbx_srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive; } + + mdbx_GetFileInformationByHandleEx = + (MDBX_GetFileInformationByHandleEx)GetProcAddress( + hKernel32dll, "GetFileInformationByHandleEx"); + + mdbx_GetVolumeInformationByHandleW = + (MDBX_GetVolumeInformationByHandleW)GetProcAddress( + hKernel32dll, "GetVolumeInformationByHandleW"); + + mdbx_GetFinalPathNameByHandleW = + (MDBX_GetFinalPathNameByHandleW)GetProcAddress( + hKernel32dll, "GetFinalPathNameByHandleW"); + + const HINSTANCE hNtdll = GetModuleHandleA("ntdll.dll"); + mdbx_NtFsControlFile = + (MDBX_NtFsControlFile)GetProcAddress(hNtdll, "NtFsControlFile"); } diff --git a/src/mdbx.c b/src/mdbx.c index 029d6015..e2b3c694 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -1134,7 +1134,7 @@ const char *__cold mdbx_strerror(int errnum) { const char *msg = __mdbx_strerr(errnum); if (!msg) { #ifdef _MSC_VER - static __thread char buffer[1024]; + static char buffer[1024]; size_t size = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, diff --git a/src/osal.c b/src/osal.c index 8d685ae0..b98a8771 100644 --- a/src/osal.c +++ b/src/osal.c @@ -17,7 +17,6 @@ #include "./bits.h" #if defined(_WIN32) || defined(_WIN64) -#include static int waitstatus2errcode(DWORD result) { switch (result) { @@ -105,13 +104,31 @@ extern NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN OUT PSIZE_T RegionSize, IN ULONG FreeType); +#ifndef WOF_CURRENT_VERSION +typedef struct _WOF_EXTERNAL_INFO { + DWORD Version; + DWORD Provider; +} WOF_EXTERNAL_INFO, *PWOF_EXTERNAL_INFO; +#endif /* WOF_CURRENT_VERSION */ + +#ifndef WIM_PROVIDER_CURRENT_VERSION +#define WIM_PROVIDER_HASH_SIZE 20 + +typedef struct _WIM_PROVIDER_EXTERNAL_INFO { + DWORD Version; + DWORD Flags; + LARGE_INTEGER DataSourceId; + BYTE ResourceHash[WIM_PROVIDER_HASH_SIZE]; +} WIM_PROVIDER_EXTERNAL_INFO, *PWIM_PROVIDER_EXTERNAL_INFO; +#endif /* WIM_PROVIDER_CURRENT_VERSION */ + #ifndef FILE_PROVIDER_CURRENT_VERSION typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 { ULONG Version; ULONG Algorithm; ULONG Flags; } FILE_PROVIDER_EXTERNAL_INFO_V1, *PFILE_PROVIDER_EXTERNAL_INFO_V1; -#endif +#endif /* FILE_PROVIDER_CURRENT_VERSION */ #ifndef STATUS_OBJECT_NOT_EXTERNALLY_BACKED #define STATUS_OBJECT_NOT_EXTERNALLY_BACKED ((NTSTATUS)0xC000046DL) @@ -120,14 +137,6 @@ typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 { #define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) #endif -extern NTSTATUS -NtFsControlFile(IN HANDLE FileHandle, IN OUT HANDLE Event, - IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, - IN OUT PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG FsControlCode, IN OUT PVOID InputBuffer, - IN ULONG InputBufferLength, OUT OPTIONAL PVOID OutputBuffer, - IN ULONG OutputBufferLength); - #endif /* _WIN32 || _WIN64 */ /*----------------------------------------------------------------------------*/ @@ -740,80 +749,85 @@ int mdbx_is_file_local(mdbx_filehandle_t handle, int flags) { if (GetFileType(handle) != FILE_TYPE_DISK) return ERROR_FILE_OFFLINE; - FILE_REMOTE_PROTOCOL_INFO RemoteProtocolInfo; - if (GetFileInformationByHandleEx(handle, FileRemoteProtocolInfo, - &RemoteProtocolInfo, - sizeof(RemoteProtocolInfo))) { - if ((RemoteProtocolInfo.Flags & (REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK | - REMOTE_PROTOCOL_INFO_FLAG_OFFLINE)) != - REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK) - return ERROR_FILE_OFFLINE; - } - -#if defined(_WIN64) && defined(WOF_CURRENT_VERSION) - NTSTATUS rc; - struct { - WOF_EXTERNAL_INFO wof_info; - union { - WIM_PROVIDER_EXTERNAL_INFO wim_info; - FILE_PROVIDER_EXTERNAL_INFO_V1 file_info; - }; - size_t reserved_for_microsoft_madness[42]; - } GetExternalBacking_OutputBuffer; - IO_STATUS_BLOCK StatusBlock; - rc = NtFsControlFile(handle, NULL, NULL, NULL, &StatusBlock, - FSCTL_GET_EXTERNAL_BACKING, NULL, 0, - &GetExternalBacking_OutputBuffer, - sizeof(GetExternalBacking_OutputBuffer)); - if (rc != STATUS_OBJECT_NOT_EXTERNALLY_BACKED && - rc != STATUS_INVALID_DEVICE_REQUEST) - return NT_SUCCESS(rc) ? ERROR_REMOTE_STORAGE_MEDIA_ERROR - : ntstatus2errcode(rc); -#endif - - WCHAR PathBuffer[INT16_MAX]; - DWORD VolumeSerialNumber, FileSystemFlags; - if (!GetVolumeInformationByHandleW(handle, PathBuffer, INT16_MAX, - &VolumeSerialNumber, NULL, - &FileSystemFlags, NULL, 0)) - return GetLastError(); - - if ((flags & MDBX_RDONLY) == 0) { - if (FileSystemFlags & (FILE_SEQUENTIAL_WRITE_ONCE | FILE_READ_ONLY_VOLUME | - FILE_VOLUME_IS_COMPRESSED)) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; - } - - if (!GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, - FILE_NAME_NORMALIZED | VOLUME_NAME_NT)) - return GetLastError(); - - if (_wcsnicmp(PathBuffer, L"\\Device\\Mup\\", 12) == 0) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; - - if (GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, - FILE_NAME_NORMALIZED | VOLUME_NAME_DOS)) { - UINT DriveType = GetDriveTypeW(PathBuffer); - if (DriveType == DRIVE_NO_ROOT_DIR && - wcsncmp(PathBuffer, L"\\\\?\\", 4) == 0 && - wcsncmp(PathBuffer + 5, L":\\", 2) == 0) { - PathBuffer[7] = 0; - DriveType = GetDriveTypeW(PathBuffer + 4); + if (mdbx_GetFileInformationByHandleEx) { + FILE_REMOTE_PROTOCOL_INFO RemoteProtocolInfo; + if (mdbx_GetFileInformationByHandleEx(handle, FileRemoteProtocolInfo, + &RemoteProtocolInfo, + sizeof(RemoteProtocolInfo))) { + if ((RemoteProtocolInfo.Flags & (REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK | + REMOTE_PROTOCOL_INFO_FLAG_OFFLINE)) != + REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK) + return ERROR_FILE_OFFLINE; } - switch (DriveType) { - case DRIVE_CDROM: - if (flags & MDBX_RDONLY) - break; - // fall through - case DRIVE_UNKNOWN: - case DRIVE_NO_ROOT_DIR: - case DRIVE_REMOTE: - default: + } + + if (mdbx_NtFsControlFile) { + NTSTATUS rc; + struct { + WOF_EXTERNAL_INFO wof_info; + union { + WIM_PROVIDER_EXTERNAL_INFO wim_info; + FILE_PROVIDER_EXTERNAL_INFO_V1 file_info; + }; + size_t reserved_for_microsoft_madness[42]; + } GetExternalBacking_OutputBuffer; + IO_STATUS_BLOCK StatusBlock; + rc = mdbx_NtFsControlFile(handle, NULL, NULL, NULL, &StatusBlock, + FSCTL_GET_EXTERNAL_BACKING, NULL, 0, + &GetExternalBacking_OutputBuffer, + sizeof(GetExternalBacking_OutputBuffer)); + if (rc != STATUS_OBJECT_NOT_EXTERNALLY_BACKED && + rc != STATUS_INVALID_DEVICE_REQUEST) + return NT_SUCCESS(rc) ? ERROR_REMOTE_STORAGE_MEDIA_ERROR + : ntstatus2errcode(rc); + } + + if (mdbx_GetVolumeInformationByHandleW && mdbx_GetFinalPathNameByHandleW) { + WCHAR PathBuffer[INT16_MAX]; + DWORD VolumeSerialNumber, FileSystemFlags; + if (!mdbx_GetVolumeInformationByHandleW(handle, PathBuffer, INT16_MAX, + &VolumeSerialNumber, NULL, + &FileSystemFlags, NULL, 0)) + return GetLastError(); + + if ((flags & MDBX_RDONLY) == 0) { + if (FileSystemFlags & (FILE_SEQUENTIAL_WRITE_ONCE | + FILE_READ_ONLY_VOLUME | FILE_VOLUME_IS_COMPRESSED)) + return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + } + + if (!mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, + FILE_NAME_NORMALIZED | VOLUME_NAME_NT)) + return GetLastError(); + + if (_wcsnicmp(PathBuffer, L"\\Device\\Mup\\", 12) == 0) return ERROR_REMOTE_STORAGE_MEDIA_ERROR; - case DRIVE_REMOVABLE: - case DRIVE_FIXED: - case DRIVE_RAMDISK: - break; + + if (mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, + FILE_NAME_NORMALIZED | + VOLUME_NAME_DOS)) { + UINT DriveType = GetDriveTypeW(PathBuffer); + if (DriveType == DRIVE_NO_ROOT_DIR && + wcsncmp(PathBuffer, L"\\\\?\\", 4) == 0 && + wcsncmp(PathBuffer + 5, L":\\", 2) == 0) { + PathBuffer[7] = 0; + DriveType = GetDriveTypeW(PathBuffer + 4); + } + switch (DriveType) { + case DRIVE_CDROM: + if (flags & MDBX_RDONLY) + break; + // fall through + case DRIVE_UNKNOWN: + case DRIVE_NO_ROOT_DIR: + case DRIVE_REMOTE: + default: + return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + case DRIVE_REMOVABLE: + case DRIVE_FIXED: + case DRIVE_RAMDISK: + break; + } } } #else diff --git a/src/osal.h b/src/osal.h index 4fc9265c..e27b4bc6 100644 --- a/src/osal.h +++ b/src/osal.h @@ -65,9 +65,11 @@ /* Systems includes */ #if defined(_WIN32) || defined(_WIN64) +#define WIN32_LEAN_AND_MEAN #include #include #include +#include #define HAVE_SYS_STAT_H #define HAVE_SYS_TYPES_H typedef HANDLE mdbx_thread_t; @@ -576,6 +578,36 @@ typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *); extern MDBX_srwlock_function mdbx_srwlock_Init, mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared, mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive; + +typedef BOOL(WINAPI *MDBX_GetFileInformationByHandleEx)( + _In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass, + _Out_ LPVOID lpFileInformation, _In_ DWORD dwBufferSize); +extern MDBX_GetFileInformationByHandleEx mdbx_GetFileInformationByHandleEx; + +typedef BOOL(WINAPI *MDBX_GetVolumeInformationByHandleW)( + _In_ HANDLE hFile, _Out_opt_ LPWSTR lpVolumeNameBuffer, + _In_ DWORD nVolumeNameSize, _Out_opt_ LPDWORD lpVolumeSerialNumber, + _Out_opt_ LPDWORD lpMaximumComponentLength, + _Out_opt_ LPDWORD lpFileSystemFlags, + _Out_opt_ LPWSTR lpFileSystemNameBuffer, _In_ DWORD nFileSystemNameSize); + +extern MDBX_GetVolumeInformationByHandleW mdbx_GetVolumeInformationByHandleW; + +typedef DWORD(WINAPI *MDBX_GetFinalPathNameByHandleW)(_In_ HANDLE hFile, + _Out_ LPWSTR lpszFilePath, + _In_ DWORD cchFilePath, + _In_ DWORD dwFlags); +extern MDBX_GetFinalPathNameByHandleW mdbx_GetFinalPathNameByHandleW; + +typedef NTSTATUS(NTAPI *MDBX_NtFsControlFile)( + IN HANDLE FileHandle, IN OUT HANDLE Event, + IN OUT PVOID /* PIO_APC_ROUTINE */ ApcRoutine, IN OUT PVOID ApcContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG FsControlCode, + IN OUT PVOID InputBuffer, IN ULONG InputBufferLength, + OUT OPTIONAL PVOID OutputBuffer, IN ULONG OutputBufferLength); + +extern MDBX_NtFsControlFile mdbx_NtFsControlFile; + #endif /* Windows */ /* Checks reader by pid. diff --git a/test/base.h b/test/base.h index bc82ff26..b23f776a 100644 --- a/test/base.h +++ b/test/base.h @@ -80,6 +80,10 @@ #include "../src/defs.h" #include "../src/osal.h" +#if !defined(__thread) && (defined(_MSC_VER) || defined(__DMC__)) +#define __thread __declspec(thread) +#endif /* __thread */ + #ifdef _MSC_VER #pragma warning(pop) #pragma warning(disable : 4201) /* nonstandard extension used : \