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.