public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin/main] Cygwin: // and //server: switch to Network Discovery
@ 2024-03-20 13:49 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2024-03-20 13:49 UTC (permalink / raw)
  To: cygwin-cvs

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

commit 205190a80bd0b50b8b34768fe298411d6bde2e25
Author:     Corinna Vinschen <corinna@vinschen.de>
AuthorDate: Wed Mar 20 14:32:49 2024 +0100
Commit:     Corinna Vinschen <corinna@vinschen.de>
CommitDate: Wed Mar 20 14:46:49 2024 +0100

    Cygwin: // and //server: switch to Network Discovery
    
    SMBv1 is ultimately deprecated since Novemer 2023.  It's also
    not installed by default on latest Windows versions.
    
    Drop using the WNet (SMBv1) API in favor of using Network Discovery.
    Given there's no documented Win32 API for that, the code now uses
    the Shell API.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/autoload.cc               |  11 +-
 winsup/cygwin/fhandler/netdrive.cc      | 477 +++++++++++++++++---------------
 winsup/cygwin/local_includes/fhandler.h |   1 +
 winsup/cygwin/release/3.6.0             |   4 +
 4 files changed, 264 insertions(+), 229 deletions(-)

diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index cc9dafe1b621..e79b6ad03a57 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -502,13 +502,6 @@ LoadDLLfunc (ldap_value_free_len, wldap32)
 LoadDLLfunc (LdapGetLastError, wldap32)
 LoadDLLfunc (LdapMapErrorToWin32, wldap32)
 
-LoadDLLfunc (WNetCloseEnum, mpr)
-LoadDLLfunc (WNetEnumResourceW, mpr)
-LoadDLLfunc (WNetGetLastErrorW, mpr)
-LoadDLLfunc (WNetGetProviderNameW, mpr)
-LoadDLLfunc (WNetGetResourceInformationW, mpr)
-LoadDLLfunc (WNetOpenEnumW, mpr)
-
 LoadDLLfunc (DsEnumerateDomainTrustsW, netapi32)
 LoadDLLfunc (DsGetDcNameW, netapi32)
 LoadDLLfunc (NetApiBufferFree, netapi32)
@@ -521,6 +514,8 @@ LoadDLLfunc (NetUserGetGroups, netapi32)
 LoadDLLfunc (NetUserGetInfo, netapi32)
 LoadDLLfunc (NetUserGetLocalGroups, netapi32)
 
+LoadDLLfunc (CoInitialize, ole32)
+LoadDLLfunc (CoUninitialize, ole32)
 LoadDLLfunc (CoTaskMemFree, ole32)
 
 LoadDLLfunc (LsaConnectUntrusted, secur32)
@@ -531,7 +526,9 @@ LoadDLLfunc (LsaLookupAuthenticationPackage, secur32)
 LoadDLLfunc (LsaRegisterLogonProcess, secur32)
 LoadDLLfunc (TranslateNameW, secur32)
 
+LoadDLLfunc (SHCreateItemFromParsingName, shell32)
 LoadDLLfunc (SHGetDesktopFolder, shell32)
+LoadDLLfunc (SHGetKnownFolderItem, shell32)
 
 LoadDLLfunc (CreateFontW, gdi32)
 LoadDLLfunc (DeleteObject, gdi32)
diff --git a/winsup/cygwin/fhandler/netdrive.cc b/winsup/cygwin/fhandler/netdrive.cc
index 7c3207139846..4f080efb0e1a 100644
--- a/winsup/cygwin/fhandler/netdrive.cc
+++ b/winsup/cygwin/fhandler/netdrive.cc
@@ -7,7 +7,6 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
-#include <stdlib.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -15,196 +14,259 @@ details. */
 #include "dtable.h"
 #include "cygheap.h"
 #include "cygthread.h"
-#include "tls_pbuf.h"
 
+#include <shobjidl.h>
+#include <shlobj.h>
+#include <lm.h>
+
+#include <stdlib.h>
 #include <dirent.h>
+#include <wctype.h>
 
-enum
-  {
-    GET_RESOURCE_OPENENUM = 1,
-    GET_RESOURCE_OPENENUMTOP = 2,
-    GET_RESOURCE_ENUM = 3
-  };
+/* SMBv1 is deprectated and not even installed by default anymore on
+   Windows 10 and 11 machines or their servers.
 
-struct netdriveinf
+   So this fhandler class now uses Network Discovery, which, unfortunately,
+   requires to use the shell API. */
+
+/* Define the required GUIDs here to avoid linking with libuuid.a */
+const GUID FOLDERID_NetworkFolder = {
+  0xd20beec4, 0x5ca8, 0x4905,
+  { 0xae, 0x3b, 0xbf, 0x25, 0x1e, 0xa0, 0x9b, 0x53 }
+};
+
+const GUID BHID_StorageEnum = {
+  0x4621a4e3, 0xf0d6, 0x4773,
+  { 0x8a, 0x9c, 0x46, 0xe7, 0x7b, 0x17, 0x48, 0x40 }
+};
+
+const GUID BHID_EnumItems = {
+  0x94f60519, 0x2850, 0x4924,
+  { 0xaa, 0x5a, 0xd1, 0x5e, 0x84, 0x86, 0x80, 0x39 }
+};
+
+class dir_cache
+{
+  size_t max_entries;
+  size_t num_entries;
+  wchar_t **entry;
+public:
+  dir_cache () : max_entries (0), num_entries (0), entry (NULL) {}
+  ~dir_cache ()
   {
-    int what;
-    int ret;
-    PVOID in;
-    PVOID out;
-    DWORD outsize;
-    HANDLE sem;
-  };
-
-struct net_hdls
+    while (num_entries > 0)
+      free (entry[--num_entries]);
+    free (entry);
+  }
+  void add (wchar_t *str)
   {
-    HANDLE net;
-    HANDLE dom;
-  };
+    if (num_entries >= max_entries)
+      {
+	wchar_t **newentry;
 
-static void
-wnet_dbg_out (const char *func, DWORD ndi_ret)
+	newentry = (wchar_t **) realloc (entry, (max_entries + 10)
+						* sizeof (wchar_t *));
+	if (!newentry)
+	  return;
+	entry = newentry;
+	max_entries += 10;
+      }
+    entry[num_entries] = wcsdup (str);
+    if (entry[num_entries])
+      {
+	wchar_t *p = entry[num_entries];
+	while ((*p = towlower (*p)))
+	  ++p;
+	++num_entries;
+      }
+  }
+  inline wchar_t *operator [](size_t idx) const
+  {
+    if (idx < num_entries)
+      return entry[idx];
+    return NULL;
+  }
+};
+
+#define DIR_cache	(*reinterpret_cast<dir_cache *> (dir->__handle))
+
+struct netdriveinf
 {
-  DWORD gle_ret;
-  DWORD error;
-  WCHAR errorbuf[MAX_PATH];
-  WCHAR namebuf[MAX_PATH];
+  DIR *dir;
+  int err;
+  bool test_only;
+  HANDLE sem;
+};
 
-  if (ndi_ret != ERROR_EXTENDED_ERROR)
-    {
-      debug_printf ("%s failed: %u", func, ndi_ret);
-      return;
-    }
-  gle_ret = WNetGetLastErrorW (&error, errorbuf, MAX_PATH, namebuf, MAX_PATH);
-  if (gle_ret == NO_ERROR)
-    debug_printf ("%s failed: %u --> %u from '%W': '%W'",
-		  func, ndi_ret, error, namebuf, errorbuf);
-  else
-    debug_printf ("WNetGetLastError failed: %u", gle_ret);
+static inline int
+hresult_to_errno (HRESULT wres, bool test_only = false)
+{
+  if (SUCCEEDED (wres))
+    return 0;
+  /* IEnumShellItems::Reset returns E_NOTIMPL when called for share
+     enumeration.  However, if the machine doesn't exist, the Win32
+     error ERROR_BAD_NETPATH (converted into a HRESULT) is returned.  In
+     test_only mode, we exploit this.  Also, E_ACCESSDENIED is a funny
+     one.  It means, the machine exists, you just have no right to
+     access the share list, or SMB doesn't run. */
+  if (test_only && (wres == E_NOTIMPL || wres == E_ACCESSDENIED))
+    return 0;
+  if (((ULONG) wres & 0xffff0000)
+      == (ULONG) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, 0))
+    return geterrno_from_win_error ((ULONG) wres & 0xffff);
+  return EACCES;
 }
 
 static DWORD
 thread_netdrive (void *arg)
 {
   netdriveinf *ndi = (netdriveinf *) arg;
-  WCHAR provider[256], *dummy = NULL;
-  LPNETRESOURCEW nro;
-  DWORD cnt, size;
-  struct net_hdls *nh;
-  tmp_pathbuf tp;
+  DIR *dir = ndi->dir;
+  IEnumShellItems *netitem_enum;
+  IShellItem *netparent;
+  HRESULT wres;
 
   ReleaseSemaphore (ndi->sem, 1, NULL);
-  switch (ndi->what)
+
+  size_t len = strlen (dir->__d_dirname);
+  wres = CoInitialize (NULL);
+  if (FAILED (wres))
     {
-    case GET_RESOURCE_OPENENUMTOP:
-      nro = (LPNETRESOURCEW) tp.c_get ();
-      nh = (struct net_hdls *) ndi->out;
-      ndi->ret = WNetGetProviderNameW (WNNC_NET_LANMAN, provider,
-				       (size = 256, &size));
-      if (ndi->ret != NO_ERROR)
-	{
-	  wnet_dbg_out ("WNetGetProviderNameW", ndi->ret);
-	  break;
-	}
-      memset (nro, 0, sizeof *nro);
-      nro->dwScope = RESOURCE_GLOBALNET;
-      nro->dwType = RESOURCETYPE_ANY;
-      nro->dwDisplayType = RESOURCEDISPLAYTYPE_GROUP;
-      nro->dwUsage = RESOURCEUSAGE_RESERVED | RESOURCEUSAGE_CONTAINER;
-      nro->lpRemoteName = provider;
-      nro->lpProvider = provider;
-      ndi->ret = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-				RESOURCEUSAGE_ALL, nro, &nh->net);
-      if (ndi->ret != NO_ERROR)
-	{
-	  wnet_dbg_out ("WNetOpenEnumW", ndi->ret);
-	  break;
-	}
-      while ((ndi->ret = WNetEnumResourceW (nh->net, (cnt = 1, &cnt), nro,
-					    (size = NT_MAX_PATH, &size)))
-	     == NO_ERROR)
-	{
-	  ndi->ret = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-				    RESOURCEUSAGE_ALL, nro, &nh->dom);
-	  if (ndi->ret == NO_ERROR)
-	    break;
-	}
-      break;
-    case GET_RESOURCE_OPENENUM:
-      nro = (LPNETRESOURCEW) tp.c_get ();
-      nh = (struct net_hdls *) ndi->out;
-      ndi->ret = WNetGetProviderNameW (WNNC_NET_LANMAN, provider,
-				      (size = 256, &size));
-      if (ndi->ret != NO_ERROR)
+      ndi->err = hresult_to_errno (wres);
+      goto out;
+    }
+
+  if (len == 2) /* // */
+    {
+      wres = SHGetKnownFolderItem (FOLDERID_NetworkFolder, KF_FLAG_DEFAULT,
+				   NULL, IID_PPV_ARGS (&netparent));
+      if (FAILED (wres))
 	{
-	  wnet_dbg_out ("WNetGetProviderNameW", ndi->ret);
-	  break;
+	  ndi->err = hresult_to_errno (wres);
+	  goto out;
 	}
-      ((LPNETRESOURCEW) ndi->in)->lpProvider = provider;
-      ndi->ret = WNetGetResourceInformationW ((LPNETRESOURCEW) ndi->in, nro,
-					      (size = NT_MAX_PATH, &size),
-					      &dummy);
-      if (ndi->ret != NO_ERROR)
+
+    }
+  else
+    {
+      wchar_t name[CYG_MAX_PATH];
+
+      sys_mbstowcs (name, CYG_MAX_PATH, dir->__d_dirname);
+      name[0] = L'\\';
+      name[1] = L'\\';
+      wres = SHCreateItemFromParsingName (name, NULL,
+					  IID_PPV_ARGS (&netparent));
+      if (FAILED (wres))
 	{
-	  wnet_dbg_out ("WNetGetResourceInformationW", ndi->ret);
-	  break;
+	  ndi->err = hresult_to_errno (wres);
+	  goto out;
 	}
-      ndi->ret = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-				RESOURCEUSAGE_ALL, nro, &nh->dom);
-      break;
-    case GET_RESOURCE_ENUM:
-      nh = (struct net_hdls *) ndi->in;
-      if (!nh->dom)
+
+    }
+
+  wres = netparent->BindToHandler (NULL, len == 2 ? BHID_StorageEnum
+						  : BHID_EnumItems,
+				   IID_PPV_ARGS (&netitem_enum));
+  if (FAILED (wres))
+    {
+      ndi->err = hresult_to_errno (wres);
+      netparent->Release ();
+      goto out;
+    }
+
+  if (len == 2 || ndi->test_only)
+    {
+      wres = netitem_enum->Reset ();
+
+      if (FAILED (wres) || ndi->test_only)
 	{
-	  ndi->ret = ERROR_NO_MORE_ITEMS;
-	  break;
+	  ndi->err = hresult_to_errno (wres, ndi->test_only);
+	  netitem_enum->Release ();
+	  netparent->Release ();
+	  goto out;
 	}
-      nro = (LPNETRESOURCEW) tp.c_get ();
-      while ((ndi->ret = WNetEnumResourceW (nh->dom, (cnt = 1, &cnt),
-					    (LPNETRESOURCEW) ndi->out,
-					    &ndi->outsize)) != NO_ERROR
-	     && nh->net)
+
+      /* Don't look at me!
+
+	 Network discovery is very unreliable and the list of machines
+	 returned is just fly-by-night, if the enumerator doesn't have
+	 enough time.  The fact that you see *most* (but not necessarily
+	 *all*) machines on the network in Windows Explorer is a result of
+	 the enumeration running in a loop.  You can observe this when
+	 rebooting a remote machine and it disappears and reappears in the
+	 Explorer Network list.
+
+	 However, this is no option for the command line. We need to be able
+	 to enumerate in a single go, since we can't just linger during
+	 readdir() and reset the enumeration multiple times until we have a
+	 supposedly full list.
+
+	 This makes the following Sleep necessary.  Sleeping ~3secs after
+	 Reset fills the enumeration with high probability with almost all
+	 available machines. */
+      Sleep (3000L);
+    }
+
+  dir->__handle = (char *) new dir_cache ();
+
+  do
+    {
+      IShellItem *netitem[10] = { 0 };
+      LPWSTR item_name = NULL;
+      ULONG count;
+
+      wres = netitem_enum->Next (10, netitem, &count);
+      if (SUCCEEDED (wres) && count > 0)
 	{
-	  WNetCloseEnum (nh->dom);
-	  nh->dom = NULL;
-	  while ((ndi->ret = WNetEnumResourceW (nh->net, (cnt = 1, &cnt), nro,
-						(size = NT_MAX_PATH, &size)))
-		 == NO_ERROR)
+	  for (ULONG idx = 0; idx < count; ++idx)
 	    {
-	      ndi->ret = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-					RESOURCEUSAGE_ALL, nro, &nh->dom);
-	      if (ndi->ret == NO_ERROR)
-		break;
+	      if (netitem[idx]->GetDisplayName (SIGDN_PARENTRELATIVEPARSING,
+						&item_name) == S_OK)
+		{
+		  DIR_cache.add (item_name);
+		  CoTaskMemFree (item_name);
+		}
+	      netitem[idx]->Release ();
 	    }
-	  if (ndi->ret != NO_ERROR)
-	    break;
 	}
-      break;
     }
+  while (wres == S_OK);
+
+  netitem_enum->Release ();
+  netparent->Release ();
+
+  ndi->err = 0;
+
+out:
+  CoUninitialize ();
   ReleaseSemaphore (ndi->sem, 1, NULL);
   return 0;
 }
 
 static DWORD
-create_thread_and_wait (int what, PVOID in, PVOID out, DWORD outsize,
-			const char *name)
+create_thread_and_wait (DIR *dir, bool test_only)
 {
-  netdriveinf ndi = { what, 0, in, out, outsize,
+  netdriveinf ndi = { dir, 0, test_only,
 		      CreateSemaphore (&sec_none_nih, 0, 2, NULL) };
-  cygthread *thr = new cygthread (thread_netdrive, &ndi, name);
+
+  cygthread *thr = new cygthread (thread_netdrive, &ndi, "netdrive");
   if (thr->detach (ndi.sem))
-    ndi.ret = ERROR_OPERATION_ABORTED;
+    ndi.err = EINTR;
   CloseHandle (ndi.sem);
-  return ndi.ret;
+  return ndi.err;
 }
 
 virtual_ftype_t
 fhandler_netdrive::exists ()
 {
-  char *to;
-  const char *from;
-  size_t len = strlen (get_name ());
-  if (len == 2)
+  if (strlen (get_name ()) == 2)
     return virt_rootdir;
 
-  char namebuf[len + 1];
-  tmp_pathbuf tp;
-  PWCHAR name = tp.w_get ();
-
-  for (to = namebuf, from = get_name (); *from; to++, from++)
-    *to = (*from == '/') ? '\\' : *from;
-  *to = '\0';
-
-  struct net_hdls nh =  { NULL, NULL };
-  NETRESOURCEW nr = {0};
-  nr.dwType = RESOURCETYPE_DISK;
-  sys_mbstowcs (name, NT_MAX_PATH, namebuf);
-  nr.lpRemoteName = name;
-  DWORD ret = create_thread_and_wait (GET_RESOURCE_OPENENUM,
-				      &nr, &nh, 0, "WNetOpenEnum");
-  if (nh.dom)
-    WNetCloseEnum (nh.dom);
-  return ret != NO_ERROR ? virt_none : virt_directory;
+  DIR dir = { 0 };
+  dir.__d_dirname = (char *) get_name ();
+  int ret = create_thread_and_wait (&dir, true);
+
+  return ret ? virt_none : virt_directory;
 }
 
 fhandler_netdrive::fhandler_netdrive ():
@@ -226,87 +288,67 @@ fhandler_netdrive::fstat (struct stat *buf)
   return 0;
 }
 
+DIR *
+fhandler_netdrive::opendir (int fd)
+{
+  DIR *dir;
+  int ret;
+
+  dir = fhandler_virtual::opendir (fd);
+  if (dir && (ret = create_thread_and_wait (dir, false)))
+    {
+      free (dir->__d_dirname);
+      free (dir->__d_dirent);
+      free (dir);
+      dir = NULL;
+      set_errno (ret);
+      syscall_printf ("%p = opendir (%s)", dir, get_name ());
+    }
+  return dir;
+}
+
 int
 fhandler_netdrive::readdir (DIR *dir, dirent *de)
 {
-  NETRESOURCEW *nro;
-  DWORD ret;
-  int res;
-  tmp_pathbuf tp;
+  int ret;
 
-  if (!dir->__d_position)
+  if (!DIR_cache[dir->__d_position])
     {
-      size_t len = strlen (get_name ());
-      PWCHAR name = NULL;
-      NETRESOURCEW nr = { 0 };
-      struct net_hdls *nh;
+      ret = ENMFILE;
+      goto out;
+    }
 
-      if (len != 2)	/* // */
-	{
-	  const char *from;
-	  char *to;
-	  char *namebuf = (char *) alloca (len + 1);
-	  for (to = namebuf, from = get_name (); *from; to++, from++)
-	    *to = (*from == '/') ? '\\' : *from;
-	  *to = '\0';
-	  name = tp.w_get ();
-	  sys_mbstowcs (name, NT_MAX_PATH, namebuf);
-	}
-      nr.lpRemoteName = name;
-      nr.dwType = RESOURCETYPE_DISK;
-      nh = (struct net_hdls *) ccalloc (HEAP_FHANDLER, 1, sizeof *nh);
-      ret = create_thread_and_wait (len == 2 ? GET_RESOURCE_OPENENUMTOP
-					     : GET_RESOURCE_OPENENUM,
-				    &nr, nh, 0, "WNetOpenEnum");
-      if (ret != NO_ERROR)
-	{
-	  dir->__handle = INVALID_HANDLE_VALUE;
-	  res = geterrno_from_win_error (ret);
-	  goto out;
-	}
-      dir->__handle = (HANDLE) nh;
+  if (strlen (dir->__d_dirname) == 2)
+    {
+      sys_wcstombs (de->d_name, sizeof de->d_name,
+		    DIR_cache[dir->__d_position] + 2);
+      de->d_ino = hash_path_name (get_ino (), de->d_name);
     }
-  nro = (LPNETRESOURCEW) tp.c_get ();
-  ret = create_thread_and_wait (GET_RESOURCE_ENUM, dir->__handle, nro,
-				NT_MAX_PATH, "WnetEnumResource");
-  if (ret != NO_ERROR)
-    res = geterrno_from_win_error (ret);
   else
     {
-      dir->__d_position++;
-      PWCHAR bs = wcsrchr (nro->lpRemoteName, L'\\');
-      bs = bs ? bs + 1 : nro->lpRemoteName;
-      if (strlen (get_name ()) == 2)
-	{
-	  UNICODE_STRING ss, ds;
-
-	  tp.u_get (&ds);
-	  RtlInitUnicodeString (&ss, bs);
-	  RtlDowncaseUnicodeString (&ds, &ss, FALSE);
-	  sys_wcstombs (de->d_name, sizeof de->d_name,
-			ds.Buffer, ds.Length / sizeof (WCHAR));
-	  de->d_ino = hash_path_name (get_ino (), de->d_name);
-	}
-      else
-	{
-	  sys_wcstombs (de->d_name, sizeof de->d_name, bs);
-	  char *rpath = tp.c_get ();
-	  sys_wcstombs (rpath, NT_MAX_PATH, nro->lpRemoteName);
-	  de->d_ino = readdir_get_ino (rpath, false);
-	}
-      de->d_type = DT_DIR;
+      char full[2 * CYG_MAX_PATH];
+      char *s;
 
-      res = 0;
+      sys_wcstombs (de->d_name, sizeof de->d_name,
+		    DIR_cache[dir->__d_position]);
+      s = stpcpy (full, dir->__d_dirname);
+      *s++ = '/';
+      stpcpy (s, de->d_name);
+      de->d_ino = readdir_get_ino (full, false);
     }
+  dir->__d_position++;
+  de->d_type = DT_DIR;
+  ret = 0;
+
 out:
-  syscall_printf ("%d = readdir(%p, %p)", res, dir, de);
-  return res;
+  syscall_printf ("%d = readdir(%p, %p)", ret, dir, de);
+  return ret;
 }
 
 void
 fhandler_netdrive::seekdir (DIR *dir, long pos)
 {
-  rewinddir (dir);
+  ::rewinddir (dir);
   if (pos < 0)
     return;
   while (dir->__d_position < pos)
@@ -317,23 +359,14 @@ fhandler_netdrive::seekdir (DIR *dir, long pos)
 void
 fhandler_netdrive::rewinddir (DIR *dir)
 {
-  if (dir->__handle != INVALID_HANDLE_VALUE)
-    {
-      struct net_hdls *nh = (struct net_hdls *) dir->__handle;
-      if (nh->dom)
-	WNetCloseEnum (nh->dom);
-      if (nh->net)
-	WNetCloseEnum (nh->net);
-      cfree (nh);
-    }
-  dir->__handle = INVALID_HANDLE_VALUE;
-  return fhandler_virtual::rewinddir (dir);
+  dir->__d_position = 0;
 }
 
 int
 fhandler_netdrive::closedir (DIR *dir)
 {
-  rewinddir (dir);
+  if (dir->__handle != INVALID_HANDLE_VALUE)
+    delete &DIR_cache;
   return fhandler_virtual::closedir (dir);
 }
 
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index d9e0a011b88c..bd684a6ea7f3 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -3079,6 +3079,7 @@ class fhandler_netdrive: public fhandler_virtual
  public:
   fhandler_netdrive ();
   virtual_ftype_t exists();
+  DIR *opendir (int);
   int readdir (DIR *, dirent *);
   void seekdir (DIR *, long);
   void rewinddir (DIR *);
diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0
index 8d9e483803e0..fee186e69b20 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -21,3 +21,7 @@ What changed:
   executable.
 
 - Drop support for NT4 and Samba < 3.0.
+
+- Now that SMBv1 is ultimately deprecated and not installed by default
+  on latest Windows versions, enumerating network servers in // and shares
+  via //machine is now using Network Discovery just like Windows Explorer.

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

only message in thread, other threads:[~2024-03-20 13:49 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-20 13:49 [newlib-cygwin/main] Cygwin: // and //server: switch to Network Discovery 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).