Skip to content

Commit 3b9b2c2

Browse files
pks-tgitster
authored andcommitted
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>
1 parent a5816e4 commit 3b9b2c2

5 files changed

Lines changed: 65 additions & 0 deletions

File tree

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,10 @@ ifdef NO_PREAD
20152015
COMPAT_CFLAGS += -DNO_PREAD
20162016
COMPAT_OBJS += compat/pread.o
20172017
endif
2018+
ifdef NO_WRITEV
2019+
COMPAT_CFLAGS += -DNO_WRITEV
2020+
COMPAT_OBJS += compat/writev.o
2021+
endif
20182022
ifdef NO_FAST_WORKING_DIRECTORY
20192023
BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
20202024
endif

compat/posix.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@
137137
#include <sys/socket.h>
138138
#include <sys/ioctl.h>
139139
#include <sys/statvfs.h>
140+
#ifndef NO_WRITEV
141+
#include <sys/uio.h>
142+
#endif
140143
#include <termios.h>
141144
#ifndef NO_SYS_SELECT_H
142145
#include <sys/select.h>
@@ -323,6 +326,17 @@ int git_lstat(const char *, struct stat *);
323326
ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
324327
#endif
325328

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+
326340
#ifdef NO_SETENV
327341
#define setenv gitsetenv
328342
int gitsetenv(const char *, const char *, int);

compat/writev.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ ifeq ($(uname_S),Windows)
457457
SANE_TOOL_PATH ?= $(msvc_bin_dir_msys)
458458
HAVE_ALLOCA_H = YesPlease
459459
NO_PREAD = YesPlease
460+
NO_WRITEV = YesPlease
460461
NEEDS_CRYPTO_WITH_SSL = YesPlease
461462
NO_LIBGEN_H = YesPlease
462463
NO_POLL = YesPlease
@@ -672,6 +673,7 @@ ifeq ($(uname_S),MINGW)
672673
pathsep = ;
673674
HAVE_ALLOCA_H = YesPlease
674675
NO_PREAD = YesPlease
676+
NO_WRITEV = YesPlease
675677
NEEDS_CRYPTO_WITH_SSL = YesPlease
676678
NO_LIBGEN_H = YesPlease
677679
NO_POLL = YesPlease

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,7 @@ checkfuncs = {
14051405
'initgroups' : [],
14061406
'strtoumax' : ['strtoumax.c', 'strtoimax.c'],
14071407
'pread' : ['pread.c'],
1408+
'writev' : ['writev.c'],
14081409
}
14091410

14101411
if host_machine.system() == 'windows'

0 commit comments

Comments
 (0)