11 #include <sys/param.h>
16 * Create a single temporary buffer for the entire vector. For writes, also
17 * copy the actual data into the temporary buffer.
20 _vectorio_setup(const struct iovec
* iov
, int iovcnt
, char ** ptr
, int op
)
23 ssize_t totallen
, copied
;
26 /* Parameter sanity checks. */
27 if (iovcnt
< 0 || iovcnt
> IOV_MAX
) {
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
) {
39 totallen
+= iov
[i
].iov_len
;
41 /* Report on NULL pointers. */
42 if (iov
[i
].iov_len
> 0 && iov
[i
].iov_base
== NULL
) {
54 /* Allocate a temporary buffer. */
55 buffer
= (char *)malloc(totallen
);
59 /* For writes, copy over the buffer contents before the call. */
60 if (op
== _VECTORIO_WRITE
) {
62 for (i
= 0; i
< iovcnt
; i
++) {
63 memcpy(buffer
+ copied
, iov
[i
].iov_base
,
65 copied
+= iov
[i
].iov_len
;
67 assert(copied
== totallen
);
70 /* Return the temporary buffer and its size. */
76 * Clean up the temporary buffer created for the vector. For successful reads,
77 * also copy out the retrieved buffer contents.
80 _vectorio_cleanup(const struct iovec
* iov
, int iovcnt
, char * buffer
,
86 /* Make sure to retain the original errno value in case of failure. */
90 * If this was for a read and the read call succeeded, copy out the
93 if (op
== _VECTORIO_READ
&& r
> 0) {
94 assert(buffer
!= NULL
);
100 if (len
> r
- copied
)
102 memcpy(iov
[i
++].iov_base
, buffer
+ copied
, len
);
105 assert(r
< 0 || r
== copied
);
108 /* Free the temporary buffer. */
119 readv(int fd
, const struct iovec
* iov
, int iovcnt
)
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)
132 r
= read(fd
, ptr
, r
);
134 _vectorio_cleanup(iov
, iovcnt
, ptr
, r
, _VECTORIO_READ
);
143 writev(int fd
, const struct iovec
* iov
, int iovcnt
)
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)
156 r
= write(fd
, ptr
, r
);
158 _vectorio_cleanup(iov
, iovcnt
, ptr
, r
, _VECTORIO_WRITE
);