1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include <lib.h>
3433d6423SLionel Sambuc #include "namespace.h"
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #include <assert.h>
6433d6423SLionel Sambuc #include <errno.h>
7433d6423SLionel Sambuc #include <limits.h>
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <string.h>
10433d6423SLionel Sambuc #include <sys/stat.h>
11433d6423SLionel Sambuc #include <sys/param.h>
12433d6423SLionel Sambuc #include <sys/uio.h>
13433d6423SLionel Sambuc #include <unistd.h>
14433d6423SLionel Sambuc
15*0df28c9fSDavid van Moolenbroek /*
16*0df28c9fSDavid van Moolenbroek * Create a single temporary buffer for the entire vector. For writes, also
17*0df28c9fSDavid van Moolenbroek * copy the actual data into the temporary buffer.
18*0df28c9fSDavid van Moolenbroek */
19*0df28c9fSDavid van Moolenbroek ssize_t
_vectorio_setup(const struct iovec * iov,int iovcnt,char ** ptr,int op)20*0df28c9fSDavid van Moolenbroek _vectorio_setup(const struct iovec * iov, int iovcnt, char ** ptr, int op)
21433d6423SLionel Sambuc {
22433d6423SLionel Sambuc char *buffer;
23*0df28c9fSDavid van Moolenbroek ssize_t totallen, copied;
24433d6423SLionel Sambuc int i;
25433d6423SLionel Sambuc
26*0df28c9fSDavid van Moolenbroek /* Parameter sanity checks. */
27*0df28c9fSDavid van Moolenbroek if (iovcnt < 0 || iovcnt > IOV_MAX) {
28433d6423SLionel Sambuc errno = EINVAL;
29433d6423SLionel Sambuc return -1;
30433d6423SLionel Sambuc }
31433d6423SLionel Sambuc
32433d6423SLionel Sambuc totallen = 0;
33*0df28c9fSDavid van Moolenbroek for (i = 0; i < iovcnt; i++) {
34*0df28c9fSDavid van Moolenbroek /* Do not read/write anything in case of possible overflow. */
35*0df28c9fSDavid van Moolenbroek if ((size_t)SSIZE_MAX - totallen < iov[i].iov_len) {
36433d6423SLionel Sambuc errno = EINVAL;
37433d6423SLionel Sambuc return -1;
38433d6423SLionel Sambuc }
39433d6423SLionel Sambuc totallen += iov[i].iov_len;
40433d6423SLionel Sambuc
41*0df28c9fSDavid van Moolenbroek /* Report on NULL pointers. */
42*0df28c9fSDavid van Moolenbroek if (iov[i].iov_len > 0 && iov[i].iov_base == NULL) {
43433d6423SLionel Sambuc errno = EFAULT;
44433d6423SLionel Sambuc return -1;
45433d6423SLionel Sambuc }
46433d6423SLionel Sambuc }
47433d6423SLionel Sambuc
48*0df28c9fSDavid van Moolenbroek /* Anything to do? */
49*0df28c9fSDavid van Moolenbroek if (totallen == 0) {
50*0df28c9fSDavid van Moolenbroek *ptr = NULL;
51433d6423SLionel Sambuc return 0;
52*0df28c9fSDavid van Moolenbroek }
53*0df28c9fSDavid van Moolenbroek
54*0df28c9fSDavid van Moolenbroek /* Allocate a temporary buffer. */
55*0df28c9fSDavid van Moolenbroek buffer = (char *)malloc(totallen);
56*0df28c9fSDavid van Moolenbroek if (buffer == NULL)
57*0df28c9fSDavid van Moolenbroek return -1;
58*0df28c9fSDavid van Moolenbroek
59*0df28c9fSDavid van Moolenbroek /* For writes, copy over the buffer contents before the call. */
60*0df28c9fSDavid van Moolenbroek if (op == _VECTORIO_WRITE) {
61*0df28c9fSDavid van Moolenbroek copied = 0;
62*0df28c9fSDavid van Moolenbroek for (i = 0; i < iovcnt; i++) {
63*0df28c9fSDavid van Moolenbroek memcpy(buffer + copied, iov[i].iov_base,
64*0df28c9fSDavid van Moolenbroek iov[i].iov_len);
65*0df28c9fSDavid van Moolenbroek copied += iov[i].iov_len;
66*0df28c9fSDavid van Moolenbroek }
67*0df28c9fSDavid van Moolenbroek assert(copied == totallen);
68*0df28c9fSDavid van Moolenbroek }
69*0df28c9fSDavid van Moolenbroek
70*0df28c9fSDavid van Moolenbroek /* Return the temporary buffer and its size. */
71*0df28c9fSDavid van Moolenbroek *ptr = buffer;
72*0df28c9fSDavid van Moolenbroek return totallen;
73*0df28c9fSDavid van Moolenbroek }
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc /*
76*0df28c9fSDavid van Moolenbroek * Clean up the temporary buffer created for the vector. For successful reads,
77*0df28c9fSDavid van Moolenbroek * also copy out the retrieved buffer contents.
78433d6423SLionel Sambuc */
79*0df28c9fSDavid van Moolenbroek void
_vectorio_cleanup(const struct iovec * iov,int iovcnt,char * buffer,ssize_t r,int op)80*0df28c9fSDavid van Moolenbroek _vectorio_cleanup(const struct iovec * iov, int iovcnt, char * buffer,
81*0df28c9fSDavid van Moolenbroek ssize_t r, int op)
82433d6423SLionel Sambuc {
83*0df28c9fSDavid van Moolenbroek int i, errno_saved;
84*0df28c9fSDavid van Moolenbroek ssize_t copied, len;
85*0df28c9fSDavid van Moolenbroek
86*0df28c9fSDavid van Moolenbroek /* Make sure to retain the original errno value in case of failure. */
87*0df28c9fSDavid van Moolenbroek errno_saved = errno;
88*0df28c9fSDavid van Moolenbroek
89*0df28c9fSDavid van Moolenbroek /*
90*0df28c9fSDavid van Moolenbroek * If this was for a read and the read call succeeded, copy out the
91*0df28c9fSDavid van Moolenbroek * resulting data.
92*0df28c9fSDavid van Moolenbroek */
93*0df28c9fSDavid van Moolenbroek if (op == _VECTORIO_READ && r > 0) {
94*0df28c9fSDavid van Moolenbroek assert(buffer != NULL);
95*0df28c9fSDavid van Moolenbroek copied = 0;
96*0df28c9fSDavid van Moolenbroek i = 0;
97*0df28c9fSDavid van Moolenbroek while (copied < r) {
98*0df28c9fSDavid van Moolenbroek assert(i < iovcnt);
99*0df28c9fSDavid van Moolenbroek len = iov[i].iov_len;
100*0df28c9fSDavid van Moolenbroek if (len > r - copied)
101*0df28c9fSDavid van Moolenbroek len = r - copied;
102*0df28c9fSDavid van Moolenbroek memcpy(iov[i++].iov_base, buffer + copied, len);
103*0df28c9fSDavid van Moolenbroek copied += len;
104*0df28c9fSDavid van Moolenbroek }
105*0df28c9fSDavid van Moolenbroek assert(r < 0 || r == copied);
106433d6423SLionel Sambuc }
107433d6423SLionel Sambuc
108*0df28c9fSDavid van Moolenbroek /* Free the temporary buffer. */
109*0df28c9fSDavid van Moolenbroek if (buffer != NULL)
110*0df28c9fSDavid van Moolenbroek free(buffer);
111*0df28c9fSDavid van Moolenbroek
112*0df28c9fSDavid van Moolenbroek errno = errno_saved;
113*0df28c9fSDavid van Moolenbroek }
114*0df28c9fSDavid van Moolenbroek
115*0df28c9fSDavid van Moolenbroek /*
116*0df28c9fSDavid van Moolenbroek * Read a vector.
117*0df28c9fSDavid van Moolenbroek */
118*0df28c9fSDavid van Moolenbroek ssize_t
readv(int fd,const struct iovec * iov,int iovcnt)119*0df28c9fSDavid van Moolenbroek readv(int fd, const struct iovec * iov, int iovcnt)
120433d6423SLionel Sambuc {
121*0df28c9fSDavid van Moolenbroek char *ptr;
122*0df28c9fSDavid van Moolenbroek ssize_t r;
123*0df28c9fSDavid van Moolenbroek
124*0df28c9fSDavid van Moolenbroek /*
125*0df28c9fSDavid van Moolenbroek * There ought to be just a readv system call here. Instead, we use an
126*0df28c9fSDavid van Moolenbroek * intermediate buffer. This approach is preferred over multiple read
127*0df28c9fSDavid van Moolenbroek * calls, because the actual I/O operation has to be atomic.
128*0df28c9fSDavid van Moolenbroek */
129*0df28c9fSDavid van Moolenbroek if ((r = _vectorio_setup(iov, iovcnt, &ptr, _VECTORIO_READ)) <= 0)
130*0df28c9fSDavid van Moolenbroek return r;
131*0df28c9fSDavid van Moolenbroek
132*0df28c9fSDavid van Moolenbroek r = read(fd, ptr, r);
133*0df28c9fSDavid van Moolenbroek
134*0df28c9fSDavid van Moolenbroek _vectorio_cleanup(iov, iovcnt, ptr, r, _VECTORIO_READ);
135*0df28c9fSDavid van Moolenbroek
136*0df28c9fSDavid van Moolenbroek return r;
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc
139*0df28c9fSDavid van Moolenbroek /*
140*0df28c9fSDavid van Moolenbroek * Write a vector.
141*0df28c9fSDavid van Moolenbroek */
142*0df28c9fSDavid van Moolenbroek ssize_t
writev(int fd,const struct iovec * iov,int iovcnt)143*0df28c9fSDavid van Moolenbroek writev(int fd, const struct iovec * iov, int iovcnt)
144*0df28c9fSDavid van Moolenbroek {
145*0df28c9fSDavid van Moolenbroek char *ptr;
146*0df28c9fSDavid van Moolenbroek ssize_t r;
147*0df28c9fSDavid van Moolenbroek
148*0df28c9fSDavid van Moolenbroek /*
149*0df28c9fSDavid van Moolenbroek * There ought to be just a writev system call here. Instead, we use
150*0df28c9fSDavid van Moolenbroek * an intermediate buffer. This approach is preferred over multiple
151*0df28c9fSDavid van Moolenbroek * write calls, because the actual I/O operation has to be atomic.
152*0df28c9fSDavid van Moolenbroek */
153*0df28c9fSDavid van Moolenbroek if ((r = _vectorio_setup(iov, iovcnt, &ptr, _VECTORIO_WRITE)) <= 0)
154*0df28c9fSDavid van Moolenbroek return r;
155*0df28c9fSDavid van Moolenbroek
156*0df28c9fSDavid van Moolenbroek r = write(fd, ptr, r);
157*0df28c9fSDavid van Moolenbroek
158*0df28c9fSDavid van Moolenbroek _vectorio_cleanup(iov, iovcnt, ptr, r, _VECTORIO_WRITE);
159*0df28c9fSDavid van Moolenbroek
160*0df28c9fSDavid van Moolenbroek return r;
161*0df28c9fSDavid van Moolenbroek }
162