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:
@@ -14,6 +14,7 @@ extern char (*stk_module_ids)[STK_MOD_ID_BUFFER];
|
||||
extern size_t module_count;
|
||||
|
||||
static char stk_mod_dir[STK_MOD_DIR_BUFFER];
|
||||
static char stk_tmp_dir[STK_MOD_DIR_BUFFER];
|
||||
static void *watch_handle = NULL;
|
||||
|
||||
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(
|
||||
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);
|
||||
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;
|
||||
char full_path[STK_PATH_MAX_OS];
|
||||
char tmp_path[STK_PATH_MAX_OS];
|
||||
|
||||
if (mod_dir) {
|
||||
strncpy(stk_mod_dir, mod_dir, STK_MOD_DIR_BUFFER - 1);
|
||||
stk_mod_dir[STK_MOD_DIR_BUFFER - 1] = '\0';
|
||||
size_t len = strlen(mod_dir);
|
||||
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 {
|
||||
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);
|
||||
|
||||
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) {
|
||||
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);
|
||||
@@ -75,13 +107,13 @@ void stk_shutdown(void)
|
||||
}
|
||||
|
||||
stk_module_unload_all();
|
||||
|
||||
platform_remove_dir(stk_tmp_dir);
|
||||
stk_log(stdout, "[stk] stk shutdown");
|
||||
}
|
||||
|
||||
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;
|
||||
size_t file_count, i;
|
||||
|
||||
@@ -94,10 +126,13 @@ size_t stk_poll(void)
|
||||
for (i = 0; i < file_count; ++i) {
|
||||
switch (events[i]) {
|
||||
case STK_MOD_RELOAD:
|
||||
/* TODO: Implement reload */
|
||||
break;
|
||||
case STK_MOD_LOAD:
|
||||
/* TODO: Implement load */
|
||||
break;
|
||||
case STK_MOD_UNLOAD:
|
||||
/* TODO: Implement unload */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user