mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 23:08:31 +00:00
Make ZipOS and Qemu work better
This change improves the dirstream library in a lot of respects, especially for /zip/... files. Also turn off MAP_STACK on Aarch64 because Qemu seems to implement it differently than Linux and it's probably responsible for a lot of mysterious crashes.
This commit is contained in:
parent
4658ae539f
commit
110559ce6a
48 changed files with 748 additions and 500 deletions
|
@ -164,7 +164,7 @@ wontreturn textstartup void cosmo(long *sp, struct Syslib *m1) {
|
|||
__switch_stacks(argc, argv, envp, auxv, cosmo2,
|
||||
(char *)mmap(ape_stack_vaddr, (uintptr_t)ape_stack_memsz,
|
||||
MAP_FIXED | PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_STACK, -1, 0) +
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) +
|
||||
(uintptr_t)ape_stack_memsz);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
#include "libc/sysv/consts/ss.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
#define MAP_ANONYMOUS_linux 0x00000020
|
||||
#define MAP_ANONYMOUS_openbsd 0x00001000
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
// TODO: this should check parent directory components
|
||||
|
||||
|
@ -31,37 +31,30 @@
|
|||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __zipos_access(const struct ZiposUri *name, int amode) {
|
||||
ssize_t cf;
|
||||
int rc, mode;
|
||||
int __zipos_access(struct ZiposUri *name, int amode) {
|
||||
|
||||
struct Zipos *z;
|
||||
if ((z = __zipos_get()) && (cf = __zipos_find(z, name)) != -1) {
|
||||
mode = GetZipCfileMode(z->map + cf);
|
||||
if (amode == F_OK) {
|
||||
rc = 0;
|
||||
} else if (amode == R_OK) {
|
||||
if (mode & 0444) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eacces();
|
||||
}
|
||||
} else if (amode == W_OK) {
|
||||
if (mode & 0222) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eacces();
|
||||
}
|
||||
} else if (amode == X_OK) {
|
||||
if (mode & 0111) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eacces();
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
rc = enoent();
|
||||
if (!(z = __zipos_get())) {
|
||||
return enoexec();
|
||||
}
|
||||
return rc;
|
||||
|
||||
ssize_t cf;
|
||||
if ((cf = __zipos_find(z, name)) == -1) {
|
||||
return enoent();
|
||||
}
|
||||
|
||||
int mode = GetZipCfileMode(z->map + cf);
|
||||
if (amode == F_OK) {
|
||||
return 0;
|
||||
}
|
||||
if (amode & ~(R_OK | W_OK | X_OK)) {
|
||||
return einval();
|
||||
}
|
||||
if (((amode & X_OK) && !(mode & 0111)) ||
|
||||
((amode & W_OK) && !(mode & 0222)) ||
|
||||
((amode & R_OK) && !(mode & 0444))) {
|
||||
return eacces();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -38,10 +37,10 @@ int __zipos_close(int fd) {
|
|||
if (!IsWindows()) {
|
||||
rc = sys_close(fd);
|
||||
} else {
|
||||
rc = 0; /* no system file descriptor needed on nt */
|
||||
rc = 0; // no system file descriptor needed on nt
|
||||
}
|
||||
if (!__vforked) {
|
||||
__zipos_free(__zipos_get(), h);
|
||||
__zipos_free(h);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,34 +17,28 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
#define ZIPOS __zipos_get()
|
||||
#define HANDLE ((struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle)
|
||||
|
||||
int __zipos_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
rc = FD_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
rc = 0;
|
||||
return 0;
|
||||
}
|
||||
} else if (cmd == F_SETFD) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
rc = FD_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
rc = 0;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
return einval();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,39 +16,30 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
// TODO(jart): improve time complexity here
|
||||
|
||||
ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) {
|
||||
const char *zname;
|
||||
size_t i, n, c, znamesize;
|
||||
ssize_t __zipos_find(struct Zipos *zipos, struct ZiposUri *name) {
|
||||
if (!name->len) {
|
||||
return 0;
|
||||
return ZIPOS_SYNTHETIC_DIRECTORY;
|
||||
}
|
||||
c = GetZipCdirOffset(zipos->cdir);
|
||||
n = GetZipCdirRecords(zipos->cdir);
|
||||
for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) {
|
||||
npassert(ZIP_CFILE_MAGIC(zipos->map + c) == kZipCfileHdrMagic);
|
||||
zname = ZIP_CFILE_NAME(zipos->map + c);
|
||||
znamesize = ZIP_CFILE_NAMESIZE(zipos->map + c);
|
||||
if ((name->len == znamesize && !memcmp(name->path, zname, name->len)) ||
|
||||
(name->len + 1 == znamesize && !memcmp(name->path, zname, name->len) &&
|
||||
zname[name->len] == '/')) {
|
||||
bool found_subfile = false;
|
||||
size_t c = GetZipCdirOffset(zipos->cdir);
|
||||
size_t n = GetZipCdirRecords(zipos->cdir);
|
||||
for (size_t i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) {
|
||||
const char *zname = ZIP_CFILE_NAME(zipos->map + c);
|
||||
size_t zsize = ZIP_CFILE_NAMESIZE(zipos->map + c);
|
||||
if ((name->len == zsize ||
|
||||
(name->len + 1 == zsize && zname[name->len] == '/')) &&
|
||||
!memcmp(name->path, zname, name->len)) {
|
||||
return c;
|
||||
} else if ((name->len < znamesize &&
|
||||
!memcmp(name->path, zname, name->len) &&
|
||||
zname[name->len - 1] == '/') ||
|
||||
(name->len + 1 < znamesize &&
|
||||
!memcmp(name->path, zname, name->len) &&
|
||||
zname[name->len] == '/')) {
|
||||
return 0;
|
||||
} else if (name->len + 1 < zsize && zname[name->len] == '/' &&
|
||||
!memcmp(name->path, zname, name->len)) {
|
||||
found_subfile = true;
|
||||
}
|
||||
}
|
||||
if (found_subfile) {
|
||||
return ZIPOS_SYNTHETIC_DIRECTORY;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
|
@ -27,12 +24,6 @@
|
|||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __zipos_fstat(const struct ZiposHandle *h, struct stat *st) {
|
||||
int rc;
|
||||
if (st) {
|
||||
rc = __zipos_stat_impl(__zipos_get(), h->cfile, st);
|
||||
} else {
|
||||
rc = efault();
|
||||
}
|
||||
return rc;
|
||||
int __zipos_fstat(struct ZiposHandle *h, struct stat *st) {
|
||||
return __zipos_stat_impl(h->zipos, h->cfile, st);
|
||||
}
|
||||
|
|
|
@ -20,16 +20,17 @@
|
|||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
__static_yoink(APE_COM_NAME);
|
||||
|
@ -81,7 +82,9 @@ struct Zipos *__zipos_get(void) {
|
|||
}
|
||||
if (fd != -1 || PLEDGED(RPATH)) {
|
||||
if (fd == -1) {
|
||||
progpath = GetProgramExecutableName();
|
||||
if (!progpath) {
|
||||
progpath = GetProgramExecutableName();
|
||||
}
|
||||
fd = open(progpath, O_RDONLY);
|
||||
}
|
||||
if (fd != -1) {
|
||||
|
|
|
@ -17,10 +17,39 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/stdckdint.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
static int64_t __zipos_lseek_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))) {
|
||||
return eisdir();
|
||||
}
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
return offset;
|
||||
case SEEK_CUR:
|
||||
if (!ckd_add(&pos, h->pos, offset)) {
|
||||
return pos;
|
||||
} else {
|
||||
return eoverflow();
|
||||
}
|
||||
case SEEK_END:
|
||||
if (!ckd_sub(&pos, h->size, offset)) {
|
||||
return pos;
|
||||
} else {
|
||||
return eoverflow();
|
||||
}
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes current position of zip file handle.
|
||||
|
@ -31,27 +60,12 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int64_t __zipos_lseek(struct ZiposHandle *h, int64_t offset, unsigned whence) {
|
||||
int64_t rc;
|
||||
int64_t pos;
|
||||
if (offset < 0) return einval();
|
||||
pthread_mutex_lock(&h->lock);
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
rc = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
rc = h->pos + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
rc = h->size - offset;
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (rc >= 0) {
|
||||
h->pos = rc;
|
||||
} else {
|
||||
rc = einval();
|
||||
if ((pos = __zipos_lseek_impl(h, offset, whence)) != -1) {
|
||||
h->pos = pos;
|
||||
}
|
||||
pthread_mutex_unlock(&h->lock);
|
||||
return rc;
|
||||
return pos;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,15 @@
|
|||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
#define IP(X) (intptr_t)(X)
|
||||
#define VIP(X) (void *)IP(X)
|
||||
|
@ -50,25 +51,36 @@
|
|||
*/
|
||||
dontasan void *__zipos_mmap(void *addr, size_t size, int prot, int flags,
|
||||
struct ZiposHandle *h, int64_t off) {
|
||||
if (!(flags & MAP_PRIVATE) ||
|
||||
(flags & ~(MAP_PRIVATE | MAP_FILE | MAP_FIXED | MAP_FIXED_NOREPLACE)) ||
|
||||
(!!(flags & MAP_FIXED) ^ !!(flags & MAP_FIXED_NOREPLACE))) {
|
||||
STRACE(
|
||||
"zipos mappings currently only support MAP_PRIVATE with select flags");
|
||||
|
||||
if (off < 0) {
|
||||
STRACE("negative zipos mmap offset");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (VERY_UNLIKELY(off < 0)) {
|
||||
STRACE("neg off");
|
||||
if (h->cfile == ZIPOS_SYNTHETIC_DIRECTORY ||
|
||||
S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
|
||||
return VIP(eisdir());
|
||||
}
|
||||
|
||||
if (flags & (MAP_SHARED | MAP_ANONYMOUS)) {
|
||||
STRACE("ZipOS bad flags");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) {
|
||||
STRACE("ZipOS bad protection");
|
||||
return VIP(einval());
|
||||
}
|
||||
|
||||
flags &= MAP_FIXED | MAP_FIXED_NOREPLACE;
|
||||
flags |= MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
|
||||
const int tempProt = !IsXnu() ? prot | PROT_WRITE : PROT_WRITE;
|
||||
void *outAddr = __mmap_unlocked(addr, size, tempProt,
|
||||
(flags & (~MAP_FILE)) | MAP_ANONYMOUS, -1, 0);
|
||||
void *outAddr = __mmap_unlocked(addr, size, tempProt, flags, -1, 0);
|
||||
if (outAddr == MAP_FAILED) {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
do {
|
||||
if (__zipos_read(h, &(struct iovec){outAddr, size}, 1, off) == -1) {
|
||||
strace_enabled(-1);
|
||||
|
@ -82,6 +94,7 @@ dontasan void *__zipos_mmap(void *addr, size_t size, int prot, int flags,
|
|||
}
|
||||
return outAddr;
|
||||
} while (0);
|
||||
|
||||
const int e = errno;
|
||||
__munmap_unlocked(outAddr, size);
|
||||
errno = e;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,22 +16,65 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/asancodes.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
void __zipos_free(struct Zipos *z, struct ZiposHandle *h) {
|
||||
if (IsAsan()) {
|
||||
__asan_poison((char *)h + sizeof(struct ZiposHandle),
|
||||
h->mapsize - sizeof(struct ZiposHandle), kAsanHeapFree);
|
||||
static size_t __zipos_trimpath(char *s, int *isabs) {
|
||||
char *p = s, *q = s;
|
||||
for (; *q; ++q) {
|
||||
if (*q == '/') {
|
||||
while (q[1] == '/') ++q;
|
||||
if (q[1] == '.' && (q[2] == '/' || q[2] == '\0')) {
|
||||
++q;
|
||||
} else {
|
||||
*p++ = '/';
|
||||
}
|
||||
} else {
|
||||
*p++ = *q;
|
||||
}
|
||||
}
|
||||
pthread_mutex_destroy(&h->lock);
|
||||
__zipos_lock();
|
||||
do h->next = z->freelist;
|
||||
while (!_cmpxchg(&z->freelist, h->next, h));
|
||||
__zipos_unlock();
|
||||
if (s < p && p[-1] == '.' && p[-2] == '.' && (p - 2 == s || p[-3] == '/')) {
|
||||
*p++ = '/';
|
||||
}
|
||||
*p = '\0';
|
||||
if (isabs) {
|
||||
*isabs = *s == '/';
|
||||
}
|
||||
return p - s;
|
||||
}
|
||||
|
||||
size_t __zipos_normpath(char *s) {
|
||||
int isabs;
|
||||
char *p = s, *q = s;
|
||||
__zipos_trimpath(s, &isabs);
|
||||
if (!*s) return 0;
|
||||
for (; *q != '\0'; ++q) {
|
||||
if (q[0] == '/' && q[1] == '.' && q[2] == '.' &&
|
||||
(q[3] == '/' || q[3] == '\0')) {
|
||||
char *ep = p;
|
||||
while (s < ep && *--ep != '/') donothing;
|
||||
if (ep != p &&
|
||||
(p[-1] != '.' || p[-2] != '.' || (s < p - 3 && p[-3] != '/'))) {
|
||||
p = ep;
|
||||
q += 2;
|
||||
continue;
|
||||
} else if (ep == s && isabs) {
|
||||
q += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (q[0] != '/' || p != s || isabs) {
|
||||
*p++ = *q;
|
||||
}
|
||||
}
|
||||
if (p == s) {
|
||||
*p++ = isabs ? '/' : '.';
|
||||
}
|
||||
if (p == s + 1 && s[0] == '.') {
|
||||
*p++ = '/';
|
||||
}
|
||||
while (p - s > 1 && p[-1] == '/') {
|
||||
--p;
|
||||
}
|
||||
*p = '\0';
|
||||
return p - s;
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -30,19 +31,21 @@
|
|||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/intrin/extend.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
static char *mapend;
|
||||
static size_t maptotal;
|
||||
|
@ -60,6 +63,18 @@ static void *__zipos_mmap_space(size_t mapsize) {
|
|||
return start + offset;
|
||||
}
|
||||
|
||||
void __zipos_free(struct ZiposHandle *h) {
|
||||
if (IsAsan()) {
|
||||
__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));
|
||||
__zipos_unlock();
|
||||
}
|
||||
|
||||
static struct ZiposHandle *__zipos_alloc(struct Zipos *zipos, size_t size) {
|
||||
size_t mapsize;
|
||||
struct ZiposHandle *h, **ph;
|
||||
|
@ -88,6 +103,7 @@ StartOver:
|
|||
}
|
||||
if (h) {
|
||||
h->size = size;
|
||||
h->zipos = zipos;
|
||||
h->mapsize = mapsize;
|
||||
pthread_mutex_init(&h->lock, 0);
|
||||
}
|
||||
|
@ -95,65 +111,63 @@ StartOver:
|
|||
}
|
||||
|
||||
static int __zipos_mkfd(int minfd) {
|
||||
int e, fd;
|
||||
static bool demodernize;
|
||||
if (!demodernize) {
|
||||
e = errno;
|
||||
if ((fd = __sys_fcntl(2, F_DUPFD_CLOEXEC, minfd)) != -1) {
|
||||
return fd;
|
||||
} else if (errno == EINVAL) {
|
||||
demodernize = true;
|
||||
errno = e;
|
||||
} else {
|
||||
return fd;
|
||||
}
|
||||
int fd, e = errno;
|
||||
if ((fd = __sys_fcntl(2, F_DUPFD_CLOEXEC, minfd)) != -1) {
|
||||
return fd;
|
||||
} else if (errno == EINVAL) {
|
||||
errno = e;
|
||||
return __fixupnewfd(__sys_fcntl(2, F_DUPFD, minfd), O_CLOEXEC);
|
||||
} else {
|
||||
return fd;
|
||||
}
|
||||
if ((fd = __sys_fcntl(2, F_DUPFD, minfd)) != -1) {
|
||||
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int __zipos_setfd(int fd, struct ZiposHandle *h, unsigned flags,
|
||||
int mode) {
|
||||
static int __zipos_setfd(int fd, struct ZiposHandle *h, unsigned flags) {
|
||||
int want = fd;
|
||||
atomic_compare_exchange_strong_explicit(
|
||||
&g_fds.f, &want, fd + 1, memory_order_release, memory_order_relaxed);
|
||||
g_fds.p[fd].kind = kFdZip;
|
||||
g_fds.p[fd].handle = (intptr_t)h;
|
||||
g_fds.p[fd].flags = flags | O_CLOEXEC;
|
||||
g_fds.p[fd].mode = mode;
|
||||
g_fds.p[fd].extra = 0;
|
||||
__fds_unlock();
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags,
|
||||
int mode) {
|
||||
static int __zipos_load(struct Zipos *zipos, size_t cf, int flags,
|
||||
struct ZiposUri *name) {
|
||||
size_t lf;
|
||||
size_t size;
|
||||
int rc, fd, minfd;
|
||||
struct ZiposHandle *h;
|
||||
lf = GetZipCfileOffset(zipos->map + cf);
|
||||
npassert((ZIP_LFILE_MAGIC(zipos->map + lf) == kZipLfileHdrMagic));
|
||||
size = GetZipLfileUncompressedSize(zipos->map + lf);
|
||||
switch (ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf)) {
|
||||
case kZipCompressionNone:
|
||||
if (!(h = __zipos_alloc(zipos, 0))) return -1;
|
||||
h->mem = ZIP_LFILE_CONTENT(zipos->map + lf);
|
||||
break;
|
||||
case kZipCompressionDeflate:
|
||||
if (!(h = __zipos_alloc(zipos, size))) return -1;
|
||||
if (!__inflate(h->data, size, ZIP_LFILE_CONTENT(zipos->map + lf),
|
||||
GetZipLfileCompressedSize(zipos->map + lf))) {
|
||||
h->mem = h->data;
|
||||
} else {
|
||||
h->mem = 0;
|
||||
eio();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return eio();
|
||||
if (cf == ZIPOS_SYNTHETIC_DIRECTORY) {
|
||||
size = name->len;
|
||||
if (!(h = __zipos_alloc(zipos, size + 1))) return -1;
|
||||
if (size) memcpy(h->data, name->path, size);
|
||||
h->data[size] = 0;
|
||||
h->mem = h->data;
|
||||
} else {
|
||||
lf = GetZipCfileOffset(zipos->map + cf);
|
||||
npassert((ZIP_LFILE_MAGIC(zipos->map + lf) == kZipLfileHdrMagic));
|
||||
size = GetZipLfileUncompressedSize(zipos->map + lf);
|
||||
switch (ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf)) {
|
||||
case kZipCompressionNone:
|
||||
if (!(h = __zipos_alloc(zipos, 0))) return -1;
|
||||
h->mem = ZIP_LFILE_CONTENT(zipos->map + lf);
|
||||
break;
|
||||
case kZipCompressionDeflate:
|
||||
if (!(h = __zipos_alloc(zipos, size))) return -1;
|
||||
if (!__inflate(h->data, size, ZIP_LFILE_CONTENT(zipos->map + lf),
|
||||
GetZipLfileCompressedSize(zipos->map + lf))) {
|
||||
h->mem = h->data;
|
||||
} else {
|
||||
h->mem = 0;
|
||||
eio();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return eio();
|
||||
}
|
||||
}
|
||||
h->pos = 0;
|
||||
h->cfile = cf;
|
||||
|
@ -164,7 +178,7 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags,
|
|||
TryAgain:
|
||||
if (IsWindows() || IsMetal()) {
|
||||
if ((fd = __reservefd_unlocked(-1)) != -1) {
|
||||
return __zipos_setfd(fd, h, flags, mode);
|
||||
return __zipos_setfd(fd, h, flags);
|
||||
}
|
||||
} else if ((fd = __zipos_mkfd(minfd)) != -1) {
|
||||
if (__ensurefds_unlocked(fd) != -1) {
|
||||
|
@ -173,16 +187,45 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags,
|
|||
minfd = fd + 1;
|
||||
goto TryAgain;
|
||||
}
|
||||
return __zipos_setfd(fd, h, flags, mode);
|
||||
return __zipos_setfd(fd, h, flags);
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
__fds_unlock();
|
||||
}
|
||||
__zipos_free(zipos, h);
|
||||
__zipos_free(h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __zipos_open_impl(struct ZiposUri *name, int flags) {
|
||||
struct Zipos *zipos;
|
||||
if (!(zipos = __zipos_get())) {
|
||||
return enoexec();
|
||||
}
|
||||
ssize_t cf;
|
||||
if ((cf = __zipos_find(zipos, name)) == -1) {
|
||||
return enoent();
|
||||
}
|
||||
if ((flags & O_ACCMODE) != O_RDONLY || (flags & O_TRUNC)) {
|
||||
return erofs();
|
||||
}
|
||||
if (flags & O_EXCL) {
|
||||
return eexist();
|
||||
}
|
||||
if (cf != ZIPOS_SYNTHETIC_DIRECTORY) {
|
||||
int mode = GetZipCfileMode(zipos->map + cf);
|
||||
#if 0
|
||||
if ((flags & O_DIRECTORY) && !S_ISDIR(mode)) {
|
||||
return enotdir();
|
||||
}
|
||||
#endif
|
||||
if (!(mode & 0444)) {
|
||||
return eacces();
|
||||
}
|
||||
}
|
||||
return __zipos_load(zipos, cf, flags, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
|
@ -190,33 +233,15 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags,
|
|||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
int __zipos_open(const struct ZiposUri *name, unsigned flags, int mode) {
|
||||
int __zipos_open(struct ZiposUri *name, int flags) {
|
||||
int rc;
|
||||
ssize_t cf;
|
||||
struct Zipos *zipos;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
BLOCK_SIGNALS;
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
if ((zipos = __zipos_get())) {
|
||||
if ((cf = __zipos_find(zipos, name)) != -1) {
|
||||
rc = __zipos_load(zipos, cf, flags, mode);
|
||||
assert(rc != 0);
|
||||
} else {
|
||||
rc = enoent();
|
||||
assert(rc != 0);
|
||||
}
|
||||
} else {
|
||||
rc = enoexec();
|
||||
assert(rc != 0);
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
assert(rc != 0);
|
||||
}
|
||||
rc = __zipos_open_impl(name, flags);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,19 +16,21 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Extracts information about ZIP URI if it is one.
|
||||
*/
|
||||
ssize_t __zipos_parseuri(const char *uri, struct ZiposUri *out) {
|
||||
size_t len;
|
||||
if ((uri[0] == '/' && uri[1] == 'z' && uri[2] == 'i' && uri[3] == 'p' &&
|
||||
if ((uri[0] == '/' && //
|
||||
uri[1] == 'z' && //
|
||||
uri[2] == 'i' && //
|
||||
uri[3] == 'p' && //
|
||||
(!uri[4] || uri[4] == '/')) &&
|
||||
(len = strlen(uri)) < PATH_MAX) {
|
||||
out->path = uri + 4 + !!uri[4];
|
||||
return (out->len = len - 4 - !!uri[4]);
|
||||
strlcpy(out->path, uri + 4 + !!uri[4], ZIPOS_PATH_MAX) < ZIPOS_PATH_MAX) {
|
||||
return (out->len = __zipos_normpath(out->path));
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -18,11 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static size_t GetIovSize(const struct iovec *iov, size_t iovlen) {
|
||||
size_t i, r;
|
||||
|
@ -30,6 +29,29 @@ static size_t GetIovSize(const struct iovec *iov, size_t iovlen) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
|
||||
size_t iovlen, ssize_t opt_offset) {
|
||||
int i;
|
||||
int64_t b, x, y;
|
||||
if (h->cfile == ZIPOS_SYNTHETIC_DIRECTORY ||
|
||||
S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
|
||||
return eisdir();
|
||||
}
|
||||
if (opt_offset == -1) {
|
||||
x = y = h->pos;
|
||||
} else {
|
||||
x = y = opt_offset;
|
||||
}
|
||||
for (i = 0; i < iovlen && y < h->size; ++i, y += b) {
|
||||
b = MIN(iov[i].iov_len, h->size - y);
|
||||
if (b) memcpy(iov[i].iov_base, h->mem + y, b);
|
||||
}
|
||||
if (opt_offset == -1) {
|
||||
h->pos = y;
|
||||
}
|
||||
return y - x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from zip store object.
|
||||
*
|
||||
|
@ -39,14 +61,10 @@ static size_t GetIovSize(const struct iovec *iov, size_t iovlen) {
|
|||
*/
|
||||
ssize_t __zipos_read(struct ZiposHandle *h, const struct iovec *iov,
|
||||
size_t iovlen, ssize_t opt_offset) {
|
||||
size_t i, b, x, y;
|
||||
ssize_t rc;
|
||||
unassert(opt_offset >= 0 || opt_offset == -1);
|
||||
pthread_mutex_lock(&h->lock);
|
||||
x = y = opt_offset != -1 ? opt_offset : h->pos;
|
||||
for (i = 0; i < iovlen && y < h->size; ++i, y += b) {
|
||||
b = min(iov[i].iov_len, h->size - y);
|
||||
if (b) memcpy(iov[i].iov_base, h->mem + y, b);
|
||||
}
|
||||
if (opt_offset == -1) h->pos = y;
|
||||
rc = __zipos_read_impl(h, iov, iovlen, opt_offset);
|
||||
pthread_mutex_unlock(&h->lock);
|
||||
return y - x;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -18,17 +18,19 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#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"
|
||||
#include "libc/runtime/zipos.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) {
|
||||
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);
|
||||
|
@ -37,8 +39,6 @@ int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
|
|||
GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim,
|
||||
&st->st_ctim, 0);
|
||||
st->st_birthtim = st->st_ctim;
|
||||
} else {
|
||||
st->st_mode = 0444 | S_IFDIR | 0111;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Reads file metadata from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
|
@ -26,22 +25,10 @@
|
|||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __zipos_stat(const struct ZiposUri *name, struct stat *st) {
|
||||
int rc;
|
||||
int __zipos_stat(struct ZiposUri *name, struct stat *st) {
|
||||
ssize_t cf;
|
||||
struct Zipos *zipos;
|
||||
if (st) {
|
||||
if ((zipos = __zipos_get())) {
|
||||
if ((cf = __zipos_find(zipos, name)) != -1) {
|
||||
rc = __zipos_stat_impl(zipos, cf, st);
|
||||
} else {
|
||||
rc = enoent();
|
||||
}
|
||||
} else {
|
||||
rc = enoexec();
|
||||
}
|
||||
} else {
|
||||
rc = efault();
|
||||
}
|
||||
return rc;
|
||||
if (!(zipos = __zipos_get())) return enoexec();
|
||||
if ((cf = __zipos_find(zipos, name)) == -1) return enoent();
|
||||
return __zipos_stat_impl(zipos, cf, st);
|
||||
}
|
||||
|
|
|
@ -6,23 +6,29 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define ZIPOS_PATH_MAX 1024
|
||||
|
||||
#define ZIPOS_SYNTHETIC_DIRECTORY 0
|
||||
|
||||
struct stat;
|
||||
struct iovec;
|
||||
struct Zipos;
|
||||
|
||||
struct ZiposUri {
|
||||
const char *path;
|
||||
size_t len;
|
||||
uint32_t len;
|
||||
char path[ZIPOS_PATH_MAX];
|
||||
};
|
||||
|
||||
struct ZiposHandle {
|
||||
struct ZiposHandle *next;
|
||||
pthread_mutex_t lock;
|
||||
size_t size; /* byte length of `mem` */
|
||||
size_t mapsize; /* total size of this struct */
|
||||
size_t pos; /* read/write byte offset state */
|
||||
uint32_t cfile; /* central directory entry rva */
|
||||
uint8_t *mem; /* points to inflated data or uncompressed image */
|
||||
uint8_t data[]; /* uncompressed file memory */
|
||||
struct Zipos *zipos;
|
||||
size_t size;
|
||||
size_t mapsize;
|
||||
size_t pos;
|
||||
size_t cfile;
|
||||
uint8_t *mem;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
struct Zipos {
|
||||
|
@ -31,17 +37,18 @@ struct Zipos {
|
|||
struct ZiposHandle *freelist;
|
||||
};
|
||||
|
||||
int __zipos_close(int);
|
||||
void __zipos_lock(void);
|
||||
void __zipos_unlock(void);
|
||||
int __zipos_close(int);
|
||||
size_t __zipos_normpath(char *);
|
||||
struct Zipos *__zipos_get(void) pureconst;
|
||||
void __zipos_free(struct Zipos *, struct ZiposHandle *);
|
||||
void __zipos_free(struct ZiposHandle *);
|
||||
ssize_t __zipos_parseuri(const char *, struct ZiposUri *);
|
||||
ssize_t __zipos_find(struct Zipos *, const struct ZiposUri *);
|
||||
int __zipos_open(const struct ZiposUri *, unsigned, int);
|
||||
int __zipos_access(const struct ZiposUri *, int);
|
||||
int __zipos_stat(const struct ZiposUri *, struct stat *);
|
||||
int __zipos_fstat(const struct ZiposHandle *, struct stat *);
|
||||
ssize_t __zipos_find(struct Zipos *, struct ZiposUri *);
|
||||
int __zipos_open(struct ZiposUri *, int);
|
||||
int __zipos_access(struct ZiposUri *, int);
|
||||
int __zipos_stat(struct ZiposUri *, struct stat *);
|
||||
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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue