#include <folly/portability/Dirent.h>
#ifdef _WIN32
#include <stdlib.h>
#include <string>
#include <folly/portability/Windows.h>
struct DIR {
dirent dir{};
HANDLE searchHandle{INVALID_HANDLE_VALUE};
int entriesRead{0};
char currentName[MAX_PATH * 3];
std::string pattern;
int close() { return FindClose(searchHandle) ? 0 : -1; }
DIR* open() {
wchar_t patternBuf[MAX_PATH + 3];
size_t len;
if (pattern.empty()) {
return nullptr;
}
if (mbstowcs_s(&len, patternBuf, MAX_PATH, pattern.c_str(), MAX_PATH - 2)) {
return nullptr;
}
if (len) {
len--;
}
if (len && patternBuf[len - 1] != '/' && patternBuf[len - 1] != '\\') {
patternBuf[len++] = '\\';
}
patternBuf[len++] = '*';
patternBuf[len] = 0;
WIN32_FIND_DATAW fdata;
HANDLE h = FindFirstFileW(patternBuf, &fdata);
if (h == INVALID_HANDLE_VALUE) {
return nullptr;
}
searchHandle = h;
dir.d_name = currentName;
if (wcstombs(currentName, fdata.cFileName, MAX_PATH * 3) == (size_t)-1) {
return nullptr;
}
setEntryType(fdata.dwFileAttributes);
return this;
}
dirent* nextDir() {
if (entriesRead) {
WIN32_FIND_DATAW fdata;
if (!FindNextFileW(searchHandle, &fdata)) {
return nullptr;
}
if (wcstombs(currentName, fdata.cFileName, MAX_PATH * 3) == (size_t)-1) {
errno = EBADF;
return nullptr;
}
setEntryType(fdata.dwFileAttributes);
}
entriesRead++;
return &dir;
}
private:
void setEntryType(DWORD attr) {
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
dir.d_type = DT_DIR;
} else {
dir.d_type = DT_REG;
}
}
};
extern "C" {
int closedir(DIR* dir) {
auto ret = dir->close();
delete dir;
return ret;
}
DIR* opendir(const char* name) {
auto dir = new DIR();
dir->pattern = name;
if (!dir->open()) {
delete dir;
return nullptr;
}
return dir;
}
dirent* readdir(DIR* dir) {
return dir->nextDir();
}
int readdir_r(DIR* dir, dirent* buf, dirent** ent) {
if (!dir || !buf || !ent) {
return EBADF;
}
*ent = dir->nextDir();
if (*ent) {
*buf = dir->dir;
}
return 0;
}
void rewinddir(DIR* dir) {
dir->close();
dir->open();
}
}
#endif