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
#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>
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
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
portability/SysResource.cpp \
portability/SysStat.cpp \
portability/SysTime.cpp \
+ portability/SysUio.cpp \
portability/Time.cpp \
portability/Unistd.cpp \
Random.cpp \
#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.
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]))
--- /dev/null
+/*
+ * 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
#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
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});
}
}
}
-#endif
TEST(String, readFile) {
srand(time(nullptr));