On Tue, 7 Dec 2021 18:15:42 +0100
Corinna Vinschen wrote:
> Hi Takashi,
> 
> ----- Forwarded message from Corinna Vinschen <corinna-cyg...@cygwin.com> 
> -----
> > The idea of the GFPNBH call is to short-circuit the path_conv handling
> > in case we have native Windows symlinks in the path.  My example above
> > was only considering what comes out of the `if ((pc_flags & ...) { ... }
> > ' expression starting in line 3485 (assuming "b" is a native symlink).
> > 
> > What I mean is this: Your patch disregards the entire string returned by
> > GFPNBH, if the returned path is an UNC path, no matter what.
> > 
> > But what if the incoming path already *was* an UNC path, and potentially
> > contains native symlinks?  In that case you have no reason to disregard
> > the resulting path from GFPNBH.
> > 
> > And if it was a drive letter path, wouldn't it be nicer to just convert
> > the UNC path prefix back to the drive letter and keep the rest of the
> > final path intact?
> > 
> > However, both of these scenarios require extra code, which isn't that
> > important for now, so, never mind.
> ----- End forwarded message -----
> 
> What I meant is something like the below (entirely untested).  Yeah, I'm
> not sure myself, if it's worth the effort...
> 
> diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
> index e254397257fd..06afd2d62996 100644
> --- a/winsup/cygwin/autoload.cc
> +++ b/winsup/cygwin/autoload.cc
> @@ -630,6 +630,7 @@ LoadDLLfunc (LdapMapErrorToWin32, 0, wldap32)
>  
>  LoadDLLfunc (WNetCloseEnum, 4, mpr)
>  LoadDLLfunc (WNetEnumResourceW, 16, mpr)
> +LoadDLLfunc (WNetGetConnectionW, 12, mpr)
>  LoadDLLfunc (WNetGetProviderNameW, 12, mpr)
>  LoadDLLfunc (WNetGetResourceInformationW, 16, mpr)
>  LoadDLLfunc (WNetOpenEnumW, 20, mpr)
> diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
> index baf04ce89a08..c7b29acf29b3 100644
> --- a/winsup/cygwin/path.cc
> +++ b/winsup/cygwin/path.cc
> @@ -3492,10 +3492,41 @@ restart:
>           {
>             UNICODE_STRING fpath;
>  
> -           RtlInitCountedUnicodeString (&fpath, fpbuf, ret * sizeof (WCHAR));
> +           /* If incoming path has no trailing backslash, but final path
> +              has one, drop trailing backslash from final path so the
> +              below string comparison has a chance to succeed. */
> +           if (upath.Buffer[(upath.Length - 1) / sizeof (WCHAR)] != L'\\'
> +                  && fpbuf[ret - 1] == L'\\')
> +                fpbuf[--ret] = L'\0';
>             fpbuf[1] = L'?';  /* \\?\ --> \??\ */
> +           RtlInitCountedUnicodeString (&fpath, fpbuf, ret * sizeof (WCHAR));
>             if (!RtlEqualUnicodeString (&upath, &fpath, !!ci_flag))
>               {
> +               /* Check if the final path is an UNC path and the incoming
> +                  path isn't.  If so... */
> +               if (RtlEqualUnicodePathPrefix (&fpath, &ro_u_uncp, TRUE)
> +                   && !RtlEqualUnicodePathPrefix (&upath, &ro_u_uncp, TRUE))
> +                 {
> +                   /* ...extract the drive letter, get the remote path,
> +                      replace remote path with drive letter, check again. */
> +                   WCHAR drive[3] = { upath.Buffer[4], L':', L'\0' };
> +                   WCHAR remote[MAX_PATH];
> +
> +                   if (WNetGetConnectionW (drive, remote, MAX_PATH)
> +                       == NO_ERROR)
> +                     {
> +                       /* Hackfest */
> +                       fpath.Buffer[4] = drive[0];
> +                       fpath.Buffer[5] = L':';
> +                       WCHAR to = fpath.Buffer + 6;
> +                       WCHAR from = to + wcslen (remote);
> +                       memmove (to, from,
> +                                (wcslen (from) + 1) * sizeof (WCHAR));
> +                       fpath.Length -= (from - to) * sizeof (WCHAR);
> +                       if (RtlEqualUnicodeString (&upath, &fpath, !!ci_flag))
> +                         goto file_not_symlink;
> +                     }
> +                 }
>                 issymlink = true;
>                 /* upath.Buffer is big enough and unused from this point on.
>                    Reuse it here, avoiding yet another buffer allocation. */

I confirmed that your patch works nicely.

...except when the drive is created by subst using UNC path,
e.g. subst w: \\server\share.

In this case, WNetGetConnectionW() fails with ERROR_NO_NET_OR_BAD_PATH.

So, I modified your patch a bit.

What about attached patch?

-- 
Takashi Yano <takashi.y...@nifty.ne.jp>

Attachment: 0001-Cygwin-path-Convert-UNC-path-prefix-back-to-drive-le.patch
Description: Binary data

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to