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:
Justine Tunney 2023-08-15 18:24:53 -07:00
parent 4658ae539f
commit 110559ce6a
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
48 changed files with 748 additions and 500 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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);