diff --git a/src/include/common/checksum_helper.h b/src/include/common/checksum_helper.h index cac7570ea13..2d533c93a6f 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 d8ae49e22d1..d91555f5c09 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 763bc5f915a..61615324442 100644 --- a/src/port/dirmod.c +++ b/src/port/dirmod.c @@ -39,6 +39,81 @@ #endif #endif + +#if defined(WIN32) && !defined(__CYGWIN__) && defined(_WIN32_WINNT_WIN10) && _WIN32_WINNT >= _WIN32_WINNT_WIN10 + +#include + +typedef struct _FILE_RENAME_INFO_VVS { + union { + BOOLEAN ReplaceIfExists; // FileRenameInfo + DWORD Flags; // FileRenameInfoEx + } DUMMYUNIONNAME; + HANDLE RootDirectory; + DWORD FileNameLength; + WCHAR FileName[MAX_PATH]; +} FILE_RENAME_INFO_VVS; + +/* + * pgrename_win10 - 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 +pgrename_win10(const char *from, const char *to) +{ + int err; + FILE_RENAME_INFO_VVS rename_info; + HANDLE f_handle; + wchar_t from_w[MAX_PATH]; + + + if (MultiByteToWideChar(CP_ACP, 0, (LPCCH)from, -1, (LPWSTR)from_w, MAX_PATH) == 0) return -1; + if (MultiByteToWideChar(CP_ACP, 0, (LPCCH)to, -1, (LPWSTR)rename_info.FileName, MAX_PATH) == 0) return -1; + + f_handle = CreateFileW(from_w, + 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; + } + + + 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 = wcslen(rename_info.FileName);; + + if (!SetFileInformationByHandle(f_handle, FileRenameInfoEx, &rename_info, sizeof(FILE_RENAME_INFO_VVS))) + { + 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 +124,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 ebe6530ba58..31b67ee5b03 100644 --- a/src/tools/msvc/MSBuildProject.pm +++ b/src/tools/msvc/MSBuildProject.pm @@ -43,6 +43,7 @@ EOF $self->{guid} + false 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 2f1679ab44f..de6201e89b0 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + +