#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
#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; 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++;
}
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,".") ){
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;
}
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;
}
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);
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
while(*p1++ != '\\');
#endif
memcpy( (dir->dd_buf)->d_name, p1, lstrlen(p1)+1);
dir->dd_size = 0;
return 0;
}