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
This commit is contained in:
Justine Tunney 2022-04-07 20:30:04 -07:00
parent 29bf8b1a30
commit 4f98ad1054
79 changed files with 707 additions and 197 deletions

23
libc/bits/midpoint.h Normal file
View file

@ -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_ */

View file

@ -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) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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"

View file

@ -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;
}

View file

@ -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;

View file

@ -63,7 +63,6 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
__winerr();
}
} else {
STRACE("%s() failed %m", "GetConsoleMode");
enotty();
}
} else {

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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) */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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.
*

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 (;;) {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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 \

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

86
libc/mem/copyfd.c Normal file
View file

@ -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;
}

10
libc/mem/io.h Normal file
View file

@ -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_ */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

32
libc/sock/dupsockfd.c Normal file
View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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
#

View file

@ -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);

View file

@ -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);
}

View file

@ -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"

View file

@ -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)) {

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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));
}

View file

@ -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));

View file

@ -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,

View file

@ -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);
}

View file

@ -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:

View file

@ -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;