From 2394d026016797231a0e5595460db5a040c04ae2 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Sat, 3 Nov 2018 23:11:29 +1300
Subject: [PATCH 1/3] Supply pread()/pwrite() where missing.

Emulate POSIX pread()/pwrite() with lseek() or Win32 OVERLAPPED.
The emulation is not perfect, as the file position is changed, but
that is OK as long as we don't mix read() and pread() calls on the
same fd.

Author: Thomas Munro
Reviewed-by:
Discussion: https://postgr.es/m/CAEepm=02rapCpPR3ZGF2vW=SBHSdFYO_bz_f-wwWJonmA3APgw@mail.gmail.com
---
 configure                     | 47 +++++++++++++++++++++++++++++
 configure.in                  |  3 ++
 src/include/pg_config.h.in    | 14 +++++++++
 src/include/pg_config.h.win32 | 14 +++++++++
 src/include/port.h            |  8 +++++
 src/port/pread.c              | 56 +++++++++++++++++++++++++++++++++++
 src/port/pwrite.c             | 56 +++++++++++++++++++++++++++++++++++
 src/tools/msvc/Mkvcbuild.pm   |  1 +
 8 files changed, 199 insertions(+)
 create mode 100644 src/port/pread.c
 create mode 100644 src/port/pwrite.c

diff --git a/configure b/configure
index 0686941331c..d42fb317513 100755
--- a/configure
+++ b/configure
@@ -15309,6 +15309,27 @@ cat >>confdefs.h <<_ACEOF
 #define HAVE_DECL_STRNLEN $ac_have_decl
 _ACEOF
 
+ac_fn_c_check_decl "$LINENO" "pread" "ac_cv_have_decl_pread" "$ac_includes_default"
+if test "x$ac_cv_have_decl_pread" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PREAD $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "pwrite" "ac_cv_have_decl_pwrite" "$ac_includes_default"
+if test "x$ac_cv_have_decl_pwrite" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PWRITE $ac_have_decl
+_ACEOF
+
 # This is probably only present on macOS, but may as well check always
 ac_fn_c_check_decl "$LINENO" "F_FULLFSYNC" "ac_cv_have_decl_F_FULLFSYNC" "#include <fcntl.h>
 "
@@ -15543,6 +15564,32 @@ esac
 
 fi
 
+ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread"
+if test "x$ac_cv_func_pread" = xyes; then :
+  $as_echo "#define HAVE_PREAD 1" >>confdefs.h
+
+else
+  case " $LIBOBJS " in
+  *" pread.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS pread.$ac_objext"
+ ;;
+esac
+
+fi
+
+ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite"
+if test "x$ac_cv_func_pwrite" = xyes; then :
+  $as_echo "#define HAVE_PWRITE 1" >>confdefs.h
+
+else
+  case " $LIBOBJS " in
+  *" pwrite.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS pwrite.$ac_objext"
+ ;;
+esac
+
+fi
+
 ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random"
 if test "x$ac_cv_func_random" = xyes; then :
   $as_echo "#define HAVE_RANDOM 1" >>confdefs.h
diff --git a/configure.in b/configure.in
index 7586deb7ee6..2b1513aa436 100644
--- a/configure.in
+++ b/configure.in
@@ -1647,6 +1647,7 @@ fi
 
 AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
 AC_CHECK_DECLS([strlcat, strlcpy, strnlen])
+AC_CHECK_DECLS([pread, pwrite])
 # This is probably only present on macOS, but may as well check always
 AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include <fcntl.h>])
 
@@ -1701,6 +1702,8 @@ AC_REPLACE_FUNCS(m4_normalize([
 	getrusage
 	inet_aton
 	mkdtemp
+	pread
+	pwrite
 	random
 	rint
 	srandom
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 9798bd24b44..2a80368a745 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -158,6 +158,14 @@
    don't. */
 #undef HAVE_DECL_POSIX_FADVISE
 
+/* Define to 1 if you have the declaration of `pread', and to 0 if you don't.
+   */
+#undef HAVE_DECL_PREAD
+
+/* Define to 1 if you have the declaration of `pwrite', and to 0 if you don't.
+   */
+#undef HAVE_DECL_PWRITE
+
 /* Define to 1 if you have the declaration of `RTLD_GLOBAL', and to 0 if you
    don't. */
 #undef HAVE_DECL_RTLD_GLOBAL
@@ -438,6 +446,9 @@
 /* Define to 1 if you have the `ppoll' function. */
 #undef HAVE_PPOLL
 
+/* Define to 1 if you have the `pread' function. */
+#undef HAVE_PREAD
+
 /* Define to 1 if you have the `pstat' function. */
 #undef HAVE_PSTAT
 
@@ -453,6 +464,9 @@
 /* Have PTHREAD_PRIO_INHERIT. */
 #undef HAVE_PTHREAD_PRIO_INHERIT
 
+/* Define to 1 if you have the `pwrite' function. */
+#undef HAVE_PWRITE
+
 /* Define to 1 if you have the `random' function. */
 #undef HAVE_RANDOM
 
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index f7a051d1127..f857661ef2f 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -147,6 +147,14 @@
    don't. */
 #define HAVE_DECL_STRTOULL 1
 
+/* Define to 1 if you have the declaration of `pread', and to 0 if you don't.
+   */
+#define HAVE_DECL_PREAD 0
+
+/* Define to 1 if you have the declaration of `pwrite', and to 0 if you don't.
+   */
+#define HAVE_DECL_PWRITE 0
+
 /* Define to 1 if you have the `dlopen' function. */
 /* #undef HAVE_DLOPEN */
 
@@ -322,12 +330,18 @@
 /* Define to 1 if you have the `ppoll' function. */
 /* #undef HAVE_PPOLL */
 
+/* Define to 1 if you have the `pread' function. */
+/* #undef HAVE_PREAD */
+
 /* Define to 1 if you have the `pstat' function. */
 /* #undef HAVE_PSTAT */
 
 /* Define to 1 if the PS_STRINGS thing exists. */
 /* #undef HAVE_PS_STRINGS */
 
+/* Define to 1 if you have the `pwrite' function. */
+/* #undef HAVE_PWRITE */
+
 /* Define to 1 if you have the `random' function. */
 /* #undef HAVE_RANDOM */
 
diff --git a/src/include/port.h b/src/include/port.h
index 3a53bcf2e4b..bcf03a5a7ac 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -392,6 +392,14 @@ extern double rint(double x);
 extern int	inet_aton(const char *cp, struct in_addr *addr);
 #endif
 
+#if !HAVE_DECL_PREAD
+extern ssize_t pread(int fd, void *buf, size_t nbyte, off_t offset);
+#endif
+
+#if !HAVE_DECL_PWRITE
+extern ssize_t pwrite(int fd, const void *buf, size_t nbyte, off_t offset);
+#endif
+
 #if !HAVE_DECL_STRLCAT
 extern size_t strlcat(char *dst, const char *src, size_t siz);
 #endif
diff --git a/src/port/pread.c b/src/port/pread.c
new file mode 100644
index 00000000000..6844353fc97
--- /dev/null
+++ b/src/port/pread.c
@@ -0,0 +1,56 @@
+/*-------------------------------------------------------------------------
+ *
+ * pread.c
+ *	  Implementation of pread(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/port/pread.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX function, so should not be mixed with regular read() calls
+ * on the same file descriptor.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+ssize_t
+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 = (uint32) offset;
+	if (!ReadFile(handle, buf, size, &result, &overlapped))
+	{
+		_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/src/port/pwrite.c b/src/port/pwrite.c
new file mode 100644
index 00000000000..50217a767b8
--- /dev/null
+++ b/src/port/pwrite.c
@@ -0,0 +1,56 @@
+/*-------------------------------------------------------------------------
+ *
+ * pwrite.c
+ *	  Implementation of pwrite(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/port/pwrite.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX function, so should not be mixed with regular write() calls
+ * on the same file descriptor.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+ssize_t
+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/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 708579d9dfb..b562044fa71 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -97,6 +97,7 @@ sub mkvcbuild
 	  srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
 	  erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
 	  dirent.c dlopen.c getopt.c getopt_long.c
+	  pread.c pwrite.c
 	  pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
 	  pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
 	  sprompt.c strerror.c tar.c thread.c
-- 
2.19.1

