aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/postgresql/src
diff options
context:
space:
mode:
authoralexv-smirnov <alex@ydb.tech>2022-12-20 00:50:48 +0300
committeralexv-smirnov <alex@ydb.tech>2022-12-20 00:50:48 +0300
commit84f2cfa253cc618438ed6e9d68b33fa7c0d88cb9 (patch)
treef0cf2236e0aafb3e437199f1ac7b559e7fad554a /contrib/libs/postgresql/src
parentbde6febc1ad3b826e72746de21d7250803e8e0b5 (diff)
downloadydb-84f2cfa253cc618438ed6e9d68b33fa7c0d88cb9.tar.gz
add windows platform to ydb github export
Diffstat (limited to 'contrib/libs/postgresql/src')
-rw-r--r--contrib/libs/postgresql/src/backend/port/win32/crashdump.c183
-rw-r--r--contrib/libs/postgresql/src/backend/port/win32/signal.c344
-rw-r--r--contrib/libs/postgresql/src/backend/port/win32/socket.c700
-rw-r--r--contrib/libs/postgresql/src/backend/port/win32/timer.c121
-rw-r--r--contrib/libs/postgresql/src/backend/port/win32_sema.c235
-rw-r--r--contrib/libs/postgresql/src/backend/port/win32_shmem.c607
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/arpa/inet.h3
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/grp.h1
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/netdb.h1
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/netinet/in.h3
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/pwd.h3
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/sys/socket.h33
-rw-r--r--contrib/libs/postgresql/src/include/port/win32/sys/wait.h3
-rw-r--r--contrib/libs/postgresql/src/include/port/win32_msvc/dirent.h34
-rw-r--r--contrib/libs/postgresql/src/include/port/win32_msvc/sys/file.h1
-rw-r--r--contrib/libs/postgresql/src/include/port/win32_msvc/sys/param.h1
-rw-r--r--contrib/libs/postgresql/src/include/port/win32_msvc/sys/time.h1
-rw-r--r--contrib/libs/postgresql/src/include/port/win32_msvc/unistd.h1
-rw-r--r--contrib/libs/postgresql/src/include/port/win32_msvc/utime.h3
-rw-r--r--contrib/libs/postgresql/src/port/dirmod.c355
-rw-r--r--contrib/libs/postgresql/src/port/dlopen.c145
-rw-r--r--contrib/libs/postgresql/src/port/getaddrinfo.c396
-rw-r--r--contrib/libs/postgresql/src/port/getopt.c136
-rw-r--r--contrib/libs/postgresql/src/port/getrusage.c110
-rw-r--r--contrib/libs/postgresql/src/port/gettimeofday.c118
-rw-r--r--contrib/libs/postgresql/src/port/inet_aton.c149
-rw-r--r--contrib/libs/postgresql/src/port/kill.c97
-rw-r--r--contrib/libs/postgresql/src/port/open.c216
-rw-r--r--contrib/libs/postgresql/src/port/pread.c58
-rw-r--r--contrib/libs/postgresql/src/port/pwrite.c55
-rw-r--r--contrib/libs/postgresql/src/port/pwritev.c58
-rw-r--r--contrib/libs/postgresql/src/port/system.c117
-rw-r--r--contrib/libs/postgresql/src/port/win32env.c163
-rw-r--r--contrib/libs/postgresql/src/port/win32error.c208
-rw-r--r--contrib/libs/postgresql/src/port/win32security.c178
-rw-r--r--contrib/libs/postgresql/src/port/win32setlocale.c193
-rw-r--r--contrib/libs/postgresql/src/port/win32stat.c327
37 files changed, 5357 insertions, 0 deletions
diff --git a/contrib/libs/postgresql/src/backend/port/win32/crashdump.c b/contrib/libs/postgresql/src/backend/port/win32/crashdump.c
new file mode 100644
index 0000000000..45b6696ba1
--- /dev/null
+++ b/contrib/libs/postgresql/src/backend/port/win32/crashdump.c
@@ -0,0 +1,183 @@
+/*-------------------------------------------------------------------------
+ *
+ * crashdump.c
+ * Automatic crash dump creation for PostgreSQL on Windows
+ *
+ * The crashdump feature traps unhandled win32 exceptions produced by the
+ * backend, and tries to produce a Windows MiniDump crash
+ * dump for later debugging and analysis. The machine performing the dump
+ * doesn't need any special debugging tools; the user only needs to send
+ * the dump to somebody who has the same version of PostgreSQL and has debugging
+ * tools.
+ *
+ * crashdump module originally by Craig Ringer <ringerc@ringerc.id.au>
+ *
+ * LIMITATIONS
+ * ===========
+ * This *won't* work in hard OOM situations or stack overflows.
+ *
+ * For those, it'd be necessary to take a much more complicated approach where
+ * the handler switches to a new stack (if it can) and forks a helper process
+ * to debug it self.
+ *
+ * POSSIBLE FUTURE WORK
+ * ====================
+ * For bonus points, the crash dump format permits embedding of user-supplied
+ * data. If there's anything else that should always be supplied with a crash
+ * dump (postgresql.conf? Last few lines of a log file?), it could potentially
+ * be added, though at the cost of a greater chance of the crash dump failing.
+ *
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/port/win32/crashdump.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#define WIN32_LEAN_AND_MEAN
+
+/*
+ * Some versions of the MS SDK contain "typedef enum { ... } ;" which the MS
+ * compiler quite sanely complains about. Well done, Microsoft.
+ * This pragma disables the warning just while we include the header.
+ * The pragma is known to work with all (as at the time of writing) supported
+ * versions of MSVC.
+ */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4091)
+#endif
+#include <dbghelp.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+/*
+ * Much of the following code is based on CodeProject and MSDN examples,
+ * particularly
+ * http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx
+ *
+ * Useful MSDN articles:
+ *
+ * http://msdn.microsoft.com/en-us/library/ff805116(v=VS.85).aspx
+ * http://msdn.microsoft.com/en-us/library/ms679294(VS.85).aspx
+ *
+ * Other useful articles on working with minidumps:
+ * http://www.debuginfo.com/articles/effminidumps.html
+ */
+
+typedef BOOL (WINAPI * MINIDUMPWRITEDUMP) (HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
+ CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
+);
+
+
+/*
+ * This function is the exception handler passed to SetUnhandledExceptionFilter.
+ * It's invoked only if there's an unhandled exception. The handler will use
+ * dbghelp.dll to generate a crash dump, then resume the normal unhandled
+ * exception process, which will generally exit with an error message from
+ * the runtime.
+ *
+ * This function is run under the unhandled exception handler, effectively
+ * in a crash context, so it should be careful with memory and avoid using
+ * any PostgreSQL functions.
+ */
+static LONG WINAPI
+crashDumpHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
+{
+ /*
+ * We only write crash dumps if the "crashdumps" directory within the
+ * postgres data directory exists.
+ */
+ DWORD attribs = GetFileAttributesA("crashdumps");
+
+ if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ /* 'crashdumps' exists and is a directory. Try to write a dump' */
+ HMODULE hDll = NULL;
+ MINIDUMPWRITEDUMP pDump = NULL;
+ MINIDUMP_TYPE dumpType;
+ char dumpPath[_MAX_PATH];
+ HANDLE selfProcHandle = GetCurrentProcess();
+ DWORD selfPid = GetProcessId(selfProcHandle);
+ HANDLE dumpFile;
+ DWORD systemTicks;
+ struct _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
+
+ ExInfo.ThreadId = GetCurrentThreadId();
+ ExInfo.ExceptionPointers = pExceptionInfo;
+ ExInfo.ClientPointers = FALSE;
+
+ /* Load the dbghelp.dll library and functions */
+ hDll = LoadLibrary("dbghelp.dll");
+ if (hDll == NULL)
+ {
+ write_stderr("could not load dbghelp.dll, cannot write crash dump\n");
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ pDump = (MINIDUMPWRITEDUMP) (pg_funcptr_t) GetProcAddress(hDll, "MiniDumpWriteDump");
+
+ if (pDump == NULL)
+ {
+ write_stderr("could not load required functions in dbghelp.dll, cannot write crash dump\n");
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ /*
+ * Dump as much as we can, except shared memory, code segments, and
+ * memory mapped files. Exactly what we can dump depends on the
+ * version of dbghelp.dll, see:
+ * http://msdn.microsoft.com/en-us/library/ms680519(v=VS.85).aspx
+ */
+ dumpType = MiniDumpNormal | MiniDumpWithHandleData |
+ MiniDumpWithDataSegs;
+
+ if (GetProcAddress(hDll, "EnumDirTree") != NULL)
+ {
+ /* If this function exists, we have version 5.2 or newer */
+ dumpType |= MiniDumpWithIndirectlyReferencedMemory |
+ MiniDumpWithPrivateReadWriteMemory;
+ }
+
+ systemTicks = GetTickCount();
+ snprintf(dumpPath, _MAX_PATH,
+ "crashdumps\\postgres-pid%0i-%0i.mdmp",
+ (int) selfPid, (int) systemTicks);
+ dumpPath[_MAX_PATH - 1] = '\0';
+
+ dumpFile = CreateFile(dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (dumpFile == INVALID_HANDLE_VALUE)
+ {
+ write_stderr("could not open crash dump file \"%s\" for writing: error code %lu\n",
+ dumpPath, GetLastError());
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ if ((*pDump) (selfProcHandle, selfPid, dumpFile, dumpType, &ExInfo,
+ NULL, NULL))
+ write_stderr("wrote crash dump to file \"%s\"\n", dumpPath);
+ else
+ write_stderr("could not write crash dump to file \"%s\": error code %lu\n",
+ dumpPath, GetLastError());
+
+ CloseHandle(dumpFile);
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+
+void
+pgwin32_install_crashdump_handler(void)
+{
+ SetUnhandledExceptionFilter(crashDumpHandler);
+}
diff --git a/contrib/libs/postgresql/src/backend/port/win32/signal.c b/contrib/libs/postgresql/src/backend/port/win32/signal.c
new file mode 100644
index 0000000000..580a517f3f
--- /dev/null
+++ b/contrib/libs/postgresql/src/backend/port/win32/signal.c
@@ -0,0 +1,344 @@
+/*-------------------------------------------------------------------------
+ *
+ * signal.c
+ * Microsoft Windows Win32 Signal Emulation Functions
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/port/win32/signal.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "libpq/pqsignal.h"
+
+/*
+ * These are exported for use by the UNBLOCKED_SIGNAL_QUEUE() macro.
+ * pg_signal_queue must be volatile since it is changed by the signal
+ * handling thread and inspected without any lock by the main thread.
+ * pg_signal_mask is only changed by main thread so shouldn't need it.
+ */
+volatile int pg_signal_queue;
+int pg_signal_mask;
+
+HANDLE pgwin32_signal_event;
+HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
+
+/*
+ * pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only
+ * variable that can be accessed from the signal sending threads!
+ */
+static CRITICAL_SECTION pg_signal_crit_sec;
+
+/* Note that array elements 0 are unused since they correspond to signal 0 */
+static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
+static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
+
+
+/* Signal handling thread functions */
+static DWORD WINAPI pg_signal_thread(LPVOID param);
+static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
+
+
+/*
+ * pg_usleep --- delay the specified number of microseconds, but
+ * stop waiting if a signal arrives.
+ *
+ * This replaces the non-signal-aware version provided by src/port/pgsleep.c.
+ */
+void
+pg_usleep(long microsec)
+{
+ Assert(pgwin32_signal_event != NULL);
+ if (WaitForSingleObject(pgwin32_signal_event,
+ (microsec < 500 ? 1 : (microsec + 500) / 1000))
+ == WAIT_OBJECT_0)
+ {
+ pgwin32_dispatch_queued_signals();
+ errno = EINTR;
+ return;
+ }
+}
+
+
+/* Initialization */
+void
+pgwin32_signal_initialize(void)
+{
+ int i;
+ HANDLE signal_thread_handle;
+
+ InitializeCriticalSection(&pg_signal_crit_sec);
+
+ for (i = 0; i < PG_SIGNAL_COUNT; i++)
+ {
+ pg_signal_array[i] = SIG_DFL;
+ pg_signal_defaults[i] = SIG_IGN;
+ }
+ pg_signal_mask = 0;
+ pg_signal_queue = 0;
+
+ /* Create the global event handle used to flag signals */
+ pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (pgwin32_signal_event == NULL)
+ ereport(FATAL,
+ (errmsg_internal("could not create signal event: error code %lu", GetLastError())));
+
+ /* Create thread for handling signals */
+ signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
+ if (signal_thread_handle == NULL)
+ ereport(FATAL,
+ (errmsg_internal("could not create signal handler thread")));
+
+ /* Create console control handle to pick up Ctrl-C etc */
+ if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
+ ereport(FATAL,
+ (errmsg_internal("could not set console control handler")));
+}
+
+/*
+ * Dispatch all signals currently queued and not blocked
+ * Blocked signals are ignored, and will be fired at the time of
+ * the pqsigsetmask() call.
+ */
+void
+pgwin32_dispatch_queued_signals(void)
+{
+ int exec_mask;
+
+ Assert(pgwin32_signal_event != NULL);
+ EnterCriticalSection(&pg_signal_crit_sec);
+ while ((exec_mask = UNBLOCKED_SIGNAL_QUEUE()) != 0)
+ {
+ /* One or more unblocked signals queued for execution */
+ int i;
+
+ for (i = 1; i < PG_SIGNAL_COUNT; i++)
+ {
+ if (exec_mask & sigmask(i))
+ {
+ /* Execute this signal */
+ pqsigfunc sig = pg_signal_array[i];
+
+ if (sig == SIG_DFL)
+ sig = pg_signal_defaults[i];
+ pg_signal_queue &= ~sigmask(i);
+ if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
+ {
+ LeaveCriticalSection(&pg_signal_crit_sec);
+ sig(i);
+ EnterCriticalSection(&pg_signal_crit_sec);
+ break; /* Restart outer loop, in case signal mask or
+ * queue has been modified inside signal
+ * handler */
+ }
+ }
+ }
+ }
+ ResetEvent(pgwin32_signal_event);
+ LeaveCriticalSection(&pg_signal_crit_sec);
+}
+
+/* signal masking. Only called on main thread, no sync required */
+int
+pqsigsetmask(int mask)
+{
+ int prevmask;
+
+ prevmask = pg_signal_mask;
+ pg_signal_mask = mask;
+
+ /*
+ * Dispatch any signals queued up right away, in case we have unblocked
+ * one or more signals previously queued
+ */
+ pgwin32_dispatch_queued_signals();
+
+ return prevmask;
+}
+
+
+/*
+ * Unix-like signal handler installation
+ *
+ * Only called on main thread, no sync required
+ */
+pqsigfunc
+pqsignal(int signum, pqsigfunc handler)
+{
+ pqsigfunc prevfunc;
+
+ if (signum >= PG_SIGNAL_COUNT || signum < 0)
+ return SIG_ERR;
+ prevfunc = pg_signal_array[signum];
+ pg_signal_array[signum] = handler;
+ return prevfunc;
+}
+
+/* Create the signal listener pipe for specified PID */
+HANDLE
+pgwin32_create_signal_listener(pid_t pid)
+{
+ char pipename[128];
+ HANDLE pipe;
+
+ snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid);
+
+ pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
+
+ if (pipe == INVALID_HANDLE_VALUE)
+ ereport(ERROR,
+ (errmsg("could not create signal listener pipe for PID %d: error code %lu",
+ (int) pid, GetLastError())));
+
+ return pipe;
+}
+
+
+/*
+ * All functions below execute on the signal handler thread
+ * and must be synchronized as such!
+ * NOTE! The only global variable that can be used is
+ * pg_signal_queue!
+ */
+
+
+/*
+ * Queue a signal for the main thread, by setting the flag bit and event.
+ */
+void
+pg_queue_signal(int signum)
+{
+ Assert(pgwin32_signal_event != NULL);
+ if (signum >= PG_SIGNAL_COUNT || signum <= 0)
+ return; /* ignore any bad signal number */
+
+ EnterCriticalSection(&pg_signal_crit_sec);
+ pg_signal_queue |= sigmask(signum);
+ LeaveCriticalSection(&pg_signal_crit_sec);
+
+ SetEvent(pgwin32_signal_event);
+}
+
+/* Signal handling thread */
+static DWORD WINAPI
+pg_signal_thread(LPVOID param)
+{
+ char pipename[128];
+ HANDLE pipe = pgwin32_initial_signal_pipe;
+
+ /* Set up pipe name, in case we have to re-create the pipe. */
+ snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
+
+ for (;;)
+ {
+ BOOL fConnected;
+
+ /* Create a new pipe instance if we don't have one. */
+ if (pipe == INVALID_HANDLE_VALUE)
+ {
+ pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
+
+ if (pipe == INVALID_HANDLE_VALUE)
+ {
+ write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
+ SleepEx(500, FALSE);
+ continue;
+ }
+ }
+
+ /*
+ * Wait for a client to connect. If something connects before we
+ * reach here, we'll get back a "failure" with ERROR_PIPE_CONNECTED,
+ * which is actually a success (way to go, Microsoft).
+ */
+ fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+ if (fConnected)
+ {
+ /*
+ * We have a connection from a would-be signal sender. Process it.
+ */
+ BYTE sigNum;
+ DWORD bytes;
+
+ if (ReadFile(pipe, &sigNum, 1, &bytes, NULL) &&
+ bytes == 1)
+ {
+ /*
+ * Queue the signal before responding to the client. In this
+ * way, it's guaranteed that once kill() has returned in the
+ * signal sender, the next CHECK_FOR_INTERRUPTS() in the
+ * signal recipient will see the signal. (This is a stronger
+ * guarantee than POSIX makes; maybe we don't need it? But
+ * without it, we've seen timing bugs on Windows that do not
+ * manifest on any known Unix.)
+ */
+ pg_queue_signal(sigNum);
+
+ /*
+ * Write something back to the client, allowing its
+ * CallNamedPipe() call to terminate.
+ */
+ WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it
+ * works or not */
+
+ /*
+ * We must wait for the client to read the data before we can
+ * disconnect, else the data will be lost. (If the WriteFile
+ * call failed, there'll be nothing in the buffer, so this
+ * shouldn't block.)
+ */
+ FlushFileBuffers(pipe);
+ }
+ else
+ {
+ /*
+ * If we fail to read a byte from the client, assume it's the
+ * client's problem and do nothing. Perhaps it'd be better to
+ * force a pipe close and reopen?
+ */
+ }
+
+ /* Disconnect from client so that we can re-use the pipe. */
+ DisconnectNamedPipe(pipe);
+ }
+ else
+ {
+ /*
+ * Connection failed. Cleanup and try again.
+ *
+ * This should never happen. If it does, there's a window where
+ * we'll miss signals until we manage to re-create the pipe.
+ * However, just trying to use the same pipe again is probably not
+ * going to work, so we have little choice.
+ */
+ CloseHandle(pipe);
+ pipe = INVALID_HANDLE_VALUE;
+ }
+ }
+ return 0;
+}
+
+
+/* Console control handler will execute on a thread created
+ by the OS at the time of invocation */
+static BOOL WINAPI
+pg_console_handler(DWORD dwCtrlType)
+{
+ if (dwCtrlType == CTRL_C_EVENT ||
+ dwCtrlType == CTRL_BREAK_EVENT ||
+ dwCtrlType == CTRL_CLOSE_EVENT ||
+ dwCtrlType == CTRL_SHUTDOWN_EVENT)
+ {
+ pg_queue_signal(SIGINT);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/contrib/libs/postgresql/src/backend/port/win32/socket.c b/contrib/libs/postgresql/src/backend/port/win32/socket.c
new file mode 100644
index 0000000000..af151e8470
--- /dev/null
+++ b/contrib/libs/postgresql/src/backend/port/win32/socket.c
@@ -0,0 +1,700 @@
+/*-------------------------------------------------------------------------
+ *
+ * socket.c
+ * Microsoft Windows Win32 Socket Functions
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/port/win32/socket.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+/*
+ * Indicate if pgwin32_recv() and pgwin32_send() should operate
+ * in non-blocking mode.
+ *
+ * Since the socket emulation layer always sets the actual socket to
+ * non-blocking mode in order to be able to deliver signals, we must
+ * specify this in a separate flag if we actually need non-blocking
+ * operation.
+ *
+ * This flag changes the behaviour *globally* for all socket operations,
+ * so it should only be set for very short periods of time.
+ */
+int pgwin32_noblock = 0;
+
+/* Undef the macros defined in win32.h, so we can access system functions */
+#undef socket
+#undef bind
+#undef listen
+#undef accept
+#undef connect
+#undef select
+#undef recv
+#undef send
+
+/*
+ * Blocking socket functions implemented so they listen on both
+ * the socket and the signal event, required for signal handling.
+ */
+
+/*
+ * Convert the last socket error code into errno
+ *
+ * Note: where there is a direct correspondence between a WSAxxx error code
+ * and a Berkeley error symbol, this mapping is actually a no-op, because
+ * in win32.h we redefine the network-related Berkeley error symbols to have
+ * the values of their WSAxxx counterparts. The point of the switch is
+ * mostly to translate near-miss error codes into something that's sensible
+ * in the Berkeley universe.
+ */
+static void
+TranslateSocketError(void)
+{
+ switch (WSAGetLastError())
+ {
+ case WSAEINVAL:
+ case WSANOTINITIALISED:
+ case WSAEINVALIDPROVIDER:
+ case WSAEINVALIDPROCTABLE:
+ case WSAEDESTADDRREQ:
+ errno = EINVAL;
+ break;
+ case WSAEINPROGRESS:
+ errno = EINPROGRESS;
+ break;
+ case WSAEFAULT:
+ errno = EFAULT;
+ break;
+ case WSAEISCONN:
+ errno = EISCONN;
+ break;
+ case WSAEMSGSIZE:
+ errno = EMSGSIZE;
+ break;
+ case WSAEAFNOSUPPORT:
+ errno = EAFNOSUPPORT;
+ break;
+ case WSAEMFILE:
+ errno = EMFILE;
+ break;
+ case WSAENOBUFS:
+ errno = ENOBUFS;
+ break;
+ case WSAEPROTONOSUPPORT:
+ case WSAEPROTOTYPE:
+ case WSAESOCKTNOSUPPORT:
+ errno = EPROTONOSUPPORT;
+ break;
+ case WSAECONNABORTED:
+ errno = ECONNABORTED;
+ break;
+ case WSAECONNREFUSED:
+ errno = ECONNREFUSED;
+ break;
+ case WSAECONNRESET:
+ errno = ECONNRESET;
+ break;
+ case WSAEINTR:
+ errno = EINTR;
+ break;
+ case WSAENOTSOCK:
+ errno = ENOTSOCK;
+ break;
+ case WSAEOPNOTSUPP:
+ errno = EOPNOTSUPP;
+ break;
+ case WSAEWOULDBLOCK:
+ errno = EWOULDBLOCK;
+ break;
+ case WSAEACCES:
+ errno = EACCES;
+ break;
+ case WSAEADDRINUSE:
+ errno = EADDRINUSE;
+ break;
+ case WSAEADDRNOTAVAIL:
+ errno = EADDRNOTAVAIL;
+ break;
+ case WSAEHOSTDOWN:
+ errno = EHOSTDOWN;
+ break;
+ case WSAEHOSTUNREACH:
+ case WSAHOST_NOT_FOUND:
+ errno = EHOSTUNREACH;
+ break;
+ case WSAENETDOWN:
+ errno = ENETDOWN;
+ break;
+ case WSAENETUNREACH:
+ errno = ENETUNREACH;
+ break;
+ case WSAENETRESET:
+ errno = ENETRESET;
+ break;
+ case WSAENOTCONN:
+ case WSAESHUTDOWN:
+ case WSAEDISCON:
+ errno = ENOTCONN;
+ break;
+ default:
+ ereport(NOTICE,
+ (errmsg_internal("unrecognized win32 socket error code: %d", WSAGetLastError())));
+ errno = EINVAL;
+ }
+}
+
+static int
+pgwin32_poll_signals(void)
+{
+ if (UNBLOCKED_SIGNAL_QUEUE())
+ {
+ pgwin32_dispatch_queued_signals();
+ errno = EINTR;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+isDataGram(SOCKET s)
+{
+ int type;
+ int typelen = sizeof(type);
+
+ if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen))
+ return 1;
+
+ return (type == SOCK_DGRAM) ? 1 : 0;
+}
+
+int
+pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
+{
+ static HANDLE waitevent = INVALID_HANDLE_VALUE;
+ static SOCKET current_socket = INVALID_SOCKET;
+ static int isUDP = 0;
+ HANDLE events[2];
+ int r;
+
+ /* Create an event object just once and use it on all future calls */
+ if (waitevent == INVALID_HANDLE_VALUE)
+ {
+ waitevent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (waitevent == INVALID_HANDLE_VALUE)
+ ereport(ERROR,
+ (errmsg_internal("could not create socket waiting event: error code %lu", GetLastError())));
+ }
+ else if (!ResetEvent(waitevent))
+ ereport(ERROR,
+ (errmsg_internal("could not reset socket waiting event: error code %lu", GetLastError())));
+
+ /*
+ * Track whether socket is UDP or not. (NB: most likely, this is both
+ * useless and wrong; there is no reason to think that the behavior of
+ * WSAEventSelect is different for TCP and UDP.)
+ */
+ if (current_socket != s)
+ isUDP = isDataGram(s);
+ current_socket = s;
+
+ /*
+ * Attach event to socket. NOTE: we must detach it again before
+ * returning, since other bits of code may try to attach other events to
+ * the socket.
+ */
+ if (WSAEventSelect(s, waitevent, what) != 0)
+ {
+ TranslateSocketError();
+ return 0;
+ }
+
+ events[0] = pgwin32_signal_event;
+ events[1] = waitevent;
+
+ /*
+ * Just a workaround of unknown locking problem with writing in UDP socket
+ * under high load: Client's pgsql backend sleeps infinitely in
+ * WaitForMultipleObjectsEx, pgstat process sleeps in pgwin32_select().
+ * So, we will wait with small timeout(0.1 sec) and if socket is still
+ * blocked, try WSASend (see comments in pgwin32_select) and wait again.
+ */
+ if ((what & FD_WRITE) && isUDP)
+ {
+ for (;;)
+ {
+ r = WaitForMultipleObjectsEx(2, events, FALSE, 100, TRUE);
+
+ if (r == WAIT_TIMEOUT)
+ {
+ char c;
+ WSABUF buf;
+ DWORD sent;
+
+ buf.buf = &c;
+ buf.len = 0;
+
+ r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL);
+ if (r == 0) /* Completed - means things are fine! */
+ {
+ WSAEventSelect(s, NULL, 0);
+ return 1;
+ }
+ else if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ TranslateSocketError();
+ WSAEventSelect(s, NULL, 0);
+ return 0;
+ }
+ }
+ else
+ break;
+ }
+ }
+ else
+ r = WaitForMultipleObjectsEx(2, events, FALSE, timeout, TRUE);
+
+ WSAEventSelect(s, NULL, 0);
+
+ if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION)
+ {
+ pgwin32_dispatch_queued_signals();
+ errno = EINTR;
+ return 0;
+ }
+ if (r == WAIT_OBJECT_0 + 1)
+ return 1;
+ if (r == WAIT_TIMEOUT)
+ {
+ errno = EWOULDBLOCK;
+ return 0;
+ }
+ ereport(ERROR,
+ (errmsg_internal("unrecognized return value from WaitForMultipleObjects: %d (error code %lu)", r, GetLastError())));
+ return 0;
+}
+
+/*
+ * Create a socket, setting it to overlapped and non-blocking
+ */
+SOCKET
+pgwin32_socket(int af, int type, int protocol)
+{
+ SOCKET s;
+ unsigned long on = 1;
+
+ s = WSASocket(af, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
+ if (s == INVALID_SOCKET)
+ {
+ TranslateSocketError();
+ return INVALID_SOCKET;
+ }
+
+ if (ioctlsocket(s, FIONBIO, &on))
+ {
+ TranslateSocketError();
+ return INVALID_SOCKET;
+ }
+ errno = 0;
+
+ return s;
+}
+
+int
+pgwin32_bind(SOCKET s, struct sockaddr *addr, int addrlen)
+{
+ int res;
+
+ res = bind(s, addr, addrlen);
+ if (res < 0)
+ TranslateSocketError();
+ return res;
+}
+
+int
+pgwin32_listen(SOCKET s, int backlog)
+{
+ int res;
+
+ res = listen(s, backlog);
+ if (res < 0)
+ TranslateSocketError();
+ return res;
+}
+
+SOCKET
+pgwin32_accept(SOCKET s, struct sockaddr *addr, int *addrlen)
+{
+ SOCKET rs;
+
+ /*
+ * Poll for signals, but don't return with EINTR, since we don't handle
+ * that in pqcomm.c
+ */
+ pgwin32_poll_signals();
+
+ rs = WSAAccept(s, addr, addrlen, NULL, 0);
+ if (rs == INVALID_SOCKET)
+ {
+ TranslateSocketError();
+ return INVALID_SOCKET;
+ }
+ return rs;
+}
+
+
+/* No signal delivery during connect. */
+int
+pgwin32_connect(SOCKET s, const struct sockaddr *addr, int addrlen)
+{
+ int r;
+
+ r = WSAConnect(s, addr, addrlen, NULL, NULL, NULL, NULL);
+ if (r == 0)
+ return 0;
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ TranslateSocketError();
+ return -1;
+ }
+
+ while (pgwin32_waitforsinglesocket(s, FD_CONNECT, INFINITE) == 0)
+ {
+ /* Loop endlessly as long as we are just delivering signals */
+ }
+
+ return 0;
+}
+
+int
+pgwin32_recv(SOCKET s, char *buf, int len, int f)
+{
+ WSABUF wbuf;
+ int r;
+ DWORD b;
+ DWORD flags = f;
+ int n;
+
+ if (pgwin32_poll_signals())
+ return -1;
+
+ wbuf.len = len;
+ wbuf.buf = buf;
+
+ r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL);
+ if (r != SOCKET_ERROR)
+ return b; /* success */
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ TranslateSocketError();
+ return -1;
+ }
+
+ if (pgwin32_noblock)
+ {
+ /*
+ * No data received, and we are in "emulated non-blocking mode", so
+ * return indicating that we'd block if we were to continue.
+ */
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+
+ /* We're in blocking mode, so wait for data */
+
+ for (n = 0; n < 5; n++)
+ {
+ if (pgwin32_waitforsinglesocket(s, FD_READ | FD_CLOSE | FD_ACCEPT,
+ INFINITE) == 0)
+ return -1; /* errno already set */
+
+ r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL);
+ if (r != SOCKET_ERROR)
+ return b; /* success */
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ TranslateSocketError();
+ return -1;
+ }
+
+ /*
+ * There seem to be cases on win2k (at least) where WSARecv can return
+ * WSAEWOULDBLOCK even when pgwin32_waitforsinglesocket claims the
+ * socket is readable. In this case, just sleep for a moment and try
+ * again. We try up to 5 times - if it fails more than that it's not
+ * likely to ever come back.
+ */
+ pg_usleep(10000);
+ }
+ ereport(NOTICE,
+ (errmsg_internal("could not read from ready socket (after retries)")));
+ errno = EWOULDBLOCK;
+ return -1;
+}
+
+/*
+ * The second argument to send() is defined by SUS to be a "const void *"
+ * and so we use the same signature here to keep compilers happy when
+ * handling callers.
+ *
+ * But the buf member of a WSABUF struct is defined as "char *", so we cast
+ * the second argument to that here when assigning it, also to keep compilers
+ * happy.
+ */
+
+int
+pgwin32_send(SOCKET s, const void *buf, int len, int flags)
+{
+ WSABUF wbuf;
+ int r;
+ DWORD b;
+
+ if (pgwin32_poll_signals())
+ return -1;
+
+ wbuf.len = len;
+ wbuf.buf = (char *) buf;
+
+ /*
+ * Readiness of socket to send data to UDP socket may be not true: socket
+ * can become busy again! So loop until send or error occurs.
+ */
+ for (;;)
+ {
+ r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL);
+ if (r != SOCKET_ERROR && b > 0)
+ /* Write succeeded right away */
+ return b;
+
+ if (r == SOCKET_ERROR &&
+ WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ TranslateSocketError();
+ return -1;
+ }
+
+ if (pgwin32_noblock)
+ {
+ /*
+ * No data sent, and we are in "emulated non-blocking mode", so
+ * return indicating that we'd block if we were to continue.
+ */
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+
+ /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
+
+ if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE, INFINITE) == 0)
+ return -1;
+ }
+
+ return -1;
+}
+
+
+/*
+ * Wait for activity on one or more sockets.
+ * While waiting, allow signals to run
+ *
+ * NOTE! Currently does not implement exceptfds check,
+ * since it is not used in postgresql!
+ */
+int
+pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout)
+{
+ WSAEVENT events[FD_SETSIZE * 2]; /* worst case is readfds totally
+ * different from writefds, so
+ * 2*FD_SETSIZE sockets */
+ SOCKET sockets[FD_SETSIZE * 2];
+ int numevents = 0;
+ int i;
+ int r;
+ DWORD timeoutval = WSA_INFINITE;
+ FD_SET outreadfds;
+ FD_SET outwritefds;
+ int nummatches = 0;
+
+ Assert(exceptfds == NULL);
+
+ if (pgwin32_poll_signals())
+ return -1;
+
+ FD_ZERO(&outreadfds);
+ FD_ZERO(&outwritefds);
+
+ /*
+ * Windows does not guarantee to log an FD_WRITE network event indicating
+ * that more data can be sent unless the previous send() failed with
+ * WSAEWOULDBLOCK. While our caller might well have made such a call, we
+ * cannot assume that here. Therefore, if waiting for write-ready, force
+ * the issue by doing a dummy send(). If the dummy send() succeeds,
+ * assume that the socket is in fact write-ready, and return immediately.
+ * Also, if it fails with something other than WSAEWOULDBLOCK, return a
+ * write-ready indication to let our caller deal with the error condition.
+ */
+ if (writefds != NULL)
+ {
+ for (i = 0; i < writefds->fd_count; i++)
+ {
+ char c;
+ WSABUF buf;
+ DWORD sent;
+
+ buf.buf = &c;
+ buf.len = 0;
+
+ r = WSASend(writefds->fd_array[i], &buf, 1, &sent, 0, NULL, NULL);
+ if (r == 0 || WSAGetLastError() != WSAEWOULDBLOCK)
+ FD_SET(writefds->fd_array[i], &outwritefds);
+ }
+
+ /* If we found any write-ready sockets, just return them immediately */
+ if (outwritefds.fd_count > 0)
+ {
+ memcpy(writefds, &outwritefds, sizeof(fd_set));
+ if (readfds)
+ FD_ZERO(readfds);
+ return outwritefds.fd_count;
+ }
+ }
+
+
+ /* Now set up for an actual select */
+
+ if (timeout != NULL)
+ {
+ /* timeoutval is in milliseconds */
+ timeoutval = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+ }
+
+ if (readfds != NULL)
+ {
+ for (i = 0; i < readfds->fd_count; i++)
+ {
+ events[numevents] = WSACreateEvent();
+ sockets[numevents] = readfds->fd_array[i];
+ numevents++;
+ }
+ }
+ if (writefds != NULL)
+ {
+ for (i = 0; i < writefds->fd_count; i++)
+ {
+ if (!readfds ||
+ !FD_ISSET(writefds->fd_array[i], readfds))
+ {
+ /* If the socket is not in the read list */
+ events[numevents] = WSACreateEvent();
+ sockets[numevents] = writefds->fd_array[i];
+ numevents++;
+ }
+ }
+ }
+
+ for (i = 0; i < numevents; i++)
+ {
+ int flags = 0;
+
+ if (readfds && FD_ISSET(sockets[i], readfds))
+ flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
+
+ if (writefds && FD_ISSET(sockets[i], writefds))
+ flags |= FD_WRITE | FD_CLOSE;
+
+ if (WSAEventSelect(sockets[i], events[i], flags) != 0)
+ {
+ TranslateSocketError();
+ /* release already-assigned event objects */
+ while (--i >= 0)
+ WSAEventSelect(sockets[i], NULL, 0);
+ for (i = 0; i < numevents; i++)
+ WSACloseEvent(events[i]);
+ return -1;
+ }
+ }
+
+ events[numevents] = pgwin32_signal_event;
+ r = WaitForMultipleObjectsEx(numevents + 1, events, FALSE, timeoutval, TRUE);
+ if (r != WAIT_TIMEOUT && r != WAIT_IO_COMPLETION && r != (WAIT_OBJECT_0 + numevents))
+ {
+ /*
+ * We scan all events, even those not signaled, in case more than one
+ * event has been tagged but Wait.. can only return one.
+ */
+ WSANETWORKEVENTS resEvents;
+
+ for (i = 0; i < numevents; i++)
+ {
+ ZeroMemory(&resEvents, sizeof(resEvents));
+ if (WSAEnumNetworkEvents(sockets[i], events[i], &resEvents) != 0)
+ elog(ERROR, "failed to enumerate network events: error code %d",
+ WSAGetLastError());
+ /* Read activity? */
+ if (readfds && FD_ISSET(sockets[i], readfds))
+ {
+ if ((resEvents.lNetworkEvents & FD_READ) ||
+ (resEvents.lNetworkEvents & FD_ACCEPT) ||
+ (resEvents.lNetworkEvents & FD_CLOSE))
+ {
+ FD_SET(sockets[i], &outreadfds);
+
+ nummatches++;
+ }
+ }
+ /* Write activity? */
+ if (writefds && FD_ISSET(sockets[i], writefds))
+ {
+ if ((resEvents.lNetworkEvents & FD_WRITE) ||
+ (resEvents.lNetworkEvents & FD_CLOSE))
+ {
+ FD_SET(sockets[i], &outwritefds);
+
+ nummatches++;
+ }
+ }
+ }
+ }
+
+ /* Clean up all the event objects */
+ for (i = 0; i < numevents; i++)
+ {
+ WSAEventSelect(sockets[i], NULL, 0);
+ WSACloseEvent(events[i]);
+ }
+
+ if (r == WSA_WAIT_TIMEOUT)
+ {
+ if (readfds)
+ FD_ZERO(readfds);
+ if (writefds)
+ FD_ZERO(writefds);
+ return 0;
+ }
+
+ /* Signal-like events. */
+ if (r == WAIT_OBJECT_0 + numevents || r == WAIT_IO_COMPLETION)
+ {
+ pgwin32_dispatch_queued_signals();
+ errno = EINTR;
+ if (readfds)
+ FD_ZERO(readfds);
+ if (writefds)
+ FD_ZERO(writefds);
+ return -1;
+ }
+
+ /* Overwrite socket sets with our resulting values */
+ if (readfds)
+ memcpy(readfds, &outreadfds, sizeof(fd_set));
+ if (writefds)
+ memcpy(writefds, &outwritefds, sizeof(fd_set));
+ return nummatches;
+}
diff --git a/contrib/libs/postgresql/src/backend/port/win32/timer.c b/contrib/libs/postgresql/src/backend/port/win32/timer.c
new file mode 100644
index 0000000000..53fdae9468
--- /dev/null
+++ b/contrib/libs/postgresql/src/backend/port/win32/timer.c
@@ -0,0 +1,121 @@
+/*-------------------------------------------------------------------------
+ *
+ * timer.c
+ * Microsoft Windows Win32 Timer Implementation
+ *
+ * Limitations of this implementation:
+ *
+ * - Does not support interval timer (value->it_interval)
+ * - Only supports ITIMER_REAL
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/port/win32/timer.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+
+/* Communication area for inter-thread communication */
+typedef struct timerCA
+{
+ struct itimerval value;
+ HANDLE event;
+ CRITICAL_SECTION crit_sec;
+} timerCA;
+
+static timerCA timerCommArea;
+static HANDLE timerThreadHandle = INVALID_HANDLE_VALUE;
+
+
+/* Timer management thread */
+static DWORD WINAPI
+pg_timer_thread(LPVOID param)
+{
+ DWORD waittime;
+
+ Assert(param == NULL);
+
+ waittime = INFINITE;
+
+ for (;;)
+ {
+ int r;
+
+ r = WaitForSingleObjectEx(timerCommArea.event, waittime, FALSE);
+ if (r == WAIT_OBJECT_0)
+ {
+ /* Event signaled from main thread, change the timer */
+ EnterCriticalSection(&timerCommArea.crit_sec);
+ if (timerCommArea.value.it_value.tv_sec == 0 &&
+ timerCommArea.value.it_value.tv_usec == 0)
+ waittime = INFINITE; /* Cancel the interrupt */
+ else
+ {
+ /* WaitForSingleObjectEx() uses milliseconds, round up */
+ waittime = (timerCommArea.value.it_value.tv_usec + 999) / 1000 +
+ timerCommArea.value.it_value.tv_sec * 1000;
+ }
+ ResetEvent(timerCommArea.event);
+ LeaveCriticalSection(&timerCommArea.crit_sec);
+ }
+ else if (r == WAIT_TIMEOUT)
+ {
+ /* Timeout expired, signal SIGALRM and turn it off */
+ pg_queue_signal(SIGALRM);
+ waittime = INFINITE;
+ }
+ else
+ {
+ /* Should never happen */
+ Assert(false);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Win32 setitimer emulation by creating a persistent thread
+ * to handle the timer setting and notification upon timeout.
+ */
+int
+setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)
+{
+ Assert(value != NULL);
+ Assert(value->it_interval.tv_sec == 0 && value->it_interval.tv_usec == 0);
+ Assert(which == ITIMER_REAL);
+
+ if (timerThreadHandle == INVALID_HANDLE_VALUE)
+ {
+ /* First call in this backend, create event and the timer thread */
+ timerCommArea.event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (timerCommArea.event == NULL)
+ ereport(FATAL,
+ (errmsg_internal("could not create timer event: error code %lu",
+ GetLastError())));
+
+ MemSet(&timerCommArea.value, 0, sizeof(struct itimerval));
+
+ InitializeCriticalSection(&timerCommArea.crit_sec);
+
+ timerThreadHandle = CreateThread(NULL, 0, pg_timer_thread, NULL, 0, NULL);
+ if (timerThreadHandle == INVALID_HANDLE_VALUE)
+ ereport(FATAL,
+ (errmsg_internal("could not create timer thread: error code %lu",
+ GetLastError())));
+ }
+
+ /* Request the timer thread to change settings */
+ EnterCriticalSection(&timerCommArea.crit_sec);
+ if (ovalue)
+ *ovalue = timerCommArea.value;
+ timerCommArea.value = *value;
+ LeaveCriticalSection(&timerCommArea.crit_sec);
+ SetEvent(timerCommArea.event);
+
+ return 0;
+}
diff --git a/contrib/libs/postgresql/src/backend/port/win32_sema.c b/contrib/libs/postgresql/src/backend/port/win32_sema.c
new file mode 100644
index 0000000000..858b88adae
--- /dev/null
+++ b/contrib/libs/postgresql/src/backend/port/win32_sema.c
@@ -0,0 +1,235 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32_sema.c
+ * Microsoft Windows Win32 Semaphores Emulation
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/port/win32_sema.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "miscadmin.h"
+#include "storage/ipc.h"
+#include "storage/pg_sema.h"
+
+static HANDLE *mySemSet; /* IDs of sema sets acquired so far */
+static int numSems; /* number of sema sets acquired so far */
+static int maxSems; /* allocated size of mySemaSet array */
+
+static void ReleaseSemaphores(int code, Datum arg);
+
+
+/*
+ * Report amount of shared memory needed for semaphores
+ */
+Size
+PGSemaphoreShmemSize(int maxSemas)
+{
+ /* No shared memory needed on Windows */
+ return 0;
+}
+
+/*
+ * PGReserveSemaphores --- initialize semaphore support
+ *
+ * In the Win32 implementation, we acquire semaphores on-demand; the
+ * maxSemas parameter is just used to size the array that keeps track of
+ * acquired semas for subsequent releasing. We use anonymous semaphores
+ * so the semaphores are automatically freed when the last referencing
+ * process exits.
+ */
+void
+PGReserveSemaphores(int maxSemas)
+{
+ mySemSet = (HANDLE *) malloc(maxSemas * sizeof(HANDLE));
+ if (mySemSet == NULL)
+ elog(PANIC, "out of memory");
+ numSems = 0;
+ maxSems = maxSemas;
+
+ on_shmem_exit(ReleaseSemaphores, 0);
+}
+
+/*
+ * Release semaphores at shutdown or shmem reinitialization
+ *
+ * (called as an on_shmem_exit callback, hence funny argument list)
+ */
+static void
+ReleaseSemaphores(int code, Datum arg)
+{
+ int i;
+
+ for (i = 0; i < numSems; i++)
+ CloseHandle(mySemSet[i]);
+ free(mySemSet);
+}
+
+/*
+ * PGSemaphoreCreate
+ *
+ * Allocate a PGSemaphore structure with initial count 1
+ */
+PGSemaphore
+PGSemaphoreCreate(void)
+{
+ HANDLE cur_handle;
+ SECURITY_ATTRIBUTES sec_attrs;
+
+ /* Can't do this in a backend, because static state is postmaster's */
+ Assert(!IsUnderPostmaster);
+
+ if (numSems >= maxSems)
+ elog(PANIC, "too many semaphores created");
+
+ ZeroMemory(&sec_attrs, sizeof(sec_attrs));
+ sec_attrs.nLength = sizeof(sec_attrs);
+ sec_attrs.lpSecurityDescriptor = NULL;
+ sec_attrs.bInheritHandle = TRUE;
+
+ /* We don't need a named semaphore */
+ cur_handle = CreateSemaphore(&sec_attrs, 1, 32767, NULL);
+ if (cur_handle)
+ {
+ /* Successfully done */
+ mySemSet[numSems++] = cur_handle;
+ }
+ else
+ ereport(PANIC,
+ (errmsg("could not create semaphore: error code %lu",
+ GetLastError())));
+
+ return (PGSemaphore) cur_handle;
+}
+
+/*
+ * PGSemaphoreReset
+ *
+ * Reset a previously-initialized PGSemaphore to have count 0
+ */
+void
+PGSemaphoreReset(PGSemaphore sema)
+{
+ /*
+ * There's no direct API for this in Win32, so we have to ratchet the
+ * semaphore down to 0 with repeated trylock's.
+ */
+ while (PGSemaphoreTryLock(sema))
+ /* loop */ ;
+}
+
+/*
+ * PGSemaphoreLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0.
+ */
+void
+PGSemaphoreLock(PGSemaphore sema)
+{
+ HANDLE wh[2];
+ bool done = false;
+
+ /*
+ * Note: pgwin32_signal_event should be first to ensure that it will be
+ * reported when multiple events are set. We want to guarantee that
+ * pending signals are serviced.
+ */
+ wh[0] = pgwin32_signal_event;
+ wh[1] = sema;
+
+ /*
+ * As in other implementations of PGSemaphoreLock, we need to check for
+ * cancel/die interrupts each time through the loop. But here, there is
+ * no hidden magic about whether the syscall will internally service a
+ * signal --- we do that ourselves.
+ */
+ while (!done)
+ {
+ DWORD rc;
+
+ CHECK_FOR_INTERRUPTS();
+
+ rc = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
+ switch (rc)
+ {
+ case WAIT_OBJECT_0:
+ /* Signal event is set - we have a signal to deliver */
+ pgwin32_dispatch_queued_signals();
+ break;
+ case WAIT_OBJECT_0 + 1:
+ /* We got it! */
+ done = true;
+ break;
+ case WAIT_IO_COMPLETION:
+
+ /*
+ * The system interrupted the wait to execute an I/O
+ * completion routine or asynchronous procedure call in this
+ * thread. PostgreSQL does not provoke either of these, but
+ * atypical loaded DLLs or even other processes might do so.
+ * Now, resume waiting.
+ */
+ break;
+ case WAIT_FAILED:
+ ereport(FATAL,
+ (errmsg("could not lock semaphore: error code %lu",
+ GetLastError())));
+ break;
+ default:
+ elog(FATAL, "unexpected return code from WaitForMultipleObjectsEx(): %lu", rc);
+ break;
+ }
+ }
+}
+
+/*
+ * PGSemaphoreUnlock
+ *
+ * Unlock a semaphore (increment count)
+ */
+void
+PGSemaphoreUnlock(PGSemaphore sema)
+{
+ if (!ReleaseSemaphore(sema, 1, NULL))
+ ereport(FATAL,
+ (errmsg("could not unlock semaphore: error code %lu",
+ GetLastError())));
+}
+
+/*
+ * PGSemaphoreTryLock
+ *
+ * Lock a semaphore only if able to do so without blocking
+ */
+bool
+PGSemaphoreTryLock(PGSemaphore sema)
+{
+ DWORD ret;
+
+ ret = WaitForSingleObject(sema, 0);
+
+ if (ret == WAIT_OBJECT_0)
+ {
+ /* We got it! */
+ return true;
+ }
+ else if (ret == WAIT_TIMEOUT)
+ {
+ /* Can't get it */
+ errno = EAGAIN;
+ return false;
+ }
+
+ /* Otherwise we are in trouble */
+ ereport(FATAL,
+ (errmsg("could not try-lock semaphore: error code %lu",
+ GetLastError())));
+
+ /* keep compiler quiet */
+ return false;
+}
diff --git a/contrib/libs/postgresql/src/backend/port/win32_shmem.c b/contrib/libs/postgresql/src/backend/port/win32_shmem.c
new file mode 100644
index 0000000000..d7a71992d8
--- /dev/null
+++ b/contrib/libs/postgresql/src/backend/port/win32_shmem.c
@@ -0,0 +1,607 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32_shmem.c
+ * Implement shared memory using win32 facilities
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/port/win32_shmem.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "miscadmin.h"
+#include "storage/dsm.h"
+#include "storage/ipc.h"
+#include "storage/pg_shmem.h"
+
+/*
+ * Early in a process's life, Windows asynchronously creates threads for the
+ * process's "default thread pool"
+ * (https://docs.microsoft.com/en-us/windows/desktop/ProcThread/thread-pools).
+ * Occasionally, thread creation allocates a stack after
+ * PGSharedMemoryReAttach() has released UsedShmemSegAddr and before it has
+ * mapped shared memory at UsedShmemSegAddr. This would cause mapping to fail
+ * if the allocator preferred the just-released region for allocating the new
+ * thread stack. We observed such failures in some Windows Server 2016
+ * configurations. To give the system another region to prefer, reserve and
+ * release an additional, protective region immediately before reserving or
+ * releasing shared memory. The idea is that, if the allocator handed out
+ * REGION1 pages before REGION2 pages at one occasion, it will do so whenever
+ * both regions are free. Windows Server 2016 exhibits that behavior, and a
+ * system behaving differently would have less need to protect
+ * UsedShmemSegAddr. The protective region must be at least large enough for
+ * one thread stack. However, ten times as much is less than 2% of the 32-bit
+ * address space and is negligible relative to the 64-bit address space.
+ */
+#define PROTECTIVE_REGION_SIZE (10 * WIN32_STACK_RLIMIT)
+void *ShmemProtectiveRegion = NULL;
+
+HANDLE UsedShmemSegID = INVALID_HANDLE_VALUE;
+void *UsedShmemSegAddr = NULL;
+static Size UsedShmemSegSize = 0;
+
+static bool EnableLockPagesPrivilege(int elevel);
+static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
+
+/*
+ * Generate shared memory segment name. Expand the data directory, to generate
+ * an identifier unique for this data directory. Then replace all backslashes
+ * with forward slashes, since backslashes aren't permitted in global object names.
+ *
+ * Store the shared memory segment in the Global\ namespace (requires NT2 TSE or
+ * 2000, but that's all we support for other reasons as well), to make sure you can't
+ * open two postmasters in different sessions against the same data directory.
+ *
+ * XXX: What happens with junctions? It's only someone breaking things on purpose,
+ * and this is still better than before, but we might want to do something about
+ * that sometime in the future.
+ */
+static char *
+GetSharedMemName(void)
+{
+ char *retptr;
+ DWORD bufsize;
+ DWORD r;
+ char *cp;
+
+ bufsize = GetFullPathName(DataDir, 0, NULL, NULL);
+ if (bufsize == 0)
+ elog(FATAL, "could not get size for full pathname of datadir %s: error code %lu",
+ DataDir, GetLastError());
+
+ retptr = malloc(bufsize + 18); /* 18 for Global\PostgreSQL: */
+ if (retptr == NULL)
+ elog(FATAL, "could not allocate memory for shared memory name");
+
+ strcpy(retptr, "Global\\PostgreSQL:");
+ r = GetFullPathName(DataDir, bufsize, retptr + 18, NULL);
+ if (r == 0 || r > bufsize)
+ elog(FATAL, "could not generate full pathname for datadir %s: error code %lu",
+ DataDir, GetLastError());
+
+ /*
+ * XXX: Intentionally overwriting the Global\ part here. This was not the
+ * original approach, but putting it in the actual Global\ namespace
+ * causes permission errors in a lot of cases, so we leave it in the
+ * default namespace for now.
+ */
+ for (cp = retptr; *cp; cp++)
+ if (*cp == '\\')
+ *cp = '/';
+
+ return retptr;
+}
+
+
+/*
+ * PGSharedMemoryIsInUse
+ *
+ * Is a previously-existing shmem segment still existing and in use?
+ *
+ * The point of this exercise is to detect the case where a prior postmaster
+ * crashed, but it left child backends that are still running. Therefore
+ * we only care about shmem segments that are associated with the intended
+ * DataDir. This is an important consideration since accidental matches of
+ * shmem segment IDs are reasonably common.
+ */
+bool
+PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
+{
+ char *szShareMem;
+ HANDLE hmap;
+
+ szShareMem = GetSharedMemName();
+
+ hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem);
+
+ free(szShareMem);
+
+ if (hmap == NULL)
+ return false;
+
+ CloseHandle(hmap);
+ return true;
+}
+
+/*
+ * EnableLockPagesPrivilege
+ *
+ * Try to acquire SeLockMemoryPrivilege so we can use large pages.
+ */
+static bool
+EnableLockPagesPrivilege(int elevel)
+{
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tp;
+ LUID luid;
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ {
+ ereport(elevel,
+ (errmsg("could not enable user right \"%s\": error code %lu",
+
+ /*
+ * translator: This is a term from Windows and should be translated to
+ * match the Windows localization.
+ */
+ _("Lock pages in memory"),
+ GetLastError()),
+ errdetail("Failed system call was %s.", "OpenProcessToken")));
+ return FALSE;
+ }
+
+ if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
+ {
+ ereport(elevel,
+ (errmsg("could not enable user right \"%s\": error code %lu", _("Lock pages in memory"), GetLastError()),
+ errdetail("Failed system call was %s.", "LookupPrivilegeValue")));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
+ {
+ ereport(elevel,
+ (errmsg("could not enable user right \"%s\": error code %lu", _("Lock pages in memory"), GetLastError()),
+ errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ if (GetLastError() != ERROR_SUCCESS)
+ {
+ if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
+ ereport(elevel,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("could not enable user right \"%s\"", _("Lock pages in memory")),
+ errhint("Assign user right \"%s\" to the Windows user account which runs PostgreSQL.",
+ _("Lock pages in memory"))));
+ else
+ ereport(elevel,
+ (errmsg("could not enable user right \"%s\": error code %lu", _("Lock pages in memory"), GetLastError()),
+ errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ CloseHandle(hToken);
+
+ return TRUE;
+}
+
+/*
+ * PGSharedMemoryCreate
+ *
+ * Create a shared memory segment of the given size and initialize its
+ * standard header.
+ */
+PGShmemHeader *
+PGSharedMemoryCreate(Size size,
+ PGShmemHeader **shim)
+{
+ void *memAddress;
+ PGShmemHeader *hdr;
+ HANDLE hmap,
+ hmap2;
+ char *szShareMem;
+ int i;
+ DWORD size_high;
+ DWORD size_low;
+ SIZE_T largePageSize = 0;
+ Size orig_size = size;
+ DWORD flProtect = PAGE_READWRITE;
+
+ ShmemProtectiveRegion = VirtualAlloc(NULL, PROTECTIVE_REGION_SIZE,
+ MEM_RESERVE, PAGE_NOACCESS);
+ if (ShmemProtectiveRegion == NULL)
+ elog(FATAL, "could not reserve memory region: error code %lu",
+ GetLastError());
+
+ /* Room for a header? */
+ Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
+
+ szShareMem = GetSharedMemName();
+
+ UsedShmemSegAddr = NULL;
+
+ if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY)
+ {
+ /* Does the processor support large pages? */
+ largePageSize = GetLargePageMinimum();
+ if (largePageSize == 0)
+ {
+ ereport(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("the processor does not support large pages")));
+ ereport(DEBUG1,
+ (errmsg_internal("disabling huge pages")));
+ }
+ else if (!EnableLockPagesPrivilege(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1))
+ {
+ ereport(DEBUG1,
+ (errmsg_internal("disabling huge pages")));
+ }
+ else
+ {
+ /* Huge pages available and privilege enabled, so turn on */
+ flProtect = PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES;
+
+ /* Round size up as appropriate. */
+ if (size % largePageSize != 0)
+ size += largePageSize - (size % largePageSize);
+ }
+ }
+
+retry:
+#ifdef _WIN64
+ size_high = size >> 32;
+#else
+ size_high = 0;
+#endif
+ size_low = (DWORD) size;
+
+ /*
+ * When recycling a shared memory segment, it may take a short while
+ * before it gets dropped from the global namespace. So re-try after
+ * sleeping for a second, and continue retrying 10 times. (both the 1
+ * second time and the 10 retries are completely arbitrary)
+ */
+ for (i = 0; i < 10; i++)
+ {
+ /*
+ * In case CreateFileMapping() doesn't set the error code to 0 on
+ * success
+ */
+ SetLastError(0);
+
+ hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */
+ NULL, /* Default security attrs */
+ flProtect,
+ size_high, /* Size Upper 32 Bits */
+ size_low, /* Size Lower 32 bits */
+ szShareMem);
+
+ if (!hmap)
+ {
+ if (GetLastError() == ERROR_NO_SYSTEM_RESOURCES &&
+ huge_pages == HUGE_PAGES_TRY &&
+ (flProtect & SEC_LARGE_PAGES) != 0)
+ {
+ elog(DEBUG1, "CreateFileMapping(%zu) with SEC_LARGE_PAGES failed, "
+ "huge pages disabled",
+ size);
+
+ /*
+ * Use the original size, not the rounded-up value, when
+ * falling back to non-huge pages.
+ */
+ size = orig_size;
+ flProtect = PAGE_READWRITE;
+ goto retry;
+ }
+ else
+ ereport(FATAL,
+ (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
+ errdetail("Failed system call was CreateFileMapping(size=%zu, name=%s).",
+ size, szShareMem)));
+ }
+
+ /*
+ * If the segment already existed, CreateFileMapping() will return a
+ * handle to the existing one and set ERROR_ALREADY_EXISTS.
+ */
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ CloseHandle(hmap); /* Close the handle, since we got a valid one
+ * to the previous segment. */
+ hmap = NULL;
+ Sleep(1000);
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * If the last call in the loop still returned ERROR_ALREADY_EXISTS, this
+ * shared memory segment exists and we assume it belongs to somebody else.
+ */
+ if (!hmap)
+ ereport(FATAL,
+ (errmsg("pre-existing shared memory block is still in use"),
+ errhint("Check if there are any old server processes still running, and terminate them.")));
+
+ free(szShareMem);
+
+ /*
+ * Make the handle inheritable
+ */
+ if (!DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, TRUE, DUPLICATE_SAME_ACCESS))
+ ereport(FATAL,
+ (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
+ errdetail("Failed system call was DuplicateHandle.")));
+
+ /*
+ * Close the old, non-inheritable handle. If this fails we don't really
+ * care.
+ */
+ if (!CloseHandle(hmap))
+ elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
+
+
+ /*
+ * Get a pointer to the new shared memory segment. Map the whole segment
+ * at once, and let the system decide on the initial address.
+ */
+ memAddress = MapViewOfFileEx(hmap2, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, NULL);
+ if (!memAddress)
+ ereport(FATAL,
+ (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
+ errdetail("Failed system call was MapViewOfFileEx.")));
+
+
+
+ /*
+ * OK, we created a new segment. Mark it as created by this process. The
+ * order of assignments here is critical so that another Postgres process
+ * can't see the header as valid but belonging to an invalid PID!
+ */
+ hdr = (PGShmemHeader *) memAddress;
+ hdr->creatorPID = getpid();
+ hdr->magic = PGShmemMagic;
+
+ /*
+ * Initialize space allocation status for segment.
+ */
+ hdr->totalsize = size;
+ hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
+ hdr->dsm_control = 0;
+
+ /* Save info for possible future use */
+ UsedShmemSegAddr = memAddress;
+ UsedShmemSegSize = size;
+ UsedShmemSegID = hmap2;
+
+ /* Register on-exit routine to delete the new segment */
+ on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));
+
+ *shim = hdr;
+ return hdr;
+}
+
+/*
+ * PGSharedMemoryReAttach
+ *
+ * This is called during startup of a postmaster child process to re-attach to
+ * an already existing shared memory segment, using the handle inherited from
+ * the postmaster.
+ *
+ * ShmemProtectiveRegion, UsedShmemSegID and UsedShmemSegAddr are implicit
+ * parameters to this routine. The caller must have already restored them to
+ * the postmaster's values.
+ */
+void
+PGSharedMemoryReAttach(void)
+{
+ PGShmemHeader *hdr;
+ void *origUsedShmemSegAddr = UsedShmemSegAddr;
+
+ Assert(ShmemProtectiveRegion != NULL);
+ Assert(UsedShmemSegAddr != NULL);
+ Assert(IsUnderPostmaster);
+
+ /*
+ * Release memory region reservations made by the postmaster
+ */
+ if (VirtualFree(ShmemProtectiveRegion, 0, MEM_RELEASE) == 0)
+ elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
+ ShmemProtectiveRegion, GetLastError());
+ if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0)
+ elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
+ UsedShmemSegAddr, GetLastError());
+
+ hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
+ if (!hdr)
+ elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
+ UsedShmemSegID, UsedShmemSegAddr, GetLastError());
+ if (hdr != origUsedShmemSegAddr)
+ elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
+ hdr, origUsedShmemSegAddr);
+ if (hdr->magic != PGShmemMagic)
+ elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
+ dsm_set_control_handle(hdr->dsm_control);
+
+ UsedShmemSegAddr = hdr; /* probably redundant */
+}
+
+/*
+ * PGSharedMemoryNoReAttach
+ *
+ * This is called during startup of a postmaster child process when we choose
+ * *not* to re-attach to the existing shared memory segment. We must clean up
+ * to leave things in the appropriate state.
+ *
+ * The child process startup logic might or might not call PGSharedMemoryDetach
+ * after this; make sure that it will be a no-op if called.
+ *
+ * ShmemProtectiveRegion, UsedShmemSegID and UsedShmemSegAddr are implicit
+ * parameters to this routine. The caller must have already restored them to
+ * the postmaster's values.
+ */
+void
+PGSharedMemoryNoReAttach(void)
+{
+ Assert(ShmemProtectiveRegion != NULL);
+ Assert(UsedShmemSegAddr != NULL);
+ Assert(IsUnderPostmaster);
+
+ /*
+ * Under Windows we will not have mapped the segment, so we don't need to
+ * un-map it. Just reset UsedShmemSegAddr to show we're not attached.
+ */
+ UsedShmemSegAddr = NULL;
+
+ /*
+ * We *must* close the inherited shmem segment handle, else Windows will
+ * consider the existence of this process to mean it can't release the
+ * shmem segment yet. We can now use PGSharedMemoryDetach to do that.
+ */
+ PGSharedMemoryDetach();
+}
+
+/*
+ * PGSharedMemoryDetach
+ *
+ * Detach from the shared memory segment, if still attached. This is not
+ * intended to be called explicitly by the process that originally created the
+ * segment (it will have an on_shmem_exit callback registered to do that).
+ * Rather, this is for subprocesses that have inherited an attachment and want
+ * to get rid of it.
+ *
+ * ShmemProtectiveRegion, UsedShmemSegID and UsedShmemSegAddr are implicit
+ * parameters to this routine.
+ */
+void
+PGSharedMemoryDetach(void)
+{
+ /*
+ * Releasing the protective region liberates an unimportant quantity of
+ * address space, but be tidy.
+ */
+ if (ShmemProtectiveRegion != NULL)
+ {
+ if (VirtualFree(ShmemProtectiveRegion, 0, MEM_RELEASE) == 0)
+ elog(LOG, "failed to release reserved memory region (addr=%p): error code %lu",
+ ShmemProtectiveRegion, GetLastError());
+
+ ShmemProtectiveRegion = NULL;
+ }
+
+ /* Unmap the view, if it's mapped */
+ if (UsedShmemSegAddr != NULL)
+ {
+ if (!UnmapViewOfFile(UsedShmemSegAddr))
+ elog(LOG, "could not unmap view of shared memory: error code %lu",
+ GetLastError());
+
+ UsedShmemSegAddr = NULL;
+ }
+
+ /* And close the shmem handle, if we have one */
+ if (UsedShmemSegID != INVALID_HANDLE_VALUE)
+ {
+ if (!CloseHandle(UsedShmemSegID))
+ elog(LOG, "could not close handle to shared memory: error code %lu",
+ GetLastError());
+
+ UsedShmemSegID = INVALID_HANDLE_VALUE;
+ }
+}
+
+
+/*
+ * pgwin32_SharedMemoryDelete
+ *
+ * Detach from and delete the shared memory segment
+ * (called as an on_shmem_exit callback, hence funny argument list)
+ */
+static void
+pgwin32_SharedMemoryDelete(int status, Datum shmId)
+{
+ Assert(DatumGetPointer(shmId) == UsedShmemSegID);
+ PGSharedMemoryDetach();
+}
+
+/*
+ * pgwin32_ReserveSharedMemoryRegion(hChild)
+ *
+ * Reserve the memory region that will be used for shared memory in a child
+ * process. It is called before the child process starts, to make sure the
+ * memory is available.
+ *
+ * Once the child starts, DLLs loading in different order or threads getting
+ * scheduled differently may allocate memory which can conflict with the
+ * address space we need for our shared memory. By reserving the shared
+ * memory region before the child starts, and freeing it only just before we
+ * attempt to get access to the shared memory forces these allocations to
+ * be given different address ranges that don't conflict.
+ *
+ * NOTE! This function executes in the postmaster, and should for this
+ * reason not use elog(FATAL) since that would take down the postmaster.
+ */
+int
+pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
+{
+ void *address;
+
+ Assert(ShmemProtectiveRegion != NULL);
+ Assert(UsedShmemSegAddr != NULL);
+ Assert(UsedShmemSegSize != 0);
+
+ /* ShmemProtectiveRegion */
+ address = VirtualAllocEx(hChild, ShmemProtectiveRegion,
+ PROTECTIVE_REGION_SIZE,
+ MEM_RESERVE, PAGE_NOACCESS);
+ if (address == NULL)
+ {
+ /* Don't use FATAL since we're running in the postmaster */
+ elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
+ ShmemProtectiveRegion, hChild, GetLastError());
+ return false;
+ }
+ if (address != ShmemProtectiveRegion)
+ {
+ /*
+ * Should never happen - in theory if allocation granularity causes
+ * strange effects it could, so check just in case.
+ *
+ * Don't use FATAL since we're running in the postmaster.
+ */
+ elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
+ address, ShmemProtectiveRegion);
+ return false;
+ }
+
+ /* UsedShmemSegAddr */
+ address = VirtualAllocEx(hChild, UsedShmemSegAddr, UsedShmemSegSize,
+ MEM_RESERVE, PAGE_READWRITE);
+ if (address == NULL)
+ {
+ elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
+ UsedShmemSegAddr, hChild, GetLastError());
+ return false;
+ }
+ if (address != UsedShmemSegAddr)
+ {
+ elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
+ address, UsedShmemSegAddr);
+ return false;
+ }
+
+ return true;
+}
diff --git a/contrib/libs/postgresql/src/include/port/win32/arpa/inet.h b/contrib/libs/postgresql/src/include/port/win32/arpa/inet.h
new file mode 100644
index 0000000000..ad1803179c
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/arpa/inet.h
@@ -0,0 +1,3 @@
+/* src/include/port/win32/arpa/inet.h */
+
+#include <sys/socket.h>
diff --git a/contrib/libs/postgresql/src/include/port/win32/grp.h b/contrib/libs/postgresql/src/include/port/win32/grp.h
new file mode 100644
index 0000000000..8b4f21310e
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/grp.h
@@ -0,0 +1 @@
+/* src/include/port/win32/grp.h */
diff --git a/contrib/libs/postgresql/src/include/port/win32/netdb.h b/contrib/libs/postgresql/src/include/port/win32/netdb.h
new file mode 100644
index 0000000000..ad0627e986
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/netdb.h
@@ -0,0 +1 @@
+/* src/include/port/win32/netdb.h */
diff --git a/contrib/libs/postgresql/src/include/port/win32/netinet/in.h b/contrib/libs/postgresql/src/include/port/win32/netinet/in.h
new file mode 100644
index 0000000000..a4e22f89f4
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/netinet/in.h
@@ -0,0 +1,3 @@
+/* src/include/port/win32/netinet/in.h */
+
+#include <sys/socket.h>
diff --git a/contrib/libs/postgresql/src/include/port/win32/pwd.h b/contrib/libs/postgresql/src/include/port/win32/pwd.h
new file mode 100644
index 0000000000..b8c7178fc0
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/pwd.h
@@ -0,0 +1,3 @@
+/*
+ * src/include/port/win32/pwd.h
+ */
diff --git a/contrib/libs/postgresql/src/include/port/win32/sys/socket.h b/contrib/libs/postgresql/src/include/port/win32/sys/socket.h
new file mode 100644
index 0000000000..9b2cdf3b9b
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/sys/socket.h
@@ -0,0 +1,33 @@
+/*
+ * src/include/port/win32/sys/socket.h
+ */
+#ifndef WIN32_SYS_SOCKET_H
+#define WIN32_SYS_SOCKET_H
+
+/*
+ * Unfortunately, <wingdi.h> of VC++ also defines ERROR.
+ * To avoid the conflict, we include <windows.h> here and undefine ERROR
+ * immediately.
+ *
+ * Note: Don't include <wingdi.h> directly. It causes compile errors.
+ */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#undef ERROR
+#undef small
+
+/* Restore old ERROR value */
+#ifdef PGERROR
+#define ERROR PGERROR
+#endif
+
+/*
+ * we can't use the windows gai_strerror{AW} functions because
+ * they are defined inline in the MS header files. So we'll use our
+ * own
+ */
+#undef gai_strerror
+
+#endif /* WIN32_SYS_SOCKET_H */
diff --git a/contrib/libs/postgresql/src/include/port/win32/sys/wait.h b/contrib/libs/postgresql/src/include/port/win32/sys/wait.h
new file mode 100644
index 0000000000..eaeb5661c9
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32/sys/wait.h
@@ -0,0 +1,3 @@
+/*
+ * src/include/port/win32/sys/wait.h
+ */
diff --git a/contrib/libs/postgresql/src/include/port/win32_msvc/dirent.h b/contrib/libs/postgresql/src/include/port/win32_msvc/dirent.h
new file mode 100644
index 0000000000..62799db001
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32_msvc/dirent.h
@@ -0,0 +1,34 @@
+/*
+ * Headers for port/dirent.c, win32 native implementation of dirent functions
+ *
+ * src/include/port/win32_msvc/dirent.h
+ */
+
+#ifndef _WIN32VC_DIRENT_H
+#define _WIN32VC_DIRENT_H
+struct dirent
+{
+ long d_ino;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ unsigned short d_namlen;
+ char d_name[MAX_PATH];
+};
+
+typedef struct DIR DIR;
+
+DIR *opendir(const char *);
+struct dirent *readdir(DIR *);
+int closedir(DIR *);
+
+/* File types for 'd_type'. */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+#endif
diff --git a/contrib/libs/postgresql/src/include/port/win32_msvc/sys/file.h b/contrib/libs/postgresql/src/include/port/win32_msvc/sys/file.h
new file mode 100644
index 0000000000..76be3e7774
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32_msvc/sys/file.h
@@ -0,0 +1 @@
+/* src/include/port/win32_msvc/sys/file.h */
diff --git a/contrib/libs/postgresql/src/include/port/win32_msvc/sys/param.h b/contrib/libs/postgresql/src/include/port/win32_msvc/sys/param.h
new file mode 100644
index 0000000000..160df3b25e
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32_msvc/sys/param.h
@@ -0,0 +1 @@
+/* src/include/port/win32_msvc/sys/param.h */
diff --git a/contrib/libs/postgresql/src/include/port/win32_msvc/sys/time.h b/contrib/libs/postgresql/src/include/port/win32_msvc/sys/time.h
new file mode 100644
index 0000000000..9d943ecc6f
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32_msvc/sys/time.h
@@ -0,0 +1 @@
+/* src/include/port/win32_msvc/sys/time.h */
diff --git a/contrib/libs/postgresql/src/include/port/win32_msvc/unistd.h b/contrib/libs/postgresql/src/include/port/win32_msvc/unistd.h
new file mode 100644
index 0000000000..b63f4770a1
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32_msvc/unistd.h
@@ -0,0 +1 @@
+/* src/include/port/win32_msvc/unistd.h */
diff --git a/contrib/libs/postgresql/src/include/port/win32_msvc/utime.h b/contrib/libs/postgresql/src/include/port/win32_msvc/utime.h
new file mode 100644
index 0000000000..c78e79c33d
--- /dev/null
+++ b/contrib/libs/postgresql/src/include/port/win32_msvc/utime.h
@@ -0,0 +1,3 @@
+/* src/include/port/win32_msvc/utime.h */
+
+#include <sys/utime.h> /* for non-unicode version */
diff --git a/contrib/libs/postgresql/src/port/dirmod.c b/contrib/libs/postgresql/src/port/dirmod.c
new file mode 100644
index 0000000000..46c9c235c8
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/dirmod.c
@@ -0,0 +1,355 @@
+/*-------------------------------------------------------------------------
+ *
+ * dirmod.c
+ * directory handling functions
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * This includes replacement versions of functions that work on
+ * Win32 (NT4 and newer).
+ *
+ * IDENTIFICATION
+ * src/port/dirmod.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+/* Don't modify declarations in system headers */
+#if defined(WIN32) || defined(__CYGWIN__)
+#undef rename
+#undef unlink
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if defined(WIN32) || defined(__CYGWIN__)
+#ifndef __CYGWIN__
+#include <winioctl.h>
+#else
+#include <windows.h>
+#error #include <w32api/winioctl.h>
+#endif
+#endif
+
+#if defined(WIN32) || defined(__CYGWIN__)
+
+/*
+ * pgrename
+ */
+int
+pgrename(const char *from, const char *to)
+{
+ int loops = 0;
+
+ /*
+ * We need to loop because even though PostgreSQL uses flags that allow
+ * rename while the file is open, other applications might have the file
+ * open without those flags. However, we won't wait indefinitely for
+ * someone else to close the file, as the caller might be holding locks
+ * and blocking other backends.
+ */
+#if defined(WIN32) && !defined(__CYGWIN__)
+ while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
+#else
+ while (rename(from, to) < 0)
+#endif
+ {
+#if defined(WIN32) && !defined(__CYGWIN__)
+ DWORD err = GetLastError();
+
+ _dosmaperr(err);
+
+ /*
+ * Modern NT-based Windows versions return ERROR_SHARING_VIOLATION if
+ * another process has the file open without FILE_SHARE_DELETE.
+ * ERROR_LOCK_VIOLATION has also been seen with some anti-virus
+ * software. This used to check for just ERROR_ACCESS_DENIED, so
+ * presumably you can get that too with some OS versions. We don't
+ * expect real permission errors where we currently use rename().
+ */
+ if (err != ERROR_ACCESS_DENIED &&
+ err != ERROR_SHARING_VIOLATION &&
+ err != ERROR_LOCK_VIOLATION)
+ return -1;
+#else
+ if (errno != EACCES)
+ return -1;
+#endif
+
+ if (++loops > 100) /* time out after 10 sec */
+ return -1;
+ pg_usleep(100000); /* us */
+ }
+ return 0;
+}
+
+
+/*
+ * pgunlink
+ */
+int
+pgunlink(const char *path)
+{
+ int loops = 0;
+
+ /*
+ * We need to loop because even though PostgreSQL uses flags that allow
+ * unlink while the file is open, other applications might have the file
+ * open without those flags. However, we won't wait indefinitely for
+ * someone else to close the file, as the caller might be holding locks
+ * and blocking other backends.
+ */
+ while (unlink(path))
+ {
+ if (errno != EACCES)
+ return -1;
+ if (++loops > 100) /* time out after 10 sec */
+ return -1;
+ pg_usleep(100000); /* us */
+ }
+ return 0;
+}
+
+/* We undefined these above; now redefine for possible use below */
+#define rename(from, to) pgrename(from, to)
+#define unlink(path) pgunlink(path)
+#endif /* defined(WIN32) || defined(__CYGWIN__) */
+
+
+#if defined(WIN32) && !defined(__CYGWIN__) /* Cygwin has its own symlinks */
+
+/*
+ * pgsymlink support:
+ *
+ * This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h
+ * but omitted in later SDK functions.
+ * We only need the SymbolicLinkReparseBuffer part of the original struct's union.
+ */
+typedef struct
+{
+ DWORD ReparseTag;
+ WORD ReparseDataLength;
+ WORD Reserved;
+ /* SymbolicLinkReparseBuffer */
+ WORD SubstituteNameOffset;
+ WORD SubstituteNameLength;
+ WORD PrintNameOffset;
+ WORD PrintNameLength;
+ WCHAR PathBuffer[FLEXIBLE_ARRAY_MEMBER];
+} REPARSE_JUNCTION_DATA_BUFFER;
+
+#define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \
+ FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
+
+
+/*
+ * pgsymlink - uses Win32 junction points
+ *
+ * For reference: http://www.codeproject.com/KB/winsdk/junctionpoints.aspx
+ */
+int
+pgsymlink(const char *oldpath, const char *newpath)
+{
+ HANDLE dirhandle;
+ DWORD len;
+ char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
+ char nativeTarget[MAX_PATH];
+ char *p = nativeTarget;
+ REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
+
+ CreateDirectory(newpath, 0);
+ dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
+ 0, 0, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
+
+ if (dirhandle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ /* make sure we have an unparsed native win32 path */
+ if (memcmp("\\??\\", oldpath, 4) != 0)
+ snprintf(nativeTarget, sizeof(nativeTarget), "\\??\\%s", oldpath);
+ else
+ strlcpy(nativeTarget, oldpath, sizeof(nativeTarget));
+
+ while ((p = strchr(p, '/')) != NULL)
+ *p++ = '\\';
+
+ len = strlen(nativeTarget) * sizeof(WCHAR);
+ reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ reparseBuf->ReparseDataLength = len + 12;
+ reparseBuf->Reserved = 0;
+ reparseBuf->SubstituteNameOffset = 0;
+ reparseBuf->SubstituteNameLength = len;
+ reparseBuf->PrintNameOffset = len + sizeof(WCHAR);
+ reparseBuf->PrintNameLength = 0;
+ MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
+ reparseBuf->PathBuffer, MAX_PATH);
+
+ /*
+ * FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version;
+ * we use our own definition
+ */
+ if (!DeviceIoControl(dirhandle,
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
+ reparseBuf,
+ reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
+ 0, 0, &len, 0))
+ {
+ LPSTR msg;
+
+ errno = 0;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(),
+ MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+ (LPSTR) &msg, 0, NULL);
+#ifndef FRONTEND
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not set junction for \"%s\": %s",
+ nativeTarget, msg)));
+#else
+ fprintf(stderr, _("could not set junction for \"%s\": %s\n"),
+ nativeTarget, msg);
+#endif
+ LocalFree(msg);
+
+ CloseHandle(dirhandle);
+ RemoveDirectory(newpath);
+ return -1;
+ }
+
+ CloseHandle(dirhandle);
+
+ return 0;
+}
+
+/*
+ * pgreadlink - uses Win32 junction points
+ */
+int
+pgreadlink(const char *path, char *buf, size_t size)
+{
+ DWORD attr;
+ HANDLE h;
+ char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
+ REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
+ DWORD len;
+ int r;
+
+ attr = GetFileAttributes(path);
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+ if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ h = CreateFile(path,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ 0);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ if (!DeviceIoControl(h,
+ FSCTL_GET_REPARSE_POINT,
+ NULL,
+ 0,
+ (LPVOID) reparseBuf,
+ sizeof(buffer),
+ &len,
+ NULL))
+ {
+ LPSTR msg;
+
+ errno = 0;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(),
+ MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+ (LPSTR) &msg, 0, NULL);
+#ifndef FRONTEND
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not get junction for \"%s\": %s",
+ path, msg)));
+#else
+ fprintf(stderr, _("could not get junction for \"%s\": %s\n"),
+ path, msg);
+#endif
+ LocalFree(msg);
+ CloseHandle(h);
+ errno = EINVAL;
+ return -1;
+ }
+ CloseHandle(h);
+
+ /* Got it, let's get some results from this */
+ if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ r = WideCharToMultiByte(CP_ACP, 0,
+ reparseBuf->PathBuffer, -1,
+ buf,
+ size,
+ NULL, NULL);
+
+ if (r <= 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * If the path starts with "\??\", which it will do in most (all?) cases,
+ * strip those out.
+ */
+ if (r > 4 && strncmp(buf, "\\??\\", 4) == 0)
+ {
+ memmove(buf, buf + 4, strlen(buf + 4) + 1);
+ r -= 4;
+ }
+ return r;
+}
+
+/*
+ * Assumes the file exists, so will return false if it doesn't
+ * (since a nonexistent file is not a junction)
+ */
+bool
+pgwin32_is_junction(const char *path)
+{
+ DWORD attr = GetFileAttributes(path);
+
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ {
+ _dosmaperr(GetLastError());
+ return false;
+ }
+ return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
+}
+#endif /* defined(WIN32) && !defined(__CYGWIN__) */
diff --git a/contrib/libs/postgresql/src/port/dlopen.c b/contrib/libs/postgresql/src/port/dlopen.c
new file mode 100644
index 0000000000..f7948b861f
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/dlopen.c
@@ -0,0 +1,145 @@
+/*-------------------------------------------------------------------------
+ *
+ * dlopen.c
+ * dynamic loader for platforms without dlopen()
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/dlopen.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#if defined(__hpux)
+
+/* System includes */
+#include <a.out.h>
+#include <dl.h>
+
+void *
+dlopen(const char *file, int mode)
+{
+ int flags = 0;
+
+ if (mode & RTLD_NOW)
+ flags |= BIND_IMMEDIATE;
+#ifdef NOT_USED
+ if (mode & RTLD_LAZY)
+ flags |= BIND_DEFERRED;
+#endif
+
+ return shl_load(file, flags | BIND_VERBOSE, 0L);
+}
+
+void *
+dlsym(void *handle, const char *symbol)
+{
+ void *value;
+
+ if (shl_findsym((shl_t *) & handle, symbol, TYPE_PROCEDURE, &value) == -1)
+ return NULL;
+ return value;
+}
+
+int
+dlclose(void *handle)
+{
+ return shl_unload((shl_t) handle);
+}
+
+char *
+dlerror(void)
+{
+ static char errmsg[] = "shl_load failed";
+
+ if (errno)
+ return strerror(errno);
+
+ return errmsg;
+}
+
+#elif defined(WIN32)
+
+static char last_dyn_error[512];
+
+static void
+set_dl_error(void)
+{
+ DWORD err = GetLastError();
+
+ if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+ last_dyn_error,
+ sizeof(last_dyn_error) - 1,
+ NULL) == 0)
+ {
+ snprintf(last_dyn_error, sizeof(last_dyn_error) - 1,
+ "unknown error %lu", err);
+ }
+}
+
+char *
+dlerror(void)
+{
+ if (last_dyn_error[0])
+ return last_dyn_error;
+ else
+ return NULL;
+}
+
+int
+dlclose(void *handle)
+{
+ if (!FreeLibrary((HMODULE) handle))
+ {
+ set_dl_error();
+ return 1;
+ }
+ last_dyn_error[0] = 0;
+ return 0;
+}
+
+void *
+dlsym(void *handle, const char *symbol)
+{
+ void *ptr;
+
+ ptr = GetProcAddress((HMODULE) handle, symbol);
+ if (!ptr)
+ {
+ set_dl_error();
+ return NULL;
+ }
+ last_dyn_error[0] = 0;
+ return ptr;
+}
+
+void *
+dlopen(const char *file, int mode)
+{
+ HMODULE h;
+ int prevmode;
+
+ /* Disable popup error messages when loading DLLs */
+ prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ h = LoadLibrary(file);
+ SetErrorMode(prevmode);
+
+ if (!h)
+ {
+ set_dl_error();
+ return NULL;
+ }
+ last_dyn_error[0] = 0;
+ return (void *) h;
+}
+
+#endif
diff --git a/contrib/libs/postgresql/src/port/getaddrinfo.c b/contrib/libs/postgresql/src/port/getaddrinfo.c
new file mode 100644
index 0000000000..bb194da529
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/getaddrinfo.c
@@ -0,0 +1,396 @@
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.c
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * We also supply getnameinfo() here, assuming that the platform will have
+ * it if and only if it has getaddrinfo(). If this proves false on some
+ * platform, we'll need to split this file and provide a separate configure
+ * test for getnameinfo().
+ *
+ * Windows may or may not have these routines, so we handle Windows specially
+ * by dynamically checking for their existence. If they already exist, we
+ * use the Windows native routines, but if not, we use our own.
+ *
+ *
+ * Copyright (c) 2003-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/getaddrinfo.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* This is intended to be used in both frontend and backend, so use c.h */
+#include "c.h"
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "getaddrinfo.h"
+#include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */
+#include "port/pg_bswap.h"
+
+
+#ifdef WIN32
+/*
+ * The native routines may or may not exist on the Windows platform we are on,
+ * so we dynamically look up the routines, and call them via function pointers.
+ * Here we need to declare what the function pointers look like
+ */
+typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res);
+
+typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo *ai);
+
+typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr *sa,
+ int salen,
+ char *node, int nodelen,
+ char *service, int servicelen,
+ int flags);
+
+/* static pointers to the native routines, so we only do the lookup once. */
+static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
+static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
+static getnameinfo_ptr_t getnameinfo_ptr = NULL;
+
+
+static bool
+haveNativeWindowsIPv6routines(void)
+{
+ void *hLibrary = NULL;
+ static bool alreadyLookedForIpv6routines = false;
+
+ if (alreadyLookedForIpv6routines)
+ return (getaddrinfo_ptr != NULL);
+
+ /*
+ * For Windows XP and later versions, the IPv6 routines are present in the
+ * WinSock 2 library (ws2_32.dll).
+ */
+ hLibrary = LoadLibraryA("ws2_32");
+
+ /* If hLibrary is null, we couldn't find a dll with functions */
+ if (hLibrary != NULL)
+ {
+ /* We found a dll, so now get the addresses of the routines */
+
+ getaddrinfo_ptr = (getaddrinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
+ "getaddrinfo");
+ freeaddrinfo_ptr = (freeaddrinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
+ "freeaddrinfo");
+ getnameinfo_ptr = (getnameinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
+ "getnameinfo");
+
+ /*
+ * If any one of the routines is missing, let's play it safe and
+ * ignore them all
+ */
+ if (getaddrinfo_ptr == NULL ||
+ freeaddrinfo_ptr == NULL ||
+ getnameinfo_ptr == NULL)
+ {
+ FreeLibrary(hLibrary);
+ hLibrary = NULL;
+ getaddrinfo_ptr = NULL;
+ freeaddrinfo_ptr = NULL;
+ getnameinfo_ptr = NULL;
+ }
+ }
+
+ alreadyLookedForIpv6routines = true;
+ return (getaddrinfo_ptr != NULL);
+}
+#endif
+
+
+/*
+ * get address info for ipv4 sockets.
+ *
+ * Bugs: - only one addrinfo is set even though hintp is NULL or
+ * ai_socktype is 0
+ * - AI_CANONNAME is not supported.
+ * - servname can only be a number, not text.
+ */
+int
+getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hintp,
+ struct addrinfo **res)
+{
+ struct addrinfo *ai;
+ struct sockaddr_in sin,
+ *psin;
+ struct addrinfo hints;
+
+#ifdef WIN32
+
+ /*
+ * If Windows has native IPv6 support, use the native Windows routine.
+ * Otherwise, fall through and use our own code.
+ */
+ if (haveNativeWindowsIPv6routines())
+ return (*getaddrinfo_ptr) (node, service, hintp, res);
+#endif
+
+ if (hintp == NULL)
+ {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ }
+ else
+ memcpy(&hints, hintp, sizeof(hints));
+
+ if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
+ return EAI_FAMILY;
+
+ if (hints.ai_socktype == 0)
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (!node && !service)
+ return EAI_NONAME;
+
+ memset(&sin, 0, sizeof(sin));
+
+ sin.sin_family = AF_INET;
+
+ if (node)
+ {
+ if (node[0] == '\0')
+ sin.sin_addr.s_addr = pg_hton32(INADDR_ANY);
+ else if (hints.ai_flags & AI_NUMERICHOST)
+ {
+ if (!inet_aton(node, &sin.sin_addr))
+ return EAI_NONAME;
+ }
+ else
+ {
+ struct hostent *hp;
+
+#ifdef FRONTEND
+ struct hostent hpstr;
+ char buf[BUFSIZ];
+ int herrno = 0;
+
+ pqGethostbyname(node, &hpstr, buf, sizeof(buf),
+ &hp, &herrno);
+#else
+ hp = gethostbyname(node);
+#endif
+ if (hp == NULL)
+ {
+ switch (h_errno)
+ {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return EAI_NONAME;
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+ case NO_RECOVERY:
+ default:
+ return EAI_FAIL;
+ }
+ }
+ if (hp->h_addrtype != AF_INET)
+ return EAI_FAIL;
+
+ memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
+ }
+ }
+ else
+ {
+ if (hints.ai_flags & AI_PASSIVE)
+ sin.sin_addr.s_addr = pg_hton32(INADDR_ANY);
+ else
+ sin.sin_addr.s_addr = pg_hton32(INADDR_LOOPBACK);
+ }
+
+ if (service)
+ sin.sin_port = pg_hton16((unsigned short) atoi(service));
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+
+ ai = malloc(sizeof(*ai));
+ if (!ai)
+ return EAI_MEMORY;
+
+ psin = malloc(sizeof(*psin));
+ if (!psin)
+ {
+ free(ai);
+ return EAI_MEMORY;
+ }
+
+ memcpy(psin, &sin, sizeof(*psin));
+
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints.ai_socktype;
+ ai->ai_protocol = hints.ai_protocol;
+ ai->ai_addrlen = sizeof(*psin);
+ ai->ai_addr = (struct sockaddr *) psin;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ *res = ai;
+
+ return 0;
+}
+
+
+void
+freeaddrinfo(struct addrinfo *res)
+{
+ if (res)
+ {
+#ifdef WIN32
+
+ /*
+ * If Windows has native IPv6 support, use the native Windows routine.
+ * Otherwise, fall through and use our own code.
+ */
+ if (haveNativeWindowsIPv6routines())
+ {
+ (*freeaddrinfo_ptr) (res);
+ return;
+ }
+#endif
+
+ if (res->ai_addr)
+ free(res->ai_addr);
+ free(res);
+ }
+}
+
+
+const char *
+gai_strerror(int errcode)
+{
+#ifdef HAVE_HSTRERROR
+ int hcode;
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ hcode = HOST_NOT_FOUND;
+ break;
+ case EAI_AGAIN:
+ hcode = TRY_AGAIN;
+ break;
+ case EAI_FAIL:
+ default:
+ hcode = NO_RECOVERY;
+ break;
+ }
+
+ return hstrerror(hcode);
+#else /* !HAVE_HSTRERROR */
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ return "Unknown host";
+ case EAI_AGAIN:
+ return "Host name lookup failure";
+ /* Errors below are probably WIN32 only */
+#ifdef EAI_BADFLAGS
+ case EAI_BADFLAGS:
+ return "Invalid argument";
+#endif
+#ifdef EAI_FAMILY
+ case EAI_FAMILY:
+ return "Address family not supported";
+#endif
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ return "Not enough memory";
+#endif
+#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
+ case EAI_NODATA:
+ return "No host data of that type was found";
+#endif
+#ifdef EAI_SERVICE
+ case EAI_SERVICE:
+ return "Class type not found";
+#endif
+#ifdef EAI_SOCKTYPE
+ case EAI_SOCKTYPE:
+ return "Socket type not supported";
+#endif
+ default:
+ return "Unknown server error";
+ }
+#endif /* HAVE_HSTRERROR */
+}
+
+/*
+ * Convert an ipv4 address to a hostname.
+ *
+ * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
+ * It will never resolve a hostname.
+ * - No IPv6 support.
+ */
+int
+getnameinfo(const struct sockaddr *sa, int salen,
+ char *node, int nodelen,
+ char *service, int servicelen, int flags)
+{
+#ifdef WIN32
+
+ /*
+ * If Windows has native IPv6 support, use the native Windows routine.
+ * Otherwise, fall through and use our own code.
+ */
+ if (haveNativeWindowsIPv6routines())
+ return (*getnameinfo_ptr) (sa, salen, node, nodelen,
+ service, servicelen, flags);
+#endif
+
+ /* Invalid arguments. */
+ if (sa == NULL || (node == NULL && service == NULL))
+ return EAI_FAIL;
+
+#ifdef HAVE_IPV6
+ if (sa->sa_family == AF_INET6)
+ return EAI_FAMILY;
+#endif
+
+ /* Unsupported flags. */
+ if (flags & NI_NAMEREQD)
+ return EAI_AGAIN;
+
+ if (node)
+ {
+ if (sa->sa_family == AF_INET)
+ {
+ if (pg_inet_net_ntop(AF_INET,
+ &((struct sockaddr_in *) sa)->sin_addr,
+ sa->sa_family == AF_INET ? 32 : 128,
+ node, nodelen) == NULL)
+ return EAI_MEMORY;
+ }
+ else
+ return EAI_MEMORY;
+ }
+
+ if (service)
+ {
+ int ret = -1;
+
+ if (sa->sa_family == AF_INET)
+ {
+ ret = snprintf(service, servicelen, "%d",
+ pg_ntoh16(((struct sockaddr_in *) sa)->sin_port));
+ }
+ if (ret < 0 || ret >= servicelen)
+ return EAI_MEMORY;
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/postgresql/src/port/getopt.c b/contrib/libs/postgresql/src/port/getopt.c
new file mode 100644
index 0000000000..207c2836d3
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/getopt.c
@@ -0,0 +1,136 @@
+/* src/port/getopt.c */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ */
+
+#include "c.h"
+
+#include "pg_getopt.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+
+
+/*
+ * On OpenBSD and some versions of Solaris, opterr and friends are defined in
+ * core libc rather than in a separate getopt module. Define these variables
+ * only if configure found they aren't there by default; otherwise, this
+ * module and its callers will just use libc's variables. (We assume that
+ * testing opterr is sufficient for all of these.)
+ */
+#ifndef HAVE_INT_OPTERR
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt; /* character checked for validity */
+char *optarg; /* argument associated with option */
+
+#endif
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt
+ * Parse argc/argv argument vector.
+ *
+ * This implementation does not use optreset. Instead, we guarantee that
+ * it can be restarted on a new argv array after a previous call returned -1,
+ * if the caller resets optind to 1 before the first call of the new series.
+ * (Internally, this means we must be sure to reset "place" to EMSG before
+ * returning -1.)
+ */
+int
+getopt(int nargc, char *const *nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (!*place)
+ { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-')
+ {
+ place = EMSG;
+ return -1;
+ }
+ if (place[1] && *++place == '-' && place[1] == '\0')
+ { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return -1;
+ }
+ } /* option letter okay? */
+ if ((optopt = (int) *place++) == (int) ':' ||
+ !(oli = strchr(ostr, optopt)))
+ {
+ /*
+ * if the user didn't specify '-' as an option, assume it means -1.
+ */
+ if (optopt == (int) '-')
+ {
+ place = EMSG;
+ return -1;
+ }
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void) fprintf(stderr,
+ "illegal option -- %c\n", optopt);
+ return BADCH;
+ }
+ if (*++oli != ':')
+ { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else
+ { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind)
+ { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return BADARG;
+ if (opterr)
+ (void) fprintf(stderr,
+ "option requires an argument -- %c\n",
+ optopt);
+ return BADCH;
+ }
+ else
+ /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return optopt; /* dump back option letter */
+}
diff --git a/contrib/libs/postgresql/src/port/getrusage.c b/contrib/libs/postgresql/src/port/getrusage.c
new file mode 100644
index 0000000000..99f240f6da
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/getrusage.c
@@ -0,0 +1,110 @@
+/*-------------------------------------------------------------------------
+ *
+ * getrusage.c
+ * get information about resource utilisation
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/getrusage.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#include "rusagestub.h"
+
+/* This code works on:
+ * solaris_i386
+ * solaris_sparc
+ * hpux 9.*
+ * win32
+ * which currently is all the supported platforms that don't have a
+ * native version of getrusage(). So, if configure decides to compile
+ * this file at all, we just use this version unconditionally.
+ */
+
+int
+getrusage(int who, struct rusage *rusage)
+{
+#ifdef WIN32
+ FILETIME starttime;
+ FILETIME exittime;
+ FILETIME kerneltime;
+ FILETIME usertime;
+ ULARGE_INTEGER li;
+
+ if (who != RUSAGE_SELF)
+ {
+ /* Only RUSAGE_SELF is supported in this implementation for now */
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+ memset(rusage, 0, sizeof(struct rusage));
+ if (GetProcessTimes(GetCurrentProcess(),
+ &starttime, &exittime, &kerneltime, &usertime) == 0)
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ /* Convert FILETIMEs (0.1 us) to struct timeval */
+ memcpy(&li, &kerneltime, sizeof(FILETIME));
+ li.QuadPart /= 10L; /* Convert to microseconds */
+ rusage->ru_stime.tv_sec = li.QuadPart / 1000000L;
+ rusage->ru_stime.tv_usec = li.QuadPart % 1000000L;
+
+ memcpy(&li, &usertime, sizeof(FILETIME));
+ li.QuadPart /= 10L; /* Convert to microseconds */
+ rusage->ru_utime.tv_sec = li.QuadPart / 1000000L;
+ rusage->ru_utime.tv_usec = li.QuadPart % 1000000L;
+#else /* all but WIN32 */
+
+ struct tms tms;
+ int tick_rate = CLK_TCK; /* ticks per second */
+ clock_t u,
+ s;
+
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+ if (times(&tms) < 0)
+ {
+ /* errno set by times */
+ return -1;
+ }
+ switch (who)
+ {
+ case RUSAGE_SELF:
+ u = tms.tms_utime;
+ s = tms.tms_stime;
+ break;
+ case RUSAGE_CHILDREN:
+ u = tms.tms_cutime;
+ s = tms.tms_cstime;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+#define TICK_TO_SEC(T, RATE) ((T)/(RATE))
+#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
+ rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
+ rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
+ rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
+#endif /* WIN32 */
+
+ return 0;
+}
diff --git a/contrib/libs/postgresql/src/port/gettimeofday.c b/contrib/libs/postgresql/src/port/gettimeofday.c
new file mode 100644
index 0000000000..ee8fe82337
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/gettimeofday.c
@@ -0,0 +1,118 @@
+/*
+ * gettimeofday.c
+ * Win32 gettimeofday() replacement
+ *
+ * src/port/gettimeofday.c
+ *
+ * Copyright (c) 2003 SRA, Inc.
+ * Copyright (c) 2003 SKC, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose, without fee, and without a
+ * written agreement is hereby granted, provided that the above
+ * copyright notice and this paragraph and the following two
+ * paragraphs appear in all copies.
+ *
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
+ * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+ * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+ * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
+ * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
+ * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "c.h"
+
+#include <sys/time.h>
+
+/* FILETIME of Jan 1 1970 00:00:00, the PostgreSQL epoch */
+static const unsigned __int64 epoch = UINT64CONST(116444736000000000);
+
+/*
+ * FILETIME represents the number of 100-nanosecond intervals since
+ * January 1, 1601 (UTC).
+ */
+#define FILETIME_UNITS_PER_SEC 10000000L
+#define FILETIME_UNITS_PER_USEC 10
+
+/*
+ * Both GetSystemTimeAsFileTime and GetSystemTimePreciseAsFileTime share a
+ * signature, so we can just store a pointer to whichever we find. This
+ * is the pointer's type.
+ */
+typedef VOID(WINAPI * PgGetSystemTimeFn) (LPFILETIME);
+
+/* One-time initializer function, must match that signature. */
+static void WINAPI init_gettimeofday(LPFILETIME lpSystemTimeAsFileTime);
+
+/* Storage for the function we pick at runtime */
+static PgGetSystemTimeFn pg_get_system_time = &init_gettimeofday;
+
+/*
+ * One time initializer. Determine whether GetSystemTimePreciseAsFileTime
+ * is available and if so, plan to use it; if not, fall back to
+ * GetSystemTimeAsFileTime.
+ */
+static void WINAPI
+init_gettimeofday(LPFILETIME lpSystemTimeAsFileTime)
+{
+ /*
+ * Because it's guaranteed that kernel32.dll will be linked into our
+ * address space already, we don't need to LoadLibrary it and worry about
+ * closing it afterwards, so we're not using Pg's dlopen/dlsym() wrapper.
+ *
+ * We'll just look up the address of GetSystemTimePreciseAsFileTime if
+ * present.
+ *
+ * While we could look up the Windows version and skip this on Windows
+ * versions below Windows 8 / Windows Server 2012 there isn't much point,
+ * and determining the windows version is its self somewhat Windows
+ * version and development SDK specific...
+ */
+ pg_get_system_time = (PgGetSystemTimeFn) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "GetSystemTimePreciseAsFileTime");
+ if (pg_get_system_time == NULL)
+ {
+ /*
+ * The expected error from GetLastError() is ERROR_PROC_NOT_FOUND, if
+ * the function isn't present. No other error should occur.
+ *
+ * We can't report an error here because this might be running in
+ * frontend code; and even if we're in the backend, it's too early to
+ * elog(...) if we get some unexpected error. Also, it's not a
+ * serious problem, so just silently fall back to
+ * GetSystemTimeAsFileTime irrespective of why the failure occurred.
+ */
+ pg_get_system_time = &GetSystemTimeAsFileTime;
+ }
+
+ (*pg_get_system_time) (lpSystemTimeAsFileTime);
+}
+
+/*
+ * timezone information is stored outside the kernel so tzp isn't used anymore.
+ *
+ * Note: this function is not for Win32 high precision timing purposes. See
+ * elapsed_time().
+ */
+int
+gettimeofday(struct timeval *tp, struct timezone *tzp)
+{
+ FILETIME file_time;
+ ULARGE_INTEGER ularge;
+
+ (*pg_get_system_time) (&file_time);
+ ularge.LowPart = file_time.dwLowDateTime;
+ ularge.HighPart = file_time.dwHighDateTime;
+
+ tp->tv_sec = (long) ((ularge.QuadPart - epoch) / FILETIME_UNITS_PER_SEC);
+ tp->tv_usec = (long) (((ularge.QuadPart - epoch) % FILETIME_UNITS_PER_SEC)
+ / FILETIME_UNITS_PER_USEC);
+
+ return 0;
+}
diff --git a/contrib/libs/postgresql/src/port/inet_aton.c b/contrib/libs/postgresql/src/port/inet_aton.c
new file mode 100644
index 0000000000..adaf18adb3
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/inet_aton.c
@@ -0,0 +1,149 @@
+/* src/port/inet_aton.c
+ *
+ * This inet_aton() function was taken from the GNU C library and
+ * incorporated into Postgres for those systems which do not have this
+ * routine in their standard C libraries.
+ *
+ * The function was been extracted whole from the file inet_aton.c in
+ * Release 5.3.12 of the Linux C library, which is derived from the
+ * GNU C library, by Bryan Henderson in October 1996. The copyright
+ * notice from that file is below.
+ */
+
+/*
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include "c.h"
+
+#include <netinet/in.h>
+#include <ctype.h>
+
+#include "port/pg_bswap.h"
+
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(const char *cp, struct in_addr *addr)
+{
+ unsigned int val;
+ int base,
+ n;
+ char c;
+ u_int parts[4];
+ u_int *pp = parts;
+
+ for (;;)
+ {
+ /*
+ * Collect number up to ``.''. Values are specified as for C: 0x=hex,
+ * 0=octal, other=decimal.
+ */
+ val = 0;
+ base = 10;
+ if (*cp == '0')
+ {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != '\0')
+ {
+ if (isdigit((unsigned char) c))
+ {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isxdigit((unsigned char) c))
+ {
+ val = (val << 4) +
+ (c + 10 - (islower((unsigned char) c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.')
+ {
+ /*
+ * Internet format: a.b.c.d a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return 0;
+ *pp++ = val, cp++;
+ }
+ else
+ break;
+ }
+
+ /*
+ * Check for trailing junk.
+ */
+ while (*cp)
+ if (!isspace((unsigned char) *cp++))
+ return 0;
+
+ /*
+ * Concoct the address according to the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n)
+ {
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return 0;
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return 0;
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return 0;
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = pg_hton32(val);
+ return 1;
+}
diff --git a/contrib/libs/postgresql/src/port/kill.c b/contrib/libs/postgresql/src/port/kill.c
new file mode 100644
index 0000000000..99b35de45b
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/kill.c
@@ -0,0 +1,97 @@
+/*-------------------------------------------------------------------------
+ *
+ * kill.c
+ * kill()
+ *
+ * Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * This is a replacement version of kill for Win32 which sends
+ * signals that the backend can recognize.
+ *
+ * IDENTIFICATION
+ * src/port/kill.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#ifdef WIN32
+/* signal sending */
+int
+pgkill(int pid, int sig)
+{
+ char pipename[128];
+ BYTE sigData = sig;
+ BYTE sigRet = 0;
+ DWORD bytes;
+
+ /* we allow signal 0 here, but it will be ignored in pg_queue_signal */
+ if (sig >= PG_SIGNAL_COUNT || sig < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (pid <= 0)
+ {
+ /* No support for process groups */
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* special case for SIGKILL: just ask the system to terminate the target */
+ if (sig == SIGKILL)
+ {
+ HANDLE prochandle;
+
+ if ((prochandle = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD) pid)) == NULL)
+ {
+ errno = ESRCH;
+ return -1;
+ }
+ if (!TerminateProcess(prochandle, 255))
+ {
+ _dosmaperr(GetLastError());
+ CloseHandle(prochandle);
+ return -1;
+ }
+ CloseHandle(prochandle);
+ return 0;
+ }
+ snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", pid);
+
+ if (CallNamedPipe(pipename, &sigData, 1, &sigRet, 1, &bytes, 1000))
+ {
+ if (bytes != 1 || sigRet != sig)
+ {
+ errno = ESRCH;
+ return -1;
+ }
+ return 0;
+ }
+
+ switch (GetLastError())
+ {
+ case ERROR_BROKEN_PIPE:
+ case ERROR_BAD_PIPE:
+
+ /*
+ * These arise transiently as a process is exiting. Treat them
+ * like POSIX treats a zombie process, reporting success.
+ */
+ return 0;
+
+ case ERROR_FILE_NOT_FOUND:
+ /* pipe fully gone, so treat the process as gone */
+ errno = ESRCH;
+ return -1;
+ case ERROR_ACCESS_DENIED:
+ errno = EPERM;
+ return -1;
+ default:
+ errno = EINVAL; /* unexpected */
+ return -1;
+ }
+}
+
+#endif
diff --git a/contrib/libs/postgresql/src/port/open.c b/contrib/libs/postgresql/src/port/open.c
new file mode 100644
index 0000000000..14c6debba9
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/open.c
@@ -0,0 +1,216 @@
+/*-------------------------------------------------------------------------
+ *
+ * open.c
+ * Win32 open() replacement
+ *
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * src/port/open.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifdef WIN32
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#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?
+ */
+int
+pgwin32_open(const char *fileName, int fileFlags,...)
+{
+ int fd;
+ HANDLE h = INVALID_HANDLE_VALUE;
+ SECURITY_ATTRIBUTES sa;
+ int loops = 0;
+
+ /* Check that we can handle the request */
+ assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
+ (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) |
+ _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() */
+#endif
+
+#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
+
+ 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)
+ {
+ /*
+ * 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)
+ {
+#ifndef FRONTEND
+ if (loops == 50)
+ ereport(LOG,
+ (errmsg("could not open file \"%s\": %s", fileName,
+ (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")),
+ errdetail("Continuing to retry for 30 seconds."),
+ errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
+#endif
+
+ if (loops < 300)
+ {
+ pg_usleep(100000);
+ loops++;
+ continue;
+ }
+ }
+
+ /*
+ * 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;
+ }
+
+ /* _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 */
+ else if (fileFlags & (O_TEXT | O_BINARY) &&
+ _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
+ {
+ _close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+FILE *
+pgwin32_fopen(const char *fileName, const char *mode)
+{
+ int openmode = 0;
+ int fd;
+
+ if (strstr(mode, "r+"))
+ openmode |= O_RDWR;
+ else if (strchr(mode, 'r'))
+ openmode |= O_RDONLY;
+ if (strstr(mode, "w+"))
+ openmode |= O_RDWR | O_CREAT | O_TRUNC;
+ else if (strchr(mode, 'w'))
+ openmode |= O_WRONLY | O_CREAT | O_TRUNC;
+ if (strchr(mode, 'a'))
+ openmode |= O_WRONLY | O_CREAT | O_APPEND;
+
+ if (strchr(mode, 'b'))
+ openmode |= O_BINARY;
+ if (strchr(mode, 't'))
+ openmode |= O_TEXT;
+
+ fd = pgwin32_open(fileName, openmode);
+ if (fd == -1)
+ return NULL;
+ return _fdopen(fd, mode);
+}
+
+#endif
diff --git a/contrib/libs/postgresql/src/port/pread.c b/contrib/libs/postgresql/src/port/pread.c
new file mode 100644
index 0000000000..486f07a7df
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/pread.c
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * pread.c
+ * Implementation of pread(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/pread.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX function, so we use the name pg_pread().
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+ssize_t
+pg_pread(int fd, void *buf, size_t size, off_t offset)
+{
+#ifdef WIN32
+ OVERLAPPED overlapped = {0};
+ HANDLE handle;
+ DWORD result;
+
+ handle = (HANDLE) _get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ overlapped.Offset = offset;
+ if (!ReadFile(handle, buf, size, &result, &overlapped))
+ {
+ if (GetLastError() == ERROR_HANDLE_EOF)
+ return 0;
+
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ return result;
+#else
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return -1;
+
+ return read(fd, buf, size);
+#endif
+}
diff --git a/contrib/libs/postgresql/src/port/pwrite.c b/contrib/libs/postgresql/src/port/pwrite.c
new file mode 100644
index 0000000000..282b27115e
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/pwrite.c
@@ -0,0 +1,55 @@
+/*-------------------------------------------------------------------------
+ *
+ * pwrite.c
+ * Implementation of pwrite(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/pwrite.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX function, so we use the name pg_pwrite().
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+ssize_t
+pg_pwrite(int fd, const void *buf, size_t size, off_t offset)
+{
+#ifdef WIN32
+ OVERLAPPED overlapped = {0};
+ HANDLE handle;
+ DWORD result;
+
+ handle = (HANDLE) _get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ overlapped.Offset = offset;
+ if (!WriteFile(handle, buf, size, &result, &overlapped))
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ return result;
+#else
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return -1;
+
+ return write(fd, buf, size);
+#endif
+}
diff --git a/contrib/libs/postgresql/src/port/pwritev.c b/contrib/libs/postgresql/src/port/pwritev.c
new file mode 100644
index 0000000000..2e8ef7e378
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/pwritev.c
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * pwritev.c
+ * Implementation of pwritev(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/pwritev.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX-like function, so we use the name pg_pwritev().
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "port/pg_iovec.h"
+
+ssize_t
+pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+#ifdef HAVE_WRITEV
+ if (iovcnt == 1)
+ return pg_pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return -1;
+ return writev(fd, iov, iovcnt);
+#else
+ ssize_t sum = 0;
+ ssize_t part;
+
+ for (int i = 0; i < iovcnt; ++i)
+ {
+ part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
+ if (part < 0)
+ {
+ if (i == 0)
+ return -1;
+ else
+ return sum;
+ }
+ sum += part;
+ offset += part;
+ if (part < iov[i].iov_len)
+ return sum;
+ }
+ return sum;
+#endif
+}
diff --git a/contrib/libs/postgresql/src/port/system.c b/contrib/libs/postgresql/src/port/system.c
new file mode 100644
index 0000000000..8618e47f97
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/system.c
@@ -0,0 +1,117 @@
+/*-------------------------------------------------------------------------
+ *
+ * system.c
+ * Win32 system() and popen() replacements
+ *
+ *
+ * Win32 needs double quotes at the beginning and end of system()
+ * strings. If not, it gets confused with multiple quoted strings.
+ * It also requires double-quotes around the executable name and
+ * any files used for redirection. Filter other args through
+ * appendShellString() to quote them.
+ *
+ * Generated using Win32 "CMD /?":
+ *
+ * 1. If all of the following conditions are met, then quote characters
+ * on the command line are preserved:
+ *
+ * - no /S switch
+ * - exactly two quote characters
+ * - no special characters between the two quote characters, where special
+ * is one of: &<>()@^|
+ * - there are one or more whitespace characters between the two quote
+ * characters
+ * - the string between the two quote characters is the name of an
+ * executable file.
+ *
+ * 2. Otherwise, old behavior is to see if the first character is a quote
+ * character and if so, strip the leading character and remove the last
+ * quote character on the command line, preserving any text after the last
+ * quote character.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * src/port/system.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <fcntl.h>
+
+#undef system
+#undef popen
+
+int
+pgwin32_system(const char *command)
+{
+ size_t cmdlen = strlen(command);
+ char *buf;
+ int save_errno;
+ int res;
+
+ /*
+ * Create a malloc'd copy of the command string, enclosed with an extra
+ * pair of quotes
+ */
+ buf = malloc(cmdlen + 2 + 1);
+ if (buf == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ buf[0] = '"';
+ memcpy(&buf[1], command, cmdlen);
+ buf[cmdlen + 1] = '"';
+ buf[cmdlen + 2] = '\0';
+
+ res = system(buf);
+
+ save_errno = errno;
+ free(buf);
+ errno = save_errno;
+
+ return res;
+}
+
+
+FILE *
+pgwin32_popen(const char *command, const char *type)
+{
+ size_t cmdlen = strlen(command);
+ char *buf;
+ int save_errno;
+ FILE *res;
+
+ /*
+ * Create a malloc'd copy of the command string, enclosed with an extra
+ * pair of quotes
+ */
+ buf = malloc(cmdlen + 2 + 1);
+ if (buf == NULL)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ buf[0] = '"';
+ memcpy(&buf[1], command, cmdlen);
+ buf[cmdlen + 1] = '"';
+ buf[cmdlen + 2] = '\0';
+
+ res = _popen(buf, type);
+
+ save_errno = errno;
+ free(buf);
+ errno = save_errno;
+
+ return res;
+}
+
+#endif
diff --git a/contrib/libs/postgresql/src/port/win32env.c b/contrib/libs/postgresql/src/port/win32env.c
new file mode 100644
index 0000000000..a03556078c
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/win32env.c
@@ -0,0 +1,163 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32env.c
+ * putenv(), setenv(), and unsetenv() for win32.
+ *
+ * These functions update both the process environment and caches in
+ * (potentially multiple) C run-time library (CRT) versions.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/win32env.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+
+/*
+ * Note that unlike POSIX putenv(), this doesn't use the passed-in string
+ * as permanent storage.
+ */
+int
+pgwin32_putenv(const char *envval)
+{
+ char *envcpy;
+ char *cp;
+ typedef int (_cdecl * PUTENVPROC) (const char *);
+ static const char *const modulenames[] = {
+ "msvcrt", /* Visual Studio 6.0 / MinGW */
+ "msvcrtd",
+ "msvcr70", /* Visual Studio 2002 */
+ "msvcr70d",
+ "msvcr71", /* Visual Studio 2003 */
+ "msvcr71d",
+ "msvcr80", /* Visual Studio 2005 */
+ "msvcr80d",
+ "msvcr90", /* Visual Studio 2008 */
+ "msvcr90d",
+ "msvcr100", /* Visual Studio 2010 */
+ "msvcr100d",
+ "msvcr110", /* Visual Studio 2012 */
+ "msvcr110d",
+ "msvcr120", /* Visual Studio 2013 */
+ "msvcr120d",
+ "ucrtbase", /* Visual Studio 2015 and later */
+ "ucrtbased",
+ NULL
+ };
+ int i;
+
+ /*
+ * Update process environment, making this change visible to child
+ * processes and to CRTs initializing in the future. Do this before the
+ * _putenv() loop, for the benefit of any CRT that initializes during this
+ * pgwin32_putenv() execution, after the loop checks that CRT.
+ *
+ * Need a copy of the string so we can modify it.
+ */
+ envcpy = strdup(envval);
+ if (!envcpy)
+ return -1;
+ cp = strchr(envcpy, '=');
+ if (cp == NULL)
+ {
+ free(envcpy);
+ return -1;
+ }
+ *cp = '\0';
+ cp++;
+ if (*cp)
+ {
+ /*
+ * Only call SetEnvironmentVariable() when we are adding a variable,
+ * not when removing it. Calling it on both crashes on at least
+ * certain versions of MinGW.
+ */
+ if (!SetEnvironmentVariable(envcpy, cp))
+ {
+ free(envcpy);
+ return -1;
+ }
+ }
+ free(envcpy);
+
+ /*
+ * Each CRT has its own _putenv() symbol and copy of the environment.
+ * Update the environment in each CRT module currently loaded, so every
+ * third-party library sees this change regardless of the CRT it links
+ * against. Addresses within these modules may become invalid the moment
+ * we call FreeLibrary(), so don't cache them.
+ */
+ for (i = 0; modulenames[i]; i++)
+ {
+ HMODULE hmodule = NULL;
+ BOOL res = GetModuleHandleEx(0, modulenames[i], &hmodule);
+
+ if (res != 0 && hmodule != NULL)
+ {
+ PUTENVPROC putenvFunc;
+
+ putenvFunc = (PUTENVPROC) (pg_funcptr_t) GetProcAddress(hmodule, "_putenv");
+ if (putenvFunc)
+ putenvFunc(envval);
+ FreeLibrary(hmodule);
+ }
+ }
+
+ /*
+ * Finally, update our "own" cache. This is redundant with the loop
+ * above, except when PostgreSQL itself links to a CRT not listed above.
+ * Ideally, the loop does visit all possible CRTs, making this redundant.
+ */
+ return _putenv(envval);
+}
+
+int
+pgwin32_setenv(const char *name, const char *value, int overwrite)
+{
+ int res;
+ char *envstr;
+
+ /* Error conditions, per POSIX */
+ if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL ||
+ value == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* No work if variable exists and we're not to replace it */
+ if (overwrite == 0 && getenv(name) != NULL)
+ return 0;
+
+ envstr = (char *) malloc(strlen(name) + strlen(value) + 2);
+ if (!envstr) /* not much we can do if no memory */
+ return -1;
+
+ sprintf(envstr, "%s=%s", name, value);
+
+ res = pgwin32_putenv(envstr);
+ free(envstr);
+ return res;
+}
+
+int
+pgwin32_unsetenv(const char *name)
+{
+ int res;
+ char *envbuf;
+
+ envbuf = (char *) malloc(strlen(name) + 2);
+ if (!envbuf)
+ return -1;
+
+ sprintf(envbuf, "%s=", name);
+ res = pgwin32_putenv(envbuf);
+ free(envbuf);
+ return res;
+}
diff --git a/contrib/libs/postgresql/src/port/win32error.c b/contrib/libs/postgresql/src/port/win32error.c
new file mode 100644
index 0000000000..0e5f91adfa
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/win32error.c
@@ -0,0 +1,208 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32error.c
+ * Map win32 error codes to errno values
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/win32error.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+static const struct
+{
+ DWORD winerr;
+ int doserr;
+} doserrors[] =
+
+{
+ {
+ ERROR_INVALID_FUNCTION, EINVAL
+ },
+ {
+ ERROR_FILE_NOT_FOUND, ENOENT
+ },
+ {
+ ERROR_PATH_NOT_FOUND, ENOENT
+ },
+ {
+ ERROR_TOO_MANY_OPEN_FILES, EMFILE
+ },
+ {
+ ERROR_ACCESS_DENIED, EACCES
+ },
+ {
+ ERROR_INVALID_HANDLE, EBADF
+ },
+ {
+ ERROR_ARENA_TRASHED, ENOMEM
+ },
+ {
+ ERROR_NOT_ENOUGH_MEMORY, ENOMEM
+ },
+ {
+ ERROR_INVALID_BLOCK, ENOMEM
+ },
+ {
+ ERROR_BAD_ENVIRONMENT, E2BIG
+ },
+ {
+ ERROR_BAD_FORMAT, ENOEXEC
+ },
+ {
+ ERROR_INVALID_ACCESS, EINVAL
+ },
+ {
+ ERROR_INVALID_DATA, EINVAL
+ },
+ {
+ ERROR_INVALID_DRIVE, ENOENT
+ },
+ {
+ ERROR_CURRENT_DIRECTORY, EACCES
+ },
+ {
+ ERROR_NOT_SAME_DEVICE, EXDEV
+ },
+ {
+ ERROR_NO_MORE_FILES, ENOENT
+ },
+ {
+ ERROR_LOCK_VIOLATION, EACCES
+ },
+ {
+ ERROR_SHARING_VIOLATION, EACCES
+ },
+ {
+ ERROR_BAD_NETPATH, ENOENT
+ },
+ {
+ ERROR_NETWORK_ACCESS_DENIED, EACCES
+ },
+ {
+ ERROR_BAD_NET_NAME, ENOENT
+ },
+ {
+ ERROR_FILE_EXISTS, EEXIST
+ },
+ {
+ ERROR_CANNOT_MAKE, EACCES
+ },
+ {
+ ERROR_FAIL_I24, EACCES
+ },
+ {
+ ERROR_INVALID_PARAMETER, EINVAL
+ },
+ {
+ ERROR_NO_PROC_SLOTS, EAGAIN
+ },
+ {
+ ERROR_DRIVE_LOCKED, EACCES
+ },
+ {
+ ERROR_BROKEN_PIPE, EPIPE
+ },
+ {
+ ERROR_DISK_FULL, ENOSPC
+ },
+ {
+ ERROR_INVALID_TARGET_HANDLE, EBADF
+ },
+ {
+ ERROR_INVALID_HANDLE, EINVAL
+ },
+ {
+ ERROR_WAIT_NO_CHILDREN, ECHILD
+ },
+ {
+ ERROR_CHILD_NOT_COMPLETE, ECHILD
+ },
+ {
+ ERROR_DIRECT_ACCESS_HANDLE, EBADF
+ },
+ {
+ ERROR_NEGATIVE_SEEK, EINVAL
+ },
+ {
+ ERROR_SEEK_ON_DEVICE, EACCES
+ },
+ {
+ ERROR_DIR_NOT_EMPTY, ENOTEMPTY
+ },
+ {
+ ERROR_NOT_LOCKED, EACCES
+ },
+ {
+ ERROR_BAD_PATHNAME, ENOENT
+ },
+ {
+ ERROR_MAX_THRDS_REACHED, EAGAIN
+ },
+ {
+ ERROR_LOCK_FAILED, EACCES
+ },
+ {
+ ERROR_ALREADY_EXISTS, EEXIST
+ },
+ {
+ ERROR_FILENAME_EXCED_RANGE, ENOENT
+ },
+ {
+ ERROR_NESTING_NOT_ALLOWED, EAGAIN
+ },
+ {
+ ERROR_NOT_ENOUGH_QUOTA, ENOMEM
+ },
+ {
+ ERROR_DELETE_PENDING, ENOENT
+ }
+};
+
+void
+_dosmaperr(unsigned long e)
+{
+ int i;
+
+ if (e == 0)
+ {
+ errno = 0;
+ return;
+ }
+
+ for (i = 0; i < lengthof(doserrors); i++)
+ {
+ if (doserrors[i].winerr == e)
+ {
+ int doserr = doserrors[i].doserr;
+
+#ifndef FRONTEND
+ ereport(DEBUG5,
+ (errmsg_internal("mapped win32 error code %lu to %d",
+ e, doserr)));
+#elif defined(FRONTEND_DEBUG)
+ fprintf(stderr, "mapped win32 error code %lu to %d", e, doserr);
+#endif
+ errno = doserr;
+ return;
+ }
+ }
+
+#ifndef FRONTEND
+ ereport(LOG,
+ (errmsg_internal("unrecognized win32 error code: %lu",
+ e)));
+#else
+ fprintf(stderr, "unrecognized win32 error code: %lu", e);
+#endif
+
+ errno = EINVAL;
+}
diff --git a/contrib/libs/postgresql/src/port/win32security.c b/contrib/libs/postgresql/src/port/win32security.c
new file mode 100644
index 0000000000..4a673fde19
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/win32security.c
@@ -0,0 +1,178 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32security.c
+ * Microsoft Windows Win32 Security Support Functions
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/win32security.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+
+/*
+ * Utility wrapper for frontend and backend when reporting an error
+ * message.
+ */
+static
+pg_attribute_printf(1, 2)
+void
+log_error(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+#ifndef FRONTEND
+ write_stderr(fmt, ap);
+#else
+ fprintf(stderr, fmt, ap);
+#endif
+ va_end(ap);
+}
+
+/*
+ * Returns nonzero if the current user has administrative privileges,
+ * or zero if not.
+ *
+ * Note: this cannot use ereport() because it's called too early during
+ * startup.
+ */
+int
+pgwin32_is_admin(void)
+{
+ PSID AdministratorsSid;
+ PSID PowerUsersSid;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+ BOOL IsAdministrators;
+ BOOL IsPowerUsers;
+
+ if (!AllocateAndInitializeSid(&NtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
+ 0, &AdministratorsSid))
+ {
+ log_error(_("could not get SID for Administrators group: error code %lu\n"),
+ GetLastError());
+ exit(1);
+ }
+
+ if (!AllocateAndInitializeSid(&NtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
+ 0, &PowerUsersSid))
+ {
+ log_error(_("could not get SID for PowerUsers group: error code %lu\n"),
+ GetLastError());
+ exit(1);
+ }
+
+ if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
+ !CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
+ {
+ log_error(_("could not check access token membership: error code %lu\n"),
+ GetLastError());
+ exit(1);
+ }
+
+ FreeSid(AdministratorsSid);
+ FreeSid(PowerUsersSid);
+
+ if (IsAdministrators || IsPowerUsers)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * We consider ourselves running as a service if one of the following is
+ * true:
+ *
+ * 1) We are running as LocalSystem (only used by services)
+ * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
+ * process token by the SCM when starting a service)
+ *
+ * The check for LocalSystem is needed, because surprisingly, if a service
+ * is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
+ * process token.
+ *
+ * Return values:
+ * 0 = Not service
+ * 1 = Service
+ * -1 = Error
+ *
+ * Note: we can't report errors via either ereport (we're called too early
+ * in the backend) or write_stderr (because that calls this). We are
+ * therefore reduced to writing directly on stderr, which sucks, but we
+ * have few alternatives.
+ */
+int
+pgwin32_is_service(void)
+{
+ static int _is_service = -1;
+ BOOL IsMember;
+ PSID ServiceSid;
+ PSID LocalSystemSid;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+
+ /* Only check the first time */
+ if (_is_service != -1)
+ return _is_service;
+
+ /* First check for LocalSystem */
+ if (!AllocateAndInitializeSid(&NtAuthority, 1,
+ SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
+ &LocalSystemSid))
+ {
+ fprintf(stderr, "could not get SID for local system account\n");
+ return -1;
+ }
+
+ if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
+ {
+ fprintf(stderr, "could not check access token membership: error code %lu\n",
+ GetLastError());
+ FreeSid(LocalSystemSid);
+ return -1;
+ }
+ FreeSid(LocalSystemSid);
+
+ if (IsMember)
+ {
+ _is_service = 1;
+ return _is_service;
+ }
+
+ /* Check for service group membership */
+ if (!AllocateAndInitializeSid(&NtAuthority, 1,
+ SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
+ &ServiceSid))
+ {
+ fprintf(stderr, "could not get SID for service group: error code %lu\n",
+ GetLastError());
+ return -1;
+ }
+
+ if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
+ {
+ fprintf(stderr, "could not check access token membership: error code %lu\n",
+ GetLastError());
+ FreeSid(ServiceSid);
+ return -1;
+ }
+ FreeSid(ServiceSid);
+
+ if (IsMember)
+ _is_service = 1;
+ else
+ _is_service = 0;
+
+ return _is_service;
+}
diff --git a/contrib/libs/postgresql/src/port/win32setlocale.c b/contrib/libs/postgresql/src/port/win32setlocale.c
new file mode 100644
index 0000000000..4edae05bb7
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/win32setlocale.c
@@ -0,0 +1,193 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32setlocale.c
+ * Wrapper to work around bugs in Windows setlocale() implementation
+ *
+ * Copyright (c) 2011-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/port/win32setlocale.c
+ *
+ *
+ * The setlocale() function in Windows is broken in two ways. First, it
+ * has a problem with locale names that have a dot in the country name. For
+ * example:
+ *
+ * "Chinese (Traditional)_Hong Kong S.A.R..950"
+ *
+ * For some reason, setlocale() doesn't accept that as argument, even though
+ * setlocale(LC_ALL, NULL) returns exactly that. Fortunately, it accepts
+ * various alternative names for such countries, so to work around the broken
+ * setlocale() function, we map the troublemaking locale names to accepted
+ * aliases, before calling setlocale().
+ *
+ * The second problem is that the locale name for "Norwegian (Bokm&aring;l)"
+ * contains a non-ASCII character. That's problematic, because it's not clear
+ * what encoding the locale name itself is supposed to be in, when you
+ * haven't yet set a locale. Also, it causes problems when the cluster
+ * contains databases with different encodings, as the locale name is stored
+ * in the pg_database system catalog. To work around that, when setlocale()
+ * returns that locale name, map it to a pure-ASCII alias for the same
+ * locale.
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#undef setlocale
+
+struct locale_map
+{
+ /*
+ * String in locale name to replace. Can be a single string (end is NULL),
+ * or separate start and end strings. If two strings are given, the locale
+ * name must contain both of them, and everything between them is
+ * replaced. This is used for a poor-man's regexp search, allowing
+ * replacement of "start.*end".
+ */
+ const char *locale_name_start;
+ const char *locale_name_end;
+
+ const char *replacement; /* string to replace the match with */
+};
+
+/*
+ * Mappings applied before calling setlocale(), to the argument.
+ */
+static const struct locale_map locale_map_argument[] = {
+ /*
+ * "HKG" is listed here:
+ * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
+ * (Country/Region Strings).
+ *
+ * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
+ * above list, but seems to work anyway.
+ */
+ {"Hong Kong S.A.R.", NULL, "HKG"},
+ {"U.A.E.", NULL, "ARE"},
+
+ /*
+ * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
+ * seem to recognize that. And Macau isn't listed in the table of accepted
+ * abbreviations linked above. Fortunately, "ZHM" seems to be accepted as
+ * an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm not sure
+ * where "ZHM" comes from, must be some legacy naming scheme. But hey, it
+ * works.
+ *
+ * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale
+ * name, not just the country part.
+ *
+ * Some versions of Windows spell it "Macau", others "Macao".
+ */
+ {"Chinese (Traditional)_Macau S.A.R..950", NULL, "ZHM"},
+ {"Chinese_Macau S.A.R..950", NULL, "ZHM"},
+ {"Chinese (Traditional)_Macao S.A.R..950", NULL, "ZHM"},
+ {"Chinese_Macao S.A.R..950", NULL, "ZHM"},
+ {NULL, NULL, NULL}
+};
+
+/*
+ * Mappings applied after calling setlocale(), to its return value.
+ */
+static const struct locale_map locale_map_result[] = {
+ /*
+ * "Norwegian (Bokm&aring;l)" locale name contains the a-ring character.
+ * Map it to a pure-ASCII alias.
+ *
+ * It's not clear what encoding setlocale() uses when it returns the
+ * locale name, so to play it safe, we search for "Norwegian (Bok*l)".
+ *
+ * Just to make life even more complicated, some versions of Windows spell
+ * the locale name without parentheses. Translate that too.
+ */
+ {"Norwegian (Bokm", "l)_Norway", "Norwegian_Norway"},
+ {"Norwegian Bokm", "l_Norway", "Norwegian_Norway"},
+ {NULL, NULL, NULL}
+};
+
+#define MAX_LOCALE_NAME_LEN 100
+
+static const char *
+map_locale(const struct locale_map *map, const char *locale)
+{
+ static char aliasbuf[MAX_LOCALE_NAME_LEN];
+ int i;
+
+ /* Check if the locale name matches any of the problematic ones. */
+ for (i = 0; map[i].locale_name_start != NULL; i++)
+ {
+ const char *needle_start = map[i].locale_name_start;
+ const char *needle_end = map[i].locale_name_end;
+ const char *replacement = map[i].replacement;
+ char *match;
+ char *match_start = NULL;
+ char *match_end = NULL;
+
+ match = strstr(locale, needle_start);
+ if (match)
+ {
+ /*
+ * Found a match for the first part. If this was a two-part
+ * replacement, find the second part.
+ */
+ match_start = match;
+ if (needle_end)
+ {
+ match = strstr(match_start + strlen(needle_start), needle_end);
+ if (match)
+ match_end = match + strlen(needle_end);
+ else
+ match_start = NULL;
+ }
+ else
+ match_end = match_start + strlen(needle_start);
+ }
+
+ if (match_start)
+ {
+ /* Found a match. Replace the matched string. */
+ int matchpos = match_start - locale;
+ int replacementlen = strlen(replacement);
+ char *rest = match_end;
+ int restlen = strlen(rest);
+
+ /* check that the result fits in the static buffer */
+ if (matchpos + replacementlen + restlen + 1 > MAX_LOCALE_NAME_LEN)
+ return NULL;
+
+ memcpy(&aliasbuf[0], &locale[0], matchpos);
+ memcpy(&aliasbuf[matchpos], replacement, replacementlen);
+ /* includes null terminator */
+ memcpy(&aliasbuf[matchpos + replacementlen], rest, restlen + 1);
+
+ return aliasbuf;
+ }
+ }
+
+ /* no match, just return the original string */
+ return locale;
+}
+
+char *
+pgwin32_setlocale(int category, const char *locale)
+{
+ const char *argument;
+ char *result;
+
+ if (locale == NULL)
+ argument = NULL;
+ else
+ argument = map_locale(locale_map_argument, locale);
+
+ /* Call the real setlocale() function */
+ result = setlocale(category, argument);
+
+ /*
+ * setlocale() is specified to return a "char *" that the caller is
+ * forbidden to modify, so casting away the "const" is innocuous.
+ */
+ if (result)
+ result = unconstify(char *, map_locale(locale_map_result, result));
+
+ return result;
+}
diff --git a/contrib/libs/postgresql/src/port/win32stat.c b/contrib/libs/postgresql/src/port/win32stat.c
new file mode 100644
index 0000000000..426e01f0ef
--- /dev/null
+++ b/contrib/libs/postgresql/src/port/win32stat.c
@@ -0,0 +1,327 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32stat.c
+ * Replacements for <sys/stat.h> functions using GetFileInformationByHandle
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/win32stat.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifdef WIN32
+
+#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.
+ */
+static __time64_t
+filetime_to_time(const FILETIME *ft)
+{
+ ULARGE_INTEGER unified_ft = {0};
+ static const uint64 EpochShift = UINT64CONST(116444736000000000);
+
+ unified_ft.LowPart = ft->dwLowDateTime;
+ unified_ft.HighPart = ft->dwHighDateTime;
+
+ if (unified_ft.QuadPart < EpochShift)
+ return -1;
+
+ unified_ft.QuadPart -= EpochShift;
+ unified_ft.QuadPart /= 10 * 1000 * 1000;
+
+ return unified_ft.QuadPart;
+}
+
+/*
+ * Convert WIN32 file attributes to a Unix-style mode.
+ *
+ * Only owner permissions are set.
+ */
+static unsigned short
+fileattr_to_unixmode(int attr)
+{
+ unsigned short uxmode = 0;
+
+ uxmode |= (unsigned short) ((attr & FILE_ATTRIBUTE_DIRECTORY) ?
+ (_S_IFDIR) : (_S_IFREG));
+
+ uxmode |= (unsigned short) ((attr & FILE_ATTRIBUTE_READONLY) ?
+ (_S_IREAD) : (_S_IREAD | _S_IWRITE));
+
+ /* there is no need to simulate _S_IEXEC using CMD's PATHEXT extensions */
+ uxmode |= _S_IEXEC;
+
+ return uxmode;
+}
+
+/*
+ * Convert WIN32 file information (from a HANDLE) to a struct stat.
+ */
+static int
+fileinfo_to_stat(HANDLE hFile, struct stat *buf)
+{
+ BY_HANDLE_FILE_INFORMATION fiData;
+
+ memset(buf, 0, sizeof(*buf));
+
+ /*
+ * GetFileInformationByHandle minimum supported version: Windows XP and
+ * Windows Server 2003, so it exists everywhere we care about.
+ */
+ if (!GetFileInformationByHandle(hFile, &fiData))
+ {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ if (fiData.ftLastWriteTime.dwLowDateTime ||
+ fiData.ftLastWriteTime.dwHighDateTime)
+ buf->st_mtime = filetime_to_time(&fiData.ftLastWriteTime);
+
+ if (fiData.ftLastAccessTime.dwLowDateTime ||
+ fiData.ftLastAccessTime.dwHighDateTime)
+ buf->st_atime = filetime_to_time(&fiData.ftLastAccessTime);
+ else
+ buf->st_atime = buf->st_mtime;
+
+ if (fiData.ftCreationTime.dwLowDateTime ||
+ fiData.ftCreationTime.dwHighDateTime)
+ buf->st_ctime = filetime_to_time(&fiData.ftCreationTime);
+ else
+ buf->st_ctime = buf->st_mtime;
+
+ buf->st_mode = fileattr_to_unixmode(fiData.dwFileAttributes);
+ buf->st_nlink = fiData.nNumberOfLinks;
+
+ buf->st_size = ((((uint64) fiData.nFileSizeHigh) << 32) |
+ fiData.nFileSizeLow);
+
+ return 0;
+}
+
+/*
+ * Windows implementation of stat().
+ *
+ * This currently also implements lstat(), though perhaps that should change.
+ */
+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.
+ */
+ 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);
+ 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);
+ return ret;
+}
+
+/*
+ * Windows implementation of fstat().
+ */
+int
+_pgfstat64(int fileno, struct stat *buf)
+{
+ HANDLE hFile = (HANDLE) _get_osfhandle(fileno);
+ BY_HANDLE_FILE_INFORMATION fiData;
+
+ if (hFile == INVALID_HANDLE_VALUE || buf == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Check if the fileno is a data stream. If so, unless it has been
+ * redirected to a file, getting information through its HANDLE will fail,
+ * so emulate its stat information in the most appropriate way and return
+ * it instead.
+ */
+ if ((fileno == _fileno(stdin) ||
+ fileno == _fileno(stdout) ||
+ fileno == _fileno(stderr)) &&
+ !GetFileInformationByHandle(hFile, &fiData))
+ {
+ memset(buf, 0, sizeof(*buf));
+ buf->st_mode = _S_IFCHR;
+ buf->st_dev = fileno;
+ buf->st_rdev = fileno;
+ buf->st_nlink = 1;
+ return 0;
+ }
+
+ /*
+ * Since we already have a file handle there is no need to check for
+ * ERROR_DELETE_PENDING.
+ */
+
+ return fileinfo_to_stat(hFile, buf);
+}
+
+#endif /* WIN32 */