1 /* fhandler_netdrive.cc: fhandler for // and //MACHINE handling
3 Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
19 #include "cygthread.h"
26 GET_RESOURCE_OPENENUM = 1,
27 GET_RESOURCE_OPENENUMTOP = 2,
48 thread_netdrive (void *arg)
50 netdriveinf *ndi = (netdriveinf *) arg;
51 char provider[256], *dummy = NULL;
56 ReleaseSemaphore (ndi->sem, 1, NULL);
59 case GET_RESOURCE_OPENENUMTOP:
60 nro = (LPNETRESOURCE) alloca (size = 4096);
61 nh = (struct net_hdls *) ndi->out;
62 ndi->ret = WNetGetProviderName (WNNC_NET_LANMAN, provider,
64 if (ndi->ret != NO_ERROR)
66 memset (nro, 0, sizeof *nro);
67 nro->dwScope = RESOURCE_GLOBALNET;
68 nro->dwType = RESOURCETYPE_ANY;
69 nro->dwDisplayType = RESOURCEDISPLAYTYPE_GROUP;
70 nro->dwUsage = RESOURCEUSAGE_RESERVED | RESOURCEUSAGE_CONTAINER;
71 nro->lpRemoteName = provider;
72 nro->lpProvider = provider;
73 ndi->ret = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
74 RESOURCEUSAGE_ALL, nro, &nh->net);
75 if (ndi->ret != NO_ERROR)
77 while ((ndi->ret = WNetEnumResource (nh->net, (cnt = 1, &cnt), nro,
78 (size = 4096, &size))) == NO_ERROR)
80 ndi->ret = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
81 RESOURCEUSAGE_ALL, nro, &nh->dom);
82 if (ndi->ret == NO_ERROR)
86 case GET_RESOURCE_OPENENUM:
87 nro = (LPNETRESOURCE) alloca (size = 4096);
88 nh = (struct net_hdls *) ndi->out;
89 ndi->ret = WNetGetProviderName (WNNC_NET_LANMAN, provider,
91 if (ndi->ret != NO_ERROR)
93 ((LPNETRESOURCE) ndi->in)->lpProvider = provider;
94 ndi->ret = WNetGetResourceInformation ((LPNETRESOURCE) ndi->in,
96 if (ndi->ret != NO_ERROR)
98 ndi->ret = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
99 RESOURCEUSAGE_ALL, nro, &nh->dom);
101 case GET_RESOURCE_ENUM:
102 nh = (struct net_hdls *) ndi->in;
105 ndi->ret = ERROR_NO_MORE_ITEMS;
108 while ((ndi->ret = WNetEnumResource (nh->dom, (cnt = 1, &cnt),
109 (LPNETRESOURCE) ndi->out,
110 &ndi->outsize)) != NO_ERROR
113 WNetCloseEnum (nh->dom);
115 nro = (LPNETRESOURCE) alloca (size = 4096);
116 while ((ndi->ret = WNetEnumResource (nh->net, (cnt = 1, &cnt), nro,
117 (size = 4096, &size))) == NO_ERROR)
119 ndi->ret = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
120 RESOURCEUSAGE_ALL, nro, &nh->dom);
121 if (ndi->ret == NO_ERROR)
124 if (ndi->ret != NO_ERROR)
129 ReleaseSemaphore (ndi->sem, 1, NULL);
134 create_thread_and_wait (int what, PVOID in, PVOID out, DWORD outsize,
137 netdriveinf ndi = { what, 0, in, out, outsize,
138 CreateSemaphore (&sec_none_nih, 0, 2, NULL) };
139 cygthread *thr = new cygthread (thread_netdrive, &ndi, name);
140 if (thr->detach (ndi.sem))
141 ndi.ret = ERROR_OPERATION_ABORTED;
142 CloseHandle (ndi.sem);
146 /* Returns 0 if path doesn't exist, >0 if path is a directory,
147 -1 if path is a file, -2 if it's a symlink. */
149 fhandler_netdrive::exists ()
153 size_t len = strlen (get_name ());
156 char namebuf[len + 1];
157 for (to = namebuf, from = get_name (); *from; to++, from++)
158 *to = (*from == '/') ? '\\' : *from;
161 struct net_hdls nh = { NULL, NULL };
162 NETRESOURCE nr = {0};
163 nr.dwType = RESOURCETYPE_DISK;
164 nr.lpRemoteName = namebuf;
165 DWORD ret = create_thread_and_wait (GET_RESOURCE_OPENENUM,
166 &nr, &nh, 0, "WNetOpenEnum");
168 WNetCloseEnum (nh.dom);
169 return ret != NO_ERROR ? virt_none : virt_directory;
172 fhandler_netdrive::fhandler_netdrive ():
178 fhandler_netdrive::fstat (struct __stat64 *buf)
180 const char *path = get_name ();
181 debug_printf ("fstat (%s)", path);
183 fhandler_base::fstat (buf);
185 buf->st_mode = S_IFDIR | STD_RBITS | STD_XBITS;
186 buf->st_ino = get_ino ();
192 fhandler_netdrive::readdir (DIR *dir, dirent *de)
198 if (!dir->__d_position)
200 size_t len = strlen (get_name ());
201 char *namebuf = NULL;
202 NETRESOURCE nr = { 0 };
205 if (len != 2) /* // */
209 namebuf = (char *) alloca (len + 1);
210 for (to = namebuf, from = get_name (); *from; to++, from++)
211 *to = (*from == '/') ? '\\' : *from;
215 nr.lpRemoteName = namebuf;
216 nr.dwType = RESOURCETYPE_DISK;
217 nh = (struct net_hdls *) ccalloc (HEAP_FHANDLER, 1, sizeof *nh);
218 ret = create_thread_and_wait (len == 2 ? GET_RESOURCE_OPENENUMTOP
219 : GET_RESOURCE_OPENENUM,
220 &nr, nh, 0, "WNetOpenEnum");
223 dir->__handle = INVALID_HANDLE_VALUE;
224 res = geterrno_from_win_error (ret);
227 dir->__handle = (HANDLE) nh;
229 ret = create_thread_and_wait (GET_RESOURCE_ENUM, dir->__handle,
230 nro = (LPNETRESOURCE) alloca (16384),
231 16384, "WnetEnumResource");
233 res = geterrno_from_win_error (ret);
237 char *bs = strrchr (nro->lpRemoteName, '\\');
238 strcpy (de->d_name, bs ? bs + 1 : nro->lpRemoteName);
239 if (strlen (get_name ()) == 2)
242 de->d_ino = hash_path_name (get_ino (), de->d_name);
246 de->d_ino = readdir_get_ino (nro->lpRemoteName, false);
247 /* We can't trust remote inode numbers of only 32 bit. That means,
248 remote NT4 NTFS, as well as shares of Samba version < 3.0. */
249 if (de->d_ino <= UINT_MAX)
250 de->d_ino = hash_path_name (0, nro->lpRemoteName);
257 syscall_printf ("%d = readdir(%p, %p)", res, dir, de);
262 fhandler_netdrive::seekdir (DIR *dir, long pos)
267 while (dir->__d_position < pos)
268 if (readdir (dir, dir->__d_dirent))
273 fhandler_netdrive::rewinddir (DIR *dir)
275 if (dir->__handle != INVALID_HANDLE_VALUE)
277 struct net_hdls *nh = (struct net_hdls *) dir->__handle;
279 WNetCloseEnum (nh->dom);
281 WNetCloseEnum (nh->net);
284 dir->__handle = INVALID_HANDLE_VALUE;
285 return fhandler_virtual::rewinddir (dir);
289 fhandler_netdrive::closedir (DIR *dir)
292 return fhandler_virtual::closedir (dir);
296 fhandler_netdrive::open (int flags, mode_t mode)
298 int res = fhandler_virtual::open (flags, mode);
304 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
310 else if (flags & O_WRONLY)
318 set_flags ((flags & ~O_TEXT) | O_BINARY | O_DIROPEN);
321 syscall_printf ("%d = fhandler_netdrive::open(%p, %d)", res, flags, mode);