From 2394d026016797231a0e5595460db5a040c04ae2 Mon Sep 17 00:00:00 2001 From: Thomas Munro 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 " @@ -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 ]) 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 ]) @@ -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 +#else +#include +#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 +#else +#include +#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