ref: 1d0c8fa113ba788ae41a977f30149113825e7b07
parent: 9ed6e9af65363ea4c9a6c4a7a3f5898bb554c56a
parent: 2e8094b71237c139d08ab373513112b258c143e4
author: Eldred Habert <[email protected]>
date: Sun Feb 9 22:08:14 EST 2020
Merge pull request #451 from rednex/atomic_output Make RGBASM overwrite output files atomically
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -16,7 +16,24 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winbase.h>
+/*
+ * The semantics of `rename` on Windows differ from POSIX in that it errors out
+ * when the target file exists, instead of overwriting it.
+ * Thus, shim `rename` with similar semantics (note that the return value of
+ * `MoveFileExA` is inverted, and it uses `GetLastError` instead of `errno`)
+ */
+#define rename(oldname, newname) \
+ MoveFileExA(oldname, newname, MOVEFILE_WRITE_THROUGH | \
+ MOVEFILE_REPLACE_EXISTING) \
+ ? 0 : (errno = GetLastError(), -1)
+#endif
+
#include "asm/asm.h"
#include "asm/charmap.h"
#include "asm/fstack.h"
@@ -531,13 +548,25 @@
*/
void out_WriteObject(void)
{
+ /* Write to a temporary file in the target's folder */
+ char *objectNameCopy = strdup(tzObjectname);
+ char const *dirPath = dirname(objectNameCopy);
+ char tmpFileName[strlen(dirPath) + 1 + 16 + 1];
+
+ sprintf(tmpFileName, "%s/rgbasm_tmpXXXXXX", dirPath);
+ free(objectNameCopy);
+ int fd = mkstemp(tmpFileName);
+
FILE *f;
struct PatchSymbol *pSym;
struct Section *pSect;
+ if (fd == -1)
+ err(1, "Couldn't create temporary file");
+
addexports();
- f = fopen(tzObjectname, "wb");
+ f = fdopen(fd, "wb");
if (f == NULL)
fatalerror("Couldn't write file '%s'\n", tzObjectname);
@@ -560,6 +589,11 @@
}
fclose(f);
+ close(fd);
+
+ if (rename(tmpFileName, tzObjectname) != 0)
+ err(1, "Couldn't create object file (temp file kept as %s)",
+ tmpFileName);
}
/*