Make improvements

- Polyfill readlink("foo/") dir check on Windows
- Support asynchronous signal delivery on Windows
- Restore Windows Console from execve() daisy chain
- Work around bug in AARCH64 Optimized Routines memcmp()
- Disable unbourne.com shell completion on Windows for now
- Don't always set virtual terminal input state on console
- Remove Musl Libc's unusual preservation of realpath("//")
- Make realpath() strongly link malloc() to pass configure test
- Delete cosh.com shell, now that unbourne.com works on Windows!
This commit is contained in:
Justine Tunney 2023-09-06 22:39:36 -07:00
parent f9c9a323fe
commit 425c055116
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
40 changed files with 581 additions and 706 deletions

View file

@ -73,7 +73,7 @@ typedef int sig_atomic_t;
bool32 isatty(int);
char *getcwd(char *, size_t);
char *realpath(const char *, char *);
char *realpath(const char *, char *) __wur;
char *ttyname(int);
int access(const char *, int) dontthrow;
int chdir(const char *);

View file

@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
# we can't use sanitizers because:
# we're on a stack owned by win32 without tls
o/$(MODE)/libc/calls/onntconsoleevent.o: private \
COPTS += \
-ffreestanding \
-fno-sanitize=all
# we can't use asan because:
# siginfo_t memory is owned by kernels
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \

View file

@ -38,6 +38,7 @@
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
@ -56,10 +57,10 @@
extern long __klog_handle;
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
__msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess;
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
__msabi extern typeof(TerminateThread) *const __imp_TerminateThread;
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
wontreturn void __switch_stacks(intptr_t, long, long, long,
void (*)(intptr_t, intptr_t, long, long),
@ -70,9 +71,9 @@ __msabi static keywords bool32 sys_execve_nt_event(uint32_t dwCtrlType) {
}
static keywords void PurgeHandle(intptr_t h) {
if (h && h != -1) {
__imp_CloseHandle(h);
}
if (!h) return;
if (h == -1) return;
__imp_CloseHandle(h);
}
static keywords void PurgeThread(intptr_t h) {

View file

@ -17,15 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/nt/console.h"
#include "libc/sysv/errfuns.h"
textwindows bool32 sys_isatty_nt(int fd) {
if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdConsole) ||
(__isfdkind(fd, kFdFile) &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar)) {
uint32_t mode;
if (GetConsoleMode(g_fds.p[fd].handle, &mode)) {
return true;
} else {
enotty();

View file

@ -20,6 +20,7 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/systeminfo.h"

View file

@ -17,49 +17,143 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sig.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/dll.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/enum/context.h"
#include "libc/nt/enum/ctrlevent.h"
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/context.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.internal.h"
#ifdef __x86_64__
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) {
struct CosmoTib tib;
// WIN32 doesn't have the System V red-zone. Microsoft says they reserve
// the right to trample all over it. so we technically don't need to use
// this value. it's just not clear how common it is for WIN32 to clobber
// the red zone, which means broken code could seem to mostly work which
// means it's better that we're not the ones responsible for breaking it
#define kRedzoneSize 128
// win32 spawns a thread on its own just to deliver sigint
// TODO(jart): make signal code lockless so we can delete!
if (__tls_enabled && !__get_tls_win32()) {
bzero(&tib, sizeof(tib));
tib.tib_self = &tib;
tib.tib_self2 = &tib;
atomic_store_explicit(&tib.tib_tid, GetCurrentThreadId(),
memory_order_relaxed);
__set_tls_win32(&tib);
}
// Both Microsoft and the Fifth Bell System agree on this one.
#define kStackAlign 16
STRACE("__onntconsoleevent(%u)", dwCtrlType);
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
__msabi extern typeof(GetThreadContext) *const __imp_GetThreadContext;
__msabi extern typeof(OpenThread) *const __imp_OpenThread;
__msabi extern typeof(ResumeThread) *const __imp_ResumeThread;
__msabi extern typeof(SuspendThread) *const __imp_SuspendThread;
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
int WinThreadLaunch(int, int, int (*)(int, int), intptr_t);
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
return n;
}
static void Log(const char *s) {
#ifndef NDEBUG
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), s, StrLen(s), 0, 0);
#endif
}
static int GetSig(uint32_t dwCtrlType) {
switch (dwCtrlType) {
case kNtCtrlCEvent:
__sig_add(0, SIGINT, SI_KERNEL);
return true;
return SIGINT;
case kNtCtrlBreakEvent:
__sig_add(0, SIGQUIT, SI_KERNEL);
return true;
return SIGQUIT;
case kNtCtrlCloseEvent:
case kNtCtrlLogoffEvent: // only received by services
case kNtCtrlShutdownEvent: // only received by services
__sig_add(0, SIGHUP, SI_KERNEL);
return true;
return SIGHUP;
default:
return false;
__builtin_unreachable();
}
}
__msabi textwindows dontinstrument dontasan dontubsan bool32
__onntconsoleevent(uint32_t dwCtrlType) {
// the signal to be delivered
int sig = GetSig(dwCtrlType);
int sic = SI_KERNEL;
// if we don't have tls, then we can't hijack a safe stack from a
// thread so just try our luck punting the signal to the next i/o
if (!__tls_enabled) {
goto PuntSignal;
}
// we're on a stack that's owned by win32. to make matters worse,
// win32 spawns a totally new thread just to invoke this handler.
// that means most of the cosmo runtime is broken right now which
// means we can't call the user signal handler safely. what we'll
// do instead is pick a posix thread at random to hijack, pretend
// to be that thread, use its stack, and then deliver this signal
// asynchronously if it isn't blocked. hopefully it won't longjmp
// because once the handler returns, we'll restore the old thread
bool gotsome = false;
pthread_spin_lock(&_pthread_lock);
for (struct Dll *e = dll_first(_pthread_list); e && !gotsome;
e = dll_next(_pthread_list, e)) {
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
int tid = atomic_load_explicit(&pt->tib->tib_tid, memory_order_acquire);
if (tid <= 0) continue; // -1 means spawning, 0 means terminated
if (pt->tib->tib_sigmask & (1ull << (sig - 1))) continue; // blocked
intptr_t th;
if ((th = __imp_OpenThread(kNtThreadSuspendResume | kNtThreadGetContext,
false, tid))) {
uint32_t old_suspend_count = __imp_SuspendThread(th);
if (old_suspend_count != -1u) {
if (!old_suspend_count &&
atomic_load_explicit(&pt->status, memory_order_acquire) <
kPosixThreadTerminated) {
struct NtContext ctx;
__repstosb(&ctx, 0, sizeof(ctx));
ctx.ContextFlags = kNtContextControl;
if (__imp_GetThreadContext(th, &ctx)) {
gotsome = true;
pthread_spin_unlock(&_pthread_lock);
__set_tls_win32(pt->tib);
WinThreadLaunch(sig, sic, __sig_raise,
ROUNDDOWN(ctx.Rsp - kRedzoneSize, kStackAlign) - 8);
} else {
Log("GetThreadContext failed\n");
}
}
__imp_ResumeThread(th);
} else {
Log("SuspendThread failed\n");
}
__imp_CloseHandle(th);
} else {
Log("OpenThread failed\n");
}
}
if (!gotsome) {
pthread_spin_unlock(&_pthread_lock);
PuntSignal:
__sig_add(0, sig, sic);
}
return true;
}
#endif /* __x86_64__ */

View file

@ -18,17 +18,11 @@
*/
#include "libc/dce.h"
#include "libc/macros.internal.h"
.text.windows
__onntconsoleevent_nt:
ezlea __onntconsoleevent,ax
jmp __nt2sysv
.endfn __onntconsoleevent_nt,globl,hidden
.init.start 300,_init_onntconsoleevent
testb IsWindows()
jz 1f
ezlea __onntconsoleevent_nt,cx
ezlea __onntconsoleevent,cx
pushpop 1,%rdx
ntcall __imp_SetConsoleCtrlHandler
1: .init.end 300,_init_onntconsoleevent,globl,hidden

View file

@ -28,7 +28,6 @@
#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"
@ -107,6 +106,7 @@ StartOver:
// since for overlapped i/o, we always use GetOverlappedResult
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
if (!ok && GetLastError() == kNtErrorIoPending) {
TryAgain:
// the i/o operation is in flight; blocking is unavoidable
// if we're in a non-blocking mode, then immediately abort
// if an interrupt is pending then we abort before waiting
@ -137,6 +137,9 @@ StartOver:
// overlapped is allocated on stack, so it's important we wait
// for windows to acknowledge that it's done using that memory
ok = GetOverlappedResult(handle, &overlap, &got, true);
if (!ok && GetLastError() == kNtErrorIoIncomplete) {
goto TryAgain;
}
}
CloseHandle(overlap.hEvent);
} else {

View file

@ -20,8 +20,11 @@
#include "libc/intrin/strace.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/fsctl.h"
#include "libc/nt/enum/io.h"
#include "libc/nt/files.h"
@ -34,28 +37,45 @@
textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
size_t bufsiz) {
char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
size_t len = strlen16(path16);
bool must_be_directory = len > 1 && path16[len - 1] == '\\';
if (must_be_directory) path16[--len] = 0;
int64_t h;
ssize_t rc;
uint64_t w;
wint_t x, y;
volatile char *memory;
uint32_t i, j, n, mem;
char16_t path16[PATH_MAX], *p;
struct NtReparseDataBuffer *rdb;
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
mem = 16384;
memory = alloca(mem);
uint32_t mem = 16384;
volatile char *memory = alloca(mem);
CheckLargeStackAllocation((char *)memory, mem);
rdb = (struct NtReparseDataBuffer *)memory;
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
struct NtReparseDataBuffer *rdb = (struct NtReparseDataBuffer *)memory;
if ((h = CreateFile(path16, kNtFileReadAttributes,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
0, kNtOpenExisting,
kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics,
0)) != -1) {
if (DeviceIoControl(h, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &n, 0)) {
// if path had trailing slash, assert last component is directory
if (must_be_directory) {
struct NtByHandleFileInformation wst;
if (GetFileType(h) != kNtFileTypeDisk ||
(GetFileInformationByHandle(h, &wst) &&
!(wst.dwFileAttributes & kNtFileAttributeDirectory))) {
return enotdir();
}
}
uint32_t bc;
if (DeviceIoControl(h, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &bc, 0)) {
if (rdb->ReparseTag == kNtIoReparseTagSymlink) {
i = 0;
j = 0;
n = rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
uint32_t i = 0;
uint32_t j = 0;
uint32_t n =
rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
char16_t *p =
(char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
p[1] = p[0];
@ -63,15 +83,18 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
p[2] = '/';
}
while (i < n) {
x = p[i++] & 0xffff;
wint_t x = p[i++] & 0xffff;
if (!IsUcs2(x)) {
if (i < n) {
y = p[i++] & 0xffff;
wint_t y = p[i++] & 0xffff;
x = MergeUtf16(x, y);
} else {
x = 0xfffd;
}
}
uint64_t w;
if (x < 0200) {
if (x == '\\') {
x = '/';
@ -95,6 +118,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
} else {
rc = -1;
}
CloseHandle(h);
} else {
rc = __fix_enotdir(-1, path16);

View file

@ -24,8 +24,8 @@
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Reads symbolic link.
@ -40,12 +40,20 @@
* and this buffer will *not* be nul-terminated
* @return number of bytes written to buf, or -1 w/ errno; if the
* return is equal to bufsiz then truncation may have occurred
* @error EINVAL if path isn't a symbolic link
* @raise EINVAL if path isn't a symbolic link
* @raise ENOENT if `path` didn't exist
* @raise ENOTDIR if parent component existed that's not a directory
* @raise ENOTDIR if base component ends with slash and is not a dir
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
* @raise EBADF on relative `path` when `dirfd` isn't open or `AT_FDCWD`
* @raise ELOOP if a loop was detected resolving parent components
* @asyncsignalsafe
*/
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
ssize_t bytes;
if ((IsAsan() && !__asan_is_valid(buf, bufsiz)) || (bufsiz && !buf)) {
if ((bufsiz && !buf) || (IsAsan() && (!__asan_is_valid_str(path) ||
!__asan_is_valid(buf, bufsiz)))) {
bytes = efault();
} else if (_weaken(__zipos_notat) &&
(bytes = __zipos_notat(dirfd, path)) == -1) {

View file

@ -1,235 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#define SYMLOOP_MAX 40
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */
static inline bool IsSlash(char c)
{
return c == '/' || c == '\\';
}
static size_t GetSlashLen(const char *s)
{
const char *s0 = s;
while (IsSlash(*s)) s++;
return s-s0;
}
static char *ResolvePath(char *d, const char *s, size_t n)
{
if (d || (_weaken(malloc) && (d = _weaken(malloc)(n+1)))) {
return memmove(d, s, n+1);
} else {
enomem();
return 0;
}
}
/**
* Returns absolute pathname.
*
* This function removes `/./` and `/../` components. IF the path is a
* symbolic link then it's resolved.
*
* @param resolved needs PATH_MAX bytes or NULL to use malloc()
* @return resolved or NULL w/ errno
*/
char *realpath(const char *filename, char *resolved)
{
ssize_t rc;
int e, up, check_dir=0;
size_t k, p, q, l, l0, cnt=0, nup=0;
char output[PATH_MAX], stack[PATH_MAX+1], *z;
/* STRACE("realpath(%#s, %#s)", filename, resolved); */
if (!filename) {
einval();
return 0;
}
l = strnlen(filename, sizeof stack);
if (!l) {
enoent();
return 0;
}
if (l >= PATH_MAX) goto toolong;
if (l >= 4 && READ32LE(filename) == READ32LE("/zip") &&
(!filename[4] || filename[4] == '/')) {
return ResolvePath(resolved, filename, l);
}
p = sizeof stack - l - 1;
q = 0;
memcpy(stack+p, filename, l+1);
/* Main loop. Each iteration pops the next part from stack of
* remaining path components and consumes any slashes that follow.
* If not a link, it's moved to output; if a link, contents are
* pushed to the stack. */
restart:
for (; ; p+=GetSlashLen(stack+p)) {
/* If stack starts with /, the whole component is / or //
* and the output state must be reset. */
if (IsSlash(stack[p])) {
check_dir=0;
nup=0;
q=0;
output[q++] = '/';
p++;
/* Initial // is special. */
if (IsSlash(stack[p]) && !IsSlash(stack[p+1]))
output[q++] = '/';
continue;
}
z = (char *)min((intptr_t)strchrnul(stack+p, '/'),
(intptr_t)strchrnul(stack+p, '\\'));
l0 = l = z-(stack+p);
if (!l && !check_dir) break;
/* Skip any . component but preserve check_dir status. */
if (l==1 && stack[p]=='.') {
p += l;
continue;
}
/* Copy next component onto output at least temporarily, to
* call readlink, but wait to advance output position until
* determining it's not a link. */
if (q && !IsSlash(output[q-1])) {
if (!p) goto toolong;
stack[--p] = '/';
l++;
}
if (q+l >= PATH_MAX) goto toolong;
if (l) memcpy(output+q, stack+p, l);
output[q+l] = 0;
p += l;
up = 0;
if (l0==2 && stack[p-2]=='.' && stack[p-1]=='.') {
up = 1;
/* Any non-.. path components we could cancel start
* after nup repetitions of the 3-byte string "../";
* if there are none, accumulate .. components to
* later apply to cwd, if needed. */
if (q <= 3*nup) {
nup++;
q += l;
continue;
}
/* When previous components are already known to be
* directories, processing .. can skip readlink. */
if (!check_dir) goto skip_readlink;
}
e = errno;
if ((rc = readlink(output, stack, p)) == -1) {
if (errno != EINVAL) return 0;
errno = e; /* [jart] undirty errno if not a symlink */
skip_readlink:
check_dir = 0;
if (up) {
while(q && !IsSlash(output[q-1])) q--;
if (q>1 && (q>2 || !IsSlash(output[0]))) q--;
continue;
}
if (l0) q += l;
check_dir = stack[p];
continue;
}
k = rc;
npassert(k <= p);
if (k==p)
goto toolong;
if (!k) {
errno = ENOENT;
return 0;
}
if (++cnt == SYMLOOP_MAX) {
errno = ELOOP;
return 0;
}
/* If link contents end in /, strip any slashes already on
* stack to avoid /->// or //->/// or spurious toolong. */
if (IsSlash(stack[k-1])) {
while (IsSlash(stack[p]))
p++;
}
p -= k;
memmove(stack+p, stack, k);
/* Skip the stack advancement in case we have a new
* absolute base path. */
goto restart;
}
output[q] = 0;
if (!IsSlash(output[0])) {
if (!getcwd(stack, sizeof(stack))) return 0;
l = strlen(stack);
/* Cancel any initial .. components. */
p = 0;
while (nup--) {
while(l>1 && !IsSlash(stack[l-1])) l--;
if (l>1) l--;
p += 2;
if (p<q) p++;
}
if (q-p && !IsSlash(stack[l-1])) stack[l++] = '/';
if (l + (q-p) + 1 >= PATH_MAX) goto toolong;
memmove(output + l, output + p, q - p + 1);
if (l) memcpy(output, stack, l);
q = l + q-p;
}
return ResolvePath(resolved, output, q);
toolong:
enametoolong();
return 0;
}

View file

@ -24,7 +24,6 @@
#include "libc/calls/struct/winsize.internal.h"
#include "libc/dce.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/struct/consolescreenbufferinfoex.h"
#include "libc/sysv/consts/sicode.h"
@ -66,7 +65,6 @@ __attribute__((__constructor__)) static void sigwinch_init(void) {
if (!IsWindows()) return;
unsigned ws = __get_console_size();
atomic_store_explicit(&__win_winsize, ws, memory_order_release);
STRACE("sigwinch_init() → %08x", ws);
}
#endif /* __x86_64__ */

View file

@ -185,18 +185,23 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
if (opt == TCSAFLUSH) {
FlushConsoleInputBuffer(hInput);
}
inmode &=
~(kNtEnableLineInput | kNtEnableEchoInput | kNtEnableProcessedInput);
inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
inmode |= kNtEnableWindowInput;
__ttymagic = 0;
if (tio->c_lflag & ICANON) {
inmode |= kNtEnableLineInput;
inmode |= kNtEnableLineInput | kNtEnableProcessedInput;
} else {
__ttymagic |= kFdTtyMunging;
if (tio->c_cc[VMIN] != 1) {
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
return einval();
}
if (IsAtLeastWindows10()) {
// - keys like f1, up, etc. get turned into \e ansi codes
// - totally destroys default console gui (e.g. up arrow)
inmode |= kNtEnableVirtualTerminalInput;
}
}
if (!(tio->c_iflag & ICRNL)) {
__ttymagic |= kFdTtyNoCr2Nl;
@ -220,13 +225,11 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
if (!(tio->c_lflag & ISIG)) {
__ttymagic |= kFdTtyNoIsigs;
}
if (IsAtLeastWindows10()) {
inmode |= kNtEnableVirtualTerminalInput;
}
__vintr = tio->c_cc[VINTR];
__vquit = tio->c_cc[VQUIT];
if ((tio->c_lflag & ISIG) && //
tio->c_cc[VINTR] == CTRL('C')) {
// allows ctrl-c to be delivered asynchronously via win32
inmode |= kNtEnableProcessedInput;
}
ok = SetConsoleMode(hInput, inmode);

View file

@ -20,7 +20,9 @@
#include "libc/calls/internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@ -30,6 +32,8 @@
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.internal.h"
/**
* @fileoverview makes windows stdin handle capable of being poll'd
@ -56,11 +60,24 @@ __msabi extern typeof(CreateFile) *const __imp_CreateFileW;
__msabi extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW;
__msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW;
__msabi extern typeof(CreateThread) *const __imp_CreateThread;
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
__msabi extern typeof(ReadFile) *const __imp_ReadFile;
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
__msabi extern typeof(WriteFile) *const __imp_WriteFile;
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
return n;
}
static void Log(const char *s) {
#if 0
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), s, StrLen(s), 0, 0);
#endif
}
__msabi static dontasan dontubsan dontinstrument textwindows uint32_t
WinStdinThread(void *lpParameter) {
char buf[4096];
@ -75,19 +92,19 @@ WinStdinThread(void *lpParameter) {
__imp_CloseHandle(g_fds.stdin.inisem);
// relay stdin to process
NTTRACE("<stdin> activated");
Log("<stdin> activated\n");
for (;;) {
if (!__imp_ReadFile(g_fds.stdin.handle, buf, sizeof(buf), &got, 0)) {
NTTRACE("<stdin> read failed");
Log("<stdin> read failed\n");
goto Finish;
}
if (!got) {
NTTRACE("<stdin> end of file");
Log("<stdin> end of file\n");
goto Finish;
}
for (i = 0; i < got; i += wrote) {
if (!__imp_WriteFile(g_fds.stdin.writer, buf + i, got - i, &wrote, 0)) {
NTTRACE("<stdin> failed to write to pipe");
Log("<stdin> failed to write to pipe\n");
goto Finish;
}
}
@ -106,13 +123,13 @@ dontasan dontubsan dontinstrument textwindows void WinMainStdin(void) {
if (!SupportsWindows()) return;
hStdin = __imp_GetStdHandle(kNtStdInputHandle);
if (hStdin == kNtInvalidHandleValue) {
NTTRACE("<stdin> GetStdHandle failed");
Log("<stdin> GetStdHandle failed\n");
return;
}
// create non-inherited semaphore with initial value of 0
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0);
if (!hSemaphore) {
NTTRACE("<stdin> CreateSemaphore failed");
Log("<stdin> CreateSemaphore failed\n");
return;
}
__create_pipe_name(pipename);
@ -120,18 +137,18 @@ dontasan dontubsan dontinstrument textwindows void WinMainStdin(void) {
pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped,
kNtPipeTypeByte | kNtPipeReadmodeByte, 1, 4096, 4096, 0, 0);
if (hReader == kNtInvalidHandleValue) {
NTTRACE("<stdin> CreateNamedPipe failed");
Log("<stdin> CreateNamedPipe failed\n");
return;
}
hWriter = __imp_CreateFileW(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting,
kNtFileFlagOverlapped, 0);
if (hWriter == kNtInvalidHandleValue) {
NTTRACE("<stdin> CreateFile failed");
Log("<stdin> CreateFile failed\n");
return;
}
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
if (!hThread) {
NTTRACE("<stdin> CreateThread failed");
Log("<stdin> CreateThread failed\n");
return;
}
g_fds.stdin.handle = hStdin;

View file

@ -0,0 +1,47 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 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/macros.internal.h"
.text.windows
// Used by clone() on Windows to launch thread.
//
// Windows owns the stack memory when we initially enter threads.
// This function switches us over, so that we can start using the
// runtime facilities.
//
// @param %rdi is arg1
// @param %rsi is arg2
// @param %rdx is func
// @param %rcx is stack
// @return %rax is res
// @see clone()
WinThreadLaunch:
push %rbx
push %r15
mov %rbp,%r15
mov %rsp,%rbx
mov %rcx,%rsp
xor %rbp,%rbp
call *%rdx
mov %r15,%rbp
mov %rbx,%rsp
pop %r15
pop %rbx
ret
.endfn WinThreadLaunch,globl,hidden