mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-01 16:58:30 +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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue