From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 7AF223858410; Wed, 20 Mar 2024 13:49:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7AF223858410 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1710942597; bh=NeaD/cu+1TH+RR9kGuSLbjHPbRyEOjMYE8/mpcJNQmA=; h=From:To:Subject:Date:From; b=COO+hj3gq0f5w3tic5TnusifD9OQMc82IdKoYfJdfckOpsOJMA83bV4BWCjSnhGQh RMb1TluXoselRRZmXKOC7zLabQKV3wgEA19Y0FTShRUxB/wCJsecPpRu1fAPl36mj+ J2s5Bsx7a9qAuEsPFF5wcxIexgK1uUcxUy89Mfbg= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin/main] Cygwin: // and //server: switch to Network Discovery X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/main X-Git-Oldrev: 80f722e97cf79b6ce64b2d665e059c5b7e15d416 X-Git-Newrev: 205190a80bd0b50b8b34768fe298411d6bde2e25 Message-Id: <20240320134957.7AF223858410@sourceware.org> Date: Wed, 20 Mar 2024 13:49:57 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D205190a80bd= 0b50b8b34768fe298411d6bde2e25 commit 205190a80bd0b50b8b34768fe298411d6bde2e25 Author: Corinna Vinschen AuthorDate: Wed Mar 20 14:32:49 2024 +0100 Commit: Corinna Vinschen CommitDate: Wed Mar 20 14:46:49 2024 +0100 Cygwin: // and //server: switch to Network Discovery =20 SMBv1 is ultimately deprecated since Novemer 2023. It's also not installed by default on latest Windows versions. =20 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. =20 Signed-off-by: Corinna Vinschen 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) =20 -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) =20 +LoadDLLfunc (CoInitialize, ole32) +LoadDLLfunc (CoUninitialize, ole32) LoadDLLfunc (CoTaskMemFree, ole32) =20 LoadDLLfunc (LsaConnectUntrusted, secur32) @@ -531,7 +526,9 @@ LoadDLLfunc (LsaLookupAuthenticationPackage, secur32) LoadDLLfunc (LsaRegisterLogonProcess, secur32) LoadDLLfunc (TranslateNameW, secur32) =20 +LoadDLLfunc (SHCreateItemFromParsingName, shell32) LoadDLLfunc (SHGetDesktopFolder, shell32) +LoadDLLfunc (SHGetKnownFolderItem, shell32) =20 LoadDLLfunc (CreateFontW, gdi32) LoadDLLfunc (DeleteObject, gdi32) diff --git a/winsup/cygwin/fhandler/netdrive.cc b/winsup/cygwin/fhandler/ne= tdrive.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" f= or details. */ =20 #include "winsup.h" -#include #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" =20 +#include +#include +#include + +#include #include +#include =20 -enum - { - GET_RESOURCE_OPENENUM =3D 1, - GET_RESOURCE_OPENENUMTOP =3D 2, - GET_RESOURCE_ENUM =3D 3 - }; +/* SMBv1 is deprectated and not even installed by default anymore on + Windows 10 and 11 machines or their servers. =20 -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 =3D { + 0xd20beec4, 0x5ca8, 0x4905, + { 0xae, 0x3b, 0xbf, 0x25, 0x1e, 0xa0, 0x9b, 0x53 } +}; + +const GUID BHID_StorageEnum =3D { + 0x4621a4e3, 0xf0d6, 0x4773, + { 0x8a, 0x9c, 0x46, 0xe7, 0x7b, 0x17, 0x48, 0x40 } +}; + +const GUID BHID_EnumItems =3D { + 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 >=3D max_entries) + { + wchar_t **newentry; =20 -static void -wnet_dbg_out (const char *func, DWORD ndi_ret) + newentry =3D (wchar_t **) realloc (entry, (max_entries + 10) + * sizeof (wchar_t *)); + if (!newentry) + return; + entry =3D newentry; + max_entries +=3D 10; + } + entry[num_entries] =3D wcsdup (str); + if (entry[num_entries]) + { + wchar_t *p =3D entry[num_entries]; + while ((*p =3D 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->__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; +}; =20 - if (ndi_ret !=3D ERROR_EXTENDED_ERROR) - { - debug_printf ("%s failed: %u", func, ndi_ret); - return; - } - gle_ret =3D WNetGetLastErrorW (&error, errorbuf, MAX_PATH, namebuf, MAX_= PATH); - if (gle_ret =3D=3D 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 =3D 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 =3D=3D E_NOTIMPL || wres =3D=3D E_ACCESSDENIED)) + return 0; + if (((ULONG) wres & 0xffff0000) + =3D=3D (ULONG) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, 0)) + return geterrno_from_win_error ((ULONG) wres & 0xffff); + return EACCES; } =20 static DWORD thread_netdrive (void *arg) { netdriveinf *ndi =3D (netdriveinf *) arg; - WCHAR provider[256], *dummy =3D NULL; - LPNETRESOURCEW nro; - DWORD cnt, size; - struct net_hdls *nh; - tmp_pathbuf tp; + DIR *dir =3D ndi->dir; + IEnumShellItems *netitem_enum; + IShellItem *netparent; + HRESULT wres; =20 ReleaseSemaphore (ndi->sem, 1, NULL); - switch (ndi->what) + + size_t len =3D strlen (dir->__d_dirname); + wres =3D CoInitialize (NULL); + if (FAILED (wres)) { - case GET_RESOURCE_OPENENUMTOP: - nro =3D (LPNETRESOURCEW) tp.c_get (); - nh =3D (struct net_hdls *) ndi->out; - ndi->ret =3D WNetGetProviderNameW (WNNC_NET_LANMAN, provider, - (size =3D 256, &size)); - if (ndi->ret !=3D NO_ERROR) - { - wnet_dbg_out ("WNetGetProviderNameW", ndi->ret); - break; - } - memset (nro, 0, sizeof *nro); - nro->dwScope =3D RESOURCE_GLOBALNET; - nro->dwType =3D RESOURCETYPE_ANY; - nro->dwDisplayType =3D RESOURCEDISPLAYTYPE_GROUP; - nro->dwUsage =3D RESOURCEUSAGE_RESERVED | RESOURCEUSAGE_CONTAINER; - nro->lpRemoteName =3D provider; - nro->lpProvider =3D provider; - ndi->ret =3D WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, - RESOURCEUSAGE_ALL, nro, &nh->net); - if (ndi->ret !=3D NO_ERROR) - { - wnet_dbg_out ("WNetOpenEnumW", ndi->ret); - break; - } - while ((ndi->ret =3D WNetEnumResourceW (nh->net, (cnt =3D 1, &cnt), = nro, - (size =3D NT_MAX_PATH, &size))) - =3D=3D NO_ERROR) - { - ndi->ret =3D WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, - RESOURCEUSAGE_ALL, nro, &nh->dom); - if (ndi->ret =3D=3D NO_ERROR) - break; - } - break; - case GET_RESOURCE_OPENENUM: - nro =3D (LPNETRESOURCEW) tp.c_get (); - nh =3D (struct net_hdls *) ndi->out; - ndi->ret =3D WNetGetProviderNameW (WNNC_NET_LANMAN, provider, - (size =3D 256, &size)); - if (ndi->ret !=3D NO_ERROR) + ndi->err =3D hresult_to_errno (wres); + goto out; + } + + if (len =3D=3D 2) /* // */ + { + wres =3D SHGetKnownFolderItem (FOLDERID_NetworkFolder, KF_FLAG_DEFAU= LT, + NULL, IID_PPV_ARGS (&netparent)); + if (FAILED (wres)) { - wnet_dbg_out ("WNetGetProviderNameW", ndi->ret); - break; + ndi->err =3D hresult_to_errno (wres); + goto out; } - ((LPNETRESOURCEW) ndi->in)->lpProvider =3D provider; - ndi->ret =3D WNetGetResourceInformationW ((LPNETRESOURCEW) ndi->in, = nro, - (size =3D NT_MAX_PATH, &size), - &dummy); - if (ndi->ret !=3D NO_ERROR) + + } + else + { + wchar_t name[CYG_MAX_PATH]; + + sys_mbstowcs (name, CYG_MAX_PATH, dir->__d_dirname); + name[0] =3D L'\\'; + name[1] =3D L'\\'; + wres =3D SHCreateItemFromParsingName (name, NULL, + IID_PPV_ARGS (&netparent)); + if (FAILED (wres)) { - wnet_dbg_out ("WNetGetResourceInformationW", ndi->ret); - break; + ndi->err =3D hresult_to_errno (wres); + goto out; } - ndi->ret =3D WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, - RESOURCEUSAGE_ALL, nro, &nh->dom); - break; - case GET_RESOURCE_ENUM: - nh =3D (struct net_hdls *) ndi->in; - if (!nh->dom) + + } + + wres =3D netparent->BindToHandler (NULL, len =3D=3D 2 ? BHID_StorageEnum + : BHID_EnumItems, + IID_PPV_ARGS (&netitem_enum)); + if (FAILED (wres)) + { + ndi->err =3D hresult_to_errno (wres); + netparent->Release (); + goto out; + } + + if (len =3D=3D 2 || ndi->test_only) + { + wres =3D netitem_enum->Reset (); + + if (FAILED (wres) || ndi->test_only) { - ndi->ret =3D ERROR_NO_MORE_ITEMS; - break; + ndi->err =3D hresult_to_errno (wres, ndi->test_only); + netitem_enum->Release (); + netparent->Release (); + goto out; } - nro =3D (LPNETRESOURCEW) tp.c_get (); - while ((ndi->ret =3D WNetEnumResourceW (nh->dom, (cnt =3D 1, &cnt), - (LPNETRESOURCEW) ndi->out, - &ndi->outsize)) !=3D 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 =3D (char *) new dir_cache (); + + do + { + IShellItem *netitem[10] =3D { 0 }; + LPWSTR item_name =3D NULL; + ULONG count; + + wres =3D netitem_enum->Next (10, netitem, &count); + if (SUCCEEDED (wres) && count > 0) { - WNetCloseEnum (nh->dom); - nh->dom =3D NULL; - while ((ndi->ret =3D WNetEnumResourceW (nh->net, (cnt =3D 1, &cnt), nro, - (size =3D NT_MAX_PATH, &size))) - =3D=3D NO_ERROR) + for (ULONG idx =3D 0; idx < count; ++idx) { - ndi->ret =3D WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, - RESOURCEUSAGE_ALL, nro, &nh->dom); - if (ndi->ret =3D=3D NO_ERROR) - break; + if (netitem[idx]->GetDisplayName (SIGDN_PARENTRELATIVEPARSING, + &item_name) =3D=3D S_OK) + { + DIR_cache.add (item_name); + CoTaskMemFree (item_name); + } + netitem[idx]->Release (); } - if (ndi->ret !=3D NO_ERROR) - break; } - break; } + while (wres =3D=3D S_OK); + + netitem_enum->Release (); + netparent->Release (); + + ndi->err =3D 0; + +out: + CoUninitialize (); ReleaseSemaphore (ndi->sem, 1, NULL); return 0; } =20 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 =3D { what, 0, in, out, outsize, + netdriveinf ndi =3D { dir, 0, test_only, CreateSemaphore (&sec_none_nih, 0, 2, NULL) }; - cygthread *thr =3D new cygthread (thread_netdrive, &ndi, name); + + cygthread *thr =3D new cygthread (thread_netdrive, &ndi, "netdrive"); if (thr->detach (ndi.sem)) - ndi.ret =3D ERROR_OPERATION_ABORTED; + ndi.err =3D EINTR; CloseHandle (ndi.sem); - return ndi.ret; + return ndi.err; } =20 virtual_ftype_t fhandler_netdrive::exists () { - char *to; - const char *from; - size_t len =3D strlen (get_name ()); - if (len =3D=3D 2) + if (strlen (get_name ()) =3D=3D 2) return virt_rootdir; =20 - char namebuf[len + 1]; - tmp_pathbuf tp; - PWCHAR name =3D tp.w_get (); - - for (to =3D namebuf, from =3D get_name (); *from; to++, from++) - *to =3D (*from =3D=3D '/') ? '\\' : *from; - *to =3D '\0'; - - struct net_hdls nh =3D { NULL, NULL }; - NETRESOURCEW nr =3D {0}; - nr.dwType =3D RESOURCETYPE_DISK; - sys_mbstowcs (name, NT_MAX_PATH, namebuf); - nr.lpRemoteName =3D name; - DWORD ret =3D create_thread_and_wait (GET_RESOURCE_OPENENUM, - &nr, &nh, 0, "WNetOpenEnum"); - if (nh.dom) - WNetCloseEnum (nh.dom); - return ret !=3D NO_ERROR ? virt_none : virt_directory; + DIR dir =3D { 0 }; + dir.__d_dirname =3D (char *) get_name (); + int ret =3D create_thread_and_wait (&dir, true); + + return ret ? virt_none : virt_directory; } =20 fhandler_netdrive::fhandler_netdrive (): @@ -226,87 +288,67 @@ fhandler_netdrive::fstat (struct stat *buf) return 0; } =20 +DIR * +fhandler_netdrive::opendir (int fd) +{ + DIR *dir; + int ret; + + dir =3D fhandler_virtual::opendir (fd); + if (dir && (ret =3D create_thread_and_wait (dir, false))) + { + free (dir->__d_dirname); + free (dir->__d_dirent); + free (dir); + dir =3D NULL; + set_errno (ret); + syscall_printf ("%p =3D 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; =20 - if (!dir->__d_position) + if (!DIR_cache[dir->__d_position]) { - size_t len =3D strlen (get_name ()); - PWCHAR name =3D NULL; - NETRESOURCEW nr =3D { 0 }; - struct net_hdls *nh; + ret =3D ENMFILE; + goto out; + } =20 - if (len !=3D 2) /* // */ - { - const char *from; - char *to; - char *namebuf =3D (char *) alloca (len + 1); - for (to =3D namebuf, from =3D get_name (); *from; to++, from++) - *to =3D (*from =3D=3D '/') ? '\\' : *from; - *to =3D '\0'; - name =3D tp.w_get (); - sys_mbstowcs (name, NT_MAX_PATH, namebuf); - } - nr.lpRemoteName =3D name; - nr.dwType =3D RESOURCETYPE_DISK; - nh =3D (struct net_hdls *) ccalloc (HEAP_FHANDLER, 1, sizeof *nh); - ret =3D create_thread_and_wait (len =3D=3D 2 ? GET_RESOURCE_OPENENUM= TOP - : GET_RESOURCE_OPENENUM, - &nr, nh, 0, "WNetOpenEnum"); - if (ret !=3D NO_ERROR) - { - dir->__handle =3D INVALID_HANDLE_VALUE; - res =3D geterrno_from_win_error (ret); - goto out; - } - dir->__handle =3D (HANDLE) nh; + if (strlen (dir->__d_dirname) =3D=3D 2) + { + sys_wcstombs (de->d_name, sizeof de->d_name, + DIR_cache[dir->__d_position] + 2); + de->d_ino =3D hash_path_name (get_ino (), de->d_name); } - nro =3D (LPNETRESOURCEW) tp.c_get (); - ret =3D create_thread_and_wait (GET_RESOURCE_ENUM, dir->__handle, nro, - NT_MAX_PATH, "WnetEnumResource"); - if (ret !=3D NO_ERROR) - res =3D geterrno_from_win_error (ret); else { - dir->__d_position++; - PWCHAR bs =3D wcsrchr (nro->lpRemoteName, L'\\'); - bs =3D bs ? bs + 1 : nro->lpRemoteName; - if (strlen (get_name ()) =3D=3D 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 =3D hash_path_name (get_ino (), de->d_name); - } - else - { - sys_wcstombs (de->d_name, sizeof de->d_name, bs); - char *rpath =3D tp.c_get (); - sys_wcstombs (rpath, NT_MAX_PATH, nro->lpRemoteName); - de->d_ino =3D readdir_get_ino (rpath, false); - } - de->d_type =3D DT_DIR; + char full[2 * CYG_MAX_PATH]; + char *s; =20 - res =3D 0; + sys_wcstombs (de->d_name, sizeof de->d_name, + DIR_cache[dir->__d_position]); + s =3D stpcpy (full, dir->__d_dirname); + *s++ =3D '/'; + stpcpy (s, de->d_name); + de->d_ino =3D readdir_get_ino (full, false); } + dir->__d_position++; + de->d_type =3D DT_DIR; + ret =3D 0; + out: - syscall_printf ("%d =3D readdir(%p, %p)", res, dir, de); - return res; + syscall_printf ("%d =3D readdir(%p, %p)", ret, dir, de); + return ret; } =20 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 !=3D INVALID_HANDLE_VALUE) - { - struct net_hdls *nh =3D (struct net_hdls *) dir->__handle; - if (nh->dom) - WNetCloseEnum (nh->dom); - if (nh->net) - WNetCloseEnum (nh->net); - cfree (nh); - } - dir->__handle =3D INVALID_HANDLE_VALUE; - return fhandler_virtual::rewinddir (dir); + dir->__d_position =3D 0; } =20 int fhandler_netdrive::closedir (DIR *dir) { - rewinddir (dir); + if (dir->__handle !=3D INVALID_HANDLE_VALUE) + delete &DIR_cache; return fhandler_virtual::closedir (dir); } =20 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. =20 - 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.