mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-26 07:49:05 +00:00
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:
parent
29bf8b1a30
commit
4f98ad1054
79 changed files with 707 additions and 197 deletions
libc
bits
calls
close-nt.cclose.cdup-nt.cfaccessat.cfadvise.cfchmodat-nt.cfchmodat.cfchownat.cfcntl-nt.cfstat-nt.cfstatat.cinternal.hioctl_tiocgwinsz-nt.cisatty.cisdirectory-nt.cisregularfile-nt.cissymlink-nt.clinkat.cmkdirat-nt.cmkdirat.cntspawn.coffset2overlap.copen-nt.copenat.cread-nt.creadlinkat-nt.creadlinkat.crenameat.csigwinch-nt.cstrace.internal.hstrace_dirfd.greg.csymlinkat.cunlinkat-nt.cunlinkat.cutimensat.cwrite-nt.c
fmt
intrin
createdirectory.greg.ccreateprocess.greg.ccxafinalize.cdescribentfileflagsandattributes.greg.cdeviceiocontrol.greg.cexit.greg.cgetfileattributes.greg.cintrin.mkkdos2errno.Swinerr.greg.c
log
mem
nt
runtime
sock
sysv
testlib
x
test/libc
third_party/quickjs
tool/build
23
libc/bits/midpoint.h
Normal file
23
libc/bits/midpoint.h
Normal 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_ */
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -63,7 +63,6 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
|
|||
__winerr();
|
||||
}
|
||||
} else {
|
||||
STRACE("%s() failed %m", "GetConsoleMode");
|
||||
enotty();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
27
libc/calls/strace_dirfd.greg.c
Normal file
27
libc/calls/strace_dirfd.greg.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
41
libc/intrin/createdirectory.greg.c
Normal file
41
libc/intrin/createdirectory.greg.c
Normal 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;
|
||||
}
|
53
libc/intrin/createprocess.greg.c
Normal file
53
libc/intrin/createprocess.greg.c
Normal 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;
|
||||
}
|
|
@ -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 (;;) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
47
libc/intrin/deviceiocontrol.greg.c
Normal file
47
libc/intrin/deviceiocontrol.greg.c
Normal 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;
|
||||
}
|
|
@ -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)
|
||||
|
|
41
libc/intrin/getfileattributes.greg.c
Normal file
41
libc/intrin/getfileattributes.greg.c
Normal 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;
|
||||
}
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
86
libc/mem/copyfd.c
Normal 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
10
libc/mem/io.h
Normal 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_ */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
32
libc/sock/dupsockfd.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
52
test/libc/calls/symlinkat_test.c
Normal file
52
test/libc/calls/symlinkat_test.c
Normal 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));
|
||||
}
|
|
@ -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));
|
||||
|
|
4
third_party/quickjs/quickjs-libc.c
vendored
4
third_party/quickjs/quickjs-libc.c
vendored
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue