etc/services - sync with NetBSD-8
[minix.git] / minix / lib / libc / sys / vectorio.c
blobc8480cfc2a4ad59d0ec2cb99fa4dac9ab9e14923
1 #include <sys/cdefs.h>
2 #include <lib.h>
3 #include "namespace.h"
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>
16 * Create a single temporary buffer for the entire vector. For writes, also
17 * copy the actual data into the temporary buffer.
19 ssize_t
20 _vectorio_setup(const struct iovec * iov, int iovcnt, char ** ptr, int op)
22 char *buffer;
23 ssize_t totallen, copied;
24 int i;
26 /* Parameter sanity checks. */
27 if (iovcnt < 0 || iovcnt > IOV_MAX) {
28 errno = EINVAL;
29 return -1;
32 totallen = 0;
33 for (i = 0; i < iovcnt; i++) {
34 /* Do not read/write anything in case of possible overflow. */
35 if ((size_t)SSIZE_MAX - totallen < iov[i].iov_len) {
36 errno = EINVAL;
37 return -1;
39 totallen += iov[i].iov_len;
41 /* Report on NULL pointers. */
42 if (iov[i].iov_len > 0 && iov[i].iov_base == NULL) {
43 errno = EFAULT;
44 return -1;
48 /* Anything to do? */
49 if (totallen == 0) {
50 *ptr = NULL;
51 return 0;
54 /* Allocate a temporary buffer. */
55 buffer = (char *)malloc(totallen);
56 if (buffer == NULL)
57 return -1;
59 /* For writes, copy over the buffer contents before the call. */
60 if (op == _VECTORIO_WRITE) {
61 copied = 0;
62 for (i = 0; i < iovcnt; i++) {
63 memcpy(buffer + copied, iov[i].iov_base,
64 iov[i].iov_len);
65 copied += iov[i].iov_len;
67 assert(copied == totallen);
70 /* Return the temporary buffer and its size. */
71 *ptr = buffer;
72 return totallen;
76 * Clean up the temporary buffer created for the vector. For successful reads,
77 * also copy out the retrieved buffer contents.
79 void
80 _vectorio_cleanup(const struct iovec * iov, int iovcnt, char * buffer,
81 ssize_t r, int op)
83 int i, errno_saved;
84 ssize_t copied, len;
86 /* Make sure to retain the original errno value in case of failure. */
87 errno_saved = errno;
90 * If this was for a read and the read call succeeded, copy out the
91 * resulting data.
93 if (op == _VECTORIO_READ && r > 0) {
94 assert(buffer != NULL);
95 copied = 0;
96 i = 0;
97 while (copied < r) {
98 assert(i < iovcnt);
99 len = iov[i].iov_len;
100 if (len > r - copied)
101 len = r - copied;
102 memcpy(iov[i++].iov_base, buffer + copied, len);
103 copied += len;
105 assert(r < 0 || r == copied);
108 /* Free the temporary buffer. */
109 if (buffer != NULL)
110 free(buffer);
112 errno = errno_saved;
116 * Read a vector.
118 ssize_t
119 readv(int fd, const struct iovec * iov, int iovcnt)
121 char *ptr;
122 ssize_t r;
125 * There ought to be just a readv system call here. Instead, we use an
126 * intermediate buffer. This approach is preferred over multiple read
127 * calls, because the actual I/O operation has to be atomic.
129 if ((r = _vectorio_setup(iov, iovcnt, &ptr, _VECTORIO_READ)) <= 0)
130 return r;
132 r = read(fd, ptr, r);
134 _vectorio_cleanup(iov, iovcnt, ptr, r, _VECTORIO_READ);
136 return r;
140 * Write a vector.
142 ssize_t
143 writev(int fd, const struct iovec * iov, int iovcnt)
145 char *ptr;
146 ssize_t r;
149 * There ought to be just a writev system call here. Instead, we use
150 * an intermediate buffer. This approach is preferred over multiple
151 * write calls, because the actual I/O operation has to be atomic.
153 if ((r = _vectorio_setup(iov, iovcnt, &ptr, _VECTORIO_WRITE)) <= 0)
154 return r;
156 r = write(fd, ptr, r);
158 _vectorio_cleanup(iov, iovcnt, ptr, r, _VECTORIO_WRITE);
160 return r;