mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-04 10:18:31 +00:00
Make improvements for Actually Portable Emacs
- Get SIGWINCH working again on the New Technology - Correctly handle O_NOFOLLOW in open() on Windows - Implement synthetic umask() functionality on Windows - Do a better job managing file execute access on Windows - Fill in `st_uid` and `st_gid` with username hash on Windows - Munge UNICODE control pictures into control codes on Windows - Do a better job ensuring Windows console settings are restored - Introduce KPRINTF_LOG environment variable to log kprintf to a file
This commit is contained in:
parent
9c7b81ee0f
commit
965516e313
108 changed files with 1126 additions and 807 deletions
|
@ -67,11 +67,6 @@ extern char ape_stack_prot[] __attribute__((__weak__));
|
|||
extern pthread_mutex_t __mmi_lock_obj;
|
||||
extern int hostos asm("__hostos");
|
||||
|
||||
void cosmo2(int, char **, char **, unsigned long *) wontreturn;
|
||||
void __switch_stacks(int, char **, char **, unsigned long *,
|
||||
void (*)(int, char **, char **, unsigned long *),
|
||||
void *) wontreturn;
|
||||
|
||||
static const char *DecodeMagnum(const char *p, long *r) {
|
||||
int k = 0;
|
||||
unsigned long c, x = 0;
|
||||
|
@ -96,6 +91,15 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) {
|
|||
unsigned long *auxv = (unsigned long *)(sp + 1 + argc + 1);
|
||||
while (*auxv++) donothing;
|
||||
|
||||
// set helpful globals
|
||||
__argc = argc;
|
||||
__argv = argv;
|
||||
__envp = envp;
|
||||
__auxv = auxv;
|
||||
environ = envp;
|
||||
program_invocation_name = argv[0];
|
||||
__oldstack = (intptr_t)sp;
|
||||
|
||||
// detect apple m1 environment
|
||||
char *magnums;
|
||||
if (SupportsXnu() && (__syslib = m1)) {
|
||||
|
@ -134,16 +138,7 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) {
|
|||
sys_sigaction(SIGSYS, act, 0, 8, 0);
|
||||
}
|
||||
|
||||
// set helpful globals
|
||||
__argc = argc;
|
||||
__argv = argv;
|
||||
__envp = envp;
|
||||
__auxv = auxv;
|
||||
environ = envp;
|
||||
program_invocation_name = argv[0];
|
||||
|
||||
// needed by kisdangerous()
|
||||
__oldstack = (intptr_t)sp;
|
||||
__pid = sys_getpid().ax;
|
||||
|
||||
// initialize memory manager
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Exits process with grace.
|
||||
|
@ -45,9 +43,5 @@ wontreturn void exit(int exitcode) {
|
|||
for (p = __fini_array_end; p > __fini_array_start;) {
|
||||
((void (*)(void))(*--p))();
|
||||
}
|
||||
#if SupportsWindows()
|
||||
_Exitr(exitcode);
|
||||
#else
|
||||
_Exit(exitcode);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/enum/startf.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/ipc.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/process.h"
|
||||
|
@ -145,18 +146,38 @@ static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
|
|||
|
||||
static textwindows int64_t MapOrDie(uint32_t prot, uint64_t size) {
|
||||
int64_t h;
|
||||
if ((h = CreateFileMapping(-1, 0, prot, size >> 32, size, 0))) {
|
||||
return h;
|
||||
} else {
|
||||
for (;;) {
|
||||
if ((h = CreateFileMapping(-1, 0, prot, size >> 32, size, 0))) {
|
||||
return h;
|
||||
}
|
||||
if (GetLastError() == kNtErrorAccessDenied) {
|
||||
switch (prot) {
|
||||
case kNtPageExecuteWritecopy:
|
||||
prot = kNtPageWritecopy;
|
||||
continue;
|
||||
case kNtPageExecuteReadwrite:
|
||||
prot = kNtPageReadwrite;
|
||||
continue;
|
||||
case kNtPageExecuteRead:
|
||||
prot = kNtPageReadonly;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
AbortFork("MapOrDie");
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows void ViewOrDie(int64_t h, uint32_t access, size_t pos,
|
||||
size_t size, void *base) {
|
||||
void *got;
|
||||
got = MapViewOfFileEx(h, access, pos >> 32, pos, size, base);
|
||||
if (!got || (base && got != base)) {
|
||||
TryAgain:
|
||||
if (!MapViewOfFileEx(h, access, pos >> 32, pos, size, base)) {
|
||||
if ((access & kNtFileMapExecute) &&
|
||||
GetLastError() == kNtErrorAccessDenied) {
|
||||
access &= ~kNtFileMapExecute;
|
||||
goto TryAgain;
|
||||
}
|
||||
AbortFork("ViewOrDie");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ COSMOPOLITAN_C_START_
|
|||
extern int __pid;
|
||||
extern char __runlevel;
|
||||
extern int ftrace_stackdigs;
|
||||
extern uint32_t __ntconsolemode[3];
|
||||
extern const char v_ntsubsystem[] __attribute__((__weak__));
|
||||
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
|
||||
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));
|
||||
|
@ -38,6 +37,7 @@ void __morph_tls(void);
|
|||
void __enable_tls(void);
|
||||
void __enable_threads(void);
|
||||
void *__cxa_finalize(void *);
|
||||
void __restore_console_win32(void);
|
||||
void __stack_chk_fail(void) wontreturn relegated;
|
||||
void __stack_chk_fail_local(void) wontreturn relegated;
|
||||
void __asan_init(int, char **, char **, intptr_t *);
|
||||
|
|
|
@ -74,7 +74,7 @@ static inline pureconst unsigned long __rounddown2pow(unsigned long x) {
|
|||
static wontreturn void __mmap_die(const char *s) {
|
||||
if (_weaken(__die)) _weaken(__die)();
|
||||
STRACE("%s %m", s);
|
||||
_Exitr(199);
|
||||
_Exit(199);
|
||||
}
|
||||
|
||||
static dontasan inline bool __overlaps_existing_mapping(char *p, size_t n) {
|
||||
|
|
|
@ -480,13 +480,15 @@ dontasan textstartup void __printargs(const char *prologue) {
|
|||
} else {
|
||||
PRINT(" - stderr");
|
||||
}
|
||||
kprintf(prologue);
|
||||
errno = 0;
|
||||
kprintf(" isatty = %d% m\n", isatty(i));
|
||||
PRINT(" isatty = %d% m", isatty(i));
|
||||
if (!tcgetwinsize(i, &ws)) {
|
||||
kprintf(" ws_row = %d\n", ws.ws_row);
|
||||
kprintf(" ws_col = %d\n", ws.ws_col);
|
||||
PRINT(" ws_row = %d", ws.ws_row);
|
||||
PRINT(" ws_col = %d", ws.ws_col);
|
||||
} else {
|
||||
PRINT(" tcgetwinsize = %s", strerror(errno));
|
||||
}
|
||||
kprintf(prologue);
|
||||
kprintf(" c_iflag =");
|
||||
if (termios.c_iflag & IGNBRK) kprintf(" IGNBRK");
|
||||
if (termios.c_iflag & BRKINT) kprintf(" BRKINT");
|
||||
|
|
|
@ -110,9 +110,7 @@ axdx_t setlongerjmp(jmp_buf)
|
|||
libcesque returnstwice paramsnonnull();
|
||||
void longerjmp(jmp_buf, intptr_t) libcesque wontreturn paramsnonnull();
|
||||
void __warn_if_powersave(void);
|
||||
void _Exitr(int) libcesque wontreturn;
|
||||
void _Exit1(int) libcesque wontreturn;
|
||||
void _restorewintty(void);
|
||||
void __paginate(int, const char *);
|
||||
/* memory management */
|
||||
void _weakfree(void *);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -59,6 +60,7 @@
|
|||
// clang-format off
|
||||
__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;
|
||||
|
@ -71,11 +73,17 @@ __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
|
||||
|
||||
extern const signed char kNtConsoleHandles[3];
|
||||
extern void cosmo(int, char **, char **, long (*)[2]) wontreturn;
|
||||
|
||||
static const signed char kNtStdio[3] = {
|
||||
(signed char)kNtStdInputHandle,
|
||||
(signed char)kNtStdOutputHandle,
|
||||
(signed char)kNtStdErrorHandle,
|
||||
};
|
||||
|
||||
static const short kConsoleModes[3] = {
|
||||
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
|
||||
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
|
||||
|
@ -87,12 +95,25 @@ static const short kConsoleModes[3] = {
|
|||
kNtEnableVirtualTerminalProcessing,
|
||||
};
|
||||
|
||||
static uint32_t __init_pid;
|
||||
static uint32_t __console_mode[3];
|
||||
|
||||
// implements all win32 apis on non-windows hosts
|
||||
__msabi long __win32_oops(void) {
|
||||
__msabi long __oops_win32(void) {
|
||||
assert(!"win32 api called on non-windows host");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// called by _exit to undo our config changes to cmd.exe
|
||||
// it must never ever be called from forked subprocesses
|
||||
void __restore_console_win32(void) {
|
||||
if (__imp_GetCurrentProcessId() == __init_pid) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
__imp_SetConsoleMode(__imp_GetStdHandle(kNtStdio[i]), __console_mode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://nullprogram.com/blog/2022/02/18/
|
||||
__msabi static inline char16_t *MyCommandLine(void) {
|
||||
void *cmd;
|
||||
|
@ -106,14 +127,14 @@ __msabi static inline char16_t *MyCommandLine(void) {
|
|||
// this ensures close(1) won't accidentally close(2) for example
|
||||
__msabi static textwindows void DeduplicateStdioHandles(void) {
|
||||
for (long i = 0; i < 3; ++i) {
|
||||
int64_t h1 = __imp_GetStdHandle(kNtConsoleHandles[i]);
|
||||
int64_t h1 = __imp_GetStdHandle(kNtStdio[i]);
|
||||
for (long j = i + 1; j < 3; ++j) {
|
||||
int64_t h2 = __imp_GetStdHandle(kNtConsoleHandles[j]);
|
||||
int64_t h2 = __imp_GetStdHandle(kNtStdio[j]);
|
||||
if (h1 == h2) {
|
||||
int64_t h3, proc = __imp_GetCurrentProcess();
|
||||
__imp_DuplicateHandle(proc, h2, proc, &h3, 0, true,
|
||||
kNtDuplicateSameAccess);
|
||||
__imp_SetStdHandle(kNtConsoleHandles[j], h3);
|
||||
__imp_SetStdHandle(kNtStdio[j], h3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,14 +144,15 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
size_t stacksize;
|
||||
struct WinArgs *wa;
|
||||
uintptr_t stackaddr;
|
||||
__init_pid = __pid;
|
||||
__oldstack = (intptr_t)__builtin_frame_address(0);
|
||||
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);
|
||||
int64_t hand = __imp_GetStdHandle(kNtStdio[i]);
|
||||
__imp_GetConsoleMode(hand, __console_mode + i);
|
||||
__imp_SetConsoleMode(hand, kConsoleModes[i]);
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +189,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
||||
ARRAYLEN(wa->envp) - 1);
|
||||
__imp_FreeEnvironmentStringsW(env16);
|
||||
__envp = &wa->envp[0];
|
||||
_jmpstack((char *)(stackaddr + (stacksize - sizeof(struct WinArgs))), cosmo,
|
||||
count, wa->argv, wa->envp, wa->auxv);
|
||||
}
|
||||
|
@ -175,8 +198,9 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
const char *lpCmdLine, int64_t nCmdShow) {
|
||||
const char16_t *cmdline;
|
||||
extern char os asm("__hostos");
|
||||
os = _HOSTWINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
|
||||
os = _HOSTWINDOWS; // madness https://news.ycombinator.com/item?id=21019722
|
||||
kStartTsc = rdtsc();
|
||||
__umask = 077;
|
||||
__pid = __imp_GetCurrentProcessId();
|
||||
DeduplicateStdioHandles();
|
||||
if (_weaken(WinMainStdin)) {
|
||||
|
@ -184,7 +208,7 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
|||
}
|
||||
cmdline = MyCommandLine();
|
||||
#ifdef SYSDEBUG
|
||||
/* sloppy flag-only check for early initialization */
|
||||
// sloppy flag-only check for early initialization
|
||||
if (__strstr16(cmdline, u"--strace")) ++__strace;
|
||||
#endif
|
||||
if (_weaken(WinSockInit)) {
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
|
@ -28,9 +30,11 @@
|
|||
#include "libc/mem/alg.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/posix.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
@ -39,23 +43,33 @@
|
|||
__static_yoink(APE_COM_NAME);
|
||||
#endif
|
||||
|
||||
static uint64_t __zipos_get_min_offset(const uint8_t *map,
|
||||
const uint8_t *cdir) {
|
||||
uint64_t i, n, c, r, o;
|
||||
static struct Zipos __zipos;
|
||||
static atomic_uint __zipos_once;
|
||||
|
||||
static void __zipos_dismiss(const uint8_t *map, const uint8_t *cdir, long pg) {
|
||||
uint64_t i, n, c, ef, lf, mo, lo, hi;
|
||||
|
||||
// determine the byte range of zip file content (excluding central dir)
|
||||
c = GetZipCdirOffset(cdir);
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (r = c, i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(map + c)) {
|
||||
o = GetZipCfileOffset(map + c);
|
||||
if (o < r) r = o;
|
||||
for (lo = c, hi = i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(map + c)) {
|
||||
lf = GetZipCfileOffset(map + c);
|
||||
if (lf < lo) lo = lf;
|
||||
ef = lf + ZIP_LFILE_HDRSIZE(map + lf) + GetZipLfileCompressedSize(map + lf);
|
||||
if (ef > hi) hi = ef;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __zipos_munmap_unneeded(const uint8_t *map, const uint8_t *cdir) {
|
||||
uint64_t n;
|
||||
n = __zipos_get_min_offset(map, cdir);
|
||||
n = ROUNDDOWN(n, FRAMESIZE);
|
||||
if (n) munmap(map, n);
|
||||
// unmap the executable portion beneath the local files
|
||||
mo = ROUNDDOWN(lo, FRAMESIZE);
|
||||
if (mo) munmap(map, mo);
|
||||
|
||||
// this is supposed to reduce our rss usage but does it
|
||||
pg = getauxval(AT_PAGESZ);
|
||||
lo = ROUNDDOWN(lo, pg);
|
||||
hi = MIN(ROUNDUP(hi, pg), ROUNDDOWN(c, pg));
|
||||
if (hi > lo) {
|
||||
posix_madvise(map + lo, hi - lo, POSIX_MADV_DONTNEED);
|
||||
}
|
||||
}
|
||||
|
||||
static int __zipos_compare_names(const void *a, const void *b, void *c) {
|
||||
|
@ -88,75 +102,67 @@ static void __zipos_generate_index(struct Zipos *zipos) {
|
|||
__zipos_compare_names, zipos);
|
||||
}
|
||||
|
||||
static void __zipos_init(void) {
|
||||
char *endptr;
|
||||
const char *s;
|
||||
struct stat st;
|
||||
int x, fd, err, msg;
|
||||
uint8_t *map, *cdir;
|
||||
const char *progpath;
|
||||
if (!(s = getenv("COSMOPOLITAN_DISABLE_ZIPOS"))) {
|
||||
// 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;
|
||||
}
|
||||
if (fd != -1 || PLEDGED(RPATH)) {
|
||||
if (fd == -1) {
|
||||
if (!progpath) {
|
||||
progpath = GetProgramExecutableName();
|
||||
}
|
||||
fd = open(progpath, O_RDONLY);
|
||||
}
|
||||
if (fd != -1) {
|
||||
if (!fstat(fd, &st) && (map = mmap(0, st.st_size, PROT_READ, MAP_SHARED,
|
||||
fd, 0)) != MAP_FAILED) {
|
||||
if ((cdir = GetZipEocd(map, st.st_size, &err))) {
|
||||
long pagesz = getauxval(AT_PAGESZ);
|
||||
__zipos_dismiss(map, cdir, pagesz);
|
||||
__zipos.map = map;
|
||||
__zipos.cdir = cdir;
|
||||
__zipos.dev = st.st_ino;
|
||||
__zipos.pagesz = pagesz;
|
||||
__zipos_generate_index(&__zipos);
|
||||
msg = kZipOk;
|
||||
} else {
|
||||
munmap(map, st.st_size);
|
||||
msg = !cdir ? err : kZipErrorRaceCondition;
|
||||
}
|
||||
} else {
|
||||
msg = kZipErrorMapFailed;
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
msg = kZipErrorOpenFailed;
|
||||
}
|
||||
} else {
|
||||
msg = -666;
|
||||
}
|
||||
} else {
|
||||
progpath = 0;
|
||||
msg = -777;
|
||||
}
|
||||
STRACE("__zipos_get(%#s) → %d% m", progpath, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pointer to zip central directory of current executable.
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
struct Zipos *__zipos_get(void) {
|
||||
char *endptr;
|
||||
const char *s;
|
||||
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) {
|
||||
if (!(s = getenv("COSMOPOLITAN_DISABLE_ZIPOS"))) {
|
||||
// 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;
|
||||
}
|
||||
if (fd != -1 || PLEDGED(RPATH)) {
|
||||
if (fd == -1) {
|
||||
if (!progpath) {
|
||||
progpath = GetProgramExecutableName();
|
||||
}
|
||||
fd = open(progpath, O_RDONLY);
|
||||
}
|
||||
if (fd != -1) {
|
||||
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);
|
||||
zipos.map = map;
|
||||
zipos.cdir = cdir;
|
||||
zipos.dev = st.st_ino;
|
||||
__zipos_generate_index(&zipos);
|
||||
msg = kZipOk;
|
||||
} else {
|
||||
munmap(map, st.st_size);
|
||||
msg = !cdir ? err : kZipErrorRaceCondition;
|
||||
}
|
||||
} else {
|
||||
msg = kZipErrorMapFailed;
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
msg = kZipErrorOpenFailed;
|
||||
}
|
||||
} else {
|
||||
msg = -666;
|
||||
}
|
||||
} else {
|
||||
progpath = 0;
|
||||
msg = -777;
|
||||
}
|
||||
STRACE("__zipos_get(%#s) → %d% m", progpath, msg);
|
||||
once = true;
|
||||
}
|
||||
__zipos_unlock();
|
||||
if (zipos.cdir) {
|
||||
res = &zipos;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
cosmo_once(&__zipos_once, __zipos_init);
|
||||
return __zipos.cdir ? &__zipos : 0;
|
||||
}
|
||||
|
|
|
@ -1,39 +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/thread.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
static pthread_mutex_t __zipos_lock_obj;
|
||||
|
||||
void(__zipos_lock)(void) {
|
||||
pthread_mutex_lock(&__zipos_lock_obj);
|
||||
}
|
||||
|
||||
void(__zipos_unlock)(void) {
|
||||
pthread_mutex_unlock(&__zipos_lock_obj);
|
||||
}
|
||||
|
||||
void __zipos_funlock(void) {
|
||||
pthread_mutex_init(&__zipos_lock_obj, 0);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __zipos_init(void) {
|
||||
__zipos_funlock();
|
||||
pthread_atfork(__zipos_lock, __zipos_unlock, __zipos_funlock);
|
||||
}
|
|
@ -45,21 +45,39 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static char *mapend;
|
||||
static size_t maptotal;
|
||||
static char *__zipos_mapend;
|
||||
static size_t __zipos_maptotal;
|
||||
static pthread_mutex_t __zipos_lock_obj;
|
||||
|
||||
static void __zipos_lock(void) {
|
||||
if (__threaded) {
|
||||
pthread_mutex_lock(&__zipos_lock_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void __zipos_unlock(void) {
|
||||
if (__threaded) {
|
||||
pthread_mutex_unlock(&__zipos_lock_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void __zipos_funlock(void) {
|
||||
pthread_mutex_init(&__zipos_lock_obj, 0);
|
||||
}
|
||||
|
||||
static void *__zipos_mmap_space(size_t mapsize) {
|
||||
char *start;
|
||||
size_t offset;
|
||||
unassert(mapsize);
|
||||
offset = maptotal;
|
||||
maptotal += mapsize;
|
||||
offset = __zipos_maptotal;
|
||||
__zipos_maptotal += mapsize;
|
||||
start = (char *)kMemtrackZiposStart;
|
||||
if (!mapend) mapend = start;
|
||||
mapend = _extend(start, maptotal, mapend, MAP_PRIVATE,
|
||||
kMemtrackZiposStart + kMemtrackZiposSize);
|
||||
if (!__zipos_mapend) __zipos_mapend = start;
|
||||
__zipos_mapend = _extend(start, __zipos_maptotal, __zipos_mapend, MAP_PRIVATE,
|
||||
kMemtrackZiposStart + kMemtrackZiposSize);
|
||||
return start + offset;
|
||||
}
|
||||
|
||||
|
@ -68,7 +86,6 @@ void __zipos_free(struct ZiposHandle *h) {
|
|||
__asan_poison((char *)h + sizeof(struct ZiposHandle),
|
||||
h->mapsize - sizeof(struct ZiposHandle), kAsanHeapFree);
|
||||
}
|
||||
pthread_mutex_destroy(&h->lock);
|
||||
__zipos_lock();
|
||||
do h->next = h->zipos->freelist;
|
||||
while (!_cmpxchg(&h->zipos->freelist, h->next, h));
|
||||
|
@ -105,7 +122,6 @@ StartOver:
|
|||
h->size = size;
|
||||
h->zipos = zipos;
|
||||
h->mapsize = mapsize;
|
||||
pthread_mutex_init(&h->lock, 0);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
@ -197,16 +213,40 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, int flags,
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int __zipos_open_impl(struct ZiposUri *name, int flags) {
|
||||
struct Zipos *zipos;
|
||||
/**
|
||||
* Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __zipos_open(struct ZiposUri *name, int flags) {
|
||||
|
||||
// check if this thread is cancelled
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// validate api usage
|
||||
if ((flags & O_CREAT) || //
|
||||
(flags & O_TRUNC) || //
|
||||
(flags & O_ACCMODE) != O_RDONLY) {
|
||||
return erofs();
|
||||
}
|
||||
|
||||
// get the zipos global singleton
|
||||
struct Zipos *zipos;
|
||||
if (!(zipos = __zipos_get())) {
|
||||
return enoexec();
|
||||
}
|
||||
|
||||
// most open() calls are due to languages path searching assets. the
|
||||
// majority of these calls will return ENOENT or ENOTDIR. we need to
|
||||
// perform two extremely costly sigprocmask() calls below. thanks to
|
||||
// zipos being a read-only filesystem, we can avoid it in many cases
|
||||
ssize_t cf;
|
||||
if ((cf = __zipos_find(zipos, name)) == -1) {
|
||||
return -1;
|
||||
|
@ -223,25 +263,14 @@ static int __zipos_open_impl(struct ZiposUri *name, int flags) {
|
|||
return eacces();
|
||||
}
|
||||
}
|
||||
return __zipos_load(zipos, cf, flags, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __zipos_open(struct ZiposUri *name, int flags) {
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
// now do the heavy lifting
|
||||
BLOCK_SIGNALS;
|
||||
rc = __zipos_open_impl(name, flags);
|
||||
rc = __zipos_load(zipos, cf, flags, name);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __zipos_ctor(void) {
|
||||
pthread_atfork(__zipos_lock, __zipos_unlock, __zipos_funlock);
|
||||
}
|
||||
|
|
|
@ -21,14 +21,9 @@
|
|||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static size_t GetIovSize(const struct iovec *iov, size_t iovlen) {
|
||||
size_t i, r;
|
||||
for (r = i = 0; i < iovlen; ++i) r += iov[i].iov_len;
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
|
||||
size_t iovlen, ssize_t opt_offset) {
|
||||
int i;
|
||||
|
@ -61,10 +56,6 @@ static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
|
|||
*/
|
||||
ssize_t __zipos_read(struct ZiposHandle *h, const struct iovec *iov,
|
||||
size_t iovlen, ssize_t opt_offset) {
|
||||
ssize_t rc;
|
||||
unassert(opt_offset >= 0 || opt_offset == -1);
|
||||
pthread_mutex_lock(&h->lock);
|
||||
rc = __zipos_read_impl(h, iov, iovlen, opt_offset);
|
||||
pthread_mutex_unlock(&h->lock);
|
||||
return rc;
|
||||
return __zipos_read_impl(h, iov, iovlen, opt_offset);
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@
|
|||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static int64_t __zipos_lseek_impl(struct ZiposHandle *h, int64_t offset,
|
||||
unsigned whence) {
|
||||
static int64_t __zipos_seek_impl(struct ZiposHandle *h, int64_t offset,
|
||||
unsigned whence) {
|
||||
int64_t pos;
|
||||
if (h->cfile == ZIPOS_SYNTHETIC_DIRECTORY ||
|
||||
S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
|
||||
|
@ -71,12 +72,10 @@ static int64_t __zipos_lseek_impl(struct ZiposHandle *h, int64_t offset,
|
|||
* @return new position relative to beginning, or -1 on error
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int64_t __zipos_lseek(struct ZiposHandle *h, int64_t offset, unsigned whence) {
|
||||
int64_t __zipos_seek(struct ZiposHandle *h, int64_t offset, unsigned whence) {
|
||||
int64_t pos;
|
||||
pthread_mutex_lock(&h->lock);
|
||||
if ((pos = __zipos_lseek_impl(h, offset, whence)) != -1) {
|
||||
if ((pos = __zipos_seek_impl(h, offset, whence)) != -1) {
|
||||
h->pos = pos;
|
||||
}
|
||||
pthread_mutex_unlock(&h->lock);
|
||||
return pos;
|
||||
}
|
|
@ -16,7 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -30,7 +32,8 @@ int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
|
|||
st->st_dev = zipos->dev;
|
||||
st->st_blksize = FRAMESIZE;
|
||||
if (cf == ZIPOS_SYNTHETIC_DIRECTORY) {
|
||||
st->st_mode = S_IFDIR | 0555;
|
||||
st->st_mode = S_IFDIR | (0555 & ~atomic_load_explicit(
|
||||
&__umask, memory_order_acquire));
|
||||
} else {
|
||||
lf = GetZipCfileOffset(zipos->map + cf);
|
||||
st->st_mode = GetZipCfileMode(zipos->map + cf);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
.yoink __zipos_fcntl
|
||||
.yoink __zipos_fstat
|
||||
.yoink __zipos_access
|
||||
.yoink __zipos_lseek
|
||||
.yoink __zipos_seek
|
||||
.yoink __zipos_open
|
||||
.yoink __zipos_parseuri
|
||||
.yoink __zipos_read
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_
|
||||
#define COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_
|
||||
#include "libc/intrin/nopl.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -21,7 +18,6 @@ struct ZiposUri {
|
|||
|
||||
struct ZiposHandle {
|
||||
struct ZiposHandle *next;
|
||||
pthread_mutex_t lock;
|
||||
struct Zipos *zipos;
|
||||
size_t size;
|
||||
size_t mapsize;
|
||||
|
@ -32,6 +28,7 @@ struct ZiposHandle {
|
|||
};
|
||||
|
||||
struct Zipos {
|
||||
long pagesz;
|
||||
uint8_t *map;
|
||||
uint8_t *cdir;
|
||||
uint64_t dev;
|
||||
|
@ -41,8 +38,6 @@ struct Zipos {
|
|||
};
|
||||
|
||||
int __zipos_close(int);
|
||||
void __zipos_lock(void);
|
||||
void __zipos_unlock(void);
|
||||
void __zipos_free(struct ZiposHandle *);
|
||||
struct Zipos *__zipos_get(void) pureconst;
|
||||
size_t __zipos_normpath(char *, const char *, size_t);
|
||||
|
@ -57,20 +52,12 @@ int __zipos_fstat(struct ZiposHandle *, struct stat *);
|
|||
int __zipos_stat_impl(struct Zipos *, size_t, struct stat *);
|
||||
ssize_t __zipos_read(struct ZiposHandle *, const struct iovec *, size_t,
|
||||
ssize_t);
|
||||
int64_t __zipos_lseek(struct ZiposHandle *, int64_t, unsigned);
|
||||
int64_t __zipos_seek(struct ZiposHandle *, int64_t, unsigned);
|
||||
int __zipos_fcntl(int, int, uintptr_t);
|
||||
int __zipos_notat(int, const char *);
|
||||
void *__zipos_mmap(void *, uint64_t, int32_t, int32_t, struct ZiposHandle *,
|
||||
int64_t) dontasan;
|
||||
|
||||
#ifdef _NOPL0
|
||||
#define __zipos_lock() _NOPL0("__threadcalls", __zipos_lock)
|
||||
#define __zipos_unlock() _NOPL0("__threadcalls", __zipos_unlock)
|
||||
#else
|
||||
#define __zipos_lock() (__threaded ? __zipos_lock() : 0)
|
||||
#define __zipos_unlock() (__threaded ? __zipos_unlock() : 0)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue