blob: d06ef7ef3f815b1435cca4de8b35b5bf8fa8e765 [file] [log] [blame] [raw]
/* A part of the Windows CE C Extra Library (celibc)
Copyright 2007-2015 PC GO Ld.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#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_dirent_type(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 = sizeof r->dd_dir;
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 = 0;
*dirp->dd_dir.d_name = 0;
}
dirp->dd_dir.d_namlen = len;
dirp->dd_dir.d_type = attribute_to_dirent_type(dirp->dd_data.dwFileAttributes);
return &dirp->dd_dir;
}
return NULL;
}
int closedir(DIR *dirp) {
void *h = NULL;
if(!dirp) {
errno = EBADF;
return -1;
}
if(dirp->dd_handle != (void *)-1) {
h = dirp->dd_handle;
}
free(dirp);
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));
}
}