diff options
| author | Patrick Steinhardt <ps@pks.im> | 2026-03-13 07:45:16 +0100 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-13 08:54:14 -0700 |
| commit | 3b9b2c2a29a1d529ca9884fa0a6529f6e2496abe (patch) | |
| tree | e7548eabbdb68250a4fadc3c3bf27749e88a89dd /compat/writev.c | |
| parent | a5816e4596891f1c7552b049053e94929c699b78 (diff) | |
| download | git-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/writev.c')
| -rw-r--r-- | compat/writev.c | 44 |
1 files changed, 44 insertions, 0 deletions
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; +} |
