Thank you
Thank you
In this version of patch:
1. Made function isWindows1607OrGreater() without manifest
2. To open a directory using CreateFile, have to specify the
FILE_FLAG_BACKUP_SEMANTICS flag as part of dwFlagsAndAttributes. Checks
that file is a directory by the GetFileAttributes function.
Victor Spirin
Postgres Professional:http://www.postgrespro.com
The Russian Postgres Company
01.10.2021 15:37, Juan José Santamaría Flecha пишет:
On Thu, Sep 30, 2021 at 11:00 PM Victor Spirin
<v.spi...@postgrespro.ru <mailto:v.spi...@postgrespro.ru>> wrote:
IsWindowsVersionOrGreater(10,0,1607) always returns false
Only IsWindowsVersionOrGreater(10,0,0) is a valid call. (There are
no service packs in Windows 10.)
I haven't found a way to determine the Windows 10 release ID.
The RtlGetVersion function returns dwBuildNumber = 19042 on my
Windows.
I heard that Microsoft does not support older versions of Windows
10 and requires a mandatory update.
You can translate the BuildNumber to the ReleaseId, for 1607 it will
be 14393 [1].
We might find pretty much anything in the wild, the safer the check
the better.
[1] https://en.wikipedia.org/wiki/Windows_10_version_history
<https://en.wikipedia.org/wiki/Windows_10_version_history>
Regards,
Juan José Santamaría Flecha
diff --git a/src/include/common/checksum_helper.h
b/src/include/common/checksum_helper.h
index cac7570ea1..2d533c93a6 100644
--- a/src/include/common/checksum_helper.h
+++ b/src/include/common/checksum_helper.h
@@ -26,6 +26,13 @@
* MD5 here because any new that does need a cryptographically strong checksum
* should use something better.
*/
+
+ /*
+ * CHECKSUM_TYPE_NONE defined in the winioctl.h when _WIN32_WINNT >=
_WIN32_WINNT_WIN10
+ */
+#ifdef CHECKSUM_TYPE_NONE
+#undef CHECKSUM_TYPE_NONE
+#endif
typedef enum pg_checksum_type
{
CHECKSUM_TYPE_NONE,
diff --git a/src/include/port/win32.h b/src/include/port/win32.h
index d8ae49e22d..d91555f5c0 100644
--- a/src/include/port/win32.h
+++ b/src/include/port/win32.h
@@ -12,12 +12,13 @@
/*
* Make sure _WIN32_WINNT has the minimum required value.
* Leave a higher value in place. When building with at least Visual
- * Studio 2015 the minimum requirement is Windows Vista (0x0600) to
- * get support for GetLocaleInfoEx() with locales. For everything else
+ * Studio 2015 the minimum requirement is Windows 10 (0x0A00) to get support
for SetFileInformationByHandle.
+ * The minimum requirement is Windows Vista (0x0600) get support for
GetLocaleInfoEx() with locales.
+ * For everything else
* the minimum version is Windows XP (0x0501).
*/
#if defined(_MSC_VER) && _MSC_VER >= 1900
-#define MIN_WINNT 0x0600
+#define MIN_WINNT 0x0A00
#else
#define MIN_WINNT 0x0501
#endif
diff --git a/src/port/dirmod.c b/src/port/dirmod.c
index 763bc5f915..12e9c35cef 100644
--- a/src/port/dirmod.c
+++ b/src/port/dirmod.c
@@ -39,6 +39,146 @@
#endif
#endif
+
+#if defined(WIN32) && !defined(__CYGWIN__) && defined(_WIN32_WINNT_WIN10) &&
_WIN32_WINNT >= _WIN32_WINNT_WIN10
+
+#include <winternl.h>
+
+/*
+ * Checks Windows version using RtlGetVersion
+ * Version 1607 (Build 14393) is required for SetFileInformationByHandle
+ * function with FILE_RENAME_FLAG_POSIX_SEMANTICS flag
+*/
+typedef NTSYSAPI(NTAPI * PFN_RTLGETVERSION)
+(OUT PRTL_OSVERSIONINFOEXW lpVersionInformation);
+
+static int isWin1607 = -1;
+static int isWindows1607OrGreater()
+{
+ HMODULE ntdll;
+ PFN_RTLGETVERSION _RtlGetVersion = NULL;
+ OSVERSIONINFOEXW info;
+ if (isWin1607 >= 0) return isWin1607;
+ ntdll = LoadLibraryEx("ntdll.dll", NULL, 0);
+ if (ntdll == NULL)
+ {
+ DWORD err = GetLastError();
+
+ _dosmaperr(err);
+ return -1;
+ }
+
+ _RtlGetVersion = (PFN_RTLGETVERSION)(pg_funcptr_t)
+ GetProcAddress(ntdll, "RtlGetVersion");
+ if (_RtlGetVersion == NULL)
+ {
+ DWORD err = GetLastError();
+
+ FreeLibrary(ntdll);
+ _dosmaperr(err);
+ return -1;
+ }
+ info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+ if (!NT_SUCCESS(_RtlGetVersion(&info)))
+ {
+ DWORD err = GetLastError();
+
+ FreeLibrary(ntdll);
+ _dosmaperr(err);
+ return -1;
+ }
+
+ if (info.dwMajorVersion >= 10 && info.dwBuildNumber >= 14393) isWin1607
= 1;
+ else isWin1607 = 0;
+ FreeLibrary(ntdll);
+ return isWin1607;
+
+}
+
+typedef struct _FILE_RENAME_INFO_EXT {
+ FILE_RENAME_INFO fri;
+ WCHAR extra_space[MAX_PATH];
+} FILE_RENAME_INFO_EXT;
+
+/*
+ * pgrename_windows_posix_semantics - uses SetFileInformationByHandle function
+ * with FILE_RENAME_FLAG_POSIX_SEMANTICS flag for atomic rename file
+ * working only on Windows 10 (1607) or later and _WIN32_WINNT must be >=
_WIN32_WINNT_WIN10
+ */
+static int
+pgrename_windows_posix_semantics(const char *from, const char *to)
+{
+ int err;
+ FILE_RENAME_INFO_EXT rename_info;
+ PFILE_RENAME_INFO prename_info;
+ HANDLE f_handle;
+ wchar_t from_w[MAX_PATH];
+ DWORD dwFlagsAndAttributes;
+ DWORD dwAttrib;
+
+
+ prename_info = (PFILE_RENAME_INFO)&rename_info;
+
+ if (MultiByteToWideChar(CP_ACP, 0, (LPCCH)from, -1, (LPWSTR)from_w,
MAX_PATH) == 0) {
+ err = GetLastError();
+ _dosmaperr(err);
+ return -1;
+ }
+ if (MultiByteToWideChar(CP_ACP, 0, (LPCCH)to, -1,
(LPWSTR)prename_info->FileName, MAX_PATH) == 0) {
+ err = GetLastError();
+ _dosmaperr(err);
+ return -1;
+ }
+ /*
+ * To open a directory using CreateFile, specify the
FILE_FLAG_BACKUP_SEMANTICS flag as part of dwFlagsAndAttributes.
+ */
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ dwAttrib = GetFileAttributes(from_w);
+ if(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) dwFlagsAndAttributes =
FILE_FLAG_BACKUP_SEMANTICS;
+
+ f_handle = CreateFileW(from_w,
+ GENERIC_READ | GENERIC_WRITE | DELETE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ dwFlagsAndAttributes,
+ NULL);
+
+
+ if (f_handle == INVALID_HANDLE_VALUE)
+ {
+ err = GetLastError();
+
+ _dosmaperr(err);
+
+ return -1;
+ }
+
+
+ prename_info->ReplaceIfExists = TRUE;
+ prename_info->Flags = FILE_RENAME_FLAG_POSIX_SEMANTICS |
FILE_RENAME_FLAG_REPLACE_IF_EXISTS;
+
+ prename_info->RootDirectory = NULL;
+ prename_info->FileNameLength = wcslen(prename_info->FileName);
+
+ if (!SetFileInformationByHandle(f_handle, FileRenameInfoEx,
prename_info, sizeof(FILE_RENAME_INFO_EXT)))
+ {
+ err = GetLastError();
+
+ _dosmaperr(err);
+ CloseHandle(f_handle);
+ return -1;
+ }
+
+ CloseHandle(f_handle);
+ return 0;
+
+}
+
+#endif /* #if
defined(WIN32) && !defined(__CYGWIN__) && defined(_WIN32_WINNT_WIN10) &&
_WIN32_WINNT >= _WIN32_WINNT_WIN10 */
+
+
#if defined(WIN32) || defined(__CYGWIN__)
/*
@@ -49,6 +189,16 @@ pgrename(const char *from, const char *to)
{
int loops = 0;
+ /*
+ * Calls pgrename_windows_posix_semantics on Windows 10 and later when
_WIN32_WINNT >= _WIN32_WINNT_WIN10.
+ */
+#if defined(_WIN32_WINNT_WIN10) && _WIN32_WINNT >= _WIN32_WINNT_WIN10 &&
!defined(__CYGWIN__)
+ if (isWindows1607OrGreater()>0) {
+ return pgrename_windows_posix_semantics(from, to);
+ }
+#endif
+
+
/*
* We need to loop because even though PostgreSQL uses flags that allow
* rename while the file is open, other applications might have the file