mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Implement __zipos_dup (#972)
* Implement __zipos_dup Makes ZiposHandle reference-counted by an `rc` field in a union with its freelist `next` pointer. The functions `__zipos_free` and `__zipos_keep` function as incref/decref for it. Adds `__zipos_postdup` to fix metadata on file descriptors after dup-like operations, and adds zipos support to `sys_dup_nt` + `sys_close_nt`. * Remove noop __zipos_postdup rc is never a zipos file because it is always a previously unused file descriptor. fd is never a zipos file because that case has been handled above by __zipos_fcntl.
This commit is contained in:
parent
6556dd2673
commit
d1a745c17c
11 changed files with 138 additions and 39 deletions
|
@ -24,6 +24,7 @@
|
|||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -32,6 +33,8 @@ textwindows int sys_close_nt(int fd, int fildes) {
|
|||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
switch (f->kind) {
|
||||
case kFdZip:
|
||||
return _weaken(__zipos_close)(fd);
|
||||
case kFdEmpty:
|
||||
return ebadf();
|
||||
case kFdFile:
|
||||
|
|
|
@ -59,30 +59,34 @@ static textwindows int sys_dup_nt_impl(int oldfd, int newfd, int flags,
|
|||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
if (g_fds.p[newfd].kind == kFdZip) {
|
||||
_weaken(__zipos_close)(newfd);
|
||||
} else {
|
||||
sys_close_nt(newfd, newfd);
|
||||
}
|
||||
sys_close_nt(newfd, newfd);
|
||||
}
|
||||
}
|
||||
|
||||
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
|
||||
GetCurrentProcess(), &handle, 0, true,
|
||||
kNtDuplicateSameAccess)) {
|
||||
g_fds.p[newfd] = g_fds.p[oldfd];
|
||||
g_fds.p[newfd].handle = handle;
|
||||
if (flags & _O_CLOEXEC) {
|
||||
g_fds.p[newfd].flags |= _O_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[newfd].flags &= ~_O_CLOEXEC;
|
||||
}
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
handle = (intptr_t)_weaken(__zipos_keep)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[oldfd].handle);
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd(newfd);
|
||||
rc = __winerr();
|
||||
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
|
||||
GetCurrentProcess(), &handle, 0, true,
|
||||
kNtDuplicateSameAccess)) {
|
||||
rc = newfd;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
__releasefd(newfd);
|
||||
__fds_unlock();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
g_fds.p[newfd] = g_fds.p[oldfd];
|
||||
g_fds.p[newfd].handle = handle;
|
||||
if (flags & _O_CLOEXEC) {
|
||||
g_fds.p[newfd].flags |= _O_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[newfd].flags &= ~_O_CLOEXEC;
|
||||
}
|
||||
__fds_unlock();
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Duplicates file descriptor.
|
||||
|
@ -51,10 +53,11 @@
|
|||
*/
|
||||
int dup(int fd) {
|
||||
int rc;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
if (!IsWindows()) {
|
||||
rc = sys_dup(fd);
|
||||
if (rc != -1 && __isfdkind(fd, kFdZip)) {
|
||||
_weaken(__zipos_postdup)(fd, rc);
|
||||
}
|
||||
} else {
|
||||
rc = sys_dup_nt(fd, -1, 0, -1);
|
||||
}
|
||||
|
|
|
@ -67,20 +67,24 @@ int dup2(int oldfd, int newfd) {
|
|||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
#ifdef __aarch64__
|
||||
} else if (oldfd == newfd) {
|
||||
if (oldfd == newfd) {
|
||||
// linux aarch64 defines dup3() but not dup2(), which wasn't such a
|
||||
// great decision, since the two syscalls don't behave the same way
|
||||
if (!(rc = read(oldfd, 0, 0))) rc = oldfd;
|
||||
} else
|
||||
#endif
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup2(oldfd, newfd, 0);
|
||||
if (rc != -1 && oldfd != newfd && __isfdkind(newfd, kFdZip) && !__vforked) {
|
||||
_weaken(__zipos_free)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[newfd].handle);
|
||||
bzero(g_fds.p + newfd, sizeof(*g_fds.p));
|
||||
if (!IsWindows()) {
|
||||
if (__isfdkind(oldfd, kFdZip) || __isfdkind(newfd, kFdZip)) {
|
||||
if (__vforked) {
|
||||
return enotsup();
|
||||
}
|
||||
rc = sys_dup2(oldfd, newfd, 0);
|
||||
if (rc != -1) {
|
||||
_weaken(__zipos_postdup)(oldfd, newfd);
|
||||
}
|
||||
} else {
|
||||
rc = sys_dup2(oldfd, newfd, 0);
|
||||
}
|
||||
} else if (newfd < 0) {
|
||||
rc = ebadf();
|
||||
|
|
|
@ -70,14 +70,17 @@ int dup3(int oldfd, int newfd, int flags) {
|
|||
rc = einval(); // NetBSD doesn't do this
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
if (rc != -1 && __isfdkind(newfd, kFdZip) && !__vforked) {
|
||||
_weaken(__zipos_free)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[newfd].handle);
|
||||
bzero(g_fds.p + newfd, sizeof(*g_fds.p));
|
||||
if (__isfdkind(oldfd, kFdZip) || __isfdkind(newfd, kFdZip)) {
|
||||
if (__vforked) {
|
||||
return enotsup();
|
||||
}
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
if (rc != -1) {
|
||||
_weaken(__zipos_postdup)(oldfd, newfd);
|
||||
}
|
||||
} else {
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
}
|
||||
} else {
|
||||
rc = sys_dup_nt(oldfd, newfd, flags, -1);
|
||||
|
|
|
@ -16,13 +16,30 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/createfileflags.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.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"
|
||||
|
||||
static int __zipos_dupfd(int fd, int cmd, int start) {
|
||||
int rc;
|
||||
if (start < 0) return einval();
|
||||
if (IsWindows()) {
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0),
|
||||
start);
|
||||
}
|
||||
rc = sys_fcntl(fd, cmd, start, __sys_fcntl);
|
||||
if (rc != -1) {
|
||||
__zipos_postdup(fd, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __zipos_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
|
@ -38,6 +55,8 @@ int __zipos_fcntl(int fd, int cmd, uintptr_t arg) {
|
|||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||
return __zipos_dupfd(fd, cmd, arg);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
|
|
|
@ -78,7 +78,20 @@ static void *__zipos_mmap_space(size_t mapsize) {
|
|||
return start + offset;
|
||||
}
|
||||
|
||||
struct ZiposHandle *__zipos_keep(struct ZiposHandle *h) {
|
||||
atomic_fetch_add_explicit(&h->refs, 1, memory_order_relaxed);
|
||||
return h;
|
||||
}
|
||||
|
||||
static bool __zipos_drop(struct ZiposHandle *h) {
|
||||
int refs = atomic_load_explicit(&h->refs, memory_order_acquire);
|
||||
return -1 == refs || -1 == atomic_fetch_sub(&h->refs, 1);
|
||||
}
|
||||
|
||||
void __zipos_free(struct ZiposHandle *h) {
|
||||
if (!__zipos_drop(h)) {
|
||||
return;
|
||||
}
|
||||
if (IsAsan()) {
|
||||
__asan_poison((char *)h + sizeof(struct ZiposHandle),
|
||||
h->mapsize - sizeof(struct ZiposHandle), kAsanHeapFree);
|
||||
|
@ -100,7 +113,7 @@ StartOver:
|
|||
while ((h = *ph)) {
|
||||
if (h->mapsize >= mapsize) {
|
||||
if (!_cmpxchg(ph, h, h->next)) goto StartOver;
|
||||
h->next = 0;
|
||||
atomic_init(&h->refs, 0);
|
||||
break;
|
||||
}
|
||||
ph = &h->next;
|
||||
|
@ -209,6 +222,27 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, int flags,
|
|||
return -1;
|
||||
}
|
||||
|
||||
void __zipos_postdup(int oldfd, int newfd) {
|
||||
if (oldfd == newfd) {
|
||||
return;
|
||||
}
|
||||
if (__isfdkind(newfd, kFdZip)) {
|
||||
__zipos_free((struct ZiposHandle *)(intptr_t)g_fds.p[newfd].handle);
|
||||
if (!__isfdkind(oldfd, kFdZip)) {
|
||||
__fds_lock();
|
||||
bzero(g_fds.p + newfd, sizeof(*g_fds.p));
|
||||
__fds_unlock();
|
||||
}
|
||||
}
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
__zipos_keep((struct ZiposHandle *)(intptr_t)g_fds.p[oldfd].handle);
|
||||
__fds_lock();
|
||||
__ensurefds_unlocked(newfd);
|
||||
g_fds.p[newfd] = g_fds.p[oldfd];
|
||||
__fds_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads compressed file from αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
.yoink __zipos_stat
|
||||
.yoink __zipos_notat
|
||||
.yoink __zipos_mmap
|
||||
.yoink __zipos_postdup
|
||||
.yoink __zipos_keep
|
||||
.yoink __zipos_free
|
||||
|
||||
// TODO(jart): why does corruption happen when zip has no assets?
|
||||
.yoink .cosmo
|
||||
|
|
|
@ -20,8 +20,9 @@ struct ZiposHandle {
|
|||
struct Zipos *zipos;
|
||||
size_t size;
|
||||
size_t mapsize;
|
||||
size_t pos;
|
||||
size_t cfile;
|
||||
_Atomic(int) refs;
|
||||
size_t pos; // TODO atomic
|
||||
uint8_t *mem;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
@ -38,6 +39,7 @@ struct Zipos {
|
|||
|
||||
int __zipos_close(int);
|
||||
void __zipos_free(struct ZiposHandle *);
|
||||
struct ZiposHandle *__zipos_keep(struct ZiposHandle *);
|
||||
struct Zipos *__zipos_get(void) pureconst;
|
||||
size_t __zipos_normpath(char *, const char *, size_t);
|
||||
ssize_t __zipos_find(struct Zipos *, struct ZiposUri *);
|
||||
|
@ -45,6 +47,7 @@ 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);
|
||||
void __zipos_postdup(int, int);
|
||||
int __zipos_access(struct ZiposUri *, int);
|
||||
int __zipos_stat(struct ZiposUri *, struct stat *);
|
||||
int __zipos_fstat(struct ZiposHandle *, struct stat *);
|
||||
|
|
|
@ -75,7 +75,7 @@ TEST(dup, bigNumber) {
|
|||
ASSERT_SYS(0, 0, close(100));
|
||||
}
|
||||
|
||||
TEST(dup2, zipos) {
|
||||
TEST(dup2, ziposdest) {
|
||||
ASSERT_SYS(0, 3, creat("real", 0644));
|
||||
ASSERT_SYS(0, 4, open("/zip/libc/testlib/hyperion.txt", O_RDONLY));
|
||||
ASSERT_SYS(0, 2, write(3, "hi", 2));
|
||||
|
@ -86,6 +86,15 @@ TEST(dup2, zipos) {
|
|||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(dup2, zipossrc) {
|
||||
char b[8];
|
||||
ASSERT_SYS(0, 3, open("/zip/libc/testlib/hyperion.txt", O_RDONLY));
|
||||
ASSERT_SYS(0, 4, dup2(3, 4));
|
||||
ASSERT_SYS(0, 8, read(4, b, 8));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
TEST(dup, clearsCloexecFlag) {
|
||||
static bool once;
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "libc/thread/thread.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
__static_yoink("libc/testlib/hyperion.txt");
|
||||
__static_yoink("zipos");
|
||||
|
||||
int Lock(int fd, int type, long start, long len) {
|
||||
int e;
|
||||
struct flock lock = {
|
||||
|
@ -121,6 +124,17 @@ TEST(fcntl, F_DUPFD_CLOEXEC) {
|
|||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(fcntl, ziposDupFd) {
|
||||
char b[8];
|
||||
ASSERT_SYS(0, 3, open("/zip/libc/testlib/hyperion.txt", O_RDONLY));
|
||||
ASSERT_SYS(0, 4, fcntl(3, F_DUPFD, 4));
|
||||
ASSERT_SYS(0, 8, read(3, b, 8));
|
||||
ASSERT_SYS(0, 0, lseek(4, 0, SEEK_SET));
|
||||
ASSERT_SYS(0, 8, read(4, b, 8));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
}
|
||||
|
||||
void OnSig(int sig) {
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue