public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: add flag to indicate reparse points unknown to WinAPI
@ 2020-12-02 15:16 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2020-12-02 15:16 UTC (permalink / raw)
  To: cygwin-cvs

https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=aec6479820fee5f71d50930bf0dde2bbf386bd4b

commit aec6479820fee5f71d50930bf0dde2bbf386bd4b
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Wed Dec 2 16:12:58 2020 +0100

    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>

Diff:
---
 winsup/cygwin/path.cc |  8 ++++----
 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);}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-12-02 15:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-02 15:16 [newlib-cygwin] Cygwin: add flag to indicate reparse points unknown to WinAPI Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).