Files
CgeFs/win32/Dir.c
Mikhail Romanko dac684a8a0
All checks were successful
CI / build-and-analyze (push) Successful in 1m17s
Simplify checks
2026-08-18 10:53:02 +03:00

176 lines
3.9 KiB
C

#define WIN32_LEAN_AND_MEAN
#include "../CgeFs.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
struct CgeFsDir {
HANDLE handle;
WIN32_FIND_DATAW findData;
int hasEntry;
};
static int utf8ToWchar(const char *utf8, wchar_t *out, int size) {
int len;
if (size <= 0)
return 0;
len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, out, size);
if (len <= 0 || len > size) {
out[0] = L'\0';
return 0;
}
return 1;
}
static void wcharToUtf8(const wchar_t *w, char *out, int size) {
int len;
len = WideCharToMultiByte(CP_UTF8, 0, w, -1, out, size, NULL, NULL);
if (len <= 0 || len > size)
out[0] = '\0';
}
static int mapWinError(DWORD value) {
switch (value) {
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
return CGE_FS_ENOENT;
case ERROR_ACCESS_DENIED:
return CGE_FS_EACCES;
case ERROR_DIRECTORY:
return CGE_FS_ENOTDIR;
default:
return CGE_FS_EUNKNOWN;
}
}
static uint64_t fileTimeToUint64(const FILETIME *ft) {
ULARGE_INTEGER u;
u.LowPart = ft->dwLowDateTime;
u.HighPart = ft->dwHighDateTime;
return u.QuadPart / 10000000ULL - 11644473600ULL;
}
CgeFsDir *CgeFsOpen(const char *path, int *result) {
wchar_t findPathW[MAX_PATH];
char findPathA[MAX_PATH * 4];
CgeFsDir *d;
snprintf(findPathA, sizeof(findPathA), "%s\\*", path);
d = malloc(sizeof(*d));
if (!d) {
if (result)
*result = CGE_FS_EUNKNOWN;
return NULL;
}
d->handle = INVALID_HANDLE_VALUE;
d->hasEntry = 0;
if (!utf8ToWchar(findPathA, findPathW, MAX_PATH)) {
if (result)
*result = CGE_FS_EUNKNOWN;
free(d);
return NULL;
}
d->handle = FindFirstFileW(findPathW, &d->findData);
if (d->handle == INVALID_HANDLE_VALUE) {
if (result)
*result = mapWinError(GetLastError());
free(d);
return NULL;
}
d->hasEntry = 1;
return d;
}
int CgeFsNext(CgeFsDir *d, CgeFsInfo *info, int *result) {
WIN32_FIND_DATAW *ent;
char nameUtf8[CGE_FS_NAME_MAX];
while (d->hasEntry) {
ent = &d->findData;
d->hasEntry = 0;
if (!wcscmp(ent->cFileName, L".") || !wcscmp(ent->cFileName, L"..")) {
if (FindNextFileW(d->handle, &d->findData) != 0)
d->hasEntry = 1;
continue;
}
wcharToUtf8(ent->cFileName, nameUtf8, sizeof(nameUtf8));
strncpy(info->name, nameUtf8, CGE_FS_NAME_MAX - 1);
info->name[CGE_FS_NAME_MAX - 1] = '\0';
info->type = (ent->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? CGE_FS_DIR : CGE_FS_FILE;
info->size = ((uint64_t)ent->nFileSizeHigh << 32) | ent->nFileSizeLow;
info->mtime = (uint64_t)(fileTimeToUint64(&ent->ftLastWriteTime));
if (FindNextFileW(d->handle, &d->findData) != 0)
d->hasEntry = 1;
return 1;
}
if (result)
*result = CGE_FS_EEOF;
return 0;
}
void CgeFsClose(CgeFsDir *d) {
if (!d)
return;
if (d->handle != INVALID_HANDLE_VALUE)
FindClose(d->handle);
free(d);
}
int CgeFsCreateDir(const char *path, int *result) {
wchar_t wpath[MAX_PATH];
if (!utf8ToWchar(path, wpath, MAX_PATH)) {
if (result)
*result = CGE_FS_EUNKNOWN;
return 0;
}
if (CreateDirectoryW(wpath, NULL) == 0) {
if (result)
*result = mapWinError(GetLastError());
return 0;
}
return 1;
}
int CgeFsRemoveDir(const char *path, int *result) {
wchar_t wpath[MAX_PATH];
if (!utf8ToWchar(path, wpath, MAX_PATH)) {
if (result)
*result = CGE_FS_EUNKNOWN;
return 0;
}
if (RemoveDirectoryW(wpath) == 0) {
if (result)
*result = mapWinError(GetLastError());
return 0;
}
return 1;
}