Revert "Rewrite ZipOS"

This reverts commit b01282e23e. Some tests
are broken. It's not clear how it'll impact metal yet. Let's revisit the
memory optimization benefits of this change again sometime soon.
This commit is contained in:
Justine Tunney 2023-10-03 14:40:03 -07:00
parent ee8a861635
commit ff250a0c10
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
21 changed files with 420 additions and 407 deletions

View file

@ -12,7 +12,6 @@
#include "dsp/tty/tty.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
@ -29,6 +28,7 @@
#include "libc/mem/arraylist2.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
@ -1808,12 +1808,19 @@ void GetOpts(int argc, char* argv[]) {
}
size_t FindZipGames(void) {
DIR* dir;
if ((dir = opendir("/zip/usr/share/rom"))) {
struct dirent* ent;
while ((ent = readdir(dir))) {
if (endswith(ent->d_name, ".nes")) {
char* name = xasprintf("/zip/usr/share/rom/%s", ent->d_name);
char* name;
size_t i, cf;
struct Zipos* zipos;
if ((zipos = __zipos_get())) {
for (i = 0, cf = ZIP_CDIR_OFFSET(zipos->cdir);
i < ZIP_CDIR_RECORDS(zipos->cdir);
++i, cf += ZIP_CFILE_HDRSIZE(zipos->map + cf)) {
if (ZIP_CFILE_NAMESIZE(zipos->map + cf) > 4 &&
!memcmp((ZIP_CFILE_NAME(zipos->map + cf) +
ZIP_CFILE_NAMESIZE(zipos->map + cf) - 4),
".nes", 4) &&
(name = xasprintf("/zip/%.*s", ZIP_CFILE_NAMESIZE(zipos->map + cf),
ZIP_CFILE_NAME(zipos->map + cf)))) {
APPEND(&zipgames_.p, &zipgames_.i, &zipgames_.n, &name);
}
}

View file

@ -28,14 +28,9 @@
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/rlimit.h"
// Hack for guessing the unknowable boundaries of _start()'s stack
// Hack for guessing boundaries of _start()'s stack
//
// This code always guesses correctly on Windows because WinMain()
// is written to allocate a stack ourself. Local testing on Linux,
// XNU, FreeBSD, OpenBSD, and NetBSD says that accuracy is ±1 page
// and that error rate applies to both beginning and end addresses
//
// Every UNIX system in our support vector creates arg blocks like
// Every UNIX system in our support vector creates arg blocks like:
//
// <HIGHEST-STACK-ADDRESS>
// last environ string
@ -60,6 +55,11 @@
// up to the microprocessor page size (this computes the top addr)
// and the bottom is computed by subtracting RLIMIT_STACK rlim_cur
// It's simple but gets tricky if we consider environ can be empty
//
// This code always guesses correctly on Windows because WinMain()
// is written to allocate a stack ourself. Local testing on Linux,
// XNU, FreeBSD, OpenBSD, and NetBSD says that accuracy is ±1 page
// and that error rate applies to both beginning and end addresses
static char *__get_last(char **list) {
char *res = 0;

View file

@ -135,6 +135,7 @@ __msabi extern typeof(WriteFile) *const __imp_WriteFile;
// clang-format on
long __klog_handle;
extern struct SymbolTable *__symtab;
__funline char *kadvance(char *p, char *e, long n) {
intptr_t t = (intptr_t)p;
@ -754,11 +755,11 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
// can be manually consulted to look up the faulting code.
int idx;
x = va_arg(va, intptr_t);
if (_weaken(__symtab) && _weaken(__symtab)->st &&
if (_weaken(__symtab) && *_weaken(__symtab) &&
(idx = _weaken(__get_symbol)(0, x)) != -1) {
if (p + 1 <= e) *p++ = '&';
s = _weaken(__symtab)->st->name_base +
_weaken(__symtab)->st->names[idx];
s = (*_weaken(__symtab))->name_base +
(*_weaken(__symtab))->names[idx];
goto FormatString;
}
base = 4;

View file

@ -19,6 +19,8 @@
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
extern struct SymbolTable *__symtab;
/**
* Returns low index into symbol table for address.
*
@ -31,8 +33,8 @@ privileged int __get_symbol(struct SymbolTable *t, intptr_t a) {
// we don't want function tracing because:
// function tracing depends on this function via kprintf
unsigned l, m, r, n, k;
if (!t && __symtab.st) {
t = __symtab.st;
if (!t && __symtab) {
t = __symtab;
}
if (t) {
l = 0;

View file

@ -16,89 +16,127 @@
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/cosmo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/assert.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/promises.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
#include "libc/x/x.h"
#include "libc/zip.internal.h"
#include "third_party/puff/puff.h"
__static_yoink("__get_symbol");
struct SymbolTableLoader __symtab;
static pthread_spinlock_t g_lock;
struct SymbolTable *__symtab; // for kprintf
static struct SymbolTable *GetSymbolTableFromZip(void) {
int fd;
struct SymbolTable *res = 0;
if ((fd = open("/zip/.symtab." _ARCH_NAME, O_RDONLY)) != -1 ||
(fd = open("/zip/.symtab", O_RDONLY)) != -1) {
void *map;
ssize_t size;
if ((size = lseek(fd, 0, SEEK_END)) != -1 &&
(map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) !=
MAP_FAILED) {
res = map;
static ssize_t GetZipFile(struct Zipos *zipos, const char *name) {
size_t i, n, c, z;
z = strlen(name);
c = GetZipCdirOffset(zipos->cdir);
n = GetZipCdirRecords(zipos->cdir);
for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) {
if (ZIP_CFILE_NAMESIZE(zipos->map + c) == z &&
!memcmp(ZIP_CFILE_NAME(zipos->map + c), name, z)) {
return c;
}
close(fd);
}
return -1;
}
/**
* Reads symbol table from zip directory.
* @note This code can't depend on dlmalloc()
*/
static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
ssize_t cf, lf;
size_t size, size2;
struct SymbolTable *res = 0;
if ((cf = GetZipFile(zipos, ".symtab." _ARCH_NAME)) != -1 ||
(cf = GetZipFile(zipos, ".symtab")) != -1) {
lf = GetZipCfileOffset(zipos->map + cf);
size = GetZipLfileUncompressedSize(zipos->map + lf);
size2 = ROUNDUP(size, FRAMESIZE);
if ((res = _mapanon(size2))) {
switch (ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf)) {
case kZipCompressionNone:
memcpy(res, (void *)ZIP_LFILE_CONTENT(zipos->map + lf), size);
break;
case kZipCompressionDeflate:
if (__inflate((void *)res, size,
(void *)ZIP_LFILE_CONTENT(zipos->map + lf),
GetZipLfileCompressedSize(zipos->map + lf))) {
munmap(res, size2);
res = 0;
}
break;
default:
munmap(res, size2);
res = 0;
break;
}
}
}
STRACE("GetSymbolTableFromZip() → %p", res);
return res;
}
/**
* Reads symbol table from .com.dbg file.
* @note This code can't depend on dlmalloc()
*/
static struct SymbolTable *GetSymbolTableFromElf(void) {
const char *path;
if ((path = FindDebugBinary())) {
return OpenSymbolTable(path);
const char *s;
if (PLEDGED(RPATH) && (s = FindDebugBinary())) {
return OpenSymbolTable(s);
} else {
return 0;
}
}
static void GetSymbolTableInit(void) {
if (!PLEDGED(RPATH)) return;
int e = errno;
if ((__symtab.st = GetSymbolTableFromZip())) {
__symtab.st->names =
(uint32_t *)((char *)__symtab.st + __symtab.st->names_offset);
__symtab.st->name_base =
(char *)((char *)__symtab.st + __symtab.st->name_base_offset);
}
if (!__symtab.st) {
__symtab.st = GetSymbolTableFromElf();
}
errno = e;
}
/**
* Returns symbol table singleton.
*
* This uses multiple strategies to find the symbol table. The first
* strategy, depends on whether or not the following is linked:
*
* __static_yoink("zipos");
* __static_yoink("__zipos_get");
*
* In that case, the symbol table may be read from `/zip/.symtab.ARCH`
* or `/zip/.symtab` which are generated by `o//tool/build/symtab.com`
* or `o//tool/build/apelink.com`.
* In that case, the symbol table may be read from `/zip/.symtab` which
* is generated by `o//tool/build/symtab.com`. The second strategy is to
* look for the concomitant `.com.dbg` executable, which may very well
* be the one currently executing, or it could be placed in the same
* folder as your `.com` binary, or lastly, it could be explicitly
* specified via the `COMDBG` environment variable.
*
* The second strategy is to look for the ELF executable for the current
* program. If you're running a .com binary, it'll look for the .com.dbg
* file. If it's running the .com.dbg or .elf file, then it'll just read
* the symbols from itself. In other cases, you can explicitly specify a
* debug symbol binary via the `COMDBG` environment variable.
*
* When using pledge() security, it's recommended that this function get
* called *before* calling pledge() if it lacks the rpath promise, so it
* can load the symbols into memory before the filesystem goes away.
* Function tracing is disabled throughout the duration of this call.
* Backtraces and other core runtime functionality depend on this.
*
* @return symbol table, or NULL if not found
*/
struct SymbolTable *GetSymbolTable(void) {
cosmo_once(&__symtab.once, GetSymbolTableInit);
return __symtab.st;
struct Zipos *z;
if (pthread_spin_trylock(&g_lock)) return 0;
if (!__symtab && !__isworker) {
if (_weaken(__zipos_get) && (z = _weaken(__zipos_get)())) {
if ((__symtab = GetSymbolTableFromZip(z))) {
__symtab->names =
(uint32_t *)((char *)__symtab + __symtab->names_offset);
__symtab->name_base =
(char *)((char *)__symtab + __symtab->name_base_offset);
}
}
if (!__symtab) {
__symtab = GetSymbolTableFromElf();
}
}
pthread_spin_unlock(&g_lock);
return __symtab;
}

View file

@ -26,12 +26,6 @@ struct SymbolTable {
struct Symbol symbols[]; /* sorted and non-overlapping intervals */
};
struct SymbolTableLoader {
_Atomic(unsigned) once;
struct SymbolTable *st;
};
extern struct SymbolTableLoader __symtab;
struct SymbolTable *GetSymbolTable(void);
const char *FindComBinary(void);
const char *FindDebugBinary(void);

View file

@ -39,14 +39,14 @@ int __zipos_access(struct ZiposUri *name, int amode) {
return enoexec();
}
int cf;
ssize_t cf;
if ((cf = __zipos_find(z, name)) == -1) {
return -1;
}
int mode;
if (cf != ZIPOS_SYNTHETIC_DIRECTORY) {
mode = GetZipCfileMode(z->cdir + cf);
mode = GetZipCfileMode(z->map + cf);
} else {
mode = S_IFDIR | 0555;
}

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"
@ -31,14 +30,16 @@
* @vforksafe
*/
int __zipos_close(int fd) {
if (__vforked) {
sys_close(fd);
return 0;
int rc;
struct ZiposHandle *h;
h = (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle;
if (!IsWindows()) {
rc = sys_close(fd);
} else {
rc = 0; // no system file descriptor needed on nt
}
if (!__vforked) {
__zipos_free(h);
}
struct ZiposHandle *h = (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle;
g_fds.p[fd].handle = h->handle;
g_fds.p[fd].kind = kFdFile;
int rc = close(fd);
__zipos_free(h);
return rc;
}

View file

@ -24,11 +24,11 @@
#include "libc/sysv/errfuns.h"
#include "libc/zip.internal.h"
static int __zipos_match(struct Zipos *z, struct ZiposUri *name, int len,
int i) {
int cfile = z->index[i];
const char *zname = ZIP_CFILE_NAME(z->cdir + cfile);
int zsize = ZIP_CFILE_NAMESIZE(z->cdir + cfile);
static ssize_t __zipos_match(struct Zipos *z, struct ZiposUri *name, int len,
int i) {
size_t cfile = z->index[i];
const char *zname = ZIP_CFILE_NAME(z->map + cfile);
int zsize = ZIP_CFILE_NAMESIZE(z->map + cfile);
if ((len == zsize || (len + 1 == zsize && zname[len] == '/')) &&
!memcmp(name->path, zname, len)) {
return cfile;
@ -40,7 +40,7 @@ static int __zipos_match(struct Zipos *z, struct ZiposUri *name, int len,
}
}
int __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
ssize_t __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
// strip trailing slash from search name
int len = name->len;
@ -55,12 +55,12 @@ int __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
// binary search for leftmost name in central directory
int l = 0;
int r = zipos->cnt;
int r = zipos->records;
while (l < r) {
int m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2)
const char *xp = ZIP_CFILE_NAME(zipos->cdir + zipos->index[m]);
const char *xp = ZIP_CFILE_NAME(zipos->map + zipos->index[m]);
const char *yp = name->path;
int xn = ZIP_CFILE_NAMESIZE(zipos->cdir + zipos->index[m]);
int xn = ZIP_CFILE_NAMESIZE(zipos->map + zipos->index[m]);
int yn = len;
int n = MIN(xn, yn);
int c;
@ -78,25 +78,25 @@ int __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
}
}
if (l < zipos->cnt) {
if (l < zipos->records) {
int dx;
int cfile = zipos->index[l];
const char *zname = ZIP_CFILE_NAME(zipos->cdir + cfile);
int zsize = ZIP_CFILE_NAMESIZE(zipos->cdir + cfile);
size_t cfile = zipos->index[l];
const char *zname = ZIP_CFILE_NAME(zipos->map + cfile);
int zsize = ZIP_CFILE_NAMESIZE(zipos->map + cfile);
if (zsize > len && (dx = '/' - (zname[len] & 255))) {
// since the index is asciibetical, we need to specially handle
// the case where, when searching for a directory, regular files
// exist whose names share the same prefix as the directory name.
dx = dx > +1 ? +1 : dx;
dx = dx < -1 ? -1 : dx;
for (l += dx; 0 <= l && l < zipos->cnt; l += dx) {
int cf;
for (l += dx; 0 <= l && l < zipos->records; l += dx) {
ssize_t cf;
if ((cf = __zipos_match(zipos, name, len, l)) != -1) {
return cf;
}
cfile = zipos->index[l];
zname = ZIP_CFILE_NAME(zipos->cdir + cfile);
zsize = ZIP_CFILE_NAMESIZE(zipos->cdir + cfile);
zname = ZIP_CFILE_NAME(zipos->map + cfile);
zsize = ZIP_CFILE_NAMESIZE(zipos->map + cfile);
if (zsize < len || (len && zname[len - 1] != name->path[len - 1])) {
break;
}
@ -112,8 +112,8 @@ int __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
}
// support code for open(), stat(), and access()
int __zipos_find(struct Zipos *zipos, struct ZiposUri *name) {
int cf;
ssize_t __zipos_find(struct Zipos *zipos, struct ZiposUri *name) {
ssize_t cf;
if ((cf = __zipos_scan(zipos, name)) == -1) {
// test if parent component exists that isn't a directory
char *p;
@ -121,7 +121,7 @@ int __zipos_find(struct Zipos *zipos, struct ZiposUri *name) {
name->path[name->len = p - name->path] = 0;
if ((cf = __zipos_scan(zipos, name)) != -1 &&
cf != ZIPOS_SYNTHETIC_DIRECTORY &&
!S_ISDIR(GetZipCfileMode(zipos->cdir + cf))) {
!S_ISDIR(GetZipCfileMode(zipos->map + cf))) {
return enotdir();
}
}
@ -130,7 +130,7 @@ int __zipos_find(struct Zipos *zipos, struct ZiposUri *name) {
// test if we're opening "foo/" and "foo" isn't a directory
if (cf != ZIPOS_SYNTHETIC_DIRECTORY && //
name->len && name->path[name->len - 1] == '/' &&
!S_ISDIR(GetZipCfileMode(zipos->cdir + cf))) {
!S_ISDIR(GetZipCfileMode(zipos->map + cf))) {
return enotdir();
}
return cf;

View file

@ -16,17 +16,25 @@
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/promises.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.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"
@ -34,162 +42,118 @@
__static_yoink(APE_COM_NAME);
#endif
struct ZiposPlanner {
uint8_t buf[kZipLookbehindBytes];
struct stat st;
};
static struct Zipos __zipos;
static atomic_uint __zipos_once;
static void __zipos_wipe(void) {
pthread_mutex_init(&__zipos.lock, 0);
static void __zipos_dismiss(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 (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;
}
// 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 really?
lo = ROUNDDOWN(lo, pg);
hi = MIN(ROUNDUP(hi, pg), ROUNDDOWN(c, pg));
if (hi > lo) {
posix_madvise(map + lo, hi - lo, POSIX_MADV_DONTNEED);
}
}
void __zipos_lock(void) {
pthread_mutex_lock(&__zipos.lock);
}
void __zipos_unlock(void) {
pthread_mutex_unlock(&__zipos.lock);
}
static int __zipos_compare(const void *a, const void *b, void *c) {
uint8_t *cdir = (uint8_t *)c;
const int *x = (const int *)a;
const int *y = (const int *)b;
int xn = ZIP_CFILE_NAMESIZE(cdir + *x);
int yn = ZIP_CFILE_NAMESIZE(cdir + *y);
static int __zipos_compare_names(const void *a, const void *b, void *c) {
const size_t *x = (const size_t *)a;
const size_t *y = (const size_t *)b;
struct Zipos *z = (struct Zipos *)c;
int xn = ZIP_CFILE_NAMESIZE(z->map + *x);
int yn = ZIP_CFILE_NAMESIZE(z->map + *y);
int n = MIN(xn, yn);
if (n) {
int res = memcmp(ZIP_CFILE_NAME(cdir + *x), ZIP_CFILE_NAME(cdir + *y), n);
int res =
memcmp(ZIP_CFILE_NAME(z->map + *x), ZIP_CFILE_NAME(z->map + *y), n);
if (res) return res;
}
return xn - yn; // xn and yn are 16-bit
}
static dontinline int __zipos_plan(int fd, struct ZiposPlanner *p) {
// get file size and dev/inode
// this might fail if a bad fd was passed via environment
if (fstat(fd, &p->st)) {
return kZipErrorOpenFailed;
// creates binary searchable array of file offsets to cdir records
static void __zipos_generate_index(struct Zipos *zipos) {
size_t c, i;
zipos->records = GetZipCdirRecords(zipos->cdir);
zipos->index = _mapanon(zipos->records * sizeof(size_t));
for (i = 0, c = GetZipCdirOffset(zipos->cdir); i < zipos->records;
++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) {
zipos->index[i] = c;
}
// read the last 64kb of file
// the zip file format magic can be anywhere in there
int amt;
int64_t off;
if (p->st.st_size <= kZipLookbehindBytes) {
off = 0;
amt = p->st.st_size;
} else {
off = p->st.st_size - kZipLookbehindBytes;
amt = p->st.st_size - off;
}
if (pread(fd, p->buf, amt, off) != amt) {
return kZipErrorReadFailed;
}
// search backwards for the end-of-central-directory record
// the eocd (cdir) says where the central directory (cfile) array is located
// we consistency check some legacy fields, to be extra sure that it is eocd
int cnt = 0;
for (int i = amt - MIN(kZipCdirHdrMinSize, kZipCdir64LocatorSize); i; --i) {
uint32_t magic = READ32LE(p->buf + i);
if (magic == kZipCdir64LocatorMagic && i + kZipCdir64LocatorSize <= amt &&
pread(fd, p->buf, kZipCdirHdrMinSize,
ZIP_LOCATE64_OFFSET(p->buf + i)) == kZipCdirHdrMinSize &&
READ32LE(p->buf) == kZipCdir64HdrMagic &&
ZIP_CDIR64_RECORDS(p->buf) == ZIP_CDIR64_RECORDSONDISK(p->buf) &&
ZIP_CDIR64_RECORDS(p->buf) && ZIP_CDIR64_SIZE(p->buf) <= INT_MAX) {
cnt = ZIP_CDIR64_RECORDS(p->buf);
off = ZIP_CDIR64_OFFSET(p->buf);
amt = ZIP_CDIR64_SIZE(p->buf);
break;
}
if (magic == kZipCdirHdrMagic && i + kZipCdirHdrMinSize <= amt &&
ZIP_CDIR_RECORDS(p->buf + i) == ZIP_CDIR_RECORDSONDISK(p->buf + i) &&
ZIP_CDIR_RECORDS(p->buf + i) && ZIP_CDIR_SIZE(p->buf + i) <= INT_MAX) {
cnt = ZIP_CDIR_RECORDS(p->buf + i);
off = ZIP_CDIR_OFFSET(p->buf + i);
amt = ZIP_CDIR_SIZE(p->buf + i);
break;
}
}
if (cnt <= 0) {
return kZipErrorEocdNotFound;
}
// we'll store the entire central directory in memory
// in addition to a file name index that's bisectable
void *memory;
int cdirsize = amt;
size_t indexsize = cnt * sizeof(int);
size_t memorysize = indexsize + cdirsize;
if (!(memory = _mapanon(memorysize))) {
return kZipErrorMapFailed;
}
int *index = memory;
uint8_t *cdir = (uint8_t *)memory + indexsize;
// read the central directory
if (pread(fd, cdir, cdirsize, off) != cdirsize) {
return kZipErrorReadFailed;
}
// generate our file name index
// smoothsort() isn't the fastest algorithm, but it guarantees
// o(logn), won't smash the stack and doesn't depend on malloc
int entry_index, entry_offset;
for (entry_index = entry_offset = 0;
entry_index < cnt && entry_offset + kZipCfileHdrMinSize <= cdirsize &&
entry_offset + ZIP_CFILE_HDRSIZE(cdir + entry_offset) <= cdirsize;
++entry_index, entry_offset += ZIP_CFILE_HDRSIZE(cdir + entry_offset)) {
index[entry_index] = entry_offset;
}
if (cnt != entry_index) {
return kZipErrorZipCorrupt;
}
smoothsort_r(index, cnt, sizeof(int), __zipos_compare, cdir);
// finally populate the global singleton
__zipos.cnt = cnt;
__zipos.cdir = cdir;
__zipos.index = index;
__zipos.dev = p->st.st_ino;
__zipos.cdirsize = cdirsize;
return kZipOk;
}
static dontinline int __zipos_setup(int fd) {
// allocates 64kb on the stack as scratch memory
// this should only be used from the main thread
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wframe-larger-than="
struct ZiposPlanner p;
CheckLargeStackAllocation(&p, sizeof(p));
#pragma GCC pop_options
return __zipos_plan(fd, &p);
smoothsort_r(zipos->index, zipos->records, sizeof(size_t),
__zipos_compare_names, zipos);
}
static void __zipos_init(void) {
int status;
if (getenv("COSMOPOLITAN_DISABLE_ZIPOS")) return;
if (!(__zipos.progpath = getenv("COSMOPOLITAN_INIT_ZIPOS"))) {
__zipos.progpath = GetProgramExecutableName();
}
int fd = open(__zipos.progpath, O_RDONLY);
if (fd != -1) {
if (!(status = __zipos_setup(fd))) {
__zipos_wipe();
pthread_atfork(__zipos_lock, __zipos_unlock, __zipos_wipe);
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;
}
close(fd);
} else {
status = kZipErrorOpenFailed;
progpath = 0;
msg = -777;
}
(void)status;
STRACE("__zipos_init(%#s) → %d% m", __zipos.progpath, status);
(void)msg;
STRACE("__zipos_get(%#s) → %d% m", progpath, msg);
}
/**
@ -197,6 +161,6 @@ static void __zipos_init(void) {
* @asyncsignalsafe
*/
struct Zipos *__zipos_get(void) {
cosmo_once(&__zipos.once, __zipos_init);
return __zipos.cnt ? &__zipos : 0;
cosmo_once(&__zipos_once, __zipos_init);
return __zipos.cdir ? &__zipos : 0;
}

View file

@ -33,6 +33,7 @@ static uint64_t __zipos_fnv(const char *s, int len) {
uint64_t __zipos_inode(struct Zipos *zipos, int64_t cfile, //
const void *name, size_t namelen) {
unassert(cfile >= 0);
if (cfile == ZIPOS_SYNTHETIC_DIRECTORY) {
if (namelen && ((char *)name)[namelen - 1] == '/') --namelen;
cfile = INT64_MIN | __zipos_fnv(name, namelen);

View file

@ -50,7 +50,7 @@
* @return virtual base address of new mapping, or MAP_FAILED w/ errno
*/
void *__zipos_mmap(void *addr, size_t size, int prot, int flags,
struct ZiposHandle *h, int64_t off) {
struct ZiposHandle *h, int64_t off) {
if (off < 0) {
STRACE("negative zipos mmap offset");
@ -58,7 +58,7 @@ void *__zipos_mmap(void *addr, size_t size, int prot, int flags,
}
if (h->cfile == ZIPOS_SYNTHETIC_DIRECTORY ||
S_ISDIR(GetZipCfileMode(h->zipos->cdir + h->cfile))) {
S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
return VIP(eisdir());
}

View file

@ -16,56 +16,68 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/blocksigs.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#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"
#include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#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/str/str.h"
#include "libc/sysv/consts/at.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/thread/tls.h"
#include "libc/zip.internal.h"
#include "third_party/zlib/zconf.h"
#include "third_party/zlib/zlib.h"
static bool __zipos_method_is_supported(int method) {
switch (method) {
case kZipCompressionNone:
case kZipCompressionDeflate:
return true;
default:
return false;
}
static char *__zipos_mapend;
static size_t __zipos_maptotal;
static pthread_mutex_t __zipos_lock_obj;
static void __zipos_wipe(void) {
pthread_mutex_init(&__zipos_lock_obj, 0);
}
static void *__zipos_mmap_space(struct Zipos *zipos, size_t mapsize) {
static void __zipos_lock(void) {
pthread_mutex_lock(&__zipos_lock_obj);
}
static void __zipos_unlock(void) {
pthread_mutex_unlock(&__zipos_lock_obj);
}
static void *__zipos_mmap_space(size_t mapsize) {
char *start;
size_t offset;
offset = zipos->maptotal;
zipos->maptotal += mapsize;
unassert(mapsize);
offset = __zipos_maptotal;
__zipos_maptotal += mapsize;
start = (char *)kMemtrackZiposStart;
if (!zipos->mapend) zipos->mapend = start;
zipos->mapend = _extend(start, zipos->maptotal, zipos->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;
}
void __zipos_free(struct ZiposHandle *h) {
if (!h) return;
if (IsAsan()) {
__asan_poison((char *)h + sizeof(struct ZiposHandle),
h->mapsize - sizeof(struct ZiposHandle), kAsanHeapFree);
@ -93,7 +105,7 @@ StartOver:
ph = &h->next;
}
if (!h) {
h = __zipos_mmap_space(zipos, mapsize);
h = __zipos_mmap_space(mapsize);
}
__zipos_unlock();
if (IsAsan()) {
@ -110,85 +122,91 @@ StartOver:
return h;
}
static int __zipos_load_fd(struct Zipos *zipos, int cf, int fd,
struct ZiposUri *name,
struct ZiposHandle **out_handle) {
uint64_t size;
static int __zipos_mkfd(int minfd) {
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;
}
}
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].extra = 0;
__fds_unlock();
return fd;
}
static int __zipos_load(struct Zipos *zipos, size_t cf, int flags,
struct ZiposUri *name) {
size_t lf;
size_t size;
int fd, minfd;
struct ZiposHandle *h;
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 {
uint8_t lfile[kZipLfileHdrMinSize];
uint64_t lf = GetZipCfileOffset(zipos->cdir + cf);
int compressed = ZIP_CFILE_COMPRESSIONMETHOD(zipos->cdir + cf);
if (!__zipos_method_is_supported(compressed) ||
pread(fd, lfile, kZipLfileHdrMinSize, lf) != kZipLfileHdrMinSize ||
ZIP_LFILE_MAGIC(lfile) != kZipLfileHdrMagic) {
return eio(); // this corruption
}
size = GetZipCfileUncompressedSize(zipos->cdir + cf);
if (!(h = __zipos_alloc(zipos, size))) return -1;
uint64_t off = lf + ZIP_LFILE_HDRSIZE(lfile);
if (!compressed) {
if (pread(fd, h->data, size, off) != size) {
__zipos_free(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();
}
} else {
struct ZiposHandle *h2;
uint64_t compsize = GetZipCfileCompressedSize(zipos->cdir + cf);
if (!(h2 = __zipos_alloc(zipos, compsize))) {
__zipos_free(h);
return -1;
}
if (pread(fd, h2->data, compsize, off) != compsize ||
__inflate(h->data, size, h2->data, compsize)) {
__zipos_free(h2);
__zipos_free(h);
return eio();
}
__zipos_free(h2);
}
}
h->pos = 0;
h->cfile = cf;
h->size = size;
*out_handle = h;
return 0;
}
static int __zipos_load(struct Zipos *zipos, int cf, int flags,
struct ZiposUri *name) {
int fd;
if ((fd = openat(AT_FDCWD, zipos->progpath,
O_RDONLY | O_CLOEXEC |
(flags & (O_NONBLOCK | O_RANDOM | O_SEQUENTIAL)),
0)) != -1) {
struct ZiposHandle *h = 0;
if (__zipos_load_fd(zipos, cf, fd, name, &h) != -1) {
if (!IsWindows() && !IsMetal()) {
// unix doesn't use the g_fds table by default, so we need to
// explicitly ensure an entry exists for our new open()d file
__ensurefds(fd);
if (h->mem) {
minfd = 3;
__fds_lock();
TryAgain:
if (IsWindows() || IsMetal()) {
if ((fd = __reservefd_unlocked(-1)) != -1) {
return __zipos_setfd(fd, h, flags);
}
// turn it from a file fd to a zip fd
// layer the handle on windows so it can be restored on close
h->handle = g_fds.p[fd].handle;
g_fds.p[fd].kind = kFdZip;
g_fds.p[fd].handle = (intptr_t)h;
g_fds.p[fd].flags &= ~O_CLOEXEC;
g_fds.p[fd].flags |= flags & O_CLOEXEC;
return fd;
} else {
close(fd);
return -1;
} else if ((fd = __zipos_mkfd(minfd)) != -1) {
if (__ensurefds_unlocked(fd) != -1) {
if (g_fds.p[fd].kind) {
sys_close(fd);
minfd = fd + 1;
goto TryAgain;
}
return __zipos_setfd(fd, h, flags);
}
sys_close(fd);
}
} else {
return -1;
__fds_unlock();
}
__zipos_free(h);
return -1;
}
/**
@ -213,10 +231,6 @@ int __zipos_open(struct ZiposUri *name, int flags) {
(flags & O_ACCMODE) != O_RDONLY) {
return erofs();
}
if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_NOFOLLOW | O_NOCTTY | O_DIRECTORY |
O_NOATIME | O_RANDOM | O_SEQUENTIAL))) {
return einval();
}
// get the zipos global singleton
struct Zipos *zipos;
@ -228,12 +242,15 @@ int __zipos_open(struct ZiposUri *name, int flags) {
// 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
int cf;
ssize_t cf;
if ((cf = __zipos_find(zipos, name)) == -1) {
return -1;
}
if (flags & O_EXCL) {
return eexist();
}
if (cf != ZIPOS_SYNTHETIC_DIRECTORY) {
int mode = GetZipCfileMode(zipos->cdir + cf);
int mode = GetZipCfileMode(zipos->map + cf);
if ((flags & O_DIRECTORY) && !S_ISDIR(mode)) {
return enotdir();
}
@ -248,3 +265,8 @@ int __zipos_open(struct ZiposUri *name, int flags) {
ALLOW_SIGNALS;
return rc;
}
__attribute__((__constructor__)) static void __zipos_ctor(void) {
__zipos_wipe();
pthread_atfork(__zipos_lock, __zipos_unlock, __zipos_wipe);
}

View file

@ -29,7 +29,7 @@ static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
int i;
int64_t b, x, y;
if (h->cfile == ZIPOS_SYNTHETIC_DIRECTORY ||
S_ISDIR(GetZipCfileMode(h->zipos->cdir + h->cfile))) {
S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
return eisdir();
}
if (opt_offset == -1) {
@ -39,7 +39,7 @@ static ssize_t __zipos_read_impl(struct ZiposHandle *h, const struct iovec *iov,
}
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->data + y, b);
if (b) memcpy(iov[i].iov_base, h->mem + y, b);
}
if (opt_offset == -1) {
h->pos = y;

View file

@ -25,7 +25,8 @@
#include "libc/sysv/consts/s.h"
#include "libc/zip.internal.h"
int __zipos_stat_impl(struct Zipos *zipos, int cf, struct stat *st) {
int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
size_t lf;
bzero(st, sizeof(*st));
st->st_nlink = 1;
st->st_dev = zipos->dev;
@ -34,11 +35,12 @@ int __zipos_stat_impl(struct Zipos *zipos, int cf, struct stat *st) {
st->st_mode = S_IFDIR | (0555 & ~atomic_load_explicit(
&__umask, memory_order_acquire));
} else {
st->st_mode = GetZipCfileMode(zipos->cdir + cf);
st->st_size = GetZipCfileUncompressedSize(zipos->cdir + cf);
lf = GetZipCfileOffset(zipos->map + cf);
st->st_mode = GetZipCfileMode(zipos->map + cf);
st->st_size = GetZipLfileUncompressedSize(zipos->map + lf);
st->st_blocks =
roundup(GetZipCfileCompressedSize(zipos->cdir + cf), 512) / 512;
GetZipCfileTimestamps(zipos->cdir + cf, &st->st_mtim, &st->st_atim,
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;
}

View file

@ -27,7 +27,7 @@
* @asyncsignalsafe
*/
int __zipos_stat(struct ZiposUri *name, struct stat *st) {
int cf;
ssize_t cf;
struct Zipos *zipos;
if (!(zipos = __zipos_get())) return enoexec();
if ((cf = __zipos_find(zipos, name)) == -1) return -1;

View file

@ -1,12 +1,11 @@
#ifndef COSMOPOLITAN_ZIPOS_H_
#define COSMOPOLITAN_ZIPOS_H_
#include "libc/thread/thread.h"
#ifndef COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_
#define COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define ZIPOS_PATH_MAX 1024
#define ZIPOS_SYNTHETIC_DIRECTORY -2
#define ZIPOS_SYNTHETIC_DIRECTORY 0
struct stat;
struct iovec;
@ -20,43 +19,37 @@ struct ZiposUri {
struct ZiposHandle {
struct ZiposHandle *next;
struct Zipos *zipos;
int64_t handle; /* original upstream open()'d handle */
uint64_t size; /* accessible bytes stored at data[] */
uint64_t mapsize; /* the full byte size of this struct */
uint64_t pos; /* the file position, relative start */
int cfile; /* byte offset into zipos->cdir ents */
uint8_t data[]; /* original file content or dir name */
size_t size;
size_t mapsize;
size_t pos;
size_t cfile;
uint8_t *mem;
uint8_t data[];
};
struct Zipos {
_Atomic(unsigned) once;
int cnt; /* element count, accessible via `index` */
int cdirsize; /* number of bytes accessible via `cdir` */
uint64_t dev; /* remembers st_dev, of zipos image file */
int *index; /* points to cdirsize+cnt*4 mmap'd bytes */
uint8_t *cdir; /* points after index, in the above mmap */
const char *progpath;
long pagesz;
uint8_t *map;
uint8_t *cdir;
uint64_t dev;
size_t *index;
size_t records;
struct ZiposHandle *freelist;
char *mapend;
size_t maptotal;
pthread_mutex_t lock;
};
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);
int __zipos_find(struct Zipos *, struct ZiposUri *);
int __zipos_scan(struct Zipos *, struct ZiposUri *);
ssize_t __zipos_find(struct Zipos *, struct ZiposUri *);
ssize_t __zipos_scan(struct Zipos *, struct ZiposUri *);
ssize_t __zipos_parseuri(const char *, struct ZiposUri *);
uint64_t __zipos_inode(struct Zipos *, int64_t, const void *, size_t);
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 *, int, 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_seek(struct ZiposHandle *, int64_t, unsigned);
@ -67,4 +60,4 @@ void *__zipos_mmap(void *, uint64_t, int32_t, int32_t, struct ZiposHandle *,
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_ZIPOS_H_ */
#endif /* COSMOPOLITAN_LIBC_ZIPOS_ZIPOS_H_ */

View file

@ -77,8 +77,8 @@ struct dirstream {
struct {
struct Zipos *zipos;
uint64_t inode;
int offset;
int records;
uint64_t offset;
uint64_t records;
struct ZiposUri prefix;
struct critbit0 found;
} zip;
@ -298,7 +298,7 @@ DIR *fdopendir(int fd) {
// ensure open /zip/... file is a directory
struct ZiposHandle *h = (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle;
if (h->cfile != ZIPOS_SYNTHETIC_DIRECTORY &&
!S_ISDIR(GetZipCfileMode(h->zipos->cdir + h->cfile))) {
!S_ISDIR(GetZipCfileMode(h->zipos->map + h->cfile))) {
free(dir);
enotdir();
return 0;
@ -308,8 +308,8 @@ DIR *fdopendir(int fd) {
size_t len;
const char *name;
if (h->cfile != ZIPOS_SYNTHETIC_DIRECTORY) {
len = ZIP_CFILE_NAMESIZE(h->zipos->cdir + h->cfile);
name = ZIP_CFILE_NAME(h->zipos->cdir + h->cfile);
len = ZIP_CFILE_NAMESIZE(h->zipos->map + h->cfile);
name = ZIP_CFILE_NAME(h->zipos->map + h->cfile);
} else {
len = h->size;
name = (const char *)h->data;
@ -328,8 +328,8 @@ DIR *fdopendir(int fd) {
// setup state values for directory iterator
dir->zip.zipos = h->zipos;
dir->zip.offset = 0;
dir->zip.records = h->zipos->cnt;
dir->zip.offset = GetZipCdirOffset(h->zipos->cdir);
dir->zip.records = GetZipCdirRecords(h->zipos->cdir);
dir->zip.inode = __zipos_inode(h->zipos, h->cfile, dir->zip.prefix.path,
dir->zip.prefix.len);
@ -397,8 +397,8 @@ static struct dirent *readdir_zipos(DIR *dir) {
ent->d_ino = __zipos_inode(
dir->zip.zipos, __zipos_scan(dir->zip.zipos, &p), p.path, p.len);
} else {
const char *s = ZIP_CFILE_NAME(dir->zip.zipos->cdir + dir->zip.offset);
size_t n = ZIP_CFILE_NAMESIZE(dir->zip.zipos->cdir + dir->zip.offset);
const char *s = ZIP_CFILE_NAME(dir->zip.zipos->map + dir->zip.offset);
size_t n = ZIP_CFILE_NAMESIZE(dir->zip.zipos->map + dir->zip.offset);
if (n > dir->zip.prefix.len &&
!memcmp(dir->zip.prefix.path, s, dir->zip.prefix.len)) {
s += dir->zip.prefix.len;
@ -408,7 +408,7 @@ static struct dirent *readdir_zipos(DIR *dir) {
if (p) {
n = p - s;
d_type = DT_DIR;
} else if (S_ISDIR(GetZipCfileMode(dir->zip.zipos->cdir +
} else if (S_ISDIR(GetZipCfileMode(dir->zip.zipos->map +
dir->zip.offset))) {
d_type = DT_DIR;
} else {
@ -425,7 +425,7 @@ static struct dirent *readdir_zipos(DIR *dir) {
}
}
dir->zip.offset +=
ZIP_CFILE_HDRSIZE(dir->zip.zipos->cdir + dir->zip.offset);
ZIP_CFILE_HDRSIZE(dir->zip.zipos->map + dir->zip.offset);
}
dir->tell++;
}
@ -611,7 +611,7 @@ void rewinddir(DIR *dir) {
if (dir->iszip) {
critbit0_clear(&dir->zip.found);
dir->tell = 0;
dir->zip.offset = 0;
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;
@ -637,7 +637,7 @@ void seekdir(DIR *dir, long tell) {
if (dir->iszip) {
critbit0_clear(&dir->zip.found);
dir->tell = 0;
dir->zip.offset = 0;
dir->zip.offset = GetZipCdirOffset(dir->zip.zipos->cdir);
while (dir->tell < tell) {
if (!readdir_zipos(dir)) {
break;

View file

@ -36,8 +36,6 @@
#define kZipErrorRaceCondition _ZE(-12)
#define kZipErrorMapFailed _ZE(-13)
#define kZipErrorOpenFailed _ZE(-14)
#define kZipErrorReadFailed _ZE(-15)
#define kZipErrorZipCorrupt _ZE(-16)
#define kZipCosmopolitanVersion kZipEra2001
@ -72,8 +70,6 @@
#define kZipCompressionNone 0
#define kZipCompressionDeflate 8
#define kZipLookbehindBytes 65536
#define kZipCdirHdrMagic ZM_(0x06054b50) /* PK♣♠ "PK\5\6" */
#define kZipCdirHdrMagicTodo ZM_(0x19184b50) /* PK♣♠ "PK\30\31" */
#define kZipCdirHdrMinSize 22

View file

@ -139,9 +139,9 @@ TEST(unveil, canBeUsedAgainAfterVfork) {
TEST(unveil, rwc_createExecutableFile_isAllowedButCantBeRun) {
SPAWN(fork);
ASSERT_SYS(0, 0, mkdir("folder", 0755));
testlib_extract("/zip/life.elf", "folder/life.elf", 0755);
ASSERT_SYS(0, 0, unveil("folder", "rwc"));
ASSERT_SYS(0, 0, unveil(0, 0));
testlib_extract("/zip/life.elf", "folder/life.elf", 0755);
SPAWN(fork);
ASSERT_SYS(0, 0, stat("folder/life.elf", &st));
ASSERT_SYS(EACCES, -1, execl("folder/life.elf", "folder/life.elf", 0));
@ -152,9 +152,9 @@ TEST(unveil, rwc_createExecutableFile_isAllowedButCantBeRun) {
TEST(unveil, rwcx_createExecutableFile_canAlsoBeRun) {
SPAWN(fork);
ASSERT_SYS(0, 0, mkdir("folder", 0755));
testlib_extract("/zip/life.elf", "folder/life.elf", 0755);
ASSERT_SYS(0, 0, unveil("folder", "rwcx"));
ASSERT_SYS(0, 0, unveil(0, 0));
testlib_extract("/zip/life.elf", "folder/life.elf", 0755);
SPAWN(fork);
ASSERT_SYS(0, 0, stat("folder/life.elf", &st));
execl("folder/life.elf", "folder/life.elf", 0);

View file

@ -52,7 +52,7 @@ void *Worker(void *arg) {
}
TEST(zipos, test) {
int i, n = 20;
int i, n = 16;
pthread_t *t = gc(malloc(sizeof(pthread_t) * n));
for (i = 0; i < n; ++i) {
ASSERT_SYS(0, 0, pthread_create(t + i, 0, Worker, 0));
@ -86,14 +86,6 @@ TEST(zipos, readPastEof) {
EXPECT_SYS(0, 0, close(3));
}
TEST(zipos, simple) {
char buf[31] = {0};
ASSERT_SYS(0, 3, open("/zip/libc/testlib/hyperion.txt", O_RDONLY));
ASSERT_SYS(0, 30, read(3, buf, 30));
ASSERT_STREQ("The fall of Hyperion - a Dream", buf);
ASSERT_SYS(0, 0, close(3));
}
TEST(zipos_O_DIRECTORY, blocksOpeningOfNormalFiles) {
ASSERT_SYS(ENOTDIR, -1,
open("/zip/libc/testlib/hyperion.txt", O_RDONLY | O_DIRECTORY));