mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Improve handling of weird reparse points
On Windows file system tools like `ls` would print errors when they find things like WSL symlinks, which can't be read by WIN32. I don't know how they got on my hard drive but this change ensures Cosmo will handle them more gracefully. If a reparse point can't be followed, then fstatat will return information about the link itself. If readlink encounters reparse points that are WIN32 symlinks, then it'll log more helpful details when using MODE=dbg (a.k.a. cosmocc -mdbg). Speaking of which, this change is also going to help you troubleshoot locks; when you build your app using the cosmocc -mdbg flag your --strace logs will now show lock acquisition
This commit is contained in:
parent
90460ceb3c
commit
79516bf08e
4 changed files with 57 additions and 48 deletions
|
@ -16,11 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
|
@ -97,14 +97,27 @@ TryAgain:
|
|||
0)) != -1) {
|
||||
rc = st ? sys_fstat_nt_handle(fh, path16, st) : 0;
|
||||
CloseHandle(fh);
|
||||
} else if (dwDesiredAccess == kNtFileGenericRead &&
|
||||
(GetLastError() == kNtErrorAccessDenied ||
|
||||
GetLastError() == kNtErrorSharingViolation)) {
|
||||
dwDesiredAccess = kNtFileReadAttributes;
|
||||
errno = e;
|
||||
goto TryAgain;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
uint32_t dwErrorCode = GetLastError();
|
||||
if (dwDesiredAccess == kNtFileGenericRead &&
|
||||
(dwErrorCode == kNtErrorAccessDenied ||
|
||||
dwErrorCode == kNtErrorSharingViolation)) {
|
||||
dwDesiredAccess = kNtFileReadAttributes;
|
||||
errno = e;
|
||||
goto TryAgain;
|
||||
} else if (!(flags & AT_SYMLINK_NOFOLLOW) &&
|
||||
dwErrorCode == kNtErrorCantAccessFile) {
|
||||
// ERROR_CANT_ACCESS_FILE (1920) usually means that the I/O system
|
||||
// a WSL symlink is accessed from WIN32 API. Falling back with the
|
||||
// failed to traverse a filesystem reparse point. For example when
|
||||
// details of the link itself is better than providing nothing. It
|
||||
// should never be like this on UNIX but Windows gets a bit screwy
|
||||
flags |= AT_SYMLINK_NOFOLLOW;
|
||||
errno = e;
|
||||
goto TryAgain;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
}
|
||||
ALLOW_SIGNALS;
|
||||
|
||||
|
|
|
@ -18,14 +18,15 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, //
|
||||
int newdirfd, const char *newpath) {
|
||||
#pragma GCC push_options
|
||||
#pragma GCC diagnostic ignored "-Wframe-larger-than="
|
||||
struct {
|
||||
|
@ -36,7 +37,10 @@ textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, int newdirfd,
|
|||
#pragma GCC pop_options
|
||||
if (__mkntpathat(olddirfd, oldpath, 0, M.oldpath16) != -1 &&
|
||||
__mkntpathat(newdirfd, newpath, 0, M.newpath16) != -1) {
|
||||
if (CreateHardLink(M.newpath16, M.oldpath16, NULL)) {
|
||||
bool32 ok = CreateHardLink(M.newpath16, M.oldpath16, NULL);
|
||||
NTTRACE("CreateHardLink(%#hs, %#hs, NULL) → {%hhhd, %d}", M.newpath16,
|
||||
M.oldpath16, ok, GetLastError());
|
||||
if (ok) {
|
||||
return 0;
|
||||
} else {
|
||||
return __fix_enotdir3(__winerr(), M.newpath16, M.oldpath16);
|
||||
|
|
|
@ -172,9 +172,8 @@ static textwindows void FreeKeystroke(struct Dll **list, struct Dll *key) {
|
|||
|
||||
static textwindows void FreeKeystrokes(struct Dll **list) {
|
||||
struct Dll *key;
|
||||
while ((key = dll_first(*list))) {
|
||||
while ((key = dll_first(*list)))
|
||||
FreeKeystroke(list, key);
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows void OpenConsole(void) {
|
||||
|
@ -248,9 +247,8 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) {
|
|||
uint16_t cks = r->Event.KeyEvent.dwControlKeyState;
|
||||
|
||||
// ignore keyup events
|
||||
if (!r->Event.KeyEvent.bKeyDown && (!c || vk != kNtVkMenu)) {
|
||||
if (!r->Event.KeyEvent.bKeyDown && (!c || vk != kNtVkMenu))
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// this code is useful for troubleshooting why keys don't work
|
||||
|
@ -310,25 +308,21 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) {
|
|||
__keystroke.utf16hs = c;
|
||||
return 0;
|
||||
}
|
||||
if (IsLowSurrogate(c)) {
|
||||
if (IsLowSurrogate(c))
|
||||
c = MergeUtf16(__keystroke.utf16hs, c);
|
||||
}
|
||||
|
||||
// enter sends \r with raw terminals
|
||||
// make it a multics newline instead
|
||||
if (c == '\r' && !(__ttyconf.magic & kTtyNoCr2Nl)) {
|
||||
if (c == '\r' && !(__ttyconf.magic & kTtyNoCr2Nl))
|
||||
c = '\n';
|
||||
}
|
||||
|
||||
// ctrl-space (^@) is literally zero
|
||||
if (c == ' ' && (cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))) {
|
||||
if (c == ' ' && (cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed)))
|
||||
c = '\0';
|
||||
}
|
||||
|
||||
// make backspace (^?) distinguishable from ctrl-h (^H)
|
||||
if (c == kNtVkBack && !(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))) {
|
||||
if (c == kNtVkBack && !(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed)))
|
||||
c = 0177;
|
||||
}
|
||||
|
||||
// handle ctrl-\ and ctrl-c
|
||||
// note we define _POSIX_VDISABLE as zero
|
||||
|
@ -407,12 +401,10 @@ static textwindows int ProcessMouseEvent(const struct NtInputRecord *r,
|
|||
}
|
||||
}
|
||||
} else if ((bs || currentbs) && (__ttyconf.magic & kTtyXtMouse)) {
|
||||
if (bs && (ev & kNtMouseMoved) && currentbs) {
|
||||
if (bs && (ev & kNtMouseMoved) && currentbs)
|
||||
e |= 32; // dragging
|
||||
}
|
||||
if ((bs | currentbs) & kNtRightmostButtonPressed) {
|
||||
if ((bs | currentbs) & kNtRightmostButtonPressed)
|
||||
e |= 2; // right
|
||||
}
|
||||
OutputXtermMouseEvent:
|
||||
*p++ = 033;
|
||||
*p++ = '[';
|
||||
|
@ -489,9 +481,8 @@ static textwindows bool EraseKeystroke(void) {
|
|||
if ((k->buf[i] & 0300) == 0200)
|
||||
continue; // utf-8 cont
|
||||
EraseCharacter();
|
||||
if (!(__ttyconf.magic & kTtyEchoRaw) && IsCtl(k->buf[i])) {
|
||||
if (!(__ttyconf.magic & kTtyEchoRaw) && IsCtl(k->buf[i]))
|
||||
EraseCharacter();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -504,9 +495,8 @@ static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
|
|||
// convert win32 console event into ansi
|
||||
int len;
|
||||
char buf[23];
|
||||
if (!(len = ConvertConsoleInputToAnsi(r, buf))) {
|
||||
if (!(len = ConvertConsoleInputToAnsi(r, buf)))
|
||||
return;
|
||||
}
|
||||
|
||||
// handle backspace in canonical mode
|
||||
if (len == 1 && buf[0] && //
|
||||
|
@ -532,9 +522,8 @@ static textwindows void IngestConsoleInputRecord(struct NtInputRecord *r) {
|
|||
|
||||
// echo input if it was successfully recorded
|
||||
// assuming the win32 console isn't doing it already
|
||||
if (!(__ttyconf.magic & kTtySilence)) {
|
||||
if (!(__ttyconf.magic & kTtySilence))
|
||||
EchoTty(buf, len);
|
||||
}
|
||||
|
||||
// save keystroke to appropriate list
|
||||
if (__ttyconf.magic & kTtyUncanon) {
|
||||
|
@ -597,12 +586,10 @@ textwindows int CountConsoleInputBytes(void) {
|
|||
InitConsole();
|
||||
LockKeystrokes();
|
||||
IngestConsoleInput();
|
||||
for (e = dll_first(__keystroke.list); e; e = dll_next(__keystroke.list, e)) {
|
||||
for (e = dll_first(__keystroke.list); e; e = dll_next(__keystroke.list, e))
|
||||
count += KEYSTROKE_CONTAINER(e)->buflen;
|
||||
}
|
||||
if (!count && __keystroke.end_of_file) {
|
||||
if (!count && __keystroke.end_of_file)
|
||||
count = -1;
|
||||
}
|
||||
UnlockKeystrokes();
|
||||
ALLOW_SIGNALS;
|
||||
return count;
|
||||
|
@ -702,9 +689,8 @@ static textwindows bool DigestConsoleInput(char *data, size_t size, int *rc) {
|
|||
} else {
|
||||
FreeKeystroke(&__keystroke.list, e);
|
||||
}
|
||||
if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin) {
|
||||
if ((__ttyconf.magic & kTtyUncanon) && toto >= __ttyconf.vmin)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// return result
|
||||
|
@ -731,9 +717,8 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
|
|||
return -1;
|
||||
if (f->flags & _O_NONBLOCK)
|
||||
return eagain();
|
||||
if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
|
||||
if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask)))
|
||||
goto DeliverSignal;
|
||||
}
|
||||
struct PosixThread *pt = _pthread_self();
|
||||
pt->pt_blkmask = waitmask;
|
||||
pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0);
|
||||
|
@ -781,17 +766,14 @@ textwindows ssize_t ReadBuffer(int fd, void *data, size_t size, int64_t offset,
|
|||
// switch to terminal polyfill if reading from win32 console
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
|
||||
if (f->kind == kFdDevNull) {
|
||||
if (f->kind == kFdDevNull)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f->kind == kFdDevRandom) {
|
||||
if (f->kind == kFdDevRandom)
|
||||
return ProcessPrng(data, size) ? size : __winerr();
|
||||
}
|
||||
|
||||
if (f->kind == kFdConsole) {
|
||||
if (f->kind == kFdConsole)
|
||||
return ReadFromConsole(f, data, size, waitmask);
|
||||
}
|
||||
|
||||
// perform heavy lifting
|
||||
ssize_t rc;
|
||||
|
|
|
@ -120,7 +120,17 @@ static textwindows ssize_t sys_readlinkat_nt_impl(int dirfd, const char *path,
|
|||
}
|
||||
rc = j;
|
||||
} else {
|
||||
NTTRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
|
||||
// e.g. 0xA000001D means IO_REPARSE_TAG_LX_SYMLINK
|
||||
//
|
||||
// "WSL symlinks can't be opened from Windows, only from
|
||||
// within WSL, so if we identify them as fs.ModeSymlink,
|
||||
// then functions like filepath.Walk would fail when trying
|
||||
// to follow the link."
|
||||
//
|
||||
// —Quoth Quim Muntal (dev on Go team at Microsoft)
|
||||
//
|
||||
// See also MSDN Learn § 2.1.2.1 Reparse Tags
|
||||
NTTRACE("reparse tag %#x != kNtIoReparseTagSymlink", rdb->ReparseTag);
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue