1*433d6423SLionel Sambuc #include <sys/cdefs.h> 2*433d6423SLionel Sambuc #include <lib.h> 3*433d6423SLionel Sambuc #include "namespace.h" 4*433d6423SLionel Sambuc 5*433d6423SLionel Sambuc #include <assert.h> 6*433d6423SLionel Sambuc #include <errno.h> 7*433d6423SLionel Sambuc #include <limits.h> 8*433d6423SLionel Sambuc #include <stdlib.h> 9*433d6423SLionel Sambuc #include <string.h> 10*433d6423SLionel Sambuc #include <sys/stat.h> 11*433d6423SLionel Sambuc #include <sys/param.h> 12*433d6423SLionel Sambuc #include <sys/uio.h> 13*433d6423SLionel Sambuc #include <unistd.h> 14*433d6423SLionel Sambuc 15*433d6423SLionel Sambuc #define VECTORIO_READ 1 16*433d6423SLionel Sambuc #define VECTORIO_WRITE 2 17*433d6423SLionel Sambuc 18*433d6423SLionel Sambuc static ssize_t vectorio_buffer(int fildes, const struct iovec *iov, 19*433d6423SLionel Sambuc int iovcnt, int readwrite, ssize_t totallen) 20*433d6423SLionel Sambuc { 21*433d6423SLionel Sambuc char *buffer; 22*433d6423SLionel Sambuc int iovidx, errno_saved; 23*433d6423SLionel Sambuc ssize_t copied, len, r; 24*433d6423SLionel Sambuc 25*433d6423SLionel Sambuc /* allocate buffer */ 26*433d6423SLionel Sambuc buffer = (char *) malloc(totallen); 27*433d6423SLionel Sambuc if (!buffer) 28*433d6423SLionel Sambuc return -1; 29*433d6423SLionel Sambuc 30*433d6423SLionel Sambuc /* perform the actual read/write for the entire buffer */ 31*433d6423SLionel Sambuc switch (readwrite) 32*433d6423SLionel Sambuc { 33*433d6423SLionel Sambuc case VECTORIO_READ: 34*433d6423SLionel Sambuc /* first read, then copy buffers (only part read) */ 35*433d6423SLionel Sambuc r = read(fildes, buffer, totallen); 36*433d6423SLionel Sambuc 37*433d6423SLionel Sambuc copied = 0; 38*433d6423SLionel Sambuc iovidx = 0; 39*433d6423SLionel Sambuc while (copied < r) 40*433d6423SLionel Sambuc { 41*433d6423SLionel Sambuc assert(iovidx < iovcnt); 42*433d6423SLionel Sambuc len = MIN(r - copied, iov[iovidx].iov_len); 43*433d6423SLionel Sambuc memcpy(iov[iovidx++].iov_base, buffer + copied, len); 44*433d6423SLionel Sambuc copied += len; 45*433d6423SLionel Sambuc } 46*433d6423SLionel Sambuc assert(r < 0 || r == copied); 47*433d6423SLionel Sambuc break; 48*433d6423SLionel Sambuc 49*433d6423SLionel Sambuc case VECTORIO_WRITE: 50*433d6423SLionel Sambuc /* first copy buffers, then write */ 51*433d6423SLionel Sambuc copied = 0; 52*433d6423SLionel Sambuc for (iovidx = 0; iovidx < iovcnt; iovidx++) 53*433d6423SLionel Sambuc { 54*433d6423SLionel Sambuc memcpy(buffer + copied, iov[iovidx].iov_base, 55*433d6423SLionel Sambuc iov[iovidx].iov_len); 56*433d6423SLionel Sambuc copied += iov[iovidx].iov_len; 57*433d6423SLionel Sambuc } 58*433d6423SLionel Sambuc assert(copied == totallen); 59*433d6423SLionel Sambuc 60*433d6423SLionel Sambuc r = write(fildes, buffer, totallen); 61*433d6423SLionel Sambuc break; 62*433d6423SLionel Sambuc 63*433d6423SLionel Sambuc default: 64*433d6423SLionel Sambuc assert(0); 65*433d6423SLionel Sambuc errno = EINVAL; 66*433d6423SLionel Sambuc r = -1; 67*433d6423SLionel Sambuc } 68*433d6423SLionel Sambuc 69*433d6423SLionel Sambuc /* free the buffer, keeping errno unchanged */ 70*433d6423SLionel Sambuc errno_saved = errno; 71*433d6423SLionel Sambuc free(buffer); 72*433d6423SLionel Sambuc errno = errno_saved; 73*433d6423SLionel Sambuc 74*433d6423SLionel Sambuc return r; 75*433d6423SLionel Sambuc } 76*433d6423SLionel Sambuc 77*433d6423SLionel Sambuc static ssize_t vectorio(int fildes, const struct iovec *iov, 78*433d6423SLionel Sambuc int iovcnt, int readwrite) 79*433d6423SLionel Sambuc { 80*433d6423SLionel Sambuc int i; 81*433d6423SLionel Sambuc ssize_t totallen; 82*433d6423SLionel Sambuc 83*433d6423SLionel Sambuc /* parameter sanity checks */ 84*433d6423SLionel Sambuc if (iovcnt > IOV_MAX) 85*433d6423SLionel Sambuc { 86*433d6423SLionel Sambuc errno = EINVAL; 87*433d6423SLionel Sambuc return -1; 88*433d6423SLionel Sambuc } 89*433d6423SLionel Sambuc 90*433d6423SLionel Sambuc totallen = 0; 91*433d6423SLionel Sambuc for (i = 0; i < iovcnt; i++) 92*433d6423SLionel Sambuc { 93*433d6423SLionel Sambuc /* don't read/write anything in case of possible overflow */ 94*433d6423SLionel Sambuc if ((ssize_t) (totallen + iov[i].iov_len) < totallen) 95*433d6423SLionel Sambuc { 96*433d6423SLionel Sambuc errno = EINVAL; 97*433d6423SLionel Sambuc return -1; 98*433d6423SLionel Sambuc } 99*433d6423SLionel Sambuc totallen += iov[i].iov_len; 100*433d6423SLionel Sambuc 101*433d6423SLionel Sambuc /* report on NULL pointers */ 102*433d6423SLionel Sambuc if (iov[i].iov_len && !iov[i].iov_base) 103*433d6423SLionel Sambuc { 104*433d6423SLionel Sambuc errno = EFAULT; 105*433d6423SLionel Sambuc return -1; 106*433d6423SLionel Sambuc } 107*433d6423SLionel Sambuc } 108*433d6423SLionel Sambuc 109*433d6423SLionel Sambuc /* anything to do? */ 110*433d6423SLionel Sambuc if (totallen == 0) 111*433d6423SLionel Sambuc return 0; 112*433d6423SLionel Sambuc 113*433d6423SLionel Sambuc /* 114*433d6423SLionel Sambuc * there aught to be a system call here; instead we use an intermediate 115*433d6423SLionel Sambuc * buffer; this is preferred over multiple read/write calls because 116*433d6423SLionel Sambuc * this function has to be atomic 117*433d6423SLionel Sambuc */ 118*433d6423SLionel Sambuc return vectorio_buffer(fildes, iov, iovcnt, readwrite, totallen); 119*433d6423SLionel Sambuc } 120*433d6423SLionel Sambuc 121*433d6423SLionel Sambuc ssize_t readv(int fildes, const struct iovec *iov, int iovcnt) 122*433d6423SLionel Sambuc { 123*433d6423SLionel Sambuc return vectorio(fildes, iov, iovcnt, VECTORIO_READ); 124*433d6423SLionel Sambuc } 125*433d6423SLionel Sambuc 126*433d6423SLionel Sambuc ssize_t writev(int fildes, const struct iovec *iov, int iovcnt) 127*433d6423SLionel Sambuc { 128*433d6423SLionel Sambuc return vectorio(fildes, iov, iovcnt, VECTORIO_WRITE); 129*433d6423SLionel Sambuc } 130*433d6423SLionel Sambuc 131