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

Reply via email to