mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-10 02:31:35 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4072e40bb8 | ||
|
|
393a642c22 | ||
|
|
95173645a1 | ||
|
|
417797d218 | ||
|
|
b8d26e2418 | ||
|
|
21e1023d28 | ||
|
|
eaca5b3e81 | ||
|
|
bf8b1623c8 | ||
|
|
6070319f84 | ||
|
|
36b4bf74f7 | ||
|
|
caee314a50 | ||
|
|
a5f3456333 | ||
|
|
f7c7b949fd | ||
|
|
b2260c2278 |
No files matched your search
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [jart]
|
||||
@@ -20,7 +20,7 @@ Here's how to get started with the freestanding hermetically-sealed
|
||||
monolithic source repository:
|
||||
|
||||
```sh
|
||||
tar xf cosmopolitan-0.1.tar.gz # see our releases page
|
||||
tar xf cosmopolitan-0.1.2.tar.gz # see our releases page
|
||||
cd cosmo
|
||||
make -j12
|
||||
o//examples/hello.com
|
||||
@@ -30,7 +30,7 @@ Here's how to get started with the amalgamated binaries, which let you
|
||||
bring your own build system:
|
||||
|
||||
```sh
|
||||
unzip cosmopolitan-amalgamated-0.1.zip # see our releases page
|
||||
unzip cosmopolitan-amalgamated-0.1.2.zip # see our releases page
|
||||
echo 'main() { printf("hello world\n"); }' >hello.c
|
||||
gcc -g -O -static -fno-pie -no-pie -mno-red-zone -nostdlib -nostdinc \
|
||||
-o hello.com.dbg hello.c -Wl,--gc-sections -Wl,-z,max-page-size=0x1000 -fuse-ld=bfd \
|
||||
|
||||
@@ -783,8 +783,8 @@ ape.pe: .ascin "PE",4
|
||||
.long 0 # Checksum
|
||||
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
||||
.short .LDLLEXE # DllCharacteristics
|
||||
.quad 0x0000000000020000 # StackReserve
|
||||
.quad 0x0000000000020000 # StackCommit
|
||||
.quad 0x0000000000100000 # StackReserve
|
||||
.quad 0x00000000000fc000 # StackCommit
|
||||
.quad 0 # HeapReserve
|
||||
.quad 0 # HeapCommit
|
||||
.long 0 # LoaderFlags
|
||||
|
||||
+21
-3
@@ -11,12 +11,31 @@
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
/**
|
||||
* @fileoverview x86 instruction length decoder by way of hex pipe.
|
||||
*/
|
||||
|
||||
int fgethex(FILE *f) {
|
||||
int o, t = -1;
|
||||
while (!((o = fgetc(f)) & ~0xFF)) {
|
||||
switch (t) {
|
||||
case -1:
|
||||
t = isxdigit(o) ? hextoint(o) : -1;
|
||||
break;
|
||||
default:
|
||||
if (isxdigit(o)) {
|
||||
return t * 16 + hextoint(o);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= 0) return einval();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[argc]) {
|
||||
unsigned c, i, j, l;
|
||||
enum XedError err;
|
||||
@@ -42,9 +61,8 @@ int main(int argc, char *argv[argc]) {
|
||||
l = xedd.length;
|
||||
if (l <= 0 || l > i) abort();
|
||||
for (j = 0; j < l; ++j) {
|
||||
if (fputhex(buf[j], stdout) == -1) {
|
||||
return errno;
|
||||
}
|
||||
fputc("0123456789ABCDEF"[(buf[j] & 0xf0) >> 4], stdout);
|
||||
fputc("0123456789ABCDEF"[(buf[j] & 0x0f) >> 0], stdout);
|
||||
}
|
||||
putchar('\n');
|
||||
memcpy(&buf[0], &buf[l], i -= l);
|
||||
|
||||
+1
-11
@@ -17,10 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
@@ -31,12 +28,5 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return faccessat$sysv(AT_FDCWD, path, mode, 0);
|
||||
} else {
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
}
|
||||
return faccessat(AT_FDCWD, path, mode, 0);
|
||||
}
|
||||
+5
-4
@@ -230,10 +230,7 @@ long ptrace(int, int, void *, void *);
|
||||
int chroot(const char *);
|
||||
int prctl();
|
||||
int sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
(__builtin_constant_p(BUF) && (&(BUF)[0] == NULL) ? get_current_dir_name() \
|
||||
: getcwd(BUF, SIZE))
|
||||
int fchdir(int);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § system calls » formatting ─╬─│┼
|
||||
@@ -247,6 +244,10 @@ 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);
|
||||
|
||||
|
||||
+25
-7
@@ -17,21 +17,39 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int chdir$nt(const char *path) {
|
||||
int len;
|
||||
int e, ms, len;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (path16[len - 1] != u'/' && path16[len - 1] != u'\\') {
|
||||
path16[len + 0] = u'/';
|
||||
if (path16[len - 1] != u'\\') {
|
||||
if (len + 1 + 1 > PATH_MAX) return enametoolong();
|
||||
path16[len + 0] = u'\\';
|
||||
path16[len + 1] = u'\0';
|
||||
}
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
/*
|
||||
* chdir() seems flaky on windows 7
|
||||
* in a similar way to rmdir() sigh
|
||||
*/
|
||||
for (ms = 1;; ms *= 2) {
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
return 0;
|
||||
} else {
|
||||
e = GetLastError();
|
||||
if (ms <= 512 &&
|
||||
(e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) {
|
||||
Sleep(ms);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
+2
-2
@@ -23,11 +23,11 @@
|
||||
|
||||
/**
|
||||
* Sets current directory.
|
||||
*
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
* @see fchdir()
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return chdir$sysv(path);
|
||||
} else {
|
||||
|
||||
@@ -32,9 +32,7 @@
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
|
||||
if (!pathname) return efault();
|
||||
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, 0);
|
||||
}
|
||||
+17
-10
@@ -27,7 +27,9 @@ static bool AccessCommand(char path[hasatleast PATH_MAX], const char *name,
|
||||
size_t namelen, size_t pathlen) {
|
||||
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1;
|
||||
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
||||
path[pathlen++] = '/';
|
||||
path[pathlen] =
|
||||
!IsWindows() ? '/' : memchr(path, '\\', pathlen) ? '\\' : '/';
|
||||
pathlen++;
|
||||
}
|
||||
memcpy(path + pathlen, name, namelen + 1);
|
||||
if (isexecutable(path)) return true;
|
||||
@@ -43,15 +45,18 @@ static bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
||||
size_t i;
|
||||
const char *p;
|
||||
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
|
||||
for (;; p += i) {
|
||||
while (*p == ':' || *p == ';') ++p;
|
||||
if (!*p) break;
|
||||
for (i = 0; i < PATH_MAX && p[i] && p[i] != ':' && p[i] != ';'; ++i) {
|
||||
path[i] = p[i];
|
||||
for (;;) {
|
||||
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
|
||||
if (i < PATH_MAX) path[i] = p[i];
|
||||
}
|
||||
if (AccessCommand(path, name, namelen, i)) {
|
||||
return true;
|
||||
}
|
||||
if (p[i] == ':' || p[i] == ';') {
|
||||
p += i + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -71,9 +76,12 @@ char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||
int rc, olderr;
|
||||
if (!(namelen = strlen(name))) return PROGN(enoent(), NULL);
|
||||
if (namelen + 1 > PATH_MAX) return PROGN(enametoolong(), NULL);
|
||||
if (name[0] == '/' || name[0] == '\\') {
|
||||
memcpy(pathbuf, name, namelen + 1);
|
||||
return pathbuf;
|
||||
if (strchr(name, '/') || strchr(name, '\\')) {
|
||||
if (AccessCommand(strcpy(pathbuf, ""), name, namelen, 0)) {
|
||||
return pathbuf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
olderr = errno;
|
||||
if ((IsWindows() &&
|
||||
@@ -81,7 +89,6 @@ char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
|
||||
AccessCommand(pathbuf, name, namelen,
|
||||
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf))) ||
|
||||
AccessCommand(strcpy(pathbuf, ""), name, namelen, 0) ||
|
||||
SearchPath(pathbuf, name, namelen)) {
|
||||
errno = olderr;
|
||||
return pathbuf;
|
||||
|
||||
@@ -47,11 +47,8 @@ textwindows int execve$nt(const char *program, char *const argv[],
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
for (i = 0; argv[i];) ++i;
|
||||
i = (i + 1) * sizeof(char *);
|
||||
argv = memcpy(alloca(i), argv, i);
|
||||
memcpy(argv, &program, sizeof(program));
|
||||
rc = ntspawn(argv, envp, NULL, NULL, true, 0, NULL, &startinfo, &procinfo);
|
||||
rc = ntspawn(program, argv, envp, NULL, NULL, true, 0, NULL, &startinfo,
|
||||
&procinfo);
|
||||
if (rc == -1) return -1;
|
||||
CloseHandle(procinfo.hThread);
|
||||
do {
|
||||
|
||||
@@ -25,15 +25,16 @@
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int execve$sysv(const char *prog, char *const argv[], char *const envp[]) {
|
||||
size_t i, n;
|
||||
char **shargs, bash[PATH_MAX];
|
||||
size_t i;
|
||||
char **shargs;
|
||||
if (__execve$sysv(prog, argv, envp) != -1) return 0;
|
||||
if (errno != ENOEXEC) return -1;
|
||||
for (i = 0; argv[i];) ++i;
|
||||
shargs = alloca((i + 2) * sizeof(char *));
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
shargs[0] = !IsFreebsd() ? _PATH_BSHELL
|
||||
: firstnonnull(commandv("bash", bash), _PATH_BSHELL);
|
||||
: firstnonnull(commandv("bash", alloca(PATH_MAX)),
|
||||
_PATH_BSHELL);
|
||||
shargs[1] = prog;
|
||||
return __execve$sysv(shargs[0], shargs, envp);
|
||||
}
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
int faccessat$nt(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (dirfd != AT_FDCWD || flags) return einval();
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
}
|
||||
@@ -25,12 +25,13 @@
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
*
|
||||
* @param dirfd is usually AT_FDCWD
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param path is a filename or directory
|
||||
* @param flags can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param flags should be 0
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
if (!path) return efault();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int fchdir$nt(int dirfd) {
|
||||
uint32_t len;
|
||||
char16_t dir[PATH_MAX];
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
len = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (len + 1 + 1 > ARRAYLEN(dir)) return enametoolong();
|
||||
if (dir[len - 1] != u'\\') {
|
||||
dir[len + 0] = u'\\';
|
||||
dir[len + 1] = u'\0';
|
||||
}
|
||||
if (SetCurrentDirectory(dir)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,18 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
textwindows int lstat$nt(const char *pathname, struct stat *st) {
|
||||
return stat$nt(pathname, st); /* todo(jart) */
|
||||
/**
|
||||
* Sets current directory based on file descriptor.
|
||||
*
|
||||
* @see open(path, O_DIRECTORY)
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fchdir(int dirfd) {
|
||||
if (!IsWindows()) {
|
||||
return fchdir$sysv(dirfd);
|
||||
} else {
|
||||
return fchdir$nt(dirfd);
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,8 @@
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int fchownat(int dirfd, const char *pathname, uint32_t uid, uint32_t gid,
|
||||
uint32_t flags) {
|
||||
/* TODO(jart): Windows? */
|
||||
return fchownat$sysv(dirfd, pathname, uid, gid, flags);
|
||||
}
|
||||
@@ -26,11 +26,12 @@
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
textwindows int stat$nt(const char *path, struct stat *st) {
|
||||
textwindows int fstatat$nt(int dirfd, const char *path, struct stat *st,
|
||||
uint32_t flags) {
|
||||
int rc;
|
||||
int64_t fh;
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(
|
||||
path16, kNtFileReadAttributes,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
|
||||
+15
-17
@@ -16,33 +16,31 @@
|
||||
│ 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/errno.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Performs stat() w/ features for threaded apps.
|
||||
* Returns information about thing.
|
||||
*
|
||||
* @param dirfd can be AT_FDCWD or an open directory descriptor, and is
|
||||
* ignored if pathname is absolute
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file becomes relative to dirfd
|
||||
* @param st is where result is stored
|
||||
* @param flags can have AT_{EMPTY_PATH,NO_AUTOMOUNT,SYMLINK_NOFOLLOW}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see S_ISDIR(st.st_mode), S_ISREG()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fstatat(int dirfd, const char *pathname, struct stat *st, uint32_t flags) {
|
||||
int olderr = errno;
|
||||
int rc = fstatat$sysv(dirfd, pathname, st, flags);
|
||||
if (rc != -1) {
|
||||
stat2linux(st);
|
||||
} else if (errno == ENOSYS && dirfd == AT_FDCWD) {
|
||||
if (!flags) {
|
||||
errno = olderr;
|
||||
rc = stat(pathname, st);
|
||||
} else if (flags == AT_SYMLINK_NOFOLLOW) {
|
||||
errno = olderr;
|
||||
rc = lstat(pathname, st);
|
||||
}
|
||||
int fstatat(int dirfd, const char *path, struct stat *st, uint32_t flags) {
|
||||
struct ZiposUri zipname;
|
||||
if (weaken(__zipos_stat) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
return weaken(__zipos_stat)(&zipname, st);
|
||||
} else if (!IsWindows()) {
|
||||
return fstatat$sysv(dirfd, path, st, flags);
|
||||
} else {
|
||||
return fstatat$nt(dirfd, path, st, flags);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -23,12 +23,12 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows char *getcwd$nt(char *buf, size_t size) {
|
||||
uint16_t name16[PATH_MAX + 1];
|
||||
uint16_t name16[PATH_MAX];
|
||||
if (GetCurrentDirectory(ARRAYLEN(name16), name16)) {
|
||||
tprecode16to8(buf, size, name16);
|
||||
return buf;
|
||||
} else {
|
||||
__winerr();
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define XNU_F_GETPATH 50
|
||||
#define XNU_MAXPATHLEN 1024
|
||||
|
||||
char *getcwd$xnu(char *res, size_t size) {
|
||||
int fd;
|
||||
struct stat st[2];
|
||||
char buf[XNU_MAXPATHLEN], *ret = NULL;
|
||||
if ((fd = openat$sysv(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY)) != -1) {
|
||||
if (fstat$sysv(fd, &st[0]) != -1) {
|
||||
if (st[0].st_dev && st[0].st_ino) {
|
||||
if (fcntl$sysv(fd, XNU_F_GETPATH, buf) != -1) {
|
||||
if (fstatat$sysv(AT_FDCWD, buf, &st[1], 0) != -1) {
|
||||
if (st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino) {
|
||||
if (memccpy(res, buf, '\0', size)) {
|
||||
ret = res;
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
+8
-22
@@ -19,8 +19,6 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns current working directory.
|
||||
@@ -34,28 +32,16 @@
|
||||
* @error ERANGE, EINVAL
|
||||
*/
|
||||
char *(getcwd)(char *buf, size_t size) {
|
||||
if (buf) {
|
||||
buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
int olderr = errno;
|
||||
if (getcwd$sysv(buf, size) != NULL) {
|
||||
return buf;
|
||||
} else if (IsXnu() && errno == ENOSYS) {
|
||||
if (size >= 2) {
|
||||
buf[0] = '.'; /* XXX: could put forth more effort */
|
||||
buf[1] = '\0';
|
||||
errno = olderr;
|
||||
return buf;
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
if (buf && size) buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
if (IsXnu()) {
|
||||
return getcwd$xnu(buf, size);
|
||||
} else if (getcwd$sysv(buf, size) != (void *)-1) {
|
||||
return buf;
|
||||
} else {
|
||||
return getcwd$nt(buf, size);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
efault();
|
||||
return NULL;
|
||||
return getcwd$nt(buf, size);
|
||||
}
|
||||
}
|
||||
@@ -73,16 +73,27 @@ struct dirent$bsd {
|
||||
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);
|
||||
if (name16[len - 1] == u'/' || name16[len - 1] == u'\\') {
|
||||
name16[--len] = u'\0';
|
||||
}
|
||||
name16[len++] = u'/';
|
||||
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;
|
||||
@@ -194,6 +205,7 @@ struct dirent *readdir(DIR *dir) {
|
||||
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 */
|
||||
@@ -202,10 +214,19 @@ struct dirent *readdir(DIR *dir) {
|
||||
dir->buf_pos = 0;
|
||||
dir->buf_end = rc;
|
||||
}
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
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;
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#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"
|
||||
@@ -119,6 +121,7 @@ textwindows void WinMainForked(void) {
|
||||
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;
|
||||
@@ -137,7 +140,8 @@ textwindows int fork$nt(void) {
|
||||
startinfo.hStdInput = g_fds.p[0].handle;
|
||||
startinfo.hStdOutput = g_fds.p[1].handle;
|
||||
startinfo.hStdError = g_fds.p[2].handle;
|
||||
if (ntspawn(g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL,
|
||||
GetModuleFileNameA(0, exe, ARRAYLEN(exe));
|
||||
if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL,
|
||||
&startinfo, &procinfo) != -1) {
|
||||
CloseHandle(reader);
|
||||
CloseHandle(procinfo.hThread);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
*/
|
||||
nodiscard char *get_current_dir_name(void) {
|
||||
char *buf, *res;
|
||||
if ((res = getenv("PWD"))) return strdup(res);
|
||||
if (!(buf = malloc(PATH_MAX))) return NULL;
|
||||
if (!(res = (getcwd)(buf, PATH_MAX))) free(buf);
|
||||
return res;
|
||||
|
||||
+12
-8
@@ -99,6 +99,7 @@ forceinline size_t clampio(size_t size) {
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
char *getcwd$sysv(char *, u64) hidden;
|
||||
char *getcwd$xnu(char *, u64) hidden;
|
||||
i32 __dup3$sysv(i32, i32, i32) hidden;
|
||||
i32 __execve$sysv(const char *, char *const[], char *const[]) hidden;
|
||||
i32 __fstat$sysv(i32, struct stat *) hidden;
|
||||
@@ -115,11 +116,12 @@ i32 execve$sysv(const char *, char *const[], char *const[]) hidden;
|
||||
i32 faccessat$sysv(i32, const char *, i32, u32) hidden;
|
||||
i32 fadvise$sysv(i32, i64, i64, i32) hidden;
|
||||
i32 fallocate$sysv(i64, i32, i64, i64) hidden;
|
||||
i32 fchdir$sysv(i32) hidden;
|
||||
i32 fchmod$sysv(i32, u32) hidden;
|
||||
i32 fchmodat$sysv(i32, const char *, u32, u32) hidden;
|
||||
i32 fchown$sysv(i64, u32, u32) hidden;
|
||||
i32 fchownat$sysv(i32, const char *, u32, u32, u32) hidden;
|
||||
i32 fcntl$sysv(i32, i32, i32) hidden;
|
||||
i32 fcntl$sysv(i32, i32, ...) hidden;
|
||||
i32 fdatasync$sysv(i32) hidden;
|
||||
i32 flock$sysv(i32, i32) hidden;
|
||||
i32 fork$sysv(void) hidden;
|
||||
@@ -150,7 +152,7 @@ i32 mprotect$sysv(void *, u64, i32) hidden;
|
||||
i32 msync$sysv(void *, u64, i32) hidden;
|
||||
i32 munmap$sysv(void *, u64) hidden;
|
||||
i32 nanosleep$sysv(const struct timespec *, struct timespec *) hidden;
|
||||
i32 openat$sysv(i32, const char *, i32, i32) hidden;
|
||||
i32 openat$sysv(i32, const char *, i32, ...) hidden;
|
||||
i32 pause$sysv(void) hidden;
|
||||
i32 pipe$sysv(i32[hasatleast 2]) hidden;
|
||||
i32 pipe2$sysv(i32[hasatleast 2], u32) hidden;
|
||||
@@ -230,11 +232,13 @@ int dup$nt(int, int, int) hidden;
|
||||
int execve$nt(const char *, char *const[], char *const[]) hidden;
|
||||
int faccessat$nt(int, const char *, int, uint32_t) hidden;
|
||||
int fadvise$nt(int, u64, u64, int) hidden;
|
||||
int fchdir$nt(int) hidden;
|
||||
int fcntl$nt(int, int, unsigned) hidden;
|
||||
int fdatasync$nt(int) hidden;
|
||||
int flock$nt(int, int) hidden;
|
||||
int fork$nt(void) hidden;
|
||||
int fstat$nt(i64, struct stat *) hidden;
|
||||
int fstatat$nt(int, const char *, struct stat *, uint32_t) hidden;
|
||||
int ftruncate$nt(int, u64) hidden;
|
||||
int getpriority$nt(int) hidden;
|
||||
int getrusage$nt(int, struct rusage *) hidden;
|
||||
@@ -243,22 +247,21 @@ int kill$nt(int, int) hidden;
|
||||
int link$nt(const char *, const char *) hidden;
|
||||
int lstat$nt(const char *, struct stat *) hidden;
|
||||
int madvise$nt(void *, size_t, int) hidden;
|
||||
int mkdirat$nt(int, const char *, uint32_t) hidden;
|
||||
int msync$nt(void *, size_t, int) hidden;
|
||||
int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
|
||||
int pipe$nt(int[hasatleast 2], unsigned) hidden;
|
||||
int rename$nt(const char *, const char *) hidden;
|
||||
int rmdir$nt(const char *) hidden;
|
||||
int renameat$nt(int, const char *, int, const char *) hidden;
|
||||
int sched_yield$nt(void) hidden;
|
||||
int setitimer$nt(int, const struct itimerval *, struct itimerval *) hidden;
|
||||
int setpriority$nt(int) hidden;
|
||||
int stat$nt(const char *, struct stat *) hidden;
|
||||
int symlink$nt(const char *, const char *) hidden;
|
||||
int symlinkat$nt(const char *, int, const char *) hidden;
|
||||
int sync$nt(void) hidden;
|
||||
int sysinfo$nt(struct sysinfo *) hidden;
|
||||
int truncate$nt(const char *, u64) hidden;
|
||||
int unlink$nt(const char *) hidden;
|
||||
int unlinkat$nt(int, const char *, int) hidden;
|
||||
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
|
||||
ssize_t open$nt(const char *, u32, i32) nodiscard hidden;
|
||||
ssize_t open$nt(int, const char *, u32, i32) nodiscard hidden;
|
||||
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
|
||||
@@ -278,6 +281,7 @@ int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
|
||||
int64_t __winerr(void) nocallback privileged;
|
||||
int __mkntpath(const char *, char16_t[hasatleast PATH_MAX - 16]) hidden;
|
||||
int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX - 16], int) hidden;
|
||||
int __mkntpathat(int, const char *, int, char16_t[PATH_MAX]) hidden;
|
||||
unsigned __wincrash$nt(struct NtExceptionPointers *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
||||
@@ -31,6 +31,5 @@
|
||||
* @see /etc/group for group ids
|
||||
*/
|
||||
int lchown(const char *pathname, uint32_t uid, uint32_t gid) {
|
||||
/* TODO(jart): Windows? */
|
||||
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
+1
-7
@@ -16,8 +16,6 @@
|
||||
│ 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/consts/at.h"
|
||||
|
||||
@@ -26,9 +24,5 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int lstat(const char *pathname, struct stat *st) {
|
||||
if (!IsWindows()) {
|
||||
return fstatat$sysv(AT_FDCWD, pathname, st, AT_SYMLINK_NOFOLLOW);
|
||||
} else {
|
||||
return lstat$nt(pathname, st);
|
||||
}
|
||||
return fstatat(AT_FDCWD, pathname, st, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
+9
-17
@@ -24,30 +24,22 @@
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows noinline int mkdir$nt(const char *path, uint32_t mode) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (CreateDirectory(path16, NULL)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates directory a.k.a. folder.
|
||||
*
|
||||
* mkdir o → 0
|
||||
* mkdir o/yo/yo/yo → -1 w/ ENOENT
|
||||
* if o/yo is file → -1 w/ ENOTDIR
|
||||
* if o/yo/yo/yo is dir → -1 w/ EEXIST
|
||||
* if o/yo/yo/yo is file → -1 w/ EEXIST
|
||||
*
|
||||
* @param path is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param mode can be, for example, 0755
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @error EEXIST, ENOTDIR, ENAMETOOLONG, EACCES
|
||||
* @asyncsignalsafe
|
||||
* @see makedirs()
|
||||
*/
|
||||
int mkdir(const char *path, uint32_t mode) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return mkdirat$sysv(AT_FDCWD, path, mode);
|
||||
} else {
|
||||
return mkdir$nt(path, mode);
|
||||
}
|
||||
int mkdir(const char *path, unsigned mode) {
|
||||
return mkdirat(AT_FDCWD, path, mode);
|
||||
}
|
||||
@@ -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/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static textwindows bool SubpathExistsThatsNotDirectory(char16_t *path) {
|
||||
char16_t *p;
|
||||
uint32_t attrs;
|
||||
while ((p = strrchr16(path, '\\'))) {
|
||||
*p = u'\0';
|
||||
if ((attrs = GetFileAttributes(path)) != -1u) {
|
||||
if (attrs & kNtFileAttributeDirectory) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
textwindows int mkdirat$nt(int dirfd, const char *path, uint32_t mode) {
|
||||
int e;
|
||||
char16_t *p, path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (CreateDirectory(path16, NULL)) return 0;
|
||||
e = GetLastError();
|
||||
/* WIN32 doesn't distinguish between ENOTDIR and ENOENT */
|
||||
if (e == ENOTDIR && !SubpathExistsThatsNotDirectory(path16)) e = ENOENT;
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
+17
-4
@@ -19,11 +19,24 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int mkdirat(int dirfd, const char *pathname, unsigned mode) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return mkdir(pathname, mode);
|
||||
/**
|
||||
* Creates directory a.k.a. folder.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* path is relative, then path becomes relative to dirfd
|
||||
* @param path is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param mode can be, for example, 0755
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @error EEXIST, ENOTDIR, ENAMETOOLONG, EACCES, ENOENT
|
||||
* @asyncsignalsafe
|
||||
* @see makedirs()
|
||||
*/
|
||||
int mkdirat(int dirfd, const char *path, unsigned mode) {
|
||||
if (!IsWindows()) {
|
||||
return mkdirat$sysv(dirfd, path, mode);
|
||||
} else {
|
||||
return mkdirat$sysv(dirfd, pathname, mode);
|
||||
return mkdirat$nt(dirfd, path, mode);
|
||||
}
|
||||
}
|
||||
@@ -30,24 +30,28 @@
|
||||
* GetDosArgv() or GetDosArgv(). This function does NOT escape
|
||||
* command interpreter syntax, e.g. $VAR (sh), %VAR% (cmd).
|
||||
*
|
||||
* @param cmdline is output buffer
|
||||
* @param prog is used as argv[0]
|
||||
* @param argv is an a NULL-terminated array of UTF-8 strings
|
||||
* @return freshly allocated lpCommandLine or NULL w/ errno
|
||||
* @kudos Daniel Colascione for teaching how to quote
|
||||
* @see libc/runtime/dosargv.c
|
||||
*/
|
||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], char *const argv[]) {
|
||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
char *arg;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
int slashes, n;
|
||||
size_t i, j, k;
|
||||
bool needsquote;
|
||||
char16_t cbuf[2];
|
||||
for (k = i = 0; argv[i]; ++i) {
|
||||
for (arg = prog, k = i = 0; arg; arg = argv[++i]) {
|
||||
if (i) {
|
||||
cmdline[k++] = u' ';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
}
|
||||
needsquote = !*argv[i] || argv[i][strcspn(argv[i], " \t\n\v\"")];
|
||||
needsquote = !arg[0] || arg[strcspn(arg, " \t\n\v\"")];
|
||||
if (needsquote) {
|
||||
cmdline[k++] = u'"';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
@@ -55,20 +59,20 @@ textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], char *const argv[]) {
|
||||
for (j = 0;;) {
|
||||
if (needsquote) {
|
||||
slashes = 0;
|
||||
while (argv[i][j] && argv[i][j] == '\\') slashes++, j++;
|
||||
while (arg[j] && arg[j] == '\\') slashes++, j++;
|
||||
slashes <<= 1;
|
||||
if (argv[i][j] == '"') slashes++;
|
||||
if (arg[j] == '"') slashes++;
|
||||
while (slashes--) {
|
||||
cmdline[k++] = u'\\';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
}
|
||||
}
|
||||
x = argv[i][j++] & 0xff;
|
||||
x = arg[j++] & 0xff;
|
||||
if (x >= 0300) {
|
||||
n = ThomPikeLen(x);
|
||||
x = ThomPikeByte(x);
|
||||
while (--n) {
|
||||
if ((y = argv[i][j++] & 0xff)) {
|
||||
if ((y = arg[j++] & 0xff)) {
|
||||
x = ThomPikeMerge(x, y);
|
||||
} else {
|
||||
x = 0;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*-*- 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/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int __mkntpathat(int dirfd, const char *path, int flags,
|
||||
char16_t file[PATH_MAX]) {
|
||||
char16_t dir[PATH_MAX];
|
||||
uint32_t dirlen, filelen;
|
||||
if ((filelen = __mkntpath2(path, file, flags)) == -1) return -1;
|
||||
if (file[0] != u'\\' && dirfd != AT_FDCWD) { /* ProTip: \\?\C:\foo */
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
dirlen = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (!dirlen) return __winerr();
|
||||
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong();
|
||||
dir[dirlen] = u'\\';
|
||||
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
|
||||
memcpy(file, dir, (dirlen + 1 + filelen + 1) * sizeof(char16_t));
|
||||
return dirlen + 1 + filelen;
|
||||
} else {
|
||||
return filelen;
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ struct SpawnBlock {
|
||||
* @see spawnve() which abstracts this function
|
||||
*/
|
||||
textwindows int ntspawn(
|
||||
char *const argv[], char *const envp[],
|
||||
const char *prog, char *const argv[], char *const envp[],
|
||||
struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
|
||||
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
|
||||
@@ -80,7 +80,7 @@ textwindows int ntspawn(
|
||||
(block =
|
||||
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
|
||||
blocksize, NULL, kNtNumaNoPreferredNode))) {
|
||||
if (mkntcmdline(block->cmdline, argv) != -1 &&
|
||||
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
|
||||
mkntenvblock(block->envvars, envp) != -1) {
|
||||
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int mkntcmdline(char16_t[ARG_MAX], char *const[]) hidden;
|
||||
int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden;
|
||||
int mkntenvblock(char16_t[ARG_MAX], char *const[]) hidden;
|
||||
int ntspawn(char *const[], char *const[], struct NtSecurityAttributes *,
|
||||
struct NtSecurityAttributes *, bool32, uint32_t, const char16_t *,
|
||||
const struct NtStartupInfo *, struct NtProcessInformation *) hidden;
|
||||
int ntspawn(const char *, char *const[], char *const[],
|
||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
||||
struct NtProcessInformation *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -48,13 +48,10 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
||||
}
|
||||
switch ((rva = __sighandrvas[sig])) {
|
||||
case (uintptr_t)SIG_DFL:
|
||||
dprintf(2, "__onntconsoleevent ExitProcess\n");
|
||||
ExitProcess(128 + sig);
|
||||
case (uintptr_t)SIG_IGN:
|
||||
dprintf(2, "__onntconsoleevent SIG_IGN\n");
|
||||
return true;
|
||||
default:
|
||||
dprintf(2, "__onntconsoleevent %#x\n", rva);
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
((sigaction_f)(_base + rva))(sig, &info, NULL);
|
||||
|
||||
+29
-22
@@ -30,18 +30,19 @@
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
|
||||
int32_t mode) {
|
||||
static textwindows int64_t open$nt$impl(int dirfd, const char *path,
|
||||
uint32_t flags, int32_t mode) {
|
||||
uint32_t br;
|
||||
int64_t handle;
|
||||
char16_t file16[PATH_MAX];
|
||||
if (__mkntpath2(file, file16, flags) == -1) return -1;
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
|
||||
if ((handle = CreateFile(
|
||||
file16,
|
||||
path16,
|
||||
(flags & 0xf000000f) |
|
||||
(/* this is needed if we mmap(rwx+cow)
|
||||
nt is choosy about open() access */
|
||||
@@ -82,11 +83,18 @@ static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
|
||||
*/
|
||||
DeviceIoControl(handle, kNtFsctlSetSparse, NULL, 0, NULL, 0, &br, NULL);
|
||||
}
|
||||
return handle;
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & O_CREAT) &&
|
||||
(flags & O_TRUNC))) { /* TODO(jart): What was this? */
|
||||
return eisdir();
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static textwindows ssize_t open$nt$console(const struct NtMagicPaths *mp,
|
||||
static textwindows ssize_t open$nt$console(int dirfd,
|
||||
const struct NtMagicPaths *mp,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar &&
|
||||
@@ -94,39 +102,38 @@ static textwindows ssize_t open$nt$console(const struct NtMagicPaths *mp,
|
||||
g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle;
|
||||
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
|
||||
} else if ((g_fds.p[fd].handle = open$nt$impl(
|
||||
mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode)) != -1) {
|
||||
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode)) !=
|
||||
-1) {
|
||||
g_fds.p[fd].extra =
|
||||
open$nt$impl(mp->conout, (flags & ~O_ACCMODE) | O_WRONLY, mode);
|
||||
open$nt$impl(dirfd, mp->conout, (flags & ~O_ACCMODE) | O_WRONLY, mode);
|
||||
assert(g_fds.p[fd].extra != -1);
|
||||
} else {
|
||||
return __winerr();
|
||||
return -1;
|
||||
}
|
||||
g_fds.p[fd].kind = kFdConsole;
|
||||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static textwindows ssize_t open$nt$file(const char *file, uint32_t flags,
|
||||
int32_t mode, size_t fd) {
|
||||
if ((g_fds.p[fd].handle = open$nt$impl(file, flags, mode)) != -1) {
|
||||
static textwindows ssize_t open$nt$file(int dirfd, const char *file,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
if ((g_fds.p[fd].handle = open$nt$impl(dirfd, file, flags, mode)) != -1) {
|
||||
g_fds.p[fd].kind = kFdFile;
|
||||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & O_CREAT) && (flags & O_TRUNC))) {
|
||||
return eisdir();
|
||||
} else {
|
||||
return __winerr();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
textwindows ssize_t open$nt(const char *file, uint32_t flags, int32_t mode) {
|
||||
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;
|
||||
if ((flags & O_ACCMODE) == O_RDWR &&
|
||||
strcmp(file, kNtMagicPaths.devtty) == 0) {
|
||||
return open$nt$console(&kNtMagicPaths, flags, mode, fd);
|
||||
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
|
||||
return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||
} else {
|
||||
return open$nt$file(file, flags, mode, fd);
|
||||
return open$nt$file(dirfd, file, flags, mode, fd);
|
||||
}
|
||||
}
|
||||
+1
-16
@@ -16,14 +16,8 @@
|
||||
│ 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/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Opens file.
|
||||
@@ -34,23 +28,14 @@
|
||||
* @param mode is an octal user/group/other permission signifier, that's
|
||||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @note don't call open() from signal handlers
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int open(const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
struct ZiposUri zipname;
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
if (!file) return efault();
|
||||
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else if (!IsWindows()) {
|
||||
return openat$sysv(AT_FDCWD, file, flags, mode);
|
||||
} else {
|
||||
return open$nt(file, flags, mode);
|
||||
}
|
||||
return openat(AT_FDCWD, file, flags, mode);
|
||||
}
|
||||
+19
-7
@@ -16,15 +16,20 @@
|
||||
│ 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/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Opens file, the modern way.
|
||||
* Opens file.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD or an open relative directory thing
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param file is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
|
||||
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
|
||||
@@ -33,16 +38,23 @@
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int openat(int dirfd, const char *pathname, int flags, ...) {
|
||||
nodiscard int openat(int dirfd, const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
struct ZiposUri zipname;
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
if (!pathname) return efault();
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return open(pathname, flags, mode);
|
||||
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 */
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
return openat$sysv(dirfd, file, flags, mode);
|
||||
} else {
|
||||
return openat$sysv(dirfd, pathname, flags, mode);
|
||||
return open$nt(dirfd, file, flags, mode);
|
||||
}
|
||||
}
|
||||
+1
-9
@@ -17,10 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Moves file the Unix way.
|
||||
@@ -29,10 +26,5 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int rename(const char *oldpathname, const char *newpathname) {
|
||||
if (!oldpathname || !newpathname) return efault();
|
||||
if (!IsWindows()) {
|
||||
return renameat$sysv(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
|
||||
} else {
|
||||
return rename$nt(oldpathname, newpathname);
|
||||
}
|
||||
return renameat(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
|
||||
}
|
||||
@@ -23,11 +23,12 @@
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int rename$nt(const char *oldpath, const char *newpath) {
|
||||
textwindows int renameat$nt(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
char16_t oldpath16[PATH_MAX];
|
||||
char16_t newpath16[PATH_MAX];
|
||||
if (__mkntpath(oldpath, oldpath16) == -1 ||
|
||||
__mkntpath(newpath, newpath16) == -1) {
|
||||
if (__mkntpathat(olddirfd, oldpath, 0, oldpath16) == -1 ||
|
||||
__mkntpathat(newdirfd, newpath, 0, newpath16) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (MoveFileEx(oldpath16, newpath16, kNtMovefileReplaceExisting)) {
|
||||
+11
-4
@@ -19,16 +19,23 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Renames files relative to directories.
|
||||
*
|
||||
* @param olddirfd is normally AT_FDCWD but if it's an open directory
|
||||
* and oldpath is relative, then oldpath become relative to dirfd
|
||||
* @param newdirfd is normally AT_FDCWD but if it's an open directory
|
||||
* and newpath is relative, then newpath become relative to dirfd
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int renameat(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
unsigned mode;
|
||||
if (olddirfd == AT_FDCWD && newdirfd == AT_FDCWD) {
|
||||
return rename(oldpath, newpath);
|
||||
} else {
|
||||
if (!oldpath || !newpath) return efault();
|
||||
if (!IsWindows()) {
|
||||
return renameat$sysv(olddirfd, oldpath, newdirfd, newpath);
|
||||
} else {
|
||||
return renameat$nt(olddirfd, oldpath, newdirfd, newpath);
|
||||
}
|
||||
}
|
||||
+2
-11
@@ -16,11 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
@@ -29,10 +25,5 @@
|
||||
* @return 0 on success or -1 w/ errno on error
|
||||
*/
|
||||
int rmdir(const char *path) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(AT_FDCWD, path, AT_REMOVEDIR);
|
||||
} else {
|
||||
return rmdir$nt(path);
|
||||
}
|
||||
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_SCHED_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_SCHED_H_
|
||||
#include "libc/calls/struct/sched_param.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int sched_setscheduler(int, int, const struct sched_param *);
|
||||
int sched_getscheduler(int);
|
||||
int sched_setparam(int, const struct sched_param *);
|
||||
int sched_getparam(int, struct sched_param *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_SCHED_H_ */
|
||||
+3
-16
@@ -16,29 +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/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Returns information about thing.
|
||||
*
|
||||
* @param st is where result is stored
|
||||
* @see S_ISDIR(st.st_mode), S_ISREG(), etc.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int stat(const char *pathname, struct stat *st) {
|
||||
struct ZiposUri zipname;
|
||||
if (weaken(__zipos_stat) &&
|
||||
weaken(__zipos_parseuri)(pathname, &zipname) != -1) {
|
||||
return weaken(__zipos_stat)(&zipname, st);
|
||||
} else if (!IsWindows()) {
|
||||
return fstatat$sysv(AT_FDCWD, pathname, st, 0);
|
||||
} else {
|
||||
return stat$nt(pathname, st);
|
||||
}
|
||||
int stat(const char *path, struct stat *st) {
|
||||
return fstatat(AT_FDCWD, path, st, 0);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_DIRENT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct dirent { /* openbsd and linux getdents64 abi */
|
||||
struct dirent { /* linux getdents64 abi */
|
||||
uint64_t d_ino; /* inode number */
|
||||
int64_t d_off; /* implementation-dependent location number */
|
||||
uint16_t d_reclen; /* byte length of this whole struct and string */
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Creates symbolic link.
|
||||
@@ -36,10 +33,5 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int symlink(const char *target, const char *linkpath) {
|
||||
if (!target || !linkpath) return efault();
|
||||
if (!IsWindows()) {
|
||||
return symlinkat$sysv(target, AT_FDCWD, linkpath);
|
||||
} else {
|
||||
return symlink$nt(target, linkpath);
|
||||
}
|
||||
return symlinkat(target, AT_FDCWD, linkpath);
|
||||
}
|
||||
@@ -20,10 +20,13 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
||||
textwindows int symlink$nt(const char *target, const char *linkpath) {
|
||||
char16_t linkpath16[PATH_MAX], target16[PATH_MAX];
|
||||
uint32_t flags = isdirectory(target) ? kNtSymbolicLinkFlagDirectory : 0;
|
||||
if (__mkntpath(linkpath, linkpath16) == -1) return -1;
|
||||
textwindows int symlinkat$nt(const char *target, int newdirfd,
|
||||
const char *linkpath) {
|
||||
uint32_t flags;
|
||||
char16_t target16[PATH_MAX];
|
||||
char16_t linkpath16[PATH_MAX];
|
||||
flags = isdirectory(target) ? kNtSymbolicLinkFlagDirectory : 0;
|
||||
if (__mkntpathat(newdirfd, linkpath, 0, linkpath16) == -1) return -1;
|
||||
if (__mkntpath(target, target16) == -1) return -1;
|
||||
if (CreateSymbolicLink(linkpath16, target16, flags)) {
|
||||
return 0;
|
||||
@@ -0,0 +1,43 @@
|
||||
/*-*- 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/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Creates symbolic link.
|
||||
*
|
||||
* This is like link() but adds a tiny indirection to make the fact that
|
||||
* the file is a link obvious. It also enables certain other features,
|
||||
* like the ability to be broken.
|
||||
*
|
||||
* @param target can be relative and needn't exist
|
||||
* @param linkpath is what gets created
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @note Windows NT only lets admins do this
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int symlinkat(const char *target, int newdirfd, const char *linkpath) {
|
||||
if (!IsWindows()) {
|
||||
return symlinkat$sysv(target, newdirfd, linkpath);
|
||||
} else {
|
||||
return symlinkat$nt(target, newdirfd, linkpath);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,5 @@
|
||||
int touch(const char *file, uint32_t mode) {
|
||||
int fd;
|
||||
if ((fd = open(file, O_CREAT | O_WRONLY, mode)) == -1) return -1;
|
||||
fsync(fd); /* TODO(jart): do we need it? */
|
||||
return close(fd);
|
||||
}
|
||||
+2
-11
@@ -16,12 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Deletes file.
|
||||
@@ -35,10 +31,5 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int unlink(const char *name) {
|
||||
if (!name) return efault();
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(AT_FDCWD, name, 0);
|
||||
} else {
|
||||
return unlink$nt(name);
|
||||
}
|
||||
return unlinkat(AT_FDCWD, name, 0);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*-*- 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/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
static textwindows int unlink$nt(const char16_t *path) {
|
||||
if (DeleteFile(path)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows int rmdir$nt(const char16_t *path) {
|
||||
int e, ms;
|
||||
for (ms = 1;; ms *= 2) {
|
||||
if (RemoveDirectory(path)) return 0;
|
||||
/*
|
||||
* Files can linger, for absolutely no reason.
|
||||
* Possibly some Windows Defender bug on Win7.
|
||||
* Sleep for up to one second w/ expo backoff.
|
||||
* Alternative is use Microsoft internal APIs.
|
||||
* Never could have imagined it'd be this bad.
|
||||
*/
|
||||
if ((e = GetLastError()) == kNtErrorDirNotEmpty && ms <= 512) {
|
||||
Sleep(ms);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
textwindows int unlinkat$nt(int dirfd, const char *path, int flags) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (flags & AT_REMOVEDIR) {
|
||||
return rmdir$nt(path16);
|
||||
} else {
|
||||
return unlink$nt(path16);
|
||||
}
|
||||
}
|
||||
+14
-4
@@ -18,12 +18,22 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
int unlinkat(int dirfd, const char *pathname, int flags) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return unlink(pathname);
|
||||
/**
|
||||
* Deletes inode and maybe the file too.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* path is relative, then path becomes relative to dirfd
|
||||
* @param path is the thing to delete
|
||||
* @param flags can have AT_REMOVEDIR
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int unlinkat(int dirfd, const char *path, int flags) {
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(dirfd, path, flags);
|
||||
} else {
|
||||
return unlinkat$sysv(dirfd, pathname, flags);
|
||||
return unlinkat$nt(dirfd, path, flags);
|
||||
}
|
||||
}
|
||||
@@ -35,25 +35,12 @@ textwindows int utimensat$nt(int dirfd, const char *path,
|
||||
const struct timespec ts[2], int flags) {
|
||||
int i, rc;
|
||||
int64_t fh;
|
||||
bool closeme;
|
||||
uint16_t path16[PATH_MAX];
|
||||
struct NtFileTime ft[2], *ftp[2];
|
||||
if (flags) return einval();
|
||||
if (path) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead,
|
||||
NULL, kNtOpenExisting, kNtFileAttributeNormal, 0)) !=
|
||||
-1) {
|
||||
closeme = true;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0)) == -1) {
|
||||
return __winerr();
|
||||
}
|
||||
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||
GetSystemTimeAsFileTime(ft);
|
||||
@@ -78,8 +65,6 @@ textwindows int utimensat$nt(int dirfd, const char *path,
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
if (closeme) {
|
||||
CloseHandle(fh);
|
||||
}
|
||||
CloseHandle(fh);
|
||||
return rc;
|
||||
}
|
||||
@@ -46,6 +46,8 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||
const struct StackFrame *frame;
|
||||
const char *debugbin, *p1, *p2, *p3, *addr2line;
|
||||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||
if (IsOpenbsd()) return -1;
|
||||
if (IsWindows()) return -1;
|
||||
if (!(debugbin = FindDebugBinary()) || !(addr2line = GetAddr2linePath())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ int64_t LoadLibraryEx(const char16_t *lpLibFileName, int64_t hFile,
|
||||
uint32_t dwFlags);
|
||||
uint32_t GetModuleFileName(int64_t hModule, char16_t *lpFilename,
|
||||
uint32_t nSize);
|
||||
uint32_t GetModuleFileNameA(int64_t hModule, char *lpFilename, uint32_t nSize);
|
||||
intptr_t GetModuleHandle(const char *opt_lpModuleName);
|
||||
intptr_t GetModuleHandleW(const char16_t *opt_lpModuleName);
|
||||
void *GetProcAddress(int64_t hModule, const char *lpProcName);
|
||||
|
||||
@@ -199,6 +199,15 @@ bool32 WriteFileGather(int64_t hFileOpenedWithOverlappedAndNoBuffering,
|
||||
uint32_t nNumberOfBytesToWrite, uint32_t *lpReserved,
|
||||
struct NtOverlapped inout_lpOverlapped) paramsnonnull();
|
||||
|
||||
#define kNtFileNameNormalized 0x0
|
||||
#define kNtFileNameOpened 0x8
|
||||
#define kNtVolumeNameDos 0x0 /* e.g. \\?\C:\Users\jart */
|
||||
#define kNtVolumeNameGuid 0x1 /* e.g. \\?\Volume{ea38-etc.}\Users\jart */
|
||||
#define kNtVolumeNameNt 0x2 /* e.g. \Device\HarddiskVolume4\Users\jart */
|
||||
#define kNtVolumeNameNone 0x4 /* e.g. \Users\jart */
|
||||
uint32_t GetFinalPathNameByHandle(int64_t hFile, char16_t *out_path,
|
||||
uint32_t arraylen, uint32_t flags);
|
||||
|
||||
#if ShouldUseMsabiAttribute()
|
||||
#include "libc/nt/thunk/files.inc"
|
||||
#endif /* ShouldUseMsabiAttribute() */
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_GetFinalPathNameByHandleA,GetFinalPathNameByHandleA,0
|
||||
|
||||
.text.windows
|
||||
GetFinalPathNameByHandleA:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
mov __imp_GetFinalPathNameByHandleA(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
.endfn GetFinalPathNameByHandleA,globl
|
||||
.previous
|
||||
@@ -1,2 +1,12 @@
|
||||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_GetFinalPathNameByHandleW,GetFinalPathNameByHandleW,0
|
||||
|
||||
.text.windows
|
||||
GetFinalPathNameByHandle:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
mov __imp_GetFinalPathNameByHandleW(%rip),%rax
|
||||
jmp __sysv2nt
|
||||
.endfn GetFinalPathNameByHandle,globl
|
||||
.previous
|
||||
+2
-2
@@ -2176,8 +2176,8 @@ imp 'GetFileVersionInfoSizeExA' GetFileVersionInfoSizeExA KernelBase 561
|
||||
imp 'GetFileVersionInfoSizeEx' GetFileVersionInfoSizeExW KernelBase 562
|
||||
imp 'GetFileVersionInfoSize' GetFileVersionInfoSizeW KernelBase 563
|
||||
imp 'GetFileVersionInfo' GetFileVersionInfoW KernelBase 564
|
||||
imp 'GetFinalPathNameByHandleA' GetFinalPathNameByHandleA kernel32 0 # KernelBase
|
||||
imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 0 # KernelBase
|
||||
imp 'GetFinalPathNameByHandleA' GetFinalPathNameByHandleA kernel32 0 4 # KernelBase
|
||||
imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 0 4 # KernelBase
|
||||
imp 'GetFirmwareEnvironmentVariableA' GetFirmwareEnvironmentVariableA kernel32 597
|
||||
imp 'GetFirmwareEnvironmentVariableExA' GetFirmwareEnvironmentVariableExA kernel32 598
|
||||
imp 'GetFirmwareEnvironmentVariableEx' GetFirmwareEnvironmentVariableExW kernel32 599
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.h"
|
||||
@@ -31,19 +32,31 @@
|
||||
* @return path to debug binary, or -1 w/ errno
|
||||
*/
|
||||
const char *FindDebugBinary(void) {
|
||||
static char buf[PATH_MAX];
|
||||
if (buf[0]) return &buf[0];
|
||||
const char *const trybins[] = {program_invocation_name,
|
||||
(const char *)getauxval(AT_EXECFN)};
|
||||
for (unsigned i = 0; i < ARRAYLEN(trybins); ++i) {
|
||||
const char *res = trybins[i];
|
||||
unsigned len = strlen(res);
|
||||
if (4 < len && len < sizeof(buf) - 5) {
|
||||
if (strcmp(res + len - 4, ".dbg") == 0) return res;
|
||||
/* try suffixing extension, e.g. .com → .com.dbg */
|
||||
memcpy(mempcpy(buf, res, len), ".dbg", 5);
|
||||
if (fileexists(buf)) return &buf[0];
|
||||
buf[0] = '\0';
|
||||
unsigned i, len;
|
||||
char buf[2][PATH_MAX];
|
||||
static char res[PATH_MAX];
|
||||
const char *bins[4], *pwd;
|
||||
bins[0] = program_invocation_name;
|
||||
bins[1] = (const char *)getauxval(AT_EXECFN);
|
||||
pwd = emptytonull(getenv("PWD"));
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (pwd && bins[i] && bins[i][0] != '/' && bins[i][0] != '\\' &&
|
||||
strlen(pwd) + 1 + strlen(bins[i]) + 1 <= ARRAYLEN(buf[0])) {
|
||||
strcpy(buf[i], pwd);
|
||||
strcat(buf[i], "/");
|
||||
strcat(buf[i], bins[i]);
|
||||
bins[i + 2] = buf[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (!bins[i]) continue;
|
||||
len = strlen(bins[i]);
|
||||
memcpy(res, bins[i], len + 1);
|
||||
if (!endswith(res, ".dbg") && len + 3 + 1 <= ARRAYLEN(res)) {
|
||||
strcat(res, ".dbg");
|
||||
}
|
||||
if (fileexists(res)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
errno = ENOENT;
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
* TODO: How can we ensure we never overlap with KERNEL32.DLL?
|
||||
*/
|
||||
|
||||
#define WINSTACK 0x100000
|
||||
|
||||
struct WinArgs {
|
||||
char *argv[4096];
|
||||
char *envp[4096];
|
||||
@@ -107,7 +109,7 @@ static textwindows wontreturn void WinMainNew(void) {
|
||||
NormalizeCmdExe();
|
||||
*(/*unconst*/ int *)&__hostos = WINDOWS;
|
||||
addr = NtGetVersion() < kNtVersionWindows10 ? 0xff00000 : 0x777000000000;
|
||||
size = ROUNDUP(STACKSIZE + sizeof(struct WinArgs), FRAMESIZE);
|
||||
size = ROUNDUP(WINSTACK + sizeof(struct WinArgs), FRAMESIZE);
|
||||
_mmi.p[0].h =
|
||||
__mmap$nt((char *)addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, -1, 0)
|
||||
.maphandle;
|
||||
@@ -128,7 +130,7 @@ static textwindows wontreturn void WinMainNew(void) {
|
||||
FreeEnvironmentStrings(env16);
|
||||
auxv[0][0] = pushpop(0L);
|
||||
auxv[0][1] = pushpop(0L);
|
||||
_jmpstack((char *)addr + STACKSIZE, _executive, count, wa->argv, wa->envp,
|
||||
_jmpstack((char *)addr + WINSTACK, _executive, count, wa->argv, wa->envp,
|
||||
auxv);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ int putchar(int);
|
||||
int puts(const char *) paramsnonnull();
|
||||
ssize_t getline(char **, size_t *, FILE *) paramsnonnull();
|
||||
ssize_t getdelim(char **, size_t *, int, FILE *) paramsnonnull();
|
||||
int fputhex(int, FILE *) paramsnonnull();
|
||||
int fgethex(FILE *) paramsnonnull();
|
||||
FILE *fopen(const char *, const char *) paramsnonnull() nodiscard;
|
||||
FILE *fdopen(int, const char *) paramsnonnull() nodiscard;
|
||||
FILE *fmemopen(void *, size_t, const char *) paramsnonnull((3)) nodiscard;
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
* This API was thought to be nearly extinct until recent versions
|
||||
* of Clang (c. 2019) started generating synthetic calls to it.
|
||||
*
|
||||
* @return unsigned char subtraction at stop index
|
||||
* @return 0 if a and b have equal contents, otherwise non-zero
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int bcmp(const void *a, const void *b, size_t n) {
|
||||
|
||||
@@ -151,10 +151,13 @@ int strcasecmpzbw(const uint16_t *, const char *) strlenesque;
|
||||
char *stpcpy(char *, const char *) memcpyesque;
|
||||
char *stpncpy(char *, const char *, size_t) memcpyesque;
|
||||
char *strcat(char *, const char *) memcpyesque;
|
||||
char16_t *strcat16(char16_t *, const char16_t *) memcpyesque;
|
||||
wchar_t *wcscat(wchar_t *, const wchar_t *) memcpyesque;
|
||||
size_t strlcpy(char *, const char *, size_t);
|
||||
size_t strlcat(char *, const char *, size_t);
|
||||
char *strcpy(char *, const char *) memcpyesque;
|
||||
char16_t *strcpy16(char16_t *, const char16_t *) memcpyesque;
|
||||
wchar_t *wcscpy(wchar_t *, const wchar_t *) memcpyesque;
|
||||
char *strncat(char *, const char *, size_t) memcpyesque;
|
||||
char *strncpy(char *, const char *, size_t) memcpyesque;
|
||||
char *strtok(char *, const char *) paramsnonnull((2)) libcesque;
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int unlink$nt(const char *name) {
|
||||
uint16_t name16[PATH_MAX];
|
||||
if (__mkntpath(name, name16) == -1) return -1;
|
||||
if (DeleteFile(name16)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
/**
|
||||
* Appends 𝑠 to 𝑑.
|
||||
*
|
||||
* @param 𝑑 is a NUL-terminated 16-bit string buffer
|
||||
* @param 𝑠 is a NUL-terminated 16-bit string
|
||||
* @return 𝑑
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
char16_t *strcat16(char16_t *d, const char16_t *s) {
|
||||
return strcpy16(d + strlen16(d), s);
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pcmpeqb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -28,5 +28,5 @@
|
||||
* @return original dest
|
||||
*/
|
||||
char16_t *strcpy16(char16_t *dest, const char16_t *src) {
|
||||
return memcpy(dest, src, (strlen16(src) + 1) << 1);
|
||||
return memcpy(dest, src, (strlen16(src) + 1) * sizeof(char16_t));
|
||||
}
|
||||
@@ -16,11 +16,16 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int fputhex(int c, FILE *f) {
|
||||
return (fputc("0123456789ABCDEF"[(c / 16) & 0xF], f) >= 0 &&
|
||||
fputc("0123456789ABCDEF"[(c % 16) & 0xF], f) >= 0)
|
||||
? c
|
||||
: -1;
|
||||
/**
|
||||
* Appends 𝑠 to 𝑑.
|
||||
*
|
||||
* @param 𝑑 is a NUL-terminated 32-bit string
|
||||
* @param 𝑠 is a NUL-terminated 32-bit string
|
||||
* @return 𝑑
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
wchar_t *wcscat(wchar_t *d, const wchar_t *s) {
|
||||
return wcscpy(d + wcslen(d), s);
|
||||
}
|
||||
@@ -16,16 +16,18 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int rmdir$nt(const char *path) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (RemoveDirectory(path16)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
/**
|
||||
* Copies NUL-terminated wide character string.
|
||||
*
|
||||
* 𝑑 and 𝑠 must not overlap unless 𝑑 ≤ 𝑠.
|
||||
*
|
||||
* @param 𝑑 is destination memory
|
||||
* @param 𝑠 is a NUL-terminated string
|
||||
* @return original dest
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
wchar_t *wcscpy(wchar_t *d, const wchar_t *s) {
|
||||
return memcpy(d, s, (wcslen(s) + 1) * sizeof(wchar_t));
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall fchdir$sysv 0x000d000d200d0051 globl hidden
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall fchdir 0x000d000d200d0051 globl
|
||||
@@ -1,2 +1,2 @@
|
||||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall mknodat 0x014022ffffff0103 globl
|
||||
.scall mknodat 0x0140022fffff0103 globl
|
||||
@@ -0,0 +1,2 @@
|
||||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall posix_spawn$sysv 0xffffffff20f4ffff globl hidden
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall posix_spawn 0xffffffff20f4ffff globl hidden
|
||||
+3
-15
@@ -25,7 +25,7 @@ dir=libc/sysv/consts
|
||||
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
|
||||
syscon errno ENOSYS 38 78 78 78 1 # bsd consensus & kNtErrorInvalidFunction
|
||||
syscon errno EPERM 1 1 1 1 12 # unix consensus & kNtErrorInvalidAccess (should be kNtErrorNotOwner but is that mutex only??)
|
||||
syscon errno ENOENT 2 2 2 2 2 # unix consensus & kNtErrorFileNot_FOUND
|
||||
syscon errno ENOENT 2 2 2 2 2 # unix consensus & kNtErrorFileNotFound
|
||||
syscon errno ESRCH 3 3 3 3 566 # "no such process" & kNtErrorThreadNotInProcess (cf. kNtErrorInvalidHandle)
|
||||
syscon errno EINTR 4 4 4 4 10004 # unix consensus & WSAEINTR
|
||||
syscon errno EIO 5 5 5 5 1117 # unix consensus & kNtErrorIoDevice
|
||||
@@ -44,7 +44,7 @@ syscon errno EBUSY 16 16 16 16 170 # unix consensus & kNtErrorBusy
|
||||
syscon errno EEXIST 17 17 17 17 183 # unix consensus & kNtErrorAlreadyExists (should be kNtErrorFileExists too)
|
||||
syscon errno EXDEV 18 18 18 18 17 # unix consensus & kNtErrorNotSameDevice
|
||||
syscon errno ENODEV 19 19 19 19 1200 # unix consensus & kNtErrorBadDevice
|
||||
syscon errno ENOTDIR 20 20 20 20 3 # unix consensus & kNtErrorPathNotFound (TODO)
|
||||
syscon errno ENOTDIR 20 20 20 20 3 # unix consensus & kNtErrorPathNotFound
|
||||
syscon errno EISDIR 21 21 21 21 267 # unix consensus & kNtErrorDirectoryNotSupported
|
||||
syscon errno EINVAL 22 22 22 22 87 # unix consensus & kNtErrorInvalidParameter
|
||||
syscon errno ENFILE 23 23 23 23 331 # unix consensus & kNtErrorTooManyDescriptors
|
||||
@@ -63,7 +63,7 @@ syscon errno ERANGE 34 34 34 34 -1 # bsd consensus
|
||||
syscon errno EDEADLK 35 11 11 11 1131 # bsd consensus & kNtErrorPossibleDeadlock
|
||||
syscon errno ENAMETOOLONG 36 63 63 63 0x274f # bsd consensus & WSAENAMETOOLONG
|
||||
syscon errno ENOLCK 37 77 77 77 -1 # bsd consensus
|
||||
syscon errno ENOTEMPTY 39 66 66 66 0x2752 # bsd consensus & WSAENOTEMPTY
|
||||
syscon errno ENOTEMPTY 39 66 66 66 145 # bsd consensus & kNtErrorDirNotEmpty (TODO: What is WSAENOTEMPTY? 0x2752)
|
||||
syscon errno ELOOP 40 62 62 62 0x274e # bsd consensus & WSAELOOP
|
||||
syscon errno ENOMSG 42 91 83 90 -1
|
||||
syscon errno EIDRM 43 90 82 89 -1
|
||||
@@ -280,18 +280,6 @@ syscon madv MADV_HWPOISON 100 0 0 0 0 # TODO(jart): what is it?
|
||||
syscon madv MADV_REMOVE 9 0 0 0 0 # TODO(jart): what is it?
|
||||
syscon fadv POSIX_FADV_NOREUSE 5 0 5 0 0 # wut
|
||||
|
||||
# posix_spawn()
|
||||
# only native on xnu
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
|
||||
syscon spawn POSIX_SPAWN_RESETIDS 1 1 1 1 0 # unix consensus
|
||||
syscon spawn POSIX_SPAWN_SETPGROUP 2 2 2 2 0 # unix consensus
|
||||
syscon spawn POSIX_SPAWN_SETSIGDEF 4 4 0x10 0x10 0
|
||||
syscon spawn POSIX_SPAWN_SETSIGMASK 8 8 0x20 0x20 0
|
||||
syscon spawn POSIX_SPAWN_SETSCHEDPARAM 0x10 0 4 4 0
|
||||
syscon spawn POSIX_SPAWN_SETSCHEDULER 0x20 0 8 8 0
|
||||
syscon spawn POSIX_SPAWN_USEVFORK 0x40 0 0 0 0
|
||||
|
||||
# mmap(), mprotect(), etc.
|
||||
# digital restrictions management for the people
|
||||
#
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon errno ENOTEMPTY 39 66 66 66 0x2752
|
||||
.syscon errno ENOTEMPTY 39 66 66 66 145
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_RESETIDS 1 1 1 1 0
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_SETPGROUP 2 2 2 2 0
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_SETSCHEDPARAM 0x10 0 4 4 0
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_SETSCHEDULER 0x20 0 8 8 0
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_SETSIGDEF 4 4 0x10 0x10 0
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_SETSIGMASK 8 8 0x20 0x20 0
|
||||
@@ -1,2 +0,0 @@
|
||||
.include "libc/sysv/consts/syscon.inc"
|
||||
.syscon spawn POSIX_SPAWN_USEVFORK 0x40 0 0 0 0
|
||||
+13
-27
@@ -1,26 +1,6 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_POSIX_H_
|
||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_POSIX_H_
|
||||
#include "libc/runtime/symbolic.h"
|
||||
|
||||
#define POSIX_FADV_DONTNEED SYMBOLIC(POSIX_FADV_DONTNEED)
|
||||
#define POSIX_FADV_NOREUSE SYMBOLIC(POSIX_FADV_NOREUSE)
|
||||
#define POSIX_FADV_NORMAL SYMBOLIC(POSIX_FADV_NORMAL)
|
||||
#define POSIX_FADV_RANDOM SYMBOLIC(POSIX_FADV_RANDOM)
|
||||
#define POSIX_FADV_SEQUENTIAL SYMBOLIC(POSIX_FADV_SEQUENTIAL)
|
||||
#define POSIX_FADV_WILLNEED SYMBOLIC(POSIX_FADV_WILLNEED)
|
||||
#define POSIX_MADV_DONTNEED SYMBOLIC(POSIX_MADV_DONTNEED)
|
||||
#define POSIX_MADV_NORMAL SYMBOLIC(POSIX_MADV_NORMAL)
|
||||
#define POSIX_MADV_RANDOM SYMBOLIC(POSIX_MADV_RANDOM)
|
||||
#define POSIX_MADV_SEQUENTIAL SYMBOLIC(POSIX_MADV_SEQUENTIAL)
|
||||
#define POSIX_MADV_WILLNEED SYMBOLIC(POSIX_MADV_WILLNEED)
|
||||
#define POSIX_SPAWN_RESETIDS SYMBOLIC(POSIX_SPAWN_RESETIDS)
|
||||
#define POSIX_SPAWN_SETPGROUP SYMBOLIC(POSIX_SPAWN_SETPGROUP)
|
||||
#define POSIX_SPAWN_SETSCHEDPARAM SYMBOLIC(POSIX_SPAWN_SETSCHEDPARAM)
|
||||
#define POSIX_SPAWN_SETSCHEDULER SYMBOLIC(POSIX_SPAWN_SETSCHEDULER)
|
||||
#define POSIX_SPAWN_SETSIGDEF SYMBOLIC(POSIX_SPAWN_SETSIGDEF)
|
||||
#define POSIX_SPAWN_SETSIGMASK SYMBOLIC(POSIX_SPAWN_SETSIGMASK)
|
||||
#define POSIX_SPAWN_USEVFORK SYMBOLIC(POSIX_SPAWN_USEVFORK)
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
@@ -35,14 +15,20 @@ hidden extern const long POSIX_MADV_NORMAL;
|
||||
hidden extern const long POSIX_MADV_RANDOM;
|
||||
hidden extern const long POSIX_MADV_SEQUENTIAL;
|
||||
hidden extern const long POSIX_MADV_WILLNEED;
|
||||
hidden extern const long POSIX_SPAWN_RESETIDS;
|
||||
hidden extern const long POSIX_SPAWN_SETPGROUP;
|
||||
hidden extern const long POSIX_SPAWN_SETSCHEDPARAM;
|
||||
hidden extern const long POSIX_SPAWN_SETSCHEDULER;
|
||||
hidden extern const long POSIX_SPAWN_SETSIGDEF;
|
||||
hidden extern const long POSIX_SPAWN_SETSIGMASK;
|
||||
hidden extern const long POSIX_SPAWN_USEVFORK;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
#define POSIX_FADV_DONTNEED SYMBOLIC(POSIX_FADV_DONTNEED)
|
||||
#define POSIX_FADV_NOREUSE SYMBOLIC(POSIX_FADV_NOREUSE)
|
||||
#define POSIX_FADV_NORMAL SYMBOLIC(POSIX_FADV_NORMAL)
|
||||
#define POSIX_FADV_RANDOM SYMBOLIC(POSIX_FADV_RANDOM)
|
||||
#define POSIX_FADV_SEQUENTIAL SYMBOLIC(POSIX_FADV_SEQUENTIAL)
|
||||
#define POSIX_FADV_WILLNEED SYMBOLIC(POSIX_FADV_WILLNEED)
|
||||
#define POSIX_MADV_DONTNEED SYMBOLIC(POSIX_MADV_DONTNEED)
|
||||
#define POSIX_MADV_NORMAL SYMBOLIC(POSIX_MADV_NORMAL)
|
||||
#define POSIX_MADV_RANDOM SYMBOLIC(POSIX_MADV_RANDOM)
|
||||
#define POSIX_MADV_SEQUENTIAL SYMBOLIC(POSIX_MADV_SEQUENTIAL)
|
||||
#define POSIX_MADV_WILLNEED SYMBOLIC(POSIX_MADV_WILLNEED)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_POSIX_H_ */
|
||||
@@ -91,7 +91,7 @@ scall 'setsockopt$sysv' 0x0069006920690036 globl hidden
|
||||
scall 'getsockopt$sysv' 0x0076007620760037 globl hidden
|
||||
scall '__fork$sysv' 0x0002000220020039 globl hidden # xnu needs eax=~-edx b/c eax always holds pid and edx is 0 for parent and 1 for child
|
||||
#scall vfork 0x004200422042003a globl # this syscall is from the moon so we implement it by hand in libc/calls/hefty/vfork.S
|
||||
scall posix_spawn 0xffffffff20f4ffff globl hidden # TODO: put in spawnve()
|
||||
scall 'posix_spawn$sysv' 0xffffffff20f4ffff globl hidden # good luck figuring out how xnu defines this
|
||||
scall '__execve$sysv' 0x003b003b203b003b globl hidden
|
||||
scall 'wait4$sysv' 0x000b00072007003d globl hidden
|
||||
scall 'kill$sysv' 0x007a00252025003e globl hidden # kill(pid, sig, 1) b/c xnu
|
||||
@@ -118,7 +118,7 @@ scall '__truncate$sysv' 0x00c801df20c8004c globl hidden # openbsd:pad
|
||||
scall '__ftruncate$sysv' 0x00c901e020c9004d globl hidden # openbsd:pad
|
||||
scall 'getcwd$sysv' 0x01300146ffff004f globl hidden
|
||||
scall 'chdir$sysv' 0x000c000c200c0050 globl hidden
|
||||
scall fchdir 0x000d000d200d0051 globl
|
||||
scall 'fchdir$sysv' 0x000d000d200d0051 globl hidden
|
||||
scall 'rename$sysv' 0x0080008020800052 globl hidden
|
||||
scall 'mkdir$sysv' 0x0088008820880053 globl hidden
|
||||
scall 'rmdir$sysv' 0x0089008920890054 globl hidden
|
||||
@@ -164,7 +164,7 @@ scall sigpending 0x003400342034007f globl
|
||||
scall 'sigsuspend$sysv' 0x006f0155206f0082 globl hidden
|
||||
scall sigaltstack 0x0120003520350083 globl
|
||||
scall 'mknod$sysv' 0x000e000e200e0085 globl hidden
|
||||
scall mknodat 0x014022ffffff0103 globl # FreeBSD 12+
|
||||
scall mknodat 0x0140022fffff0103 globl # FreeBSD 12+
|
||||
scall 'mkfifo$sysv' 0x008400842084ffff globl hidden
|
||||
scall mkfifoat 0x013f01f1ffffffff globl
|
||||
scall statfs 0x003f022b21590089 globl
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Recursively creates directory a.k.a. folder.
|
||||
*
|
||||
* @param path is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param mode can be, for example, 0755
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see mkdir()
|
||||
*/
|
||||
int makedirs(const char *path, unsigned mode) {
|
||||
int rc;
|
||||
char *dir;
|
||||
if (mkdir(path, mode) != -1) return 0;
|
||||
if (errno != ENOENT) return -1;
|
||||
dir = xdirname(path);
|
||||
if (strcmp(dir, path)) {
|
||||
rc = makedirs(dir, mode);
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
free(dir);
|
||||
if (rc == -1) return -1;
|
||||
return mkdir(path, mode);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*-*- 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/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
static int rmrfdir(const char *dirpath) {
|
||||
int rc;
|
||||
DIR *d;
|
||||
char *path;
|
||||
struct dirent *e;
|
||||
if (!(d = opendir(dirpath))) return -1;
|
||||
while ((e = readdir(d))) {
|
||||
if (!strcmp(e->d_name, ".")) continue;
|
||||
if (!strcmp(e->d_name, "..")) continue;
|
||||
if (strchr(e->d_name, '/')) abort();
|
||||
path = xjoinpaths(dirpath, e->d_name);
|
||||
if (e->d_type == DT_DIR) {
|
||||
rc = rmrfdir(path);
|
||||
} else {
|
||||
rc = unlink(path);
|
||||
}
|
||||
if (rc == -1) {
|
||||
free(path);
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
rc = closedir(d);
|
||||
rc |= rmdir(dirpath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removes file or directory.
|
||||
*/
|
||||
int rmrf(const char *path) {
|
||||
struct stat st;
|
||||
if (stat(path, &st) == -1) return -1;
|
||||
if (!S_ISDIR(st.st_mode)) return unlink(path);
|
||||
return rmrfdir(path);
|
||||
}
|
||||
+8
-1
@@ -45,9 +45,16 @@ char *xstrdup(const char *) _XPNN _XMAL;
|
||||
char *xstrndup(const char *, size_t) _XPNN _XMAL;
|
||||
char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL;
|
||||
char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL;
|
||||
char *xinet_ntop(int, const void *) _XPNN _XMAL;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § eXtended apis » files ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int rmrf(const char *);
|
||||
int makedirs(const char *, unsigned);
|
||||
char *xdirname(const char *) paramsnonnull() _XMAL;
|
||||
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
|
||||
char *xinet_ntop(int, const void *) _XPNN _XMAL;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § eXtended apis » time ─╬─│┼
|
||||
|
||||
@@ -34,6 +34,7 @@ LIBC_X_A_CHECKS = \
|
||||
|
||||
LIBC_X_A_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
|
||||
@@ -16,52 +16,79 @@
|
||||
│ 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/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
uint64_t i;
|
||||
char pathbuf[PATH_MAX];
|
||||
const char *oldpath, *bindir, *homedir, *binsh, *sh;
|
||||
char pathbuf[PATH_MAX], testdir[PATH_MAX], *oldpath;
|
||||
|
||||
TEST(commandv_00, todo) { /* TODO(jart): Improve this on Windows. */
|
||||
if (IsWindows()) exit(0);
|
||||
void SetUp(void) {
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
mkdir("bin", 0755);
|
||||
mkdir("home", 0755);
|
||||
oldpath = strdup(nulltoempty(getenv("PATH")));
|
||||
CHECK_NE(-1, setenv("PATH", "bin", true));
|
||||
}
|
||||
|
||||
TEST(commandv_001, setupFiles) {
|
||||
mkdir("o", 0755);
|
||||
mkdir("o/tmp", 0755);
|
||||
oldpath = strdup(getenv("PATH"));
|
||||
homedir = xasprintf("o/tmp/home.%d", getpid());
|
||||
bindir = xasprintf("o/tmp/bin.%d", getpid());
|
||||
binsh = xasprintf("%s/sh.com", bindir);
|
||||
ASSERT_NE(-1, mkdir(homedir, 0755));
|
||||
ASSERT_NE(-1, mkdir(bindir, 0755));
|
||||
ASSERT_NE(-1, touch(binsh, 0755));
|
||||
ASSERT_NE(-1, setenv("PATH", bindir, true));
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, setenv("PATH", oldpath, true));
|
||||
CHECK_NE(-1, chdir("../../.."));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(commandv_010, testSlashes_wontSearchPath_butChecksAccess) {
|
||||
sh = defer(unlink, gc(xasprintf("%s/sh.com", homedir)));
|
||||
EXPECT_NE(-1, touch(sh, 0755));
|
||||
TEST(commandv, testPathSearch) {
|
||||
EXPECT_NE(-1, touch("bin/sh", 0755));
|
||||
EXPECT_STREQ("bin/sh", commandv("sh", pathbuf));
|
||||
}
|
||||
|
||||
TEST(commandv, testPathSearch_appendsComExtension) {
|
||||
EXPECT_NE(-1, touch("bin/sh.com", 0755));
|
||||
EXPECT_STREQ("bin/sh.com", commandv("sh", pathbuf));
|
||||
}
|
||||
|
||||
TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) {
|
||||
EXPECT_NE(-1, touch("home/sh", 0755));
|
||||
i = g_syscount;
|
||||
EXPECT_STREQ(sh, commandv(sh, pathbuf));
|
||||
if (!IsWindows()) EXPECT_EQ(i + 1 /* access() */, g_syscount);
|
||||
EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf));
|
||||
if (!IsWindows()) EXPECT_EQ(i + 1, g_syscount);
|
||||
}
|
||||
|
||||
TEST(commandv_999, teardown) {
|
||||
setenv("PATH", oldpath, true);
|
||||
unlink(binsh);
|
||||
rmdir(bindir);
|
||||
rmdir(homedir);
|
||||
free(bindir);
|
||||
free(binsh);
|
||||
free(homedir);
|
||||
free(oldpath);
|
||||
TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) {
|
||||
EXPECT_NE(-1, touch("home/sh.com", 0755));
|
||||
i = g_syscount;
|
||||
EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf));
|
||||
if (!IsWindows()) EXPECT_EQ(i + 2, g_syscount);
|
||||
}
|
||||
|
||||
TEST(commandv, testSameDir_doesntHappenByDefault) {
|
||||
EXPECT_NE(-1, touch("bog", 0755));
|
||||
EXPECT_EQ(NULL, commandv("bog", pathbuf));
|
||||
}
|
||||
|
||||
TEST(commandv, testSameDir_willHappenWithColonBlank) {
|
||||
CHECK_NE(-1, setenv("PATH", "bin:", true));
|
||||
EXPECT_NE(-1, touch("bog", 0755));
|
||||
EXPECT_STREQ("bog", commandv("bog", pathbuf));
|
||||
}
|
||||
|
||||
TEST(commandv, testSameDir_willHappenWithColonBlank2) {
|
||||
CHECK_NE(-1, setenv("PATH", ":bin", true));
|
||||
EXPECT_NE(-1, touch("bog", 0755));
|
||||
EXPECT_STREQ("bog", commandv("bog", pathbuf));
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*-*- 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/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char basedir[PATH_MAX];
|
||||
char testdir[PATH_MAX];
|
||||
|
||||
void SetUp(void) {
|
||||
getcwd(basedir, ARRAYLEN(basedir));
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, chdir(basedir));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(getcwd, test) {
|
||||
char buf[PATH_MAX];
|
||||
EXPECT_NE(-1, mkdir("subdir", 0755));
|
||||
EXPECT_NE(-1, chdir("subdir"));
|
||||
EXPECT_STREQ("subdir", basename(getcwd(buf, ARRAYLEN(buf))));
|
||||
}
|
||||
|
||||
TEST(getcwd, testNullBuf_allocatesResult) {
|
||||
EXPECT_NE(-1, mkdir("subdir", 0755));
|
||||
EXPECT_NE(-1, chdir("subdir"));
|
||||
EXPECT_STREQ("subdir", basename(gc(getcwd(NULL, 0))));
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*-*- 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/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char testdir[PATH_MAX];
|
||||
|
||||
void SetUp(void) {
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, chdir("../../.."));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(lseek, wat) {
|
||||
int fd, pid;
|
||||
char buf[8] = {0};
|
||||
ASSERT_NE(-1, (fd = open("wut", O_RDWR | O_CREAT, 0644)));
|
||||
ASSERT_EQ(3, write(fd, "wut", 3));
|
||||
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
|
||||
if (!(pid = fork())) {
|
||||
lseek(fd, 1, SEEK_SET);
|
||||
_exit(0);
|
||||
}
|
||||
EXPECT_NE(-1, waitpid(pid, 0, 0));
|
||||
EXPECT_EQ(1, read(fd, buf, 1));
|
||||
EXPECT_EQ('u', buf[0]); /* wat?! */
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*-*- 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/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char testdir[PATH_MAX];
|
||||
|
||||
void SetUp(void) {
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, chdir("../../.."));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(mkdir, testNothingExists_ENOENT) {
|
||||
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
||||
EXPECT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST(mkdir, testDirectoryComponentIsFile_ENOTDIR) {
|
||||
EXPECT_NE(-1, touch("yo", 0644));
|
||||
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
||||
EXPECT_EQ(ENOTDIR, errno);
|
||||
}
|
||||
|
||||
TEST(mkdir, testPathIsFile_EEXIST) {
|
||||
EXPECT_NE(-1, mkdir("yo", 0755));
|
||||
EXPECT_NE(-1, mkdir("yo/yo", 0755));
|
||||
EXPECT_NE(-1, touch("yo/yo/yo", 0644));
|
||||
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
||||
EXPECT_EQ(EEXIST, errno);
|
||||
}
|
||||
|
||||
TEST(mkdir, testPathIsDirectory_EEXIST) {
|
||||
EXPECT_NE(-1, mkdir("yo", 0755));
|
||||
EXPECT_NE(-1, mkdir("yo/yo", 0755));
|
||||
EXPECT_NE(-1, mkdir("yo/yo/yo", 0755));
|
||||
EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755));
|
||||
EXPECT_EQ(EEXIST, errno);
|
||||
}
|
||||
|
||||
TEST(makedirs, testEmptyString_ENOENT) {
|
||||
EXPECT_EQ(-1, makedirs("", 0755));
|
||||
EXPECT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST(mkdirat, testRelativePath_opensRelativeToDirFd) {
|
||||
int dirfd;
|
||||
ASSERT_NE(-1, mkdir("foo", 0755));
|
||||
ASSERT_NE(-1, (dirfd = open("foo", O_RDONLY | O_DIRECTORY)));
|
||||
EXPECT_NE(-1, mkdirat(dirfd, "bar", 0755));
|
||||
EXPECT_TRUE(isdirectory("foo/bar"));
|
||||
EXPECT_EQ(-1, makedirs("", 0755));
|
||||
EXPECT_NE(-1, close(dirfd));
|
||||
}
|
||||
@@ -27,49 +27,49 @@ char16_t cmdline[ARG_MAX];
|
||||
|
||||
TEST(mkntcmdline, emptyArgvList_isEmpty) {
|
||||
char *argv[] = {NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"", cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, emptyArg_getsQuoted) {
|
||||
char *argv[] = {"", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"\"\"", cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, ignoranceIsBliss) {
|
||||
char *argv[] = {"echo", "hello", "world", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"echo hello world", cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, spaceInArgument_getQuotesWrappedAround) {
|
||||
char *argv[] = {"echo", "hello there", "world", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"echo \"hello there\" world", cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, justQuote) {
|
||||
char *argv[] = {"\"", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"\"\\\"\"", cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, justSlash) {
|
||||
char *argv[] = {"\\", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"\\", cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, justSlashQuote) {
|
||||
char *argv[] = {"\\\"", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"\"\\\\\\\"\"" /* "\\\"" */, cmdline);
|
||||
}
|
||||
|
||||
TEST(mkntcmdline, basicQuoting) {
|
||||
char *argv[] = {"a\"b c", "d", NULL};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv[0], argv));
|
||||
EXPECT_STREQ(u"\"a\\\"b c\" d" /* "a\"b c" d */, cmdline);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ TEST(mkntcmdline, testUnicode) {
|
||||
strdup("要依法治国是赞美那些谁是公义的和惩罚恶人。 - 韩非"),
|
||||
NULL,
|
||||
};
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv1));
|
||||
EXPECT_NE(-1, mkntcmdline(cmdline, argv1[0], argv1));
|
||||
EXPECT_STREQ(u"(╯°□°)╯ \"要依法治国是赞美那些谁是公义的和惩罚恶人。 - 韩非\"",
|
||||
cmdline);
|
||||
}
|
||||
@@ -30,4 +30,5 @@ TEST(dirname, test) {
|
||||
EXPECT_STREQ(".", dirname(gc(strdup("hello"))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup("."))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup(".."))));
|
||||
EXPECT_STREQ("", dirname(gc(strdup(""))));
|
||||
}
|
||||
@@ -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 │
|
||||
@@ -16,24 +16,20 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
int fgethex(FILE *f) {
|
||||
int o, t = -1;
|
||||
while (!((o = fgetc(f)) & ~0xFF)) {
|
||||
switch (t) {
|
||||
case -1:
|
||||
t = isxdigit(o) ? hextoint(o) : -1;
|
||||
break;
|
||||
default:
|
||||
if (isxdigit(o)) {
|
||||
return t * 16 + hextoint(o);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= 0) return einval();
|
||||
return -1;
|
||||
TEST(strcasecmp, test) {
|
||||
EXPECT_EQ(0, strcasecmp("HELLO", "hello"));
|
||||
EXPECT_EQ(-17, strcasecmp("HELLO", "yello"));
|
||||
EXPECT_EQ(-17, strcasecmp("HELLO", "YELLO"));
|
||||
EXPECT_EQ(+17, strcasecmp("yello", "HELLO"));
|
||||
EXPECT_EQ(+17, strcasecmp("YELLO", "HELLO"));
|
||||
}
|
||||
|
||||
BENCH(strcasecmp, bench) {
|
||||
EZBENCH2("strcasecmp 16 eq", donothing,
|
||||
EXPROPRIATE(
|
||||
strcasecmp(VEIL("r", "abcdefghijklmnop"), "ABCDEFGHIJKLMNOP")));
|
||||
}
|
||||
+5
-1
@@ -393,7 +393,11 @@ int Serve(void) {
|
||||
if (!Poll() && (!g_timeout || g_interrupted)) break;
|
||||
}
|
||||
close(g_servfd);
|
||||
LOGF("timeout expired, shutting down");
|
||||
if (!g_timeout) {
|
||||
LOGF("timeout expired, shutting down");
|
||||
} else {
|
||||
LOGF("got ctrl-c, shutting down");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user