xref: /minix3/minix/lib/libc/sys/vectorio.c (revision 0df28c9fa4ef5089bb1cdfdcfea7906456fefd3e)
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