fix(platform): implement atomic hot-reload synchronization
* Resolve STATUS_INVALID_IMAGE_FORMAT on Windows by preventing race conditions during file I/O. * is_file_ready: Uses GENERIC_WRITE to block if any process (compiler, copy, etc.) is writing to the source. Added GetFileSize check to ensure headers are flushed. * platform_copy_file: Copies to .tmp and uses MoveFileExA for an atomic swap, hiding the file from the loader until completion. * Refactor: Unified Win32 and POSIX logic with a single exit point.
This commit is contained in:
+18
-6
@@ -32,14 +32,21 @@ void extract_module_id(const char *path, char *out_id);
|
|||||||
static uint8_t is_file_ready(const char *dir_path, const char *filename)
|
static uint8_t is_file_ready(const char *dir_path, const char *filename)
|
||||||
{
|
{
|
||||||
char full_path[STK_PATH_MAX_OS];
|
char full_path[STK_PATH_MAX_OS];
|
||||||
|
DWORD size;
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
|
|
||||||
sprintf(full_path, "%s\\%s", dir_path, filename);
|
sprintf(full_path, "%s\\%s", dir_path, filename);
|
||||||
h = CreateFileA(full_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
h = CreateFileA(full_path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
size = GetFileSize(h, NULL);
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
|
|
||||||
|
if (size == INVALID_FILE_SIZE || size < 1024)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -93,13 +100,19 @@ int platform_remove_file(const char *path)
|
|||||||
|
|
||||||
int platform_copy_file(const char *from, const char *to)
|
int platform_copy_file(const char *from, const char *to)
|
||||||
{
|
{
|
||||||
|
char buf[STK_PATH_MAX_OS];
|
||||||
|
int ret = -1;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return CopyFileA(from, to, FALSE) ? 0 : -1;
|
sprintf(buf, "%s.tmp", to);
|
||||||
|
if (CopyFileA(from, buf, FALSE)) {
|
||||||
|
if (MoveFileExA(buf, to, MOVEFILE_REPLACE_EXISTING))
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
DeleteFileA(buf);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
FILE *src = NULL, *dst = NULL;
|
FILE *src = NULL, *dst = NULL;
|
||||||
char buf[STK_PATH_MAX_OS];
|
|
||||||
size_t n;
|
size_t n;
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
src = fopen(from, "rb");
|
src = fopen(from, "rb");
|
||||||
if (!src)
|
if (!src)
|
||||||
@@ -117,12 +130,11 @@ int platform_copy_file(const char *from, const char *to)
|
|||||||
cleanup:
|
cleanup:
|
||||||
if (src)
|
if (src)
|
||||||
fclose(src);
|
fclose(src);
|
||||||
|
|
||||||
if (dst)
|
if (dst)
|
||||||
fclose(dst);
|
fclose(dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_remove_dir(const char *path)
|
int platform_remove_dir(const char *path)
|
||||||
|
|||||||
Reference in New Issue
Block a user