compat/posix: introduce writev(3p) wrapper
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>
Patrick Steinhardt committed
Mar 13, 2026 at 07:45 UTC
3b9b2c2a29a1d529ca9884fa0a6529f6e2496abe
5 files changed
+65
Makefile
+4
@@ -2015,6 +2015,10 @@ ifdef NO_PREAD
2015
COMPAT_CFLAGS += -DNO_PREAD
2016
COMPAT_OBJS += compat/pread.o
2017
endif
2018
+ifdef NO_WRITEV
2019
+ COMPAT_CFLAGS += -DNO_WRITEV
2020
+ COMPAT_OBJS += compat/writev.o
2021
+endif
2022
ifdef NO_FAST_WORKING_DIRECTORY
2023
BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
2024
endif
compat/posix.h
+14
@@ -137,6 +137,9 @@
137
#include <sys/socket.h>
138
#include <sys/ioctl.h>
139
#include <sys/statvfs.h>
140
+#ifndef NO_WRITEV
141
+#include <sys/uio.h>
142
+#endif
143
#include <termios.h>
144
#ifndef NO_SYS_SELECT_H
145
#include <sys/select.h>
@@ -323,6 +326,17 @@ int git_lstat(const char *, struct stat *);
326
ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
327
#endif
328
329
+#ifdef NO_WRITEV
330
+#define writev git_writev
331
+#define iovec git_iovec
332
+struct git_iovec {
333
+ void *iov_base;
334
+ size_t iov_len;
335
+};
336
+
337
+ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt);
338
+#endif
339
+
340
#ifdef NO_SETENV
341
#define setenv gitsetenv
342
int gitsetenv(const char *, const char *, int);
compat/writev.c
new
+44
@@ -0,0 +1,44 @@
1
+#include "../git-compat-util.h"
2
+#include "../wrapper.h"
3
+
4
+ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt)
5
+{
6
+ size_t total_written = 0;
7
+ size_t sum = 0;
8
+
9
+ /*
10
+ * According to writev(3p), the syscall shall error with EINVAL in case
11
+ * the sum of `iov_len` overflows `ssize_t`.
12
+ */
13
+ for (int i = 0; i < iovcnt; i++) {
14
+ if (iov[i].iov_len > maximum_signed_value_of_type(ssize_t) ||
15
+ iov[i].iov_len + sum > maximum_signed_value_of_type(ssize_t)) {
16
+ errno = EINVAL;
17
+ return -1;
18
+ }
19
+
20
+ sum += iov[i].iov_len;
21
+ }
22
+
23
+ for (int i = 0; i < iovcnt; i++) {
24
+ const char *bytes = iov[i].iov_base;
25
+ size_t iovec_written = 0;
26
+
27
+ while (iovec_written < iov[i].iov_len) {
28
+ ssize_t bytes_written = xwrite(fd, bytes + iovec_written,
29
+ iov[i].iov_len - iovec_written);
30
+ if (bytes_written < 0) {
31
+ if (total_written)
32
+ goto out;
33
+ return bytes_written;
34
+ }
35
+ if (!bytes_written)
36
+ goto out;
37
+ iovec_written += bytes_written;
38
+ total_written += bytes_written;
39
+ }
40
+ }
41
+
42
+out:
43
+ return (ssize_t) total_written;
44
+}
config.mak.uname
+2
@@ -457,6 +457,7 @@ ifeq ($(uname_S),Windows)
457
SANE_TOOL_PATH ?= $(msvc_bin_dir_msys)
458
HAVE_ALLOCA_H = YesPlease
459
NO_PREAD = YesPlease
460
+ NO_WRITEV = YesPlease
461
NEEDS_CRYPTO_WITH_SSL = YesPlease
462
NO_LIBGEN_H = YesPlease
463
NO_POLL = YesPlease
@@ -672,6 +673,7 @@ ifeq ($(uname_S),MINGW)
673
pathsep = ;
674
HAVE_ALLOCA_H = YesPlease
675
NO_PREAD = YesPlease
676
+ NO_WRITEV = YesPlease
677
NEEDS_CRYPTO_WITH_SSL = YesPlease
678
NO_LIBGEN_H = YesPlease
679
NO_POLL = YesPlease
meson.build
+1
@@ -1405,6 +1405,7 @@ checkfuncs = {
1405
'initgroups' : [],
1406
'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
1407
'pread' : ['pread.c'],
1408
+ 'writev' : ['writev.c'],
1409
}
1410
1411
if host_machine.system() == 'windows'