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

commit d4a5c2be8bc09823b9afd4c6eafd41981e5ed645
Author:     Corinna Vinschen <[email protected]>
AuthorDate: Thu Feb 27 13:51:39 2025 +0100
Commit:     Corinna Vinschen <[email protected]>
CommitDate: Thu Feb 27 13:51:39 2025 +0100

    Cygwin: fhandler_netdrive: fix character conversion required for NFS shares
    
    While filenames on NFS shares are converted internally to a widechar
    representation of the input bytes treated as the default system ANSI
    codepage (CP_ACP), this doesn't hold for share names.  The names
    returned by WNetEnumResourceW are just the original bytes dropped
    verbatim into WCHAR.
    
    The original conversion from 7db1c6fc4e2a ("Cygwin: //server: revert
    to using WNet and support NFS shares") was erroneous in that it
    treated the bytes as ISO-8859-1, not as CP_ACP codepoints.
    
    Fix the conversion to convert from CP_ACP to widechar.  Use a tmp_pathbuf
    buffer for the new widechar string instead of malloc/free.  Extend the
    comment, better explaining the encoding difference between files and
    shares.
    
    Fixes: 7db1c6fc4e2a ("Cygwin: //server: revert to using WNet and support 
NFS shares")
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 winsup/cygwin/fhandler/netdrive.cc | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/winsup/cygwin/fhandler/netdrive.cc 
b/winsup/cygwin/fhandler/netdrive.cc
index 58447ed5aaab..426542fe212b 100644
--- a/winsup/cygwin/fhandler/netdrive.cc
+++ b/winsup/cygwin/fhandler/netdrive.cc
@@ -317,6 +317,7 @@ thread_netdrive_wnet (void *arg)
   size_t entry_cache_size = DIR_cache.count ();
   WCHAR provider[256], *dummy = NULL;
   wchar_t srv_name[CYG_MAX_PATH];
+  wchar_t *nfs_namebuf = NULL;
   NETRESOURCEW nri = { 0 };
   LPNETRESOURCEW nro;
   NETINFOSTRUCT netinfo;
@@ -397,6 +398,10 @@ thread_netdrive_wnet (void *arg)
          ndi->err = ENOENT;
          goto out;
        }
+      /* We need a temporary buffer for the multibyte to widechar conversion
+        only required for NFS shares. */
+      if (!nfs_namebuf)
+       nfs_namebuf = tp.w_get ();
       break;
     case WNNC_NET_DAV:
       /* WebDAV enumeration isn't supported, by the provider, but we can
@@ -447,19 +452,21 @@ thread_netdrive_wnet (void *arg)
 
       if (net_type == WNNC_NET_MS_NFS)
        {
-         wchar_t *nm = name;
-         /* Convert from "ANSI embedded in widechar" to multibyte and convert
-            back to widechar. */
+         /* With MS NFS, the bytes of the share name on the remote side
+            are simply dropped into a WCHAR buffer without conversion to
+            Unicode.  So convert from "multibyte embedded in widechar" to
+            real multibyte and then convert back to widechar here.
+
+            Quirky: This conversion is already performed for files on an
+            MS NFS filesystem when calling NtQueryDirectoryFile, but it's
+            not performed on the strings returned by WNetEnumResourceW. */
          char mbname[wcslen (name) + 1];
          char *mb = mbname;
-         while ((*mb++ = *nm++))
+         while ((*mb++ = *name++))
            ;
-         sys_mbstowcs_alloc (&name, HEAP_NOTHEAP, mbname);
-         if (!name)
-           {
-             ndi->err = ENOMEM;
-             goto out;
-           }
+
+         name = nfs_namebuf;
+         MultiByteToWideChar (CP_ACP, 0, mbname, -1, name, NT_MAX_PATH);
        }
       /* Some providers have deep links so convert embedded '\\' to '/' here */
       for (wchar_t *bs = name; (bs = wcschr (bs, L'\\')); *bs++ = L'/')
@@ -470,8 +477,6 @@ thread_netdrive_wnet (void *arg)
          break;
       if (cache_idx >= entry_cache_size)
        DIR_cache.add (name);
-      if (net_type == WNNC_NET_MS_NFS)
-       free (name);
     }
 out:
   if (dom)

Reply via email to