From dc6c67256fa3f0f0b02bbcb4493797630db127f3 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 16 Aug 2023 07:54:40 -0700 Subject: [PATCH] Remove old stack code and improve dirstream --- ape/aarch64.lds | 3 +- ape/ape.S | 8 +- ape/ape.lds | 3 +- libc/calls/chdir.c | 15 + libc/calls/fchdir.c | 10 +- libc/calls/getrlimit.c | 5 + libc/calls/setrlimit.c | 2 + libc/calls/wincrash.c | 5 +- libc/integral/c.inc | 5 +- libc/integral/normalize.inc | 2 - libc/mem/critbit0.h | 2 +- libc/mem/critbit0_emplace.c | 34 +- libc/mem/critbit0_insert.c | 10 +- libc/runtime/cosmo.S | 60 --- libc/runtime/cosmo2.c | 12 - libc/runtime/printargs.c | 6 +- libc/runtime/stack.h | 30 +- libc/runtime/switchstacks.S | 31 -- libc/runtime/winmain.greg.c | 123 +----- libc/runtime/zipos-get.c | 24 +- libc/runtime/zipos-stat-impl.c | 33 +- libc/runtime/zipos.internal.h | 1 + libc/stdio/dirstream.c | 454 +++++++++++---------- libc/stdio/stdio.mk | 1 + libc/sysv/consts.sh | 4 +- libc/sysv/consts/RLIMIT_STACK.S | 2 +- libc/sysv/consts/RLIM_NLIMITS.S | 2 +- libc/x/x.h | 2 +- test/libc/calls/ioctl_test.c | 1 - test/libc/calls/lock_test.c | 1 - test/libc/calls/pledge_test.c | 1 - test/libc/calls/timespec_test.c | 1 - test/libc/intrin/dos2errno_test.c | 1 - test/libc/intrin/pthread_spin_lock_test.c | 1 - test/libc/log/backtrace_test.c | 1 - test/libc/mem/critbit0_test.c | 8 + test/libc/runtime/daemon_test.c | 1 - test/libc/runtime/fork_test.c | 1 - test/libc/runtime/grow_test.c | 1 - test/libc/runtime/mmap_test.c | 1 - test/libc/runtime/munmap_test.c | 1 - test/libc/sock/nonblock_test.c | 1 - test/libc/sock/sendfile_test.c | 1 - test/libc/stdio/dirstream_test.c | 73 +++- test/libc/stdio/posix_spawn_test.c | 1 - test/libc/stdio/zipdir_test.c | 1 + test/libc/thread/pthread_key_create_test.c | 1 - test/libc/thread/pthread_setname_np_test.c | 1 - test/libc/thread/sem_open_test.c | 1 - test/libc/thread/spawn_test.c | 56 --- test/libc/tinymath/magicu_test.c | 1 - test/tool/net/sqlite_test.c | 1 - third_party/tr/tr.c | 1 - tool/build/apelink.c | 1 - tool/build/ar.c | 1 - tool/build/cp.c | 1 - tool/build/elf2pe.c | 1 - tool/build/fixupobj.c | 1 - tool/build/rm.c | 3 +- tool/curl/curl.c | 1 - tool/emacs/cosmo-cpp-constants.el | 1 - 61 files changed, 463 insertions(+), 595 deletions(-) delete mode 100644 libc/runtime/switchstacks.S delete mode 100644 test/libc/thread/spawn_test.c diff --git a/ape/aarch64.lds b/ape/aarch64.lds index 5a4b5f6e5..824512fa0 100644 --- a/ape/aarch64.lds +++ b/ape/aarch64.lds @@ -279,8 +279,7 @@ SECTIONS { } ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000; -ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : APE_STACKSIZE; -ape_stack_memsz2 = ape_stack_memsz * 2; +ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024; _tls_size = _tbss_end - _tdata_start; _tdata_size = _tdata_end - _tdata_start; diff --git a/ape/ape.S b/ape/ape.S index 1b4338f8e..ed97635b0 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -794,7 +794,7 @@ ape_loader_end: .stub ape_stack_vaddr,quad // is mmap()'d with MAP_FIXED .stub ape_stack_paddr,quad // ignored .stub ape_stack_filesz,quad // ignored - .stub ape_stack_memsz2,quad // is mmap(size) argument + .stub ape_stack_memsz,quad // ignored? .stub ape_stack_align,quad // must be 16+ #if SupportsOpenbsd() || SupportsNetbsd() @@ -1082,8 +1082,8 @@ ape_pe: .ascin "PE",4 .long 0 // Checksum .short v_ntsubsystem // Subsystem: 0=Neutral,2=GUI,3=Console .short v_ntdllchar // DllCharacteristics - .quad 0x30000 // StackReserve - .quad 0x30000 // StackCommit + .quad 0x10000 // StackReserve + .quad 0x10000 // StackCommit .quad 0 // HeapReserve .quad 0 // HeapCommit .long 0 // LoaderFlags @@ -1735,7 +1735,7 @@ ape_grub_entry: │ αcτµαlly pδrταblε εxεcµταblε § cosmopolitan libc runtime runtime ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ kernel: movabs $ape_stack_vaddr,%rsp - add $ape_stack_memsz2,%rsp + add $ape_stack_memsz,%rsp movl $0,0x7b000 // unmap null 2mb #if USE_SYMBOL_HACK .byte 0x0f,0x1f,0207 // nop rdi binbase diff --git a/ape/ape.lds b/ape/ape.lds index c45756ca3..2ec759ff1 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -584,8 +584,7 @@ ape_stack_offset = 0; ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000; ape_stack_paddr = ape_ram_paddr + ape_ram_filesz; ape_stack_filesz = 0; -ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : APE_STACKSIZE; -ape_stack_memsz2 = ape_stack_memsz * 2; +ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024; ape_stack_align = 16; ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr); diff --git a/libc/calls/chdir.c b/libc/calls/chdir.c index bc3743f3c..ba4f5d94b 100644 --- a/libc/calls/chdir.c +++ b/libc/calls/chdir.c @@ -21,7 +21,9 @@ #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/intrin/weaken.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/zipos.internal.h" #include "libc/sysv/errfuns.h" /** @@ -30,14 +32,27 @@ * This does *not* update the `PWD` environment variable. * * @return 0 on success, or -1 w/ errno + * @raise ELOOP if a loop was detected resolving components of `path` + * @raise EACCES if search permission was denied on directory + * @raise ENOTDIR if component of `path` isn't a directory + * @raise ENOMEM if insufficient memory was available + * @raise EFAULT if `path` points to invalid memory + * @raise ENOTSUP if `path` is a `/zip/...` file + * @raise ENAMETOOLONG if `path` was too long + * @raise ENOENT if `path` doesn't exist + * @raise EIO if an i/o error happened * @asyncsignalsafe * @see fchdir() */ int chdir(const char *path) { int rc; + struct ZiposUri zipname; GetProgramExecutableName(); // XXX: ugly workaround if (!path || (IsAsan() && !__asan_is_valid_str(path))) { rc = efault(); + } else if (_weaken(__zipos_parseuri) && + _weaken(__zipos_parseuri)(path, &zipname) != -1) { + rc = enotsup(); } else if (!IsWindows()) { rc = sys_chdir(path); } else { diff --git a/libc/calls/fchdir.c b/libc/calls/fchdir.c index e5405f37a..49643b717 100644 --- a/libc/calls/fchdir.c +++ b/libc/calls/fchdir.c @@ -17,22 +17,30 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/strace.internal.h" +#include "libc/sysv/errfuns.h" /** * Sets current directory based on file descriptor. * * This does *not* update the `PWD` environment variable. * + * @raise EACCES if search permission was denied on directory + * @raise ENOTDIR if `dirfd` doesn't refer to a directory + * @raise EBADF if `dirfd` isn't a valid file descriptor + * @raise ENOTSUP if `dirfd` refers to `/zip/...` file * @see open(path, O_DIRECTORY) * @asyncsignalsafe */ int fchdir(int dirfd) { int rc; - if (!IsWindows()) { + if (__isfdkind(dirfd, kFdZip)) { + rc = enotsup(); + } else if (!IsWindows()) { rc = sys_fchdir(dirfd); } else { rc = sys_fchdir_nt(dirfd); diff --git a/libc/calls/getrlimit.c b/libc/calls/getrlimit.c index 52b57eea0..8ec08d5dd 100644 --- a/libc/calls/getrlimit.c +++ b/libc/calls/getrlimit.c @@ -22,6 +22,7 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/runtime/stack.h" #include "libc/sysv/consts/rlimit.h" #include "libc/sysv/errfuns.h" @@ -41,6 +42,10 @@ int getrlimit(int resource, struct rlimit *rlim) { rc = efault(); } else if (!IsWindows()) { rc = sys_getrlimit(resource, rlim); + } else if (resource == RLIMIT_STACK) { + rlim->rlim_cur = (uintptr_t)ape_stack_memsz; + rlim->rlim_max = (uintptr_t)ape_stack_memsz; + rc = 0; } else if (resource == RLIMIT_AS) { rlim->rlim_cur = __virtualmax; rlim->rlim_max = __virtualmax; diff --git a/libc/calls/setrlimit.c b/libc/calls/setrlimit.c index c1b082dd3..21779e720 100644 --- a/libc/calls/setrlimit.c +++ b/libc/calls/setrlimit.c @@ -78,6 +78,8 @@ int setrlimit(int resource, const struct rlimit *rlim) { // TODO(jart): What's up with XNU and NetBSD? __virtualmax = rlim->rlim_cur; } + } else if (resource == RLIMIT_STACK) { + rc = enotsup(); } else if (resource == RLIMIT_AS) { __virtualmax = rlim->rlim_cur; rc = 0; diff --git a/libc/calls/wincrash.c b/libc/calls/wincrash.c index 16b604560..6242f7b5b 100644 --- a/libc/calls/wincrash.c +++ b/libc/calls/wincrash.c @@ -78,6 +78,7 @@ unsigned __wincrash(struct NtExceptionPointers *ep) { break; case kNtSignalGuardPage: case kNtSignalInPageError: + case kNtStatusStackOverflow: code = SEGV_MAPERR; sig = SIGSEGV; break; @@ -128,7 +129,9 @@ unsigned __wincrash(struct NtExceptionPointers *ep) { sig = SIGSYS; break; default: - return kNtExceptionContinueSearch; + code = ep->ExceptionRecord->ExceptionCode; + sig = SIGSEGV; + break; } rip = ep->ContextRecord->Rip; diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 581b38b30..7113129e4 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -153,9 +153,8 @@ typedef struct { #define libcesque dontthrow nocallback #define memcpyesque libcesque #define strlenesque libcesque nosideeffect paramsnonnull() -#define vallocesque \ - libcesque dontdiscard returnsaligned((APE_PAGESIZE)) \ - returnspointerwithnoaliases +#define vallocesque \ + libcesque dontdiscard returnsaligned((65536)) returnspointerwithnoaliases #define reallocesque libcesque returnsaligned((16)) #define mallocesque reallocesque returnspointerwithnoaliases #define interruptfn nocallersavedregisters forcealignargpointer diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 090171b0e..107f76ba1 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -74,8 +74,6 @@ #define __BIGGEST_ALIGNMENT__ 16 #endif -#define APE_STACKSIZE 8388608 -#define APE_PAGESIZE 65536 #ifdef _COSMO_SOURCE #define FRAMESIZE 65536 #define _PAGESIZE 4096 diff --git a/libc/mem/critbit0.h b/libc/mem/critbit0.h index c5f3d9b78..bfae0543f 100644 --- a/libc/mem/critbit0.h +++ b/libc/mem/critbit0.h @@ -20,7 +20,7 @@ char *critbit0_get(struct critbit0 *, const char *); intptr_t critbit0_allprefixed(struct critbit0 *, const char *, intptr_t (*)(const char *, void *), void *) paramsnonnull((1, 2, 3)) dontthrow; -int critbit0_emplace(struct critbit0 *, char *, size_t) paramsnonnull(); +int critbit0_emplace(struct critbit0 *, const void *, size_t) paramsnonnull(); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/mem/critbit0_emplace.c b/libc/mem/critbit0_emplace.c index 6c1badd7b..1272df6a1 100644 --- a/libc/mem/critbit0_emplace.c +++ b/libc/mem/critbit0_emplace.c @@ -21,23 +21,35 @@ #include "libc/mem/mem.h" #include "libc/str/str.h" +static void *critbit0_dup(const void *u, size_t ulen) { + char *res; + if ((res = malloc(ulen + 1))) { + if (ulen) { + memcpy(res, u, ulen); + } + res[ulen] = 0; + } + return res; +} + /** * Inserts 𝑢 into 𝑡 without copying. * - * @param t is critical bit tree - * @param u is nul-terminated string which must be 8+ byte aligned - * and becomes owned by the tree afterwards - * @return true if 𝑡 was mutated, or -1 w/ errno + * @return 1 if 𝑡 was mutated, 0 if present, or -1 w/ errno * @note h/t djb and agl */ -int critbit0_emplace(struct critbit0 *t, char *u, size_t ulen) { +int critbit0_emplace(struct critbit0 *t, const void *u, size_t ulen) { unsigned char *p = t->root; if (!p) { - t->root = u; - t->count = 1; - return 1; + if ((u = critbit0_dup(u, ulen))) { + t->root = u; + t->count = 1; + return 1; + } else { + return -1; + } } - const unsigned char *const ubytes = (void *)u; + const unsigned char *ubytes = (void *)u; while (1 & (intptr_t)p) { struct CritbitNode *q = (void *)(p - 1); unsigned char c = 0; @@ -66,7 +78,8 @@ DifferentByteFound: unsigned char c = p[newbyte]; int newdirection = (1 + (newotherbits | c)) >> 8; struct CritbitNode *newnode; - if ((newnode = malloc(sizeof(struct CritbitNode)))) { + if ((newnode = malloc(sizeof(struct CritbitNode))) && + (ubytes = critbit0_dup(ubytes, ulen))) { newnode->byte = newbyte; newnode->otherbits = newotherbits; newnode->child[1 - newdirection] = (void *)ubytes; @@ -87,6 +100,7 @@ DifferentByteFound: t->count++; return 1; } else { + free(newnode); return -1; } } diff --git a/libc/mem/critbit0_insert.c b/libc/mem/critbit0_insert.c index e65c3ba23..9005f0098 100644 --- a/libc/mem/critbit0_insert.c +++ b/libc/mem/critbit0_insert.c @@ -25,15 +25,9 @@ * Inserts 𝑢 into 𝑡. * @param t tree * @param u NUL-terminated string - * @return true if 𝑡 was mutated, or -1 w/ errno + * @return 1 if 𝑡 was mutated, 0 if present, or -1 w/ errno * @note h/t djb and agl */ int critbit0_insert(struct critbit0 *t, const char *u) { - char *p; - size_t n; - if ((p = malloc((n = strlen(u)) + 1))) { - return critbit0_emplace(t, memcpy(p, u, n + 1), n); - } else { - return -1; - } + return critbit0_emplace(t, u, strlen(u)); } diff --git a/libc/runtime/cosmo.S b/libc/runtime/cosmo.S index 172fe164b..51a1404fd 100644 --- a/libc/runtime/cosmo.S +++ b/libc/runtime/cosmo.S @@ -123,66 +123,6 @@ cosmo: push %rbp pop %rdi .init.end 304,_init_tls -#if !IsTiny() -// Creates deterministically addressed stack we can use -// -// This helps debugging be more comprehensible, because -// when diagnosing low-level problems when error report -// isn't working, sometimes numbers are all you have to -// go on, and we can't use them if kernel hardening has -// configured that meaningful data to be randomized. -// -// Having deterministic addresses is also key to ensure -// builds, execution, and other things are reproducible - .init.start 304,_init_stack - testb IsWindows() - jnz 9f - testb IsMetal() - jnz 9f - push %rdi - push %rsi - -// allocate stack - movabs $ape_stack_vaddr,%rdi - mov $ape_stack_memsz,%esi - mov $ape_stack_prot,%edx - mov $MAP_STACK,%ecx - or MAP_ANONYMOUS,%ecx - or $-1,%r8 - xor %r9d,%r9d - push %rsi - push %rsi - call mmap - pop %r8 - pop %r8 - pop %rsi - pop %rdi - cmp $-1,%rax - je 9f - -// switch stacks -// -// we subtract 8 because the openbsd kernel always checks rsp -// is on a MAP_STACK interval non-inclusively of stack + size - leave - pop %rcx // return address - sub $8,%r8d // openbsd:stackbound - lea (%rax,%r8),%rsp - mov $ape_stack_align,%eax - neg %rax - and %rax,%rsp - push %rcx - push %rbp - mov %rsp,%rbp - -9: nop - .init.end 304,_init_stack - .weak ape_stack_prot - .weak ape_stack_vaddr - .weak ape_stack_memsz - .weak ape_stack_align -#endif - #if IsAsan() .init.start 305,_init_symbols push %rdi diff --git a/libc/runtime/cosmo2.c b/libc/runtime/cosmo2.c index 6af619190..c5f2f182b 100644 --- a/libc/runtime/cosmo2.c +++ b/libc/runtime/cosmo2.c @@ -64,8 +64,6 @@ extern init_f *__preinit_array_start[] __attribute__((__weak__)); extern init_f *__preinit_array_end[] __attribute__((__weak__)); extern init_f *__init_array_start[] __attribute__((__weak__)); extern init_f *__init_array_end[] __attribute__((__weak__)); -extern char ape_stack_vaddr[] __attribute__((__weak__)); -extern char ape_stack_memsz[] __attribute__((__weak__)); extern char ape_stack_prot[] __attribute__((__weak__)); extern pthread_mutex_t __mmi_lock_obj; extern int hostos asm("__hostos"); @@ -161,16 +159,6 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) { __enable_tls(); - __switch_stacks(argc, argv, envp, auxv, cosmo2, - (char *)mmap(ape_stack_vaddr, (uintptr_t)ape_stack_memsz, - MAP_FIXED | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + - (uintptr_t)ape_stack_memsz); -} - -wontreturn textstartup void cosmo2(int argc, char **argv, char **envp, - unsigned long *auxv) { - #if 0 #if IsAsan() // TODO(jart): Figure out ASAN data model on AARCH64. diff --git a/libc/runtime/printargs.c b/libc/runtime/printargs.c index 92c6349bd..b8b0eb16a 100644 --- a/libc/runtime/printargs.c +++ b/libc/runtime/printargs.c @@ -453,9 +453,11 @@ dontasan textstartup void __printargs(const char *prologue) { PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName", GetInterpreterExecutableName(u.path, sizeof(u.path))); PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0)); - PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr()); - PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0)); PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize()); + PRINT(" ☼ %s = %p", "GetGuardSize()", GetGuardSize()); + PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr()); + PRINT(" ☼ %s = %p", "GetStaticStackSize()", GetStaticStackSize()); + PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0)); PRINT(""); PRINT("MEMTRACK"); diff --git a/libc/runtime/stack.h b/libc/runtime/stack.h index 9d75c728e..3aaddccf2 100644 --- a/libc/runtime/stack.h +++ b/libc/runtime/stack.h @@ -3,6 +3,20 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) #ifdef _COSMO_SOURCE +/** + * Returns preferred size and alignment of thread stack. + * + * This will always be equal to `PTHREAD_STACK_MIN`. + */ +#define GetStackSize() 262144 + +/** + * Returns preferred stack guard size. + * + * This is the max cpu page size of supported architectures. + */ +#define GetGuardSize() 16384 + /** * Tunes APE stack maximum size. * @@ -80,20 +94,6 @@ extern char ape_stack_prot[] __attribute__((__weak__)); extern char ape_stack_memsz[] __attribute__((__weak__)); extern char ape_stack_align[] __attribute__((__weak__)); -/** - * Returns preferred size and alignment of thread stack. - * - * This will always be equal to `PTHREAD_STACK_MIN`. - */ -#define GetStackSize() 262144 - -/** - * Returns preferred stack guard size. - * - * This is the max cpu page size of supported architectures. - */ -#define GetGuardSize() 16384 - /** * Returns address of bottom of stack. * @@ -107,6 +107,8 @@ extern char ape_stack_align[] __attribute__((__weak__)); #define GetStackAddr() \ (((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) +#define GetStaticStackSize() ((uintptr_t)ape_stack_memsz) + #ifdef __x86_64__ /** * Returns preferred bottom address of stack. diff --git a/libc/runtime/switchstacks.S b/libc/runtime/switchstacks.S deleted file mode 100644 index 10dd0d1bd..000000000 --- a/libc/runtime/switchstacks.S +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2023 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/macros.internal.h" - -__switch_stacks: -#ifdef __x86_64__ - int3 -#elif defined(__aarch64__) - mov x29,0 - mov sp,x5 - br x4 -#else -#error "unsupported architecture" -#endif - .endfn __switch_stacks,globl diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 8a2ba78ae..bbd739c69 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -22,14 +22,11 @@ #include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/describeflags.internal.h" -#include "libc/intrin/kprintf.h" -#include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" #include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nt/console.h" -#include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/creationdisposition.h" @@ -59,12 +56,8 @@ #ifdef __x86_64__ // clang-format off -__msabi extern typeof(AddVectoredExceptionHandler) *const __imp_AddVectoredExceptionHandler; -__msabi extern typeof(CloseHandle) *const __imp_CloseHandle; -__msabi extern typeof(CreateFile) *const __imp_CreateFileW; __msabi extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW; __msabi extern typeof(DuplicateHandle) *const __imp_DuplicateHandle; -__msabi extern typeof(ExitProcess) *const __imp_ExitProcess; __msabi extern typeof(FreeEnvironmentStrings) *const __imp_FreeEnvironmentStringsW; __msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode; __msabi extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess; @@ -72,21 +65,13 @@ __msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId; __msabi extern typeof(GetEnvironmentStrings) *const __imp_GetEnvironmentStringsW; __msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle; __msabi extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx; -__msabi extern typeof(ReadFile) *const __imp_ReadFile; __msabi extern typeof(SetConsoleCP) *const __imp_SetConsoleCP; __msabi extern typeof(SetConsoleMode) *const __imp_SetConsoleMode; __msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP; __msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle; __msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; -__msabi extern typeof(WriteFile) *const __imp_WriteFile; // clang-format on -/* - * TODO: Why can't we allocate addresses above 4GB on Windows 7 x64? - * TODO: How can we ensure we never overlap with KERNEL32.DLL? - */ - -extern int64_t __wincrashearly; extern const signed char kNtConsoleHandles[3]; extern void cosmo(int, char **, char **, long (*)[2]) wontreturn; @@ -117,55 +102,15 @@ __msabi static inline char16_t *MyCommandLine(void) { return cmd; } -__msabi static inline size_t StrLen16(const char16_t *s) { - size_t n; - for (n = 0;; ++n) { - if (!s[n]) { - return n; - } - } -} - -__msabi static textwindows int OnEarlyWinCrash(struct NtExceptionPointers *ep) { - uint32_t wrote; - char buf[64], *p = buf; - *p++ = 'c'; - *p++ = 'r'; - *p++ = 'a'; - *p++ = 's'; - *p++ = 'h'; - *p++ = ' '; - *p++ = '0'; - *p++ = 'x'; - p = __fixcpy(p, ep->ExceptionRecord->ExceptionCode, 32); - *p++ = ' '; - *p++ = 'r'; - *p++ = 'i'; - *p++ = 'p'; - *p++ = ' '; - p = __fixcpy(p, ep->ContextRecord ? ep->ContextRecord->Rip : -1, 32); - *p++ = '\r'; - *p++ = '\n'; - __imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), buf, p - buf, &wrote, - 0); - __imp_ExitProcess(11); - __builtin_unreachable(); -} - -__msabi static textwindows bool ProxyStdin(void) { - return true; -} - // this ensures close(1) won't accidentally close(2) for example __msabi static textwindows void DeduplicateStdioHandles(void) { - long i, j; int64_t h1, h2, h3, proc; - for (i = 0; i < 3; ++i) { - h1 = __imp_GetStdHandle(kNtConsoleHandles[i]); - for (j = i + 1; j < 3; ++j) { - h3 = h2 = __imp_GetStdHandle(kNtConsoleHandles[j]); + for (long i = 0; i < 3; ++i) { + int64_t h1 = __imp_GetStdHandle(kNtConsoleHandles[i]); + for (long j = i + 1; j < 3; ++j) { + int64_t h2 = __imp_GetStdHandle(kNtConsoleHandles[j]); if (h1 == h2) { - proc = __imp_GetCurrentProcess(); + int64_t h3, proc = __imp_GetCurrentProcess(); __imp_DuplicateHandle(proc, h2, proc, &h3, 0, true, kNtDuplicateSameAccess); __imp_SetStdHandle(kNtConsoleHandles[j], h3); @@ -175,53 +120,35 @@ __msabi static textwindows void DeduplicateStdioHandles(void) { } __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { - bool32 rc; - int64_t h, hand; - uint32_t oldprot; struct WinArgs *wa; - char inflagsbuf[256]; - char outflagsbuf[128]; - const char16_t *env16; - int i, prot, count, version; size_t allocsize, stacksize; - intptr_t stackaddr, allocaddr; - version = NtGetPeb()->OSMajorVersion; + uintptr_t stackaddr, allocaddr; __oldstack = (intptr_t)__builtin_frame_address(0); - if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) { - rc = __imp_SetConsoleCP(kNtCpUtf8); - NTTRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc); - rc = __imp_SetConsoleOutputCP(kNtCpUtf8); - NTTRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc); - for (i = 0; i < 3; ++i) { - hand = __imp_GetStdHandle(kNtConsoleHandles[i]); - rc = __imp_GetConsoleMode(hand, __ntconsolemode + i); - NTTRACE("GetConsoleMode(%p, [%s]) → %hhhd", hand, - i ? (DescribeNtConsoleOutFlags)(outflagsbuf, __ntconsolemode[i]) - : (DescribeNtConsoleInFlags)(inflagsbuf, __ntconsolemode[i]), - rc); - rc = __imp_SetConsoleMode(hand, kConsoleModes[i]); - NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hand, - i ? (DescribeNtConsoleOutFlags)(outflagsbuf, kConsoleModes[i]) - : (DescribeNtConsoleInFlags)(inflagsbuf, kConsoleModes[i]), - rc); + if (NtGetPeb()->OSMajorVersion >= 10 && + (intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui) { + __imp_SetConsoleCP(kNtCpUtf8); + __imp_SetConsoleOutputCP(kNtCpUtf8); + for (int i = 0; i < 3; ++i) { + int64_t hand = __imp_GetStdHandle(kNtConsoleHandles[i]); + __imp_GetConsoleMode(hand, __ntconsolemode + i); + __imp_SetConsoleMode(hand, kConsoleModes[i]); } - (void)rc; } _Static_assert(sizeof(struct WinArgs) % FRAMESIZE == 0, ""); _mmi.p = _mmi.s; _mmi.n = ARRAYLEN(_mmi.s); stackaddr = GetStaticStackAddr(0); - stacksize = GetStackSize(); + stacksize = GetStaticStackSize(); allocaddr = stackaddr; allocsize = stacksize + sizeof(struct WinArgs); - NTTRACE("WinMainNew() mapping %'zu byte stack at %p", allocsize, allocaddr); __imp_MapViewOfFileEx((_mmi.p[0].h = __imp_CreateFileMappingW( -1, &kNtIsInheritable, kNtPageExecuteReadwrite, allocsize >> 32, allocsize, NULL)), kNtFileMapWrite | kNtFileMapExecute, 0, 0, allocsize, (void *)allocaddr); - prot = (intptr_t)ape_stack_prot; + int prot = (intptr_t)ape_stack_prot; if (~prot & PROT_EXEC) { + uint32_t oldprot; __imp_VirtualProtect((void *)allocaddr, allocsize, kNtPageReadwrite, &oldprot); } @@ -232,20 +159,17 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { _mmi.p[0].size = allocsize; _mmi.i = 1; wa = (struct WinArgs *)(allocaddr + stacksize); - NTTRACE("WinMainNew() loading arg block"); - count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), wa->argv, - ARRAYLEN(wa->argv)); - for (i = 0; wa->argv[0][i]; ++i) { + int count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), + wa->argv, ARRAYLEN(wa->argv)); + for (int i = 0; wa->argv[0][i]; ++i) { if (wa->argv[0][i] == '\\') { wa->argv[0][i] = '/'; } } - env16 = __imp_GetEnvironmentStringsW(); - NTTRACE("WinMainNew() loading environment"); + const char16_t *env16 = __imp_GetEnvironmentStringsW(); GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp, ARRAYLEN(wa->envp) - 1); __imp_FreeEnvironmentStringsW(env16); - NTTRACE("WinMainNew() switching stacks"); _jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo, count, wa->argv, wa->envp, wa->auxv); } @@ -261,16 +185,11 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, if (_weaken(WinMainStdin)) { _weaken(WinMainStdin)(); } -#if !IsTiny() - __wincrashearly = - __imp_AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash); -#endif cmdline = MyCommandLine(); #ifdef SYSDEBUG /* sloppy flag-only check for early initialization */ if (__strstr16(cmdline, u"--strace")) ++__strace; #endif - NTTRACE("WinMain()"); if (_weaken(WinSockInit)) { _weaken(WinSockInit)(); } diff --git a/libc/runtime/zipos-get.c b/libc/runtime/zipos-get.c index b5a1b8ae7..4fdf35a20 100644 --- a/libc/runtime/zipos-get.c +++ b/libc/runtime/zipos-get.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/metalfile.internal.h" +#include "libc/calls/struct/stat.h" #include "libc/fmt/conv.h" #include "libc/intrin/cmpxchg.h" #include "libc/intrin/kprintf.h" @@ -26,6 +27,7 @@ #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/zipos.internal.h" +#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" @@ -64,19 +66,19 @@ static void __zipos_munmap_unneeded(const uint8_t *base, const uint8_t *cdir, */ struct Zipos *__zipos_get(void) { char *endptr; - ssize_t size; - int fd, err, msg; + struct stat st; static bool once; struct Zipos *res; + int x, fd, err, msg; uint8_t *map, *cdir; const char *progpath; static struct Zipos zipos; __zipos_lock(); if (!once) { - progpath = getenv("COSMOPOLITAN_INIT_ZIPOS"); - if (progpath) { - fd = strtol(progpath, &endptr, 10); - if (*endptr) fd = -1; + // this environment variable may be a filename or file descriptor + if ((progpath = getenv("COSMOPOLITAN_INIT_ZIPOS")) && + (x = strtol(progpath, &endptr, 10)) >= 0 && !*endptr) { + fd = x; } else { fd = -1; } @@ -88,16 +90,16 @@ struct Zipos *__zipos_get(void) { fd = open(progpath, O_RDONLY); } if (fd != -1) { - if ((size = lseek(fd, 0, SEEK_END)) != -1 && - (map = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0)) != - MAP_FAILED) { - if ((cdir = GetZipEocd(map, size, &err))) { + if (!fstat(fd, &st) && (map = mmap(0, st.st_size, PROT_READ, + MAP_PRIVATE, fd, 0)) != MAP_FAILED) { + if ((cdir = GetZipEocd(map, st.st_size, &err))) { __zipos_munmap_unneeded(map, cdir, map); zipos.map = map; zipos.cdir = cdir; + zipos.dev = st.st_ino; msg = kZipOk; } else { - munmap(map, size); + munmap(map, st.st_size); msg = !cdir ? err : kZipErrorRaceCondition; } } else { diff --git a/libc/runtime/zipos-stat-impl.c b/libc/runtime/zipos-stat-impl.c index 61b0f2e7f..b11713275 100644 --- a/libc/runtime/zipos-stat-impl.c +++ b/libc/runtime/zipos-stat-impl.c @@ -21,27 +21,26 @@ #include "libc/runtime/zipos.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/s.h" -#include "libc/sysv/errfuns.h" #include "libc/zip.internal.h" int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) { size_t lf; - if (zipos && st) { - bzero(st, sizeof(*st)); - if (cf == ZIPOS_SYNTHETIC_DIRECTORY) { - st->st_mode = S_IFDIR | 0555; - } else { - lf = GetZipCfileOffset(zipos->map + cf); - st->st_mode = GetZipCfileMode(zipos->map + cf); - st->st_size = GetZipLfileUncompressedSize(zipos->map + lf); - st->st_blocks = - roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512; - GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim, - &st->st_ctim, 0); - st->st_birthtim = st->st_ctim; - } - return 0; + bzero(st, sizeof(*st)); + st->st_ino = cf; + st->st_nlink = 1; + st->st_dev = zipos->dev; + st->st_blksize = FRAMESIZE; + if (cf == ZIPOS_SYNTHETIC_DIRECTORY) { + st->st_mode = S_IFDIR | 0555; } else { - return einval(); + lf = GetZipCfileOffset(zipos->map + cf); + st->st_mode = GetZipCfileMode(zipos->map + cf); + st->st_size = GetZipLfileUncompressedSize(zipos->map + lf); + st->st_blocks = + roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512; + GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim, + &st->st_ctim, 0); + st->st_birthtim = st->st_ctim; } + return 0; } diff --git a/libc/runtime/zipos.internal.h b/libc/runtime/zipos.internal.h index cddb10cde..a5f666962 100644 --- a/libc/runtime/zipos.internal.h +++ b/libc/runtime/zipos.internal.h @@ -34,6 +34,7 @@ struct ZiposHandle { struct Zipos { uint8_t *map; uint8_t *cdir; + uint64_t dev; struct ZiposHandle *freelist; }; diff --git a/libc/stdio/dirstream.c b/libc/stdio/dirstream.c index d9b308b40..64d95494a 100644 --- a/libc/stdio/dirstream.c +++ b/libc/stdio/dirstream.c @@ -25,13 +25,19 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/kprintf.h" -#include "libc/intrin/nopl.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" +#include "libc/macros.internal.h" +#include "libc/mem/critbit0.h" #include "libc/mem/mem.h" +#include "libc/nt/createfile.h" +#include "libc/nt/enum/accessmask.h" +#include "libc/nt/enum/creationdisposition.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" +#include "libc/nt/runtime.h" +#include "libc/nt/struct/byhandlefileinformation.h" #include "libc/nt/struct/win32finddata.h" #include "libc/runtime/zipos.internal.h" #include "libc/str/str.h" @@ -60,18 +66,20 @@ int sys_getdents(unsigned, void *, unsigned, long *); struct dirstream { int fd; bool iszip; + long tell; int64_t hand; - int64_t tell; - char16_t *name; pthread_mutex_t lock; - struct { - uint64_t offset; - uint64_t records; - size_t prefixlen; - uint8_t prefix[ZIPOS_PATH_MAX]; - } zip; struct dirent ent; union { + struct { + struct Zipos *zipos; + uint64_t inode; + uint64_t offset; + uint64_t records; + size_t prefixlen; + uint8_t prefix[ZIPOS_PATH_MAX]; + struct critbit0 found; + } zip; struct { unsigned buf_pos; unsigned buf_end; @@ -80,6 +88,8 @@ struct dirstream { struct { bool isdone; struct NtWin32FindData windata; + char16_t name16[PATH_MAX]; + uint32_t name16len; }; }; }; @@ -119,69 +129,40 @@ struct dirent_netbsd { char d_name[512]; }; -// TODO(jart): wipe these locks when forking - -void _lockdir(DIR *dir) { - pthread_mutex_lock(&dir->lock); -} - -void _unlockdir(DIR *dir) { - pthread_mutex_unlock(&dir->lock); -} - -#ifdef _NOPL1 -#define _lockdir(d) _NOPL1("__threadcalls", _lockdir, d) -#define _unlockdir(d) _NOPL1("__threadcalls", _unlockdir, d) -#else -#define _lockdir(d) (__threaded ? _lockdir(d) : 0) -#define _unlockdir(d) (__threaded ? _unlockdir(d) : 0) -#endif - -static textwindows DIR *opendir_nt_impl(char16_t *name, size_t len) { - DIR *res; - if (len + 2 + 1 <= PATH_MAX) { - if (len == 1 && name[0] == '.') { - name[0] = '*'; - } else { - if (len > 1 && name[len - 1] != u'\\') { - name[len++] = u'\\'; - } - name[len++] = u'*'; - } - name[len] = u'\0'; - if ((res = calloc(1, sizeof(DIR)))) { - if ((res->hand = FindFirstFile(name, &res->windata)) != -1) { - return res; - } - __fix_enotdir(-1, name); - free(res); - } - } else { - enametoolong(); +static void _lockdir(DIR *dir) { + if (__threaded) { + pthread_mutex_lock(&dir->lock); } - return NULL; } -static textwindows dontinline DIR *fdopendir_nt(int fd) { - DIR *res; - char16_t *name; - if (__isfdkind(fd, kFdFile)) { - if ((name = calloc(1, PATH_MAX * 2))) { - if ((res = opendir_nt_impl( - name, GetFinalPathNameByHandle( - g_fds.p[fd].handle, name, PATH_MAX, - kNtFileNameNormalized | kNtVolumeNameDos)))) { - res->name = name; - res->fd = -1; - close(fd); - return res; - } - free(name); - } - } else { - ebadf(); +static void _unlockdir(DIR *dir) { + if (__threaded) { + pthread_mutex_unlock(&dir->lock); } - return NULL; +} + +static textwindows dontinline int fdopendir_nt(DIR *res, int fd) { + if (!__isfdkind(fd, kFdFile)) { + return ebadf(); + } + res->name16len = GetFinalPathNameByHandle( + g_fds.p[fd].handle, res->name16, ARRAYLEN(res->name16), + kNtFileNameNormalized | kNtVolumeNameDos); + if (!res->name16len) { + return __winerr(); + } + if (res->name16len + 2 + 1 > ARRAYLEN(res->name16)) { + return enametoolong(); + } + if (res->name16len > 1 && res->name16[res->name16len - 1] != u'\\') { + res->name16[res->name16len++] = u'\\'; + } + res->name16[res->name16len++] = u'*'; + res->name16[res->name16len] = u'\0'; + if ((res->hand = FindFirstFile(res->name16, &res->windata)) == -1) { + return __fix_enotdir(-1, res->name16); + } + return 0; } static textwindows uint8_t GetNtDirentType(struct NtWin32FindData *w) { @@ -204,26 +185,57 @@ static textwindows uint8_t GetNtDirentType(struct NtWin32FindData *w) { } static textwindows dontinline struct dirent *readdir_nt(DIR *dir) { - size_t i; - if (!dir->isdone) { - bzero(&dir->ent, sizeof(dir->ent)); - dir->ent.d_ino++; - dir->ent.d_off = dir->tell++; - dir->ent.d_reclen = - tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name) - 2, - dir->windata.cFileName) - .ax; - for (i = 0; i < dir->ent.d_reclen; ++i) { - if (dir->ent.d_name[i] == '\\') { - dir->ent.d_name[i] = '/'; - } - } - dir->ent.d_type = GetNtDirentType(&dir->windata); - dir->isdone = !FindNextFile(dir->hand, &dir->windata); - return &dir->ent; - } else { + if (dir->isdone) { return NULL; } + + // join absolute path + uint64_t ino = 0; + size_t i = dir->name16len - 1; + char16_t *p = dir->windata.cFileName; + while (*p) { + if (i + 1 < ARRAYLEN(dir->name16)) { + dir->name16[i++] = *p++; + } else { + // ignore errors and set inode to zero + goto GiveUpOnGettingInode; + } + } + dir->name16[i] = u'\0'; + + // get inode that's consistent with stat() + int e = errno; + int64_t fh = + CreateFile(dir->name16, kNtFileReadAttributes, 0, 0, kNtOpenExisting, + kNtFileAttributeNormal | kNtFileFlagBackupSemantics | + kNtFileFlagOpenReparsePoint, + 0); + if (fh != -1) { + struct NtByHandleFileInformation wst; + if (GetFileInformationByHandle(fh, &wst)) { + ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow; + } + CloseHandle(fh); + } else { + // ignore errors and set inode to zero + // TODO(jart): How do we handle "." and ".."? + errno = e; + } + +GiveUpOnGettingInode: + // restore original directory search path + dir->name16[dir->name16len - 1] = u'*'; + dir->name16[dir->name16len] = u'\0'; + + // create result object + bzero(&dir->ent, sizeof(dir->ent)); + dir->ent.d_ino = ino; + dir->ent.d_off = dir->tell++; + tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name), + dir->windata.cFileName); + dir->ent.d_type = GetNtDirentType(&dir->windata); + dir->isdone = !FindNextFile(dir->hand, &dir->windata); + return &dir->ent; } /** @@ -246,8 +258,12 @@ DIR *fdopendir(int fd) { dir->fd = fd; if (!__isfdkind(fd, kFdZip)) { if (IsWindows()) { - free(dir); - return fdopendir_nt(fd); + if (!fdopendir_nt(dir, fd)) { + return dir; + } else { + free(dir); + return 0; + } } return dir; } @@ -285,6 +301,8 @@ DIR *fdopendir(int fd) { dir->zip.prefixlen = len; // setup state values for directory iterator + dir->zip.zipos = h->zipos; + dir->zip.inode = h->cfile; dir->zip.offset = GetZipCdirOffset(h->zipos->cdir); dir->zip.records = GetZipCdirRecords(h->zipos->cdir); @@ -325,124 +343,123 @@ DIR *opendir(const char *name) { return res; } -static struct dirent *readdir_impl(DIR *dir) { - size_t n; - int rc, mode; - uint8_t *s, *p; - struct Zipos *zip; - struct dirent *ent; - struct dirent *lastent; - struct dirent_bsd *bsd; - struct dirent_netbsd *nbsd; - struct dirent_openbsd *obsd; - if (dir->iszip) { - ent = 0; - zip = _weaken(__zipos_get)(); - while (!ent && dir->tell < dir->zip.records + 2) { - if (!dir->tell) { - ent = (struct dirent *)dir->buf; - ent->d_ino++; - ent->d_off = dir->tell; - ent->d_reclen = 1; - ent->d_type = DT_DIR; - strcpy(ent->d_name, "."); - } else if (dir->tell == 1) { - ent = (struct dirent *)dir->buf; - ent->d_ino++; - ent->d_off = dir->tell; - ent->d_reclen = 2; - ent->d_type = DT_DIR; - strcpy(ent->d_name, ".."); - } else { - s = ZIP_CFILE_NAME(zip->map + dir->zip.offset); - n = ZIP_CFILE_NAMESIZE(zip->map + dir->zip.offset); - if (dir->zip.prefixlen < n && - !memcmp(dir->zip.prefix, s, dir->zip.prefixlen)) { - s += dir->zip.prefixlen; - n -= dir->zip.prefixlen; - p = memchr(s, '/', n); - if (!p || p + 1 - s == n) { - if (p + 1 - s == n) --n; - mode = GetZipCfileMode(zip->map + dir->zip.offset); - ent = (struct dirent *)dir->buf; - ent->d_ino++; - ent->d_off = dir->tell; - ent->d_reclen = MIN(n, 255); - ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG; - if (ent->d_reclen) { - memcpy(ent->d_name, s, ent->d_reclen); - } - ent->d_name[ent->d_reclen] = 0; - } else { - lastent = (struct dirent *)dir->buf; - n = p - s; - n = MIN(n, 255); - if (!lastent->d_ino || (n != lastent->d_reclen) || - memcmp(lastent->d_name, s, n)) { - ent = lastent; - mode = GetZipCfileMode(zip->map + dir->zip.offset); - ent->d_ino++; - ent->d_off = dir->tell; - ent->d_reclen = n; - ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG; - if (ent->d_reclen) { - memcpy(ent->d_name, s, ent->d_reclen); - } - ent->d_name[ent->d_reclen] = 0; - } - } - } - dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset); - } - dir->tell++; - } - return ent; - } else if (!IsWindows()) { - if (dir->buf_pos >= dir->buf_end) { - long basep = dir->tell; - rc = sys_getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep); - STRACE("sys_getdents(%d) → %d% m", dir->fd, rc); - if (!rc || rc == -1) return NULL; - dir->buf_pos = 0; - dir->buf_end = rc; - } - if (IsLinux()) { - ent = (struct dirent *)((char *)dir->buf + dir->buf_pos); - dir->buf_pos += ent->d_reclen; - dir->tell = ent->d_off; - } else if (IsOpenbsd()) { - obsd = (struct dirent_openbsd *)((char *)dir->buf + dir->buf_pos); - dir->buf_pos += obsd->d_reclen; - dir->tell = obsd->d_off; +static struct dirent *readdir_zipos(DIR *dir) { + struct dirent *ent = 0; + while (!ent && dir->tell < dir->zip.records + 2) { + size_t n; + if (!dir->tell) { 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 if (IsNetbsd()) { - nbsd = (struct dirent_netbsd *)((char *)dir->buf + dir->buf_pos); - dir->buf_pos += nbsd->d_reclen; + ent->d_off = dir->tell; + ent->d_ino = dir->zip.inode; + ent->d_type = DT_DIR; + ent->d_name[0] = '.'; + ent->d_name[1] = 0; + n = 1; + } else if (dir->tell == 1) { ent = &dir->ent; - ent->d_ino = nbsd->d_fileno; - ent->d_off = (dir->tell += nbsd->d_reclen); - ent->d_reclen = nbsd->d_reclen; - ent->d_type = nbsd->d_type; - memcpy(ent->d_name, nbsd->d_name, MAX(256, nbsd->d_namlen + 1)); + ent->d_off = dir->tell; + ent->d_ino = 0; // TODO + ent->d_type = DT_DIR; + ent->d_name[0] = '.'; + ent->d_name[1] = '.'; + ent->d_name[2] = 0; + n = 2; } else { - bsd = (struct dirent_bsd *)((char *)dir->buf + dir->buf_pos); - dir->buf_pos += bsd->d_reclen; - ent = &dir->ent; - ent->d_ino = bsd->d_fileno; - ent->d_off = dir->tell++; - ent->d_reclen = bsd->d_reclen; - ent->d_type = bsd->d_type; - memcpy(ent->d_name, bsd->d_name, bsd->d_namlen + 1); + uint8_t *s = ZIP_CFILE_NAME(dir->zip.zipos->map + dir->zip.offset); + n = ZIP_CFILE_NAMESIZE(dir->zip.zipos->map + dir->zip.offset); + if (n > dir->zip.prefixlen && + !memcmp(dir->zip.prefix, s, dir->zip.prefixlen)) { + s += dir->zip.prefixlen; + n -= dir->zip.prefixlen; + uint8_t *p = memchr(s, '/', n); + if (p) n = p - s; + if ((n = MIN(n, sizeof(ent->d_name) - 1)) && + critbit0_emplace(&dir->zip.found, s, n) == 1) { + ent = &dir->ent; + ent->d_ino = dir->zip.offset; + ent->d_off = dir->tell; + ent->d_type = + S_ISDIR(GetZipCfileMode(dir->zip.zipos->map + dir->zip.offset)) + ? DT_DIR + : DT_REG; + memcpy(ent->d_name, s, n); + ent->d_name[n] = 0; + } + } + dir->zip.offset += + ZIP_CFILE_HDRSIZE(dir->zip.zipos->map + dir->zip.offset); } - return ent; + dir->tell++; + } + return ent; +} + +static struct dirent *readdir_unix(DIR *dir) { + if (dir->buf_pos >= dir->buf_end) { + long basep = dir->tell; + int rc = sys_getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep); + STRACE("sys_getdents(%d) → %d% m", dir->fd, rc); + if (!rc || rc == -1) { + return NULL; + } + dir->buf_pos = 0; + dir->buf_end = rc; + } + struct dirent *ent; + if (IsLinux()) { + ent = (struct dirent *)((char *)dir->buf + dir->buf_pos); + dir->buf_pos += ent->d_reclen; + dir->tell = ent->d_off; + } else if (IsOpenbsd()) { + struct dirent_openbsd *obsd = + (struct dirent_openbsd *)((char *)dir->buf + dir->buf_pos); + dir->buf_pos += obsd->d_reclen; + dir->tell = obsd->d_off; + 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 if (IsNetbsd()) { + struct dirent_netbsd *nbsd = + (struct dirent_netbsd *)((char *)dir->buf + dir->buf_pos); + dir->buf_pos += nbsd->d_reclen; + ent = &dir->ent; + ent->d_ino = nbsd->d_fileno; + ent->d_off = (dir->tell += nbsd->d_reclen); + ent->d_reclen = nbsd->d_reclen; + ent->d_type = nbsd->d_type; + size_t n = + MIN(nbsd->d_namlen, MIN(sizeof(ent->d_name) - 1, sizeof(nbsd->d_name))); + memcpy(ent->d_name, nbsd->d_name, n); + ent->d_name[n] = 0; } else { + struct dirent_bsd *bsd = + (struct dirent_bsd *)((char *)dir->buf + dir->buf_pos); + dir->buf_pos += bsd->d_reclen; + ent = &dir->ent; + ent->d_ino = bsd->d_fileno; + ent->d_off = dir->tell++; + ent->d_reclen = bsd->d_reclen; + ent->d_type = bsd->d_type; + memcpy(ent->d_name, bsd->d_name, bsd->d_namlen + 1); + } + if (ent) { + ent->d_reclen = + ROUNDUP(offsetof(struct dirent, d_name) + strlen(ent->d_name) + 1, 8); + } + return ent; +} + +static struct dirent *readdir_impl(DIR *dir) { + if (dir->iszip) { + return readdir_zipos(dir); + } + if (IsWindows()) { return readdir_nt(dir); } + return readdir_unix(dir); } /** @@ -509,10 +526,12 @@ errno_t readdir_r(DIR *dir, struct dirent *output, struct dirent **result) { int closedir(DIR *dir) { int rc = 0; if (dir) { + if (dir->iszip) { + critbit0_clear(&dir->zip.found); + } if (dir->fd != -1) { rc |= close(dir->fd); } - free(dir->name); if (IsWindows() && !dir->iszip) { if (!FindClose(dir->hand)) { rc = __winerr(); @@ -540,11 +559,7 @@ long telldir(DIR *dir) { * @threadsafe */ int dirfd(DIR *dir) { - int rc; - _lockdir(dir); - rc = dir->fd; - _unlockdir(dir); - return rc; + return dir->fd; } /** @@ -554,8 +569,9 @@ int dirfd(DIR *dir) { void rewinddir(DIR *dir) { _lockdir(dir); if (dir->iszip) { + critbit0_clear(&dir->zip.found); dir->tell = 0; - dir->zip.offset = GetZipCdirOffset(_weaken(__zipos_get)()->cdir); + dir->zip.offset = GetZipCdirOffset(dir->zip.zipos->cdir); } else if (!IsWindows()) { if (!lseek(dir->fd, 0, SEEK_SET)) { dir->buf_pos = dir->buf_end = 0; @@ -563,7 +579,7 @@ void rewinddir(DIR *dir) { } } else { FindClose(dir->hand); - if ((dir->hand = FindFirstFile(dir->name, &dir->windata)) != -1) { + if ((dir->hand = FindFirstFile(dir->name16, &dir->windata)) != -1) { dir->isdone = false; dir->tell = 0; } else { @@ -577,27 +593,26 @@ void rewinddir(DIR *dir) { * Seeks in directory stream. * @threadsafe */ -void seekdir(DIR *dir, long off) { - long i; - struct Zipos *zip; +void seekdir(DIR *dir, long tell) { _lockdir(dir); - zip = _weaken(__zipos_get)(); if (dir->iszip) { - dir->zip.offset = GetZipCdirOffset(_weaken(__zipos_get)()->cdir); - for (i = 0; i < off && i < dir->zip.records; ++i) { - if (i >= 2) { - dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset); + critbit0_clear(&dir->zip.found); + dir->tell = 0; + dir->zip.offset = GetZipCdirOffset(dir->zip.zipos->cdir); + while (dir->tell < tell) { + if (!readdir_zipos(dir)) { + break; } } } else if (!IsWindows()) { - i = lseek(dir->fd, off, SEEK_SET); + dir->tell = lseek(dir->fd, tell, SEEK_SET); dir->buf_pos = dir->buf_end = 0; } else { - i = 0; + dir->tell = 0; dir->isdone = false; FindClose(dir->hand); - if ((dir->hand = FindFirstFile(dir->name, &dir->windata)) != -1) { - for (; i < off; ++i) { + if ((dir->hand = FindFirstFile(dir->name16, &dir->windata)) != -1) { + for (; dir->tell < tell; ++dir->tell) { if (!FindNextFile(dir->hand, &dir->windata)) { dir->isdone = true; break; @@ -607,7 +622,6 @@ void seekdir(DIR *dir, long off) { dir->isdone = true; } } - dir->tell = i; _unlockdir(dir); } diff --git a/libc/stdio/stdio.mk b/libc/stdio/stdio.mk index 8794cfcd8..7e9e08069 100644 --- a/libc/stdio/stdio.mk +++ b/libc/stdio/stdio.mk @@ -56,6 +56,7 @@ o//libc/stdio/appendw.o: private \ CFLAGS += \ -Os +o/$(MODE)/libc/stdio/dirstream.o \ o/$(MODE)/libc/stdio/posix_spawnattr.o \ o/$(MODE)/libc/stdio/posix_spawn_file_actions.o \ o/$(MODE)/libc/stdio/mt19937.o: private \ diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 2a0fd647f..c3d56cd0a 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -458,7 +458,7 @@ syscon auxv AT_NO_AUTOMOUNT 0x0800 0x0800 0 0 0 0x0800 0 0x0800 syscon rlimit RLIMIT_CPU 0 0 0 0 0 0 0 127 # max cpu time in seconds; see SIGXCPU; unix consensus syscon rlimit RLIMIT_FSIZE 1 1 1 1 1 1 1 127 # max file size in bytes; unix consensus syscon rlimit RLIMIT_DATA 2 2 2 2 2 2 2 127 # max mmap() / brk() / sbrk() size in bytes; unix consensus -syscon rlimit RLIMIT_STACK 3 3 3 3 3 3 3 127 # max stack size in bytes; see SIGXFSZ; unix consensus +syscon rlimit RLIMIT_STACK 3 3 3 3 3 3 3 1 # max stack size in bytes; see SIGXFSZ; unix consensus syscon rlimit RLIMIT_CORE 4 4 4 4 4 4 4 127 # max core file size in bytes; unix consensus syscon rlimit RLIMIT_RSS 5 5 5 5 5 5 5 127 # max physical memory size in bytes; see mmap()→ENOMEM; unix consensus syscon rlimit RLIMIT_NPROC 6 6 7 7 7 7 7 127 # max number of processes; see fork()→EAGAIN; bsd consensus @@ -479,7 +479,7 @@ syscon compat RLIMIT_VMEM 9 9 5 5 10 127 10 127 # same as RLI # resource limit special values # # group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon rlim RLIM_NLIMITS 16 16 9 9 15 9 12 1 +syscon rlim RLIM_NLIMITS 16 16 9 9 15 9 12 2 syscon rlim RLIM_INFINITY 0xffffffffffffffff 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0xffffffffffffffff syscon rlim RLIM_SAVED_CUR 0xffffffffffffffff 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0xffffffffffffffff syscon rlim RLIM_SAVED_MAX 0xffffffffffffffff 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff 0xffffffffffffffff diff --git a/libc/sysv/consts/RLIMIT_STACK.S b/libc/sysv/consts/RLIMIT_STACK.S index b902f213e..59ca2ee9e 100644 --- a/libc/sysv/consts/RLIMIT_STACK.S +++ b/libc/sysv/consts/RLIMIT_STACK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlimit,RLIMIT_STACK,3,3,3,3,3,3,3,127 +.syscon rlimit,RLIMIT_STACK,3,3,3,3,3,3,3,1 diff --git a/libc/sysv/consts/RLIM_NLIMITS.S b/libc/sysv/consts/RLIM_NLIMITS.S index 134c8c33f..c5b1b8483 100644 --- a/libc/sysv/consts/RLIM_NLIMITS.S +++ b/libc/sysv/consts/RLIM_NLIMITS.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon rlim,RLIM_NLIMITS,16,16,9,9,15,9,12,1 +.syscon rlim,RLIM_NLIMITS,16,16,9,9,15,9,12,2 diff --git a/libc/x/x.h b/libc/x/x.h index 5de249497..1c073ba25 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -52,7 +52,7 @@ void *xrealloc(void *, size_t) attributeallocsize((2)) dontthrow nocallback dontdiscard; void *xcalloc(size_t, size_t) attributeallocsize((1, 2)) returnspointerwithnoaliases dontthrow nocallback dontdiscard returnsnonnull; -void *xvalloc(size_t) attributeallocsize((1)) returnsaligned((APE_PAGESIZE)) +void *xvalloc(size_t) attributeallocsize((1)) returnsaligned((65536)) returnspointerwithnoaliases dontthrow nocallback dontdiscard returnsnonnull; void *xmemalign(size_t, size_t) attributeallocalign((1)) attributeallocsize((2)) returnspointerwithnoaliases dontthrow nocallback dontdiscard returnsnonnull; diff --git a/test/libc/calls/ioctl_test.c b/test/libc/calls/ioctl_test.c index 78d048aaf..f667220ff 100644 --- a/test/libc/calls/ioctl_test.c +++ b/test/libc/calls/ioctl_test.c @@ -19,7 +19,6 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/intrin/bits.h" -#include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/mem/gc.internal.h" diff --git a/test/libc/calls/lock_test.c b/test/libc/calls/lock_test.c index 6b59c2f0e..9afe24bec 100644 --- a/test/libc/calls/lock_test.c +++ b/test/libc/calls/lock_test.c @@ -20,7 +20,6 @@ #include "libc/calls/struct/flock.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/f.h" diff --git a/test/libc/calls/pledge_test.c b/test/libc/calls/pledge_test.c index ae24dc873..7791a9d78 100644 --- a/test/libc/calls/pledge_test.c +++ b/test/libc/calls/pledge_test.c @@ -29,7 +29,6 @@ #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/internal.h" diff --git a/test/libc/calls/timespec_test.c b/test/libc/calls/timespec_test.c index e6caabb0a..e9564226a 100644 --- a/test/libc/calls/timespec_test.c +++ b/test/libc/calls/timespec_test.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timeval.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/stdio/rand.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/intrin/dos2errno_test.c b/test/libc/intrin/dos2errno_test.c index 39e675711..686b30838 100644 --- a/test/libc/intrin/dos2errno_test.c +++ b/test/libc/intrin/dos2errno_test.c @@ -19,7 +19,6 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/dos2errno.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/nt/errors.h" #include "libc/sock/internal.h" #include "libc/str/str.h" diff --git a/test/libc/intrin/pthread_spin_lock_test.c b/test/libc/intrin/pthread_spin_lock_test.c index 62260f96a..f832573ed 100644 --- a/test/libc/intrin/pthread_spin_lock_test.c +++ b/test/libc/intrin/pthread_spin_lock_test.c @@ -19,7 +19,6 @@ #include "libc/atomic.h" #include "libc/calls/struct/timespec.h" #include "libc/intrin/atomic.h" -#include "libc/intrin/kprintf.h" #include "libc/testlib/testlib.h" #include "libc/thread/thread.h" #include "third_party/zip/zip.h" diff --git a/test/libc/log/backtrace_test.c b/test/libc/log/backtrace_test.c index 5589a68ba..9b541fe53 100644 --- a/test/libc/log/backtrace_test.c +++ b/test/libc/log/backtrace_test.c @@ -22,7 +22,6 @@ #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/intrin/asan.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/libfatal.internal.h" #include "libc/log/log.h" diff --git a/test/libc/mem/critbit0_test.c b/test/libc/mem/critbit0_test.c index b193be932..0353de4ff 100644 --- a/test/libc/mem/critbit0_test.c +++ b/test/libc/mem/critbit0_test.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/critbit0.h" #include "libc/intrin/bits.h" #include "libc/mem/critbit0.h" #include "libc/mem/mem.h" @@ -128,3 +129,10 @@ TEST(critbit0, testAllPrefixed_haltOnNonzero) { critbit0_clear(tree); FreeBog(&a); } + +TEST(critbit0, duplicate) { + struct critbit0 tree = {0}; + ASSERT_TRUE(critbit0_insert(&tree, "hi")); + ASSERT_FALSE(critbit0_insert(&tree, "hi")); + critbit0_clear(&tree); +} diff --git a/test/libc/runtime/daemon_test.c b/test/libc/runtime/daemon_test.c index b06ca4fc3..3e5ccd4c8 100644 --- a/test/libc/runtime/daemon_test.c +++ b/test/libc/runtime/daemon_test.c @@ -19,7 +19,6 @@ #include "libc/calls/calls.h" #include "libc/calls/struct/sigset.h" #include "libc/dce.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" diff --git a/test/libc/runtime/fork_test.c b/test/libc/runtime/fork_test.c index df20517c5..ed7f6039f 100644 --- a/test/libc/runtime/fork_test.c +++ b/test/libc/runtime/fork_test.c @@ -23,7 +23,6 @@ #include "libc/calls/struct/timespec.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" diff --git a/test/libc/runtime/grow_test.c b/test/libc/runtime/grow_test.c index 0564b7c52..b1889081f 100644 --- a/test/libc/runtime/grow_test.c +++ b/test/libc/runtime/grow_test.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/kprintf.h" #include "libc/intrin/pushpop.internal.h" #include "libc/limits.h" #include "libc/macros.internal.h" diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index 3fce7930b..494b35c70 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -25,7 +25,6 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/atomic.h" #include "libc/intrin/bits.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/safemacros.internal.h" #include "libc/intrin/xchg.internal.h" #include "libc/log/log.h" diff --git a/test/libc/runtime/munmap_test.c b/test/libc/runtime/munmap_test.c index efb39f84e..b29bf5d88 100644 --- a/test/libc/runtime/munmap_test.c +++ b/test/libc/runtime/munmap_test.c @@ -19,7 +19,6 @@ #include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/log/log.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/map.h" diff --git a/test/libc/sock/nonblock_test.c b/test/libc/sock/nonblock_test.c index 498a20f56..193565436 100644 --- a/test/libc/sock/nonblock_test.c +++ b/test/libc/sock/nonblock_test.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/strace.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/syslib.internal.h" diff --git a/test/libc/sock/sendfile_test.c b/test/libc/sock/sendfile_test.c index 72b903fe2..f768891ab 100644 --- a/test/libc/sock/sendfile_test.c +++ b/test/libc/sock/sendfile_test.c @@ -20,7 +20,6 @@ #include "libc/calls/struct/sigaction.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/mem/gc.internal.h" #include "libc/mem/mem.h" diff --git a/test/libc/stdio/dirstream_test.c b/test/libc/stdio/dirstream_test.c index 82730e5d6..3b875f64f 100644 --- a/test/libc/stdio/dirstream_test.c +++ b/test/libc/stdio/dirstream_test.c @@ -21,7 +21,7 @@ #include "libc/calls/struct/stat.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" +#include "libc/fmt/fmt.h" #include "libc/mem/gc.h" #include "libc/mem/gc.internal.h" #include "libc/runtime/runtime.h" @@ -35,6 +35,7 @@ #include "libc/x/xiso8601.h" __static_yoink("zipos"); +__static_yoink("usr/share/zoneinfo/"); __static_yoink("usr/share/zoneinfo/New_York"); char testlib_enable_tmp_setup_teardown; @@ -248,5 +249,75 @@ TEST(dirstream, seek) { ASSERT_NE(NULL, (ent = readdir(dir))); // #3 ASSERT_NE(NULL, (ent = readdir(dir))); // #4 ASSERT_EQ(NULL, (ent = readdir(dir))); // eod + ASSERT_EQ(NULL, (ent = readdir(dir))); // eod + ASSERT_SYS(0, 0, closedir(dir)); +} + +TEST(dirstream, ino) { + if (IsNetbsd()) return; // omg + ASSERT_SYS(0, 0, mkdir("boop", 0755)); + EXPECT_SYS(0, 0, touch("boop/a", 0644)); + EXPECT_SYS(0, 0, touch("boop/b", 0644)); + EXPECT_SYS(0, 0, touch("boop/c", 0644)); + ASSERT_NE(NULL, (dir = opendir("boop"))); + ASSERT_NE(NULL, (ent = readdir(dir))); // #1 + ASSERT_NE(NULL, (ent = readdir(dir))); // #2 + long pos = telldir(dir); + ASSERT_NE(NULL, (ent = readdir(dir))); // #3 + char name[32]; + strlcpy(name, ent->d_name, sizeof(name)); + ASSERT_NE(NULL, (ent = readdir(dir))); // #4 + ASSERT_NE(NULL, (ent = readdir(dir))); // #5 + ASSERT_EQ(NULL, (ent = readdir(dir))); // eod + seekdir(dir, pos); + ASSERT_NE(NULL, (ent = readdir(dir))); // #2 + ASSERT_STREQ(name, ent->d_name); + ASSERT_NE(NULL, (ent = readdir(dir))); // #3 + ASSERT_NE(NULL, (ent = readdir(dir))); // #4 + ASSERT_EQ(NULL, (ent = readdir(dir))); // eod + ASSERT_EQ(NULL, (ent = readdir(dir))); // eod + ASSERT_SYS(0, 0, closedir(dir)); +} + +TEST(dirstream, dots) { + bool got_dot = false; + bool got_dot_dot = false; + ASSERT_NE(NULL, (dir = opendir("."))); + while ((ent = readdir(dir))) { + got_dot |= !strcmp(ent->d_name, "."); + got_dot_dot |= !strcmp(ent->d_name, ".."); + } + ASSERT_SYS(0, 0, closedir(dir)); + ASSERT_TRUE(got_dot_dot); + ASSERT_TRUE(got_dot); +} + +TEST(dirstream, inoFile_isConsistentWithStat) { + struct stat st; + bool gotsome = false; + EXPECT_SYS(0, 0, touch("foo", 0644)); + EXPECT_SYS(0, 0, stat("foo", &st)); + ASSERT_NE(NULL, (dir = opendir("."))); + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, "foo")) { + ASSERT_EQ(st.st_ino, ent->d_ino); + gotsome = true; + } + } + ASSERT_SYS(0, 0, closedir(dir)); + ASSERT_TRUE(gotsome); +} + +TEST(dirstream_zipos, inoFile_isConsistentWithStat) { + struct stat st; + const char *dirpath; + char filename[PATH_MAX]; + dirpath = "/zip/usr/share/zoneinfo"; + ASSERT_NE(NULL, (dir = opendir(dirpath))); + while ((ent = readdir(dir))) { + snprintf(filename, sizeof(filename), "%s/%s", dirpath, ent->d_name); + EXPECT_SYS(0, 0, stat(filename, &st)); + ASSERT_EQ(st.st_ino, ent->d_ino); + } ASSERT_SYS(0, 0, closedir(dir)); } diff --git a/test/libc/stdio/posix_spawn_test.c b/test/libc/stdio/posix_spawn_test.c index 10d25fad1..b8b4810ca 100644 --- a/test/libc/stdio/posix_spawn_test.c +++ b/test/libc/stdio/posix_spawn_test.c @@ -23,7 +23,6 @@ #include "libc/calls/struct/sigaction.h" #include "libc/dce.h" #include "libc/fmt/conv.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/safemacros.internal.h" #include "libc/mem/gc.h" #include "libc/mem/mem.h" diff --git a/test/libc/stdio/zipdir_test.c b/test/libc/stdio/zipdir_test.c index 786bef995..b7e7b1e22 100644 --- a/test/libc/stdio/zipdir_test.c +++ b/test/libc/stdio/zipdir_test.c @@ -54,6 +54,7 @@ TEST(zipdir, test) { ASSERT_EQ(0, strcmp(ent->d_name, "moby.txt")); ASSERT_EQ(DT_REG, ent->d_type); ASSERT_EQ(NULL, (ent = readdir(dir))); + ASSERT_EQ(NULL, (ent = readdir(dir))); ASSERT_SYS(0, 0, closedir(dir)); } diff --git a/test/libc/thread/pthread_key_create_test.c b/test/libc/thread/pthread_key_create_test.c index 7f8641b88..04b4cd6a2 100644 --- a/test/libc/thread/pthread_key_create_test.c +++ b/test/libc/thread/pthread_key_create_test.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/atomic.h" -#include "libc/intrin/kprintf.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/nexgen32e.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/thread/pthread_setname_np_test.c b/test/libc/thread/pthread_setname_np_test.c index d63a72d7b..40ea90d75 100644 --- a/test/libc/thread/pthread_setname_np_test.c +++ b/test/libc/thread/pthread_setname_np_test.c @@ -23,7 +23,6 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/testlib/testlib.h" #include "libc/thread/thread.h" diff --git a/test/libc/thread/sem_open_test.c b/test/libc/thread/sem_open_test.c index 34e9f75af..e84540c8c 100644 --- a/test/libc/thread/sem_open_test.c +++ b/test/libc/thread/sem_open_test.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/mem/gc.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" diff --git a/test/libc/thread/spawn_test.c b/test/libc/thread/spawn_test.c deleted file mode 100644 index 084e567af..000000000 --- a/test/libc/thread/spawn_test.c +++ /dev/null @@ -1,56 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2022 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/thread/spawn.h" -#include "libc/assert.h" -#include "libc/atomic.h" -#include "libc/calls/calls.h" -#include "libc/calls/syscall-sysv.internal.h" -#include "libc/intrin/atomic.h" -#include "libc/macros.internal.h" -#include "libc/mem/gc.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/internal.h" -#include "libc/testlib/testlib.h" - -atomic_int itworked; -_Thread_local int var; - -void SetUpOnce(void) { - __enable_threads(); - ASSERT_SYS(0, 0, pledge("stdio", 0)); -} - -int Worker(void *arg, int tid) { - int i = (long)arg; - ASSERT_EQ(0, var++); - ASSERT_EQ(gettid(), tid); - ASSERT_EQ(1, var++); - ASSERT_EQ(sys_gettid(), tid); - ASSERT_EQ(2, var++); - itworked++; - return 0; -} - -TEST(_spawn, test) { - long i, n = 64; - struct spawn *t = gc(malloc(sizeof(struct spawn) * n)); - for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, (void *)i, t + i)); - for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i)); - EXPECT_EQ(n, itworked); -} diff --git a/test/libc/tinymath/magicu_test.c b/test/libc/tinymath/magicu_test.c index 3502b3a09..f188663cb 100644 --- a/test/libc/tinymath/magicu_test.c +++ b/test/libc/tinymath/magicu_test.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/tinymath/magicu.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" diff --git a/test/tool/net/sqlite_test.c b/test/tool/net/sqlite_test.c index b579f30eb..f10e79746 100644 --- a/test/tool/net/sqlite_test.c +++ b/test/tool/net/sqlite_test.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/dce.h" -#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/mem/gc.h" #include "libc/mem/mem.h" diff --git a/third_party/tr/tr.c b/third_party/tr/tr.c index 2fac8512e..309b04b21 100644 --- a/third_party/tr/tr.c +++ b/third_party/tr/tr.c @@ -34,7 +34,6 @@ │ │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/intrin/kprintf.h" #include "libc/log/bsd.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" diff --git a/tool/build/apelink.c b/tool/build/apelink.c index f178d0d05..56e9c9ac0 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -28,7 +28,6 @@ #include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" #include "libc/intrin/bits.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/macho.internal.h" #include "libc/macros.internal.h" diff --git a/tool/build/ar.c b/tool/build/ar.c index 3a59daa50..4d6da88f3 100644 --- a/tool/build/ar.c +++ b/tool/build/ar.c @@ -31,7 +31,6 @@ #include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/bits.h" #include "libc/intrin/bsr.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" diff --git a/tool/build/cp.c b/tool/build/cp.c index a2279be95..25a4eea3e 100644 --- a/tool/build/cp.c +++ b/tool/build/cp.c @@ -24,7 +24,6 @@ #include "libc/fmt/fmt.h" #include "libc/fmt/libgen.h" #include "libc/fmt/magnumstrs.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/mem/gc.h" #include "libc/runtime/runtime.h" #include "libc/stdio/ftw.h" diff --git a/tool/build/elf2pe.c b/tool/build/elf2pe.c index 97e85db9a..4b17aa416 100644 --- a/tool/build/elf2pe.c +++ b/tool/build/elf2pe.c @@ -27,7 +27,6 @@ #include "libc/intrin/bits.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/dll.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" diff --git a/tool/build/fixupobj.c b/tool/build/fixupobj.c index c5012a307..722fdafe8 100644 --- a/tool/build/fixupobj.c +++ b/tool/build/fixupobj.c @@ -30,7 +30,6 @@ #include "libc/fmt/itoa.h" #include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/bits.h" -#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/log.h" #include "libc/macros.internal.h" diff --git a/tool/build/rm.c b/tool/build/rm.c index 84edb7221..3450478f1 100644 --- a/tool/build/rm.c +++ b/tool/build/rm.c @@ -20,14 +20,13 @@ #include "libc/calls/struct/stat.h" #include "libc/errno.h" #include "libc/fmt/magnumstrs.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" +#include "libc/stdio/ftw.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/ok.h" #include "libc/sysv/consts/s.h" #include "third_party/getopt/getopt.internal.h" -#include "libc/stdio/ftw.h" #define USAGE \ " FILE...\n\ diff --git a/tool/curl/curl.c b/tool/curl/curl.c index dd718064d..5733c0a10 100644 --- a/tool/curl/curl.c +++ b/tool/curl/curl.c @@ -15,7 +15,6 @@ #include "libc/errno.h" #include "libc/fmt/itoa.h" #include "libc/fmt/magnumstrs.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/mem/gc.internal.h" #include "libc/mem/mem.h" diff --git a/tool/emacs/cosmo-cpp-constants.el b/tool/emacs/cosmo-cpp-constants.el index 173dfe4e6..a841ca651 100644 --- a/tool/emacs/cosmo-cpp-constants.el +++ b/tool/emacs/cosmo-cpp-constants.el @@ -179,7 +179,6 @@ (defconst cosmo-cpp-constants-cosmopolitan '("__SAUCE__" - "APE_STACKSIZE" "FRAMESIZE" "ARG_MAX" "PATH_MAX"