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