wrapper: introduce writev(3p) wrappers

In the preceding commit we have added a compatibility wrapper for the writev(3p) syscall. Introduce some generic wrappers for this function that we nowadays take for granted in the Git codebase. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 16, 2026 at 09:52 UTC ba35aa3e0cea2dd396d254079913514d91bce584
4 files changed +59
wrapper.c
+41
@@ -323,6 +323,47 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
323 return total;
324 }
325
326 +ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt)
327 +{
328 + ssize_t total_written = 0;
329 +
330 + while (iovcnt) {
331 + ssize_t bytes_written = writev(fd, iov, iovcnt);
332 + if (bytes_written < 0) {
333 + if (errno == EINTR || errno == EAGAIN)
334 + continue;
335 + return -1;
336 + }
337 + if (!bytes_written) {
338 + errno = ENOSPC;
339 + return -1;
340 + }
341 +
342 + total_written += bytes_written;
343 +
344 + /*
345 + * We first need to discard any iovec entities that have been
346 + * fully written.
347 + */
348 + while (iovcnt && (size_t)bytes_written >= iov->iov_len) {
349 + bytes_written -= iov->iov_len;
350 + iov++;
351 + iovcnt--;
352 + }
353 +
354 + /*
355 + * Finally, we need to adjust the last iovec in case we have
356 + * performed a partial write.
357 + */
358 + if (iovcnt && bytes_written) {
359 + iov->iov_base = (char *) iov->iov_base + bytes_written;
360 + iov->iov_len -= bytes_written;
361 + }
362 + }
363 +
364 + return total_written;
365 +}
366 +
367 ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
368 {
369 char *p = buf;
wrapper.h
+9
@@ -47,6 +47,15 @@ ssize_t read_in_full(int fd, void *buf, size_t count);
47 ssize_t write_in_full(int fd, const void *buf, size_t count);
48 ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
49
50 +/*
51 + * Try to write all iovecs. Returns -1 in case an error occurred with a proper
52 + * errno set, the number of bytes written otherwise.
53 + *
54 + * Note that the iovec will be modified as a result of this call to adjust for
55 + * partial writes!
56 + */
57 +ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt);
58 +
59 static inline ssize_t write_str_in_full(int fd, const char *str)
60 {
61 return write_in_full(fd, str, strlen(str));
write-or-die.c
+8
@@ -96,6 +96,14 @@ void write_or_die(int fd, const void *buf, size_t count)
96 }
97 }
98
99 +void writev_or_die(int fd, struct iovec *iov, int iovlen)
100 +{
101 + if (writev_in_full(fd, iov, iovlen) < 0) {
102 + check_pipe(errno);
103 + die_errno("writev error");
104 + }
105 +}
106 +
107 void fwrite_or_die(FILE *f, const void *buf, size_t count)
108 {
109 if (fwrite(buf, 1, count, f) != count)
write-or-die.h
+1
@@ -7,6 +7,7 @@ void fprintf_or_die(FILE *, const char *fmt, ...);
7 void fwrite_or_die(FILE *f, const void *buf, size_t count);
8 void fflush_or_die(FILE *f);
9 void write_or_die(int fd, const void *buf, size_t count);
10 +void writev_or_die(int fd, struct iovec *iov, int iovlen);
11
12 /*
13 * These values are used to help identify parts of a repository to fsync.