mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +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
Binary file not shown.
|
@ -29,9 +29,9 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Replaces current process with program.
|
||||
|
@ -74,7 +74,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
if (!rc) {
|
||||
if (_weaken(__zipos_parseuri) &&
|
||||
(_weaken(__zipos_parseuri)(prog, &uri) != -1)) {
|
||||
rc = _weaken(__zipos_open)(&uri, O_RDONLY | O_CLOEXEC, 0);
|
||||
rc = _weaken(__zipos_open)(&uri, O_RDONLY | O_CLOEXEC);
|
||||
if (rc != -1) {
|
||||
const int zipFD = rc;
|
||||
strace_enabled(-1);
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
|
@ -51,7 +51,7 @@
|
|||
int faccessat(int dirfd, const char *path, int amode, int flags) {
|
||||
int e, rc;
|
||||
struct ZiposUri zipname;
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns information about file, via open()'d descriptor.
|
||||
|
@ -38,7 +38,9 @@
|
|||
*/
|
||||
int fstat(int fd, struct stat *st) {
|
||||
int rc;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
if (IsAsan() && !__asan_is_valid(st, sizeof(*st))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(fd, kFdZip)) {
|
||||
rc = _weaken(__zipos_fstat)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
|
|
|
@ -29,10 +29,10 @@
|
|||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
static inline const char *__strace_fstatat_flags(char buf[12], int flags) {
|
||||
if (flags == AT_SYMLINK_NOFOLLOW) return "AT_SYMLINK_NOFOLLOW";
|
||||
|
@ -56,7 +56,9 @@ int fstatat(int dirfd, const char *path, struct stat *st, int flags) {
|
|||
/* execve() depends on this */
|
||||
int rc;
|
||||
struct ZiposUri zipname;
|
||||
if (__isfdkind(dirfd, kFdZip)) {
|
||||
if (IsAsan() && !__asan_is_valid(st, sizeof(*st))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
STRACE("zipos dirfd not supported yet");
|
||||
rc = einval();
|
||||
} else if (_weaken(__zipos_stat) &&
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes current position of file descriptor, e.g.
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Opens file.
|
||||
|
@ -166,7 +166,7 @@ int openat(int dirfd, const char *file, int flags, ...) {
|
|||
if (_weaken(__zipos_open) &&
|
||||
_weaken(__zipos_parseuri)(file, &zipname) != -1) {
|
||||
if (!__vforked && dirfd == AT_FDCWD) {
|
||||
rc = _weaken(__zipos_open)(&zipname, flags, mode);
|
||||
rc = _weaken(__zipos_open)(&zipname, flags);
|
||||
} else {
|
||||
rc = enotsup(); /* TODO */
|
||||
}
|
||||
|
|
|
@ -742,14 +742,6 @@ void abort(void) wontreturn;
|
|||
#pragma GCC diagnostic error "-Wtrampolines"
|
||||
#if __GNUC__ >= 6
|
||||
#pragma GCC diagnostic error "-Wnonnull-compare"
|
||||
#if defined(_COSMO_SOURCE) && !defined(MODE_DBG) && \
|
||||
!defined(STACK_FRAME_UNLIMITED)
|
||||
#pragma GCC diagnostic error "-Wframe-larger-than=131072"
|
||||
#if __GNUC__ >= 9
|
||||
// #pragma GCC diagnostic error "-Walloca-larger-than=1024"
|
||||
// #pragma GCC diagnostic error "-Wvla-larger-than=1024"
|
||||
#endif /* GCC 9+ */
|
||||
#endif /* STACK_FRAME_UNLIMITED */
|
||||
#elif __GNUC__ >= 9
|
||||
#pragma GCC diagnostic error /* e.g. fabs not abs */ "-Wabsolute-value"
|
||||
#endif /* GCC 6+ */
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
#define __BIGGEST_ALIGNMENT__ 16
|
||||
#endif
|
||||
|
||||
#define APE_STACKSIZE 4194304 /* default 4mb stack */
|
||||
#define APE_STACKSIZE 8388608 /* default 8mb stack */
|
||||
#define APE_PAGESIZE 0x10000 /* i386+ */
|
||||
#ifdef _COSMO_SOURCE
|
||||
#define FRAMESIZE 0x10000
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* @param delta is added to enabled state
|
||||
* @return enabled state before `delta` was applied
|
||||
*/
|
||||
dontinstrument int ftrace_enabled(int delta) {
|
||||
dontasan dontubsan dontinstrument int ftrace_enabled(int delta) {
|
||||
int res;
|
||||
struct CosmoTib *tib;
|
||||
if (__tls_enabled) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* @param delta is added to enabled state
|
||||
* @return enabled state before `delta` was applied
|
||||
*/
|
||||
dontinstrument int strace_enabled(int delta) {
|
||||
dontasan dontubsan dontinstrument int strace_enabled(int delta) {
|
||||
int res;
|
||||
struct CosmoTib *tib;
|
||||
if (__tls_enabled) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nopl.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/struct/win32finddata.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -39,7 +41,6 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/zip.internal.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Directory Streams for Linux+Mac+Windows+FreeBSD+OpenBSD.
|
||||
|
@ -57,15 +58,17 @@ int sys_getdents(unsigned, void *, unsigned, long *);
|
|||
* Directory stream object.
|
||||
*/
|
||||
struct dirstream {
|
||||
int fd;
|
||||
bool iszip;
|
||||
int64_t fd;
|
||||
int64_t hand;
|
||||
int64_t tell;
|
||||
char16_t *name;
|
||||
pthread_mutex_t lock;
|
||||
struct {
|
||||
uint64_t offset;
|
||||
uint64_t records;
|
||||
uint8_t *prefix;
|
||||
size_t prefixlen;
|
||||
uint8_t prefix[ZIPOS_PATH_MAX];
|
||||
} zip;
|
||||
struct dirent ent;
|
||||
union {
|
||||
|
@ -76,7 +79,6 @@ struct dirstream {
|
|||
};
|
||||
struct {
|
||||
bool isdone;
|
||||
char16_t *name;
|
||||
struct NtWin32FindData windata;
|
||||
};
|
||||
};
|
||||
|
@ -148,7 +150,7 @@ static textwindows DIR *opendir_nt_impl(char16_t *name, size_t len) {
|
|||
}
|
||||
name[len] = u'\0';
|
||||
if ((res = calloc(1, sizeof(DIR)))) {
|
||||
if ((res->fd = FindFirstFile(name, &res->windata)) != -1) {
|
||||
if ((res->hand = FindFirstFile(name, &res->windata)) != -1) {
|
||||
return res;
|
||||
}
|
||||
__fix_enotdir(-1, name);
|
||||
|
@ -160,35 +162,17 @@ static textwindows DIR *opendir_nt_impl(char16_t *name, size_t len) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static textwindows dontinline DIR *opendir_nt(const char *path) {
|
||||
int len;
|
||||
DIR *res;
|
||||
char16_t *name;
|
||||
if (*path) {
|
||||
if ((name = malloc(PATH_MAX * 2))) {
|
||||
if ((len = __mkntpath(path, name)) != -1 &&
|
||||
(res = opendir_nt_impl(name, len))) {
|
||||
res->name = name;
|
||||
return res;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
} else {
|
||||
enoent();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static textwindows dontinline DIR *fdopendir_nt(int fd) {
|
||||
DIR *res;
|
||||
char16_t *name;
|
||||
if (__isfdkind(fd, kFdFile)) {
|
||||
if ((name = malloc(PATH_MAX * 2))) {
|
||||
if ((name = calloc(1, PATH_MAX * 2))) {
|
||||
if ((res = opendir_nt_impl(
|
||||
name, GetFinalPathNameByHandle(
|
||||
g_fds.p[fd].handle, name, PATH_MAX,
|
||||
kNtFileNameNormalized | kNtVolumeNameDos)))) {
|
||||
res->name = name;
|
||||
res->fd = -1;
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
|
@ -235,86 +219,13 @@ static textwindows dontinline struct dirent *readdir_nt(DIR *dir) {
|
|||
}
|
||||
}
|
||||
dir->ent.d_type = GetNtDirentType(&dir->windata);
|
||||
dir->isdone = !FindNextFile(dir->fd, &dir->windata);
|
||||
dir->isdone = !FindNextFile(dir->hand, &dir->windata);
|
||||
return &dir->ent;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens directory, e.g.
|
||||
*
|
||||
* DIR *d;
|
||||
* struct dirent *e;
|
||||
* CHECK((d = opendir(path)));
|
||||
* while ((e = readdir(d))) {
|
||||
* printf("%s/%s\n", path, e->d_name);
|
||||
* }
|
||||
* LOGIFNEG1(closedir(d));
|
||||
*
|
||||
* @returns newly allocated DIR object, or NULL w/ errno
|
||||
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if we needed to block and a signal was delivered instead
|
||||
* @cancellationpoint
|
||||
* @see glob()
|
||||
*/
|
||||
DIR *opendir(const char *name) {
|
||||
DIR *res;
|
||||
int fd, rc;
|
||||
struct stat st;
|
||||
struct Zipos *zip;
|
||||
struct ZiposUri zipname;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return 0;
|
||||
}
|
||||
if (!name || (IsAsan() && !__asan_is_valid_str(name))) {
|
||||
efault();
|
||||
res = 0;
|
||||
} else if (_weaken(__zipos_get) &&
|
||||
_weaken(__zipos_parseuri)(name, &zipname) != -1) {
|
||||
if (_weaken(__zipos_stat)(&zipname, &st) != -1) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
zip = _weaken(__zipos_get)();
|
||||
if ((res = calloc(1, sizeof(DIR)))) {
|
||||
res->iszip = true;
|
||||
res->fd = -1;
|
||||
res->zip.offset = GetZipCdirOffset(zip->cdir);
|
||||
res->zip.records = GetZipCdirRecords(zip->cdir);
|
||||
res->zip.prefix = malloc(zipname.len + 2);
|
||||
if (zipname.len) {
|
||||
memcpy(res->zip.prefix, zipname.path, zipname.len);
|
||||
}
|
||||
if (zipname.len && res->zip.prefix[zipname.len - 1] != '/') {
|
||||
res->zip.prefix[zipname.len++] = '/';
|
||||
}
|
||||
res->zip.prefix[zipname.len] = '\0';
|
||||
res->zip.prefixlen = zipname.len;
|
||||
}
|
||||
} else {
|
||||
enotdir();
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
res = 0;
|
||||
if ((fd = open(name, O_RDONLY | O_NOCTTY | O_DIRECTORY | O_CLOEXEC)) !=
|
||||
-1) {
|
||||
if (!(res = fdopendir(fd))) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = opendir_nt(name);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates directory object for file descriptor.
|
||||
*
|
||||
|
@ -324,19 +235,98 @@ DIR *opendir(const char *name) {
|
|||
* @errors ENOMEM and fd is closed
|
||||
*/
|
||||
DIR *fdopendir(int fd) {
|
||||
|
||||
// allocate directory iterator object
|
||||
DIR *dir;
|
||||
if (!IsWindows()) {
|
||||
if (!(dir = calloc(1, sizeof(*dir)))) return NULL;
|
||||
dir->fd = fd;
|
||||
} else {
|
||||
dir = fdopendir_nt(fd);
|
||||
if (!(dir = calloc(1, sizeof(*dir)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// on unix, file descriptor isn't required to be tracked
|
||||
dir->fd = fd;
|
||||
if (!__isfdkind(fd, kFdZip)) {
|
||||
if (IsWindows()) {
|
||||
free(dir);
|
||||
return fdopendir_nt(fd);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
dir->iszip = true;
|
||||
|
||||
// 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->map + h->cfile))) {
|
||||
free(dir);
|
||||
enotdir();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get path of this file descriptor and ensure trailing slash
|
||||
size_t len;
|
||||
char *name;
|
||||
if (h->cfile != ZIPOS_SYNTHETIC_DIRECTORY) {
|
||||
len = ZIP_CFILE_NAMESIZE(h->zipos->map + h->cfile);
|
||||
name = ZIP_CFILE_NAME(h->zipos->map + h->cfile);
|
||||
} else {
|
||||
len = h->size;
|
||||
name = (char *)h->data;
|
||||
}
|
||||
if (len + 2 > ZIPOS_PATH_MAX) {
|
||||
free(dir);
|
||||
enametoolong();
|
||||
return 0;
|
||||
}
|
||||
if (len) memcpy(dir->zip.prefix, name, len);
|
||||
if (len && dir->zip.prefix[len - 1] != '/') {
|
||||
dir->zip.prefix[len++] = '/';
|
||||
}
|
||||
dir->zip.prefix[len] = 0;
|
||||
dir->zip.prefixlen = len;
|
||||
|
||||
// setup state values for directory iterator
|
||||
dir->zip.offset = GetZipCdirOffset(h->zipos->cdir);
|
||||
dir->zip.records = GetZipCdirRecords(h->zipos->cdir);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens directory, e.g.
|
||||
*
|
||||
* DIR *d;
|
||||
* struct dirent *e;
|
||||
* d = opendir(path);
|
||||
* while ((e = readdir(d))) {
|
||||
* printf("%s/%s\n", path, e->d_name);
|
||||
* }
|
||||
* closedir(d);
|
||||
*
|
||||
* @returns newly allocated DIR object, or NULL w/ errno
|
||||
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if we needed to block and a signal was delivered instead
|
||||
* @cancellationpoint
|
||||
* @see glob()
|
||||
*/
|
||||
DIR *opendir(const char *name) {
|
||||
int rc;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return 0;
|
||||
}
|
||||
int fd;
|
||||
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_NOCTTY | O_CLOEXEC)) == -1) {
|
||||
return 0;
|
||||
}
|
||||
DIR *res = fdopendir(fd);
|
||||
if (!res) close(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct dirent *readdir_impl(DIR *dir) {
|
||||
size_t n;
|
||||
long basep;
|
||||
int rc, mode;
|
||||
uint8_t *s, *p;
|
||||
struct Zipos *zip;
|
||||
|
@ -348,53 +338,68 @@ static struct dirent *readdir_impl(DIR *dir) {
|
|||
if (dir->iszip) {
|
||||
ent = 0;
|
||||
zip = _weaken(__zipos_get)();
|
||||
while (!ent && dir->tell < dir->zip.records) {
|
||||
npassert(ZIP_CFILE_MAGIC(zip->map + dir->zip.offset) ==
|
||||
kZipCfileHdrMagic);
|
||||
s = ZIP_CFILE_NAME(zip->map + dir->zip.offset);
|
||||
n = ZIP_CFILE_NAMESIZE(zip->map + dir->zip.offset);
|
||||
if (dir->zip.prefixlen < n &&
|
||||
!memcmp(dir->zip.prefix, s, dir->zip.prefixlen)) {
|
||||
s += dir->zip.prefixlen;
|
||||
n -= dir->zip.prefixlen;
|
||||
p = memchr(s, '/', n);
|
||||
if (!p || p + 1 - s == n) {
|
||||
if (p + 1 - s == n) --n;
|
||||
mode = GetZipCfileMode(zip->map + dir->zip.offset);
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->zip.offset;
|
||||
ent->d_reclen = MIN(n, 255);
|
||||
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
|
||||
if (ent->d_reclen) {
|
||||
memcpy(ent->d_name, s, ent->d_reclen);
|
||||
}
|
||||
ent->d_name[ent->d_reclen] = 0;
|
||||
} else {
|
||||
lastent = (struct dirent *)dir->buf;
|
||||
n = p - s;
|
||||
n = MIN(n, 255);
|
||||
if (!lastent->d_ino || (n != lastent->d_reclen) ||
|
||||
memcmp(lastent->d_name, s, n)) {
|
||||
ent = lastent;
|
||||
while (!ent && dir->tell < dir->zip.records + 2) {
|
||||
if (!dir->tell) {
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = 1;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
} else if (dir->tell == 1) {
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = 2;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
} else {
|
||||
s = ZIP_CFILE_NAME(zip->map + dir->zip.offset);
|
||||
n = ZIP_CFILE_NAMESIZE(zip->map + dir->zip.offset);
|
||||
if (dir->zip.prefixlen < n &&
|
||||
!memcmp(dir->zip.prefix, s, dir->zip.prefixlen)) {
|
||||
s += dir->zip.prefixlen;
|
||||
n -= dir->zip.prefixlen;
|
||||
p = memchr(s, '/', n);
|
||||
if (!p || p + 1 - s == n) {
|
||||
if (p + 1 - s == n) --n;
|
||||
mode = GetZipCfileMode(zip->map + dir->zip.offset);
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = -1;
|
||||
ent->d_reclen = n;
|
||||
ent->d_type = DT_DIR;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = MIN(n, 255);
|
||||
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
|
||||
if (ent->d_reclen) {
|
||||
memcpy(ent->d_name, s, ent->d_reclen);
|
||||
}
|
||||
ent->d_name[ent->d_reclen] = 0;
|
||||
} else {
|
||||
lastent = (struct dirent *)dir->buf;
|
||||
n = p - s;
|
||||
n = MIN(n, 255);
|
||||
if (!lastent->d_ino || (n != lastent->d_reclen) ||
|
||||
memcmp(lastent->d_name, s, n)) {
|
||||
ent = lastent;
|
||||
mode = GetZipCfileMode(zip->map + dir->zip.offset);
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = n;
|
||||
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
|
||||
if (ent->d_reclen) {
|
||||
memcpy(ent->d_name, s, ent->d_reclen);
|
||||
}
|
||||
ent->d_name[ent->d_reclen] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset);
|
||||
}
|
||||
dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset);
|
||||
dir->tell++;
|
||||
}
|
||||
return ent;
|
||||
} else if (!IsWindows()) {
|
||||
if (dir->buf_pos >= dir->buf_end) {
|
||||
basep = dir->tell; /* TODO(jart): what does xnu do */
|
||||
long basep = dir->tell;
|
||||
rc = sys_getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep);
|
||||
STRACE("sys_getdents(%d) → %d% m", dir->fd, rc);
|
||||
if (!rc || rc == -1) return NULL;
|
||||
|
@ -408,6 +413,7 @@ static struct dirent *readdir_impl(DIR *dir) {
|
|||
} else if (IsOpenbsd()) {
|
||||
obsd = (struct dirent_openbsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += obsd->d_reclen;
|
||||
dir->tell = obsd->d_off;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = obsd->d_fileno;
|
||||
ent->d_off = obsd->d_off;
|
||||
|
@ -419,7 +425,7 @@ static struct dirent *readdir_impl(DIR *dir) {
|
|||
dir->buf_pos += nbsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = nbsd->d_fileno;
|
||||
ent->d_off = dir->tell++;
|
||||
ent->d_off = (dir->tell += nbsd->d_reclen);
|
||||
ent->d_reclen = nbsd->d_reclen;
|
||||
ent->d_type = nbsd->d_type;
|
||||
memcpy(ent->d_name, nbsd->d_name, MAX(256, nbsd->d_namlen + 1));
|
||||
|
@ -428,7 +434,7 @@ static struct dirent *readdir_impl(DIR *dir) {
|
|||
dir->buf_pos += bsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = bsd->d_fileno;
|
||||
ent->d_off = IsXnu() ? (dir->tell = basep) : dir->tell++;
|
||||
ent->d_off = dir->tell++;
|
||||
ent->d_reclen = bsd->d_reclen;
|
||||
ent->d_type = bsd->d_type;
|
||||
memcpy(ent->d_name, bsd->d_name, bsd->d_namlen + 1);
|
||||
|
@ -450,9 +456,14 @@ static struct dirent *readdir_impl(DIR *dir) {
|
|||
*/
|
||||
struct dirent *readdir(DIR *dir) {
|
||||
struct dirent *e;
|
||||
_lockdir(dir);
|
||||
e = readdir_impl(dir);
|
||||
_unlockdir(dir);
|
||||
if (dir) {
|
||||
_lockdir(dir);
|
||||
e = readdir_impl(dir);
|
||||
_unlockdir(dir);
|
||||
} else {
|
||||
efault();
|
||||
e = 0;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
@ -496,20 +507,18 @@ errno_t readdir_r(DIR *dir, struct dirent *output, struct dirent **result) {
|
|||
* @return 0 on success or -1 w/ errno
|
||||
*/
|
||||
int closedir(DIR *dir) {
|
||||
int rc;
|
||||
int rc = 0;
|
||||
if (dir) {
|
||||
if (dir->iszip) {
|
||||
free(dir->zip.prefix);
|
||||
rc = 0;
|
||||
} else if (!IsWindows()) {
|
||||
rc = close(dir->fd);
|
||||
} else {
|
||||
free(dir->name);
|
||||
rc = FindClose(dir->fd) ? 0 : __winerr();
|
||||
if (dir->fd != -1) {
|
||||
rc |= close(dir->fd);
|
||||
}
|
||||
free(dir->name);
|
||||
if (IsWindows() && !dir->iszip) {
|
||||
if (!FindClose(dir->hand)) {
|
||||
rc = __winerr();
|
||||
}
|
||||
}
|
||||
free(dir);
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -533,13 +542,7 @@ long telldir(DIR *dir) {
|
|||
int dirfd(DIR *dir) {
|
||||
int rc;
|
||||
_lockdir(dir);
|
||||
if (dir->iszip) {
|
||||
rc = eopnotsupp();
|
||||
} else if (IsWindows()) {
|
||||
rc = eopnotsupp();
|
||||
} else {
|
||||
rc = dir->fd;
|
||||
}
|
||||
rc = dir->fd;
|
||||
_unlockdir(dir);
|
||||
return rc;
|
||||
}
|
||||
|
@ -559,8 +562,8 @@ void rewinddir(DIR *dir) {
|
|||
dir->tell = 0;
|
||||
}
|
||||
} else {
|
||||
FindClose(dir->fd);
|
||||
if ((dir->fd = FindFirstFile(dir->name, &dir->windata)) != -1) {
|
||||
FindClose(dir->hand);
|
||||
if ((dir->hand = FindFirstFile(dir->name, &dir->windata)) != -1) {
|
||||
dir->isdone = false;
|
||||
dir->tell = 0;
|
||||
} else {
|
||||
|
@ -582,11 +585,27 @@ void seekdir(DIR *dir, long off) {
|
|||
if (dir->iszip) {
|
||||
dir->zip.offset = GetZipCdirOffset(_weaken(__zipos_get)()->cdir);
|
||||
for (i = 0; i < off && i < dir->zip.records; ++i) {
|
||||
dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset);
|
||||
if (i >= 2) {
|
||||
dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (!IsWindows()) {
|
||||
i = lseek(dir->fd, off, SEEK_SET);
|
||||
dir->buf_pos = dir->buf_end = 0;
|
||||
} else {
|
||||
i = 0;
|
||||
dir->isdone = false;
|
||||
FindClose(dir->hand);
|
||||
if ((dir->hand = FindFirstFile(dir->name, &dir->windata)) != -1) {
|
||||
for (; i < off; ++i) {
|
||||
if (!FindNextFile(dir->hand, &dir->windata)) {
|
||||
dir->isdone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dir->isdone = true;
|
||||
}
|
||||
}
|
||||
dir->tell = i;
|
||||
_unlockdir(dir);
|
||||
|
|
|
@ -957,18 +957,6 @@ syscon pf PF_VSOCK 40 40 0 0 0 0 0 0
|
|||
syscon pf PF_WANPIPE 25 25 0 0 0 0 0 0
|
||||
syscon pf PF_X25 9 9 0 0 0 0 0 0
|
||||
|
||||
# getdents() constants
|
||||
#
|
||||
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon dt DT_UNKNOWN 0 0 0 0 0 0 0 0 # consensus
|
||||
syscon dt DT_FIFO 1 1 1 1 1 1 1 1 # unix consensus & faked nt
|
||||
syscon dt DT_CHR 2 2 2 2 2 2 2 2 # unix consensus & faked nt
|
||||
syscon dt DT_DIR 4 4 4 4 4 4 4 4 # unix consensus & faked nt
|
||||
syscon dt DT_BLK 6 6 6 6 6 6 6 6 # unix consensus & faked nt
|
||||
syscon dt DT_REG 8 8 8 8 8 8 8 8 # unix consensus & faked nt
|
||||
syscon dt DT_LNK 10 10 10 10 10 10 10 10 # unix consensus & faked nt
|
||||
syscon dt DT_SOCK 12 12 12 12 12 12 12 12 # unix consensus & faked nt
|
||||
|
||||
# msync() flags
|
||||
#
|
||||
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_BLK,6,6,6,6,6,6,6,6
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_CHR,2,2,2,2,2,2,2,2
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_DIR,4,4,4,4,4,4,4,4
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_FIFO,1,1,1,1,1,1,1,1
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_LNK,10,10,10,10,10,10,10,10
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_REG,8,8,8,8,8,8,8,8
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_SOCK,12,12,12,12,12,12,12,12
|
|
@ -1,2 +0,0 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon dt,DT_UNKNOWN,0,0,0,0,0,0,0,0
|
|
@ -1,19 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_
|
||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const uint8_t DT_UNKNOWN;
|
||||
extern const uint8_t DT_FIFO;
|
||||
extern const uint8_t DT_CHR;
|
||||
extern const uint8_t DT_DIR;
|
||||
extern const uint8_t DT_BLK;
|
||||
extern const uint8_t DT_REG;
|
||||
extern const uint8_t DT_LNK;
|
||||
extern const uint8_t DT_SOCK;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
|
|
|
@ -35,7 +35,6 @@ void SetUpOnce(void) {
|
|||
}
|
||||
|
||||
TEST(access, efault) {
|
||||
ASSERT_SYS(EFAULT, -1, access(0, F_OK));
|
||||
if (IsWindows() || !IsAsan()) return; // not possible
|
||||
ASSERT_SYS(EFAULT, -1, access((void *)77, F_OK));
|
||||
}
|
||||
|
|
|
@ -71,6 +71,15 @@ TEST(read_pipe, canBeInterruptedByAlarm) {
|
|||
close(fds[0]);
|
||||
}
|
||||
|
||||
TEST(read_directory, eisdir) {
|
||||
// TODO(jart): what
|
||||
if (IsWindows() || IsFreebsd()) return;
|
||||
ASSERT_SYS(0, 0, mkdir("boop", 0755));
|
||||
ASSERT_SYS(0, 3, open("boop", O_RDONLY | O_DIRECTORY));
|
||||
ASSERT_SYS(EISDIR, -1, read(3, 0, 0));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BENCH(read, bench) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
|
@ -47,13 +48,15 @@ TEST(stat_010, testEmptyFile_sizeIsZero) {
|
|||
}
|
||||
|
||||
TEST(stat, enoent) {
|
||||
ASSERT_SYS(ENOENT, -1, stat("hi", 0));
|
||||
ASSERT_SYS(ENOENT, -1, stat("o/doesnotexist", 0));
|
||||
struct stat st;
|
||||
ASSERT_SYS(ENOENT, -1, stat("hi", &st));
|
||||
ASSERT_SYS(ENOENT, -1, stat("o/doesnotexist", &st));
|
||||
}
|
||||
|
||||
TEST(stat, enotdir) {
|
||||
struct stat st;
|
||||
ASSERT_SYS(0, 0, close(creat("yo", 0644)));
|
||||
ASSERT_SYS(ENOTDIR, -1, stat("yo/there", 0));
|
||||
ASSERT_SYS(ENOTDIR, -1, stat("yo/there", &st));
|
||||
}
|
||||
|
||||
TEST(stat, zipos) {
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
|
@ -53,3 +56,39 @@ TEST(zipos, test) {
|
|||
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
||||
__print_maps();
|
||||
}
|
||||
|
||||
TEST(zipos, normpath) {
|
||||
{
|
||||
char s[] = "";
|
||||
__zipos_normpath(s);
|
||||
ASSERT_STREQ("", s);
|
||||
}
|
||||
{
|
||||
char s[] = "usr/";
|
||||
__zipos_normpath(s);
|
||||
ASSERT_STREQ("usr", s);
|
||||
}
|
||||
{
|
||||
char s[] = "usr/./";
|
||||
__zipos_normpath(s);
|
||||
ASSERT_STREQ("usr", s);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(zipos_O_DIRECTORY, blocksOpeningOfNormalFiles) {
|
||||
ASSERT_SYS(ENOTDIR, -1,
|
||||
open("/zip/libc/testlib/hyperion.txt", O_RDONLY | O_DIRECTORY));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(zipos, readPastEof) {
|
||||
char buf[512];
|
||||
ASSERT_SYS(0, 3, open("/zip/libc/testlib/hyperion.txt", O_RDONLY));
|
||||
EXPECT_SYS(EINVAL, -1, pread(3, buf, 512, UINT64_MAX));
|
||||
EXPECT_SYS(0, 0, pread(3, buf, 512, INT64_MAX));
|
||||
EXPECT_SYS(EINVAL, -1, lseek(3, UINT64_MAX, SEEK_SET));
|
||||
EXPECT_SYS(0, INT64_MAX, lseek(3, INT64_MAX, SEEK_SET));
|
||||
EXPECT_SYS(0, 0, read(3, buf, 512));
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
|
|
@ -18,13 +18,18 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "libc/x/xiso8601.h"
|
||||
|
@ -61,6 +66,10 @@ TEST(opendir, enotdir) {
|
|||
TEST(opendir, zipTest_fake) {
|
||||
ASSERT_NE(NULL, (dir = opendir("/zip")));
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ(".", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("..", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("echo.com", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("usr", ent->d_name);
|
||||
|
@ -70,6 +79,10 @@ TEST(opendir, zipTest_fake) {
|
|||
EXPECT_EQ(0, closedir(dir));
|
||||
ASSERT_NE(NULL, (dir = opendir("/zip/")));
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ(".", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("..", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("echo.com", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("usr", ent->d_name);
|
||||
|
@ -79,11 +92,19 @@ TEST(opendir, zipTest_fake) {
|
|||
EXPECT_EQ(0, closedir(dir));
|
||||
ASSERT_NE(NULL, (dir = opendir("/zip/usr")));
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ(".", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("..", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("share", ent->d_name);
|
||||
EXPECT_EQ(NULL, (ent = readdir(dir)));
|
||||
EXPECT_EQ(0, closedir(dir));
|
||||
ASSERT_NE(NULL, (dir = opendir("/zip/usr/")));
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ(".", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("..", ent->d_name);
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_STREQ("share", ent->d_name);
|
||||
EXPECT_EQ(NULL, (ent = readdir(dir)));
|
||||
EXPECT_EQ(0, closedir(dir));
|
||||
|
@ -91,6 +112,28 @@ TEST(opendir, zipTest_fake) {
|
|||
EXPECT_EQ(NULL, (dir = opendir("/zip/us/")));
|
||||
}
|
||||
|
||||
TEST(opendir, openSyntheticDirEntry) {
|
||||
struct stat st;
|
||||
ASSERT_SYS(0, 3, open("/zip", O_RDONLY | O_DIRECTORY));
|
||||
ASSERT_SYS(0, 0, fstat(3, &st));
|
||||
ASSERT_TRUE(S_ISDIR(st.st_mode));
|
||||
EXPECT_SYS(EISDIR, -1, read(3, 0, 0));
|
||||
ASSERT_NE(NULL, (dir = fdopendir(3)));
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_EQ(0, closedir(dir));
|
||||
}
|
||||
|
||||
TEST(opendir, openRealDirEntry) {
|
||||
struct stat st;
|
||||
ASSERT_SYS(0, 3, open("/zip/usr/share/zoneinfo", O_RDONLY | O_DIRECTORY));
|
||||
ASSERT_SYS(0, 0, fstat(3, &st));
|
||||
ASSERT_TRUE(S_ISDIR(st.st_mode));
|
||||
EXPECT_SYS(EISDIR, -1, read(3, 0, 0));
|
||||
ASSERT_NE(NULL, (dir = fdopendir(3)));
|
||||
EXPECT_NE(NULL, (ent = readdir(dir)));
|
||||
EXPECT_EQ(0, closedir(dir));
|
||||
}
|
||||
|
||||
TEST(dirstream, testDots) {
|
||||
int hasdot = 0;
|
||||
int hasdotdot = 0;
|
||||
|
@ -115,9 +158,9 @@ TEST(dirstream, test) {
|
|||
bool hasfoo = false;
|
||||
bool hasbar = false;
|
||||
char *dpath, *file1, *file2;
|
||||
dpath = _gc(xasprintf("%s.%d", "dirstream", rand()));
|
||||
file1 = _gc(xasprintf("%s/%s", dpath, "foo"));
|
||||
file2 = _gc(xasprintf("%s/%s", dpath, "bar"));
|
||||
dpath = gc(xasprintf("%s.%d", "dirstream", rand()));
|
||||
file1 = gc(xasprintf("%s/%s", dpath, "foo"));
|
||||
file2 = gc(xasprintf("%s/%s", dpath, "bar"));
|
||||
EXPECT_NE(-1, mkdir(dpath, 0755));
|
||||
EXPECT_NE(-1, touch(file1, 0644));
|
||||
EXPECT_NE(-1, touch(file2, 0644));
|
||||
|
@ -143,12 +186,11 @@ TEST(dirstream, test) {
|
|||
TEST(dirstream, zipTest) {
|
||||
bool foundNewYork = false;
|
||||
const char *path = "/zip/usr/share/zoneinfo/";
|
||||
ASSERT_NE(0, _gc(xiso8601ts(NULL)));
|
||||
ASSERT_NE(NULL, (dir = opendir(path)));
|
||||
while ((ent = readdir(dir))) {
|
||||
foundNewYork |= !strcmp(ent->d_name, "New_York");
|
||||
}
|
||||
closedir(dir);
|
||||
EXPECT_SYS(0, 0, closedir(dir));
|
||||
EXPECT_TRUE(foundNewYork);
|
||||
}
|
||||
|
||||
|
@ -156,9 +198,9 @@ TEST(rewinddir, test) {
|
|||
bool hasfoo = false;
|
||||
bool hasbar = false;
|
||||
char *dpath, *file1, *file2;
|
||||
dpath = _gc(xasprintf("%s.%d", "dirstream", rand()));
|
||||
file1 = _gc(xasprintf("%s/%s", dpath, "foo"));
|
||||
file2 = _gc(xasprintf("%s/%s", dpath, "bar"));
|
||||
dpath = gc(xasprintf("%s.%d", "dirstream", rand()));
|
||||
file1 = gc(xasprintf("%s/%s", dpath, "foo"));
|
||||
file2 = gc(xasprintf("%s/%s", dpath, "bar"));
|
||||
EXPECT_NE(-1, mkdir(dpath, 0755));
|
||||
EXPECT_NE(-1, touch(file1, 0644));
|
||||
EXPECT_NE(-1, touch(file2, 0644));
|
||||
|
@ -183,3 +225,28 @@ TEST(dirstream, zipTest_notDir) {
|
|||
ASSERT_EQ(NULL, opendir("/zip/usr/share/zoneinfo/New_York"));
|
||||
ASSERT_EQ(ENOTDIR, errno);
|
||||
}
|
||||
|
||||
TEST(dirstream, seek) {
|
||||
if (IsNetbsd()) return; // omg
|
||||
ASSERT_SYS(0, 0, mkdir("boop", 0755));
|
||||
EXPECT_SYS(0, 0, touch("boop/a", 0644));
|
||||
EXPECT_SYS(0, 0, touch("boop/b", 0644));
|
||||
EXPECT_SYS(0, 0, touch("boop/c", 0644));
|
||||
ASSERT_NE(NULL, (dir = opendir("boop")));
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #1
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #2
|
||||
long pos = telldir(dir);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #3
|
||||
char name[32];
|
||||
strlcpy(name, ent->d_name, sizeof(name));
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #4
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #5
|
||||
ASSERT_EQ(NULL, (ent = readdir(dir))); // eod
|
||||
seekdir(dir, pos);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #2
|
||||
ASSERT_STREQ(name, ent->d_name);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #3
|
||||
ASSERT_NE(NULL, (ent = readdir(dir))); // #4
|
||||
ASSERT_EQ(NULL, (ent = readdir(dir))); // eod
|
||||
ASSERT_SYS(0, 0, closedir(dir));
|
||||
}
|
||||
|
|
69
test/libc/stdio/zipdir_test.c
Normal file
69
test/libc/stdio/zipdir_test.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*-*- 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 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
__static_yoink("zipos");
|
||||
__static_yoink("libc/testlib/hyperion.txt");
|
||||
__static_yoink("libc/testlib/moby.txt");
|
||||
__static_yoink("usr/share/zoneinfo/New_York");
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
|
||||
TEST(zipdir, test) {
|
||||
const char *path = "/zip/libc/testlib///";
|
||||
ASSERT_NE(NULL, (dir = opendir(path)));
|
||||
ASSERT_EQ(0, telldir(dir));
|
||||
ASSERT_NE(NULL, (ent = readdir(dir)));
|
||||
ASSERT_EQ(0, strcmp(ent->d_name, "."));
|
||||
ASSERT_EQ(DT_DIR, ent->d_type);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir)));
|
||||
ASSERT_EQ(0, strcmp(ent->d_name, ".."));
|
||||
ASSERT_EQ(DT_DIR, ent->d_type);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir)));
|
||||
ASSERT_EQ(0, strcmp(ent->d_name, "hyperion.txt"));
|
||||
ASSERT_EQ(DT_REG, ent->d_type);
|
||||
long pos = telldir(dir);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir)));
|
||||
ASSERT_EQ(0, strcmp(ent->d_name, "moby.txt"));
|
||||
ASSERT_EQ(DT_REG, ent->d_type);
|
||||
ASSERT_EQ(NULL, (ent = readdir(dir)));
|
||||
seekdir(dir, pos);
|
||||
ASSERT_NE(NULL, (ent = readdir(dir)));
|
||||
ASSERT_EQ(0, strcmp(ent->d_name, "moby.txt"));
|
||||
ASSERT_EQ(DT_REG, ent->d_type);
|
||||
ASSERT_EQ(NULL, (ent = readdir(dir)));
|
||||
ASSERT_SYS(0, 0, closedir(dir));
|
||||
}
|
||||
|
||||
TEST(dirstream, hasDirectoryEntry) {
|
||||
bool gotsome = false;
|
||||
const char *path = "/zip/usr/share/zoneinfo";
|
||||
ASSERT_NE(NULL, (dir = opendir(path)));
|
||||
while ((ent = readdir(dir))) {
|
||||
gotsome = true;
|
||||
}
|
||||
ASSERT_SYS(0, 0, closedir(dir));
|
||||
EXPECT_TRUE(gotsome);
|
||||
}
|
2
third_party/unzip/process.c
vendored
2
third_party/unzip/process.c
vendored
|
@ -1330,7 +1330,7 @@ static int find_ecrec64(__G__ searchlen) /* return PK-class error */
|
|||
if (memcmp((char *)byterec, end_central64_sig, 4) ) {
|
||||
/* Zip64 EOCD Record not found */
|
||||
/* Since we already have seen the Zip64 EOCD Locator, it's
|
||||
possible we got here because there are bytes prepended
|
||||
possible we got h-ere because there are bytes prepended
|
||||
to the archive, like the sfx prefix. */
|
||||
|
||||
/* Make a guess as to where the Zip64 EOCD Record might be */
|
||||
|
|
|
@ -22,8 +22,11 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
|
@ -130,7 +133,7 @@ static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize,
|
|||
/**
|
||||
* Embeds zip file in elf object.
|
||||
*/
|
||||
void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
|
||||
void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *cname,
|
||||
size_t namesize, const void *data, size_t size,
|
||||
uint32_t mode, struct timespec mtim, struct timespec atim,
|
||||
struct timespec ctim, bool nocompress) {
|
||||
|
@ -144,6 +147,13 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
|
|||
|
||||
CHECK_NE(0, mtim.tv_sec);
|
||||
|
||||
char *name = gc(strndup(cname, namesize));
|
||||
namesize = __zipos_normpath(name);
|
||||
if (S_ISDIR(mode) && namesize && name[namesize - 1] != '/') {
|
||||
name[namesize++] = '/';
|
||||
name[namesize] = 0;
|
||||
}
|
||||
|
||||
gflags = 0;
|
||||
iattrs = 0;
|
||||
compsize = size;
|
||||
|
|
Loading…
Reference in a new issue