blob: b57d8ff5528372d9416205a66404d700c6e2a05b [file] [log] [blame] [raw]
#include <dirent.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
static unsigned char attribute_to_dirtype(unsigned long int attrib) {
//fprintf(stderr, "function: attribute_to_dirtype(0x%lx)\n", attrib);
if(attrib & FILE_ATTRIBUTE_DIRECTORY) return DT_DIR;
//if(attrib & FILE_ATTRIBUTE_NORMAL) return DT_REG;
//return DT_UNKNOWN;
return DT_REG;
}
DIR *opendir(const char *path) {
if(!path) {
errno = EFAULT;
return NULL;
}
if(!*path) {
errno = ENOENT;
return NULL;
}
int attrib;
size_t len = strlen(path);
{
wchar_t wpath[len + 1];
mbstowcs(wpath, path, len + 1);
attrib = GetFileAttributesW(wpath);
}
if(attrib == -1) return NULL;
if(!(attrib & FILE_ATTRIBUTE_DIRECTORY)) {
errno = ENOTDIR;
return NULL;
}
DIR *r = malloc(sizeof(DIR) + len + 3);
if(!r) {
errno = ENOMEM;
return NULL;
}
memcpy(r->dd_name, path, len); // No need to copy the '\0'
if(r->dd_name[len - 1] != '/' && r->dd_name[len - 1] != '\\') r->dd_name[len++] = '/';
r->dd_name[len++] = '*';
r->dd_name[len] = 0;
r->dd_handle = (void *)-1;
r->dd_stat = 0;
r->dd_dir.d_ino = 0;
r->dd_dir.d_reclen = 0;
r->dd_dir.d_namlen = 0;
r->dd_dir.d_type = DT_UNKNOWN;
memset(r->dd_dir.d_name, 0, FILENAME_MAX);
return r;
}
struct dirent *readdir(DIR *dirp) {
errno = 0;
if(!dirp) {
errno = EBADF;
return NULL;
}
if(dirp->dd_stat < 0) {
return NULL;
} else if(dirp->dd_stat > 0) {
if(FindNextFileW(dirp->dd_handle, &dirp->dd_data)) {
dirp->dd_stat++;
} else {
if(GetLastError() == ERROR_NO_MORE_FILES) errno = 0;
FindClose(dirp->dd_handle);
dirp->dd_handle = (void *)-1;
dirp->dd_stat = -1;
}
} else {
size_t len = strlen(dirp->dd_name) + 1;
wchar_t wname[len];
mbstowcs(wname, dirp->dd_name, len);
dirp->dd_handle = FindFirstFileW(wname, &dirp->dd_data);
if(dirp->dd_handle == (void *)-1) {
dirp->dd_stat = -1;
} else {
dirp->dd_stat = 1;
}
}
if(dirp->dd_stat > 0) {
//size_t len = wcslen(dirp->dd_data.cFileName) * 2;
int len = wcstombs(dirp->dd_dir.d_name, dirp->dd_data.cFileName, FILENAME_MAX);
//fprintf(stderr, "celibc debug: dd_data.cFileName = L\"%ls\", dd_dir.d_name = %p\"%s\"\n", dirp->dd_data.cFileName, dirp->dd_dir.d_name, dirp->dd_dir.d_name);
if(len < 0) len = strlen(dirp->dd_dir.d_name);
dirp->dd_dir.d_namlen = len;
dirp->dd_dir.d_type = attribute_to_dirtype(dirp->dd_data.dwFileAttributes);
return &dirp->dd_dir;
}
return NULL;
}
int closedir(DIR *dirp) {
// int r = 0;
void *h = NULL;
errno = 0;
if(!dirp) {
errno = EBADF;
return -1;
}
if(dirp->dd_handle != (void *)-1) {
//r = FindClose(dirp->dd_handle) ? 0 : -1;
h = dirp->dd_handle;
}
free(dirp);
// if(h && !FindClose(h)) r = -1;
// return r;
return (h && !FindClose(h)) ? -1 : 0;
}
void rewinddir(DIR *dirp) {
if(!dirp) return;
if(dirp->dd_handle != (void *)-1) {
FindClose(dirp->dd_handle);
}
dirp->dd_handle = (void *)-1;
dirp->dd_stat = 0;
}
long int telldir(DIR *dirp) {
if(!dirp) {
errno = EBADF;
return -1;
}
return dirp->dd_stat;
}
void seekdir(DIR *dirp, long int offset) {
if(!dirp) return;
if(offset < -1) return;
if(offset == -1) {
if(dirp->dd_handle != (void *)-1) {
FindClose(dirp->dd_handle);
dirp->dd_handle = (void *)-1;
}
dirp->dd_stat = -1;
} else {
rewinddir(dirp);
while(dirp->dd_stat < offset && readdir(dirp));
}
}