git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 1/5] compat/posix: introduce writev(3p) wrapper

From
Patrick Steinhardt <ps@pks.im>
Date
Aug 7, 2026, 06:18 UTC
Message-ID
<20260807-pks-reintroduce-writev-v2-1-30fcff0e89c1@pks.im>
In-Reply-To
<20260807-pks-reintroduce-writev-v2-0-30fcff0e89c1@pks.im>

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

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 Makefile                            |  4 ++++
 compat/posix.h                      | 14 +++++++++++++
 compat/writev.c                     | 41 +++++++++++++++++++++++++++++++++++++
 config.mak.uname                    |  2 ++
 contrib/buildsystems/CMakeLists.txt |  6 +++++-
 meson.build                         |  1 +
 6 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1f3f099f5c..eda5ecc5b4 100644
--- a/Makefile
+++ b/Makefile
@@ -2033,6 +2033,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
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..71cc731620 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -148,6 +148,9 @@
 #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>
@@ -334,6 +337,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
index 0000000000..540f66de61
--- /dev/null
+++ b/compat/writev.c
@@ -0,0 +1,41 @@
+#include "../git-compat-util.h"
+#include "../wrapper.h"
+
+ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+	size_t sum = 0;
+
+	if (iovcnt <= 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * 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) ||
+		    unsigned_add_overflows(iov[i].iov_len, sum) ||
+		    iov[i].iov_len + sum > maximum_signed_value_of_type(ssize_t)) {
+			errno = EINVAL;
+			return -1;
+		}
+
+		sum += iov[i].iov_len;
+	}
+
+	/*
+	 * We only ever write the first non-empty vector so that we can
+	 * guarantee the call to be non-interleaving as guaranteed by POSIX.
+	 * This works just fine as callers have to loop around writev anyway.
+	 */
+	for (int i = 0; i < iovcnt; i++) {
+		if (!iov[i].iov_len)
+			continue;
+		return xwrite(fd, iov[i].iov_base, iov[i].iov_len);
+	}
+
+	/* When all iovec members were zero we ought to return 0 according to POSIX. */
+	return 0;
+}
diff --git a/config.mak.uname b/config.mak.uname
index 9ebd240378..95ef6e64dc 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -483,6 +483,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
@@ -697,6 +698,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
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index a57c4b464f..8f56203f34 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -378,7 +378,7 @@ endif()
 #function checks
 set(function_checks
 	strcasestr memmem strlcpy strtoimax strtoumax strtoull
-	setenv mkdtemp poll pread memmem)
+	setenv mkdtemp poll pread memmem writev)
 
 #unsetenv,hstrerror are incompatible with windows build
 if(NOT WIN32)
@@ -423,6 +423,10 @@ if(NOT HAVE_MEMMEM)
 	list(APPEND compat_SOURCES compat/memmem.c)
 endif()
 
+if(NOT HAVE_WRITEV)
+	list(APPEND compat_SOURCES compat/writev.c)
+endif()
+
 if(NOT WIN32)
 	if(NOT HAVE_UNSETENV)
 		list(APPEND compat_SOURCES compat/unsetenv.c)
diff --git a/meson.build b/meson.build
index ca235801cf..613828ff25 100644
--- a/meson.build
+++ b/meson.build
@@ -1446,6 +1446,7 @@ checkfuncs = {
   'initgroups' : [],
   'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
   'pread' : ['pread.c'],
+  'writev' : ['writev.c'],
 }
 
 if host_machine.system() == 'windows'
-- 
2.55.0.679.g6767b8d81c.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 23 of 27 in “Reintroduce writev(3p)”
  1. 0/5 Reintroduce writev(3p)Patrick Steinhardt, Jul 16, 2026
  2. 1/5 compat/posix: introduce writev(3p) wrapperPatrick Steinhardt, Jul 16, 2026
  3. Simon RichterJul 16, 2026
  4. Junio C HamanoJul 16, 2026
  5. Junio C HamanoJul 16, 2026
  6. Patrick SteinhardtAug 5, 2026
  7. 2/5 wrapper: introduce writev(3p) wrappersPatrick Steinhardt, Jul 16, 2026
  8. 3/5 wrapper: properly handle MAX_IO_SIZE in writev(3p)Patrick Steinhardt, Jul 16, 2026
  9. 4/5 sideband: use writev(3p) to send pktlinesPatrick Steinhardt, Jul 16, 2026
  10. 5/5 fast-import: use writev(3p) to send cat-blob responsesPatrick Steinhardt, Jul 16, 2026
  11. Johannes SixtJul 16, 2026
  12. Junio C HamanoJul 27, 2026
  13. Patrick SteinhardtAug 5, 2026
  14. Junio C HamanoAug 5, 2026
  15. Johannes SixtAug 5, 2026
  16. Junio C HamanoAug 5, 2026
  17. Johannes SixtAug 5, 2026
  18. Junio C HamanoAug 5, 2026
  19. Patrick SteinhardtAug 6, 2026
  20. Junio C HamanoAug 6, 2026
  21. Patrick SteinhardtAug 7, 2026
  22. 0/5 Reintroduce writev(3p)Patrick Steinhardt, Aug 7, 2026
  23. 1/5 compat/posix: introduce writev(3p) wrapperPatrick Steinhardt, Aug 7, 2026
  24. 2/5 wrapper: introduce writev(3p) wrappersPatrick Steinhardt, Aug 7, 2026
  25. 3/5 wrapper: properly handle MAX_IO_SIZE in writev(3p)Patrick Steinhardt, Aug 7, 2026
  26. 4/5 sideband: use writev(3p) to send pktlinesPatrick Steinhardt, Aug 7, 2026
  27. 5/5 fast-import: use writev(3p) to send cat-blob responsesPatrick Steinhardt, Aug 7, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.