1/*$Header: /p/tcsh/cvsroot/tcsh/win32/dirent.c,v 1.9 2006/04/07 00:57:59 amold Exp $*/
2/*-
3 * Copyright (c) 1980, 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/* dirent.c
32 * directory interface functions. Sort of like dirent functions on unix.
33 * Also allow browsing network shares as if they were directories
34 *
35 * -amol
36 *
37 */
38#define WIN32_LEAN_AND_MEAN
39#include <stdio.h>
40#include <errno.h>
41#include <assert.h>
42#include <direct.h>
43#include "dirent.h"
44#include <winnetwk.h>
45
46#ifndef WINDOWS_ONLY
47#define STRSAFE_NO_DEPRECATE
48#endif /* WINDOWS_ONLY*/
49#define STRSAFE_LIB
50#define STRSAFE_NO_CCH_FUNCTIONS
51#include <strsafe.h>
52
53#pragma intrinsic("memset")
54
55static HANDLE open_enum(char *,WIN32_FIND_DATA*);
56static void close_enum(DIR*) ;
57static int enum_next_share(DIR*);
58
59typedef struct _enum_h {
60	unsigned char *netres;
61	HANDLE henum;
62} nethandle_t;
63
64static int inode= 1; // useless piece that some unix programs need
65DIR * opendir(const char *inbuf) {
66
67    DIR *dptr;
68    WIN32_FIND_DATA fdata = {0};
69    char *tmp  = NULL;
70    char *buf = NULL;
71    int is_net=0;
72    int had_error = 0;
73    size_t buflen;
74
75    buflen = lstrlen(inbuf) + 1;
76    buf= (char *)heap_alloc(buflen);
77    (void)StringCbCopy(buf,buflen,inbuf);
78
79    if (!buf)
80	buf = "." ;
81    tmp = buf;
82    while(*tmp) {
83#ifdef DSPMBYTE
84	if (Ismbyte1(*tmp) && *(tmp + 1))
85	    tmp ++;
86	else
87#endif DSPMBYTE
88	    if (*tmp == '\\')
89		*tmp = '/';
90	tmp++;
91    }
92    /*
93     * paths like / confuse NT because it looks like a UNC name
94     * when we append "\*" -amol
95     */
96    if (*(tmp -1) == '/')
97	*(tmp -1) = 0;
98
99    buflen = lstrlen(buf) + 4;
100    tmp= (char *)heap_alloc(buflen);
101
102    if ( (buf[0] == '/') && (buf[1] != '/') ) {
103	(void)StringCbPrintf(tmp,buflen, "%c:%s*",
104			     'A' + (_getdrive()-1),buf);
105    }
106    else if ( (buf[0] == '/')  &&  (buf[1] == '/')  ){
107	is_net = 1;
108	(void)StringCbPrintf(tmp,buflen,"%s",buf);
109    }
110    else {
111	(void)StringCbPrintf(tmp,buflen,"%s/*",buf);
112    }
113
114    dptr = (DIR *)heap_alloc(sizeof(DIR));
115    dptr->dd_fd = INVALID_HANDLE_VALUE;
116    if (!dptr){
117	errno = ENOMEM;
118	had_error =1;
119	goto done;
120    }
121
122    if (is_net){
123	dptr->dd_fd = open_enum(tmp,&fdata);
124	dptr->flags = IS_NET;
125    }
126    if (dptr->dd_fd == INVALID_HANDLE_VALUE){
127	(void)StringCbPrintf(tmp,buflen,"%s/*",buf);
128	dptr->flags = 0;
129	dptr->dd_fd = FindFirstFile(tmp,&fdata);
130    }
131    if (dptr->dd_fd == INVALID_HANDLE_VALUE){
132	if (GetLastError() == ERROR_DIRECTORY)
133	    errno = ENOTDIR;
134	else
135	    errno = ENOENT;
136
137	had_error =1;
138	goto done;
139    }
140    memset(dptr->orig_dir_name,0,sizeof(dptr->orig_dir_name));
141    memcpy(dptr->orig_dir_name,tmp,lstrlen(tmp));
142
143    dptr->dd_loc = 0;
144    dptr->dd_size = fdata.nFileSizeLow;
145    dptr->dd_buf = (struct dirent *)heap_alloc(sizeof(struct dirent));
146    if (!dptr->dd_buf){
147	errno = ENOMEM;
148	had_error=1;
149	goto done;
150    }
151    (dptr->dd_buf)->d_ino = inode++;
152    (dptr->dd_buf)->d_off = 0;
153    (dptr->dd_buf)->d_reclen = 0;
154    if (lstrcmpi(fdata.cFileName,".") ){
155	//dptr->dd_buf->d_name[0] = '.';
156	memcpy((dptr->dd_buf)->d_name,".",2);
157	dptr->flags |= IS_ROOT;
158    }
159    else
160	memcpy((dptr->dd_buf)->d_name,fdata.cFileName,MAX_PATH);
161
162done:
163    if(tmp)
164	heap_free(tmp);
165    if(had_error) {
166	heap_free(dptr);
167	dptr = NULL;
168    }
169
170    return dptr;
171}
172int closedir(DIR *dptr){
173
174	if (!dptr)
175		return 0;
176	if (dptr->flags & IS_NET) {
177		close_enum(dptr);
178	}
179	else
180		FindClose(dptr->dd_fd);
181	heap_free(dptr->dd_buf);
182	heap_free(dptr);
183	return 0;
184}
185void rewinddir(DIR *dptr) {
186
187	HANDLE hfind;
188	WIN32_FIND_DATA fdata;
189	char *tmp = dptr->orig_dir_name;
190
191	if (!dptr) return;
192
193	if (dptr->flags & IS_NET) {
194		hfind = open_enum(tmp,&fdata);
195		close_enum(dptr);
196		dptr->dd_fd = hfind;
197	}
198	else {
199		hfind = FindFirstFile(tmp,&fdata);
200		assert(hfind != INVALID_HANDLE_VALUE);
201		FindClose(dptr->dd_fd);
202		dptr->dd_fd = hfind;
203	}
204	dptr->dd_size = fdata.nFileSizeLow;
205	(dptr->dd_buf)->d_ino = inode++;
206	(dptr->dd_buf)->d_off = 0;
207	(dptr->dd_buf)->d_reclen = 0;
208	memcpy((dptr->dd_buf)->d_name,fdata.cFileName,MAX_PATH);
209	return;
210}
211struct dirent *readdir(DIR *dir) {
212
213	WIN32_FIND_DATA fdata = {0};
214	HANDLE hfind;
215	char *tmp ;
216
217	if (!dir)
218		return NULL;
219
220	if (dir->flags & IS_NET) {
221		if(enum_next_share(dir)<0)
222			return NULL;
223	}
224	// special hack for root (which does not have . or ..)
225	else if (dir->flags & IS_ROOT) {
226		tmp= dir->orig_dir_name;
227		hfind = FindFirstFile(tmp,&fdata);
228		FindClose(dir->dd_fd);
229		dir->dd_fd = hfind;
230		dir->dd_size = fdata.nFileSizeLow;
231		(dir->dd_buf)->d_ino = inode++;
232		(dir->dd_buf)->d_off = 0;
233		(dir->dd_buf)->d_reclen = 0;
234		memcpy((dir->dd_buf)->d_name,fdata.cFileName,MAX_PATH);
235		dir->flags &= ~IS_ROOT;
236		return dir->dd_buf;
237
238	}
239	if(!(dir->flags & IS_NET) && !FindNextFile(dir->dd_fd,&fdata) ){
240		return NULL;
241	}
242	(dir->dd_buf)->d_ino = inode++;
243	(dir->dd_buf)->d_off = 0;
244	(dir->dd_buf)->d_reclen = 0;
245	if (! (dir->flags & IS_NET))
246		memcpy((dir->dd_buf)->d_name,fdata.cFileName,MAX_PATH);
247
248	return dir->dd_buf;
249
250}
251
252// Support for treating share names as directories
253// -amol 5/28/97
254static int ginited = 0;
255static HMODULE hmpr;
256
257typedef DWORD (__stdcall *open_fn)(DWORD,DWORD,DWORD,NETRESOURCE *, HANDLE*);
258typedef DWORD (__stdcall *close_fn)( HANDLE);
259typedef DWORD (__stdcall *enum_fn)( HANDLE,DWORD * ,void *,DWORD*);
260
261
262static open_fn p_WNetOpenEnum;
263static close_fn p_WNetCloseEnum;
264static enum_fn  p_WNetEnumResource;
265
266HANDLE open_enum(char *server, WIN32_FIND_DATA *fdata) {
267
268	NETRESOURCE netres;
269	HANDLE henum;
270	unsigned long ret;
271	char *ptr;
272	int slashes;
273
274	nethandle_t *hnet;
275
276	ptr = server;
277	slashes = 0;
278
279	while(*ptr) {
280		if (*ptr == '/') {
281			*ptr = '\\';
282			slashes++;
283		}
284		ptr++;
285	}
286
287	if (!ginited) {
288		hmpr = LoadLibrary("MPR.DLL");
289		if (!hmpr)
290			return INVALID_HANDLE_VALUE;
291
292		p_WNetOpenEnum = (open_fn)GetProcAddress(hmpr,"WNetOpenEnumA");
293		p_WNetCloseEnum = (close_fn)GetProcAddress(hmpr,"WNetCloseEnum");
294		p_WNetEnumResource = (enum_fn)GetProcAddress(hmpr,"WNetEnumResourceA");
295
296		if (!p_WNetOpenEnum || !p_WNetCloseEnum || !p_WNetEnumResource)
297			return INVALID_HANDLE_VALUE;
298		ginited = 1;
299	}
300	if (slashes > 2)
301		return INVALID_HANDLE_VALUE;
302
303	memset(fdata,0,sizeof(WIN32_FIND_DATA));
304	fdata->cFileName[0] = '.';
305
306	netres.dwScope = RESOURCE_GLOBALNET;
307	netres.dwType = RESOURCETYPE_ANY;
308	netres.lpRemoteName = server;
309	netres.lpProvider = NULL;
310	netres.dwUsage = 0;
311
312	ret = p_WNetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,0,
313							&netres,&henum);
314	if (ret != NO_ERROR)
315		return INVALID_HANDLE_VALUE;
316
317	hnet = heap_alloc(sizeof(nethandle_t));
318	hnet->netres = heap_alloc(1024);/*FIXBUF*/
319	hnet->henum = henum;
320
321
322	return (HANDLE)hnet;
323
324}
325void close_enum(DIR*dptr) {
326	nethandle_t *hnet;
327
328	hnet = (nethandle_t*)(dptr->dd_fd);
329
330	heap_free(hnet->netres);
331	p_WNetCloseEnum(hnet->henum);
332	heap_free(hnet);
333}
334int enum_next_share(DIR *dir) {
335	nethandle_t *hnet;
336	char *tmp,*p1;
337	HANDLE henum;
338	DWORD count, breq,ret;
339
340	hnet = (nethandle_t*)(dir->dd_fd);
341	henum = hnet->henum;
342	count =  1;
343	breq = 1024;
344
345	ret = p_WNetEnumResource(henum, &count,hnet->netres,&breq);
346	if (ret != NO_ERROR)
347		return -1;
348
349	tmp = ((NETRESOURCE*)hnet->netres)->lpRemoteName;
350	p1 = &tmp[2];
351#ifdef DSPMBYTE
352	for (; *p1 != '\\'; p1 ++)
353		if (Ismbyte1(*p1) && *(p1 + 1))
354			p1 ++;
355#else /* DSPMBYTE */
356	while(*p1++ != '\\');
357#endif /* DSPMBYTE */
358
359	memcpy( (dir->dd_buf)->d_name, p1, lstrlen(p1)+1);
360
361	dir->dd_size = 0;
362
363	return 0;
364}
365