Hi

I used the SetFileInformationByHandle function with the FILE_RENAME_FLAG_POSIX_SEMANTICS flag for the file rename function..

1) The _WIN32_WINNT variable needs to be increased to 0x0A00 (Windows 10).  Fixed conflict with #undef CHECKSUM_TYPE_NONE

2) The SetFileInformationByHandle function works correctly only on Windows 10 and higher.

The app must have a manifest to check the Windows version using the IsWindows10OrGreater() function. I added a manifest to all postgres projects and disabled the GenerateManifest option on windows projects.

This patch related to this post: https://www.postgresql.org/message-id/CAEepm%3D0FV-k%2B%3Dd9z08cW%3DZXoR1%3Dkw9wdpkP6WAuOrKJdz-8ujg%40mail.gmail.com


--
Victor Spirin
Postgres Professional:http://www.postgrespro.com
The Russian Postgres Company

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..fbd051699d 100644
--- a/src/port/dirmod.c
+++ b/src/port/dirmod.c
@@ -39,6 +39,110 @@
 #endif
 #endif
 
+
+#if defined(WIN32) && !defined(__CYGWIN__) && defined(_WIN32_WINNT_WIN10) && 
_WIN32_WINNT >= _WIN32_WINNT_WIN10
+
+#include <versionhelpers.h>
+
+/*
+ * win10_rename - uses SetFileInformationByHandle function with 
FILE_RENAME_FLAG_POSIX_SEMANTICS flag for atomic rename file
+ * working only on Windows 10 or later and  _WIN32_WINNT must be >= 
_WIN32_WINNT_WIN10
+ */
+static int win10_rename(wchar_t const* from, wchar_t const* to)
+{
+
+       int err;
+       size_t len;
+       FILE_RENAME_INFO* rename_info;
+       HANDLE f_handle;
+
+       f_handle = CreateFileW(from,
+               GENERIC_READ | GENERIC_WRITE | DELETE,
+               FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+               NULL,
+               OPEN_EXISTING,
+               FILE_ATTRIBUTE_NORMAL,
+               NULL);
+
+
+       if (f_handle == INVALID_HANDLE_VALUE)
+       {
+               err = GetLastError();
+               _dosmaperr(err);
+               return -1;
+       }
+
+
+       len = wcslen(to);
+       rename_info = (FILE_RENAME_INFO*)malloc(sizeof(FILE_RENAME_INFO) + (len 
+ 1) * sizeof(wchar_t));
+       rename_info->ReplaceIfExists = TRUE;
+       rename_info->Flags = FILE_RENAME_FLAG_POSIX_SEMANTICS | 
FILE_RENAME_FLAG_REPLACE_IF_EXISTS;
+
+       rename_info->RootDirectory = NULL;
+       rename_info->FileNameLength = len;
+       memcpy(rename_info->FileName, to, (len + 1) * sizeof(wchar_t));
+       if (!SetFileInformationByHandle(f_handle, FileRenameInfoEx, 
rename_info, sizeof(FILE_RENAME_INFO) + (len + 1) * sizeof(wchar_t)))
+       {
+               err = GetLastError();
+
+               _dosmaperr(err);
+               CloseHandle(f_handle);
+               free(rename_info);
+               return -1;
+       }
+
+       CloseHandle(f_handle);
+
+       return 0;
+}
+
+
+/*
+ *     pgrename_win10 - converts arguments from Windows ANSI code page to 
wchar_t and calls win10_rename function
+*/
+int
+pgrename_win10(const char *from, const char *to)
+{
+       wchar_t *from_w, *to_w;
+       size_t size, wsize;
+       int wlen;
+       int ret;
+
+       size = strlen(from) + 1;
+       wsize = size * sizeof(wchar_t);
+
+       from_w = (wchar_t*)malloc(wsize);
+       wlen = MultiByteToWideChar(CP_ACP, 0, (LPCCH)from, (int)size, 
(LPWSTR)from_w, (int)size);
+       if (wlen == 0)
+       {
+               free(from_w);
+               return -1;
+       }
+
+       size = strlen(to) + 1;
+       wsize = size * sizeof(wchar_t);
+
+       to_w = (wchar_t*)malloc(wsize);
+       wlen = MultiByteToWideChar(CP_ACP, 0, (LPCCH)to, (int)size, 
(LPWSTR)to_w, (int)size);
+       if (wlen == 0)
+       {
+               free(to_w);
+               free(from_w);
+               return -1;
+       }
+
+       ret = win10_rename(from_w, to_w);
+
+       free(to_w);
+       free(from_w);
+
+       return ret;
+
+}
+
+#endif                                                         /* #if 
defined(WIN32) && !defined(__CYGWIN__) && defined(_WIN32_WINNT_WIN10) && 
_WIN32_WINNT >= _WIN32_WINNT_WIN10 */
+
+
 #if defined(WIN32) || defined(__CYGWIN__)
 
 /*
@@ -49,6 +153,16 @@ pgrename(const char *from, const char *to)
 {
        int                     loops = 0;
 
+       /*
+       * Calls pgrename_win10 on Windows 10 and later when _WIN32_WINNT >= 
_WIN32_WINNT_WIN10.
+       */
+#if defined(_WIN32_WINNT_WIN10) && _WIN32_WINNT >= _WIN32_WINNT_WIN10 && 
!defined(__CYGWIN__)
+       if (IsWindows10OrGreater()) {
+               if (pgrename_win10(from, to) == 0) return 0;
+       }
+#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
diff --git a/src/tools/msvc/MSBuildProject.pm b/src/tools/msvc/MSBuildProject.pm
index ebe6530ba5..31b67ee5b0 100644
--- a/src/tools/msvc/MSBuildProject.pm
+++ b/src/tools/msvc/MSBuildProject.pm
@@ -43,6 +43,7 @@ EOF
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>$self->{guid}</ProjectGuid>
+    <GenerateManifest>false</GenerateManifest>
 EOF
        # Check whether WindowsSDKVersion env variable is present.
        # Add WindowsTargetPlatformVersion node if so.
diff --git a/src/tools/msvc/Project.pm b/src/tools/msvc/Project.pm
index 2f1679ab44..de6201e89b 100644
--- a/src/tools/msvc/Project.pm
+++ b/src/tools/msvc/Project.pm
@@ -352,6 +352,9 @@ sub AddResourceFile
                        }
                        print $o $_;
                }
+               # manifest with ms_compatibility:supportedOS tags for using 
IsWindows10OrGreater() function
+               print $o "\n1 24 \"src/port/win10.manifest\"\n";
+
                close($o);
                close($i);
        }
diff --git a/src/port/win10.manifest b/src/port/win10.manifest
new file mode 100644
index 00000000000..fd3a344bee0
--- /dev/null
+++ b/src/port/win10.manifest
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" 
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
+
+  <!-- Enable use of version 6 of the common controls (Win XP and later) -->
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type="win32"
+                        name="Microsoft.Windows.Common-Controls"
+                        version="6.0.0.0"
+                        processorArchitecture="*"
+                        publicKeyToken="6595b64144ccf1df"
+                        language="*" />
+    </dependentAssembly>
+  </dependency>
+
+  <!-- Indicate UAC compliance, with no need for elevated privileges (Win 
Vista and later) -->
+  <!-- (if you need enhanced privileges, set the level to "highestAvailable" 
or "requireAdministrator") -->
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+
+  <!-- Indicate high API awareness (Win Vista and later) -->
+  <!-- (if you support per-monitor high DPI, set this to "True/PM") -->
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAware 
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings";>false</dpiAware>
+    </windowsSettings>
+  </application>
+
+  <!-- Declare support for various versions of Windows -->
+  <ms_compatibility:compatibility 
xmlns:ms_compatibility="urn:schemas-microsoft-com:compatibility.v1" 
xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <ms_compatibility:application>
+      <!-- Windows Vista/Server 2008 -->
+      <ms_compatibility:supportedOS 
Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
+      <!-- Windows 7/Server 2008 R2 -->
+      <ms_compatibility:supportedOS 
Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
+      <!-- Windows 8/Server 2012 -->
+      <ms_compatibility:supportedOS 
Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
+      <!-- Windows 8.1/Server 2012 R2 -->
+      <ms_compatibility:supportedOS 
Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
+      <!-- Windows 10 -->
+      <ms_compatibility:supportedOS 
Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
+    </ms_compatibility:application>
+  </ms_compatibility:compatibility>
+
+</assembly>

Reply via email to