aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2026-03-13 07:45:17 +0100
committerJunio C Hamano <gitster@pobox.com>2026-03-13 08:54:14 -0700
commit1970fcef93adcc5a35f6468d00a5a634d5af2b3c (patch)
tree72a7d14cd6856beff59ccdf49a71dcda0066f06a
parent3b9b2c2a29a1d529ca9884fa0a6529f6e2496abe (diff)
downloadgit-1970fcef93adcc5a35f6468d00a5a634d5af2b3c.tar.xz
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>
-rw-r--r--wrapper.c41
-rw-r--r--wrapper.h9
-rw-r--r--write-or-die.c8
-rw-r--r--write-or-die.h1
4 files changed, 59 insertions, 0 deletions
diff --git a/wrapper.c b/wrapper.c
index b794fb20e7..fa40f399b3 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -323,6 +323,47 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
return total;
}
+ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt)
+{
+ ssize_t total_written = 0;
+
+ while (iovcnt) {
+ ssize_t bytes_written = writev(fd, iov, iovcnt);
+ if (bytes_written < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ if (!bytes_written) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ total_written += bytes_written;
+
+ /*
+ * We first need to discard any iovec entities that have been
+ * fully written.
+ */
+ while (iovcnt && (size_t)bytes_written >= iov->iov_len) {
+ bytes_written -= iov->iov_len;
+ iov++;
+ iovcnt--;
+ }
+
+ /*
+ * Finally, we need to adjust the last iovec in case we have
+ * performed a partial write.
+ */
+ if (iovcnt && bytes_written) {
+ iov->iov_base = (char *) iov->iov_base + bytes_written;
+ iov->iov_len -= bytes_written;
+ }
+ }
+
+ return total_written;
+}
+
ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
{
char *p = buf;
diff --git a/wrapper.h b/wrapper.h
index 15ac3bab6e..27519b32d1 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -47,6 +47,15 @@ ssize_t read_in_full(int fd, void *buf, size_t count);
ssize_t write_in_full(int fd, const void *buf, size_t count);
ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
+/*
+ * Try to write all iovecs. Returns -1 in case an error occurred with a proper
+ * errno set, the number of bytes written otherwise.
+ *
+ * Note that the iovec will be modified as a result of this call to adjust for
+ * partial writes!
+ */
+ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt);
+
static inline ssize_t write_str_in_full(int fd, const char *str)
{
return write_in_full(fd, str, strlen(str));
diff --git a/write-or-die.c b/write-or-die.c
index 01a9a51fa2..5f522fb728 100644
--- a/write-or-die.c
+++ b/write-or-die.c
@@ -96,6 +96,14 @@ void write_or_die(int fd, const void *buf, size_t count)
}
}
+void writev_or_die(int fd, struct iovec *iov, int iovlen)
+{
+ if (writev_in_full(fd, iov, iovlen) < 0) {
+ check_pipe(errno);
+ die_errno("writev error");
+ }
+}
+
void fwrite_or_die(FILE *f, const void *buf, size_t count)
{
if (fwrite(buf, 1, count, f) != count)
diff --git a/write-or-die.h b/write-or-die.h
index 65a5c42a47..ae3d7d88b8 100644
--- a/write-or-die.h
+++ b/write-or-die.h
@@ -7,6 +7,7 @@ void fprintf_or_die(FILE *, const char *fmt, ...);
void fwrite_or_die(FILE *f, const void *buf, size_t count);
void fflush_or_die(FILE *f);
void write_or_die(int fd, const void *buf, size_t count);
+void writev_or_die(int fd, struct iovec *iov, int iovlen);
/*
* These values are used to help identify parts of a repository to fsync.