1 /* fhandler_netdrive.cc: fhandler for // and //MACHINE handling
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
17 #include "cygthread.h"
24 GET_RESOURCE_OPENENUM
= 1,
25 GET_RESOURCE_OPENENUMTOP
= 2,
46 wnet_dbg_out (const char *func
, DWORD ndi_ret
)
50 WCHAR errorbuf
[MAX_PATH
];
51 WCHAR namebuf
[MAX_PATH
];
53 if (ndi_ret
!= ERROR_EXTENDED_ERROR
)
55 debug_printf ("%s failed: %u", func
, ndi_ret
);
58 gle_ret
= WNetGetLastErrorW (&error
, errorbuf
, MAX_PATH
, namebuf
, MAX_PATH
);
59 if (gle_ret
== NO_ERROR
)
60 debug_printf ("%s failed: %u --> %u from '%W': '%W'",
61 func
, ndi_ret
, error
, namebuf
, errorbuf
);
63 debug_printf ("WNetGetLastError failed: %u", gle_ret
);
67 thread_netdrive (void *arg
)
69 netdriveinf
*ndi
= (netdriveinf
*) arg
;
70 WCHAR provider
[256], *dummy
= NULL
;
76 ReleaseSemaphore (ndi
->sem
, 1, NULL
);
79 case GET_RESOURCE_OPENENUMTOP
:
80 nro
= (LPNETRESOURCEW
) tp
.c_get ();
81 nh
= (struct net_hdls
*) ndi
->out
;
82 ndi
->ret
= WNetGetProviderNameW (WNNC_NET_LANMAN
, provider
,
84 if (ndi
->ret
!= NO_ERROR
)
86 wnet_dbg_out ("WNetGetProviderNameW", ndi
->ret
);
89 memset (nro
, 0, sizeof *nro
);
90 nro
->dwScope
= RESOURCE_GLOBALNET
;
91 nro
->dwType
= RESOURCETYPE_ANY
;
92 nro
->dwDisplayType
= RESOURCEDISPLAYTYPE_GROUP
;
93 nro
->dwUsage
= RESOURCEUSAGE_RESERVED
| RESOURCEUSAGE_CONTAINER
;
94 nro
->lpRemoteName
= provider
;
95 nro
->lpProvider
= provider
;
96 ndi
->ret
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
97 RESOURCEUSAGE_ALL
, nro
, &nh
->net
);
98 if (ndi
->ret
!= NO_ERROR
)
100 wnet_dbg_out ("WNetOpenEnumW", ndi
->ret
);
103 while ((ndi
->ret
= WNetEnumResourceW (nh
->net
, (cnt
= 1, &cnt
), nro
,
104 (size
= NT_MAX_PATH
, &size
)))
107 ndi
->ret
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
108 RESOURCEUSAGE_ALL
, nro
, &nh
->dom
);
109 if (ndi
->ret
== NO_ERROR
)
113 case GET_RESOURCE_OPENENUM
:
114 nro
= (LPNETRESOURCEW
) tp
.c_get ();
115 nh
= (struct net_hdls
*) ndi
->out
;
116 ndi
->ret
= WNetGetProviderNameW (WNNC_NET_LANMAN
, provider
,
117 (size
= 256, &size
));
118 if (ndi
->ret
!= NO_ERROR
)
120 wnet_dbg_out ("WNetGetProviderNameW", ndi
->ret
);
123 ((LPNETRESOURCEW
) ndi
->in
)->lpProvider
= provider
;
124 ndi
->ret
= WNetGetResourceInformationW ((LPNETRESOURCEW
) ndi
->in
, nro
,
125 (size
= NT_MAX_PATH
, &size
),
127 if (ndi
->ret
!= NO_ERROR
)
129 wnet_dbg_out ("WNetGetResourceInformationW", ndi
->ret
);
132 ndi
->ret
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
133 RESOURCEUSAGE_ALL
, nro
, &nh
->dom
);
135 case GET_RESOURCE_ENUM
:
136 nh
= (struct net_hdls
*) ndi
->in
;
139 ndi
->ret
= ERROR_NO_MORE_ITEMS
;
142 nro
= (LPNETRESOURCEW
) tp
.c_get ();
143 while ((ndi
->ret
= WNetEnumResourceW (nh
->dom
, (cnt
= 1, &cnt
),
144 (LPNETRESOURCEW
) ndi
->out
,
145 &ndi
->outsize
)) != NO_ERROR
148 WNetCloseEnum (nh
->dom
);
150 while ((ndi
->ret
= WNetEnumResourceW (nh
->net
, (cnt
= 1, &cnt
), nro
,
151 (size
= NT_MAX_PATH
, &size
)))
154 ndi
->ret
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
155 RESOURCEUSAGE_ALL
, nro
, &nh
->dom
);
156 if (ndi
->ret
== NO_ERROR
)
159 if (ndi
->ret
!= NO_ERROR
)
164 ReleaseSemaphore (ndi
->sem
, 1, NULL
);
169 create_thread_and_wait (int what
, PVOID in
, PVOID out
, DWORD outsize
,
172 netdriveinf ndi
= { what
, 0, in
, out
, outsize
,
173 CreateSemaphore (&sec_none_nih
, 0, 2, NULL
) };
174 cygthread
*thr
= new cygthread (thread_netdrive
, &ndi
, name
);
175 if (thr
->detach (ndi
.sem
))
176 ndi
.ret
= ERROR_OPERATION_ABORTED
;
177 CloseHandle (ndi
.sem
);
182 fhandler_netdrive::exists ()
186 size_t len
= strlen (get_name ());
190 char namebuf
[len
+ 1];
192 PWCHAR name
= tp
.w_get ();
194 for (to
= namebuf
, from
= get_name (); *from
; to
++, from
++)
195 *to
= (*from
== '/') ? '\\' : *from
;
198 struct net_hdls nh
= { NULL
, NULL
};
199 NETRESOURCEW nr
= {0};
200 nr
.dwType
= RESOURCETYPE_DISK
;
201 sys_mbstowcs (name
, NT_MAX_PATH
, namebuf
);
202 nr
.lpRemoteName
= name
;
203 DWORD ret
= create_thread_and_wait (GET_RESOURCE_OPENENUM
,
204 &nr
, &nh
, 0, "WNetOpenEnum");
206 WNetCloseEnum (nh
.dom
);
207 return ret
!= NO_ERROR
? virt_none
: virt_directory
;
210 fhandler_netdrive::fhandler_netdrive ():
216 fhandler_netdrive::fstat (struct stat
*buf
)
218 const char *path
= get_name ();
219 debug_printf ("fstat (%s)", path
);
221 fhandler_base::fstat (buf
);
223 buf
->st_mode
= S_IFDIR
| STD_RBITS
| STD_XBITS
;
224 buf
->st_ino
= get_ino ();
230 fhandler_netdrive::readdir (DIR *dir
, dirent
*de
)
237 if (!dir
->__d_position
)
239 size_t len
= strlen (get_name ());
241 NETRESOURCEW nr
= { 0 };
244 if (len
!= 2) /* // */
248 char *namebuf
= (char *) alloca (len
+ 1);
249 for (to
= namebuf
, from
= get_name (); *from
; to
++, from
++)
250 *to
= (*from
== '/') ? '\\' : *from
;
253 sys_mbstowcs (name
, NT_MAX_PATH
, namebuf
);
255 nr
.lpRemoteName
= name
;
256 nr
.dwType
= RESOURCETYPE_DISK
;
257 nh
= (struct net_hdls
*) ccalloc (HEAP_FHANDLER
, 1, sizeof *nh
);
258 ret
= create_thread_and_wait (len
== 2 ? GET_RESOURCE_OPENENUMTOP
259 : GET_RESOURCE_OPENENUM
,
260 &nr
, nh
, 0, "WNetOpenEnum");
263 dir
->__handle
= INVALID_HANDLE_VALUE
;
264 res
= geterrno_from_win_error (ret
);
267 dir
->__handle
= (HANDLE
) nh
;
269 nro
= (LPNETRESOURCEW
) tp
.c_get ();
270 ret
= create_thread_and_wait (GET_RESOURCE_ENUM
, dir
->__handle
, nro
,
271 NT_MAX_PATH
, "WnetEnumResource");
273 res
= geterrno_from_win_error (ret
);
277 PWCHAR bs
= wcsrchr (nro
->lpRemoteName
, L
'\\');
278 bs
= bs
? bs
+ 1 : nro
->lpRemoteName
;
279 if (strlen (get_name ()) == 2)
281 UNICODE_STRING ss
, ds
;
284 RtlInitUnicodeString (&ss
, bs
);
285 RtlDowncaseUnicodeString (&ds
, &ss
, FALSE
);
286 sys_wcstombs (de
->d_name
, sizeof de
->d_name
,
287 ds
.Buffer
, ds
.Length
/ sizeof (WCHAR
));
288 de
->d_ino
= hash_path_name (get_ino (), de
->d_name
);
292 sys_wcstombs (de
->d_name
, sizeof de
->d_name
, bs
);
293 char *rpath
= tp
.c_get ();
294 sys_wcstombs (rpath
, NT_MAX_PATH
, nro
->lpRemoteName
);
295 de
->d_ino
= readdir_get_ino (rpath
, false);
302 syscall_printf ("%d = readdir(%p, %p)", res
, dir
, de
);
307 fhandler_netdrive::seekdir (DIR *dir
, long pos
)
312 while (dir
->__d_position
< pos
)
313 if (readdir (dir
, dir
->__d_dirent
))
318 fhandler_netdrive::rewinddir (DIR *dir
)
320 if (dir
->__handle
!= INVALID_HANDLE_VALUE
)
322 struct net_hdls
*nh
= (struct net_hdls
*) dir
->__handle
;
324 WNetCloseEnum (nh
->dom
);
326 WNetCloseEnum (nh
->net
);
329 dir
->__handle
= INVALID_HANDLE_VALUE
;
330 return fhandler_virtual::rewinddir (dir
);
334 fhandler_netdrive::closedir (DIR *dir
)
337 return fhandler_virtual::closedir (dir
);
341 fhandler_netdrive::open (int flags
, mode_t mode
)
343 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
348 if (flags
& O_WRONLY
)
353 /* Open a fake handle to \\Device\\Null */
354 return open_null (flags
);
358 fhandler_netdrive::close ()
360 /* Skip fhandler_virtual::close, which is a no-op. */
361 return fhandler_base::close ();