rtengine/src/runtime/fsutils.c
Kevin Trogant b4eef37741 Fix linux build
I did not test if it actually runs, but it builds with warning_level=2.
2024-02-29 16:12:09 +01:00

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(&current, &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(&current, &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