225 lines
5.7 KiB
C
225 lines
5.7 KiB
C
#include "fsutils.h"
|
|
#include "runtime.h"
|
|
#include "threading.h"
|
|
|
|
#ifdef _WIN32
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
|
|
struct rt_scandir_handle_s {
|
|
HANDLE handle;
|
|
rt_dirent next;
|
|
};
|
|
|
|
static rt_scandir_handle _dirs[256];
|
|
static unsigned int _next = 0;
|
|
static rt_mutex *_guard = NULL;
|
|
|
|
RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
|
|
char wildcard_path[MAX_PATH];
|
|
strncpy(wildcard_path, path, MAX_PATH);
|
|
strncat(wildcard_path, "\\*", MAX_PATH - strlen(path));
|
|
WCHAR wpath[MAX_PATH];
|
|
if (rtUTF8ToWStr(wildcard_path, wpath, MAX_PACKAGE_NAME) != RT_SUCCESS)
|
|
return NULL;
|
|
WIN32_FIND_DATAW data;
|
|
HANDLE h = FindFirstFileW(wpath, &data);
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
return NULL;
|
|
|
|
if (!_guard) {
|
|
_guard = rtCreateMutex();
|
|
if (!_guard) {
|
|
FindClose(h);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
rtLockMutex(_guard);
|
|
rt_scandir_handle *dir = &_dirs[_next];
|
|
_next = (_next + 1) % RT_ARRAY_COUNT(_dirs);
|
|
rtUnlockMutex(_guard);
|
|
|
|
if (dir->handle != NULL) {
|
|
rtLog("core", "Failed to acquire a scandir handle.");
|
|
FindClose(h);
|
|
return NULL;
|
|
}
|
|
|
|
dir->handle = h;
|
|
dir->next.is_last = false;
|
|
rtWStrToUTF8(data.cFileName, dir->next.name, 260);
|
|
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
dir->next.type = RT_DIRENT_TYPE_DIRECTORY;
|
|
else
|
|
dir->next.type = RT_DIRENT_TYPE_FILE;
|
|
|
|
return dir;
|
|
}
|
|
|
|
RT_DLLEXPORT rt_dirent rtNextDirectoryEntry(rt_scandir_handle *dir) {
|
|
rt_dirent current;
|
|
memcpy(¤t, &dir->next, sizeof(rt_dirent));
|
|
|
|
WIN32_FIND_DATAW data;
|
|
if (!FindNextFileW(dir->handle, &data)) {
|
|
current.is_last = true;
|
|
return current;
|
|
}
|
|
rtWStrToUTF8(data.cFileName, dir->next.name, 260);
|
|
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
dir->next.type = RT_DIRENT_TYPE_DIRECTORY;
|
|
else
|
|
dir->next.type = RT_DIRENT_TYPE_FILE;
|
|
|
|
return current;
|
|
}
|
|
|
|
RT_DLLEXPORT void rtCloseDirectory(rt_scandir_handle *dir) {
|
|
if (!dir)
|
|
return;
|
|
FindClose(dir->handle);
|
|
dir->handle = NULL;
|
|
}
|
|
|
|
RT_DLLEXPORT bool rtCreateDirectory(const char *path) {
|
|
WCHAR wpath[MAX_PATH];
|
|
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
|
|
return CreateDirectoryW(wpath, NULL);
|
|
}
|
|
|
|
RT_DLLEXPORT size_t rtGetFileSize(const char *path) {
|
|
WCHAR wpath[MAX_PATH];
|
|
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
|
|
WIN32_FILE_ATTRIBUTE_DATA attribs;
|
|
if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &attribs))
|
|
return 0;
|
|
return (size_t)attribs.nFileSizeHigh << 32 | (size_t)attribs.nFileSizeLow;
|
|
}
|
|
|
|
uint64_t rtGetCurrentTimestamp(void) {
|
|
FILETIME ft;
|
|
GetSystemTimeAsFileTime(&ft);
|
|
uint64_t ts = ft.dwLowDateTime;
|
|
ts |= (uint64_t)ft.dwHighDateTime << 32;
|
|
return ts;
|
|
}
|
|
|
|
uint64_t rtGetFileModificationTimestamp(const char *path) {
|
|
WCHAR wpath[MAX_PATH];
|
|
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
|
|
WIN32_FILE_ATTRIBUTE_DATA attribs;
|
|
if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &attribs))
|
|
return 0;
|
|
uint64_t ts = attribs.ftLastWriteTime.dwLowDateTime;
|
|
ts |= (uint64_t)attribs.ftLastWriteTime.dwHighDateTime << 32;
|
|
return ts;
|
|
}
|
|
|
|
#elif defined(__linux__)
|
|
|
|
#include <string.h>
|
|
#include <sys/dir.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
|
|
struct rt_scandir_handle_s {
|
|
DIR *handle;
|
|
rt_dirent next;
|
|
};
|
|
|
|
static rt_scandir_handle _dirs[256];
|
|
static unsigned int _next = 0;
|
|
static rt_mutex *_guard = NULL;
|
|
|
|
RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
|
|
DIR *h = opendir(path);
|
|
if (!h)
|
|
return NULL;
|
|
|
|
if (!_guard) {
|
|
_guard = rtCreateMutex();
|
|
if (!_guard) {
|
|
closedir(h);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
rtLockMutex(_guard);
|
|
rt_scandir_handle *dir = &_dirs[_next];
|
|
_next = (_next + 1) % RT_ARRAY_COUNT(_dirs);
|
|
rtUnlockMutex(_guard);
|
|
|
|
if (dir->handle != NULL) {
|
|
rtLog("core", "Failed to acquire a scandir handle.");
|
|
closedir(h);
|
|
return NULL;
|
|
}
|
|
|
|
struct dirent *ent = readdir(h);
|
|
if (!ent) {
|
|
closedir(h);
|
|
return NULL;
|
|
}
|
|
dir->handle = h;
|
|
dir->next.is_last = false;
|
|
memcpy(dir->next.name, ent->d_name, 255);
|
|
if (ent->d_type == DT_DIR)
|
|
dir->next.type = RT_DIRENT_TYPE_DIRECTORY;
|
|
else
|
|
dir->next.type = RT_DIRENT_TYPE_FILE;
|
|
|
|
return dir;
|
|
}
|
|
|
|
RT_DLLEXPORT rt_dirent rtNextDirectoryEntry(rt_scandir_handle *dir) {
|
|
rt_dirent current;
|
|
memcpy(¤t, &dir->next, sizeof(rt_dirent));
|
|
|
|
struct dirent *ent = readdir(dir->handle);
|
|
if (!ent) {
|
|
current.is_last = true;
|
|
return current;
|
|
}
|
|
memcpy(dir->next.name, ent->d_name, 255);
|
|
if (ent->d_type == DT_DIR)
|
|
dir->next.type = RT_DIRENT_TYPE_DIRECTORY;
|
|
else
|
|
dir->next.type = RT_DIRENT_TYPE_FILE;
|
|
return current;
|
|
}
|
|
|
|
RT_DLLEXPORT void rtCloseDirectory(rt_scandir_handle *dir) {
|
|
if (!dir)
|
|
return;
|
|
closedir(dir->handle);
|
|
dir->handle = NULL;
|
|
}
|
|
|
|
RT_DLLEXPORT bool rtCreateDirectory(const char *path) {
|
|
return mkdir(path, S_IRWXU | S_IRGRP) == 0;
|
|
}
|
|
|
|
RT_DLLEXPORT size_t rtGetFileSize(const char *path) {
|
|
struct stat st;
|
|
if (stat(path, &st) != 0)
|
|
return 0;
|
|
return (size_t)st.st_size;
|
|
}
|
|
|
|
uint64_t rtGetCurrentTimestamp(void) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
return (uint64_t)ts.tv_sec;
|
|
}
|
|
|
|
uint64_t rtGetFileModificationTimestamp(const char *path) {
|
|
struct stat st;
|
|
if (stat(path, &st) != 0)
|
|
return 0;
|
|
return (uint64_t)st.st_mtim.tv_sec;
|
|
}
|
|
|
|
#endif
|