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>
This commit is contained in:
parent
e9bc4cccef
commit
aec6479820
|
@ -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;
|
||||
|
|
|
@ -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);}
|
||||
|
|
Loading…
Reference in New Issue