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