Make improvements

- You can now run `make -j8 toolchain` on Windows
- You can now run `make -j` on MacOS ARM64 and BSD OSes
- You can now use our Emacs dev environment on MacOS/Windows
- Fix bug where the x16 register was being corrupted by --ftrace
- The programs under build/bootstrap/ are updated as fat binaries
- The Makefile now explains how to download cosmocc-0.0.12 toolchain
- The build scripts under bin/ now support "cosmo" branded toolchains
- stat() now goes faster on Windows (shaves 100ms off `make` latency)
- Code cleanup and added review on the Windows signal checking code
- posix_spawnattr_setrlimit() now works around MacOS ARM64 bugs
- Landlock Make now favors posix_spawn() on non-Linux/OpenBSD
- posix_spawn() now has better --strace logging on Windows
- fstatat() can now avoid EACCES in more cases on Windows
- fchmod() can now change the readonly bit on Windows
This commit is contained in:
Justine Tunney 2023-10-14 20:57:15 -07:00
parent 06c6baaf50
commit c9fecf3a55
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
109 changed files with 1188 additions and 454 deletions

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describebacktrace.internal.h"
@ -28,9 +29,11 @@
*/
void __assert_fail(const char *expr, const char *file, int line) {
char ibuf[12];
sigset_t m = __sig_block();
FormatInt32(ibuf, line);
tinyprint(2, file, ":", ibuf, ": assert(", expr, ") failed (",
program_invocation_short_name, " ",
DescribeBacktrace(__builtin_frame_address(0)), ")\n", NULL);
__sig_unblock(m);
abort();
}

View file

@ -1,6 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
#define COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
#include "libc/thread/thread.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@ -26,23 +27,6 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
// code size optimization
// <sync libc/sysv/consts.sh>
#define _O_APPEND 0x00000400 // kNtFileAppendData
#define _O_CREAT 0x00000040 // kNtOpenAlways
#define _O_EXCL 0x00000080 // kNtCreateNew
#define _O_TRUNC 0x00000200 // kNtCreateAlways
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32)
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
#define _O_CLOEXEC 0x00080000
// </sync libc/sysv/consts.sh>
textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
uint32_t *out_share, uint32_t *out_disp,
uint32_t *out_attr) {

View file

@ -0,0 +1,22 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_
// code size optimization
// <sync libc/sysv/consts.sh>
#define _O_APPEND 0x00000400 // kNtFileAppendData
#define _O_CREAT 0x00000040 // kNtOpenAlways
#define _O_EXCL 0x00000080 // kNtCreateNew
#define _O_TRUNC 0x00000200 // kNtCreateAlways
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32)
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
#define _O_NOFOLLOW 0x00020000 // kNtFileFlagOpenReparsePoint
#define _O_CLOEXEC 0x00080000
// </sync libc/sysv/consts.sh>
#endif /* COSMOPOLITAN_LIBC_CALLS_CREATEFILEFLAGS_INTERNAL_H_ */

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.internal.h"
@ -65,10 +66,10 @@ static textwindows int sys_dup_nt_impl(int oldfd, int newfd, int flags,
kNtDuplicateSameAccess)) {
g_fds.p[newfd] = g_fds.p[oldfd];
g_fds.p[newfd].handle = handle;
if (flags & O_CLOEXEC) {
g_fds.p[newfd].flags |= O_CLOEXEC;
if (flags & _O_CLOEXEC) {
g_fds.p[newfd].flags |= _O_CLOEXEC;
} else {
g_fds.p[newfd].flags &= ~O_CLOEXEC;
g_fds.p[newfd].flags &= ~_O_CLOEXEC;
}
rc = newfd;
} else {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
@ -41,17 +42,17 @@ static textwindows int sys_fadvise_nt_impl(int fd, uint64_t offset,
h1 = g_fds.p[fd].handle;
mode = g_fds.p[fd].mode;
flags = g_fds.p[fd].flags;
flags &= ~(O_SEQUENTIAL | O_RANDOM);
flags &= ~(_O_SEQUENTIAL | _O_RANDOM);
switch (advice) {
case MADV_NORMAL:
break;
case MADV_RANDOM:
flags |= O_RANDOM;
flags |= _O_RANDOM;
break;
case MADV_WILLNEED:
case MADV_SEQUENTIAL:
flags |= O_SEQUENTIAL;
flags |= _O_SEQUENTIAL;
break;
default:
return einval();

57
libc/calls/fchmod-nt.c Normal file
View file

@ -0,0 +1,57 @@
/*-*- 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 2023 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/struct/fd.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/fileinfobyhandleclass.h"
#include "libc/nt/files.h"
#include "libc/nt/struct/filebasicinfo.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
// validate file descriptor
if (fd + 0u >= g_fds.n) return ebadf();
if (g_fds.p[fd].kind == kFdEmpty) return ebadf();
// get current information
struct NtFileBasicInfo fbi;
if (!GetFileInformationByHandleEx(g_fds.p[fd].handle, kNtFileBasicInfo, &fbi,
sizeof(fbi))) {
return __winerr();
}
// change attributes
if (mode & 0222) {
fbi.FileAttributes &= ~kNtFileAttributeReadonly;
} else {
fbi.FileAttributes |= kNtFileAttributeReadonly;
}
// set new attributes
if (!SetFileInformationByHandle(g_fds.p[fd].handle, kNtFileBasicInfo, &fbi,
sizeof(fbi))) {
return __winerr();
}
// all good
return 0;
}

View file

@ -17,18 +17,32 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Changes file permissions via open()'d file descriptor.
*
* @param mode contains octal flags (base 8)
* @raise EROFS if `fd` is a `/zip/...` file
* @asyncsignalsafe
* @see chmod()
*/
int fchmod(int fd, uint32_t mode) {
// TODO(jart): Windows
return sys_fchmod(fd, mode);
int rc;
if (__isfdkind(fd, kFdZip)) {
rc = erofs();
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
rc = sys_fchmod(fd, mode);
} else if (IsWindows()) {
rc = sys_fchmod_nt(fd, mode);
} else {
rc = enosys();
}
STRACE("fchmod(%d, %#o) → %d% m", fd, mode, rc);
return rc;
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/flock.h"
@ -318,7 +319,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0), start);
}
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
@ -329,21 +330,21 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
__isfdkind(fd, kFdConsole) || //
__isfdkind(fd, kFdDevNull)) {
if (cmd == F_GETFL) {
rc = g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_DIRECT | O_NONBLOCK |
O_RANDOM | O_SEQUENTIAL);
rc = g_fds.p[fd].flags & (O_ACCMODE | _O_APPEND | _O_DIRECT |
_O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL);
} else if (cmd == F_SETFL) {
rc = sys_fcntl_nt_setfl(fd, arg);
} else if (cmd == F_GETFD) {
if (g_fds.p[fd].flags & O_CLOEXEC) {
if (g_fds.p[fd].flags & _O_CLOEXEC) {
rc = FD_CLOEXEC;
} else {
rc = 0;
}
} else if (cmd == F_SETFD) {
if (arg & FD_CLOEXEC) {
g_fds.p[fd].flags |= O_CLOEXEC;
g_fds.p[fd].flags |= _O_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
g_fds.p[fd].flags &= ~_O_CLOEXEC;
}
rc = 0;
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {

View file

@ -36,9 +36,8 @@ textwindows int sys_fdatasync_nt(int fd, bool fake) {
// kNtGenericWrite access, and MSDN doesn't document it.
return 0;
}
if (_check_cancel() == -1) return -1;
if (_check_signal(false) == -1) return -1;
if (fake) return 0;
if (_check_signal(false) == -1) return -1;
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
}

View file

@ -107,11 +107,12 @@ textwindows int sys_fstat_nt(int fd, struct stat *st) {
case kFdSocket:
return sys_fstat_nt_socket(g_fds.p[fd].kind, st);
default:
return sys_fstat_nt_handle(g_fds.p[fd].handle, st);
return sys_fstat_nt_handle(g_fds.p[fd].handle, 0, st);
}
}
textwindows int sys_fstat_nt_handle(int64_t handle, struct stat *out_st) {
textwindows int sys_fstat_nt_handle(int64_t handle, const char16_t *path,
struct stat *out_st) {
struct stat st = {0};
// Always set st_blksize to avoid divide by zero issues.
@ -143,7 +144,7 @@ textwindows int sys_fstat_nt_handle(int64_t handle, struct stat *out_st) {
}
st.st_mode = 0444 & ~umask;
if ((wst.dwFileAttributes & kNtFileAttributeDirectory) ||
IsWindowsExecutable(handle)) {
IsWindowsExecutable(handle, path)) {
st.st_mode |= 0111 & ~umask;
}
st.st_flags = wst.dwFileAttributes;

View file

@ -74,10 +74,11 @@ TryAgain:
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
: 0),
0)) != -1) {
rc = st ? sys_fstat_nt_handle(fh, st) : 0;
rc = st ? sys_fstat_nt_handle(fh, path16, st) : 0;
CloseHandle(fh);
} else if (dwDesiredAccess == kNtFileGenericRead &&
GetLastError() == kNtErrorSharingViolation) {
(GetLastError() == kNtErrorAccessDenied ||
GetLastError() == kNtErrorSharingViolation)) {
dwDesiredAccess = kNtFileReadAttributes;
errno = e;
goto TryAgain;

View file

@ -0,0 +1,94 @@
/*-*- 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 2023 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/intrin/asmflag.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/sysv/consts/grnd.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__
static bool GetRandomRdseed(uint64_t *out) {
int i;
char cf;
uint64_t x;
for (i = 0; i < 10; ++i) {
asm volatile(CFLAG_ASM("rdseed\t%1")
: CFLAG_CONSTRAINT(cf), "=r"(x)
: /* no inputs */
: "cc");
if (cf) {
*out = x;
return true;
}
asm volatile("pause");
}
return false;
}
static bool GetRandomRdrand(uint64_t *out) {
int i;
char cf;
uint64_t x;
for (i = 0; i < 10; ++i) {
asm volatile(CFLAG_ASM("rdrand\t%1")
: CFLAG_CONSTRAINT(cf), "=r"(x)
: /* no inputs */
: "cc");
if (cf) {
*out = x;
return true;
}
asm volatile("pause");
}
return false;
}
static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) {
uint64_t x;
size_t i, j;
for (i = 0; i < n; i += j) {
TryAgain:
if (!impl(&x)) {
if (f || i >= 256) break;
goto TryAgain;
}
for (j = 0; j < 8 && i + j < n; ++j) {
p[i + j] = x;
x >>= 8;
}
}
return n;
}
ssize_t sys_getrandom_metal(char *p, size_t n, int f) {
if (f & GRND_RANDOM) {
if (X86_HAVE(RDSEED)) {
return GetRandomCpu(p, n, f, GetRandomRdseed);
} else {
return enosys();
}
} else {
if (X86_HAVE(RDRND)) {
return GetRandomCpu(p, n, f, GetRandomRdrand);
} else {
return enosys();
}
}
}
#endif /* __x86_64__ */

View file

@ -55,78 +55,10 @@
__static_yoink("rdrand_init");
int sys_getentropy(void *, size_t) asm("sys_getrandom");
ssize_t sys_getrandom_metal(char *, size_t, int);
static bool have_getrandom;
static bool GetRandomRdseed(uint64_t *out) {
int i;
char cf;
uint64_t x;
for (i = 0; i < 10; ++i) {
asm volatile(CFLAG_ASM("rdseed\t%1")
: CFLAG_CONSTRAINT(cf), "=r"(x)
: /* no inputs */
: "cc");
if (cf) {
*out = x;
return true;
}
asm volatile("pause");
}
return false;
}
static bool GetRandomRdrand(uint64_t *out) {
int i;
char cf;
uint64_t x;
for (i = 0; i < 10; ++i) {
asm volatile(CFLAG_ASM("rdrand\t%1")
: CFLAG_CONSTRAINT(cf), "=r"(x)
: /* no inputs */
: "cc");
if (cf) {
*out = x;
return true;
}
asm volatile("pause");
}
return false;
}
static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) {
uint64_t x;
size_t i, j;
for (i = 0; i < n; i += j) {
TryAgain:
if (!impl(&x)) {
if (f || i >= 256) break;
goto TryAgain;
}
for (j = 0; j < 8 && i + j < n; ++j) {
p[i + j] = x;
x >>= 8;
}
}
return n;
}
static ssize_t GetRandomMetal(char *p, size_t n, int f) {
if (f & GRND_RANDOM) {
if (X86_HAVE(RDSEED)) {
return GetRandomCpu(p, n, f, GetRandomRdseed);
} else {
return enosys();
}
} else {
if (X86_HAVE(RDRND)) {
return GetRandomCpu(p, n, f, GetRandomRdrand);
} else {
return enosys();
}
}
}
static void GetRandomEntropy(char *p, size_t n) {
unassert(n <= 256);
if (sys_getentropy(p, n)) notpossible;
@ -181,8 +113,10 @@ ssize_t __getrandom(void *p, size_t n, unsigned f) {
}
} else if (IsFreebsd() || IsNetbsd()) {
rc = GetRandomBsd(p, n, GetRandomArnd);
#ifdef __x86_64__
} else if (IsMetal()) {
rc = GetRandomMetal(p, n, f);
rc = sys_getrandom_metal(p, n, f);
#endif
} else {
BEGIN_CANCELATION_POINT;
rc = GetDevUrandom(p, n);

View file

@ -24,11 +24,11 @@ int __ensurefds(int);
uint32_t sys_getuid_nt(void);
int __ensurefds_unlocked(int);
void __printfds(struct Fd *, size_t);
int IsWindowsExecutable(int64_t);
int CountConsoleInputBytes(void);
int FlushConsoleInputBytes(void);
int64_t GetConsoleInputHandle(void);
int64_t GetConsoleOutputHandle(void);
int IsWindowsExecutable(int64_t, const char16_t *);
void InterceptTerminalCommands(const char *, size_t);
forceinline int64_t __getfdhandleactual(int fd) {

View file

@ -36,8 +36,10 @@ textwindows int _check_cancel(void) {
textwindows int _check_signal(bool restartable) {
int status;
if (_check_cancel() == -1) return -1;
if (!_weaken(__sig_check)) return 0;
if (!(status = _weaken(__sig_check)())) return 0;
if (_check_cancel() == -1) return -1;
if (status == 2 && restartable) return 0;
return eintr();
}

View file

@ -115,6 +115,7 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
*arg = avail;
return 0;
} else if (GetLastError() == kNtErrorBrokenPipe) {
*arg = 0; // win32 can give epipe on reader end
return 0;
} else {
return __winerr();

View file

@ -108,7 +108,7 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
0)) != -1) {
unassert(GetFileInformationByHandle(hFile, &wst));
if ((wst.dwFileAttributes & kNtFileAttributeDirectory) ||
IsWindowsExecutable(hFile)) {
IsWindowsExecutable(hFile, pathname)) {
rc = 0;
} else {
rc = eacces();

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.internal.h"
@ -56,31 +57,31 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
// implement no follow flag
// you can't open symlinks; use readlink
// this flag only applies to the final path component
// if O_NOFOLLOW_ANY is passed (-1 on NT) it'll be rejected later
// if _O_NOFOLLOW_ANY is passed (-1 on NT) it'll be rejected later
uint32_t fattr = GetFileAttributes(path16);
if (flags & O_NOFOLLOW) {
if (flags & _O_NOFOLLOW) {
if (fattr != -1u && (fattr & kNtFileAttributeReparsePoint)) {
return eloop();
}
flags &= ~O_NOFOLLOW; // don't actually pass this to win32
flags &= ~_O_NOFOLLOW; // don't actually pass this to win32
}
// handle some obvious cases while we have the attributes
// we should ideally resolve symlinks ourself before doing this
if (fattr != -1u) {
if (fattr & kNtFileAttributeDirectory) {
if ((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT)) {
if ((flags & O_ACCMODE) != O_RDONLY || (flags & _O_CREAT)) {
// tried to open directory for writing. note that our
// undocumented O_TMPFILE support on windows requires that a
// undocumented _O_TMPFILE support on windows requires that a
// filename be passed, rather than a directory like linux.
return eisdir();
}
// on posix, the o_directory flag is an advisory safeguard that
// isn't required. on windows, it's mandatory for opening a dir
flags |= O_DIRECTORY;
flags |= _O_DIRECTORY;
} else if (!(fattr & kNtFileAttributeReparsePoint)) {
// we know for certain file isn't a directory
if (flags & O_DIRECTORY) {
if (flags & _O_DIRECTORY) {
return enotdir();
}
}
@ -186,7 +187,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
ssize_t rc;
BLOCK_SIGNALS;
__fds_lock();
if (!(flags & O_CREAT)) mode = 0;
if (!(flags & _O_CREAT)) mode = 0;
if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
if (startswith(file, "/dev/")) {
if (!strcmp(file + 5, "tty")) {

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/nt/enum/wait.h"
@ -45,11 +46,13 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
om = __sig_beginwait(waitmask);
if ((rc = _check_cancel()) != -1 && (rc = _check_signal(restartable)) != -1) {
unassert((wi = WaitForSingleObject(sem, msdelay)) != -1u);
if (restartable && !(pt->pt_flags & PT_RESTARTABLE)) rc = eintr();
rc |= _check_signal(restartable);
if (rc == -1 && errno == EINTR) _check_cancel();
if ((rc = _check_signal(restartable)) != -1) {
if ((wi = WaitForSingleObject(sem, msdelay)) != -1u) {
if (restartable && !(pt->pt_flags & PT_RESTARTABLE)) rc = eintr();
rc |= _check_signal(restartable);
} else {
rc = __winerr();
}
}
__sig_finishwait(om);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release);

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
@ -729,7 +730,7 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
ms = __ttyconf.vtime * 100;
}
}
if (f->flags & O_NONBLOCK) {
if (f->flags & _O_NONBLOCK) {
return eagain(); // standard unix non-blocking
}
pt = _pthread_self();
@ -738,12 +739,14 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
pthread_cleanup_push((void *)CloseHandle, (void *)sem);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
m = __sig_beginwait(waitmask);
if ((rc = _check_cancel()) != -1 && (rc = _check_signal(true)) != -1) {
if ((rc = _check_signal(true)) != -1) {
int64_t hands[2] = {sem, __keystroke.cin};
unassert(WaitForMultipleObjects(2, hands, 0, ms) != -1u);
if (~pt->pt_flags & PT_RESTARTABLE) rc = eintr();
rc |= _check_signal(true);
if (rc == -1 && errno == EINTR) _check_cancel();
if (WaitForMultipleObjects(2, hands, 0, ms) != -1u) {
if (!(pt->pt_flags & PT_RESTARTABLE)) rc = eintr();
rc |= _check_signal(true);
} else {
rc = __winerr();
}
}
__sig_finishwait(m);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/fd.internal.h"
@ -140,15 +141,16 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
pt->pt_flags |= PT_RESTARTABLE;
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_IO, memory_order_release);
m = __sig_beginwait(waitmask);
if (f->flags & O_NONBLOCK) {
if (f->flags & _O_NONBLOCK) {
CancelIoEx(handle, &overlap);
eagained = true;
} else if (_check_cancel()) {
CancelIoEx(handle, &overlap);
canceled = true;
} else if (_check_signal(true)) {
CancelIoEx(handle, &overlap);
eintered = true;
if (errno == ECANCELED) {
canceled = true;
} else {
eintered = true;
}
} else {
WaitForSingleObject(overlap.hEvent, -1u);
}
@ -197,7 +199,7 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
// it's also fine to do nothing here; punt to next cancelation point
if (GetLastError() == kNtErrorOperationAborted) {
if (_check_cancel() == -1) return ecanceled();
if (!eintered && _check_signal(false)) return eintr();
if (!eintered && _check_signal(false)) return -1;
}
// if we chose to process a pending signal earlier then we preserve

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
@ -36,8 +37,9 @@ textwindows int sys_fcntl_nt_setfl(int fd, unsigned flags) {
// - O_DIRECT works but haven't tested
//
// the other bits are ignored.
unsigned allowed = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT | O_NONBLOCK;
unsigned needreo = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT;
unsigned allowed =
_O_APPEND | _O_SEQUENTIAL | _O_RANDOM | _O_DIRECT | _O_NONBLOCK;
unsigned needreo = _O_APPEND | _O_SEQUENTIAL | _O_RANDOM | _O_DIRECT;
unsigned newflag = (g_fds.p[fd].flags & ~allowed) | (flags & allowed);
if (g_fds.p[fd].kind == kFdFile &&

View file

@ -33,9 +33,7 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bsf.h"
#include "libc/intrin/bsr.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/popcnt.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
@ -105,7 +103,7 @@ static textwindows int __sig_getter(struct CosmoTib *tib, atomic_ulong *sigs) {
pending = atomic_load_explicit(sigs, memory_order_acquire);
masked = atomic_load_explicit(&tib->tib_sigmask, memory_order_acquire);
if ((deliverable = pending & ~masked)) {
sig = _bsf(deliverable) + 1;
sig = _bsfl(deliverable) + 1;
bit = 1ull << (sig - 1);
if (atomic_fetch_and_explicit(sigs, ~bit, memory_order_acq_rel) & bit) {
return sig;
@ -263,7 +261,7 @@ textwindows void __sig_cancel(struct PosixThread *pt, int sig, unsigned flags) {
WakeByAddressSingle(blocker);
}
// the user's signal handler callback is composed with this trampoline
// the user's signal handler callback is wrapped with this trampoline
static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
int sig = sf->si.si_signo;
struct CosmoTib *tib = __get_tls();

View file

@ -9,7 +9,7 @@ int sys_fstat(int, struct stat *);
int sys_fstatat(int, const char *, struct stat *, int);
int sys_fstat_nt(int, struct stat *);
int sys_fstat_nt_special(int, struct stat *);
int sys_fstat_nt_handle(int64_t, struct stat *);
int sys_fstat_nt_handle(int64_t, const char16_t *, struct stat *);
int sys_fstatat_nt(int, const char *, struct stat *, int);
int sys_lstat_nt(const char *, struct stat *);
int sys_fstat_metal(int, struct stat *);

View file

@ -1,7 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_H_
#define SYS_NMLN 321
#define SYS_NMLN 150
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -12,6 +12,7 @@ int sys_execve_nt(const char *, char *const[], char *const[]);
int sys_faccessat_nt(int, const char *, int, uint32_t);
int sys_fadvise_nt(int, uint64_t, uint64_t, int);
int sys_fchdir_nt(int);
int sys_fchmod_nt(int, uint32_t);
int sys_fchmodat_nt(int, const char *, uint32_t, int);
int sys_fcntl_nt(int, int, uintptr_t);
int sys_fdatasync_nt(int, bool);

View file

@ -91,7 +91,12 @@ errno_t ttyname_r(int fd, char *buf, size_t size) {
} else if (IsWindows()) {
res = sys_ttyname_nt(fd, buf, size);
} else {
res = ENOSYS;
// TODO(jart): Use that fstat(dev/ino) + readdir(/dev/) trick.
if (strlcpy(buf, "/dev/tty", size) < size) {
res = 0;
} else {
res = ERANGE;
}
}
errno = e;
STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)size, buf,

View file

@ -18,14 +18,57 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/intrin/bits.h"
#include "libc/nt/errors.h"
#include "libc/nt/events.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "third_party/linenoise/linenoise.h"
#define EXT(s) READ32LE(s "\0\0")
static bool IsGraph(wint_t c) {
return 0x21 <= c && c <= 0x7E;
}
static uint32_t GetFileExtension(const char16_t *s) {
uint32_t w;
size_t i, n;
n = s ? strlen16(s) : 0;
for (i = w = 0; n--;) {
wint_t c = s[n];
if (!IsGraph(c)) return 0;
if (c == '.') break;
if (++i > 4) return 0;
w <<= 8;
w |= kToLower[c];
}
return w;
}
// checks if file should be considered an executable on windows
textwindows int IsWindowsExecutable(int64_t handle) {
textwindows int IsWindowsExecutable(int64_t handle, const char16_t *path) {
// fast path known file extensions
// shaves away 100ms of gnu make latency in cosmo monorepo
uint32_t ext;
if (!IsTiny() && (ext = GetFileExtension(path))) {
if (ext == EXT("c") || // c code
ext == EXT("cc") || // c++ code
ext == EXT("h") || // c/c++ header
ext == EXT("s") || // assembly code
ext == EXT("o")) { // object file
return false;
}
if (ext == EXT("com") || // mz executable
ext == EXT("exe") || // mz executable
ext == EXT("sh")) { // bourne shells
return true;
}
}
// read first two bytes of file
// access() and stat() aren't cancelation points