feat: implement .tmp directory isolation for safe hot-reload
Add foundation for cross-platform hot-reload system by isolating loaded modules from source files using a temporary directory. Changes: - Add configurable tmp directory parameter to stk_init() (defaults to mods/.tmp/ if not specified) - Copy all modules from mods/ to .tmp/ on initialization - Load modules exclusively from .tmp/ directory - Clean up .tmp/ directory on shutdown - Add cross-platform file operations: * platform_mkdir() - create directories * platform_copy_file() - copy files * platform_remove_file() - delete files * platform_remove_dir() - delete directory and contents - Improve BSD kqueue implementation to detect file overwrites (adds individual file watches with NOTE_WRITE) This isolates the loaded shared libraries from source files, preventing segfaults when users overwrite mods using cp/copy operations. The actual reload logic remains unimplemented (marked as TODO in stk_poll switch cases).
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@ typedef enum {
|
|||||||
STK_MOD_RELOAD
|
STK_MOD_RELOAD
|
||||||
} stk_module_event_t;
|
} stk_module_event_t;
|
||||||
|
|
||||||
int stk_init(const char *mod_dir);
|
int stk_init(const char *mod_dir, const char *tmp_dir);
|
||||||
void stk_shutdown(void);
|
void stk_shutdown(void);
|
||||||
size_t stk_module_count(void);
|
size_t stk_module_count(void);
|
||||||
size_t stk_poll(void);
|
size_t stk_poll(void);
|
||||||
|
|||||||
+291
-97
@@ -86,6 +86,112 @@ static uint8_t is_module_loaded(const char *filename,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int platform_mkdir(const char *path)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return CreateDirectoryA(path, NULL) ? 0 : -1;
|
||||||
|
#else
|
||||||
|
return mkdir(path, 0755);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int platform_remove_file(const char *path)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return DeleteFileA(path) ? 0 : -1;
|
||||||
|
#else
|
||||||
|
return unlink(path);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int platform_copy_file(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return CopyFileA(from, to, FALSE) ? 0 : -1;
|
||||||
|
#else
|
||||||
|
FILE *src, *dst;
|
||||||
|
char buffer[STK_PATH_MAX];
|
||||||
|
size_t bytes;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
src = fopen(from, "rb");
|
||||||
|
if (!src)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dst = fopen(to, "wb");
|
||||||
|
if (!dst) {
|
||||||
|
fclose(src);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0) {
|
||||||
|
if (fwrite(buffer, 1, bytes, dst) != bytes) {
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(src);
|
||||||
|
fclose(dst);
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int platform_remove_dir(const char *path)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
WIN32_FIND_DATAW find_data;
|
||||||
|
HANDLE find_handle;
|
||||||
|
WCHAR search_path[STK_PATH_MAX_OS];
|
||||||
|
char temp_filename[STK_PATH_MAX];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
swprintf(search_path, STK_PATH_MAX_OS, L"%S\\*", path);
|
||||||
|
find_handle = FindFirstFileW(search_path, &find_data);
|
||||||
|
|
||||||
|
if (find_handle != INVALID_HANDLE_VALUE) {
|
||||||
|
do {
|
||||||
|
if (find_data.dwFileAttributes &
|
||||||
|
FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = WideCharToMultiByte(
|
||||||
|
CP_UTF8, 0, find_data.cFileName, -1, temp_filename,
|
||||||
|
STK_PATH_MAX - 1, NULL, NULL);
|
||||||
|
if (len > 0) {
|
||||||
|
char full_path[STK_PATH_MAX_OS];
|
||||||
|
snprintf(full_path, sizeof(full_path), "%s\\%s",
|
||||||
|
path, temp_filename);
|
||||||
|
DeleteFileA(full_path);
|
||||||
|
}
|
||||||
|
} while (FindNextFileW(find_handle, &find_data));
|
||||||
|
FindClose(find_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RemoveDirectoryA(path) ? 0 : -1;
|
||||||
|
#else
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
char filepath[STK_PATH_MAX_OS];
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
|
if (strcmp(entry->d_name, ".") == 0 ||
|
||||||
|
strcmp(entry->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sprintf(filepath, "%s/%s", path, entry->d_name);
|
||||||
|
unlink(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return rmdir(path);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(__linux__) && !defined(_WIN32)
|
#if !defined(__linux__) && !defined(_WIN32)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char filename[STK_PATH_MAX];
|
char filename[STK_PATH_MAX];
|
||||||
@@ -96,6 +202,8 @@ typedef struct {
|
|||||||
int kq;
|
int kq;
|
||||||
int dir_fd;
|
int dir_fd;
|
||||||
char path[STK_PATH_MAX];
|
char path[STK_PATH_MAX];
|
||||||
|
int *file_fds;
|
||||||
|
size_t file_fd_count;
|
||||||
file_snapshot_t *snapshots;
|
file_snapshot_t *snapshots;
|
||||||
size_t snapshot_count;
|
size_t snapshot_count;
|
||||||
size_t snapshot_capacity;
|
size_t snapshot_capacity;
|
||||||
@@ -144,7 +252,7 @@ static file_snapshot_t *create_snapshot(const char *path, size_t *out_count,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
capacity = count + 8;
|
capacity = count;
|
||||||
snapshots = malloc(capacity * sizeof(file_snapshot_t));
|
snapshots = malloc(capacity * sizeof(file_snapshot_t));
|
||||||
if (!snapshots) {
|
if (!snapshots) {
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
@@ -192,6 +300,83 @@ static file_snapshot_t *find_in_snapshot(file_snapshot_t *snapshots,
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setup_file_watches(kqueue_watch_context_t *ctx)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
char filepath[STK_PATH_MAX_OS];
|
||||||
|
struct kevent event;
|
||||||
|
size_t idx;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
dir = opendir(ctx->path);
|
||||||
|
if (!dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx->file_fd_count = 0;
|
||||||
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
|
if (is_valid_module_file(entry->d_name))
|
||||||
|
ctx->file_fd_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->file_fd_count == 0) {
|
||||||
|
closedir(dir);
|
||||||
|
ctx->file_fds = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->file_fds = malloc(ctx->file_fd_count * sizeof(int));
|
||||||
|
if (!ctx->file_fds) {
|
||||||
|
closedir(dir);
|
||||||
|
ctx->file_fd_count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewinddir(dir);
|
||||||
|
idx = 0;
|
||||||
|
|
||||||
|
while ((entry = readdir(dir)) != NULL && idx < ctx->file_fd_count) {
|
||||||
|
if (!is_valid_module_file(entry->d_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sprintf(filepath, "%s/%s", ctx->path, entry->d_name);
|
||||||
|
fd = open(filepath, O_RDONLY);
|
||||||
|
if (fd >= 0) {
|
||||||
|
ctx->file_fds[idx++] = fd;
|
||||||
|
EV_SET(&event, fd, EVFILT_VNODE,
|
||||||
|
EV_ADD | EV_ENABLE | EV_CLEAR,
|
||||||
|
NOTE_WRITE | NOTE_DELETE | NOTE_ATTRIB, 0, NULL);
|
||||||
|
kevent(ctx->kq, &event, 1, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->file_fd_count = idx;
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup_file_watches(kqueue_watch_context_t *ctx)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!ctx->file_fds)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->file_fd_count; i++) {
|
||||||
|
if (ctx->file_fds[i] >= 0)
|
||||||
|
close(ctx->file_fds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ctx->file_fds);
|
||||||
|
ctx->file_fds = NULL;
|
||||||
|
ctx->file_fd_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refresh_file_watches(kqueue_watch_context_t *ctx)
|
||||||
|
{
|
||||||
|
cleanup_file_watches(ctx);
|
||||||
|
setup_file_watches(ctx);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *platform_load_library(const char *path)
|
void *platform_load_library(const char *path)
|
||||||
@@ -253,6 +438,8 @@ void *platform_directory_watch_start(const char *path)
|
|||||||
ctx->dir_fd = open(path, O_RDONLY);
|
ctx->dir_fd = open(path, O_RDONLY);
|
||||||
strncpy(ctx->path, path, STK_PATH_MAX - 1);
|
strncpy(ctx->path, path, STK_PATH_MAX - 1);
|
||||||
ctx->path[STK_PATH_MAX - 1] = '\0';
|
ctx->path[STK_PATH_MAX - 1] = '\0';
|
||||||
|
ctx->file_fds = NULL;
|
||||||
|
ctx->file_fd_count = 0;
|
||||||
ctx->snapshots = create_snapshot(path, &ctx->snapshot_count,
|
ctx->snapshots = create_snapshot(path, &ctx->snapshot_count,
|
||||||
&ctx->snapshot_capacity);
|
&ctx->snapshot_capacity);
|
||||||
|
|
||||||
@@ -269,6 +456,9 @@ void *platform_directory_watch_start(const char *path)
|
|||||||
EV_SET(&event, ctx->dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
|
EV_SET(&event, ctx->dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
|
||||||
NOTE_WRITE | NOTE_DELETE | NOTE_RENAME, 0, NULL);
|
NOTE_WRITE | NOTE_DELETE | NOTE_RENAME, 0, NULL);
|
||||||
kevent(ctx->kq, &event, 1, NULL, 0, NULL);
|
kevent(ctx->kq, &event, 1, NULL, 0, NULL);
|
||||||
|
|
||||||
|
setup_file_watches(ctx);
|
||||||
|
|
||||||
return (void *)ctx;
|
return (void *)ctx;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -286,6 +476,7 @@ void platform_directory_watch_stop(void *handle)
|
|||||||
ctx = (kqueue_watch_context_t *)handle;
|
ctx = (kqueue_watch_context_t *)handle;
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return;
|
return;
|
||||||
|
cleanup_file_watches(ctx);
|
||||||
if (ctx->dir_fd >= 0)
|
if (ctx->dir_fd >= 0)
|
||||||
close(ctx->dir_fd);
|
close(ctx->dir_fd);
|
||||||
if (ctx->kq >= 0)
|
if (ctx->kq >= 0)
|
||||||
@@ -433,17 +624,19 @@ stk_module_event_t *platform_directory_watch_check(
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
kqueue_watch_context_t *ctx;
|
kqueue_watch_context_t *ctx;
|
||||||
struct kevent event;
|
struct kevent events_buf[64];
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
file_snapshot_t *new_snapshots, *old_snap;
|
file_snapshot_t *new_snapshots, *old_snap;
|
||||||
size_t new_count, new_capacity, i, change_count;
|
size_t new_count, new_capacity, i, change_count;
|
||||||
|
int nevents;
|
||||||
|
|
||||||
ctx = (kqueue_watch_context_t *)handle;
|
ctx = (kqueue_watch_context_t *)handle;
|
||||||
timeout.tv_sec = 0;
|
timeout.tv_sec = 0;
|
||||||
timeout.tv_nsec = 0;
|
timeout.tv_nsec = 0;
|
||||||
change_count = 0;
|
change_count = 0;
|
||||||
|
|
||||||
if (kevent(ctx->kq, NULL, 0, &event, 1, &timeout) <= 0) {
|
nevents = kevent(ctx->kq, NULL, 0, events_buf, 64, &timeout);
|
||||||
|
if (nevents <= 0) {
|
||||||
*out_count = 0;
|
*out_count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -504,122 +697,123 @@ stk_module_event_t *platform_directory_watch_check(
|
|||||||
ctx->snapshots = new_snapshots;
|
ctx->snapshots = new_snapshots;
|
||||||
ctx->snapshot_count = new_count;
|
ctx->snapshot_count = new_count;
|
||||||
ctx->snapshot_capacity = new_capacity;
|
ctx->snapshot_capacity = new_capacity;
|
||||||
|
|
||||||
|
refresh_file_watches(ctx);
|
||||||
#endif
|
#endif
|
||||||
*out_count = index;
|
*out_count = index;
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
char (*platform_directory_init_scan(const char *mod_dir,
|
char (*platform_directory_init_scan(const char *mod_dir, size_t *out_count))
|
||||||
size_t *out_count))[STK_PATH_MAX]
|
[STK_PATH_MAX] {
|
||||||
{
|
char (*file_list)[STK_PATH_MAX] = NULL;
|
||||||
char(*file_list)[STK_PATH_MAX] = NULL;
|
char work_path[STK_PATH_MAX_OS];
|
||||||
char work_path[STK_PATH_MAX_OS];
|
size_t count = 0, index = 0;
|
||||||
size_t count = 0, index = 0;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
WIN32_FIND_DATAW find_data;
|
WIN32_FIND_DATAW find_data;
|
||||||
HANDLE find_handle;
|
HANDLE find_handle;
|
||||||
WCHAR search_path[STK_PATH_MAX_OS];
|
WCHAR search_path[STK_PATH_MAX_OS];
|
||||||
char temp_filename[STK_PATH_MAX];
|
char temp_filename[STK_PATH_MAX];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
swprintf(search_path, STK_PATH_MAX_OS, L"%S\\*", mod_dir);
|
swprintf(search_path, STK_PATH_MAX_OS, L"%S\\*", mod_dir);
|
||||||
find_handle = FindFirstFileW(search_path, &find_data);
|
find_handle = FindFirstFileW(search_path, &find_data);
|
||||||
|
|
||||||
if (find_handle == INVALID_HANDLE_VALUE) {
|
if (find_handle == INVALID_HANDLE_VALUE) {
|
||||||
CreateDirectoryA(mod_dir, NULL);
|
CreateDirectoryA(mod_dir, NULL);
|
||||||
*out_count = 0;
|
*out_count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, -1,
|
len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName,
|
||||||
temp_filename, STK_PATH_MAX - 1, NULL,
|
-1, temp_filename,
|
||||||
NULL);
|
STK_PATH_MAX - 1, NULL, NULL);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
temp_filename[len] = '\0';
|
temp_filename[len] = '\0';
|
||||||
if (is_valid_module_file(temp_filename))
|
if (is_valid_module_file(temp_filename))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
} while (FindNextFileW(find_handle, &find_data));
|
} while (FindNextFileW(find_handle, &find_data));
|
||||||
FindClose(find_handle);
|
FindClose(find_handle);
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
*out_count = 0;
|
*out_count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
find_handle = FindFirstFileW(search_path, &find_data);
|
find_handle = FindFirstFileW(search_path, &find_data);
|
||||||
file_list = malloc(count * sizeof(*file_list));
|
file_list = malloc(count * sizeof(*file_list));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, -1,
|
len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName,
|
||||||
file_list[index], STK_PATH_MAX - 1,
|
-1, file_list[index],
|
||||||
NULL, NULL);
|
STK_PATH_MAX - 1, NULL, NULL);
|
||||||
if (len > 0 && index < count) {
|
if (len > 0 && index < count) {
|
||||||
file_list[index][len] = '\0';
|
file_list[index][len] = '\0';
|
||||||
if (is_valid_module_file(file_list[index]))
|
if (is_valid_module_file(file_list[index]))
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
} while (FindNextFileW(find_handle, &find_data) && index < count);
|
} while (FindNextFileW(find_handle, &find_data) && index < count);
|
||||||
FindClose(find_handle);
|
FindClose(find_handle);
|
||||||
#else
|
#else
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
|
|
||||||
dir = opendir(mod_dir);
|
dir = opendir(mod_dir);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
mkdir(mod_dir, 0755);
|
mkdir(mod_dir, 0755);
|
||||||
*out_count = 0;
|
*out_count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
if (!is_valid_module_file(entry->d_name))
|
if (!is_valid_module_file(entry->d_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sprintf(work_path, "%s/%s", mod_dir, entry->d_name);
|
sprintf(work_path, "%s/%s", mod_dir, entry->d_name);
|
||||||
if (stat(work_path, &file_stat) == 0 &&
|
if (stat(work_path, &file_stat) == 0 &&
|
||||||
S_ISREG(file_stat.st_mode))
|
S_ISREG(file_stat.st_mode))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
*out_count = 0;
|
*out_count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rewinddir(dir);
|
rewinddir(dir);
|
||||||
file_list = malloc(count * sizeof(*file_list));
|
file_list = malloc(count * sizeof(*file_list));
|
||||||
if (!file_list) {
|
if (!file_list) {
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
*out_count = 0;
|
*out_count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((entry = readdir(dir)) != NULL && index < count) {
|
while ((entry = readdir(dir)) != NULL && index < count) {
|
||||||
if (!is_valid_module_file(entry->d_name))
|
if (!is_valid_module_file(entry->d_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sprintf(work_path, "%s/%s", mod_dir, entry->d_name);
|
sprintf(work_path, "%s/%s", mod_dir, entry->d_name);
|
||||||
if (stat(work_path, &file_stat) != 0 ||
|
if (stat(work_path, &file_stat) != 0 ||
|
||||||
!S_ISREG(file_stat.st_mode))
|
!S_ISREG(file_stat.st_mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
strncpy(file_list[index], entry->d_name, STK_PATH_MAX - 1);
|
strncpy(file_list[index], entry->d_name, STK_PATH_MAX - 1);
|
||||||
file_list[index][STK_PATH_MAX - 1] = '\0';
|
file_list[index][STK_PATH_MAX - 1] = '\0';
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
#endif
|
#endif
|
||||||
*out_count = index;
|
*out_count = index;
|
||||||
return file_list;
|
return file_list;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ extern char (*stk_module_ids)[STK_MOD_ID_BUFFER];
|
|||||||
extern size_t module_count;
|
extern size_t module_count;
|
||||||
|
|
||||||
static char stk_mod_dir[STK_MOD_DIR_BUFFER];
|
static char stk_mod_dir[STK_MOD_DIR_BUFFER];
|
||||||
|
static char stk_tmp_dir[STK_MOD_DIR_BUFFER];
|
||||||
static void *watch_handle = NULL;
|
static void *watch_handle = NULL;
|
||||||
|
|
||||||
char *extract_module_id(const char *path);
|
char *extract_module_id(const char *path);
|
||||||
@@ -30,20 +31,49 @@ int stk_module_init_memory(size_t capacity);
|
|||||||
stk_module_event_t *platform_directory_watch_check(
|
stk_module_event_t *platform_directory_watch_check(
|
||||||
void *handle, char (**file_list)[STK_PATH_MAX], size_t *out_count,
|
void *handle, char (**file_list)[STK_PATH_MAX], size_t *out_count,
|
||||||
char (*loaded_module_ids)[STK_MOD_ID_BUFFER], const size_t loaded_count);
|
char (*loaded_module_ids)[STK_MOD_ID_BUFFER], const size_t loaded_count);
|
||||||
|
int platform_mkdir(const char *path);
|
||||||
|
int platform_copy_file(const char *from, const char *to);
|
||||||
|
int platform_remove_dir(const char *path);
|
||||||
|
|
||||||
int stk_init(const char *mod_dir)
|
int stk_init(const char *mod_dir, const char *tmp_dir)
|
||||||
{
|
{
|
||||||
char(*files)[STK_PATH_MAX] = NULL;
|
char (*files)[STK_PATH_MAX] = NULL;
|
||||||
size_t file_count, i;
|
size_t file_count, i;
|
||||||
char full_path[STK_PATH_MAX_OS];
|
char full_path[STK_PATH_MAX_OS];
|
||||||
|
char tmp_path[STK_PATH_MAX_OS];
|
||||||
|
|
||||||
if (mod_dir) {
|
if (mod_dir) {
|
||||||
strncpy(stk_mod_dir, mod_dir, STK_MOD_DIR_BUFFER - 1);
|
size_t len = strlen(mod_dir);
|
||||||
stk_mod_dir[STK_MOD_DIR_BUFFER - 1] = '\0';
|
if (len >= STK_MOD_DIR_BUFFER)
|
||||||
|
len = STK_MOD_DIR_BUFFER - 1;
|
||||||
|
memcpy(stk_mod_dir, mod_dir, len);
|
||||||
|
stk_mod_dir[len] = '\0';
|
||||||
} else {
|
} else {
|
||||||
strcpy(stk_mod_dir, "mods");
|
strcpy(stk_mod_dir, "mods");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tmp_dir) {
|
||||||
|
size_t len = strlen(tmp_dir);
|
||||||
|
if (len >= STK_MOD_DIR_BUFFER)
|
||||||
|
len = STK_MOD_DIR_BUFFER - 1;
|
||||||
|
memcpy(stk_tmp_dir, tmp_dir, len);
|
||||||
|
stk_tmp_dir[len] = '\0';
|
||||||
|
} else {
|
||||||
|
size_t mod_len = strlen(stk_mod_dir);
|
||||||
|
const char *suffix = "/.tmp";
|
||||||
|
size_t suffix_len = strlen(suffix);
|
||||||
|
|
||||||
|
if (mod_len + suffix_len >= STK_MOD_DIR_BUFFER) {
|
||||||
|
mod_len = STK_MOD_DIR_BUFFER - suffix_len - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(stk_tmp_dir, stk_mod_dir, mod_len);
|
||||||
|
memcpy(stk_tmp_dir + mod_len, suffix, suffix_len);
|
||||||
|
stk_tmp_dir[mod_len + suffix_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_mkdir(stk_tmp_dir);
|
||||||
|
|
||||||
files = platform_directory_init_scan(stk_mod_dir, &file_count);
|
files = platform_directory_init_scan(stk_mod_dir, &file_count);
|
||||||
|
|
||||||
if (file_count > 0 && stk_module_init_memory(file_count) != 0)
|
if (file_count > 0 && stk_module_init_memory(file_count) != 0)
|
||||||
@@ -54,7 +84,9 @@ int stk_init(const char *mod_dir)
|
|||||||
|
|
||||||
for (i = 0; i < file_count; ++i) {
|
for (i = 0; i < file_count; ++i) {
|
||||||
sprintf(full_path, "%s/%s", stk_mod_dir, files[i]);
|
sprintf(full_path, "%s/%s", stk_mod_dir, files[i]);
|
||||||
stk_module_load_init(full_path, i);
|
sprintf(tmp_path, "%s/%s", stk_tmp_dir, files[i]);
|
||||||
|
if (platform_copy_file(full_path, tmp_path) == 0)
|
||||||
|
stk_module_load_init(tmp_path, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(files);
|
free(files);
|
||||||
@@ -75,13 +107,13 @@ void stk_shutdown(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
stk_module_unload_all();
|
stk_module_unload_all();
|
||||||
|
platform_remove_dir(stk_tmp_dir);
|
||||||
stk_log(stdout, "[stk] stk shutdown");
|
stk_log(stdout, "[stk] stk shutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t stk_poll(void)
|
size_t stk_poll(void)
|
||||||
{
|
{
|
||||||
char(*file_list)[STK_PATH_MAX] = NULL;
|
char (*file_list)[STK_PATH_MAX] = NULL;
|
||||||
stk_module_event_t *events = NULL;
|
stk_module_event_t *events = NULL;
|
||||||
size_t file_count, i;
|
size_t file_count, i;
|
||||||
|
|
||||||
@@ -94,10 +126,13 @@ size_t stk_poll(void)
|
|||||||
for (i = 0; i < file_count; ++i) {
|
for (i = 0; i < file_count; ++i) {
|
||||||
switch (events[i]) {
|
switch (events[i]) {
|
||||||
case STK_MOD_RELOAD:
|
case STK_MOD_RELOAD:
|
||||||
|
/* TODO: Implement reload */
|
||||||
break;
|
break;
|
||||||
case STK_MOD_LOAD:
|
case STK_MOD_LOAD:
|
||||||
|
/* TODO: Implement load */
|
||||||
break;
|
break;
|
||||||
case STK_MOD_UNLOAD:
|
case STK_MOD_UNLOAD:
|
||||||
|
/* TODO: Implement unload */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user