Make important improvements

- Fix preadv() and pwritev() for old distros
- Introduce _npassert() and _unassert() macros
- Prove that file locks work properly on Windows
- Support fcntl(F_DUPFD_CLOEXEC) on more systems
This commit is contained in:
Justine Tunney 2022-09-14 21:29:50 -07:00
parent 1ad2f530f9
commit 3f49889841
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
130 changed files with 1225 additions and 431 deletions

View file

@ -16,91 +16,104 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
static bool once, demodernize;
int i, err;
ssize_t rc;
size_t got, toto;
int e, i;
size_t got;
bool masked;
ssize_t rc, toto;
sigset_t mask, oldmask;
if (fd < 0) {
return ebadf();
}
if (iovlen < 0) {
return einval();
}
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
return efault();
}
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return _weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);
} else if (IsWindows()) {
}
if (IsMetal()) {
return espipe(); // must be serial or console if not zipos
}
if (IsWindows()) {
if (fd < g_fds.n) {
return sys_read_nt(g_fds.p + fd, iov, iovlen, off);
} else {
return ebadf();
}
} else if (IsMetal()) {
return enosys();
}
if (iovlen == 1) {
return sys_pread(fd, iov[0].iov_base, iov[0].iov_len, off, off);
}
/*
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
*/
if (!__vforked && !once) {
err = errno;
rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc == -1 && errno == ENOSYS) {
errno = err;
once = true;
demodernize = true;
STRACE("demodernizing %s() due to %s", "preadv", "ENOSYS");
} else {
once = true;
return rc;
}
}
if (!demodernize) {
return sys_preadv(fd, iov, iovlen, off, off);
while (iovlen && !iov->iov_len) {
--iovlen;
++iov;
}
if (!iovlen) {
return sys_pread(fd, NULL, 0, off, off);
return sys_pread(fd, 0, 0, off, off);
}
if (iovlen == 1) {
return sys_pread(fd, iov->iov_base, iov->iov_len, off, off);
}
e = errno;
rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc != -1 || errno != ENOSYS) return rc;
errno = e;
for (toto = i = 0; i < iovlen; ++i) {
rc = sys_pread(fd, iov[i].iov_base, iov[i].iov_len, off, off);
if (rc == -1) {
if (toto && (errno == EINTR || errno == EAGAIN)) {
return toto;
} else {
return -1;
if (!toto) {
toto = -1;
}
break;
}
got = rc;
toto += got;
off += got;
if (got != iov[i].iov_len) {
break;
}
if (!masked) {
sigfillset(&mask);
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
masked = true;
}
}
if (masked) {
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
}
return toto;