]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: add flag to indicate reparse points unknown to WinAPI
authorCorinna Vinschen <corinna@vinschen.de>
Wed, 2 Dec 2020 15:12:58 +0000 (16:12 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Wed, 2 Dec 2020 15:14:41 +0000 (16:14 +0100)
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>
winsup/cygwin/path.cc
winsup/cygwin/path.h

index 7e6243d3287e8832111c175f2ff76fe1d8197064..abd3687dfb69487bda2fafcabaddec6fcd7abc7f 100644 (file)
@@ -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;
index 45a047ad3d73690012f334e4b2f19ebefecb3722..62bd5ddd535943b0e2b39e5a675ae1209b71261c 100644 (file)
@@ -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);}
This page took 0.040435 seconds and 5 git commands to generate.