mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 02:38:31 +00:00
Make improvements for Actually Portable Emacs
- Get SIGWINCH working again on the New Technology - Correctly handle O_NOFOLLOW in open() on Windows - Implement synthetic umask() functionality on Windows - Do a better job managing file execute access on Windows - Fill in `st_uid` and `st_gid` with username hash on Windows - Munge UNICODE control pictures into control codes on Windows - Do a better job ensuring Windows console settings are restored - Introduce KPRINTF_LOG environment variable to log kprintf to a file
This commit is contained in:
parent
9c7b81ee0f
commit
965516e313
108 changed files with 1126 additions and 807 deletions
|
@ -26,9 +26,12 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/enum/wait.h"
|
||||
#include "libc/nt/errors.h"
|
||||
|
@ -48,83 +51,12 @@
|
|||
|
||||
#ifdef __x86_64__
|
||||
|
||||
enum Action {
|
||||
DO_NOTHING,
|
||||
DO_RESTART,
|
||||
DO_EINTR,
|
||||
};
|
||||
|
||||
static textwindows void sys_read_nt_abort(int64_t handle,
|
||||
struct NtOverlapped *overlapped) {
|
||||
unassert(CancelIoEx(handle, overlapped) ||
|
||||
GetLastError() == kNtErrorNotFound);
|
||||
}
|
||||
|
||||
static textwindows int MungeTerminalInput(char *p, uint32_t *n) {
|
||||
size_t i, j;
|
||||
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
|
||||
for (i = 0; i < *n; ++i) {
|
||||
if (p[i] == '\r') {
|
||||
p[i] = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoIsigs)) {
|
||||
bool delivered = false;
|
||||
bool got_vintr = false;
|
||||
bool got_vquit = false;
|
||||
for (j = i = 0; i < *n; ++i) {
|
||||
if (__vintr != _POSIX_VDISABLE && p[i] == __vintr) {
|
||||
got_vintr = true;
|
||||
} else if (__vquit != _POSIX_VDISABLE && p[i] == __vquit) {
|
||||
got_vquit = true;
|
||||
} else {
|
||||
p[j++] = p[i];
|
||||
}
|
||||
}
|
||||
if (got_vintr) {
|
||||
delivered |= __sig_handle(0, SIGINT, SI_KERNEL, 0);
|
||||
}
|
||||
if (got_vquit) {
|
||||
delivered |= __sig_handle(0, SIGQUIT, SI_KERNEL, 0);
|
||||
}
|
||||
if (*n && !j) {
|
||||
if (delivered) {
|
||||
return DO_EINTR;
|
||||
} else {
|
||||
return DO_RESTART;
|
||||
}
|
||||
}
|
||||
*n = j;
|
||||
}
|
||||
return DO_NOTHING;
|
||||
}
|
||||
|
||||
// Manual CMD.EXE echoing for when !ICANON && ECHO is the case.
|
||||
static textwindows void EchoTerminalInput(struct Fd *fd, char *p, size_t n) {
|
||||
int64_t hOutput;
|
||||
if (fd->kind == kFdConsole) {
|
||||
hOutput = fd->extra;
|
||||
} else {
|
||||
hOutput = g_fds.p[1].handle;
|
||||
}
|
||||
if (__ttymagic & kFdTtyEchoRaw) {
|
||||
WriteFile(hOutput, p, n, 0, 0);
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (isascii(p[i]) && iscntrl(p[i]) && p[i] != '\n' && p[i] != '\t') {
|
||||
char ctl[2];
|
||||
ctl[0] = '^';
|
||||
ctl[1] = p[i] ^ 0100;
|
||||
WriteFile(hOutput, ctl, 2, 0, 0);
|
||||
} else {
|
||||
WriteFile(hOutput, p + i, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
||||
size_t size, int64_t offset) {
|
||||
|
||||
|
@ -133,11 +65,38 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
|||
uint32_t got;
|
||||
int filetype;
|
||||
int64_t handle;
|
||||
uint32_t remain;
|
||||
uint32_t conmode;
|
||||
char *targetdata;
|
||||
uint32_t targetsize;
|
||||
bool is_console_input;
|
||||
int abort_errno = EAGAIN;
|
||||
StartOver:
|
||||
size = MIN(size, 0x7ffff000);
|
||||
handle = __resolve_stdin_handle(fd->handle);
|
||||
filetype = GetFileType(handle);
|
||||
is_console_input = g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle
|
||||
: fd->handle == g_fds.p[0].handle;
|
||||
|
||||
// the caller might be reading a single byte at a time. but we need to
|
||||
// be able to munge three bytes into just 1 e.g. "\342\220\200" → "\0"
|
||||
if (size && fd->buflen) {
|
||||
ReturnDataFromBuffer:
|
||||
got = MIN(size, fd->buflen);
|
||||
remain = fd->buflen - got;
|
||||
if (got) memcpy(data, fd->buf, got);
|
||||
if (remain) memmove(fd->buf, fd->buf + got, remain);
|
||||
fd->buflen = remain;
|
||||
return got;
|
||||
}
|
||||
if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) {
|
||||
targetdata = fd->buf;
|
||||
targetsize = sizeof(fd->buf);
|
||||
} else {
|
||||
targetdata = data;
|
||||
targetsize = size;
|
||||
}
|
||||
|
||||
if (filetype == kNtFileTypeChar || filetype == kNtFileTypePipe) {
|
||||
struct NtOverlapped overlap = {0};
|
||||
if (offset != -1) {
|
||||
|
@ -147,7 +106,7 @@ StartOver:
|
|||
if ((overlap.hEvent = CreateEvent(0, 0, 0, 0))) {
|
||||
// the win32 manual says it's important to *not* put &got here
|
||||
// since for overlapped i/o, we always use GetOverlappedResult
|
||||
ok = ReadFile(handle, data, size, 0, &overlap);
|
||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||
if (!ok && GetLastError() == kNtErrorIoPending) {
|
||||
// the i/o operation is in flight; blocking is unavoidable
|
||||
// if we're in a non-blocking mode, then immediately abort
|
||||
|
@ -155,7 +114,7 @@ StartOver:
|
|||
// otherwise wait for i/o periodically checking interrupts
|
||||
if (fd->flags & O_NONBLOCK) {
|
||||
sys_read_nt_abort(handle, &overlap);
|
||||
} else if (_check_interrupts(kSigOpRestartable, g_fds.p)) {
|
||||
} else if (_check_interrupts(kSigOpRestartable)) {
|
||||
Interrupted:
|
||||
abort_errno = errno;
|
||||
sys_read_nt_abort(handle, &overlap);
|
||||
|
@ -164,7 +123,7 @@ StartOver:
|
|||
uint32_t i;
|
||||
i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS);
|
||||
if (i == kNtWaitTimeout) {
|
||||
if (_check_interrupts(kSigOpRestartable, g_fds.p)) {
|
||||
if (_check_interrupts(kSigOpRestartable)) {
|
||||
goto Interrupted;
|
||||
}
|
||||
} else {
|
||||
|
@ -186,7 +145,7 @@ StartOver:
|
|||
}
|
||||
} else if (offset == -1) {
|
||||
// perform simple blocking file read
|
||||
ok = ReadFile(handle, data, size, &got, 0);
|
||||
ok = ReadFile(handle, targetdata, targetsize, &got, 0);
|
||||
} else {
|
||||
// perform pread()-style file read at particular file offset
|
||||
int64_t position;
|
||||
|
@ -196,17 +155,17 @@ StartOver:
|
|||
}
|
||||
struct NtOverlapped overlap = {0};
|
||||
overlap.Pointer = (void *)(uintptr_t)offset;
|
||||
ok = ReadFile(handle, data, size, 0, &overlap);
|
||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||
if (!ok && GetLastError() == kNtErrorIoPending) ok = true;
|
||||
if (ok) ok = GetOverlappedResult(handle, &overlap, &got, true);
|
||||
// restore file pointer which windows clobbers, even on error
|
||||
unassert(SetFilePointerEx(handle, position, 0, SEEK_SET));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle
|
||||
: fd->handle == g_fds.p[0].handle) {
|
||||
if (is_console_input) {
|
||||
if (__ttymagic & kFdTtyMunging) {
|
||||
switch (MungeTerminalInput(data, &got)) {
|
||||
switch (_weaken(__munge_terminal_input)(targetdata, &got)) {
|
||||
case DO_NOTHING:
|
||||
break;
|
||||
case DO_RESTART:
|
||||
|
@ -218,9 +177,13 @@ StartOver:
|
|||
}
|
||||
}
|
||||
if (__ttymagic & kFdTtyEchoing) {
|
||||
EchoTerminalInput(fd, data, got);
|
||||
_weaken(__echo_terminal_input)(fd, targetdata, got);
|
||||
}
|
||||
}
|
||||
if (targetdata != data) {
|
||||
fd->buflen = got;
|
||||
goto ReturnDataFromBuffer;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
|
@ -245,7 +208,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
|||
uint32_t size;
|
||||
size_t i, total;
|
||||
if (opt_offset < -1) return einval();
|
||||
if (_check_interrupts(kSigOpRestartable, fd)) return -1;
|
||||
if (_check_interrupts(kSigOpRestartable)) return -1;
|
||||
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
|
||||
if (iovlen) {
|
||||
for (total = i = 0; i < iovlen; ++i) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue