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