From 4f98ad10549a5ccca91824bfd8d9e3d06f9d0d17 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 7 Apr 2022 20:30:04 -0700 Subject: [PATCH] Improve system call support on NT - Improve i/o perf on New Technology - Code cleanup on read() for New Technology - Fix bad bug with dup() of socket on New Technology - Clean up some more strace errors on New Technology --- libc/bits/midpoint.h | 23 +++++ libc/calls/close-nt.c | 7 +- libc/calls/close.c | 42 +++++---- libc/calls/dup-nt.c | 9 +- libc/calls/faccessat.c | 4 +- libc/calls/fadvise.c | 8 +- libc/calls/fchmodat-nt.c | 2 +- libc/calls/fchmodat.c | 11 ++- libc/calls/fchownat.c | 5 +- libc/calls/fcntl-nt.c | 2 +- libc/calls/fstat-nt.c | 1 + libc/calls/fstatat.c | 16 +++- libc/calls/internal.h | 4 +- libc/calls/ioctl_tiocgwinsz-nt.c | 1 - libc/calls/isatty.c | 18 ++-- libc/calls/isdirectory-nt.c | 4 + libc/calls/isregularfile-nt.c | 4 + libc/calls/issymlink-nt.c | 4 + libc/calls/linkat.c | 6 +- libc/calls/mkdirat-nt.c | 31 +++++-- libc/calls/mkdirat.c | 4 +- libc/calls/ntspawn.c | 26 ++---- libc/calls/offset2overlap.c | 4 +- libc/calls/open-nt.c | 2 + libc/calls/openat.c | 5 +- libc/calls/read-nt.c | 4 +- libc/calls/readlinkat-nt.c | 23 ++--- libc/calls/readlinkat.c | 5 +- libc/calls/renameat.c | 5 +- libc/calls/sigwinch-nt.c | 4 +- libc/calls/strace.internal.h | 1 + libc/calls/strace_dirfd.greg.c | 27 ++++++ libc/calls/symlinkat.c | 12 ++- libc/calls/unlinkat-nt.c | 3 + libc/calls/unlinkat.c | 4 +- libc/calls/utimensat.c | 10 ++- libc/calls/write-nt.c | 4 +- libc/fmt/strerror_r.greg.c | 9 -- libc/intrin/createdirectory.greg.c | 41 +++++++++ libc/intrin/createprocess.greg.c | 53 ++++++++++++ libc/intrin/cxafinalize.c | 2 + .../describentfileflagsandattributes.greg.c | 1 + libc/intrin/deviceiocontrol.greg.c | 47 ++++++++++ libc/intrin/exit.greg.c | 2 +- libc/intrin/getfileattributes.greg.c | 41 +++++++++ libc/intrin/intrin.mk | 4 + libc/intrin/kdos2errno.S | 1 + libc/intrin/winerr.greg.c | 5 +- libc/log/die.c | 6 +- libc/log/leaks.c | 4 +- libc/log/restoretty.c | 3 + libc/mem/copyfd.c | 86 +++++++++++++++++++ libc/mem/io.h | 10 +++ libc/nt/kernel32/CreateDirectoryW.s | 4 +- libc/nt/kernel32/CreateProcessW.s | 4 +- libc/nt/kernel32/DeviceIoControl.s | 4 +- libc/nt/kernel32/GetFileAttributesW.s | 4 +- libc/nt/master.sh | 8 +- libc/nt/thunk/process.inc | 3 - libc/runtime/arch_prctl.c | 4 + libc/runtime/getsymboltable.c | 7 +- libc/runtime/msync-nt.c | 11 +-- libc/sock/dupsockfd.c | 32 +++++++ libc/sock/internal.h | 1 + libc/sock/socket-nt.c | 1 + libc/sysv/consts.sh | 3 +- libc/testlib/benchrunner.c | 6 +- libc/testlib/quota.c | 4 +- libc/testlib/showerror.c | 8 +- libc/testlib/testmain.c | 3 +- libc/testlib/testrunner.c | 20 +++-- libc/x/makedirs.c | 40 +++++---- test/libc/calls/mkdir_test.c | 8 +- test/libc/calls/symlinkat_test.c | 52 +++++++++++ test/libc/stdio/dirstream_test.c | 6 +- third_party/quickjs/quickjs-libc.c | 4 - tool/build/blinkenlights.c | 2 +- tool/build/lib/machine.c | 3 + tool/build/lib/pml4t.c | 2 +- 79 files changed, 707 insertions(+), 197 deletions(-) create mode 100644 libc/bits/midpoint.h create mode 100644 libc/calls/strace_dirfd.greg.c create mode 100644 libc/intrin/createdirectory.greg.c create mode 100644 libc/intrin/createprocess.greg.c create mode 100644 libc/intrin/deviceiocontrol.greg.c create mode 100644 libc/intrin/getfileattributes.greg.c create mode 100644 libc/mem/copyfd.c create mode 100644 libc/mem/io.h create mode 100644 libc/sock/dupsockfd.c create mode 100644 test/libc/calls/symlinkat_test.c diff --git a/libc/bits/midpoint.h b/libc/bits/midpoint.h new file mode 100644 index 000000000..6144cf837 --- /dev/null +++ b/libc/bits/midpoint.h @@ -0,0 +1,23 @@ +#ifndef COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ +#define COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ +#include "libc/assert.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) + +/** + * Computes `(a + b) / 2` assuming unsigned. + */ +#define _midpoint(a, b) \ + ({ \ + typeof((a) + (b)) a_ = (a); \ + typeof(a_) b_ = (b); \ + assert(a_ >= 0); \ + assert(b_ >= 0); \ + asm("add\t%1,%0\n\t" \ + "rcr\t%0" \ + : "+r"(a_) \ + : "r"(b_)); \ + a_; \ + }) + +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ */ diff --git a/libc/calls/close-nt.c b/libc/calls/close-nt.c index b3c4bb7b5..2c62a7069 100644 --- a/libc/calls/close-nt.c +++ b/libc/calls/close-nt.c @@ -20,17 +20,22 @@ #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" +#include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" textwindows int sys_close_nt(struct Fd *fd) { + int e; bool32 ok; - if (fd->kind == kFdFile && GetFileType(fd->handle) == kNtFileTypeDisk) { + if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY && + GetFileType(fd->handle) == kNtFileTypeDisk)) { /* * Like Linux, closing a file on Windows doesn't guarantee it's * immediately synced to disk. But unlike Linux, this could cause * subsequent operations, e.g. unlink() to break w/ access error. */ + e = errno; FlushFileBuffers(fd->handle); + errno = e; } ok = CloseHandle(fd->handle); if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) { diff --git a/libc/calls/close.c b/libc/calls/close.c index 49fa693b3..d5f01d38d 100644 --- a/libc/calls/close.c +++ b/libc/calls/close.c @@ -46,31 +46,35 @@ */ int close(int fd) { int rc; - if (fd == -1) return 0; - if (fd < 0) return einval(); - if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { - rc = weaken(__zipos_close)(fd); + if (fd == -1) { + rc = 0; + } else if (fd < 0) { + rc = einval(); } else { - if (!IsWindows() && !IsMetal()) { - rc = sys_close(fd); - } else if (IsMetal()) { - rc = 0; + if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { + rc = weaken(__zipos_close)(fd); } else { - if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) { - rc = weaken(sys_close_epoll_nt)(fd); - } else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) { - rc = weaken(sys_closesocket_nt)(g_fds.p + fd); - } else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdFile || - g_fds.p[fd].kind == kFdConsole || - g_fds.p[fd].kind == kFdProcess)) { - rc = sys_close_nt(g_fds.p + fd); + if (!IsWindows() && !IsMetal()) { + rc = sys_close(fd); + } else if (IsMetal()) { + rc = 0; } else { - STRACE("close(%d) unknown kind: %d", fd, g_fds.p[fd].kind); - rc = ebadf(); + if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) { + rc = weaken(sys_close_epoll_nt)(fd); + } else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) { + rc = weaken(sys_closesocket_nt)(g_fds.p + fd); + } else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdFile || + g_fds.p[fd].kind == kFdConsole || + g_fds.p[fd].kind == kFdProcess)) { + rc = sys_close_nt(g_fds.p + fd); + } else { + STRACE("close(%d) unknown kind: %d", fd, g_fds.p[fd].kind); + rc = ebadf(); + } } } + __releasefd(fd); } - __releasefd(fd); STRACE("%s(%d) → %d% m", "close", fd, rc); return rc; } diff --git a/libc/calls/dup-nt.c b/libc/calls/dup-nt.c index 0e2727907..21bbf0d38 100644 --- a/libc/calls/dup-nt.c +++ b/libc/calls/dup-nt.c @@ -17,11 +17,13 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +#include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/mem/mem.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" +#include "libc/sock/internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" @@ -47,8 +49,13 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags) { if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle, 0, true, kNtDuplicateSameAccess)) { g_fds.p[newfd].kind = g_fds.p[oldfd].kind; - g_fds.p[newfd].extra = g_fds.p[oldfd].extra; g_fds.p[newfd].flags = flags; + if (g_fds.p[oldfd].kind == kFdSocket && weaken(_dupsockfd)) { + g_fds.p[newfd].extra = + (intptr_t)weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra); + } else { + g_fds.p[newfd].extra = g_fds.p[oldfd].extra; + } return newfd; } else { __releasefd(newfd); diff --git a/libc/calls/faccessat.c b/libc/calls/faccessat.c index 8c1365d1e..6b2c7ac3b 100644 --- a/libc/calls/faccessat.c +++ b/libc/calls/faccessat.c @@ -39,6 +39,7 @@ */ int faccessat(int dirfd, const char *path, int mode, uint32_t flags) { int rc; + char buf[12]; if (IsAsan() && !__asan_is_valid(path, 1)) { rc = efault(); } else if (weaken(__zipos_notat) && @@ -49,6 +50,7 @@ int faccessat(int dirfd, const char *path, int mode, uint32_t flags) { } else { rc = sys_faccessat_nt(dirfd, path, mode, flags); } - STRACE("faccessat(%d, %#s, %#o, %#x) → %d% m", dirfd, path, mode, flags, rc); + STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", __strace_dirfd(buf, dirfd), + path, mode, flags, rc); return rc; } diff --git a/libc/calls/fadvise.c b/libc/calls/fadvise.c index f464228be..31044b604 100644 --- a/libc/calls/fadvise.c +++ b/libc/calls/fadvise.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/dce.h" /** @@ -31,9 +32,12 @@ * @return -1 on error */ int fadvise(int fd, uint64_t offset, uint64_t len, int advice) { + int rc; if (!IsWindows()) { - return sys_fadvise(fd, offset, len, advice); /* linux & freebsd */ + rc = sys_fadvise(fd, offset, len, advice); /* linux & freebsd */ } else { - return sys_fadvise_nt(fd, offset, len, advice); + rc = sys_fadvise_nt(fd, offset, len, advice); } + STRACE("fadvise(%d, %'lu, %'lu, %d) → %d% m", fd, offset, len, advice, rc); + return rc; } diff --git a/libc/calls/fchmodat-nt.c b/libc/calls/fchmodat-nt.c index fd8d0f190..7b0ba5f7c 100644 --- a/libc/calls/fchmodat-nt.c +++ b/libc/calls/fchmodat-nt.c @@ -25,7 +25,7 @@ textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode, uint32_t attr; uint16_t path16[PATH_MAX]; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; - if ((attr = GetFileAttributes(path16)) != -1) { + if ((attr = GetFileAttributes(path16)) != -1u) { if (mode & 0200) { attr &= ~kNtFileAttributeReadonly; } else { diff --git a/libc/calls/fchmodat.c b/libc/calls/fchmodat.c index 75db6c761..26aa9305e 100644 --- a/libc/calls/fchmodat.c +++ b/libc/calls/fchmodat.c @@ -41,14 +41,17 @@ */ int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) { int rc; - if (IsAsan() && !__asan_is_valid(path, 1)) return efault(); - if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { - STRACE("zipos fchmodat not supported yet"); + char buf[12]; + if (IsAsan() && !__asan_is_valid(path, 1)) { + rc = efault(); + } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { + rc = eopnotsupp(); } else if (!IsWindows()) { rc = sys_fchmodat(dirfd, path, mode, flags); } else { rc = sys_fchmodat_nt(dirfd, path, mode, flags); } - STRACE("fchmodat(%d, %#s, %#o, %d) → %d% m", dirfd, path, mode, flags, rc); + STRACE("fchmodat(%s, %#s, %#o, %d) → %d% m", __strace_dirfd(buf, dirfd), path, + mode, flags, rc); return rc; } diff --git a/libc/calls/fchownat.c b/libc/calls/fchownat.c index e4b55f6e8..fc1e5530c 100644 --- a/libc/calls/fchownat.c +++ b/libc/calls/fchownat.c @@ -41,6 +41,7 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid, int flags) { int rc; + char sb[12]; if (IsAsan() && !__asan_is_valid(path, 1)) { rc = efault(); } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { @@ -48,7 +49,7 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid, } else { rc = sys_fchownat(dirfd, path, uid, gid, flags); } - STRACE("fchownat(%d, %#s, %d, %d, %#b) → %d% m", dirfd, path, uid, gid, flags, - rc); + STRACE("fchownat(%s, %#s, %d, %d, %#b) → %d% m", __strace_dirfd(sb, dirfd), + path, uid, gid, flags, rc); return rc; } diff --git a/libc/calls/fcntl-nt.c b/libc/calls/fcntl-nt.c index 1d042fba2..56861a6cb 100644 --- a/libc/calls/fcntl-nt.c +++ b/libc/calls/fcntl-nt.c @@ -98,7 +98,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) { } if (!len) len = size - off; if (off < 0 || len < 0) return einval(); - offset2overlap(off, &ov); + _offset2overlap(off, &ov); if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) { flags = 0; if (cmd == F_SETLK) flags |= kNtLockfileFailImmediately; diff --git a/libc/calls/fstat-nt.c b/libc/calls/fstat-nt.c index c2909562a..01ffa70c5 100644 --- a/libc/calls/fstat-nt.c +++ b/libc/calls/fstat-nt.c @@ -21,6 +21,7 @@ #include "libc/calls/strace.internal.h" #include "libc/calls/struct/stat.h" #include "libc/fmt/conv.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/bsr.h" #include "libc/nt/enum/fileflagandattributes.h" diff --git a/libc/calls/fstatat.c b/libc/calls/fstatat.c index 1dc1357d3..008c0908f 100644 --- a/libc/calls/fstatat.c +++ b/libc/calls/fstatat.c @@ -22,20 +22,29 @@ #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/fmt/itoa.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/log/log.h" #include "libc/str/str.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" +static inline const char *__strace_fstatat_flags(int flags) { + static char buf[12]; + if (flags == AT_SYMLINK_NOFOLLOW) return "AT_SYMLINK_NOFOLLOW"; + FormatInt32(buf, flags); + return buf; +} + /** * Returns information about thing. * * @param dirfd is normally AT_FDCWD but if it's an open directory and * file is a relative path, then file becomes relative to dirfd * @param st is where result is stored - * @param flags can have AT_{EMPTY_PATH,NO_AUTOMOUNT,SYMLINK_NOFOLLOW} + * @param flags can have AT_SYMLINK_NOFOLLOW * @return 0 on success, or -1 w/ errno * @see S_ISDIR(st.st_mode), S_ISREG() * @asyncsignalsafe @@ -44,6 +53,7 @@ int fstatat(int dirfd, const char *path, struct stat *st, int flags) { /* execve() depends on this */ int rc; + char buf[12]; struct ZiposUri zipname; if (__isfdkind(dirfd, kFdZip)) { STRACE("zipos dirfd not supported yet"); @@ -60,7 +70,7 @@ int fstatat(int dirfd, const char *path, struct stat *st, int flags) { } else { rc = sys_fstatat_nt(dirfd, path, st, flags); } - STRACE("fstatat(%d, %#s, [%s], %#b) → %d% m", dirfd, path, - __strace_stat(rc, st), flags, rc); + STRACE("fstatat(%s, %#s, [%s], %s) → %d% m", __strace_dirfd(buf, dirfd), path, + __strace_stat(rc, st), __strace_fstatat_flags(flags), rc); return rc; } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 07ead39b6..835e043e8 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -89,7 +89,7 @@ forceinline bool __isfdkind(int fd, int kind) { return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind == kind; } -forceinline size_t clampio(size_t size) { +forceinline size_t _clampio(size_t size) { if (!IsTrustworthy()) { return MIN(size, 0x7ffff000); } else { @@ -326,7 +326,7 @@ int64_t __winerr(void) nocallback privileged; int64_t ntreturn(uint32_t); ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int) hidden; ssize_t sys_writev_nt(int, const struct iovec *, int) hidden; -struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden; +struct NtOverlapped *_offset2overlap(int64_t, struct NtOverlapped *) hidden; unsigned __wincrash_nt(struct NtExceptionPointers *); void *GetProcAddressModule(const char *, const char *) hidden; void WinMainForked(void) hidden; diff --git a/libc/calls/ioctl_tiocgwinsz-nt.c b/libc/calls/ioctl_tiocgwinsz-nt.c index b0b6ead64..25980bc22 100644 --- a/libc/calls/ioctl_tiocgwinsz-nt.c +++ b/libc/calls/ioctl_tiocgwinsz-nt.c @@ -63,7 +63,6 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) { __winerr(); } } else { - STRACE("%s() failed %m", "GetConsoleMode"); enotty(); } } else { diff --git a/libc/calls/isatty.c b/libc/calls/isatty.c index 788e8c66c..3498b7bc3 100644 --- a/libc/calls/isatty.c +++ b/libc/calls/isatty.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/winsize.h" #include "libc/dce.h" #include "libc/errno.h" @@ -27,23 +28,24 @@ * Returns true if file descriptor is backed by a terminal device. */ bool32 isatty(int fd) { - int err; + int e; bool32 res; struct winsize ws; + e = errno; if (fd >= 0) { if (__isfdkind(fd, kFdZip)) { - return false; + res = false; } else if (IsMetal()) { - return false; + res = false; } else if (!IsWindows()) { - err = errno; res = sys_ioctl(fd, TIOCGWINSZ, &ws) != -1; - errno = err; - return res; } else { - return sys_isatty_nt(fd); + res = sys_isatty_nt(fd); } } else { - return false; + res = false; } + STRACE("isatty(%d) → %hhhd% m", fd, res); + errno = e; + return res; } diff --git a/libc/calls/isdirectory-nt.c b/libc/calls/isdirectory-nt.c index 6cbac59e9..d0579a967 100644 --- a/libc/calls/isdirectory-nt.c +++ b/libc/calls/isdirectory-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" @@ -25,12 +26,15 @@ * Returns true if file exists and is a directory on Windows NT. */ bool isdirectory_nt(const char *path) { + int e; uint32_t x; char16_t path16[PATH_MAX]; + e = errno; if (__mkntpath(path, path16) == -1) return -1; if ((x = GetFileAttributes(path16)) != -1u) { return !!(x & kNtFileAttributeDirectory); } else { + errno = e; return false; } } diff --git a/libc/calls/isregularfile-nt.c b/libc/calls/isregularfile-nt.c index cac70076b..45614ef64 100644 --- a/libc/calls/isregularfile-nt.c +++ b/libc/calls/isregularfile-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" @@ -25,12 +26,15 @@ * Returns true if file exists and is a regular file on Windows NT. */ bool isregularfile_nt(const char *path) { + int e; uint32_t x; char16_t path16[PATH_MAX]; + e = errno; if (__mkntpath(path, path16) == -1) return -1; if ((x = GetFileAttributes(path16)) != -1u) { return !(x & (kNtFileAttributeDirectory | kNtFileAttributeReparsePoint)); } else { + errno = e; return false; } } diff --git a/libc/calls/issymlink-nt.c b/libc/calls/issymlink-nt.c index 267f70cb8..4c074cadb 100644 --- a/libc/calls/issymlink-nt.c +++ b/libc/calls/issymlink-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" @@ -25,12 +26,15 @@ * Returns true if file exists and is a symbolic link on Windows NT. */ bool issymlink_nt(const char *path) { + int e; uint32_t x; char16_t path16[PATH_MAX]; + e = errno; if (__mkntpath(path, path16) == -1) return -1; if ((x = GetFileAttributes(path16)) != -1u) { return !!(x & kNtFileAttributeReparsePoint); } else { + errno = e; return false; } } diff --git a/libc/calls/linkat.c b/libc/calls/linkat.c index 05ef16efb..816b31a59 100644 --- a/libc/calls/linkat.c +++ b/libc/calls/linkat.c @@ -38,6 +38,7 @@ int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) { int rc; + char buf[2][12]; if (IsAsan() && (!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) { rc = efault(); @@ -50,7 +51,8 @@ int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, } else { rc = sys_linkat_nt(olddirfd, oldpath, newdirfd, newpath); } - STRACE("linkat(%d, %#s, %d, %#s, %#b) → %d% m", olddirfd, oldpath, newdirfd, - newpath, flags, rc); + STRACE("linkat(%s, %#s, %s, %#s, %#b) → %d% m", + __strace_dirfd(buf[0], olddirfd), oldpath, + __strace_dirfd(buf[1], newdirfd), newpath, flags, rc); return rc; } diff --git a/libc/calls/mkdirat-nt.c b/libc/calls/mkdirat-nt.c index c269daa4d..ba3276624 100644 --- a/libc/calls/mkdirat-nt.c +++ b/libc/calls/mkdirat-nt.c @@ -24,13 +24,20 @@ #include "libc/str/str.h" static textwindows bool SubpathExistsThatsNotDirectory(char16_t *path) { + int e; char16_t *p; uint32_t attrs; + e = errno; while ((p = strrchr16(path, '\\'))) { *p = u'\0'; if ((attrs = GetFileAttributes(path)) != -1u) { - if (attrs & kNtFileAttributeDirectory) return false; - return true; + if (attrs & kNtFileAttributeDirectory) { + return false; + } else { + return true; + } + } else { + errno = e; } } return false; @@ -40,10 +47,20 @@ textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) { int e; char16_t *p, path16[PATH_MAX]; if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; - if (CreateDirectory(path16, NULL)) return 0; - e = GetLastError(); - /* WIN32 doesn't distinguish between ENOTDIR and ENOENT */ - if (e == ENOTDIR && !SubpathExistsThatsNotDirectory(path16)) e = ENOENT; - errno = e; + if (CreateDirectory(path16, 0)) return 0; + + // WIN32 doesn't distinguish between ENOTDIR and ENOENT + // + // - ENOTDIR: A component used as a directory in pathname is not, in + // fact, a directory. -or- pathname is relative and dirfd is a file + // descriptor referring to a file other than a directory. + // + // - ENOENT: A directory component in pathname does not exist or is a + // dangling symbolic link. + if (errno == ENOTDIR) { + if (!SubpathExistsThatsNotDirectory(path16)) { + errno = ENOENT; + } + } return -1; } diff --git a/libc/calls/mkdirat.c b/libc/calls/mkdirat.c index b34f83418..bdb0b5a38 100644 --- a/libc/calls/mkdirat.c +++ b/libc/calls/mkdirat.c @@ -40,6 +40,7 @@ */ int mkdirat(int dirfd, const char *path, unsigned mode) { int rc; + char buf[12]; if (IsAsan() && !__asan_is_valid(path, 1)) { rc = efault(); } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { @@ -49,6 +50,7 @@ int mkdirat(int dirfd, const char *path, unsigned mode) { } else { rc = sys_mkdirat_nt(dirfd, path, mode); } - STRACE("mkdirat(%d, %#s, %#o) → %d% m", dirfd, path, mode, rc); + STRACE("mkdirat(%s, %#s, %#o) → %d% m", __strace_dirfd(buf, dirfd), path, + mode, rc); return rc; } diff --git a/libc/calls/ntspawn.c b/libc/calls/ntspawn.c index b9d9a91b5..0e978f0ee 100644 --- a/libc/calls/ntspawn.c +++ b/libc/calls/ntspawn.c @@ -81,23 +81,15 @@ textwindows int ntspawn( NULL, false}, pushpop(kNtPageReadwrite), 0, blocksize, NULL)) && (block = MapViewOfFileEx(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, - blocksize, NULL))) { - if (mkntcmdline(block->cmdline, prog, argv) != -1 && - mkntenvblock(block->envvars, envp, extravar) != -1) { - if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes, - opt_lpThreadAttributes, bInheritHandles, - dwCreationFlags | kNtCreateUnicodeEnvironment, - block->envvars, opt_lpCurrentDirectory, lpStartupInfo, - opt_out_lpProcessInformation)) { - rc = 0; - } else { - __winerr(); - } - STRACE("CreateProcess(%#hs, %!#hs) → %d% m", prog16, block->cmdline, rc); - } - } else { - __winerr(); - STRACE("ntspawn() alloc failed %m"); + blocksize, NULL)) && + mkntcmdline(block->cmdline, prog, argv) != -1 && + mkntenvblock(block->envvars, envp, extravar) != -1 && + CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes, + opt_lpThreadAttributes, bInheritHandles, + dwCreationFlags | kNtCreateUnicodeEnvironment, + block->envvars, opt_lpCurrentDirectory, lpStartupInfo, + opt_out_lpProcessInformation)) { + rc = 0; } if (block) UnmapViewOfFile(block); if (handle) CloseHandle(handle); diff --git a/libc/calls/offset2overlap.c b/libc/calls/offset2overlap.c index 84d356868..38e00d3dc 100644 --- a/libc/calls/offset2overlap.c +++ b/libc/calls/offset2overlap.c @@ -20,8 +20,8 @@ #include "libc/nt/struct/overlapped.h" #include "libc/str/str.h" -textwindows struct NtOverlapped *offset2overlap(int64_t opt_offset, - struct NtOverlapped *mem) { +textwindows struct NtOverlapped *_offset2overlap(int64_t opt_offset, + struct NtOverlapped *mem) { if (opt_offset == -1) return NULL; bzero(mem, sizeof(struct NtOverlapped)); mem->Pointer = (void *)(uintptr_t)opt_offset; diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index f3beff7eb..a95a3da4a 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -57,6 +57,7 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, uint32_t br, err; char16_t path16[PATH_MAX]; uint32_t perm, share, disp, attr; + if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; switch (flags & O_ACCMODE) { @@ -109,6 +110,7 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, } } } + flags |= kNtFileFlagOverlapped; if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed; if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed; diff --git a/libc/calls/openat.c b/libc/calls/openat.c index 00f1ad729..349430dea 100644 --- a/libc/calls/openat.c +++ b/libc/calls/openat.c @@ -46,6 +46,7 @@ int openat(int dirfd, const char *file, int flags, ...) { int rc; va_list va; + char buf[12]; unsigned mode; struct ZiposUri zipname; va_start(va, flags); @@ -73,7 +74,7 @@ int openat(int dirfd, const char *file, int flags, ...) { } else { rc = efault(); } - STRACE("openat(%d, %#s, %#x, %#o) → %d% m", dirfd, file, flags, - (flags & (O_CREAT | O_TMPFILE)) ? mode : 0, rc); + STRACE("openat(%s, %#s, %#x, %#o) → %d% m", __strace_dirfd(buf, dirfd), file, + flags, (flags & (O_CREAT | O_TMPFILE)) ? mode : 0, rc); return rc; } diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index 8a9685392..03859fd13 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -32,8 +32,8 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data, size_t size, ssize_t offset) { uint32_t got; struct NtOverlapped overlap; - if (ReadFile(fd->handle, data, clampio(size), &got, - offset2overlap(offset, &overlap))) { + if (ReadFile(fd->handle, data, _clampio(size), &got, + _offset2overlap(offset, &overlap))) { return got; } else if ( // make sure read() returns 0 on broken pipe diff --git a/libc/calls/readlinkat-nt.c b/libc/calls/readlinkat-nt.c index 566bba449..ea8b53b54 100644 --- a/libc/calls/readlinkat-nt.c +++ b/libc/calls/readlinkat-nt.c @@ -16,11 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/bits/bits.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/bsr.h" #include "libc/nt/createfile.h" @@ -36,19 +39,6 @@ #include "libc/str/utf16.h" #include "libc/sysv/errfuns.h" -static textwindows ssize_t sys_readlinkat_nt_error(void) { - uint32_t e; - e = GetLastError(); - STRACE("sys_readlinkat_nt() error %d", e); - switch (e) { - case kNtErrorNotAReparsePoint: - return einval(); - default: - errno = e; - return -1; - } -} - textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, size_t bufsiz) { int64_t h; @@ -60,7 +50,6 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, char16_t path16[PATH_MAX], *p; struct NtReparseDataBuffer *rdb; if (__mkntpathat(dirfd, path, 0, path16) == -1) { - STRACE("sys_readlinkat_nt() failed b/c __mkntpathat() failed"); return -1; } if (weaken(malloc)) { @@ -121,12 +110,12 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, rc = einval(); } } else { - STRACE("%s failed %m", "DeviceIoControl(kNtFsctlGetReparsePoint)"); - rc = sys_readlinkat_nt_error(); + assert(errno == EINVAL); + rc = -1; } CloseHandle(h); } else { - rc = sys_readlinkat_nt_error(); + rc = -1; } if (freeme && weaken(free)) { weaken(free)(freeme); diff --git a/libc/calls/readlinkat.c b/libc/calls/readlinkat.c index 9b946c6a9..374213175 100644 --- a/libc/calls/readlinkat.c +++ b/libc/calls/readlinkat.c @@ -49,6 +49,7 @@ * @asyncsignalsafe */ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { + char sb[12]; ssize_t bytes; if ((IsAsan() && !__asan_is_valid(buf, bufsiz)) || (bufsiz && !buf)) { bytes = efault(); @@ -60,7 +61,7 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { } else { bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz); } - STRACE("readlinkat(%d, %#s, [%#.*s]) → %d% m", dirfd, path, MAX(0, bytes), - buf, bytes); + STRACE("readlinkat(%s, %#s, [%#.*s]) → %d% m", __strace_dirfd(sb, dirfd), + path, MAX(0, bytes), buf, bytes); return bytes; } diff --git a/libc/calls/renameat.c b/libc/calls/renameat.c index cf7eec9ce..f2cd5087f 100644 --- a/libc/calls/renameat.c +++ b/libc/calls/renameat.c @@ -38,6 +38,7 @@ int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { int rc; + char buf[2][12]; if (IsAsan() && (!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) { rc = efault(); @@ -50,7 +51,7 @@ int renameat(int olddirfd, const char *oldpath, int newdirfd, } else { rc = sys_renameat_nt(olddirfd, oldpath, newdirfd, newpath); } - STRACE("renameat(%d, %#s, %d, %#s) → %d% m", olddirfd, oldpath, newdirfd, - newpath, rc); + STRACE("renameat(%s, %#s, %s, %#s) → %d% m", __strace_dirfd(buf[0], olddirfd), + oldpath, __strace_dirfd(buf[1], newdirfd), newpath, rc); return rc; } diff --git a/libc/calls/sigwinch-nt.c b/libc/calls/sigwinch-nt.c index f041fa2b9..c941b7524 100644 --- a/libc/calls/sigwinch-nt.c +++ b/libc/calls/sigwinch-nt.c @@ -38,8 +38,8 @@ textwindows void _check_sigwinch(struct Fd *fd) { struct winsize ws, old; struct NtConsoleScreenBufferInfoEx sbinfo; old = __ws; + e = errno; if (old.ws_row != 0xffff) { - e = errno; if (ioctl_tiocgwinsz_nt(fd, &ws) != -1) { if (old.ws_col != ws.ws_col || old.ws_row != ws.ws_row) { __ws = ws; @@ -48,10 +48,10 @@ textwindows void _check_sigwinch(struct Fd *fd) { } } } else { - errno = e; if (!old.ws_row && !old.ws_col) { __ws.ws_row = 0xffff; } } } + errno = e; } diff --git a/libc/calls/strace.internal.h b/libc/calls/strace.internal.h index 4de1226cb..af87cc139 100644 --- a/libc/calls/strace.internal.h +++ b/libc/calls/strace.internal.h @@ -29,6 +29,7 @@ const char *__strace_sigset(char[41], size_t, int, const sigset_t *); const char *__strace_rlimit_name(int); const char *__strace_rlimit(char[41], size_t, int, const struct rlimit *); const char *__strace_timespec(char[45], size_t, int, const struct timespec *); +const char *__strace_dirfd(char[12], int); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/calls/strace_dirfd.greg.c b/libc/calls/strace_dirfd.greg.c new file mode 100644 index 000000000..7b60493a5 --- /dev/null +++ b/libc/calls/strace_dirfd.greg.c @@ -0,0 +1,27 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/strace.internal.h" +#include "libc/fmt/itoa.h" +#include "libc/sysv/consts/at.h" + +privileged const char *__strace_dirfd(char buf[12], int dirfd) { + if (dirfd == AT_FDCWD) return "AT_FDCWD"; + FormatInt32(buf, dirfd); + return buf; +} diff --git a/libc/calls/symlinkat.c b/libc/calls/symlinkat.c index 889674236..8f23366e3 100644 --- a/libc/calls/symlinkat.c +++ b/libc/calls/symlinkat.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/consts/at.h" @@ -37,13 +38,18 @@ * @asyncsignalsafe */ int symlinkat(const char *target, int newdirfd, const char *linkpath) { + int rc; + char buf[12]; if (IsAsan() && (!__asan_is_valid(target, 1) || !__asan_is_valid(linkpath, 1))) { - return efault(); + rc = efault(); } if (!IsWindows()) { - return sys_symlinkat(target, newdirfd, linkpath); + rc = sys_symlinkat(target, newdirfd, linkpath); } else { - return sys_symlinkat_nt(target, newdirfd, linkpath); + rc = sys_symlinkat_nt(target, newdirfd, linkpath); } + STRACE("symlinkat(%#s, %s, %#s) → %d% m", target, + __strace_dirfd(buf, newdirfd), linkpath); + return rc; } diff --git a/libc/calls/unlinkat-nt.c b/libc/calls/unlinkat-nt.c index 5903648a0..ae9d2eba2 100644 --- a/libc/calls/unlinkat-nt.c +++ b/libc/calls/unlinkat-nt.c @@ -75,9 +75,11 @@ static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) { } static textwindows bool IsDirectorySymlink(const char16_t *path) { + int e; int64_t h; struct NtWin32FindData data; struct NtWin32FileAttributeData info; + e = errno; if (GetFileAttributesEx(path, 0, &info) && ((info.dwFileAttributes & kNtFileAttributeDirectory) && (info.dwFileAttributes & kNtFileAttributeReparsePoint)) && @@ -86,6 +88,7 @@ static textwindows bool IsDirectorySymlink(const char16_t *path) { return data.dwReserved0 == kNtIoReparseTagSymlink || data.dwReserved0 == kNtIoReparseTagMountPoint; } else { + errno = e; return false; } } diff --git a/libc/calls/unlinkat.c b/libc/calls/unlinkat.c index 04073b41b..5326350ce 100644 --- a/libc/calls/unlinkat.c +++ b/libc/calls/unlinkat.c @@ -39,6 +39,7 @@ */ int unlinkat(int dirfd, const char *path, int flags) { int rc; + char buf[12]; if (IsAsan() && !__asan_is_valid(path, 1)) { rc = efault(); } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { @@ -48,6 +49,7 @@ int unlinkat(int dirfd, const char *path, int flags) { } else { rc = sys_unlinkat_nt(dirfd, path, flags); } - STRACE("unlinkat(%d, %#s, %#b) → %d% m", dirfd, path, flags, rc); + STRACE("unlinkat(%s, %#s, %#b) → %d% m", __strace_dirfd(buf, dirfd), path, + flags, rc); return rc; } diff --git a/libc/calls/utimensat.c b/libc/calls/utimensat.c index 0e0e2ce54..8861f0420 100644 --- a/libc/calls/utimensat.c +++ b/libc/calls/utimensat.c @@ -36,6 +36,7 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2], int flags) { int rc; + char buf[12]; if (IsAsan() && (!__asan_is_valid(path, 1) || (ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) { rc = efault(); @@ -47,11 +48,12 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2], rc = sys_utimensat_nt(dirfd, path, ts, flags); } if (ts) { - STRACE("utimensat(%d, %#s, {{%,ld, %,ld}, {%,ld, %,ld}}, %#b) → %d% m", - dirfd, path, ts[0].tv_sec, ts[0].tv_nsec, ts[1].tv_sec, - ts[1].tv_nsec, flags, rc); + STRACE("utimensat(%s, %#s, {{%,ld, %,ld}, {%,ld, %,ld}}, %#b) → %d% m", + __strace_dirfd(buf, dirfd), path, ts[0].tv_sec, ts[0].tv_nsec, + ts[1].tv_sec, ts[1].tv_nsec, flags, rc); } else { - STRACE("utimensat(%d, %#s, 0, %#b) → %d% m", dirfd, path, flags, rc); + STRACE("utimensat(%s, %#s, 0, %#b) → %d% m", __strace_dirfd(buf, dirfd), + path, flags, rc); } return rc; } diff --git a/libc/calls/write-nt.c b/libc/calls/write-nt.c index 568cb274e..3e98f3f3d 100644 --- a/libc/calls/write-nt.c +++ b/libc/calls/write-nt.c @@ -49,8 +49,8 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size, ssize_t offset) { uint32_t sent; struct NtOverlapped overlap; - if (WriteFile(g_fds.p[fd].handle, data, clampio(size), &sent, - offset2overlap(offset, &overlap))) { + if (WriteFile(g_fds.p[fd].handle, data, _clampio(size), &sent, + _offset2overlap(offset, &overlap))) { return sent; } else if (GetLastError() == kNtErrorBrokenPipe) { return sys_write_nt_epipe(fd); diff --git a/libc/fmt/strerror_r.greg.c b/libc/fmt/strerror_r.greg.c index 961698ace..b1195a3cd 100644 --- a/libc/fmt/strerror_r.greg.c +++ b/libc/fmt/strerror_r.greg.c @@ -34,15 +34,6 @@ #include "libc/str/str.h" #include "libc/str/tpenc.h" -#if !IsTiny() && SupportsWindows() -/* - * If we're paying the code size costs for all the system five magnums - * that this module pulls in then we might as well pull in support for - * the improved accuracy windows errno conversions used by __winerr() - */ -STATIC_YOINK("__dos2errno"); -#endif - /** * Converts errno value to string. * diff --git a/libc/intrin/createdirectory.greg.c b/libc/intrin/createdirectory.greg.c new file mode 100644 index 000000000..d6d242f92 --- /dev/null +++ b/libc/intrin/createdirectory.greg.c @@ -0,0 +1,41 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/files.h" +#include "libc/nt/thunk/msabi.h" + +extern typeof(CreateDirectory) *const __imp_CreateDirectoryW __msabi; + +/** + * Creates directory on the New Technology. + * + * @return handle, or -1 on failure + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +textwindows bool32 +CreateDirectory(const char16_t *lpPathName, + struct NtSecurityAttributes *lpSecurityAttributes) { + bool32 ok; + ok = __imp_CreateDirectoryW(lpPathName, lpSecurityAttributes); + if (!ok) __winerr(); + STRACE("CreateDirectory(%#hs, %p) → %hhhd% m", lpPathName, + lpSecurityAttributes, ok); + return ok; +} diff --git a/libc/intrin/createprocess.greg.c b/libc/intrin/createprocess.greg.c new file mode 100644 index 000000000..56b0679ea --- /dev/null +++ b/libc/intrin/createprocess.greg.c @@ -0,0 +1,53 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/process.h" +#include "libc/nt/thunk/msabi.h" + +extern typeof(CreateProcess) *const __imp_CreateProcessW __msabi; + +/** + * Creates process on the New Technology. + * + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +textwindows bool32 +CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine, + struct NtSecurityAttributes *opt_lpProcessAttributes, + struct NtSecurityAttributes *opt_lpThreadAttributes, + bool32 bInheritHandles, uint32_t dwCreationFlags, + void *opt_lpEnvironment, const char16_t *opt_lpCurrentDirectory, + const struct NtStartupInfo *lpStartupInfo, + struct NtProcessInformation *opt_out_lpProcessInformation) { + bool32 ok; + ok = __imp_CreateProcessW(opt_lpApplicationName, lpCommandLine, + opt_lpProcessAttributes, opt_lpThreadAttributes, + bInheritHandles, dwCreationFlags, opt_lpEnvironment, + opt_lpCurrentDirectory, lpStartupInfo, + opt_out_lpProcessInformation); + if (!ok) __winerr(); + STRACE( + "CreateFile(%#hs, %#hs, %p, %p, %hhhd, %u, %p, %#hs, %p, %p) → %hhhd% m", + opt_lpApplicationName, lpCommandLine, opt_lpProcessAttributes, + opt_lpThreadAttributes, bInheritHandles, dwCreationFlags, + opt_lpEnvironment, opt_lpCurrentDirectory, lpStartupInfo, + opt_out_lpProcessInformation, ok); + return ok; +} diff --git a/libc/intrin/cxafinalize.c b/libc/intrin/cxafinalize.c index 741fee0dc..34250cd3d 100644 --- a/libc/intrin/cxafinalize.c +++ b/libc/intrin/cxafinalize.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/bits/weaken.h" +#include "libc/calls/strace.internal.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/bsf.h" #include "libc/runtime/cxaatexit.internal.h" @@ -35,6 +36,7 @@ void __cxa_finalize(void *pred) { unsigned i, mask; struct CxaAtexitBlock *b, *b2; + STRACE("__cxa_finalize()"); StartOver: if ((b = __cxa_blocks.p)) { for (;;) { diff --git a/libc/intrin/describentfileflagsandattributes.greg.c b/libc/intrin/describentfileflagsandattributes.greg.c index 374bc486d..d0ce0675c 100644 --- a/libc/intrin/describentfileflagsandattributes.greg.c +++ b/libc/intrin/describentfileflagsandattributes.greg.c @@ -51,6 +51,7 @@ static const struct DescribeFlags kFileFlags[] = { const char *DescribeNtFileFlagsAndAttributes(uint32_t x) { static char ntfileflags[256]; + if (x == -1u) return "-1u"; return DescribeFlags(ntfileflags, sizeof(ntfileflags), kFileFlags, ARRAYLEN(kFileFlags), "kNtFile", x); } diff --git a/libc/intrin/deviceiocontrol.greg.c b/libc/intrin/deviceiocontrol.greg.c new file mode 100644 index 000000000..3a471cdea --- /dev/null +++ b/libc/intrin/deviceiocontrol.greg.c @@ -0,0 +1,47 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/files.h" +#include "libc/nt/struct/overlapped.h" +#include "libc/nt/thunk/msabi.h" + +extern typeof(DeviceIoControl) *const __imp_DeviceIoControl __msabi; + +/** + * Does device file stuff on the New Technology. + * + * @return handle, or -1 on failure + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +textwindows bool32 DeviceIoControl(int64_t hDevice, uint32_t dwIoControlCode, + void *lpInBuffer, uint32_t nInBufferSize, + void *lpOutBuffer, uint32_t nOutBufferSize, + uint32_t *lpBytesReturned, + struct NtOverlapped *lpOverlapped) { + bool32 ok; + ok = __imp_DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, + nInBufferSize, lpOutBuffer, nOutBufferSize, + lpBytesReturned, lpOverlapped); + if (!ok) __winerr(); + STRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m", + hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, + nOutBufferSize, lpBytesReturned, lpOverlapped, ok); + return ok; +} diff --git a/libc/intrin/exit.greg.c b/libc/intrin/exit.greg.c index 599b5ec63..1e3d47615 100644 --- a/libc/intrin/exit.greg.c +++ b/libc/intrin/exit.greg.c @@ -37,7 +37,7 @@ privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) { int i; STRACE("_Exit(%d)", exitcode); - if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) { + if (!IsWindows() && !IsMetal()) { asm volatile("syscall" : /* no outputs */ : "a"(__NR_exit_group), "D"(exitcode) diff --git a/libc/intrin/getfileattributes.greg.c b/libc/intrin/getfileattributes.greg.c new file mode 100644 index 000000000..77e5284f6 --- /dev/null +++ b/libc/intrin/getfileattributes.greg.c @@ -0,0 +1,41 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/nt/enum/fileflagandattributes.h" +#include "libc/nt/files.h" +#include "libc/nt/thunk/msabi.h" + +extern typeof(GetFileAttributes) *const __imp_GetFileAttributesW __msabi; + +/** + * Gets file info on the New Technology. + * + * @return handle, or -1 on failure + * @note this wrapper takes care of ABI, STRACE(), and __winerr() + */ +textwindows uint32_t GetFileAttributes(const char16_t *lpPathName) { + uint32_t flags; + flags = __imp_GetFileAttributesW(lpPathName); + if (flags == -1u) __winerr(); + STRACE("GetFileAttributes(%#hs) → %s% m", lpPathName, + DescribeNtFileFlagsAndAttributes(flags)); + return flags; +} diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index 4ee76de74..4b5d0dce8 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -67,11 +67,15 @@ o/$(MODE)/libc/intrin/createfile.greg.o \ o/$(MODE)/libc/intrin/createpipe.greg.o \ o/$(MODE)/libc/intrin/closehandle.greg.o \ o/$(MODE)/libc/intrin/createthread.greg.o \ +o/$(MODE)/libc/intrin/createprocess.greg.o \ o/$(MODE)/libc/intrin/describeflags.greg.o \ o/$(MODE)/libc/intrin/createnamedpipe.greg.o \ o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \ o/$(MODE)/libc/intrin/flushviewoffile.greg.o \ +o/$(MODE)/libc/intrin/deviceiocontrol.greg.o \ +o/$(MODE)/libc/intrin/createdirectory.greg.o \ o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \ +o/$(MODE)/libc/intrin/getfileattributes.greg.o \ o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ o/$(MODE)/libc/intrin/kstarttsc.o \ diff --git a/libc/intrin/kdos2errno.S b/libc/intrin/kdos2errno.S index 9976cda72..ae0e6a393 100644 --- a/libc/intrin/kdos2errno.S +++ b/libc/intrin/kdos2errno.S @@ -52,6 +52,7 @@ kDos2Errno: .e kNtErrorHostUnreachable,EHOSTUNREACH .e kNtErrorInsufficientBuffer,EFAULT .e kNtErrorInvalidAddress,EADDRNOTAVAIL + .e kNtErrorNotAReparsePoint,EINVAL .e kNtErrorInvalidFunction,EINVAL .e kNtErrorInvalidNetname,EADDRNOTAVAIL .e kNtErrorInvalidUserBuffer,EMSGSIZE diff --git a/libc/intrin/winerr.greg.c b/libc/intrin/winerr.greg.c index cc0643792..80360fa62 100644 --- a/libc/intrin/winerr.greg.c +++ b/libc/intrin/winerr.greg.c @@ -34,10 +34,7 @@ privileged int64_t __winerr(void) { errno_t e; if (IsWindows()) { - e = __imp_GetLastError(); - if (weaken(__dos2errno)) { - e = weaken(__dos2errno)(e); - } + e = __dos2errno(__imp_GetLastError()); } else { e = ENOSYS; } diff --git a/libc/log/die.c b/libc/log/die.c index 2d76ea0ec..647825420 100644 --- a/libc/log/die.c +++ b/libc/log/die.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/log/backtrace.internal.h" #include "libc/log/internal.h" #include "libc/log/libfatal.internal.h" @@ -33,7 +34,8 @@ relegated wontreturn void __die(void) { /* asan runtime depends on this function */ static bool once; - if (cmpxchg(&once, false, true)) { + kprintf("__die() called%n"); + if (lockcmpxchg(&once, false, true)) { __restore_tty(1); if (IsDebuggerPresent(false)) { DebugBreak(); @@ -42,7 +44,7 @@ relegated wontreturn void __die(void) { __restorewintty(); _Exit(77); } - __write_str("PANIC: __DIE() DIED\r\n"); + kprintf("panic: __die() died%n"); __restorewintty(); _Exit(78); } diff --git a/libc/log/leaks.c b/libc/log/leaks.c index 3ffe88b99..cb7658372 100644 --- a/libc/log/leaks.c +++ b/libc/log/leaks.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +#include "libc/calls/strace.internal.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/kprintf.h" #include "libc/runtime/internal.h" @@ -71,11 +72,12 @@ static noasan bool HasLeaks(void) { */ noasan void CheckForMemoryLeaks(void) { struct mallinfo mi; - if (!cmpxchg(&once, false, true)) { + if (!lockcmpxchg(&once, false, true)) { kprintf("CheckForMemoryLeaks() may only be called once\n"); exit(1); } __cxa_finalize(0); + STRACE("checking for memory leaks"); if (!IsAsan()) { /* TODO(jart): How can we make this work without ASAN? */ return; diff --git a/libc/log/restoretty.c b/libc/log/restoretty.c index dc69e71bd..85ff62cfa 100644 --- a/libc/log/restoretty.c +++ b/libc/log/restoretty.c @@ -50,8 +50,11 @@ const void *const g_oldtermios_ctor[] initarray = { }; void __restore_tty(int fd) { + int e; + e = errno; if (g_oldtermios.c_lflag && !__nocolor && isatty(fd)) { write(fd, ANSI_RESTORE, strlen(ANSI_RESTORE)); tcsetattr(fd, TCSAFLUSH, &g_oldtermios); } + errno = e; } diff --git a/libc/mem/copyfd.c b/libc/mem/copyfd.c new file mode 100644 index 000000000..c058505e5 --- /dev/null +++ b/libc/mem/copyfd.c @@ -0,0 +1,86 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/mem/mem.h" + +#define CHUNK 32768 + +/** + * Copies data between fds the old fashioned way. + * + * Even though Cosmopolitan polyfills copy_file_range() to fallback to + * doing this, it's useful to call this function in cases where you know + * it'd be more helpful to get the larger buffer size with read/write. + * + * Reads are allowed to be interrupted. Writes are uninterruptible. If + * we get an interrupt when partial data was written, we return the + * partial amount. Therefore the file descriptors are guaranteed to + * remain in a consistent state, provided EINTR is the only error. + * + * If n is 0 then 0 is returned and no i/o operations are performed. + * + * @return bytes successfully exchanged + */ +ssize_t _copyfd(int infd, int outfd, size_t n) { + int e; + char *buf; + ssize_t rc; + size_t i, j, got, sent; + rc = 0; + if (n) { + if ((buf = malloc(CHUNK))) { + for (e = errno, i = 0; i < n; i += j) { + rc = read(infd, buf, CHUNK); + if (rc == -1) { + // eintr may interrupt the read operation + if (i && errno == EINTR) { + // suppress error if partially completed + errno = e; + rc = i; + } + break; + } + got = rc; + if (!got) { + rc = i; + break; + } + // write operation must complete + for (j = 0; j < got; j += sent) { + rc = write(outfd, buf + j, got - j); + if (rc != -1) { + sent = rc; + } else if (errno == EINTR) { + // write operation must be uninterruptible + errno = e; + sent = 0; + } else { + break; + } + } + if (rc == -1) break; + } + free(buf); + } else { + rc = -1; + } + } + return rc; +} diff --git a/libc/mem/io.h b/libc/mem/io.h new file mode 100644 index 000000000..22f365c15 --- /dev/null +++ b/libc/mem/io.h @@ -0,0 +1,10 @@ +#ifndef COSMOPOLITAN_LIBC_MEM_IO_H_ +#define COSMOPOLITAN_LIBC_MEM_IO_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +ssize_t _copyfd(int, int, size_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_MEM_IO_H_ */ diff --git a/libc/nt/kernel32/CreateDirectoryW.s b/libc/nt/kernel32/CreateDirectoryW.s index e8e6c595e..543ba1726 100644 --- a/libc/nt/kernel32/CreateDirectoryW.s +++ b/libc/nt/kernel32/CreateDirectoryW.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_CreateDirectoryW,CreateDirectoryW,0 .text.windows -CreateDirectory: +__CreateDirectory: push %rbp mov %rsp,%rbp .profilable mov __imp_CreateDirectoryW(%rip),%rax jmp __sysv2nt - .endfn CreateDirectory,globl + .endfn __CreateDirectory,globl .previous diff --git a/libc/nt/kernel32/CreateProcessW.s b/libc/nt/kernel32/CreateProcessW.s index 5f7eb201e..50fe02ff4 100644 --- a/libc/nt/kernel32/CreateProcessW.s +++ b/libc/nt/kernel32/CreateProcessW.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_CreateProcessW,CreateProcessW,0 .text.windows -CreateProcess: +__CreateProcess: push %rbp mov %rsp,%rbp .profilable mov __imp_CreateProcessW(%rip),%rax jmp __sysv2nt10 - .endfn CreateProcess,globl + .endfn __CreateProcess,globl .previous diff --git a/libc/nt/kernel32/DeviceIoControl.s b/libc/nt/kernel32/DeviceIoControl.s index 166497c20..f250662fb 100644 --- a/libc/nt/kernel32/DeviceIoControl.s +++ b/libc/nt/kernel32/DeviceIoControl.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_DeviceIoControl,DeviceIoControl,0 .text.windows -DeviceIoControl: +__DeviceIoControl: push %rbp mov %rsp,%rbp .profilable mov __imp_DeviceIoControl(%rip),%rax jmp __sysv2nt8 - .endfn DeviceIoControl,globl + .endfn __DeviceIoControl,globl .previous diff --git a/libc/nt/kernel32/GetFileAttributesW.s b/libc/nt/kernel32/GetFileAttributesW.s index 0295417db..581fde16b 100644 --- a/libc/nt/kernel32/GetFileAttributesW.s +++ b/libc/nt/kernel32/GetFileAttributesW.s @@ -2,7 +2,7 @@ .imp kernel32,__imp_GetFileAttributesW,GetFileAttributesW,0 .text.windows -GetFileAttributes: +__GetFileAttributes: push %rbp mov %rsp,%rbp .profilable @@ -11,5 +11,5 @@ GetFileAttributes: call *__imp_GetFileAttributesW(%rip) leave ret - .endfn GetFileAttributes,globl + .endfn __GetFileAttributes,globl .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index 430d0b1bc..1a9d1b5bb 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -560,7 +560,7 @@ imp 'CreateDialogIndirectParamAor' CreateDialogIndirectParamAorW user32 1 imp 'CreateDialogIndirectParam' CreateDialogIndirectParamW user32 1612 imp 'CreateDialogParamA' CreateDialogParamA user32 1613 imp 'CreateDialogParam' CreateDialogParamW user32 1614 -imp 'CreateDirectory' CreateDirectoryW kernel32 0 2 # KernelBase +imp '__CreateDirectory' CreateDirectoryW kernel32 0 2 # KernelBase imp 'CreateDirectoryA' CreateDirectoryA kernel32 0 2 # KernelBase imp 'CreateDirectoryExA' CreateDirectoryExA kernel32 182 imp 'CreateDirectoryEx' CreateDirectoryExW kernel32 0 # KernelBase @@ -643,7 +643,7 @@ imp 'CreatePrivateObjectSecurity' CreatePrivateObjectSecurity advapi32 0 imp 'CreatePrivateObjectSecurityEx' CreatePrivateObjectSecurityEx advapi32 0 # KernelBase imp 'CreatePrivateObjectSecurityWithMultipleInheritance' CreatePrivateObjectSecurityWithMultipleInheritance advapi32 0 # KernelBase imp 'CreateProcessA' CreateProcessA kernel32 0 10 # KernelBase -imp 'CreateProcess' CreateProcessW kernel32 0 10 # KernelBase +imp '__CreateProcess' CreateProcessW kernel32 0 10 # KernelBase imp 'CreateProcessAsUserA' CreateProcessAsUserA advapi32 0 11 # KernelBase imp 'CreateProcessAsUser' CreateProcessAsUserW advapi32 0 11 # KernelBase imp 'CreateProcessInternal' CreateProcessInternalW KernelBase 211 @@ -1218,7 +1218,7 @@ imp 'DestroyPrivateObjectSecurity' DestroyPrivateObjectSecurity advapi32 0 imp 'DestroyReasons' DestroyReasons user32 1689 imp 'DestroyWindow' DestroyWindow user32 1690 1 imp 'DeviceCapabilitiesExA' DeviceCapabilitiesExA gdi32 1391 -imp 'DeviceIoControl' DeviceIoControl kernel32 0 8 # KernelBase +imp '__DeviceIoControl' DeviceIoControl kernel32 0 8 # KernelBase imp 'DialogBoxIndirectParamA' DialogBoxIndirectParamA user32 1691 imp 'DialogBoxIndirectParamAor' DialogBoxIndirectParamAorW user32 1692 imp 'DialogBoxIndirectParam' DialogBoxIndirectParamW user32 1693 @@ -2121,7 +2121,7 @@ imp 'GetExtensionProperty' GetExtensionProperty KernelBase 540 imp 'GetExtensionProperty2' GetExtensionProperty2 KernelBase 541 imp 'GetFallbackDisplayName' GetFallbackDisplayName KernelBase 542 imp 'GetFileAttributesA' GetFileAttributesA kernel32 0 1 # KernelBase -imp 'GetFileAttributes' GetFileAttributesW kernel32 0 1 # KernelBase +imp '__GetFileAttributes' GetFileAttributesW kernel32 0 1 # KernelBase imp 'GetFileAttributesExA' GetFileAttributesExA kernel32 0 3 # KernelBase imp 'GetFileAttributesEx' GetFileAttributesExW kernel32 0 3 # KernelBase imp 'GetFileAttributesTransactedA' GetFileAttributesTransactedA kernel32 583 diff --git a/libc/nt/thunk/process.inc b/libc/nt/thunk/process.inc index 63cdb8e9f..e81ff9d66 100644 --- a/libc/nt/thunk/process.inc +++ b/libc/nt/thunk/process.inc @@ -15,8 +15,5 @@ extern typeof(SetPriorityClass) *const __imp_SetPriorityClass __msabi; #define GetCurrentProcessId(...) __imp_GetCurrentProcessId(__VA_ARGS__) extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId __msabi; -#define CreateProcess(...) __imp_CreateProcessW(__VA_ARGS__) -extern typeof(CreateProcess) *const __imp_CreateProcessW __msabi; - extern typeof(FormatMessage) *const __imp_FormatMessageW __msabi; extern typeof(SetLastError) *const __imp_SetLastError __msabi; diff --git a/libc/runtime/arch_prctl.c b/libc/runtime/arch_prctl.c index 6cd3ec76b..547747804 100644 --- a/libc/runtime/arch_prctl.c +++ b/libc/runtime/arch_prctl.c @@ -161,6 +161,8 @@ static struct InterruptibleCall g_fsgs_icall; */ int arch_prctl(int code, int64_t addr) { void *fn = arch_prctl_fsgsbase; + +#if 0 if (!g_fsgs_once) { g_fsgs_once = true; if (X86_HAVE(FSGSBASE)) { @@ -180,6 +182,8 @@ int arch_prctl(int code, int64_t addr) { if (g_fsgs_once == 2) { return arch_prctl_fsgsbase(code, addr); } +#endif + switch (__hostos) { case METAL: return arch_prctl_msr(code, addr); diff --git a/libc/runtime/getsymboltable.c b/libc/runtime/getsymboltable.c index 897e5944b..797a50f2c 100644 --- a/libc/runtime/getsymboltable.c +++ b/libc/runtime/getsymboltable.c @@ -114,10 +114,12 @@ noasan static struct SymbolTable *GetSymbolTableFromElf(void) { * @return symbol table, or NULL w/ errno on first call */ noasan struct SymbolTable *GetSymbolTable(void) { + int ft, st; struct Zipos *z; static struct SymbolTable *t; if (!t) { - ++g_ftrace; + ft = g_ftrace, g_ftrace = 0; + st = __strace, __strace = 0; if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) { if ((t = GetSymbolTableFromZip(z))) { t->names = (uint32_t *)((char *)t + t->names_offset); @@ -127,7 +129,8 @@ noasan struct SymbolTable *GetSymbolTable(void) { if (!t) { t = GetSymbolTableFromElf(); } - --g_ftrace; + g_ftrace = ft; + __strace = st; } return t; } diff --git a/libc/runtime/msync-nt.c b/libc/runtime/msync-nt.c index 08006baef..dc6730547 100644 --- a/libc/runtime/msync-nt.c +++ b/libc/runtime/msync-nt.c @@ -22,7 +22,10 @@ #include "libc/nt/files.h" #include "libc/nt/memory.h" #include "libc/runtime/memtrack.internal.h" +#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/msync.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" #define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16)) @@ -41,13 +44,7 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) { rc = -1; break; } - if (flags & MS_SYNC) { - if (!FlushFileBuffers(_mmi.p[i].h)) { - // TODO(jart): what's up with this? - // rc = -1; - // break; - } - } + // TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC? } else { break; } diff --git a/libc/sock/dupsockfd.c b/libc/sock/dupsockfd.c new file mode 100644 index 000000000..f688c4d42 --- /dev/null +++ b/libc/sock/dupsockfd.c @@ -0,0 +1,32 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/nt/winsock.h" +#include "libc/sock/internal.h" + +textwindows struct SockFd *_dupsockfd(struct SockFd *sockfd) { + struct SockFd *newsf; + if ((newsf = calloc(1, sizeof(struct SockFd)))) { + newsf->family = sockfd->family; + newsf->type = sockfd->type; + newsf->protocol = sockfd->protocol; + newsf->event = WSACreateEvent(); + } + return newsf; +} diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 2615b0f62..6401fea14 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -139,6 +139,7 @@ void WinSockInit(void) hidden; int64_t __winsockerr(void) nocallback hidden; int __fixupnewsockfd(int, int) hidden; int64_t __winsockblock(int64_t, unsigned, int64_t) hidden; +struct SockFd *_dupsockfd(struct SockFd *) hidden; int sys_close_epoll(int) hidden; diff --git a/libc/sock/socket-nt.c b/libc/sock/socket-nt.c index ebe8b79bf..4a7497c36 100644 --- a/libc/sock/socket-nt.c +++ b/libc/sock/socket-nt.c @@ -36,6 +36,7 @@ */ STATIC_YOINK("GetAdaptersAddresses"); STATIC_YOINK("tprecode16to8"); +STATIC_YOINK("_dupsockfd"); textwindows int sys_socket_nt(int family, int type, int protocol) { int64_t h; diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index afdc3e8f7..2fc4ea27f 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -436,12 +436,11 @@ syscon ioctl TIOCINQ 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon at AT_FDCWD -100 -2 -100 -100 -100 -100 # faked nt -syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 0x400 0 syscon at AT_SYMLINK_NOFOLLOW 0x0100 0x20 0x0200 2 0x200 0x0100 # faked nt syscon at AT_REMOVEDIR 0x0200 0x80 0x0800 8 0x800 0x0200 # faked nt syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0 -syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 4 0 syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc. +syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 0x400 0 # uhhh wut # memfd_create() flags # diff --git a/libc/testlib/benchrunner.c b/libc/testlib/benchrunner.c index f5051aba2..0b4c57937 100644 --- a/libc/testlib/benchrunner.c +++ b/libc/testlib/benchrunner.c @@ -55,8 +55,10 @@ void testlib_runallbenchmarks(void) { int e; e = errno; _peekall(); - mlockall(MCL_CURRENT); - nice(-1); + if (!IsWindows()) { + mlockall(MCL_CURRENT); + nice(-1); + } errno = e; __log_level = kLogWarn; testlib_runtestcases(__bench_start, __bench_end, testlib_benchwarmup); diff --git a/libc/testlib/quota.c b/libc/testlib/quota.c index 3386fcdd7..da71fa5c9 100644 --- a/libc/testlib/quota.c +++ b/libc/testlib/quota.c @@ -44,9 +44,9 @@ static noasan relegated uint64_t CountMappedBytes(void) { static relegated void DieBecauseOfQuota(int rc, const char *message) { int e = errno; char hostname[32]; - __stpcpy(hostname, "unknown"); + stpcpy(hostname, "unknown"); gethostname(hostname, sizeof(hostname)); - kprintf("%s on %s pid %d\n", message, hostname, (long)__getpid()); + kprintf("%s on %s pid %d\n", message, hostname, (long)getpid()); PrintBacktraceUsingSymbols(2, 0, GetSymbolTable()); exit(rc); } diff --git a/libc/testlib/showerror.c b/libc/testlib/showerror.c index 50d9a8f66..aceb323fc 100644 --- a/libc/testlib/showerror.c +++ b/libc/testlib/showerror.c @@ -37,8 +37,8 @@ testonly void testlib_showerror(const char *file, int line, const char *func, const char *code, char *v1, char *v2) { char *p; char hostname[128]; - __getpid(); /* make strace easier to read */ - __getpid(); + if (!IsWindows()) __getpid(); /* make strace easier to read */ + if (!IsWindows()) __getpid(); __stpcpy(hostname, "unknown"); gethostname(hostname, sizeof(hostname)); kprintf("%serror%s%s:%s:%d%s: %s() in %s(%s) on %s\n" @@ -62,8 +62,8 @@ testonly void testlib_showerror_(int line, const char *wantcode, va_list va; char hostname[128]; e = errno; - __getpid(); - __getpid(); + if (!IsWindows()) __getpid(); + if (!IsWindows()) __getpid(); __stpcpy(hostname, "unknown"); gethostname(hostname, sizeof(hostname)); kprintf("%serror%s:%s%s:%d%s: %s(%s) on %s\n" diff --git a/libc/testlib/testmain.c b/libc/testlib/testmain.c index 629915bab..ae0dc2f69 100644 --- a/libc/testlib/testmain.c +++ b/libc/testlib/testmain.c @@ -23,6 +23,7 @@ #include "libc/calls/struct/sigaction.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/log/libfatal.internal.h" #include "libc/log/log.h" #include "libc/mem/mem.h" @@ -89,7 +90,7 @@ noasan int main(int argc, char *argv[]) { GetOpts(argc, argv); ShowCrashReports(); g_testlib_shoulddebugbreak = IsDebuggerPresent(false); - sys_getpid(); /* make strace easier to read */ + if (!IsWindows()) sys_getpid(); /* make strace easier to read */ testlib_clearxmmregisters(); testlib_runalltests(); if (!g_testlib_failed && runbenchmarks_ && weaken(testlib_runallbenchmarks)) { diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index 514d0b757..3dddd4dae 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -19,16 +19,19 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/log/check.h" -#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/nt/process.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" #include "libc/stdio/stdio.h" +#include "libc/str/str.h" #include "libc/sysv/consts/sig.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" @@ -52,10 +55,10 @@ wontreturn void testlib_abort(void) { static void SetupTmpDir(void) { char *p = g_testlib_tmpdir; - p = __stpcpy(p, "o/tmp/"); - p = __stpcpy(p, program_invocation_short_name), *p++ = '.'; - p = __intcpy(p, __getpid()), *p++ = '.'; - p = __intcpy(p, x++); + p = stpcpy(p, "o/tmp/"); + p = stpcpy(p, program_invocation_short_name), *p++ = '.'; + p = FormatInt64(p, getpid()), *p++ = '.'; + p = FormatInt64(p, x++); p[0] = '\0'; CHECK_NE(-1, makedirs(g_testlib_tmpdir, 0755), "%s", g_testlib_tmpdir); CHECK_EQ(1, isdirectory(g_testlib_tmpdir), "%s", g_testlib_tmpdir); @@ -66,7 +69,8 @@ static void SetupTmpDir(void) { static void TearDownTmpDir(void) { CHECK_NE(-1, chdir(g_testlib_olddir)); - CHECK_NE(-1, rmrf(g_testlib_tmpdir)); + CHECK_NE(-1, rmrf(g_testlib_tmpdir), "ugh %s", g_testlib_tmpdir); + CHECK_EQ(0, isdirectory(g_testlib_tmpdir), "%s", g_testlib_tmpdir); } /** @@ -98,11 +102,11 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end, if (weaken(SetUp)) weaken(SetUp)(); errno = 0; SetLastError(0); - sys_getpid(); + if (!IsWindows()) sys_getpid(); if (warmup) warmup(); testlib_clearxmmregisters(); (*fn)(); - sys_getpid(); + if (!IsWindows()) sys_getpid(); if (weaken(TearDown)) weaken(TearDown)(); if (weaken(testlib_enable_tmp_setup_teardown)) TearDownTmpDir(); } diff --git a/libc/x/makedirs.c b/libc/x/makedirs.c index 05e3e0a9d..1d3fd2eb8 100644 --- a/libc/x/makedirs.c +++ b/libc/x/makedirs.c @@ -16,12 +16,36 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/safemacros.internal.h" +#include "libc/bits/weaken.h" #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/errno.h" +#include "libc/log/log.h" #include "libc/mem/mem.h" #include "libc/str/str.h" #include "libc/x/x.h" +static int MakeDirs(const char *path, unsigned mode, int e) { + int rc; + char *dir; + if (mkdir(path, mode) != -1) { + errno = e; + return 0; + } + if (errno != ENOENT) return -1; + dir = xdirname(path); + if (strcmp(dir, path)) { + rc = MakeDirs(dir, mode, e); + } else { + rc = -1; + } + free(dir); + if (rc == -1) return -1; + errno = e; + return mkdir(path, mode); +} + /** * Recursively creates directory a.k.a. folder. * @@ -31,19 +55,5 @@ * @see mkdir() */ int makedirs(const char *path, unsigned mode) { - int e, rc; - char *dir; - e = errno; - if (mkdir(path, mode) != -1) return 0; - if (errno != ENOENT) return -1; - dir = xdirname(path); - if (strcmp(dir, path)) { - rc = makedirs(dir, mode); - } else { - rc = -1; - } - free(dir); - if (rc == -1) return -1; - errno = e; - return mkdir(path, mode); + return MakeDirs(path, mode, errno); } diff --git a/test/libc/calls/mkdir_test.c b/test/libc/calls/mkdir_test.c index 4b38b4567..8da031afd 100644 --- a/test/libc/calls/mkdir_test.c +++ b/test/libc/calls/mkdir_test.c @@ -27,6 +27,10 @@ char testlib_enable_tmp_setup_teardown; +void SetUp(void) { + errno = 0; +} + TEST(mkdir, testNothingExists_ENOENT) { EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); EXPECT_EQ(ENOENT, errno); @@ -55,8 +59,8 @@ TEST(mkdir, testPathIsDirectory_EEXIST) { } TEST(makedirs, testEmptyString_EEXIST) { - EXPECT_EQ(-1, makedirs("", 0755)); - EXPECT_EQ(EEXIST, errno); + EXPECT_EQ(-1, mkdir("", 0755)); + EXPECT_EQ(ENOENT, errno); } TEST(mkdirat, testRelativePath_opensRelativeToDirFd) { diff --git a/test/libc/calls/symlinkat_test.c b/test/libc/calls/symlinkat_test.c new file mode 100644 index 000000000..821cd50c9 --- /dev/null +++ b/test/libc/calls/symlinkat_test.c @@ -0,0 +1,52 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/stat.h" +#include "libc/fmt/fmt.h" +#include "libc/fmt/itoa.h" +#include "libc/rand/rand.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/at.h" +#include "libc/testlib/testlib.h" + +char testlib_enable_tmp_setup_teardown; +char p[2][PATH_MAX]; +struct stat st; + +TEST(symlinkat, test) { + sprintf(p[0], "%s.%d", program_invocation_short_name, rand()); + sprintf(p[1], "%s.%d", program_invocation_short_name, rand()); + + EXPECT_EQ(0, touch(p[0], 0644)); + EXPECT_EQ(0, symlink(p[0], p[1])); + + // check the normal file + EXPECT_FALSE(issymlink(p[0])); + EXPECT_EQ(0, lstat(p[0], &st)); + EXPECT_FALSE(S_ISLNK(st.st_mode)); + + // check the symlink file + EXPECT_TRUE(issymlink(p[1])); + EXPECT_EQ(0, lstat(p[1], &st)); + EXPECT_TRUE(S_ISLNK(st.st_mode)); + + // symlink isn't a symlink if we use it normally + EXPECT_EQ(0, stat(p[1], &st)); + EXPECT_FALSE(S_ISLNK(st.st_mode)); +} diff --git a/test/libc/stdio/dirstream_test.c b/test/libc/stdio/dirstream_test.c index f8afc6f0e..a0dfc29a9 100644 --- a/test/libc/stdio/dirstream_test.c +++ b/test/libc/stdio/dirstream_test.c @@ -29,13 +29,15 @@ STATIC_YOINK("zip_uri_support"); STATIC_YOINK("usr/share/zoneinfo/New_York"); +char testlib_enable_tmp_setup_teardown; + TEST(dirstream, test) { DIR *dir; struct dirent *ent; bool hasfoo = false; bool hasbar = false; char *dpath, *file1, *file2; - dpath = gc(xasprintf("%s%s%lu", kTmpPath, "dirstream", rand64())); + dpath = gc(xasprintf("%s.%d", "dirstream", rand())); file1 = gc(xasprintf("%s/%s", dpath, "foo")); file2 = gc(xasprintf("%s/%s", dpath, "bar")); EXPECT_NE(-1, mkdir(dpath, 0755)); @@ -74,7 +76,7 @@ TEST(rewinddir, test) { bool hasfoo = false; bool hasbar = false; char *dpath, *file1, *file2; - dpath = gc(xasprintf("%s%s%lu", kTmpPath, "dirstream", rand64())); + dpath = gc(xasprintf("%s.%d", "dirstream", rand())); file1 = gc(xasprintf("%s/%s", dpath, "foo")); file2 = gc(xasprintf("%s/%s", dpath, "bar")); EXPECT_NE(-1, mkdir(dpath, 0755)); diff --git a/third_party/quickjs/quickjs-libc.c b/third_party/quickjs/quickjs-libc.c index d3598fb2b..de6269ab5 100644 --- a/third_party/quickjs/quickjs-libc.c +++ b/third_party/quickjs/quickjs-libc.c @@ -627,10 +627,6 @@ static void setenv(const char *name, const char *value, int overwrite) free(str); } -static void unsetenv(const char *name) -{ - setenv(name, "", TRUE); -} #endif /* _WIN32 */ static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 5e46eeec5..ba9324705 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -2492,7 +2492,7 @@ static void OnSlowmo(void) { } else if (speed > 0) { speed = ClampSpeed(speed >> 1); } else { - speed = ClampSpeed(speed << 1); + speed = ClampSpeed((unsigned)speed << 1); } SetStatus("speed %,d", speed); } diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index 5f54e73f8..0cf9a0d01 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -1604,6 +1604,9 @@ static void OpNopEv(struct Machine *m, uint32_t rde) { case 0105: OpBofram(m, rde); break; + case 0106: + OpBofram(m, rde); + break; case 0007: case 0107: case 0207: diff --git a/tool/build/lib/pml4t.c b/tool/build/lib/pml4t.c index 4d67a7bf8..9d3f7a6ab 100644 --- a/tool/build/lib/pml4t.c +++ b/tool/build/lib/pml4t.c @@ -35,7 +35,7 @@ static void FindContiguousMemoryRangesImpl( entry = Read64(m->real.p + pt + i * 8); if (!(entry & 1)) continue; entry &= 0x7ffffffff000; - page = (addr | i << level) << 16 >> 16; + page = (int64_t)((uint64_t)(addr | i << level) << 16) >> 16; if (level == 12) { if (ranges->i && page == ranges->p[ranges->i - 1].b) { ranges->p[ranges->i - 1].b += 0x1000;