Make the sys/uio.h portability header work for Windows
authorChristopher Dykes <cdykes@fb.com>
Wed, 11 May 2016 23:55:28 +0000 (16:55 -0700)
committerFacebook Github Bot 0 <facebook-github-bot-0-bot@fb.com>
Thu, 12 May 2016 00:05:21 +0000 (17:05 -0700)
Summary: Windows doesn't have sys/uio.h, so implement it. This doesn't adjust any includes of it yet, I'll leave that for a separate diff.

Reviewed By: yfeldblum

Differential Revision: D2978042

fbshipit-source-id: 16d398a856de50b6c662f739eb11dfb851096592

folly/FileUtil.cpp
folly/FileUtil.h
folly/Makefile.am
folly/Portability.h
folly/configure.ac
folly/portability/SysUio.cpp [new file with mode: 0755]
folly/portability/SysUio.h
folly/test/FileUtilTest.cpp

index 26525debb09a394c74cdd239760f8448443f6861..f814ddad1c0fa0a95cfbfec7de5afa7f79ddcdcd 100644 (file)
@@ -132,20 +132,16 @@ ssize_t readvFull(int fd, iovec* iov, int count) {
   return wrapvFull(readv, fd, iov, count);
 }
 
-#if FOLLY_HAVE_PREADV
 ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset) {
   return wrapvFull(preadv, fd, iov, count, offset);
 }
-#endif
 
 ssize_t writevFull(int fd, iovec* iov, int count) {
   return wrapvFull(writev, fd, iov, count);
 }
 
-#if FOLLY_HAVE_PWRITEV
 ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset) {
   return wrapvFull(pwritev, fd, iov, count, offset);
 }
-#endif
 
 }  // namespaces
index a28b0477971d8eb3319ebd50d0ca0e7e37d5292b..de250aefdd0f997dcf6af01f9a1b48d0c4a64c6c 100644 (file)
 #include <folly/Conv.h>
 #include <folly/Portability.h>
 #include <folly/ScopeGuard.h>
+#include <folly/portability/SysUio.h>
 
 #include <cassert>
 #include <limits>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/uio.h>
 #include <fcntl.h>
 #include <unistd.h>
 
@@ -80,9 +80,7 @@ ssize_t writevNoInt(int fd, const iovec* iov, int count);
 ssize_t readFull(int fd, void* buf, size_t n);
 ssize_t preadFull(int fd, void* buf, size_t n, off_t offset);
 ssize_t readvFull(int fd, iovec* iov, int count);
-#if FOLLY_HAVE_PREADV
 ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
-#endif
 
 /**
  * Similar to readFull and preadFull above, wrappers around write() and
@@ -101,9 +99,7 @@ ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
 ssize_t writeFull(int fd, const void* buf, size_t n);
 ssize_t pwriteFull(int fd, const void* buf, size_t n, off_t offset);
 ssize_t writevFull(int fd, iovec* iov, int count);
-#if FOLLY_HAVE_PWRITEV
 ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset);
-#endif
 
 /**
  * Read entire file (if num_bytes is defaulted) or no more than
index b3b355f25b3596a51abefb0e9d56179d0d14f354..178d49fefc37912784e50a48b094389703c8e2b2 100644 (file)
@@ -446,6 +446,7 @@ libfolly_la_SOURCES = \
        portability/SysResource.cpp \
        portability/SysStat.cpp \
        portability/SysTime.cpp \
+       portability/SysUio.cpp \
        portability/Time.cpp \
        portability/Unistd.cpp \
        Random.cpp \
index c9616ea7caa23dcaa304007be149877249218b88..55c5dd5ca8b9a11f818acd0cfda8dd82338b5843 100644 (file)
@@ -200,16 +200,6 @@ namespace std { typedef ::max_align_t max_align_t; }
 #undef FOLLY_TLS
 #endif
 
-// Define to 1 if you have the `preadv' and `pwritev' functions, respectively
-#if !defined(FOLLY_HAVE_PREADV) && !defined(FOLLY_HAVE_PWRITEV)
-# if defined(__GLIBC_PREREQ)
-#  if __GLIBC_PREREQ(2, 10)
-#   define FOLLY_HAVE_PREADV 1
-#   define FOLLY_HAVE_PWRITEV 1
-#  endif
-# endif
-#endif
-
 // It turns out that GNU libstdc++ and LLVM libc++ differ on how they implement
 // the 'std' namespace; the latter uses inline namespaces. Wrap this decision
 // up in a macro to make forward-declarations easier.
index af1bbb4a204c39da41696047cb8cbd7c3a9ffd5f..c2670fd00e1c106e6a13ba6075bdf734696be135 100644 (file)
@@ -478,7 +478,10 @@ AC_CHECK_FUNCS([getdelim \
                 malloc_size \
                 malloc_usable_size \
                 memrchr \
-                pipe2])
+                pipe2 \
+                preadv \
+                pwritev \
+              ])
 
 AC_CHECK_HEADER([lz4.h], AC_CHECK_LIB([lz4], [LZ4_decompress_safe]))
 AC_CHECK_HEADER([snappy.h], AC_CHECK_LIB([snappy], [main]))
diff --git a/folly/portability/SysUio.cpp b/folly/portability/SysUio.cpp
new file mode 100755 (executable)
index 0000000..1a51728
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/portability/SysUio.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <folly/ScopeGuard.h>
+#include <folly/portability/SysFile.h>
+#include <folly/portability/Unistd.h>
+
+template <class F, class... Args>
+static int wrapPositional(F f, int fd, off_t offset, Args... args) {
+  off_t origLoc = lseek(fd, 0, SEEK_CUR);
+  if (origLoc == off_t(-1)) {
+    return -1;
+  }
+  if (lseek(fd, offset, SEEK_SET) == off_t(-1)) {
+    return -1;
+  }
+
+  int res = (int)f(fd, args...);
+
+  int curErrNo = errno;
+  if (lseek(fd, origLoc, SEEK_SET) == off_t(-1)) {
+    if (res == -1) {
+      errno = curErrNo;
+    }
+    return -1;
+  }
+  errno = curErrNo;
+
+  return res;
+}
+
+#if defined(FOLLY_HAVE_PREADV) && !FOLLY_HAVE_PREADV
+extern "C" ssize_t preadv(int fd, const iovec* iov, int count, off_t offset) {
+  return wrapPositional(readv, fd, offset, iov, count);
+}
+#endif
+
+#if defined(FOLLY_HAVE_PWRITEV) && !FOLLY_HAVE_PWRITEV
+extern "C" ssize_t pwritev(int fd, const iovec* iov, int count, off_t offset) {
+  return wrapPositional(writev, fd, offset, iov, count);
+}
+#endif
+
+#ifdef _WIN32
+template <bool isRead>
+static ssize_t doVecOperation(int fd, const iovec* iov, int count) {
+  if (!count) {
+    return 0;
+  }
+  if (count < 0 || count > folly::kIovMax) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (lockf(fd, F_LOCK, 0) == -1) {
+    return -1;
+  }
+  SCOPE_EXIT { lockf(fd, F_ULOCK, 0); };
+
+  ssize_t bytesProcessed = 0;
+  int curIov = 0;
+  void* curBase = iov[0].iov_base;
+  size_t curLen = iov[0].iov_len;
+  while (curIov < count) {
+    int res = 0;
+    if (isRead) {
+      res = read(fd, curBase, (unsigned int)curLen);
+      if (res == 0 && curLen != 0) {
+        break; // End of File
+      }
+    } else {
+      res = write(fd, curBase, (unsigned int)curLen);
+      // Write of zero bytes is fine.
+    }
+
+    if (res == -1) {
+      return -1;
+    }
+
+    if (res == curLen) {
+      curIov++;
+      if (curIov < count) {
+        curBase = iov[curIov].iov_base;
+        curLen = iov[curIov].iov_len;
+      }
+    } else {
+      curBase += (void*)((char*)curBase + res);
+      curLen -= res;
+    }
+
+    if (bytesProcessed + res < 0) {
+      // Overflow
+      errno = EINVAL;
+      return -1;
+    }
+    bytesProcessed += res;
+  }
+
+  return bytesProcessed;
+}
+
+extern "C" ssize_t readv(int fd, const iovec* iov, int count) {
+  return doVecOperation<true>(fd, iov, count);
+}
+
+extern "C" ssize_t writev(int fd, const iovec* iov, int count) {
+  return doVecOperation<false>(fd, iov, count);
+}
+#endif
index 9640f6803410b81a11f9529ca30092dad5177b4b..aa243d51d7eed841ef1b026be16382fb41f22100 100644 (file)
 
 #pragma once
 
-#include <sys/uio.h>
+#include <folly/portability/Config.h>
+#include <folly/portability/IOVec.h>
+#include <folly/portability/SysTypes.h>
 
-namespace folly {
+#if defined(FOLLY_HAVE_PREADV) && !FOLLY_HAVE_PREADV
+extern "C" ssize_t preadv(int fd, const iovec* iov, int count, off_t offset);
+#endif
+#if defined(FOLLY_HAVE_PWRITEV) && !FOLLY_HAVE_PWRITEV
+extern "C" ssize_t pwritev(int fd, const iovec* iov, int count, off_t offset);
+#endif
 
+#ifdef _WIN32
+extern "C" ssize_t readv(int fd, const iovec* iov, int count);
+extern "C" ssize_t writev(int fd, const iovec* iov, int count);
+#endif
+
+namespace folly {
 #ifdef IOV_MAX // not defined on Android
 constexpr size_t kIovMax = IOV_MAX;
 #else
index 6a7f5e2ea57a759046629e5bc03527f4e54ddbc0..23a49f96faf1d4762bee91dc54f92a376f4c6bbf 100644 (file)
@@ -250,7 +250,6 @@ TEST(FileUtilTest2, wrapv) {
   EXPECT_EQ(sum, wrapvFull(writev, tempFile.fd(), iov.data(), iov.size()));
 }
 
-#if FOLLY_HAVE_PREADV
 TEST_F(FileUtilTest, preadv) {
   for (auto& p : readers_) {
     IovecBuffers buf({12, 19, 31});
@@ -264,7 +263,6 @@ TEST_F(FileUtilTest, preadv) {
     }
   }
 }
-#endif
 
 TEST(String, readFile) {
   srand(time(nullptr));