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