mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 07:18:30 +00:00
finish intellisense support and sync with upstream
This commit is contained in:
commit
ec9bfd8c56
221 changed files with 2360 additions and 1439 deletions
|
@ -21,6 +21,7 @@ LIBC_CALLS_A_FILES := \
|
|||
$(wildcard libc/calls/struct/*) \
|
||||
$(wildcard libc/calls/*)
|
||||
LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES))
|
||||
LIBC_CALLS_A_INCS = $(filter %.inc,$(LIBC_CALLS_A_FILES))
|
||||
LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES))
|
||||
LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
|
||||
|
||||
|
@ -43,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
|||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_RAND \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV_CALLS \
|
||||
|
@ -86,12 +86,11 @@ o/$(MODE)/libc/calls/mkntenvblock.o: \
|
|||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_CALLS_INCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_INCS))
|
||||
LIBC_CALLS_BINS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_BINS))
|
||||
LIBC_CALLS_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS))
|
||||
LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS))
|
||||
|
||||
.PHONY: o/$(MODE)/libc/calls
|
||||
o/$(MODE)/libc/calls: \
|
||||
o/$(MODE)/libc/calls/hefty \
|
||||
$(LIBC_CALLS_CHECKS)
|
||||
o/$(MODE)/libc/calls: $(LIBC_CALLS_CHECKS)
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see fchmod()
|
||||
* @syscall
|
||||
*/
|
||||
int chmod(const char *pathname, uint32_t mode) {
|
||||
if (!pathname) return efault();
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
* errno isn't restored to its original value, to detect prec. loss
|
||||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int clock_gettime(int clockid, struct timespec *out_ts) {
|
||||
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int close$nt(int fd) {
|
||||
bool32 ok;
|
||||
if (g_fds.p[fd].kind == kFdFile) {
|
||||
if (g_fds.p[fd].kind == kFdFile &&
|
||||
GetFileType(g_fds.p[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
|
||||
|
@ -32,6 +34,8 @@ textwindows int close$nt(int fd) {
|
|||
FlushFileBuffers(g_fds.p[fd].handle);
|
||||
}
|
||||
ok = CloseHandle(g_fds.p[fd].handle);
|
||||
if (g_fds.p[fd].kind == kFdConsole) ok &= CloseHandle(g_fds.p[fd].extra);
|
||||
if (g_fds.p[fd].kind == kFdConsole) {
|
||||
ok &= CloseHandle(g_fds.p[fd].extra);
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
}
|
||||
|
|
|
@ -53,8 +53,7 @@ int close(int fd) {
|
|||
rc = ebadf();
|
||||
}
|
||||
if (!__vforked && fd < g_fds.n) {
|
||||
g_fds.p[fd].kind = kFdEmpty;
|
||||
g_fds.f = MIN(g_fds.f, fd);
|
||||
__releasefd(fd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/hefty/copyfile.h"
|
||||
#include "libc/calls/copyfile.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
|
||||
|
||||
#define COPYFILE_NOCLOBBER 1
|
||||
#define COPYFILE_PRESERVE_OWNER 2
|
||||
|
@ -12,4 +12,4 @@ int copyfile(const char *, const char *, int) paramsnonnull();
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ */
|
|
@ -30,17 +30,18 @@
|
|||
*/
|
||||
textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
||||
int64_t proc;
|
||||
if (!__isfdkind(oldfd, kFdFile)) return ebadf();
|
||||
if (oldfd < 0) return einval();
|
||||
if (oldfd >= g_fds.n ||
|
||||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
|
||||
g_fds.p[oldfd].kind != kFdConsole)) {
|
||||
return ebadf();
|
||||
}
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __getemptyfd()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else if (__ensurefds(newfd) != -1) {
|
||||
if (g_fds.p[newfd].kind != kFdEmpty) {
|
||||
close(newfd);
|
||||
}
|
||||
if ((newfd = __reservefd()) == -1) return -1;
|
||||
} else {
|
||||
return -1;
|
||||
if (__ensurefds(newfd) == -1) return -1;
|
||||
if (g_fds.p[newfd].kind) close(newfd);
|
||||
g_fds.p[newfd].kind = kFdReserved;
|
||||
}
|
||||
proc = GetCurrentProcess();
|
||||
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
|
||||
|
@ -49,6 +50,7 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
|||
g_fds.p[newfd].flags = flags;
|
||||
return newfd;
|
||||
} else {
|
||||
__releasefd(newfd);
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,14 @@ int32_t dup3$sysv(int32_t oldfd, int32_t newfd, int flags) {
|
|||
static bool once, demodernize;
|
||||
int olderr, fd;
|
||||
if (!once) {
|
||||
once = true;
|
||||
olderr = errno;
|
||||
fd = __dup3$sysv(oldfd, newfd, flags);
|
||||
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
|
||||
demodernize = true;
|
||||
once = true;
|
||||
errno = olderr;
|
||||
} else {
|
||||
once = true;
|
||||
return fd;
|
||||
}
|
||||
} else if (!demodernize) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -24,24 +25,29 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int __ensurefds(int fd) {
|
||||
size_t n;
|
||||
struct Fd *p;
|
||||
if (fd < g_fds.n) return fd;
|
||||
if (weaken(malloc)) {
|
||||
n = MAX(fd + 1, g_fds.n + (g_fds.n << 1));
|
||||
if ((p = weaken(malloc)(n * sizeof(*p)))) {
|
||||
memcpy(p, g_fds.p, g_fds.n * sizeof(*p));
|
||||
memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p));
|
||||
if (g_fds.p != g_fds.__init_p && weaken(free)) {
|
||||
weaken(free)(g_fds.p);
|
||||
size_t n1, n2;
|
||||
struct Fd *p1, *p2;
|
||||
for (;;) {
|
||||
p1 = g_fds.p;
|
||||
n1 = g_fds.n;
|
||||
if (fd < n1) return fd;
|
||||
if (weaken(malloc)) {
|
||||
n2 = MAX(fd + 1, n1 + (n1 << 1));
|
||||
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||
memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1));
|
||||
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
|
||||
if (cmpxchg(&g_fds.p, p1, p2)) {
|
||||
g_fds.n = n2;
|
||||
return fd;
|
||||
} else if (weaken(free)) {
|
||||
weaken(free)(p2);
|
||||
}
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
g_fds.p = p;
|
||||
g_fds.n = n;
|
||||
return fd;
|
||||
} else {
|
||||
return enomem();
|
||||
return emfile();
|
||||
}
|
||||
} else {
|
||||
return emfile();
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ textwindows int execve$nt(const char *program, char *const argv[],
|
|||
close(i);
|
||||
}
|
||||
}
|
||||
rc = ntspawn(program, argv, envp, NULL, NULL, true, 0, NULL, &startinfo,
|
||||
rc = ntspawn(program, argv, envp, NULL, NULL, NULL, true, 0, NULL, &startinfo,
|
||||
&procinfo);
|
||||
if (rc == -1) return -1;
|
||||
CloseHandle(procinfo.hThread);
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
* @param len 0 means ‘til end of file
|
||||
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
|
||||
* @return -1 on error
|
||||
* @syscall
|
||||
*/
|
||||
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @note limited availability on rhel5 and openbsd
|
||||
* @see ftruncate()
|
||||
* @syscall
|
||||
*/
|
||||
int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
|
||||
int rc;
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
* @errors ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see chmod()
|
||||
* @syscall
|
||||
*/
|
||||
int fchmod(int fd, uint32_t mode) {
|
||||
/* TODO(jart): Windows */
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
* @syscall
|
||||
*/
|
||||
int fchown(int fd, uint32_t uid, uint32_t gid) {
|
||||
/* TODO(jart): Windows? */
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int fcntl(int fd, int cmd, ...) {
|
||||
va_list va;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see fsync(), sync_file_range()
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -16,10 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
|
|
|
@ -1,277 +0,0 @@
|
|||
/*-*- 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 2020 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/bits/bits.h"
|
||||
#include "libc/bits/progn.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/win32finddata.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Directory Streams for Linux+Mac+Windows+FreeBSD+OpenBSD.
|
||||
*
|
||||
* System interfaces for listing the contents of file system directories
|
||||
* are famously incompatible across platforms. Most native projects that
|
||||
* have been around a long time implement wrappers for this. Normally it
|
||||
* will only be for DOS or Windows support. So this is the first time it
|
||||
* has been done for five platforms, having a remarkably tiny footprint.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Directory stream object.
|
||||
*/
|
||||
struct dirstream {
|
||||
int64_t tell;
|
||||
int64_t fd;
|
||||
struct dirent ent;
|
||||
union {
|
||||
struct {
|
||||
unsigned buf_pos;
|
||||
unsigned buf_end;
|
||||
char buf[BUFSIZ];
|
||||
};
|
||||
struct {
|
||||
bool isdone;
|
||||
struct NtWin32FindData windata;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* FreeBSD getdents() and XNU getdirentries() ABI.
|
||||
*/
|
||||
struct dirent$bsd {
|
||||
uint32_t d_fileno;
|
||||
uint16_t d_reclen;
|
||||
uint8_t d_type;
|
||||
uint8_t d_namlen;
|
||||
char d_name[256];
|
||||
};
|
||||
|
||||
/**
|
||||
* OpenBSD getdents() ABI.
|
||||
*/
|
||||
struct dirent$openbsd {
|
||||
uint64_t d_fileno;
|
||||
int64_t d_off;
|
||||
uint16_t d_reclen;
|
||||
uint8_t d_type;
|
||||
uint8_t d_namlen;
|
||||
uint8_t __zomg[4];
|
||||
char d_name[256];
|
||||
};
|
||||
|
||||
static textwindows noinline DIR *opendir$nt(const char *name) {
|
||||
int len;
|
||||
DIR *res;
|
||||
char16_t name16[PATH_MAX];
|
||||
if ((len = __mkntpath(name, name16)) == -1) return NULL;
|
||||
if (len + 2 + 1 > PATH_MAX) return PROGN(enametoolong(), NULL);
|
||||
while (name16[len - 1] == u'\\') name16[--len] = u'\0';
|
||||
name16[len++] = u'\\';
|
||||
name16[len++] = u'*';
|
||||
name16[len] = u'\0';
|
||||
if (!(res = calloc(1, sizeof(DIR)))) return NULL;
|
||||
if ((res->fd = FindFirstFile(name16, &res->windata)) != -1) {
|
||||
return res;
|
||||
} else {
|
||||
__winerr();
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows noinline struct dirent *readdir$nt(DIR *dir) {
|
||||
if (!dir->isdone) {
|
||||
memset(&dir->ent, 0, sizeof(dir->ent));
|
||||
dir->ent.d_ino = 0;
|
||||
dir->ent.d_off = dir->tell++;
|
||||
dir->ent.d_reclen = sizeof(dir->ent) +
|
||||
tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name),
|
||||
dir->windata.cFileName)
|
||||
.ax +
|
||||
1;
|
||||
switch (dir->windata.dwFileType) {
|
||||
case kNtFileTypeDisk:
|
||||
dir->ent.d_type = DT_BLK;
|
||||
break;
|
||||
case kNtFileTypeChar:
|
||||
dir->ent.d_type = DT_CHR;
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
dir->ent.d_type = DT_FIFO;
|
||||
break;
|
||||
default:
|
||||
if (dir->windata.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
dir->ent.d_type = DT_DIR;
|
||||
} else {
|
||||
dir->ent.d_type = DT_REG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dir->isdone = !FindNextFile(dir->fd, &dir->windata);
|
||||
return &dir->ent;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens directory, e.g.
|
||||
*
|
||||
* DIR *d;
|
||||
* struct dirent *e;
|
||||
* CHECK((d = opendir(path)));
|
||||
* while ((e = readdir(d))) {
|
||||
* printf("%s/%s\n", path, e->d_name);
|
||||
* }
|
||||
* LOGIFNEG1(closedir(d));
|
||||
*
|
||||
* @returns newly allocated DIR object, or NULL w/ errno
|
||||
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
|
||||
* @see glob()
|
||||
*/
|
||||
DIR *opendir(const char *name) {
|
||||
int fd;
|
||||
DIR *res;
|
||||
if (!IsWindows()) {
|
||||
res = NULL;
|
||||
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)) != -1) {
|
||||
if (!(res = fdopendir(fd))) close(fd);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return opendir$nt(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates directory object for file descriptor.
|
||||
*
|
||||
* @param fd gets owned by this function, if it succeeds
|
||||
* @return new directory object, which must be freed by closedir(),
|
||||
* or NULL w/ errno
|
||||
* @errors ENOMEM and fd is closed
|
||||
*/
|
||||
DIR *fdopendir(int fd) {
|
||||
DIR *dir;
|
||||
if (!IsWindows()) {
|
||||
if ((dir = calloc(1, sizeof(*dir)))) {
|
||||
dir->fd = fd;
|
||||
return dir;
|
||||
}
|
||||
} else {
|
||||
enosys(); /* TODO(jart): Implement me! */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads next entry from directory stream.
|
||||
*
|
||||
* This API doesn't define any particular ordering.
|
||||
*
|
||||
* @param dir is the object opendir() or fdopendir() returned
|
||||
* @return next entry or NULL on end or error, which can be
|
||||
* differentiated by setting errno to 0 beforehand
|
||||
*/
|
||||
struct dirent *readdir(DIR *dir) {
|
||||
int rc;
|
||||
long basep;
|
||||
struct dirent *ent;
|
||||
struct dirent$bsd *bsd;
|
||||
struct dirent$openbsd *obsd;
|
||||
if (!IsWindows()) {
|
||||
if (dir->buf_pos >= dir->buf_end) {
|
||||
basep = dir->tell; /* <- what does xnu do */
|
||||
rc = getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep);
|
||||
if (!rc || rc == -1) return NULL;
|
||||
dir->buf_pos = 0;
|
||||
dir->buf_end = rc;
|
||||
}
|
||||
if (IsLinux()) {
|
||||
ent = (struct dirent *)(dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += ent->d_reclen;
|
||||
dir->tell = ent->d_off;
|
||||
} else if (IsOpenbsd()) {
|
||||
obsd = (struct dirent$openbsd *)(dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += obsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = obsd->d_fileno;
|
||||
ent->d_off = obsd->d_off;
|
||||
ent->d_reclen = obsd->d_reclen;
|
||||
ent->d_type = obsd->d_type;
|
||||
memcpy(ent->d_name, obsd->d_name, obsd->d_namlen + 1);
|
||||
} else {
|
||||
bsd = (struct dirent$bsd *)(dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += bsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = bsd->d_fileno;
|
||||
ent->d_off = IsXnu() ? (dir->tell = basep) : dir->tell++;
|
||||
ent->d_reclen = bsd->d_reclen;
|
||||
ent->d_type = bsd->d_type;
|
||||
memcpy(ent->d_name, bsd->d_name, bsd->d_namlen + 1);
|
||||
}
|
||||
return ent;
|
||||
} else {
|
||||
return readdir$nt(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes directory object returned by opendir().
|
||||
* @return 0 on success or -1 w/ errno
|
||||
*/
|
||||
int closedir(DIR *dir) {
|
||||
int rc;
|
||||
if (dir) {
|
||||
if (!IsWindows()) {
|
||||
rc = close(dir->fd);
|
||||
} else {
|
||||
rc = FindClose(dir->fd) ? 0 : __winerr();
|
||||
}
|
||||
free(dir);
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns offset into directory data.
|
||||
*/
|
||||
long telldir(DIR *dir) {
|
||||
return dir->tell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file descriptor associated with DIR object.
|
||||
*/
|
||||
int dirfd(DIR *dir) {
|
||||
return dir->fd;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*-*- 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 2020 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/alg/alg.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
static void *filecmp$mmap(int fd, size_t size) {
|
||||
return size ? mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares contents of files with memcmp().
|
||||
*
|
||||
* @return ≤0, 0, or ≥0 based on comparison; or ≠0 on error, in which
|
||||
* case we make our best effort to sift failing filenames rightward,
|
||||
* and errno can be set to 0 beforehand to differentiate errors
|
||||
*/
|
||||
int filecmp(const char *pathname1, const char *pathname2) {
|
||||
int res, olderr;
|
||||
int fd1 = -1;
|
||||
int fd2 = -1;
|
||||
char *addr1 = MAP_FAILED;
|
||||
char *addr2 = MAP_FAILED;
|
||||
size_t size1 = 0;
|
||||
size_t size2 = 0;
|
||||
if ((fd1 = open(pathname1, O_RDONLY)) != -1 &&
|
||||
(fd2 = open(pathname2, O_RDONLY)) != -1 &&
|
||||
(size1 = getfiledescriptorsize(fd1)) != -1 &&
|
||||
(size2 = getfiledescriptorsize(fd2)) != -1 &&
|
||||
(addr1 = filecmp$mmap(fd1, size1)) != MAP_FAILED &&
|
||||
(addr2 = filecmp$mmap(fd2, size2)) != MAP_FAILED) {
|
||||
olderr = errno;
|
||||
madvise(addr1, size1, MADV_WILLNEED | MADV_SEQUENTIAL);
|
||||
madvise(addr2, size2, MADV_WILLNEED | MADV_SEQUENTIAL);
|
||||
errno = olderr;
|
||||
res = memcmp(addr1, addr2, min(size1, size2));
|
||||
if (!res && size1 != size2) {
|
||||
char kNul = '\0';
|
||||
if (size1 > size2) {
|
||||
res = cmpub(addr1 + size2, &kNul);
|
||||
} else {
|
||||
res = cmpub(addr2 + size1, &kNul);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = cmpuq(&fd1, &fd2) | 1;
|
||||
}
|
||||
olderr = errno;
|
||||
munmap(addr1, size1);
|
||||
munmap(addr2, size2);
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
errno = olderr;
|
||||
return res;
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
/*-*- 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 2020 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/assert.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ntspawn.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/nt2sysv.h"
|
||||
#include "libc/nt/dll.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/enum/startf.h"
|
||||
#include "libc/nt/enum/wt.h"
|
||||
#include "libc/nt/ipc.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/signals.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/directmap.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows int64_t ParseInt(char16_t **p) {
|
||||
uint64_t x = 0;
|
||||
while ('0' <= **p && **p <= '9') {
|
||||
x *= 10;
|
||||
x += *(*p)++ - '0';
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
|
||||
bool32 (*f)()) {
|
||||
char *p;
|
||||
size_t i;
|
||||
uint32_t x;
|
||||
for (p = buf, i = 0; i < n; i += x) {
|
||||
f(h, p + i, n - i, &x, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static noinline textwindows void WriteAll(int64_t h, void *buf, size_t n) {
|
||||
ForkIo(h, buf, n, WriteFile);
|
||||
}
|
||||
|
||||
static noinline textwindows void ReadAll(int64_t h, void *buf, size_t n) {
|
||||
ForkIo(h, buf, n, ReadFile);
|
||||
}
|
||||
|
||||
textwindows void WinMainForked(void) {
|
||||
int64_t h;
|
||||
void *addr;
|
||||
jmp_buf jb;
|
||||
char16_t *p;
|
||||
uint64_t size;
|
||||
uint32_t i, varlen;
|
||||
struct DirectMap dm;
|
||||
char16_t var[21 + 1 + 21 + 1];
|
||||
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
|
||||
SetEnvironmentVariable(u"_FORK", NULL);
|
||||
if (!varlen || varlen >= ARRAYLEN(var)) return;
|
||||
p = var;
|
||||
h = ParseInt(&p);
|
||||
if (*p++ == ' ') CloseHandle(ParseInt(&p));
|
||||
ReadAll(h, jb, sizeof(jb));
|
||||
ReadAll(h, &_mmi.i, sizeof(_mmi.i));
|
||||
for (i = 0; i < _mmi.i; ++i) {
|
||||
ReadAll(h, &_mmi.p[i], sizeof(_mmi.p[i]));
|
||||
addr = (void *)((uint64_t)_mmi.p[i].x << 16);
|
||||
size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE;
|
||||
if (_mmi.p[i].flags & MAP_PRIVATE) {
|
||||
CloseHandle(_mmi.p[i].h);
|
||||
_mmi.p[i].h =
|
||||
__mmap$nt(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, -1, 0)
|
||||
.maphandle;
|
||||
ReadAll(h, addr, size);
|
||||
} else {
|
||||
MapViewOfFileExNuma(
|
||||
_mmi.p[i].h,
|
||||
(_mmi.p[i].prot & PROT_WRITE)
|
||||
? kNtFileMapWrite | kNtFileMapExecute | kNtFileMapRead
|
||||
: kNtFileMapExecute | kNtFileMapRead,
|
||||
0, 0, size, addr, kNtNumaNoPreferredNode);
|
||||
}
|
||||
}
|
||||
ReadAll(h, _edata, _end - _edata);
|
||||
CloseHandle(h);
|
||||
unsetenv("_FORK");
|
||||
if (weaken(__wincrash$nt)) {
|
||||
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash$nt));
|
||||
}
|
||||
longjmp(jb, 1);
|
||||
}
|
||||
|
||||
textwindows int fork$nt(void) {
|
||||
jmp_buf jb;
|
||||
int i, rc, pid;
|
||||
char exe[PATH_MAX];
|
||||
int64_t reader, writer;
|
||||
char *p, buf[21 + 1 + 21 + 1];
|
||||
struct NtStartupInfo startinfo;
|
||||
struct NtProcessInformation procinfo;
|
||||
if ((pid = __getemptyfd()) == -1) return -1;
|
||||
if (!setjmp(jb)) {
|
||||
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
|
||||
p = buf;
|
||||
p += uint64toarray_radix10(reader, p);
|
||||
*p++ = ' ';
|
||||
p += uint64toarray_radix10(writer, p);
|
||||
setenv("_FORK", buf, true);
|
||||
memset(&startinfo, 0, sizeof(startinfo));
|
||||
startinfo.cb = sizeof(struct NtStartupInfo);
|
||||
startinfo.dwFlags = kNtStartfUsestdhandles;
|
||||
startinfo.hStdInput = g_fds.p[0].handle;
|
||||
startinfo.hStdOutput = g_fds.p[1].handle;
|
||||
startinfo.hStdError = g_fds.p[2].handle;
|
||||
GetModuleFileNameA(0, exe, ARRAYLEN(exe));
|
||||
if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL,
|
||||
&startinfo, &procinfo) != -1) {
|
||||
CloseHandle(reader);
|
||||
CloseHandle(procinfo.hThread);
|
||||
if (weaken(__sighandrvas) &&
|
||||
weaken(__sighandrvas)[SIGCHLD] == SIG_IGN) {
|
||||
CloseHandle(procinfo.hProcess);
|
||||
} else {
|
||||
g_fds.p[pid].kind = kFdProcess;
|
||||
g_fds.p[pid].handle = procinfo.hProcess;
|
||||
g_fds.p[pid].flags = O_CLOEXEC;
|
||||
}
|
||||
WriteAll(writer, jb, sizeof(jb));
|
||||
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
|
||||
for (i = 0; i < _mmi.i; ++i) {
|
||||
WriteAll(writer, &_mmi.p[i], sizeof(_mmi.p[i]));
|
||||
if (_mmi.p[i].flags & MAP_PRIVATE) {
|
||||
WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16),
|
||||
((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE);
|
||||
}
|
||||
}
|
||||
WriteAll(writer, _edata, _end - _edata);
|
||||
CloseHandle(writer);
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
unsetenv("_FORK");
|
||||
rc = pid;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*-*- 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 2020 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/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns current working directory.
|
||||
*
|
||||
* If the PWD environment variable is set, that'll be returned (since
|
||||
* it's faster than issuing a system call).
|
||||
*
|
||||
* @return pointer that must be free()'d, or NULL w/ errno
|
||||
*/
|
||||
nodiscard char *get_current_dir_name(void) {
|
||||
char *buf, *res;
|
||||
if (!(buf = malloc(PATH_MAX))) return NULL;
|
||||
if (!(res = (getcwd)(buf, PATH_MAX))) free(buf);
|
||||
return res;
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# Cosmopolitan System Call Compatibility Layer
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This subpackage exports functions traditionally understood as system
|
||||
# calls that Cosmopolitan needs to wrap in a nontrivial way, requiring
|
||||
# things like dynamic memory allocation.
|
||||
|
||||
PKGS += LIBC_CALLS_HEFTY
|
||||
|
||||
LIBC_CALLS_HEFTY_ARTIFACTS += LIBC_CALLS_HEFTY_A
|
||||
LIBC_CALLS_HEFTY = $(LIBC_CALLS_HEFTY_A_DEPS) $(LIBC_CALLS_HEFTY_A)
|
||||
LIBC_CALLS_HEFTY_A = o/$(MODE)/libc/calls/hefty/hefty.a
|
||||
LIBC_CALLS_HEFTY_A_FILES := $(wildcard libc/calls/hefty/*)
|
||||
LIBC_CALLS_HEFTY_A_HDRS = $(filter %.h,$(LIBC_CALLS_HEFTY_A_FILES))
|
||||
LIBC_CALLS_HEFTY_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_HEFTY_A_FILES))
|
||||
LIBC_CALLS_HEFTY_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_HEFTY_A_FILES))
|
||||
|
||||
LIBC_CALLS_HEFTY_A_SRCS = \
|
||||
$(LIBC_CALLS_HEFTY_A_SRCS_S) \
|
||||
$(LIBC_CALLS_HEFTY_A_SRCS_C)
|
||||
|
||||
LIBC_CALLS_HEFTY_A_OBJS = \
|
||||
$(LIBC_CALLS_HEFTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(LIBC_CALLS_HEFTY_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
LIBC_CALLS_HEFTY_A_CHECKS = \
|
||||
$(LIBC_CALLS_HEFTY_A).pkg \
|
||||
$(LIBC_CALLS_HEFTY_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS
|
||||
|
||||
LIBC_CALLS_HEFTY_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(LIBC_CALLS_HEFTY_A): \
|
||||
libc/calls/hefty/ \
|
||||
$(LIBC_CALLS_HEFTY_A).pkg \
|
||||
$(LIBC_CALLS_HEFTY_A_OBJS)
|
||||
|
||||
$(LIBC_CALLS_HEFTY_A).pkg: \
|
||||
$(LIBC_CALLS_HEFTY_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
LIBC_CALLS_HEFTY_LIBS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_HEFTY_SRCS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_CALLS_HEFTY_HDRS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_CALLS_HEFTY_BINS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_BINS))
|
||||
LIBC_CALLS_HEFTY_CHECKS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_CALLS_HEFTY_OBJS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_OBJS))
|
||||
LIBC_CALLS_HEFTY_TESTS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_TESTS))
|
||||
$(LIBC_CALLS_HEFTY_OBJS): $(BUILD_FILES) libc/calls/hefty/hefty.mk
|
||||
|
||||
.PHONY: o/$(MODE)/libc/calls/hefty
|
||||
o/$(MODE)/libc/calls/hefty: $(LIBC_CALLS_HEFTY_CHECKS)
|
|
@ -1,48 +0,0 @@
|
|||
/*-*- 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 2020 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/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Replaces tilde in path w/ user home folder.
|
||||
*
|
||||
* @param path is NULL propagating
|
||||
* @return must be free()'d
|
||||
*/
|
||||
char *replaceuser(const char *path) {
|
||||
char *res, *p;
|
||||
const char *home;
|
||||
size_t pathlen, homelen;
|
||||
res = NULL;
|
||||
if (path && *path++ == '~' && !isempty((home = getenv("HOME")))) {
|
||||
while (*path == '/') path++;
|
||||
pathlen = strlen(path);
|
||||
homelen = strlen(home);
|
||||
while (homelen && home[homelen - 1] == '/') homelen--;
|
||||
if ((p = res = malloc(pathlen + 1 + homelen + 1))) {
|
||||
p = mempcpy(p, home, homelen);
|
||||
*p++ = '/';
|
||||
memcpy(p, path, pathlen + 1);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 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/dce.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
/ Forks process without copying page tables.
|
||||
/
|
||||
/ This is the same as fork() except it's optimized for the case
|
||||
/ where the caller invokes execve() immediately afterwards. You
|
||||
/ can also call functions like close(), dup2(), etc. You cannot
|
||||
/ call read() safely but you can call pread(). Call _exit() but
|
||||
/ don't call exit(). Look for the vforksafe function annotation
|
||||
/
|
||||
/ Do not make the assumption that the parent is suspended until
|
||||
/ the child terminates since this impl calls fork() on Windows.
|
||||
/
|
||||
/ @return pid of child process or 0 if forked process
|
||||
/ @returnstwice
|
||||
/ @vforksafe
|
||||
vfork:
|
||||
#if SupportsWindows()
|
||||
testb IsWindows()
|
||||
jnz fork$nt
|
||||
#endif
|
||||
mov __NR_vfork(%rip),%eax
|
||||
pop %rsi # saves return address in a register
|
||||
#if SupportsBsd()
|
||||
testb IsBsd()
|
||||
jnz vfork.bsd
|
||||
#endif
|
||||
syscall
|
||||
push %rsi # note it happens twice in same page
|
||||
cmp $-4095,%eax
|
||||
jae systemfive.error
|
||||
0: ezlea __vforked,di
|
||||
test %eax,%eax
|
||||
jz 1f
|
||||
decl (%rdi)
|
||||
jns 2f # openbsd doesn't actually share mem
|
||||
1: incl (%rdi)
|
||||
2: ret
|
||||
.endfn vfork,globl
|
||||
|
||||
#if SupportsBsd()
|
||||
vfork.bsd:
|
||||
syscall
|
||||
push %rsi
|
||||
jc systemfive.errno
|
||||
#if SupportsXnu()
|
||||
testb IsXnu()
|
||||
jz 0b
|
||||
neg %edx # edx is 0 for parent and 1 for child
|
||||
not %edx # eax always returned with childs pid
|
||||
and %edx,%eax
|
||||
#endif /* XNU */
|
||||
jmp 0b
|
||||
.endfn vfork.bsd
|
||||
#endif /* BSD */
|
|
@ -36,6 +36,7 @@ struct IoctlPtmGet {
|
|||
char theduxname[16];
|
||||
char workername[16];
|
||||
};
|
||||
|
||||
enum FdKind {
|
||||
kFdEmpty,
|
||||
kFdFile,
|
||||
|
@ -45,6 +46,7 @@ enum FdKind {
|
|||
kFdSerial,
|
||||
kFdZip,
|
||||
kFdEpoll,
|
||||
kFdReserved
|
||||
};
|
||||
|
||||
struct Fd {
|
||||
|
@ -71,7 +73,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo;
|
|||
hidden extern struct NtStartupInfo g_ntstartupinfo;
|
||||
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||
|
||||
ssize_t __getemptyfd(void) hidden;
|
||||
int __reservefd(void) hidden;
|
||||
void __releasefd(int) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
void __removefd(int) hidden;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
/**
|
||||
* Controls settings on device.
|
||||
* @vforksafe
|
||||
*/
|
||||
int(ioctl)(int fd, uint64_t request, void *memory) {
|
||||
__IOCTL_DISPATCH(EQUAL, fd, request, memory);
|
||||
|
|
|
@ -32,7 +32,11 @@
|
|||
|
||||
#define kBufSize 1024
|
||||
#define kProcStatus "/proc/self/status"
|
||||
_Alignas(16) static const char kGdbPid[] = "TracerPid:\t";
|
||||
#define kPid "TracerPid:\t"
|
||||
|
||||
static noasan int NtBeingDebugged(void) {
|
||||
return NtGetPeb()->BeingDebugged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if gdb, strace, windbg, etc. is controlling process.
|
||||
|
@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) {
|
|||
int fd, res;
|
||||
ssize_t got;
|
||||
char buf[1024];
|
||||
res = 0;
|
||||
res = false;
|
||||
if (!force) {
|
||||
if (getenv("HEISENDEBUG")) return false;
|
||||
if (IsGenuineCosmo()) return false;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
res = NtBeingDebugged();
|
||||
} else if (IsLinux()) {
|
||||
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
|
||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
|
||||
buf[got] = '\0';
|
||||
res =
|
||||
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
|
||||
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ forceinline typeof(PrefetchVirtualMemory) *GetPrefetchVirtualMemory(void) {
|
|||
static bool once;
|
||||
static typeof(PrefetchVirtualMemory) *PrefetchVirtualMemory_;
|
||||
if (!once) {
|
||||
once = true;
|
||||
PrefetchVirtualMemory_ = /* win8.1+ */
|
||||
GetProcAddressModule("Kernel32.dll", "PrefetchVirtualMemory");
|
||||
once = true;
|
||||
}
|
||||
return PrefetchVirtualMemory_;
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ forceinline typeof(OfferVirtualMemory) *GetOfferVirtualMemory(void) {
|
|||
static bool once;
|
||||
static typeof(OfferVirtualMemory) *OfferVirtualMemory_;
|
||||
if (!once) {
|
||||
once = true;
|
||||
OfferVirtualMemory_ = /* win8.1+ */
|
||||
GetProcAddressModule("Kernel32.dll", "OfferVirtualMemory");
|
||||
once = true;
|
||||
}
|
||||
return OfferVirtualMemory_;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
* @kudos Daniel Colascione for teaching how to quote
|
||||
* @see libc/runtime/dosargv.c
|
||||
*/
|
||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
char *arg;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
|
|
|
@ -29,21 +29,18 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static int CompareStrings(const char *l, const char *r) {
|
||||
static noasan int CompareStrings(const char *l, const char *r) {
|
||||
size_t i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
return (l[i] & 0xff) - (r[i] & 0xff);
|
||||
}
|
||||
|
||||
static void SortStrings(char **a, size_t n) {
|
||||
char *t;
|
||||
size_t i, j;
|
||||
for (i = 1; i < n; ++i) {
|
||||
for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
a[j] = t;
|
||||
static noasan void InsertString(char **a, size_t i, char *s) {
|
||||
size_t j;
|
||||
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
a[j] = s;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,19 +48,24 @@ static void SortStrings(char **a, size_t n) {
|
|||
*
|
||||
* This is designed to meet the requirements of CreateProcess().
|
||||
*
|
||||
* @param envvars receives sorted double-NUL terminated string list
|
||||
* @param envp is an a NULL-terminated array of UTF-8 strings
|
||||
* @return freshly allocated lpEnvironment or NULL w/ errno
|
||||
* @param extravar is a VAR=val string we consider part of envp or NULL
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000)
|
||||
*/
|
||||
textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[]) {
|
||||
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
|
||||
char *const envp[], const char *extravar) {
|
||||
char *t;
|
||||
axdx_t rc;
|
||||
uint64_t w;
|
||||
char **vars;
|
||||
wint_t x, y;
|
||||
size_t i, j, k, n, m;
|
||||
for (n = 0; envp[n];) n++;
|
||||
vars = alloca(n * sizeof(char *));
|
||||
memcpy(vars, envp, n * sizeof(char *));
|
||||
SortStrings(vars, n);
|
||||
vars = alloca((n + 1) * sizeof(char *));
|
||||
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
|
||||
if (extravar) InsertString(vars, n++, extravar);
|
||||
for (k = i = 0; i < n; ++i) {
|
||||
j = 0;
|
||||
do {
|
||||
|
|
|
@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
int mprotect(void *addr, uint64_t len, int prot) {
|
||||
textsyscall int mprotect(void *addr, uint64_t len, int prot) {
|
||||
bool cf;
|
||||
int64_t rc;
|
||||
uint32_t oldprot;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
|
@ -55,19 +56,21 @@ static long double MeasureNanosPerCycle(void) {
|
|||
}
|
||||
|
||||
static void InitTime(void) {
|
||||
g_now.cpn = MeasureNanosPerCycle();
|
||||
g_now.r0 = dtime(CLOCK_REALTIME);
|
||||
g_now.k0 = rdtsc();
|
||||
g_now.once = true;
|
||||
struct Now now;
|
||||
now.cpn = MeasureNanosPerCycle();
|
||||
now.r0 = dtime(CLOCK_REALTIME);
|
||||
now.k0 = rdtsc();
|
||||
now.once = true;
|
||||
memcpy(&g_now, &now, sizeof(now));
|
||||
}
|
||||
|
||||
long double converttickstonanos(uint64_t ticks) {
|
||||
long double ConvertTicksToNanos(uint64_t ticks) {
|
||||
if (!g_now.once) InitTime();
|
||||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
long double converttickstoseconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * converttickstonanos(ticks);
|
||||
static long double ConvertTicksToSeconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * ConvertTicksToNanos(ticks);
|
||||
}
|
||||
|
||||
long double nowl$sys(void) {
|
||||
|
@ -78,5 +81,5 @@ long double nowl$art(void) {
|
|||
uint64_t ticks;
|
||||
if (!g_now.once) InitTime();
|
||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||
return g_now.r0 + converttickstoseconds(ticks);
|
||||
return g_now.r0 + ConvertTicksToSeconds(ticks);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ struct SpawnBlock {
|
|||
* don't need to be passed in sorted order; however, this function
|
||||
* goes faster the closer they are to sorted
|
||||
* @param envp[m-1] is NULL
|
||||
* @param extravar is added to envp to avoid setenv() in caller
|
||||
* @param bInheritHandles means handles already marked inheritable will
|
||||
* be inherited; which, assuming the System V wrapper functions are
|
||||
* being used, should mean (1) all files and sockets that weren't
|
||||
|
@ -59,7 +60,7 @@ struct SpawnBlock {
|
|||
*/
|
||||
textwindows int ntspawn(
|
||||
const char *prog, char *const argv[], char *const envp[],
|
||||
struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
const char *extravar, struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
|
||||
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
|
||||
const struct NtStartupInfo *lpStartupInfo,
|
||||
|
@ -81,7 +82,7 @@ textwindows int ntspawn(
|
|||
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
|
||||
blocksize, NULL, kNtNumaNoPreferredNode))) {
|
||||
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
|
||||
mkntenvblock(block->envvars, envp) != -1) {
|
||||
mkntenvblock(block->envvars, envp, extravar) != -1) {
|
||||
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
||||
#include "libc/nt/struct/processinformation.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
|
@ -7,12 +7,12 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden;
|
||||
int mkntenvblock(char16_t[ARG_MAX], char *const[]) hidden;
|
||||
int ntspawn(const char *, char *const[], char *const[],
|
||||
int mkntenvblock(char16_t[ARG_MAX], char *const[], const char *) hidden;
|
||||
int ntspawn(const char *, char *const[], char *const[], const char *,
|
||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
||||
struct NtProcessInformation *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ */
|
||||
|
|
|
@ -42,16 +42,7 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
|
|||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
|
||||
if ((handle = CreateFile(
|
||||
path16,
|
||||
(flags & 0xf000000f) |
|
||||
(/* this is needed if we mmap(rwx+cow)
|
||||
nt is choosy about open() access */
|
||||
(flags & O_APPEND)
|
||||
? kNtFileAppendData
|
||||
: (flags & O_ACCMODE) == O_RDONLY
|
||||
? kNtGenericExecute | kNtFileGenericRead
|
||||
: kNtGenericExecute | kNtFileGenericRead |
|
||||
kNtFileGenericWrite),
|
||||
path16, flags & 0xf000000f, /* see consts.sh */
|
||||
(flags & O_EXCL)
|
||||
? kNtFileShareExclusive
|
||||
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
|
@ -75,14 +66,6 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
|
|||
kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics |
|
||||
kNtFileAttributeTemporary)))),
|
||||
0)) != -1) {
|
||||
if (flags & O_SPARSE) {
|
||||
/*
|
||||
* TODO(jart): Can all files be sparse files? That seems to be the
|
||||
* way Linux behaves out of the box.
|
||||
* TODO(jart): Wow why does sparse wreak havoc?
|
||||
*/
|
||||
DeviceIoControl(handle, kNtFsctlSetSparse, NULL, 0, NULL, 0, &br, NULL);
|
||||
}
|
||||
return handle;
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & O_CREAT) &&
|
||||
|
@ -129,11 +112,16 @@ static textwindows ssize_t open$nt$file(int dirfd, const char *file,
|
|||
|
||||
textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags,
|
||||
int32_t mode) {
|
||||
size_t fd;
|
||||
if ((fd = __getemptyfd()) == -1) return -1;
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
|
||||
return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||
rc = open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||
} else {
|
||||
return open$nt$file(dirfd, file, flags, mode, fd);
|
||||
rc = open$nt$file(dirfd, file, flags, mode, fd);
|
||||
}
|
||||
if (rc == -1) {
|
||||
__releasefd(fd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int open(const char *file, int flags, ...) {
|
||||
int open(const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
va_start(va, flags);
|
||||
|
|
|
@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags,
|
|||
}
|
||||
return fd;
|
||||
} else {
|
||||
if ((fd = __getemptyfd()) != -1 &&
|
||||
(g_fds.p[fd].handle = CreateFileA(
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
if ((g_fds.p[fd].handle = CreateFileA(
|
||||
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
|
||||
&kNtIsInheritable, kNtCreateAlways,
|
||||
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
||||
|
@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags,
|
|||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
} else {
|
||||
__releasefd(fd);
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int openat(int dirfd, const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
|
@ -47,11 +48,9 @@ nodiscard int openat(int dirfd, const char *file, int flags, ...) {
|
|||
va_end(va);
|
||||
if (!file) return efault();
|
||||
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else {
|
||||
return eopnotsupp(); /* TODO */
|
||||
}
|
||||
if (__vforked) return einval();
|
||||
if (dirfd != AT_FDCWD) return einval();
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else if (!IsWindows()) {
|
||||
return openat$sysv(dirfd, file, flags, mode);
|
||||
} else {
|
||||
|
|
|
@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
|||
int reader, writer;
|
||||
char16_t pipename[64];
|
||||
CreatePipeName(pipename);
|
||||
if ((reader = __reservefd()) == -1) return -1;
|
||||
if ((writer = __reservefd()) == -1) {
|
||||
__releasefd(reader);
|
||||
return -1;
|
||||
}
|
||||
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
|
||||
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
|
||||
0, &kNtIsInheritable)) != -1) {
|
||||
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
|
||||
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
|
||||
reader = __getemptyfd();
|
||||
g_fds.p[reader].kind = kFdFile;
|
||||
g_fds.p[reader].flags = flags;
|
||||
g_fds.p[reader].handle = hin;
|
||||
writer = __getemptyfd();
|
||||
g_fds.p[writer].kind = kFdFile;
|
||||
g_fds.p[writer].flags = flags;
|
||||
g_fds.p[writer].handle = hout;
|
||||
|
@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
|||
CloseHandle(hin);
|
||||
}
|
||||
}
|
||||
__releasefd(reader);
|
||||
return __winerr();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -17,25 +17,13 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
/**
|
||||
* Creates new process zygote style.
|
||||
*
|
||||
* @return 0 to child, child pid to parent, or -1 on error
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fork(void) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = fork$sysv();
|
||||
} else {
|
||||
rc = fork$nt();
|
||||
}
|
||||
if (rc == 0) {
|
||||
__onfork();
|
||||
}
|
||||
return rc;
|
||||
void __releasefd(int fd) {
|
||||
int x;
|
||||
g_fds.p[fd].kind = kFdEmpty;
|
||||
do {
|
||||
x = g_fds.f;
|
||||
if (fd >= x) break;
|
||||
} while (!cmpxchg(&g_fds.f, x, fd));
|
||||
}
|
|
@ -24,11 +24,16 @@
|
|||
/**
|
||||
* Finds open file descriptor slot.
|
||||
*/
|
||||
ssize_t __getemptyfd(void) {
|
||||
for (; g_fds.f < g_fds.n; ++g_fds.f) {
|
||||
if (g_fds.p[g_fds.f].kind == kFdEmpty) {
|
||||
return g_fds.f;
|
||||
int __reservefd(void) {
|
||||
int fd;
|
||||
for (;;) {
|
||||
fd = g_fds.f;
|
||||
if (fd >= g_fds.n) {
|
||||
if (__ensurefds(fd) == -1) return -1;
|
||||
}
|
||||
cmpxchg(&g_fds.f, fd, fd + 1);
|
||||
if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return __ensurefds(g_fds.f);
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
||||
#include "libc/calls/struct/sigaction-linux.internal.h"
|
||||
#include "libc/calls/struct/sigaction-openbsd.internal.h"
|
||||
|
@ -120,6 +121,7 @@ static void sigaction$native2cosmo(union metasigaction *sa) {
|
|||
*
|
||||
* @see xsigaction() for a much better api
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||
_Static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) &&
|
||||
|
@ -129,9 +131,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
|
||||
int rc, rva, oldrva;
|
||||
struct sigaction *ap, copy;
|
||||
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) {
|
||||
return einval();
|
||||
}
|
||||
if (!(0 < sig && sig < NSIG)) return einval();
|
||||
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
||||
if (!act) {
|
||||
rva = (int32_t)(intptr_t)SIG_DFL;
|
||||
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
||||
|
@ -142,6 +143,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
} else {
|
||||
return efault();
|
||||
}
|
||||
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
|
||||
return einval();
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
if (!IsMetal()) {
|
||||
if (act) {
|
||||
|
@ -150,16 +154,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
if (IsXnu()) {
|
||||
ap->sa_restorer = (void *)&xnutrampoline;
|
||||
ap->sa_handler = (void *)&xnutrampoline;
|
||||
} else {
|
||||
if (IsLinux()) {
|
||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||
ap->sa_flags |= SA_RESTORER;
|
||||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
}
|
||||
if (rva >= kSigactionMinRva) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||
} else if (IsLinux()) {
|
||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||
ap->sa_flags |= SA_RESTORER;
|
||||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
} else if (rva >= kSigactionMinRva) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||
}
|
||||
sigaction$cosmo2native((union metasigaction *)ap);
|
||||
} else {
|
||||
|
@ -179,7 +180,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
}
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != -1) {
|
||||
if (rc != -1 && !__vforked) {
|
||||
if (oldact) {
|
||||
oldrva = __sighandrvas[sig];
|
||||
oldact->sa_sigaction = (sigaction_f)(
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ System Five signal handler.
|
||||
/ BSD signal handler.
|
||||
/
|
||||
/ This is needed because (1) a signal is allowed to trigger at
|
||||
/ just about any time, and leaf functions (e.g. memcpy) aren't
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* @return -1 w/ few exceptions
|
||||
* @note this is a code-size saving device
|
||||
*/
|
||||
privileged int64_t __winerr(void) {
|
||||
privileged noasan int64_t __winerr(void) {
|
||||
if (IsWindows()) {
|
||||
errno = GetLastError();
|
||||
return -1;
|
||||
|
|
|
@ -42,7 +42,6 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
|
|||
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
||||
offset2overlap(opt_offset, &overlap))) {
|
||||
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
||||
FlushFileBuffers(fd->handle);
|
||||
return wrote;
|
||||
} else {
|
||||
return __winerr();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue