#include <folly/portability/SysUio.h>
#include <cerrno>
#include <cstdio>
#include <folly/ScopeGuard.h>
#include <folly/portability/Sockets.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) { … }
namespace {
#if !FOLLY_HAVE_PREADV
ssize_t preadv_fallback(int fd, const iovec* iov, int count, off_t offset) {
return static_cast<ssize_t>(wrapPositional(readv, fd, offset, iov, count));
}
#endif
#if !FOLLY_HAVE_PWRITEV
ssize_t pwritev_fallback(int fd, const iovec* iov, int count, off_t offset) {
return static_cast<ssize_t>(wrapPositional(writev, fd, offset, iov, count));
}
#endif
}
namespace folly {
#if !FOLLY_HAVE_PREADV
ssize_t preadv(int fd, const iovec* iov, int count, off_t offset) {
using sig = ssize_t(int, const iovec*, int, off_t);
static auto the_preadv = []() -> sig* {
#if defined(__APPLE__) && FOLLY_HAS_BUILTIN(__builtin_available) && \
!TARGET_OS_SIMULATOR && \
(__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600 || \
__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000)
if (__builtin_available(iOS 14.0, macOS 11.0, watchOS 7.0, tvOS 14.0, *)) {
return &::preadv;
}
#endif
return &preadv_fallback;
}();
return the_preadv(fd, iov, count, offset);
}
#endif
#if !FOLLY_HAVE_PWRITEV
ssize_t pwritev(int fd, const iovec* iov, int count, off_t offset) {
using sig = ssize_t(int, const iovec*, int, off_t);
static auto the_pwritev = []() -> sig* {
#if defined(__APPLE__) && FOLLY_HAS_BUILTIN(__builtin_available) && \
!TARGET_OS_SIMULATOR && \
(__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600 || \
__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000)
if (__builtin_available(iOS 14.0, macOS 11.0, watchOS 7.0, tvOS 14.0, *)) {
return &::pwritev;
}
#endif
return &pwritev_fallback;
}();
return the_pwritev(fd, iov, count, offset);
}
#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;
}
bool shouldLock = !folly::portability::sockets::is_fh_socket(fd);
if (shouldLock && lockf(fd, F_LOCK, 0) == -1) {
return -1;
}
SCOPE_EXIT {
if (shouldLock) {
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) {
ssize_t res = 0;
if (isRead) {
res = read(fd, curBase, (unsigned int)curLen);
if (res == 0 && curLen != 0) {
break;
}
} else {
res = write(fd, curBase, (unsigned int)curLen);
}
if (res == -1) {
return -1;
}
if (size_t(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) {
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