diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2020-12-02 16:12:58 +0100 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2020-12-02 16:14:41 +0100 |
commit | aec6479820fee5f71d50930bf0dde2bbf386bd4b (patch) | |
tree | 1e152869c24e4280f3bd92d0440a1aace56f5105 | |
parent | e9bc4cccefbdc989bafb4b6c58c8892eb07ce277 (diff) | |
download | cygnal-aec6479820fee5f71d50930bf0dde2bbf386bd4b.tar.gz cygnal-aec6479820fee5f71d50930bf0dde2bbf386bd4b.tar.bz2 cygnal-aec6479820fee5f71d50930bf0dde2bbf386bd4b.zip |
Cygwin: add flag to indicate reparse points unknown to WinAPI
https://cygwin.com/pipermail/cygwin/2020-December/246938.html
reports a problem where, when adding a Cygwin default symlink
to $PATH since Cygwin 3.1.5, $PATH handling appears to be broken.
3.1.5 switched to WSL symlinks as Cygwin default symlinks.
A piece of code in path handling skips resolving reparse points
if they are the last component in the path. Thus a reparse point
in $PATH is not resolved but converted to Windows path syntax
verbatim.
If you do this with a WSL symlink, certain WinAPI functions fail.
The underlying $PATH handling fails to recognize the reparse
point in $PATH and returns with STATUS_IO_REPARSE_TAG_NOT_HANDLED.
As a result, the calling WinAPI function fails, most prominently
so CreateProcess.
Fix this problem by adding a PATH_REP_NOAPI bit to path_types
and a matching method path_conv::is_winapi_reparse_point().
Right now this flag is set for WSL symlinks and Cygwin AF_UNIX
sockets (new type implemented as reparse points).
The aforementioned code skipping repare point path resolution calls
is_winapi_reparse_point() rather than is_known_reparse_point(),
so now path resolution is only skipped for reparse points known
to WinAPI.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
-rw-r--r-- | winsup/cygwin/path.cc | 8 | ||||
-rw-r--r-- | winsup/cygwin/path.h | 12 |
2 files changed, 16 insertions, 4 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 7e6243d32..abd3687df 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1017,7 +1017,7 @@ path_conv::check (const char *src, unsigned opt, { if (component == 0 && (!(opt & PC_SYM_FOLLOW) - || (is_known_reparse_point () + || (is_winapi_reparse_point () && (opt & PC_SYM_NOFOLLOW_REP)))) { /* Usually a trailing slash requires to follow a symlink, @@ -2622,7 +2622,7 @@ check_reparse_point_target (HANDLE h, bool remote, PREPARSE_DATA_BUFFER rp, } RtlInitCountedUnicodeString (psymbuf, utf16_buf, utf16_bufsize * sizeof (WCHAR)); - return PATH_SYMLINK | PATH_REP; + return PATH_SYMLINK | PATH_REP | PATH_REP_NOAPI; } return -EIO; } @@ -2632,10 +2632,10 @@ check_reparse_point_target (HANDLE h, bool remote, PREPARSE_DATA_BUFFER rp, if (memcmp (CYGWIN_SOCKET_GUID, &rgp->ReparseGuid, sizeof (GUID)) == 0) #ifdef __WITH_AF_UNIX - return PATH_SOCKET | PATH_REP; + return PATH_SOCKET | PATH_REP | PATH_REP_NOAPI; #else /* Recognize this as a reparse point but not as a socket. */ - return PATH_REP; + return PATH_REP | PATH_REP_NOAPI; #endif } return 0; diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 45a047ad3..62bd5ddd5 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -71,6 +71,7 @@ enum path_types PATH_SYMLINK = _BIT ( 4), /* symlink understood by Cygwin */ PATH_SOCKET = _BIT ( 5), /* AF_UNIX socket file */ PATH_RESOLVE_PROCFD = _BIT ( 6), /* fd symlink via /proc */ + PATH_REP_NOAPI = _BIT ( 7), /* rep. point unknown to WinAPI */ PATH_DONT_USE = _BIT (31) /* conversion to signed happens. */ }; @@ -179,7 +180,18 @@ class path_conv } int issymlink () const {return path_flags & PATH_SYMLINK;} int is_lnk_symlink () const {return path_flags & PATH_LNK;} + /* This indicates any known reparse point */ int is_known_reparse_point () const {return path_flags & PATH_REP;} + /* This indicates any known reparse point, handled sanely by WinAPI. + The difference is crucial: WSL symlinks, for instance, are known + reparse points, so we want to open them as reparse points usually. + However they are foreign to WinAPI and not handled sanely. If one + is part of $PATH, WinAPI functions may fail under the hood with + STATUS_IO_REPARSE_TAG_NOT_HANDLED. */ + int is_winapi_reparse_point () const + { + return (path_flags & (PATH_REP | PATH_REP_NOAPI)) == PATH_REP; + } int isdevice () const {return dev.not_device (FH_FS) && dev.not_device (FH_FIFO);} int isfifo () const {return dev.is_device (FH_FIFO);} int isspecial () const {return dev.not_device (FH_FS);} |