From 31c3c0e306cdd7f891ad3fb2c2838e235f6c6bac Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 27 Mar 2020 12:12:31 +0100 Subject: [PATCH] Cygwin: symlinks: support WSL symlinks Treat WSL symlinks just like other symlinks. Convert absolute paths pointing to Windows drives via /mnt/ to Windows-style paths : Signed-off-by: Corinna Vinschen --- winsup/cygwin/path.cc | 73 +++++++++++++++++++++++++++++++++++++ winsup/cygwin/release/3.1.5 | 6 +++ winsup/doc/new-features.xml | 4 ++ 3 files changed, 83 insertions(+) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index bda3ca1b5..7fa2bc5b5 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2360,6 +2360,29 @@ check_reparse_point_string (PUNICODE_STRING subst) return false; } +#ifndef IO_REPARSE_TAG_LX_SYMLINK +#define IO_REPARSE_TAG_LX_SYMLINK (0xa000001d) +#endif + +typedef struct _REPARSE_LX_SYMLINK_BUFFER +{ + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + struct { + DWORD FileType; /* Take member name with a grain of salt. Value is + apparently always 2 for symlinks. */ + char PathBuffer[1];/* POSIX path as given to symlink(2). + Path is not \0 terminated. + Length is ReparseDataLength - sizeof (FileType). + Always UTF-8. + Chars given in incompatible codesets, e. g. umlauts + in ISO-8859-x, are converted to the Unicode + REPLACEMENT CHARACTER 0xfffd == \xef\xbf\bd */ + } LxSymlinkReparseBuffer; +} REPARSE_LX_SYMLINK_BUFFER,*PREPARSE_LX_SYMLINK_BUFFER; + + /* Return values: <0: Negative errno. 0: No symlink. @@ -2434,6 +2457,56 @@ check_reparse_point_target (HANDLE h, bool remote, PREPARSE_DATA_BUFFER rp, if (check_reparse_point_string (psymbuf)) return PATH_SYMLINK | PATH_REP; } + else if (rp->ReparseTag == IO_REPARSE_TAG_LX_SYMLINK) + { + /* WSL symlink. Problem: We have to convert the path to UTF-16 for + the caller. Reparse points are 16K max. The buffer given to rp + is 32K. So there's enough trailing space in the buffer to convert + to UTF-16 and let psymbuf point to it. */ + PREPARSE_LX_SYMLINK_BUFFER rpl = (PREPARSE_LX_SYMLINK_BUFFER) rp; + char *path_buf = rpl->LxSymlinkReparseBuffer.PathBuffer; + DWORD path_len = rpl->ReparseDataLength - sizeof (DWORD); + PBYTE utf16_ptr; + PWCHAR utf16_buf; + int utf16_bufsize; + bool full_path = false; + const size_t drv_prefix_len = strlen ("/mnt"); + + /* Compute buffer for path converted to UTF-16. */ + utf16_ptr = (PBYTE) rpl + sizeof (REPARSE_LX_SYMLINK_BUFFER) + + rp->ReparseDataLength; + while ((intptr_t) utf16_ptr % sizeof (WCHAR)) + ++utf16_ptr; + utf16_buf = (PWCHAR) utf16_ptr; + utf16_bufsize = NT_MAX_PATH - (utf16_buf - (PWCHAR) rpl); + /* Check for abs path /mnt/x. Convert to x: after conversion to UTF-16. */ + if (path_len >= drv_prefix_len + 2 + && !strncmp (path_buf, "/mnt/", drv_prefix_len + 1) + && islower (path_buf[drv_prefix_len + 1]) + && (path_len == drv_prefix_len + 2 + || path_buf[drv_prefix_len + 2] == '/')) + { + /* Skip forward to the slash leading the drive letter. That leaves + room for adding the colon. */ + path_buf += drv_prefix_len; + path_len -= drv_prefix_len; + full_path = true; + } + utf16_bufsize = MultiByteToWideChar (CP_UTF8, 0, path_buf, path_len, + utf16_buf, utf16_bufsize); + if (utf16_bufsize) + { + if (full_path) + { + utf16_buf[0] = utf16_buf[1]; /* Move drive letter to front */ + utf16_buf[1] = L':'; /* Add colon */ + } + RtlInitCountedUnicodeString (psymbuf, utf16_buf, + utf16_bufsize * sizeof (WCHAR)); + return PATH_SYMLINK | PATH_REP; + } + return -EIO; + } #ifdef __WITH_AF_UNIX else if (rp->ReparseTag == IO_REPARSE_TAG_CYGUNIX) { diff --git a/winsup/cygwin/release/3.1.5 b/winsup/cygwin/release/3.1.5 index e567ecb32..6f16aad93 100644 --- a/winsup/cygwin/release/3.1.5 +++ b/winsup/cygwin/release/3.1.5 @@ -1,3 +1,9 @@ +What changed: +------------- + +- Support WSL symlinks. + + Bug Fixes: ---------- diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml index 9086302d3..a200300f2 100644 --- a/winsup/doc/new-features.xml +++ b/winsup/doc/new-features.xml @@ -82,6 +82,10 @@ be supported by upcoming mintty releases. For the reasoning, see https://gitlab.freedesktop.org/terminal-wg/specifications/issues/9. + +Support WSL symlinks. + +