diff options
Diffstat (limited to 'win32/dirent.c')
-rw-r--r-- | win32/dirent.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/win32/dirent.c b/win32/dirent.c new file mode 100644 index 0000000000000..bfe7d075c4b1c --- /dev/null +++ b/win32/dirent.c @@ -0,0 +1,364 @@ +/*$Header: /p/tcsh/cvsroot/tcsh/win32/dirent.c,v 1.9 2006/04/07 00:57:59 amold Exp $*/ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* dirent.c + * directory interface functions. Sort of like dirent functions on unix. + * Also allow browsing network shares as if they were directories + * + * -amol + * + */ +#define WIN32_LEAN_AND_MEAN +#include <stdio.h> +#include <errno.h> +#include <assert.h> +#include <direct.h> +#include "dirent.h" +#include <winnetwk.h> + +#ifndef WINDOWS_ONLY +#define STRSAFE_NO_DEPRECATE +#endif /* WINDOWS_ONLY*/ +#define STRSAFE_LIB +#define STRSAFE_NO_CCH_FUNCTIONS +#include <strsafe.h> + +#pragma intrinsic("memset") + +static HANDLE open_enum(char *,WIN32_FIND_DATA*); +static void close_enum(DIR*) ; +static int enum_next_share(DIR*); + +typedef struct _enum_h { + unsigned char *netres; + HANDLE henum; +} nethandle_t; + +static int inode= 1; // useless piece that some unix programs need +DIR * opendir(const char *inbuf) { + + DIR *dptr; + WIN32_FIND_DATA fdata = {0}; + char *tmp = NULL; + char *buf = NULL; + int is_net=0; + int had_error = 0; + size_t buflen; + + buflen = lstrlen(inbuf) + 1; + buf= (char *)heap_alloc(buflen); + (void)StringCbCopy(buf,buflen,inbuf); + + if (!buf) + buf = "." ; + tmp = buf; + while(*tmp) { +#ifdef DSPMBYTE + if (Ismbyte1(*tmp) && *(tmp + 1)) + tmp ++; + else +#endif DSPMBYTE + if (*tmp == '\\') + *tmp = '/'; + tmp++; + } + /* + * paths like / confuse NT because it looks like a UNC name + * when we append "\*" -amol + */ + if (*(tmp -1) == '/') + *(tmp -1) = 0; + + buflen = lstrlen(buf) + 4; + tmp= (char *)heap_alloc(buflen); + + if ( (buf[0] == '/') && (buf[1] != '/') ) { + (void)StringCbPrintf(tmp,buflen, "%c:%s*", + 'A' + (_getdrive()-1),buf); + } + else if ( (buf[0] == '/') && (buf[1] == '/') ){ + is_net = 1; + (void)StringCbPrintf(tmp,buflen,"%s",buf); + } + else { + (void)StringCbPrintf(tmp,buflen,"%s/*",buf); + } + + dptr = (DIR *)heap_alloc(sizeof(DIR)); + dptr->dd_fd = INVALID_HANDLE_VALUE; + if (!dptr){ + errno = ENOMEM; + had_error =1; + goto done; + } + + if (is_net){ + dptr->dd_fd = open_enum(tmp,&fdata); + dptr->flags = IS_NET; + } + if (dptr->dd_fd == INVALID_HANDLE_VALUE){ + (void)StringCbPrintf(tmp,buflen,"%s/*",buf); + dptr->flags = 0; + dptr->dd_fd = FindFirstFile(tmp,&fdata); + } + if (dptr->dd_fd == INVALID_HANDLE_VALUE){ + if (GetLastError() == ERROR_DIRECTORY) + errno = ENOTDIR; + else + errno = ENOENT; + + had_error =1; + goto done; + } + memset(dptr->orig_dir_name,0,sizeof(dptr->orig_dir_name)); + memcpy(dptr->orig_dir_name,tmp,lstrlen(tmp)); + + dptr->dd_loc = 0; + dptr->dd_size = fdata.nFileSizeLow; + dptr->dd_buf = (struct dirent *)heap_alloc(sizeof(struct dirent)); + if (!dptr->dd_buf){ + errno = ENOMEM; + had_error=1; + goto done; + } + (dptr->dd_buf)->d_ino = inode++; + (dptr->dd_buf)->d_off = 0; + (dptr->dd_buf)->d_reclen = 0; + if (lstrcmpi(fdata.cFileName,".") ){ + //dptr->dd_buf->d_name[0] = '.'; + memcpy((dptr->dd_buf)->d_name,".",2); + dptr->flags |= IS_ROOT; + } + else + memcpy((dptr->dd_buf)->d_name,fdata.cFileName,MAX_PATH); + +done: + if(tmp) + heap_free(tmp); + if(had_error) { + heap_free(dptr); + dptr = NULL; + } + + return dptr; +} +int closedir(DIR *dptr){ + + if (!dptr) + return 0; + if (dptr->flags & IS_NET) { + close_enum(dptr); + } + else + FindClose(dptr->dd_fd); + heap_free(dptr->dd_buf); + heap_free(dptr); + return 0; +} +void rewinddir(DIR *dptr) { + + HANDLE hfind; + WIN32_FIND_DATA fdata; + char *tmp = dptr->orig_dir_name; + + if (!dptr) return; + + if (dptr->flags & IS_NET) { + hfind = open_enum(tmp,&fdata); + close_enum(dptr); + dptr->dd_fd = hfind; + } + else { + hfind = FindFirstFile(tmp,&fdata); + assert(hfind != INVALID_HANDLE_VALUE); + FindClose(dptr->dd_fd); + dptr->dd_fd = hfind; + } + dptr->dd_size = fdata.nFileSizeLow; + (dptr->dd_buf)->d_ino = inode++; + (dptr->dd_buf)->d_off = 0; + (dptr->dd_buf)->d_reclen = 0; + memcpy((dptr->dd_buf)->d_name,fdata.cFileName,MAX_PATH); + return; +} +struct dirent *readdir(DIR *dir) { + + WIN32_FIND_DATA fdata = {0}; + HANDLE hfind; + char *tmp ; + + if (!dir) + return NULL; + + if (dir->flags & IS_NET) { + if(enum_next_share(dir)<0) + return NULL; + } + // special hack for root (which does not have . or ..) + else if (dir->flags & IS_ROOT) { + tmp= dir->orig_dir_name; + hfind = FindFirstFile(tmp,&fdata); + FindClose(dir->dd_fd); + dir->dd_fd = hfind; + dir->dd_size = fdata.nFileSizeLow; + (dir->dd_buf)->d_ino = inode++; + (dir->dd_buf)->d_off = 0; + (dir->dd_buf)->d_reclen = 0; + memcpy((dir->dd_buf)->d_name,fdata.cFileName,MAX_PATH); + dir->flags &= ~IS_ROOT; + return dir->dd_buf; + + } + if(!(dir->flags & IS_NET) && !FindNextFile(dir->dd_fd,&fdata) ){ + return NULL; + } + (dir->dd_buf)->d_ino = inode++; + (dir->dd_buf)->d_off = 0; + (dir->dd_buf)->d_reclen = 0; + if (! (dir->flags & IS_NET)) + memcpy((dir->dd_buf)->d_name,fdata.cFileName,MAX_PATH); + + return dir->dd_buf; + +} + +// Support for treating share names as directories +// -amol 5/28/97 +static int ginited = 0; +static HMODULE hmpr; + +typedef DWORD (__stdcall *open_fn)(DWORD,DWORD,DWORD,NETRESOURCE *, HANDLE*); +typedef DWORD (__stdcall *close_fn)( HANDLE); +typedef DWORD (__stdcall *enum_fn)( HANDLE,DWORD * ,void *,DWORD*); + + +static open_fn p_WNetOpenEnum; +static close_fn p_WNetCloseEnum; +static enum_fn p_WNetEnumResource; + +HANDLE open_enum(char *server, WIN32_FIND_DATA *fdata) { + + NETRESOURCE netres; + HANDLE henum; + unsigned long ret; + char *ptr; + int slashes; + + nethandle_t *hnet; + + ptr = server; + slashes = 0; + + while(*ptr) { + if (*ptr == '/') { + *ptr = '\\'; + slashes++; + } + ptr++; + } + + if (!ginited) { + hmpr = LoadLibrary("MPR.DLL"); + if (!hmpr) + return INVALID_HANDLE_VALUE; + + p_WNetOpenEnum = (open_fn)GetProcAddress(hmpr,"WNetOpenEnumA"); + p_WNetCloseEnum = (close_fn)GetProcAddress(hmpr,"WNetCloseEnum"); + p_WNetEnumResource = (enum_fn)GetProcAddress(hmpr,"WNetEnumResourceA"); + + if (!p_WNetOpenEnum || !p_WNetCloseEnum || !p_WNetEnumResource) + return INVALID_HANDLE_VALUE; + ginited = 1; + } + if (slashes > 2) + return INVALID_HANDLE_VALUE; + + memset(fdata,0,sizeof(WIN32_FIND_DATA)); + fdata->cFileName[0] = '.'; + + netres.dwScope = RESOURCE_GLOBALNET; + netres.dwType = RESOURCETYPE_ANY; + netres.lpRemoteName = server; + netres.lpProvider = NULL; + netres.dwUsage = 0; + + ret = p_WNetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,0, + &netres,&henum); + if (ret != NO_ERROR) + return INVALID_HANDLE_VALUE; + + hnet = heap_alloc(sizeof(nethandle_t)); + hnet->netres = heap_alloc(1024);/*FIXBUF*/ + hnet->henum = henum; + + + return (HANDLE)hnet; + +} +void close_enum(DIR*dptr) { + nethandle_t *hnet; + + hnet = (nethandle_t*)(dptr->dd_fd); + + heap_free(hnet->netres); + p_WNetCloseEnum(hnet->henum); + heap_free(hnet); +} +int enum_next_share(DIR *dir) { + nethandle_t *hnet; + char *tmp,*p1; + HANDLE henum; + DWORD count, breq,ret; + + hnet = (nethandle_t*)(dir->dd_fd); + henum = hnet->henum; + count = 1; + breq = 1024; + + ret = p_WNetEnumResource(henum, &count,hnet->netres,&breq); + if (ret != NO_ERROR) + return -1; + + tmp = ((NETRESOURCE*)hnet->netres)->lpRemoteName; + p1 = &tmp[2]; +#ifdef DSPMBYTE + for (; *p1 != '\\'; p1 ++) + if (Ismbyte1(*p1) && *(p1 + 1)) + p1 ++; +#else /* DSPMBYTE */ + while(*p1++ != '\\'); +#endif /* DSPMBYTE */ + + memcpy( (dir->dd_buf)->d_name, p1, lstrlen(p1)+1); + + dir->dd_size = 0; + + return 0; +} |