]> git.ipfire.org Git - thirdparty/git.git/commitdiff
compat/posix: introduce writev(3p) wrapper
authorPatrick Steinhardt <ps@pks.im>
Fri, 13 Mar 2026 06:45:16 +0000 (07:45 +0100)
committerJunio C Hamano <gitster@pobox.com>
Fri, 13 Mar 2026 15:54:14 +0000 (08:54 -0700)
In a subsequent commit we're going to add the first caller to
writev(3p). Introduce a compatibility wrapper for this syscall that we
can use on systems that don't have this syscall.

The syscall exists on modern Unixes like Linux and macOS, and seemingly
even for NonStop according to [1]. It doesn't seem to exist on Windows
though.

[1]: http://nonstoptools.com/manuals/OSS-SystemCalls.pdf
[2]: https://www.gnu.org/software/gnulib/manual/html_node/writev.html

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
compat/posix.h
compat/writev.c [new file with mode: 0644]
config.mak.uname
meson.build

index 8aa489f3b6812f0848772e790887121e837dbe30..61c7dff942a0fe77fb9b2bfb031e2c45352ae376 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2015,6 +2015,10 @@ ifdef NO_PREAD
        COMPAT_CFLAGS += -DNO_PREAD
        COMPAT_OBJS += compat/pread.o
 endif
+ifdef NO_WRITEV
+       COMPAT_CFLAGS += -DNO_WRITEV
+       COMPAT_OBJS += compat/writev.o
+endif
 ifdef NO_FAST_WORKING_DIRECTORY
        BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
 endif
index 245386fa4a9f4edd54402604583b25178bf6ea20..3c611d2736c47af930d169e67f611771f03376d8 100644 (file)
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <sys/statvfs.h>
+#ifndef NO_WRITEV
+#include <sys/uio.h>
+#endif
 #include <termios.h>
 #ifndef NO_SYS_SELECT_H
 #include <sys/select.h>
@@ -323,6 +326,17 @@ int git_lstat(const char *, struct stat *);
 ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
 #endif
 
+#ifdef NO_WRITEV
+#define writev git_writev
+#define iovec git_iovec
+struct git_iovec {
+       void *iov_base;
+       size_t iov_len;
+};
+
+ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt);
+#endif
+
 #ifdef NO_SETENV
 #define setenv gitsetenv
 int gitsetenv(const char *, const char *, int);
diff --git a/compat/writev.c b/compat/writev.c
new file mode 100644 (file)
index 0000000..3a94870
--- /dev/null
@@ -0,0 +1,44 @@
+#include "../git-compat-util.h"
+#include "../wrapper.h"
+
+ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+       size_t total_written = 0;
+       size_t sum = 0;
+
+       /*
+        * According to writev(3p), the syscall shall error with EINVAL in case
+        * the sum of `iov_len` overflows `ssize_t`.
+        */
+        for (int i = 0; i < iovcnt; i++) {
+               if (iov[i].iov_len > maximum_signed_value_of_type(ssize_t) ||
+                   iov[i].iov_len + sum > maximum_signed_value_of_type(ssize_t)) {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               sum += iov[i].iov_len;
+       }
+
+       for (int i = 0; i < iovcnt; i++) {
+               const char *bytes = iov[i].iov_base;
+               size_t iovec_written = 0;
+
+               while (iovec_written < iov[i].iov_len) {
+                       ssize_t bytes_written = xwrite(fd, bytes + iovec_written,
+                                                      iov[i].iov_len - iovec_written);
+                       if (bytes_written < 0) {
+                               if (total_written)
+                                       goto out;
+                               return bytes_written;
+                       }
+                       if (!bytes_written)
+                               goto out;
+                       iovec_written += bytes_written;
+                       total_written += bytes_written;
+               }
+       }
+
+out:
+       return (ssize_t) total_written;
+}
index 3c35ae33a3c0c074139783ef00d640b157ec23db..8e66a1cc0a04c287a28f67060734fac365690422 100644 (file)
@@ -457,6 +457,7 @@ ifeq ($(uname_S),Windows)
        SANE_TOOL_PATH ?= $(msvc_bin_dir_msys)
        HAVE_ALLOCA_H = YesPlease
        NO_PREAD = YesPlease
+       NO_WRITEV = YesPlease
        NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
        NO_POLL = YesPlease
@@ -672,6 +673,7 @@ ifeq ($(uname_S),MINGW)
        pathsep = ;
        HAVE_ALLOCA_H = YesPlease
        NO_PREAD = YesPlease
+       NO_WRITEV = YesPlease
        NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
        NO_POLL = YesPlease
index dd52efd1c875746304c717d8fc4a572d1f26a0cc..f1cd89efc7d38eca112f596e177ca9402921bbcc 100644 (file)
@@ -1405,6 +1405,7 @@ checkfuncs = {
   'initgroups' : [],
   'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
   'pread' : ['pread.c'],
+  'writev' : ['writev.c'],
 }
 
 if host_machine.system() == 'windows'