0001-Use-NtCreateFile-to-open-files-on-Windows.patch
text/x-patch
Filename: 0001-Use-NtCreateFile-to-open-files-on-Windows.patch
Type: text/x-patch
Part: 1
Patch
Format: format-patch
Series: patch 0001
Subject: Use NtCreateFile() to open files on Windows.
| File | + | − |
|---|---|---|
| configure | 6 | 0 |
| configure.ac | 1 | 0 |
| src/include/port.h | 1 | 0 |
| src/include/port/win32ntdll.h | 42 | 0 |
| src/port/open.c | 151 | 104 |
| src/port/win32ntdll.c | 68 | 0 |
| src/port/win32stat.c | 5 | 159 |
| src/tools/msvc/Mkvcbuild.pm | 2 | 1 |
From 4959e4dc6d96d7634ec5ac0c8f55f11ec37b6adb Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 5 Sep 2021 23:49:23 +1200
Subject: [PATCH] Use NtCreateFile() to open files on Windows.
1. Update our open() wrapper to bypass Win32 and use NT interfaces to
open files. This allows us to check for NT's STATUS_DELETE_PENDING and
translate it to appropriate errors.
2. Remove non-working code from our stat() wrapper that tried to handle
the same problem, and reuse the open() wrapper.
XXX TODO: resolve order-of-operations problem: pgwin32_open_handle() is
caled by _pgstat64() before the Windows signal emulation is started up,
but it might call pg_usleep().
XXX TODO: there are some macro redefinition warnings from MSVC on CI;
apparently we need some well placed #define and #undef of
WIN32_NO_STATUS.
Discussion: https://postgr.es/m/CA%2BhUKGJz_pZTF9mckn6XgSv69%2BjGwdgLkxZ6b3NWGLBCVjqUZA%40mail.gmail.com
---
configure | 6 +
configure.ac | 1 +
src/include/port.h | 1 +
src/include/port/win32ntdll.h | 42 ++++++
src/port/open.c | 255 ++++++++++++++++++++--------------
src/port/win32ntdll.c | 68 +++++++++
src/port/win32stat.c | 164 +---------------------
src/tools/msvc/Mkvcbuild.pm | 3 +-
8 files changed, 276 insertions(+), 264 deletions(-)
create mode 100644 src/include/port/win32ntdll.h
create mode 100644 src/port/win32ntdll.c
diff --git a/configure b/configure
index c550cacd5a..adfe03f3f2 100755
--- a/configure
+++ b/configure
@@ -16818,6 +16818,12 @@ esac
;;
esac
+ case " $LIBOBJS " in
+ *" win32ntdll.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS win32ntdll.$ac_objext"
+ ;;
+esac
+
case " $LIBOBJS " in
*" win32security.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS win32security.$ac_objext"
diff --git a/configure.ac b/configure.ac
index 2ee710102f..2819b91a8c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1922,6 +1922,7 @@ if test "$PORTNAME" = "win32"; then
AC_LIBOBJ(system)
AC_LIBOBJ(win32env)
AC_LIBOBJ(win32error)
+ AC_LIBOBJ(win32ntdll)
AC_LIBOBJ(win32security)
AC_LIBOBJ(win32setlocale)
AC_LIBOBJ(win32stat)
diff --git a/src/include/port.h b/src/include/port.h
index 82f63de325..ec64be429c 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -290,6 +290,7 @@ extern bool rmtree(const char *path, bool rmtopdir);
* passing of other special options.
*/
#define O_DIRECT 0x80000000
+extern HANDLE pgwin32_open_handle(const char *, int, bool);
extern int pgwin32_open(const char *, int,...);
extern FILE *pgwin32_fopen(const char *, const char *);
#define open(a,b,c) pgwin32_open(a,b,c)
diff --git a/src/include/port/win32ntdll.h b/src/include/port/win32ntdll.h
new file mode 100644
index 0000000000..14e70c6f42
--- /dev/null
+++ b/src/include/port/win32ntdll.h
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32_ntdll.h
+ * Dynamically loaded Windows NT functions.
+ *
+ * Portions Copyright (c) 2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/port/win32ntdll.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#include <ntstatus.h>
+#include <winternl.h>
+
+typedef NTSTATUS (__stdcall *NtCreateFile_t)(PHANDLE FileHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PLARGE_INTEGER AllocationSize,
+ ULONG FileAttributes,
+ ULONG ShareAccess,
+ ULONG CreateDisposition,
+ ULONG CreateOptions,
+ PVOID EaBuffer,
+ ULONG EaLength);
+
+typedef BOOLEAN (__stdcall *RtlDosPathNameToNtPathName_U_t)(PCWSTR DosName,
+ PUNICODE_STRING NtName,
+ PCWSTR *PartName,
+ void *RelativeName);
+
+typedef ULONG (__stdcall *RtlNtStatusToDosError_t)(NTSTATUS Status);
+
+extern NtCreateFile_t pg_NtCreateFile;
+extern RtlDosPathNameToNtPathName_U_t pg_RtlDosPathNameToNtPathName_U;
+extern RtlNtStatusToDosError_t pg_RtlNtStatusToDosError;
+
+extern int initialize_ntdll(void);
diff --git a/src/port/open.c b/src/port/open.c
index 14c6debba9..122e1b4ab7 100644
--- a/src/port/open.c
+++ b/src/port/open.c
@@ -19,52 +19,38 @@
#include "postgres_fe.h"
#endif
+#include "port/win32ntdll.h"
+
#include <fcntl.h>
#include <assert.h>
#include <sys/stat.h>
-
-static int
-openFlagsToCreateFileFlags(int openFlags)
-{
- switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
- {
- /* O_EXCL is meaningless without O_CREAT */
- case 0:
- case O_EXCL:
- return OPEN_EXISTING;
-
- case O_CREAT:
- return OPEN_ALWAYS;
-
- /* O_EXCL is meaningless without O_CREAT */
- case O_TRUNC:
- case O_TRUNC | O_EXCL:
- return TRUNCATE_EXISTING;
-
- case O_CREAT | O_TRUNC:
- return CREATE_ALWAYS;
-
- /* O_TRUNC is meaningless with O_CREAT */
- case O_CREAT | O_EXCL:
- case O_CREAT | O_TRUNC | O_EXCL:
- return CREATE_NEW;
- }
-
- /* will never get here */
- return 0;
-}
-
/*
- * - file attribute setting, based on fileMode?
+ * Internal function used by pgwin32_open() and _pgstat64(). When
+ * backup_semantics is true, directories may be opened (for limited uses). On
+ * failure, INVALID_HANDLE_VALUE is returned and errno is set.
*/
-int
-pgwin32_open(const char *fileName, int fileFlags,...)
+HANDLE
+pgwin32_open_handle(const char *fileName, int fileFlags, bool backup_semantics)
{
- int fd;
HANDLE h = INVALID_HANDLE_VALUE;
- SECURITY_ATTRIBUTES sa;
int loops = 0;
+ wchar_t wideFileName[MAX_PATH];
+ size_t wideFileNameSize;
+ wchar_t buffer[MAX_PATH];
+ UNICODE_STRING ntFileName;
+ ACCESS_MASK desiredAccess;
+ OBJECT_ATTRIBUTES objectAttributes;
+ IO_STATUS_BLOCK ioStatusBlock;
+ ULONG fileAttributes;
+ ULONG shareAccess;
+ ULONG createDisposition;
+ ULONG createOptions;
+ NTSTATUS status;
+ DWORD err;
+
+ if (initialize_ntdll() < 0)
+ return INVALID_HANDLE_VALUE;
/* Check that we can handle the request */
assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
@@ -72,51 +58,116 @@ pgwin32_open(const char *fileName, int fileFlags,...)
_O_SHORT_LIVED | O_DSYNC | O_DIRECT |
(O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
#ifndef FRONTEND
- Assert(pgwin32_signal_event != NULL); /* small chance of pg_usleep() */
+ /* XXX When called by stat very early on, this fails! */
+ //Assert(pgwin32_signal_event != NULL); /* small chance of pg_usleep() */
#endif
-#ifdef FRONTEND
+ /* Convert char string to wchar_t string. */
+ wideFileNameSize = MultiByteToWideChar(CP_ACP, 0, fileName, -1,
+ wideFileName,
+ lengthof(wideFileName));
+ if (wideFileNameSize == 0)
+ {
+ _dosmaperr(GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
- /*
- * Since PostgreSQL 12, those concurrent-safe versions of open() and
- * fopen() can be used by frontends, having as side-effect to switch the
- * file-translation mode from O_TEXT to O_BINARY if none is specified.
- * Caller may want to enforce the binary or text mode, but if nothing is
- * defined make sure that the default mode maps with what versions older
- * than 12 have been doing.
- */
- if ((fileFlags & O_BINARY) == 0)
- fileFlags |= O_TEXT;
-#endif
+ /* Convert DOS/Win32 path to fully qualified NT path. */
+ ntFileName.Length = 0;
+ ntFileName.MaximumLength = sizeof(buffer);
+ ntFileName.Buffer = buffer;
+ if (!pg_RtlDosPathNameToNtPathName_U(wideFileName,
+ &ntFileName,
+ NULL,
+ NULL))
+ {
+ /* XXX does GetLastError() work for this function? need the
+ * _WithStatus version maybe? */
+ _dosmaperr(GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
- sa.nLength = sizeof(sa);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- while ((h = CreateFile(fileName,
- /* cannot use O_RDONLY, as it == 0 */
- (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
- ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
- /* These flags allow concurrent rename/unlink */
- (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
- &sa,
- openFlagsToCreateFileFlags(fileFlags),
- FILE_ATTRIBUTE_NORMAL |
- ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
- ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
- ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
- ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) |
- ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) |
- ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
- NULL)) == INVALID_HANDLE_VALUE)
+ /* Convert other parameters. */
+ desiredAccess =
+ FILE_READ_ATTRIBUTES | /* allow fstat() even if O_WRONLY */
+ ((fileFlags & O_TEMPORARY) ? DELETE : 0) |
+ ((fileFlags & O_RDWR) ? FILE_GENERIC_WRITE | FILE_GENERIC_READ :
+ (fileFlags & O_WRONLY) ? FILE_GENERIC_WRITE : FILE_GENERIC_READ);
+ shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ InitializeObjectAttributes(&objectAttributes, &ntFileName,
+ OBJ_CASE_INSENSITIVE | OBJ_INHERIT, NULL, NULL);
+ fileAttributes =
+ ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0);
+ if (fileAttributes == 0)
+ fileAttributes = FILE_ATTRIBUTE_NORMAL;
+ if (fileFlags & O_CREAT)
{
+ if (fileFlags & O_EXCL)
+ createDisposition = FILE_CREATE;
+ else if (fileFlags & O_TRUNC)
+ createDisposition = FILE_OVERWRITE_IF;
+ else
+ createDisposition = FILE_OPEN_IF;
+ }
+ else if (fileFlags & O_TRUNC)
+ createDisposition = FILE_OVERWRITE;
+ else
+ createDisposition = FILE_OPEN;
+ createOptions =
+ FILE_SYNCHRONOUS_IO_NONALERT |
+ (backup_semantics ? FILE_OPEN_FOR_BACKUP_INTENT : 0) |
+ ((fileFlags & O_RANDOM) ? FILE_RANDOM_ACCESS : 0) |
+ ((fileFlags & O_SEQUENTIAL) ? FILE_SEQUENTIAL_ONLY : 0) |
+ ((fileFlags & O_DIRECT) ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
+ ((fileFlags & O_DSYNC) ? FILE_WRITE_THROUGH : 0) |
+ ((fileFlags & O_TEMPORARY) ? FILE_DELETE_ON_CLOSE : 0);
+
+ for (;;)
+ {
+ status = pg_NtCreateFile(&h,
+ desiredAccess,
+ &objectAttributes,
+ &ioStatusBlock,
+ NULL,
+ fileAttributes,
+ shareAccess,
+ createDisposition,
+ createOptions,
+ NULL,
+ 0);
+
+ if (NT_SUCCESS(status))
+ break;
+
+ /*
+ * Translate STATUS_DELETE_PENDING to a more Unix-like error.
+ *
+ * If there's no O_CREAT flag, then we'll pretend the file is
+ * invisible. With O_CREAT, we have no choice but to report that
+ * there's a file in the way (which wouldn't happen on Unix).
+ */
+ if (status == STATUS_DELETE_PENDING)
+ {
+ if (fileFlags & O_CREAT)
+ err = ERROR_FILE_EXISTS;
+ else
+ err = ERROR_FILE_NOT_FOUND;
+ _dosmaperr(err);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /*
+ * For everything else, convert the NT error into a DOS error. This
+ * is where STATUS_DELETE_PENDING would normally be mapped to
+ * ERROR_ACCESS_DENIED, and lost to us.
+ */
+ err = pg_RtlNtStatusToDosError(status);
+
/*
* Sharing violation or locking error can indicate antivirus, backup
* or similar software that's locking the file. Wait a bit and try
* again, giving up after 30 seconds.
*/
- DWORD err = GetLastError();
-
if (err == ERROR_SHARING_VIOLATION ||
err == ERROR_LOCK_VIOLATION)
{
@@ -137,41 +188,37 @@ pgwin32_open(const char *fileName, int fileFlags,...)
}
}
- /*
- * ERROR_ACCESS_DENIED is returned if the file is deleted but not yet
- * gone (Windows NT status code is STATUS_DELETE_PENDING). In that
- * case we want to wait a bit and try again, giving up after 1 second
- * (since this condition should never persist very long). However,
- * there are other commonly-hit cases that return ERROR_ACCESS_DENIED,
- * so care is needed. In particular that happens if we try to open a
- * directory, or of course if there's an actual file-permissions
- * problem. To distinguish these cases, try a stat(). In the
- * delete-pending case, it will either also get STATUS_DELETE_PENDING,
- * or it will see the file as gone and fail with ENOENT. In other
- * cases it will usually succeed. The only somewhat-likely case where
- * this coding will uselessly wait is if there's a permissions problem
- * with a containing directory, which we hope will never happen in any
- * performance-critical code paths.
- */
- if (err == ERROR_ACCESS_DENIED)
- {
- if (loops < 10)
- {
- struct stat st;
-
- if (stat(fileName, &st) != 0)
- {
- pg_usleep(100000);
- loops++;
- continue;
- }
- }
- }
-
_dosmaperr(err);
- return -1;
+ return INVALID_HANDLE_VALUE;
}
+ return h;
+}
+
+int
+pgwin32_open(const char *fileName, int fileFlags,...)
+{
+ HANDLE h;
+ int fd;
+
+ h = pgwin32_open_handle(fileName, fileFlags, false);
+ if (h == INVALID_HANDLE_VALUE)
+ return -1;
+
+#ifdef FRONTEND
+
+ /*
+ * Since PostgreSQL 12, those concurrent-safe versions of open() and
+ * fopen() can be used by frontends, having as side-effect to switch the
+ * file-translation mode from O_TEXT to O_BINARY if none is specified.
+ * Caller may want to enforce the binary or text mode, but if nothing is
+ * defined make sure that the default mode maps with what versions older
+ * than 12 have been doing.
+ */
+ if ((fileFlags & O_BINARY) == 0)
+ fileFlags |= O_TEXT;
+#endif
+
/* _open_osfhandle will, on error, set errno accordingly */
if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
CloseHandle(h); /* will not affect errno */
diff --git a/src/port/win32ntdll.c b/src/port/win32ntdll.c
new file mode 100644
index 0000000000..fc9d1b84bb
--- /dev/null
+++ b/src/port/win32ntdll.c
@@ -0,0 +1,68 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32ntdll.c
+ * Dynamically loaded Windows NT functions.
+ *
+ * Portions Copyright (c) 2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/win32ntdll.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#include "port/win32ntdll.h"
+
+NtCreateFile_t pg_NtCreateFile;
+RtlDosPathNameToNtPathName_U_t pg_RtlDosPathNameToNtPathName_U;
+RtlNtStatusToDosError_t pg_RtlNtStatusToDosError;
+
+int
+initialize_ntdll(void)
+{
+ static bool initialized;
+ HMODULE module;
+
+ static const struct {
+ const char *name;
+ pg_funcptr_t *address;
+ } routines[] = {
+ {"NtCreateFile", (pg_funcptr_t *) &pg_NtCreateFile},
+ {"RtlDosPathNameToNtPathName_U",
+ (pg_funcptr_t *) &pg_RtlDosPathNameToNtPathName_U},
+ {"RtlNtStatusToDosError", (pg_funcptr_t *) &pg_RtlNtStatusToDosError}
+ };
+
+ if (initialized)
+ return 0;
+
+ if (!(module = LoadLibraryEx("ntdll.dll", NULL, 0)))
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ for (int i = 0; i < lengthof(routines); ++i)
+ {
+ pg_funcptr_t address;
+
+ address = (pg_funcptr_t) GetProcAddress(module, routines[i].name);
+ if (!address)
+ {
+ _dosmaperr(GetLastError());
+ FreeLibrary(module);
+
+ return -1;
+ }
+
+ *(pg_funcptr_t *) routines[i].address = address;
+ }
+
+ initialized = true;
+
+ return 0;
+}
diff --git a/src/port/win32stat.c b/src/port/win32stat.c
index 2ad8ee1359..c851400dc8 100644
--- a/src/port/win32stat.c
+++ b/src/port/win32stat.c
@@ -18,53 +18,6 @@
#include "c.h"
#include <windows.h>
-/*
- * In order to support MinGW and MSVC2013 we use NtQueryInformationFile as an
- * alternative for GetFileInformationByHandleEx. It is loaded from the ntdll
- * library.
- */
-#if _WIN32_WINNT < 0x0600
-#include <winternl.h>
-
-#if !defined(__MINGW32__) && !defined(__MINGW64__)
-/* MinGW includes this in <winternl.h>, but it is missing in MSVC */
-typedef struct _FILE_STANDARD_INFORMATION
-{
- LARGE_INTEGER AllocationSize;
- LARGE_INTEGER EndOfFile;
- ULONG NumberOfLinks;
- BOOLEAN DeletePending;
- BOOLEAN Directory;
-} FILE_STANDARD_INFORMATION;
-#define FileStandardInformation 5
-#endif /* !defined(__MINGW32__) &&
- * !defined(__MINGW64__) */
-
-typedef NTSTATUS (NTAPI * PFN_NTQUERYINFORMATIONFILE)
- (IN HANDLE FileHandle,
- OUT PIO_STATUS_BLOCK IoStatusBlock,
- OUT PVOID FileInformation,
- IN ULONG Length,
- IN FILE_INFORMATION_CLASS FileInformationClass);
-
-static PFN_NTQUERYINFORMATIONFILE _NtQueryInformationFile = NULL;
-
-static HMODULE ntdll = NULL;
-
-/*
- * Load DLL file just once regardless of how many functions we load/call in it.
- */
-static void
-LoadNtdll(void)
-{
- if (ntdll != NULL)
- return;
- ntdll = LoadLibraryEx("ntdll.dll", NULL, 0);
-}
-
-#endif /* _WIN32_WINNT < 0x0600 */
-
-
/*
* Convert a FILETIME struct into a 64 bit time_t.
*/
@@ -162,120 +115,18 @@ int
_pgstat64(const char *name, struct stat *buf)
{
/*
- * We must use a handle so lstat() returns the information of the target
- * file. To have a reliable test for ERROR_DELETE_PENDING, we use
- * NtQueryInformationFile from Windows 2000 or
- * GetFileInformationByHandleEx from Server 2008 / Vista.
+ * Our open wrapper will report STATUS_DELETE_PENDING as ENOENT. We
+ * request FILE_FLAG_BACKUP_SEMANTICS so that we can open directories too,
+ * for limited purposes. We use the private handle-based version, so we
+ * don't risk running out of fds.
*/
- SECURITY_ATTRIBUTES sa;
HANDLE hFile;
int ret;
-#if _WIN32_WINNT < 0x0600
- IO_STATUS_BLOCK ioStatus;
- FILE_STANDARD_INFORMATION standardInfo;
-#else
- FILE_STANDARD_INFO standardInfo;
-#endif
-
- if (name == NULL || buf == NULL)
- {
- errno = EINVAL;
- return -1;
- }
- /* fast not-exists check */
- if (GetFileAttributes(name) == INVALID_FILE_ATTRIBUTES)
- {
- _dosmaperr(GetLastError());
- return -1;
- }
-
- /* get a file handle as lightweight as we can */
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
- hFile = CreateFile(name,
- GENERIC_READ,
- (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
- &sa,
- OPEN_EXISTING,
- (FILE_FLAG_NO_BUFFERING | FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OVERLAPPED),
- NULL);
+ hFile = pgwin32_open_handle(name, O_RDONLY, true);
if (hFile == INVALID_HANDLE_VALUE)
- {
- DWORD err = GetLastError();
-
- CloseHandle(hFile);
- _dosmaperr(err);
return -1;
- }
-
- memset(&standardInfo, 0, sizeof(standardInfo));
-
-#if _WIN32_WINNT < 0x0600
- if (_NtQueryInformationFile == NULL)
- {
- /* First time through: load ntdll.dll and find NtQueryInformationFile */
- LoadNtdll();
- if (ntdll == NULL)
- {
- DWORD err = GetLastError();
-
- CloseHandle(hFile);
- _dosmaperr(err);
- return -1;
- }
-
- _NtQueryInformationFile = (PFN_NTQUERYINFORMATIONFILE) (pg_funcptr_t)
- GetProcAddress(ntdll, "NtQueryInformationFile");
- if (_NtQueryInformationFile == NULL)
- {
- DWORD err = GetLastError();
- CloseHandle(hFile);
- _dosmaperr(err);
- return -1;
- }
- }
-
- if (!NT_SUCCESS(_NtQueryInformationFile(hFile, &ioStatus, &standardInfo,
- sizeof(standardInfo),
- FileStandardInformation)))
- {
- DWORD err = GetLastError();
-
- CloseHandle(hFile);
- _dosmaperr(err);
- return -1;
- }
-#else
- if (!GetFileInformationByHandleEx(hFile, FileStandardInfo, &standardInfo,
- sizeof(standardInfo)))
- {
- DWORD err = GetLastError();
-
- CloseHandle(hFile);
- _dosmaperr(err);
- return -1;
- }
-#endif /* _WIN32_WINNT < 0x0600 */
-
- if (standardInfo.DeletePending)
- {
- /*
- * File has been deleted, but is not gone from the filesystem yet.
- * This can happen when some process with FILE_SHARE_DELETE has it
- * open, and it will be fully removed once that handle is closed.
- * Meanwhile, we can't open it, so indicate that the file just doesn't
- * exist.
- */
- CloseHandle(hFile);
- errno = ENOENT;
- return -1;
- }
-
- /* At last we can invoke fileinfo_to_stat */
ret = fileinfo_to_stat(hFile, buf);
CloseHandle(hFile);
@@ -296,11 +147,6 @@ _pgfstat64(int fileno, struct stat *buf)
return -1;
}
- /*
- * Since we already have a file handle there is no need to check for
- * ERROR_DELETE_PENDING.
- */
-
return fileinfo_to_stat(hFile, buf);
}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 84f15f7e85..bebb0578dc 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -107,7 +107,8 @@ sub mkvcbuild
pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
pqsignal.c mkdtemp.c qsort.c qsort_arg.c bsearch_arg.c quotes.c system.c
strerror.c tar.c thread.c
- win32env.c win32error.c win32security.c win32setlocale.c win32stat.c);
+ win32env.c win32error.c win32ntdll.c
+ win32security.c win32setlocale.c win32stat.c);
push(@pgportfiles, 'strtof.c') if ($vsVersion < '14.00');
--
2.30.2