1 /* $Id: xwrite.c 5771 2002-09-17 17:00:05Z alexk $
3 ** write and writev replacements to handle partial writes.
7 ** ssize_t xwrite(int fildes, const void *buf, size_t nbyte);
8 ** ssize_t xpwrite(int fildes, const void *buf, size_t nbyte,
10 ** ssize_t xwritev(int fildes, const struct iovec *iov, int iovcnt);
12 ** xwrite, xpwrite, and xwritev behave exactly like their C library
13 ** counterparts except that, if write or writev succeeds but returns a number
14 ** of bytes written less than the total bytes, the write is repeated picking
15 ** up where it left off until the full amount of the data is written. The
16 ** write is also repeated if it failed with EINTR. The write will be aborted
17 ** after 10 successive writes with no forward progress.
19 ** Both functions return the number of bytes written on success or -1 on an
20 ** error, and will leave errno set to whatever the underlying system call
21 ** set it to. Note that it is possible for a write to fail after some data
22 ** was written, on the subsequent additional write; in that case, these
23 ** functions will return -1 and the number of bytes actually written will
34 /* If we're running the test suite, call testing versions of the write
35 functions. #undef pwrite first because large file support may define a
36 macro pwrite (pointing to pwrite64) on some platforms (e.g. Solaris). */
39 # define pwrite fake_pwrite
40 # define write fake_write
41 # define writev fake_writev
42 ssize_t fake_pwrite(int, const void *, size_t, off_t);
43 ssize_t fake_write(int, const void *, size_t);
44 ssize_t fake_writev(int, const struct iovec *, int);
48 xwrite(int fd, const void *buffer, size_t size)
57 /* Abort the write if we try ten times with no forward progress. */
58 for (total = 0; total < size; total += status) {
61 status = write(fd, (const char *) buffer + total, size - total);
70 return (total < size) ? -1 : (ssize_t) total;
74 xpwrite(int fd, const void *buffer, size_t size, off_t offset)
83 /* Abort the write if we try ten times with no forward progress. */
84 for (total = 0; total < size; total += status) {
87 status = pwrite(fd, (const char *) buffer + total, size - total,
97 return (total < size) ? -1 : (ssize_t) total;
101 xwritev(int fd, const struct iovec iov[], int iovcnt)
103 ssize_t total, status = 0;
105 int iovleft, i, count;
106 struct iovec *tmpiov;
111 /* Get a count of the total number of bytes in the iov array. */
112 for (total = 0, i = 0; i < iovcnt; i++)
113 total += iov[i].iov_len;
118 /* First, try just writing it all out. Most of the time this will
119 succeed and save us lots of work. Abort the write if we try ten times
120 with no forward progress. */
125 status = writev(fd, iov, iovcnt);
128 } while (status < 0 && errno == EINTR);
134 /* If we fell through to here, the first write partially succeeded.
135 Figure out how far through the iov array we got, and then duplicate
136 the rest of it so that we can modify it to reflect how much we manage
137 to write on successive tries. */
139 left = total - offset;
140 for (i = 0; offset >= (size_t) iov[i].iov_len; i++)
141 offset -= iov[i].iov_len;
142 iovleft = iovcnt - i;
143 tmpiov = xmalloc(iovleft * sizeof(struct iovec));
144 memcpy(tmpiov, iov + i, iovleft * sizeof(struct iovec));
146 /* status now contains the offset into the first iovec struct in tmpiov.
147 Go into the write loop, trying to write out everything remaining at
148 each point. At the top of the loop, status will contain a count of
149 bytes written out at the beginning of the set of iovec structs. */
155 /* Skip any leading data that has been written out. */
156 for (; offset >= (size_t) tmpiov[i].iov_len && iovleft > 0; i++) {
157 offset -= tmpiov[i].iov_len;
160 tmpiov[i].iov_base = (char *) tmpiov[i].iov_base + offset;
161 tmpiov[i].iov_len -= offset;
163 /* Write out what's left and return success if it's all written. */
164 status = writev(fd, tmpiov + i, iovleft);
172 } while (left > 0 && (status >= 0 || errno == EINTR));
174 /* We're either done or got an error; if we're done, left is now 0. */
176 return (left == 0) ? total : -1;