Improve ZIP filesystem and change its prefix

The ZIP filesystem has a breaking change. You now need to use /zip/ to
open() / opendir() / etc. assets within the ZIP structure of your APE
binary, instead of the previous convention of using zip: or zip! URIs.
This is needed because Python likes to use absolute paths, and having
ZIP paths encoded like URIs simply broke too many things.

Many more system calls have been updated to be able to operate on ZIP
files and file descriptors. In particular fcntl() and ioctl() since
Python would do things like ask if a ZIP file is a terminal and get
confused when the old implementation mistakenly said yes, because the
fastest way to guarantee native file descriptors is to dup(2). This
change also improves the async signal safety of zipos and ensures it
doesn't maintain any open file descriptors beyond that which the user
has opened.

This change makes a lot of progress towards adding magic numbers that
are specific to platforms other than Linux. The philosophy here is that,
if you use an operating system like FreeBSD, then you should be able to
take advantage of FreeBSD exclusive features, even if we don't polyfill
them on other platforms. For example, you can now open() a file with the
O_VERIFY flag. If your program runs on other platforms, then Cosmo will
automatically set O_VERIFY to zero. This lets you safely use it without
the need for #ifdef or ifstatements which detract from readability.

One of the blindspots of the ASAN memory hardening we use to offer Rust
like assurances has always been that memory passed to the kernel via
system calls (e.g. writev) can't be checked automatically since the
kernel wasn't built with MODE=asan. This change makes more progress
ensuring that each system call will verify the soundness of memory
before it's passed to the kernel. The code for doing these checks is
fast, particularly for buffers, where it can verify 64 bytes a cycle.

- Correct O_LOOP definition on NT
- Introduce program_executable_name
- Add ASAN guards to more system calls
- Improve termios compatibility with BSDs
- Fix bug in Windows auxiliary value encoding
- Add BSD and XNU specific errnos and open flags
- Add check to ensure build doesn't talk to internet
This commit is contained in:
Justine Tunney 2021-08-22 01:04:18 -07:00
parent 2730c66f4a
commit 00611e9b06
319 changed files with 4418 additions and 2599 deletions

View file

@ -56,6 +56,7 @@
#define WIFSTOPPED(s) ((short)((((s)&0xffff) * 0x10001) >> 8) > 0x7f00)
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WTERMSIG(s) ((s)&0x7f)
#define W_STOPCODE(s) ((s) << 8 | 0177)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -88,34 +89,35 @@ int chown(const char *, uint32_t, uint32_t);
int chroot(const char *);
int close(int);
int closedir(DIR *);
int creat(const char *, uint32_t) nodiscard;
int creat(const char *, uint32_t);
int dirfd(DIR *);
int dup(int) nodiscard;
int dup(int);
int dup2(int, int);
int dup3(int, int, int);
int execl(const char *, const char *, ...) nullterminated();
int execle(const char *, const char *, ...) nullterminated((1));
int execlp(const char *, const char *, ...) nullterminated();
int execv(const char *, char *const[]) paramsnonnull();
int execve(const char *, char *const[], char *const[]) paramsnonnull();
int execvp(const char *, char *const[]) paramsnonnull();
int execvpe(const char *, char *const[], char *const[]) paramsnonnull();
int execv(const char *, char *const[]);
int execve(const char *, char *const[], char *const[]);
int execvp(const char *, char *const[]);
int execvpe(const char *, char *const[], char *const[]);
int faccessat(int, const char *, int, uint32_t);
int fadvise(int, uint64_t, uint64_t, int);
int fchdir(int);
int fchmod(int, uint32_t) nothrow;
int fchmodat(int, const char *, uint32_t, uint32_t);
int fchmodat(int, const char *, uint32_t, int);
int fchown(int, uint32_t, uint32_t);
int fchownat(int, const char *, uint32_t, uint32_t, uint32_t);
int fchownat(int, const char *, uint32_t, uint32_t, int);
int fcntl(int, int, ...);
int fdatasync(int);
int filecmp(const char *, const char *);
int flock(int, int);
int fork(void);
int fstat(int, struct stat *);
int fstatat(int, const char *, struct stat *, uint32_t);
int fstatat(int, const char *, struct stat *, int);
int fsync(int);
int ftruncate(int, int64_t);
int getdents(unsigned, void *, unsigned, long *);
int getdomainname(char *, size_t);
int gethostname(char *, size_t);
int getpgid(int);
@ -127,7 +129,7 @@ int getrusage(int, struct rusage *);
int kill(int, int);
int killpg(int, int);
int link(const char *, const char *) nothrow;
int linkat(int, const char *, int, const char *, uint32_t);
int linkat(int, const char *, int, const char *, int);
int lstat(const char *, struct stat *);
int lutimes(const char *, const struct timeval[2]);
int madvise(void *, uint64_t, int);
@ -244,10 +246,6 @@ int vdprintf(int, const char *, va_list) paramsnonnull();
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define getcwd(BUF, SIZE) \
(__builtin_constant_p(BUF) && !(BUF) ? get_current_dir_name() \
: getcwd(BUF, SIZE))
void _init_onntconsoleevent(void);
void _init_wincrash(void);

View file

@ -75,6 +75,25 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \
OVERRIDE_COPTS += \
-O3
# TODO(jart): make va_arg optimize well in default mode
o//libc/calls/ioctl.o \
o//libc/calls/ioctl_default.o \
o//libc/calls/ioctl_fioclex-nt.o \
o//libc/calls/ioctl_fioclex.o \
o//libc/calls/ioctl_siocgifconf-nt.o \
o//libc/calls/ioctl_siocgifconf.o \
o//libc/calls/ioctl_tcgets-nt.o \
o//libc/calls/ioctl_tcgets.o \
o//libc/calls/ioctl_tcsets-nt.o \
o//libc/calls/ioctl_tcsets.o \
o//libc/calls/ioctl_tiocgwinsz-nt.o \
o//libc/calls/ioctl_tiocgwinsz.o \
o//libc/calls/ioctl_tiocswinsz-nt.o \
o//libc/calls/ioctl_tiocswinsz.o \
o//libc/calls/fcntl.o: \
OVERRIDE_CFLAGS += \
-Os
o/$(MODE)/libc/calls/execl.o \
o/$(MODE)/libc/calls/execle.o \
o/$(MODE)/libc/calls/execlp.o \

View file

@ -18,14 +18,19 @@
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Sets current directory.
*
* This does *not* update the `PWD` environment variable.
*
* @asyncsignalsafe
* @see fchdir()
*/
int chdir(const char *path) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
return sys_chdir(path);
} else {

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
/**
@ -42,5 +41,5 @@
* @see fchmod()
*/
int chmod(const char *pathname, uint32_t mode) {
return sys_fchmodat(AT_FDCWD, pathname, mode, 0);
return fchmodat(AT_FDCWD, pathname, mode, 0);
}

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
/**
@ -33,5 +32,5 @@
* @asyncsignalsafe
*/
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
return sys_fchownat(AT_FDCWD, pathname, uid, gid, 0);
return fchownat(AT_FDCWD, pathname, uid, gid, 0);
}

View file

@ -19,7 +19,9 @@
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
@ -42,6 +44,7 @@ int clock_gettime(int clockid, struct timespec *ts) {
axdx_t ad;
struct NtFileTime ft;
if (!ts) return efault();
if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) return efault();
if (clockid == -1) return einval();
if (!IsWindows()) {
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) {

View file

@ -33,7 +33,7 @@ textwindows int sys_close_nt(struct Fd *fd) {
FlushFileBuffers(fd->handle);
}
ok = CloseHandle(fd->handle);
if (fd->kind == kFdConsole) {
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
ok &= CloseHandle(fd->extra);
}
return ok ? 0 : __winerr();

View file

@ -74,6 +74,10 @@ char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
char *p;
size_t namelen;
int rc, olderr;
if (!name) {
efault();
return NULL;
}
if (!(namelen = strlen(name))) {
enoent();
return NULL;

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
/**
* Executes program, with PATH search and current environment.

View file

@ -30,7 +30,7 @@
#include "libc/sysv/consts/o.h"
textwindows int sys_execve_nt(const char *program, char *const argv[],
char *const envp[]) {
char *const envp[]) {
int rc;
size_t i;
uint32_t dwExitCode;
@ -42,13 +42,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
startinfo.hStdInput = g_fds.p[0].handle;
startinfo.hStdOutput = g_fds.p[1].handle;
startinfo.hStdError = g_fds.p[2].handle;
for (i = 2; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
close(i);
}
}
rc = ntspawn(program, argv, envp, NULL, NULL, NULL, true, 0, NULL, &startinfo,
&procinfo);
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
if (rc == -1) return -1;
CloseHandle(procinfo.hThread);
do {

View file

@ -19,6 +19,17 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
static noasan bool __asan_is_valid_strlist(char *const *p) {
for (;; ++p) {
if (!__asan_is_valid(p, sizeof(char *))) return false;
if (!*p) return true;
if (!__asan_is_valid(*p, 1)) return false;
}
}
/**
* Replaces current process with program.
@ -34,6 +45,18 @@
* @vforksafe
*/
int execve(const char *program, char *const argv[], char *const envp[]) {
size_t i;
if (!program || !argv || !envp) return efault();
if (IsAsan() &&
(!__asan_is_valid(program, 1) || !__asan_is_valid_strlist(argv) ||
!__asan_is_valid_strlist(envp))) {
return efault();
}
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
close(i);
}
}
if (!IsWindows()) {
return sys_execve(program, argv, envp);
} else {

View file

@ -17,7 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/mem/mem.h"
#include "libc/sysv/errfuns.h"
/**
* Executes program, with path environment search.
@ -34,6 +37,7 @@
int execvpe(const char *prog, char *const argv[], char *const *envp) {
char *exe;
char pathbuf[PATH_MAX];
if (IsAsan() && !__asan_is_valid(prog, 1)) return efault();
if (!(exe = commandv(prog, pathbuf))) return -1;
return execve(exe, argv, envp);
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"

View file

@ -16,11 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Checks if effective user can access path in particular ways.
@ -34,6 +37,10 @@
* @asyncsignalsafe
*/
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
if (!IsWindows()) {
return sys_faccessat(dirfd, path, mode, flags);
} else {

View file

@ -23,6 +23,8 @@
/**
* Sets current directory based on file descriptor.
*
* This does *not* update the `PWD` environment variable.
*
* @see open(path, O_DIRECTORY)
* @asyncsignalsafe
*/

View file

@ -22,22 +22,9 @@
#include "libc/sysv/errfuns.h"
/**
* Changes file permissions via open()'d file descriptor, e.g.:
*
* CHECK_NE(-1, chmod("foo/bar.txt", 0644));
* CHECK_NE(-1, chmod("o/default/program.com", 0755));
* CHECK_NE(-1, chmod("privatefolder/", 0700));
*
* The esoteric bits generally available on System V are:
*
* CHECK_NE(-1, chmod("/opt/", 01000)); // sticky bit
* CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit
* CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit
*
* This works on Windows NT if you ignore the error ;-)
* Changes file permissions via open()'d file descriptor.
*
* @param mode contains octal flags (base 8)
* @errors ENOSYS
* @asyncsignalsafe
* @see chmod()
*/

49
libc/calls/fchmodat.c Normal file
View file

@ -0,0 +1,49 @@
/*-*- 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/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Changes permissions on file, e.g.:
*
* CHECK_NE(-1, fchmodat(AT_FDCWD, "foo/bar.txt", 0644));
* CHECK_NE(-1, fchmodat(AT_FDCWD, "o/default/program.com", 0755));
* CHECK_NE(-1, fchmodat(AT_FDCWD, "privatefolder/", 0700));
*
* This works on Windows NT if you ignore the error ;-)
*
* @param path must exist
* @param mode contains octal flags (base 8)
* @param flags can have `AT_SYMLINK_NOFOLLOW`
* @errors ENOENT, ENOTDIR, ENOSYS
* @asyncsignalsafe
* @see fchmod()
*/
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
return sys_fchmodat(dirfd, path, mode, flags);
}

View file

@ -16,11 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Changes owner and/or group of pathname.
* Changes owner and/or group of path.
*
* @param dirfd is open()'d relative-to directory, or AT_FDCWD, etc.
* @param uid is user id, or -1 to not change
@ -32,7 +37,11 @@
* @see /etc/group for group ids
* @asyncsignalsafe
*/
int fchownat(int dirfd, const char *pathname, uint32_t uid, uint32_t gid,
uint32_t flags) {
return sys_fchownat(dirfd, pathname, uid, gid, flags);
int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
int flags) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
return sys_fchownat(dirfd, path, uid, gid, flags);
}

View file

@ -16,9 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Does things with file descriptor, via re-imagined hourglass api, e.g.
@ -45,9 +48,15 @@ int fcntl(int fd, int cmd, ...) {
va_start(va, cmd);
arg = va_arg(va, uintptr_t);
va_end(va);
if (!IsWindows()) {
return sys_fcntl(fd, cmd, arg);
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) {
return sys_fcntl(fd, cmd, arg);
} else {
return sys_fcntl_nt(fd, cmd, arg);
}
} else {
return sys_fcntl_nt(fd, cmd, arg);
return einval();
}
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/files.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
@ -37,6 +38,7 @@ bool fileexists(const char *path) {
int rc, olderr;
struct stat st;
uint16_t path16[PATH_MAX];
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = __sys_fstatat(AT_FDCWD, path, &st, 0);

View file

@ -17,24 +17,69 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/fmt/conv.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/fileinfobyhandleclass.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/fsctl.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/filecompressioninfo.h"
#include "libc/nt/struct/reparsedatabuffer.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
#if 0
#define DEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
#else
#define DEBUG(FMT, ...) (void)0
#endif
static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
wint_t x, y;
const char16_t *p;
uint32_t mem, i, n, z = 0;
struct NtReparseDataBuffer *rdb;
long buf[(sizeof(*rdb) + PATH_MAX * sizeof(char16_t)) / sizeof(long)];
mem = sizeof(buf);
rdb = (struct NtReparseDataBuffer *)buf;
if (DeviceIoControl(fh, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &n, 0)) {
i = 0;
n = rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
while (i < n) {
x = p[i++] & 0xffff;
if (!IsUcs2(x)) {
if (i < n) {
y = p[i++] & 0xffff;
x = MergeUtf16(x, y);
} else {
x = 0xfffd;
}
}
z += x < 0200 ? 1 : bsrl(tpenc(x)) >> 3;
}
} else {
DEBUG("GetSizeOfReparsePoint failed %d", GetLastError());
}
return z;
}
textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
int filetype;
uint64_t actualsize;
struct NtFileCompressionInfo fci;
struct NtByHandleFileInformation wst;
if (!st) return efault();
if ((filetype = GetFileType(handle))) {
memset(st, 0, sizeof(*st));
switch (filetype) {
@ -52,7 +97,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
}
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
st->st_mode |= S_IFDIR;
} else if (wst.dwFileAttributes & kNtFileFlagOpenReparsePoint) {
} else if (wst.dwFileAttributes & kNtFileAttributeReparsePoint) {
st->st_mode |= S_IFLNK;
} else {
st->st_mode |= S_IFREG;
@ -66,13 +111,19 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
st->st_rdev = wst.dwVolumeSerialNumber;
st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
st->st_nlink = wst.nNumberOfLinks;
if (GetFileInformationByHandleEx(handle, kNtFileCompressionInfo, &fci,
sizeof(fci))) {
actualsize = fci.CompressedFileSize;
if (S_ISLNK(st->st_mode)) {
if (!st->st_size) {
st->st_size = GetSizeOfReparsePoint(handle);
}
} else {
actualsize = st->st_size;
if (S_ISREG(st->st_mode) &&
GetFileInformationByHandleEx(handle, kNtFileCompressionInfo,
&fci, sizeof(fci))) {
actualsize = fci.CompressedFileSize;
}
st->st_blocks = roundup(actualsize, PAGESIZE) / 512;
}
st->st_blocks = roundup(actualsize, PAGESIZE) / 512;
}
break;
default:

View file

@ -29,7 +29,7 @@
* @asyncsignalsafe
*/
int fstat(int fd, struct stat *st) {
if (IsAsan() && (!st || !__asan_is_valid(st, sizeof(*st)))) return efault();
if (IsAsan() && !__asan_is_valid(st, sizeof(*st))) return efault();
if (__isfdkind(fd, kFdZip)) {
return weaken(__zipos_fstat)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);

View file

@ -22,12 +22,11 @@
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/at.h"
textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
uint32_t flags) {
int flags) {
int rc;
int64_t fh;
uint16_t path16[PATH_MAX];
@ -35,9 +34,12 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
if ((fh = CreateFile(
path16, kNtFileReadAttributes,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
kNtOpenExisting, kNtFileAttributeNormal | kNtFileFlagBackupSemantics,
kNtOpenExisting,
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
: 0),
0)) != -1) {
rc = sys_fstat_nt(fh, st);
rc = st ? sys_fstat_nt(fh, st) : 0;
CloseHandle(fh);
return rc;
} else {

View file

@ -19,8 +19,11 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.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"
@ -36,9 +39,13 @@
* @see S_ISDIR(st.st_mode), S_ISREG()
* @asyncsignalsafe
*/
int fstatat(int dirfd, const char *path, struct stat *st, uint32_t flags) {
int fstatat(int dirfd, const char *path, struct stat *st, int flags) {
struct ZiposUri zipname;
if (IsAsan() && (!st || !__asan_is_valid(st, sizeof(*st)))) return efault();
if (IsAsan() && (!__asan_is_valid(path, 1) ||
(st && !__asan_is_valid(st, sizeof(*st))))) {
return efault();
}
if (__isfdkind(dirfd, kFdZip)) return einval(); /* TODO(jart): implement me */
if (weaken(__zipos_stat) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
return weaken(__zipos_stat)(&zipname, st);
} else if (!IsWindows()) {

View file

@ -16,32 +16,70 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Returns current working directory.
* Returns current working directory, e.g.
*
* const char *dirname = gc(getcwd(0,0)); // if malloc is linked
* const char *dirname = getcwd(alloca(PATH_MAX),PATH_MAX);
*
* @param buf is where UTF-8 NUL-terminated path string gets written,
* which may be NULL to ask this function to malloc a buffer
* @param size is number of bytes available in buf, e.g. PATH_MAX,
* which may be 0 if buf NULL
* @return buf containing system-normative path or NULL w/ errno
* @see get_current_dir_name() which is better
* @error ERANGE, EINVAL
* @error ERANGE, EINVAL, ENOMEM
*/
char *(getcwd)(char *buf, size_t size) {
if (buf && size) buf[0] = '\0';
if (!IsWindows()) {
if (IsXnu()) {
return sys_getcwd_xnu(buf, size);
} else if (sys_getcwd(buf, size) != (void *)-1) {
return buf;
} else {
return NULL;
char *getcwd(char *buf, size_t size) {
char *p, *r;
if (buf) {
p = buf;
if (!size) {
einval();
return 0;
}
} else if (weaken(malloc)) {
if (!size) size = PATH_MAX + 1;
if (!(p = weaken(malloc)(size))) {
return 0;
}
} else {
return sys_getcwd_nt(buf, size);
einval();
return 0;
}
*p = '\0';
if (!IsWindows()) {
if (IsMetal()) {
r = size >= 5 ? strcpy(p, "/zip") : 0;
} else if (IsXnu()) {
r = sys_getcwd_xnu(p, size);
} else if (sys_getcwd(p, size) != (void *)-1) {
r = p;
} else {
r = 0;
}
} else {
r = sys_getcwd_nt(p, size);
}
if (!buf) {
if (!r) {
if (weaken(free)) {
weaken(free)(p);
}
} else {
if (weaken(realloc)) {
if ((p = weaken(realloc)(r, strlen(r) + 1))) {
r = p;
}
}
}
}
return r;
}

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -28,9 +29,13 @@
* @return 0 on success or -1 w/ errno
*/
int getitimer(int which, struct itimerval *curvalue) {
if (IsAsan() && !__asan_is_valid(curvalue, sizeof(*curvalue))) {
return efault();
}
if (!IsWindows()) {
return sys_getitimer(which, curvalue);
} else {
return sys_setitimer_nt(which, NULL, curvalue);
if (!curvalue) return efault();
return sys_setitimer_nt(which, 0, curvalue);
}
}

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -30,6 +31,7 @@
* @see libc/sysv/consts.sh
*/
int getrlimit(int resource, struct rlimit *rlim) {
if (resource == -1) return einval();
if (resource == 127) return einval();
if (IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim))) return efault();
return sys_getrlimit(resource, rlim);
}

View file

@ -18,6 +18,8 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -27,6 +29,8 @@
* @return 0 on success, or -1 w/ errno
*/
int getrusage(int who, struct rusage *usage) {
if (who == 99) return einval();
if (IsAsan() && !__asan_is_valid(usage, sizeof(*usage))) return efault();
if (!IsWindows()) {
return sys_getrusage(who, usage);
} else {

View file

@ -28,7 +28,7 @@
int sys_gettimeofday_nt(struct timeval *tv, struct timezone *tz) {
struct NtFileTime ft;
GetSystemTimeAsFileTime(&ft);
*tv = FileTimeToTimeVal(ft);
if (tv) *tv = FileTimeToTimeVal(ft);
if (tz) memset(tz, 0, sizeof(*tz));
return 0;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/time.h"
@ -35,6 +36,10 @@
*/
int gettimeofday(struct timeval *tv, struct timezone *tz) {
axdx_t ad;
if (IsAsan() && ((tv && !__asan_is_valid(tv, sizeof(*tv))) ||
(tz && !__asan_is_valid(tz, sizeof(*tz))))) {
return efault();
}
if (!IsWindows() && !IsMetal()) {
ad = sys_gettimeofday(tv, tz, NULL);
assert(ad.ax != -1);

View file

@ -117,7 +117,6 @@ i32 __sys_openat(i32, const char *, i32, u32) hidden;
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden;
i32 getdents(i32, void *, u32, i64 *) hidden;
i32 sys_chdir(const char *) hidden;
i32 sys_clock_gettime(i32, struct timespec *) hidden;
i32 sys_close(i32) hidden;
@ -232,6 +231,7 @@ int gethostname_bsd(char *, size_t) hidden;
int gethostname_nt(char *, size_t) hidden;
size_t __iovec_size(const struct iovec *, size_t) hidden;
void __rusage2linux(struct rusage *) hidden;
int __notziposat(int, const char *);
ssize_t WritevUninterruptible(int, struct iovec *, int);
void flock2cosmo(uintptr_t);
void cosmo2flock(uintptr_t);
@ -264,14 +264,14 @@ int sys_fdatasync_nt(int) hidden;
int sys_flock_nt(int, int) hidden;
int sys_fork_nt(void) hidden;
int sys_fstat_nt(i64, struct stat *) hidden;
int sys_fstatat_nt(int, const char *, struct stat *, uint32_t) hidden;
int sys_fstatat_nt(int, const char *, struct stat *, int) hidden;
int sys_ftruncate_nt(i64, u64) hidden;
int sys_getppid_nt(void) hidden;
int sys_getpriority_nt(int) hidden;
int sys_getrusage_nt(int, struct rusage *) hidden;
int sys_gettimeofday_nt(struct timeval *, struct timezone *) hidden;
int sys_kill_nt(int, int) hidden;
int sys_link_nt(const char *, const char *) hidden;
int sys_linkat_nt(int, const char *, int, const char *) hidden;
int sys_lstat_nt(const char *, struct stat *) hidden;
int sys_madvise_nt(void *, size_t, int) hidden;
int sys_mkdirat_nt(int, const char *, uint32_t) hidden;
@ -287,12 +287,12 @@ int sys_sync_nt(void) hidden;
int sys_sysinfo_nt(struct sysinfo *) hidden;
int sys_truncate_nt(const char *, u64) hidden;
int sys_unlinkat_nt(int, const char *, int) hidden;
int sys_utimes_nt(const char *, const struct timeval[2]) hidden;
int sys_utimensat_nt(int, const char *, const struct timespec *, int) hidden;
int sys_utimes_nt(const char *, const struct timeval[2]) hidden;
ssize_t sys_open_nt(int, const char *, u32, i32) nodiscard hidden;
ssize_t sys_read_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
ssize_t sys_write_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t) hidden;
ssize_t sys_write_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » windows nt » support

View file

@ -13,10 +13,10 @@ COSMOPOLITAN_C_START_
int ioctl(int, uint64_t, ...);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » ioctl » undiamonding (size optimization)
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » ioctl » undiamonding
*/
#define ioctl(FD, REQUEST, ...) \
__IOCTL_DISPATCH(__EQUIVALENT, ioctl_default(FD, REQUEST, ##__VA_ARGS__), \
@ -63,22 +63,18 @@ int ioctl(int, uint64_t, ...);
ReZ; \
})
int ioctl_tcgets(int, void *);
int ioctl_tcgets_nt(int, void *);
int ioctl_tcsets(int, uint64_t, void *);
int ioctl_tcsets_nt(int, uint64_t, void *);
int ioctl_tiocgwinsz(int, void *);
int ioctl_tiocgwinsz_nt(int, void *);
int ioctl_tiocswinsz(int, void *);
int ioctl_tiocswinsz_nt(int, void *);
int ioctl_siocgifconf(int, void *);
int ioctl_siocgifaddr(int, void *);
int ioctl_siocgifdstaddr(int, void *);
int ioctl_siocgifnetmask(int, void *);
int ioctl_siocgifbrdaddr(int, void *);
int ioctl_siocgifflags(int, void *);
int ioctl_default(int, uint64_t, void *);
int ioctl_default(int, uint64_t, ...);
int ioctl_fioclex(int, int);
int ioctl_siocgifaddr(int, ...);
int ioctl_siocgifbrdaddr(int, ...);
int ioctl_siocgifconf(int, ...);
int ioctl_siocgifdstaddr(int, ...);
int ioctl_siocgifflags(int, ...);
int ioctl_siocgifnetmask(int, ...);
int ioctl_tcgets(int, ...);
int ioctl_tcsets(int, uint64_t, ...);
int ioctl_tiocgwinsz(int, ...);
int ioctl_tiocswinsz(int, ...);
#endif /* GNUC && !ANSI */
COSMOPOLITAN_C_END_

View file

@ -23,15 +23,20 @@
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
int ioctl_default(int fd, uint64_t request, void *memory) {
int ioctl_default(int fd, uint64_t request, ...) {
int rc;
void *arg;
va_list va;
int64_t handle;
va_start(va, request);
arg = va_arg(va, void *);
va_end(va);
if (!IsWindows()) {
return sys_ioctl(fd, request, memory);
return sys_ioctl(fd, request, arg);
} else if (__isfdopen(fd)) {
if (g_fds.p[fd].kind == kFdSocket) {
handle = g_fds.p[fd].handle;
if ((rc = weaken(__sys_ioctlsocket_nt)(handle, request, memory)) != -1) {
if ((rc = weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) {
return rc;
} else {
return weaken(__winsockerr)();

View file

@ -19,8 +19,8 @@
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/dce.h"
int ioctl_fioclex_nt(int, int);
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Sets "close on exec" on file descriptor the fast way.
@ -28,9 +28,22 @@ int ioctl_fioclex_nt(int, int);
* @see ioctl(fd, FIOCLEX, 0) dispatches here
*/
int ioctl_fioclex(int fd, int req) {
if (!IsWindows()) {
return sys_ioctl(fd, req, 0);
if (fd >= 0) {
if (IsWindows() || (fd < g_fds.n && g_fds.p[fd].kind == kFdZip)) {
if (__isfdopen(fd)) {
if (req == FIOCLEX) {
g_fds.p[fd].flags |= O_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
}
return 0;
} else {
return ebadf();
}
} else {
return sys_ioctl(fd, req);
}
} else {
return ioctl_fioclex_nt(fd, req);
return einval();
}
}

View file

@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
@ -35,7 +36,6 @@
* The ifc_len is an input/output parameter: set it to the total size of
* the ifcu_buf (ifcu_req) buffer on input.
*/
int ioctl_default(int, uint64_t, void *) hidden;
int ioctl_siocgifconf_nt(int, struct ifconf *) hidden;
int ioctl_siocgifaddr_nt(int, struct ifreq *) hidden;
int ioctl_siocgifflags_nt(int, struct ifreq *) hidden;
@ -103,41 +103,66 @@ static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
*
* @see ioctl(fd, SIOCGIFCONF, tio) dispatches here
*/
int ioctl_siocgifconf(int fd, void *ifc) {
int ioctl_siocgifconf(int fd, ...) {
va_list va;
struct ifconf *ifc;
va_start(va, fd);
ifc = va_arg(va, struct ifconf *);
va_end(va);
if (!IsWindows()) {
return ioctl_siocgifconf_sysv(fd, (struct ifconf *)ifc);
return ioctl_siocgifconf_sysv(fd, ifc);
} else {
return ioctl_siocgifconf_nt(fd, ifc);
}
}
int ioctl_siocgifaddr(int fd, void *ifr) {
int ioctl_siocgifaddr(int fd, ...) {
va_list va;
struct ifreq *ifr;
va_start(va, fd);
ifr = va_arg(va, struct ifreq *);
va_end(va);
if (!IsWindows()) {
return ioctl_siocgifaddr_sysv(fd, SIOCGIFADDR, (struct ifreq *)ifr);
return ioctl_siocgifaddr_sysv(fd, SIOCGIFADDR, ifr);
} else {
return ioctl_siocgifaddr_nt(fd, (struct ifreq *)ifr);
return ioctl_siocgifaddr_nt(fd, ifr);
}
}
int ioctl_siocgifnetmask(int fd, void *ifr) {
int ioctl_siocgifnetmask(int fd, ...) {
va_list va;
struct ifreq *ifr;
va_start(va, fd);
ifr = va_arg(va, struct ifreq *);
va_end(va);
if (!IsWindows()) {
return ioctl_siocgifaddr_sysv(fd, SIOCGIFNETMASK, (struct ifreq *)ifr);
return ioctl_siocgifaddr_sysv(fd, SIOCGIFNETMASK, ifr);
} else {
return ioctl_siocgifnetmask_nt(fd, (struct ifreq *)ifr);
return ioctl_siocgifnetmask_nt(fd, ifr);
}
}
int ioctl_siocgifbrdaddr(int fd, void *ifr) {
int ioctl_siocgifbrdaddr(int fd, ...) {
va_list va;
struct ifreq *ifr;
va_start(va, fd);
ifr = va_arg(va, struct ifreq *);
va_end(va);
if (!IsWindows()) {
return ioctl_siocgifaddr_sysv(fd, SIOCGIFBRDADDR, (struct ifreq *)ifr);
return ioctl_siocgifaddr_sysv(fd, SIOCGIFBRDADDR, ifr);
} else {
return ioctl_siocgifbrdaddr_nt(fd, (struct ifreq *)ifr);
return ioctl_siocgifbrdaddr_nt(fd, ifr);
}
}
int ioctl_siocgifdstaddr(int fd, void *ifr) {
int ioctl_siocgifdstaddr(int fd, ...) {
va_list va;
struct ifreq *ifr;
va_start(va, fd);
ifr = va_arg(va, struct ifreq *);
va_end(va);
if (!IsWindows()) {
return ioctl_siocgifaddr_sysv(fd, SIOCGIFDSTADDR, (struct ifreq *)ifr);
return ioctl_siocgifaddr_sysv(fd, SIOCGIFDSTADDR, ifr);
} else {
return enotsup();
/* Not supported - Unknown how to find out how to retrieve the destination
@ -149,11 +174,16 @@ int ioctl_siocgifdstaddr(int fd, void *ifr) {
}
}
int ioctl_siocgifflags(int fd, void *ifr) {
int ioctl_siocgifflags(int fd, ...) {
va_list va;
struct ifreq *ifr;
va_start(va, fd);
ifr = va_arg(va, struct ifreq *);
va_end(va);
if (!IsWindows()) {
/* Both XNU and Linux are for once compatible here... */
return ioctl_default(fd, SIOCGIFFLAGS, ifr);
} else {
return ioctl_siocgifflags_nt(fd, (struct ifreq *)ifr);
return ioctl_siocgifflags_nt(fd, ifr);
}
}

View file

@ -17,9 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/metatermios.internal.h"
#include "libc/calls/termios.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
int ioctl_tcgets_nt(int, struct termios *) hidden;
@ -39,10 +43,23 @@ static int ioctl_tcgets_sysv(int fd, struct termios *tio) {
* @see ioctl(fd, TCGETS, tio) dispatches here
* @see ioctl(fd, TIOCGETA, tio) dispatches here
*/
int ioctl_tcgets(int fd, struct termios *tio) {
if (!IsWindows()) {
return ioctl_tcgets_sysv(fd, tio);
int ioctl_tcgets(int fd, ...) {
va_list va;
struct termios *tio;
va_start(va, fd);
tio = va_arg(va, struct termios *);
va_end(va);
if (fd >= 0) {
if (!tio) return efault();
if (IsAsan() && !__asan_is_valid(tio, sizeof(*tio))) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty();
} else if (!IsWindows()) {
return ioctl_tcgets_sysv(fd, tio);
} else {
return ioctl_tcgets_nt(fd, tio);
}
} else {
return ioctl_tcgets_nt(fd, tio);
return einval();
}
}

View file

@ -17,9 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/metatermios.internal.h"
#include "libc/calls/termios.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
@ -38,11 +40,23 @@ static int ioctl_tcsets_sysv(int fd, uint64_t request,
* @see ioctl(fd, TCSETS{,W,F}, tio) dispatches here
* @see ioctl(fd, TIOCGETA{,W,F}, tio) dispatches here
*/
int ioctl_tcsets(int fd, uint64_t request, const struct termios *tio) {
int ioctl_tcsets(int fd, uint64_t request, ...) {
va_list va;
const struct termios *tio;
va_start(va, request);
tio = va_arg(va, const struct termios *);
va_end(va);
if (!tio) return efault();
if (!IsWindows()) {
return ioctl_tcsets_sysv(fd, request, tio);
if (IsAsan() && !__asan_is_valid(tio, sizeof(*tio))) return efault();
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty();
} else if (!IsWindows()) {
return ioctl_tcsets_sysv(fd, request, tio);
} else {
return ioctl_tcsets_nt(fd, request, tio);
}
} else {
return ioctl_tcsets_nt(fd, request, tio);
return einval();
}
}

View file

@ -32,6 +32,7 @@ textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) {
uint32_t mode;
struct NtStartupInfo startinfo;
struct NtConsoleScreenBufferInfoEx sbinfo;
if (!ws) return efault();
fds[0] = fd, fds[1] = 1, fds[2] = 0;
GetStartupInfo(&startinfo);
for (i = 0; i < ARRAYLEN(fds); ++i) {

View file

@ -17,9 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/winsize.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
int ioctl_tiocgwinsz_nt(int, struct winsize *);
@ -28,10 +31,22 @@ int ioctl_tiocgwinsz_nt(int, struct winsize *);
*
* @see ioctl(fd, TIOCGWINSZ, ws) dispatches here
*/
int ioctl_tiocgwinsz(int fd, struct winsize *ws) {
if (!IsWindows()) {
return sys_ioctl(fd, TIOCGWINSZ, ws);
int ioctl_tiocgwinsz(int fd, ...) {
va_list va;
struct winsize *ws;
va_start(va, fd);
ws = va_arg(va, struct winsize *);
va_end(va);
if (IsAsan() && !__asan_is_valid(ws, sizeof(*ws))) return efault();
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty();
} else if (!IsWindows()) {
return sys_ioctl(fd, TIOCGWINSZ, ws);
} else {
return ioctl_tiocgwinsz_nt(fd, ws);
}
} else {
return ioctl_tiocgwinsz_nt(fd, ws);
return einval();
}
}

View file

@ -17,21 +17,36 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/winsize.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
int ioctl_tiocswinsz_nt(int, const struct winsize *);
/**
* Returns width and height of terminal.
* Sets width and height of terminal.
*
* @see ioctl(fd, TIOCSWINSZ, ws) dispatches here
*/
int ioctl_tiocswinsz(int fd, const struct winsize *ws) {
if (!IsWindows()) {
return sys_ioctl(fd, TIOCSWINSZ, ws);
int ioctl_tiocswinsz(int fd, ...) {
va_list va;
const struct winsize *ws;
va_start(va, fd);
ws = va_arg(va, const struct winsize *);
va_end(va);
if (IsAsan() && !__asan_is_valid(ws, sizeof(*ws))) return efault();
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty();
} else if (!IsWindows()) {
return sys_ioctl(fd, TIOCSWINSZ, ws);
} else {
return ioctl_tiocswinsz_nt(fd, ws);
}
} else {
return ioctl_tiocswinsz_nt(fd, ws);
return einval();
}
}

View file

@ -22,6 +22,7 @@
#include "libc/sysv/errfuns.h"
textwindows bool32 sys_isatty_nt(int fd) {
if (!__isfdkind(fd, kFdFile)) return ebadf();
return GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar;
return __isfdkind(fd, kFdConsole) ||
(__isfdkind(fd, kFdFile) &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
}

View file

@ -18,18 +18,30 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/winsize.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/termios.h"
/**
* Returns true if file descriptor is backed by a terminal device.
* @asyncsignalsafe
*/
bool32 isatty(int fd) {
_Alignas(short) char buf[sizeof(uint16_t) * 4];
if (!IsWindows()) {
return sys_ioctl(fd, TIOCGWINSZ, &buf) != -1;
int err;
bool32 res;
struct winsize ws;
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return false;
} else if (!IsWindows()) {
err = errno;
res = sys_ioctl(fd, TIOCGWINSZ, &ws) != -1;
errno = err;
return res;
} else {
return sys_isatty_nt(fd);
}
} else {
return sys_isatty_nt(fd);
return false;
}
}

View file

@ -21,8 +21,10 @@
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/files.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Returns true if file exists and is a directory.
@ -30,6 +32,7 @@
bool isdirectory(const char *path) {
struct stat st;
int rc, olderr;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW);

View file

@ -21,7 +21,9 @@
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Returns true if file exists and is a regular file.
@ -29,6 +31,7 @@
bool isregularfile(const char *path) {
struct stat st;
int rc, olderr;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW);

View file

@ -0,0 +1,27 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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/log/log.h"
#include "libc/runtime/runtime.h"
/**
* Returns true if current process was spawned by GNU Make.
*/
bool IsRunningUnderMake(void) {
return !!getenv("MAKEFLAGS");
}

View file

@ -21,8 +21,10 @@
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/files.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Returns true if file exists and is a symbolic link.
@ -30,6 +32,7 @@
bool issymlink(const char *path) {
struct stat st;
int rc, olderr;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW);

View file

@ -31,5 +31,5 @@
* @see /etc/group for group ids
*/
int lchown(const char *pathname, uint32_t uid, uint32_t gid) {
return sys_fchownat(AT_FDCWD, pathname, uid, gid, AT_SYMLINK_NOFOLLOW);
return fchownat(AT_FDCWD, pathname, uid, gid, AT_SYMLINK_NOFOLLOW);
}

View file

@ -32,9 +32,5 @@
* @asyncsignalsafe
*/
int link(const char *existingpath, const char *newpath) {
if (!IsWindows()) {
return sys_linkat(AT_FDCWD, existingpath, AT_FDCWD, newpath, 0);
} else {
return sys_link_nt(existingpath, newpath);
}
return linkat(AT_FDCWD, existingpath, AT_FDCWD, newpath, 0);
}

View file

@ -21,12 +21,13 @@
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
textwindows int sys_link_nt(const char *existingpath, const char *newpath) {
textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, int newdirfd,
const char *newpath) {
char16_t newpath16[PATH_MAX];
char16_t existingpath16[PATH_MAX];
if (__mkntpath(existingpath, existingpath16) != -1 &&
__mkntpath(newpath, newpath16) != -1) {
if (CreateHardLink(newpath16, existingpath16, NULL)) {
char16_t oldpath16[PATH_MAX];
if (__mkntpathat(olddirfd, oldpath, 0, oldpath16) != -1 &&
__mkntpathat(newdirfd, newpath, 0, newpath16) != -1) {
if (CreateHardLink(newpath16, oldpath16, NULL)) {
return 0;
} else {
return __winerr();

53
libc/calls/linkat.c Normal file
View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Creates hard filesystem link.
*
* This allows two names to point to the same file data on disk. They
* can only be differentiated by examining the inode number.
*
* @param flags can have AT_EMPTY_PATH or AT_SYMLINK_NOFOLLOW
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
int flags) {
if (IsAsan() &&
(!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) {
return efault();
}
if (weaken(__zipos_notat) &&
(weaken(__zipos_notat)(olddirfd, oldpath) == -1 ||
weaken(__zipos_notat)(newdirfd, newpath) == -1)) {
return -1; /* TODO(jart): implement me */
}
if (!IsWindows()) {
return sys_linkat(olddirfd, oldpath, newdirfd, newpath, flags);
} else {
return sys_linkat_nt(olddirfd, oldpath, newdirfd, newpath);
}
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/time/time.h"

View file

@ -19,6 +19,8 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Drops hints to O/S about intended access patterns of mmap()'d memory.
@ -29,6 +31,7 @@
* @see fadvise()
*/
int madvise(void *addr, size_t length, int advice) {
if (IsAsan() && !__asan_is_valid(addr, length)) return efault();
if (!IsWindows()) {
return sys_madvise(addr, length, advice);
} else {

View file

@ -16,21 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/calls/makedev.h"
#include "libc/dce.h"
textwindows int ioctl_fioclex_nt(int fd, int req) {
if (__isfdopen(fd)) {
if (req == FIOCLEX) {
g_fds.p[fd].flags |= O_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
}
return 0;
uint32_t(major)(uint64_t x) {
if (IsXnu()) {
return (x >> 24) & 0xff;
} else if (IsNetbsd()) {
return (x & 0x000fff00) >> 8;
} else if (IsOpenbsd()) {
return (x >> 8) & 0xff;
} else if (IsFreebsd()) {
return ((x >> 32) & 0xffffff00) | ((x >> 8) & 0x000000ff);
} else {
return ebadf();
return ((x >> 32) & 0xfffff000) | ((x >> 8) & 0x00000fff);
}
}

37
libc/calls/makedev.c Normal file
View file

@ -0,0 +1,37 @@
/*-*- 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/makedev.h"
#include "libc/dce.h"
uint64_t(makedev)(uint32_t x, uint32_t y) {
if (IsXnu()) {
return x << 24 | y;
} else if (IsNetbsd()) {
return ((x << 8) & 0x000fff00) | ((y << 12) & 0xfff00000) |
(y & 0x000000ff);
} else if (IsOpenbsd()) {
return (x & 0xff) << 8 | (y & 0xff) | (y & 0xffff00) << 8;
} else if (IsFreebsd()) {
return (uint64_t)(x & 0xffffff00) << 32 | (x & 0x000000ff) << 8 |
(y & 0x0000ff00) << 24 | (y & 0xffff00ff);
} else {
return (uint64_t)(x & 0xfffff000) << 32 | (x & 0x00000fff) << 8 |
(y & 0xffffff00) << 12 | (y & 0x000000ff);
}
}

View file

@ -1,52 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_MAKEDEV_H_
#define COSMOPOLITAN_LIBC_CALLS_MAKEDEV_H_
#include "libc/dce.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
static inline uint64_t major(uint64_t x) {
if (IsXnu()) {
return (x >> 24) & 0xff;
} else if (IsNetbsd()) {
return (x & 0x000fff00) >> 8;
} else if (IsOpenbsd()) {
return (x >> 8) & 0xff;
} else if (IsFreebsd()) {
return ((x >> 32) & 0xffffff00) | ((x >> 8) & 0x000000ff);
} else {
return ((x >> 32) & 0xfffff000) | ((x >> 8) & 0x00000fff);
}
}
static inline uint64_t minor(uint64_t x) {
if (IsXnu()) {
return x & 0x00ffffff;
} else if (IsNetbsd()) {
return (x & 0x000000ff) | (x & 0xfff00000) >> 12;
} else if (IsOpenbsd()) {
return (x & 0x000000ff) | (x & 0x0ffff000) >> 8;
} else if (IsFreebsd()) {
return ((x >> 24) & 0x0000ff00) | (x & 0xffff00ff);
} else {
return ((x >> 12) & 0xffffff00) | (x & 0x000000ff);
}
}
static inline uint64_t makedev(uint64_t x, uint64_t y) {
if (IsXnu()) {
return x << 24 | y;
} else if (IsNetbsd()) {
return ((x << 8) & 0x000fff00) | ((y << 12) & 0xfff00000u) |
(y & 0x000000ff);
} else if (IsOpenbsd()) {
return (x & 0xff) << 8 | (y & 0xff) | (y & 0xffff00) << 8;
} else if (IsFreebsd()) {
return (x & 0xffffff00) << 32 | (x & 0x000000ff) << 8 |
(y & 0x0000ff00) << 24 | (y & 0xffff00ff);
} else {
return (x & 0xfffff000) << 32 | (x & 0x00000fff) << 8 |
(y & 0xffffff00) << 12 | (y & 0x000000ff);
}
}
uint64_t makedev(uint32_t, uint32_t);
uint32_t major(uint64_t);
uint32_t minor(uint64_t);
#define major(x) major(x)
#define minor(x) minor(x)

34
libc/calls/minor.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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/makedev.h"
#include "libc/dce.h"
uint32_t(minor)(uint64_t x) {
if (IsXnu()) {
return x & 0x00ffffff;
} else if (IsNetbsd()) {
return (x & 0x000000ff) | (x & 0xfff00000) >> 12;
} else if (IsOpenbsd()) {
return (x & 0x000000ff) | (x & 0x0ffff000) >> 8;
} else if (IsFreebsd()) {
return ((x >> 24) & 0x0000ff00) | (x & 0xffff00ff);
} else {
return ((x >> 12) & 0xffffff00) | (x & 0x000000ff);
}
}

View file

@ -16,10 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Creates directory a.k.a. folder.
@ -34,6 +38,10 @@
* @see makedirs()
*/
int mkdirat(int dirfd, const char *path, unsigned mode) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
if (!IsWindows()) {
return sys_mkdirat(dirfd, path, mode);
} else {

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/ipc.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
@ -33,6 +34,7 @@
*/
int mkfifo(const char *pathname, unsigned mode) {
/* TODO(jart): Windows? */
if (IsAsan() && !__asan_is_valid(pathname, 1)) return efault();
if (IsLinux()) {
return sys_mknod(pathname, mode | S_IFIFO, 0);
} else {

View file

@ -16,11 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/sysv/errfuns.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
/**
* Creates filesystem inode.
@ -37,6 +38,7 @@
* @asyncsignalsafe
*/
int mknod(const char *path, uint32_t mode, uint64_t dev) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (mode & S_IFREG) return creat(path, mode & ~S_IFREG);
if (mode & S_IFDIR) return mkdir(path, mode & ~S_IFDIR);
if (mode & S_IFIFO) return mkfifo(path, mode & ~S_IFIFO);

View file

@ -16,8 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/securityimpersonationlevel.h"
#include "libc/nt/enum/securityinformation.h"
@ -30,6 +32,13 @@
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
#if 0
#define DEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
#else
#define DEBUG(FMT, ...) (void)0
#endif
/**
* Asks Microsoft if we're authorized to use a folder or file.
@ -44,19 +53,20 @@
* @see libc/sysv/consts.sh
*/
textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
int rc;
int rc, e;
void *freeme;
bool32 result;
struct NtSecurityDescriptor *s;
struct NtGenericMapping mapping;
struct NtPrivilegeSet privileges;
int64_t hToken, hImpersonatedToken;
uint32_t secsize, granted, privsize;
union NtSecurityDescriptorLol {
struct NtSecurityDescriptor s;
char b[1024];
} security;
intptr_t buffer[1024 / sizeof(intptr_t)];
freeme = 0;
granted = 0;
result = false;
secsize = sizeof(security);
s = (void *)buffer;
secsize = sizeof(buffer);
privsize = sizeof(privileges);
memset(&privileges, 0, sizeof(privileges));
mapping.GenericRead = kNtFileGenericRead;
@ -65,24 +75,55 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
mapping.GenericAll = kNtFileAllAccess;
MapGenericMask(&flags, &mapping);
hImpersonatedToken = hToken = -1;
TryAgain:
if (GetFileSecurity(pathname,
kNtOwnerSecurityInformation |
kNtGroupSecurityInformation |
kNtDaclSecurityInformation,
&security.s, 0, &secsize) &&
OpenProcessToken(GetCurrentProcess(),
kNtTokenImpersonate | kNtTokenQuery | kNtTokenDuplicate |
kNtStandardRightsRead,
&hToken) &&
DuplicateToken(hToken, kNtSecurityImpersonation, &hImpersonatedToken) &&
AccessCheck(&security.s, hImpersonatedToken, flags, &mapping, &privileges,
&privsize, &granted, &result) &&
(result || flags == F_OK)) {
rc = 0;
s, secsize, &secsize)) {
if (OpenProcessToken(GetCurrentProcess(),
kNtTokenImpersonate | kNtTokenQuery |
kNtTokenDuplicate | kNtStandardRightsRead,
&hToken)) {
if (DuplicateToken(hToken, kNtSecurityImpersonation,
&hImpersonatedToken)) {
if (AccessCheck(s, hImpersonatedToken, flags, &mapping, &privileges,
&privsize, &granted, &result)) {
if (result || flags == F_OK) {
rc = 0;
} else {
DEBUG("ntaccesscheck finale failed %d %d", result, flags);
rc = eacces();
}
} else {
rc = __winerr();
DEBUG("AccessCheck failed: %m");
}
} else {
rc = __winerr();
DEBUG("DuplicateToken failed: %m");
}
} else {
rc = __winerr();
DEBUG("OpenProcessToken failed: %m");
}
} else {
rc = __winerr();
e = GetLastError();
DEBUG("GetFileSecurity failed: %d %d", e, secsize);
if (!IsTiny() && e == kNtErrorInsufficientBuffer) {
if (!freeme && weaken(malloc) && (freeme = weaken(malloc)(secsize))) {
s = freeme;
goto TryAgain;
} else {
rc = enomem();
}
} else {
errno = e;
rc = -1;
}
}
close(hImpersonatedToken);
close(hToken);
if (freeme && weaken(free)) weaken(free)(freeme);
if (hImpersonatedToken != -1) CloseHandle(hImpersonatedToken);
if (hToken != -1) CloseHandle(hToken);
return rc;
}

View file

@ -20,6 +20,8 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
@ -43,13 +45,19 @@ int openat(int dirfd, const char *file, int flags, ...) {
va_list va;
unsigned mode;
struct ZiposUri zipname;
if (strstr(file, "0/o/dbg/test")) {
(dprintf)(2, "-- wut %`'s\n", file);
if (weaken(__die)) weaken(__die)();
}
va_start(va, flags);
mode = va_arg(va, unsigned);
va_end(va);
if (!file) return efault();
if (IsAsan() && !__asan_is_valid(file, 1)) return efault();
if (__isfdkind(dirfd, kFdZip)) return einval(); /* TODO(jart): implement me */
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
if (__vforked) return einval();
if (dirfd != AT_FDCWD) return einval();
if (__vforked) return eopnotsupp();
if (dirfd != AT_FDCWD) return eopnotsupp();
return weaken(__zipos_open)(&zipname, flags, mode);
} else if (!IsWindows() && !IsMetal()) {
return sys_openat(dirfd, file, flags, mode);

View file

@ -22,11 +22,13 @@
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/ipc.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
int64_t hin, hout;
int reader, writer;
char16_t pipename[64];
if (!pipefd) return efault();
CreatePipeName(pipename);
if ((reader = __reservefd()) == -1) return -1;
if ((writer = __reservefd()) == -1) {

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -30,7 +31,7 @@
* @see pipe2()
*/
int pipe(int pipefd[hasatleast 2]) {
if (!pipefd) return efault();
if (IsAsan() && !__asan_is_valid(pipefd, sizeof(int) * 2)) return efault();
if (!IsWindows()) {
return sys_pipe(pipefd);
} else {

View file

@ -17,6 +17,8 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -28,6 +30,7 @@
*/
int pipe2(int pipefd[hasatleast 2], int flags) {
if (!pipefd) return efault();
if (IsAsan() && !__asan_is_valid(pipefd, sizeof(int) * 2)) return efault();
if (!IsWindows()) {
return sys_pipe2(pipefd, flags);
} else {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/sock/sock.h"

View file

@ -60,13 +60,14 @@
* @see ECMA-48
*/
ssize_t readansi(int fd, char *buf, size_t size) {
int i, j;
wint_t x;
uint8_t c;
int i, j, rc;
enum { kAscii, kUtf8, kEsc, kCsi, kSs } t;
if (size) buf[0] = 0;
for (j = i = 0, t = kAscii;;) {
if (i + 2 >= size) return enomem();
if (read(fd, &c, 1) != 1) return -1;
if ((rc = read(fd, &c, 1)) != 1) return rc;
buf[i++] = c;
buf[i] = 0;
switch (t) {
@ -79,11 +80,24 @@ ssize_t readansi(int fd, char *buf, size_t size) {
}
} else if (c >= 0300) {
t = kUtf8;
x = ThomPikeByte(c);
j = ThomPikeLen(c) - 1;
}
break;
case kUtf8:
if (!--j) return i;
x = ThomPikeMerge(x, c);
if (!--j) {
switch (x) {
case '\e':
t = kEsc;
break;
case 0x9b:
t = kCsi;
break;
default:
return i;
}
}
break;
case kEsc:
switch (c) {

View file

@ -37,11 +37,12 @@
static textwindows ssize_t sys_readlinkat_nt_error(void) {
uint32_t e;
if ((e = GetLastError()) == kNtErrorNotAReparsePoint) {
return einval();
} else {
errno = e;
return -1;
switch ((e = GetLastError())) {
case kNtErrorNotAReparsePoint:
return einval();
default:
errno = e;
return -1;
}
}
@ -55,6 +56,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
uint32_t e, i, j, n, mem;
char16_t path16[PATH_MAX], *p;
struct NtReparseDataBuffer *rdb;
if (!buf) return efault();
if (weaken(malloc)) {
mem = 16384;
rdb = weaken(malloc)(mem);

View file

@ -48,8 +48,8 @@
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
struct ZiposUri zipname;
if (IsAsan() && !__asan_is_valid(buf, bufsiz)) return efault();
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
return einval();
if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) {
return -1; /* TODO(jart): code me */
}
if (!IsWindows()) {
return sys_readlinkat(dirfd, path, buf, bufsiz);

View file

@ -90,8 +90,8 @@ char *realpath(const char *filename, char *resolved)
return 0;
}
if (l >= PATH_MAX) goto toolong;
if (l > 4 && (READ32LE(filename) == READ32LE("zip:") ||
READ32LE(filename) == READ32LE("zip!"))) {
if (l >= 4 && READ32LE(filename) == READ32LE("/zip") &&
(!filename[4] || filename[4] == '/')) {
return ResolvePath(resolved, filename, l);
}
p = sizeof stack - l - 1;

View file

@ -16,10 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Renames files relative to directories.
@ -32,6 +36,15 @@
*/
int renameat(int olddirfd, const char *oldpath, int newdirfd,
const char *newpath) {
if (IsAsan() &&
(!__asan_is_valid(oldpath, 1) || !__asan_is_valid(newpath, 1))) {
return efault();
}
if (weaken(__zipos_notat) &&
(weaken(__zipos_notat)(olddirfd, oldpath) == -1 ||
weaken(__zipos_notat)(newdirfd, newpath) == -1)) {
return -1; /* TODO(jart): implement me */
}
if (!IsWindows()) {
return sys_renameat(olddirfd, oldpath, newdirfd, newpath);
} else {

View file

@ -61,7 +61,7 @@ static uint32_t ItimerWorker(void *arg) {
}
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
struct itimerval *out_opt_oldvalue) {
struct itimerval *out_opt_oldvalue) {
int32_t period;
int64_t ith, duetime;
if (which != ITIMER_REAL) return einval();

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
@ -62,14 +63,19 @@
* @return 0 on success or -1 w/ errno
*/
int setitimer(int which, const struct itimerval *newvalue,
struct itimerval *out_opt_oldvalue) {
struct itimerval *oldvalue) {
if (IsAsan() &&
((newvalue && !__asan_is_valid(newvalue, sizeof(*newvalue))) ||
(oldvalue && !__asan_is_valid(oldvalue, sizeof(*oldvalue))))) {
return efault();
}
if (!IsWindows()) {
if (newvalue) {
return sys_setitimer(which, newvalue, out_opt_oldvalue);
return sys_setitimer(which, newvalue, oldvalue);
} else {
return sys_getitimer(which, out_opt_oldvalue);
return sys_getitimer(which, oldvalue);
}
} else {
return sys_setitimer_nt(which, newvalue, out_opt_oldvalue);
return sys_setitimer_nt(which, newvalue, oldvalue);
}
}

View file

@ -18,6 +18,8 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -31,9 +33,6 @@
*/
int setrlimit(int resource, const struct rlimit *rlim) {
if (resource == 127) return einval();
if (!IsWindows()) {
return sys_setrlimit(resource, rlim);
} else {
return enosys(); /* TODO(jart): Implement me! */
}
if (IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim))) return efault();
return sys_setrlimit(resource, rlim);
}

View file

@ -30,6 +30,7 @@
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
@ -141,18 +142,23 @@ static void sigaction_native2cosmo(union metasigaction *sa) {
* @vforksafe
*/
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
_Static_assert((sizeof(struct sigaction) > sizeof(struct sigaction_linux) &&
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_in) &&
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_out) &&
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd)),
"sigaction cosmo abi needs tuning");
int64_t arg4, arg5;
int rc, rva, oldrva;
struct sigaction *ap, copy;
assert(sizeof(struct sigaction) > sizeof(struct sigaction_linux) &&
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_in) &&
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_out) &&
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd));
if (IsMetal()) return enosys(); /* TODO: Signals on Metal */
if (!(0 < sig && sig < NSIG)) return einval();
if (sig == SIGKILL || sig == SIGSTOP) return einval();
if (IsAsan() && ((act && !__asan_is_valid(act, sizeof(*act))) ||
(oldact && !__asan_is_valid(oldact, sizeof(*oldact))))) {
return efault();
}
if (!act) {
rva = (int32_t)(intptr_t)SIG_DFL;
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
@ -40,6 +41,12 @@
*/
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
int32_t x;
if (IsAsan() &&
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
(opt_out_oldset &&
!__asan_is_valid(opt_out_oldset, sizeof(*opt_out_oldset))))) {
return efault();
}
if (!IsWindows() && !IsOpenbsd()) {
return sys_sigprocmask(how, opt_set, opt_out_oldset, 8);
} else if (IsOpenbsd()) {

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -31,6 +32,7 @@
*/
int sigsuspend(const sigset_t *ignore) {
unsigned x;
if (IsAsan() && !__asan_is_valid(ignore, sizeof(*ignore))) return efault();
if (!IsWindows()) {
if (IsOpenbsd()) ignore = (sigset_t *)(uintptr_t)(*(uint32_t *)ignore);
return sys_sigsuspend(ignore, 8);

View file

@ -19,7 +19,9 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Creates symbolic link.
@ -35,6 +37,10 @@
* @asyncsignalsafe
*/
int symlinkat(const char *target, int newdirfd, const char *linkpath) {
if (IsAsan() &&
(!__asan_is_valid(target, 1) || !__asan_is_valid(linkpath, 1))) {
return efault();
}
if (!IsWindows()) {
return sys_symlinkat(target, newdirfd, linkpath);
} else {

View file

@ -17,10 +17,29 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
/**
* Changes flow of teletypewriter data.
*
* - `TCOOFF` suspends output
* - `TCOON` resumes output
* - `TCIOFF` transmits a STOP character
* - `TCION` transmits a START character
*/
int tcflow(int fd, int action) {
/* TODO(jart): BSD support */
return sys_ioctl(fd, TCXONC, (void *)(intptr_t)action);
uint8_t c;
struct termios t;
if (!IsBsd()) return sys_ioctl(fd, TCXONC, action);
if (action == TCOOFF) return sys_ioctl(fd, TIOCSTOP, 0);
if (action == TCOON) return sys_ioctl(fd, TIOCSTART, 0);
if (action != TCIOFF && action != TCION) return einval();
if (tcgetattr(fd, &t) == -1) return -1;
if ((c = t.c_cc[action == TCIOFF ? VSTOP : VSTART]) != 255) {
if (sys_write(fd, &c, 1) == -1) return -1;
}
return 0;
}

View file

@ -18,9 +18,15 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
int tcflush(int fd, int x) {
/* TODO(jart): BSD Support */
return sys_ioctl(fd, TCFLSH, x);
/**
* Flushes teletypewriter data.
*
* - `TCIFLUSH` flushes data received but not read
* - `TCOFLUSH` flushes data written but not transmitted
* - `TCIOFLUSH` does both `TCOFLUSH` and `TCIFLUSH`
*/
int tcflush(int fd, int queue) {
/* TODO(jart): Windows? */
return sys_ioctl(fd, TCFLSH, queue);
}

View file

@ -16,10 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Deletes inode and maybe the file too.
@ -31,6 +35,10 @@
* @return 0 on success, or -1 w/ errno
*/
int unlinkat(int dirfd, const char *path, int flags) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
if (!IsWindows()) {
return sys_unlinkat(dirfd, path, flags);
} else {

View file

@ -16,10 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/sysv/consts/at.h"
#include "libc/time/time.h"
#include "libc/zipos/zipos.internal.h"
#define __NR_utimensat_linux 0x118 /*RHEL5:CVE-2010-3301*/
@ -27,6 +29,9 @@ int sys_utimensat(int dirfd, const char *path, const struct timespec ts[2],
int flags) {
int rc, olderr;
struct timeval tv[2];
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
if (!IsXnu()) {
olderr = errno;
rc = __sys_utimensat(dirfd, path, ts, flags);

View file

@ -16,8 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Sets atime/mtime on file, the modern way.
@ -29,6 +34,13 @@
*/
int utimensat(int dirfd, const char *path, const struct timespec ts[2],
int flags) {
if (IsAsan() && (!__asan_is_valid(path, 1) ||
(ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) {
return efault();
}
if (weaken(__zipos_notat) && weaken(__zipos_notat)(dirfd, path) == -1) {
return -1; /* TODO(jart): implement me */
}
if (!IsWindows()) {
return sys_utimensat(dirfd, path, ts, flags);
} else {

View file

@ -37,15 +37,12 @@
*/
int wait4(int pid, int *opt_out_wstatus, int options,
struct rusage *opt_out_rusage) {
if (IsAsan()) {
if (opt_out_wstatus &&
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) {
return efault();
}
if (opt_out_rusage &&
!__asan_is_valid(opt_out_rusage, sizeof(*opt_out_rusage))) {
return efault();
}
if (IsAsan() &&
((opt_out_wstatus &&
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) ||
(opt_out_rusage &&
!__asan_is_valid(opt_out_rusage, sizeof(*opt_out_rusage))))) {
return efault();
}
if (!IsWindows()) {
return sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage);