#include #include #include "namespace.h" #include #include #include #include #include #include #include #include #include #define VECTORIO_READ 1 #define VECTORIO_WRITE 2 static ssize_t vectorio_buffer(int fildes, const struct iovec *iov, int iovcnt, int readwrite, ssize_t totallen) { char *buffer; int iovidx, errno_saved; ssize_t copied, len, r; /* allocate buffer */ buffer = (char *) malloc(totallen); if (!buffer) return -1; /* perform the actual read/write for the entire buffer */ switch (readwrite) { case VECTORIO_READ: /* first read, then copy buffers (only part read) */ r = read(fildes, buffer, totallen); copied = 0; iovidx = 0; while (copied < r) { assert(iovidx < iovcnt); len = MIN(r - copied, iov[iovidx].iov_len); memcpy(iov[iovidx++].iov_base, buffer + copied, len); copied += len; } assert(r < 0 || r == copied); break; case VECTORIO_WRITE: /* first copy buffers, then write */ copied = 0; for (iovidx = 0; iovidx < iovcnt; iovidx++) { memcpy(buffer + copied, iov[iovidx].iov_base, iov[iovidx].iov_len); copied += iov[iovidx].iov_len; } assert(copied == totallen); r = write(fildes, buffer, totallen); break; default: assert(0); errno = EINVAL; r = -1; } /* free the buffer, keeping errno unchanged */ errno_saved = errno; free(buffer); errno = errno_saved; return r; } static ssize_t vectorio(int fildes, const struct iovec *iov, int iovcnt, int readwrite) { int i; ssize_t totallen; /* parameter sanity checks */ if (iovcnt > IOV_MAX) { errno = EINVAL; return -1; } totallen = 0; for (i = 0; i < iovcnt; i++) { /* don't read/write anything in case of possible overflow */ if ((ssize_t) (totallen + iov[i].iov_len) < totallen) { errno = EINVAL; return -1; } totallen += iov[i].iov_len; /* report on NULL pointers */ if (iov[i].iov_len && !iov[i].iov_base) { errno = EFAULT; return -1; } } /* anything to do? */ if (totallen == 0) return 0; /* * there aught to be a system call here; instead we use an intermediate * buffer; this is preferred over multiple read/write calls because * this function has to be atomic */ return vectorio_buffer(fildes, iov, iovcnt, readwrite, totallen); } ssize_t readv(int fildes, const struct iovec *iov, int iovcnt) { return vectorio(fildes, iov, iovcnt, VECTORIO_READ); } ssize_t writev(int fildes, const struct iovec *iov, int iovcnt) { return vectorio(fildes, iov, iovcnt, VECTORIO_WRITE); }