| /* 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)); |
| } |
| } |