aboutsummaryrefslogtreecommitdiff
path: root/compat
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2026-03-13 07:45:16 +0100
committerJunio C Hamano <gitster@pobox.com>2026-03-13 08:54:14 -0700
commit3b9b2c2a29a1d529ca9884fa0a6529f6e2496abe (patch)
treee7548eabbdb68250a4fadc3c3bf27749e88a89dd /compat
parenta5816e4596891f1c7552b049053e94929c699b78 (diff)
downloadgit-3b9b2c2a29a1d529ca9884fa0a6529f6e2496abe.tar.xz
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>
Diffstat (limited to 'compat')
-rw-r--r--compat/posix.h14
-rw-r--r--compat/writev.c44
2 files changed, 58 insertions, 0 deletions
diff --git a/compat/posix.h b/compat/posix.h
index 245386fa4a..3c611d2736 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -137,6 +137,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>
@@ -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
index 0000000000..3a94870a2f
--- /dev/null
+++ b/compat/writev.c
@@ -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;
+}