KevEdit patch to avoid eating files on crash
Posted: Sun Jul 04, 2010 5:21 am
So when KevEdit is saving a ZZT file, it naïvely does a fopen(…, "wb") on the file directly, which implicitly truncates the file before writing out the new data. This is a losing approach except in cases of severely limited disk space, since it means that any application crash in the middle of writing the file will result in the file being overwritten with garbage, and both the old data and the new data are gone. Hope you kept backups!
Of course, you should keep backups anyway, but KevEdit suffering a rectocranial inversion while saving has eaten parts of my work multiple times now, so I minimally patched it to write out the new file before erasing the old file, which is more sensible on a modern machine.
I sent the patch upstream but didn't get any response, so I figure I'll post it here in case you folks find it useful for local installations. It's small enough that I'll just include the context diff inline. The patch itself is in the public domain insofar as I can place it there; KevEdit retains its standard upstream copyright and GNU GPL license.
Share and enjoy!
Of course, you should keep backups anyway, but KevEdit suffering a rectocranial inversion while saving has eaten parts of my work multiple times now, so I minimally patched it to write out the new file before erasing the old file, which is more sensible on a modern machine.
I sent the patch upstream but didn't get any response, so I figure I'll post it here in case you folks find it useful for local installations. It's small enough that I'll just include the context diff inline. The patch itself is in the public domain insofar as I can place it there; KevEdit retains its standard upstream copyright and GNU GPL license.
Share and enjoy!
Code: Select all
--- kevedit-cvs/src/libzzt2/world.c 2005-06-28 22:20:34.000000000 -0500
+++ kevedit-new/src/libzzt2/world.c 2010-06-28 00:10:41.000000000 -0500
@@ -114,11 +114,19 @@
{
int result;
FILE *fp;
+ char const *const filename = world->filename;
+ size_t const tmp_size = strlen(filename) + 5;
+ char *tmp_filename = malloc(tmp_size);
+ if (tmp_filename == NULL)
+ return 0;
+ snprintf(tmp_filename, tmp_size, "%s.new", filename);
/* Open file */
- fp = fopen(world->filename, "wb");
- if(fp == NULL)
+ fp = fopen(tmp_filename, "wb");
+ if(fp == NULL) {
+ free(tmp_filename);
return 0;
+ }
/* Commit current board */
zztBoardCommit(world);
@@ -126,6 +134,10 @@
result = zztWorldWrite(world, fp);
fclose(fp);
+ if (result)
+ rename(tmp_filename, filename);
+ free(tmp_filename);
+
/* Decompress the current board */
zztBoardDecompress(&(world->boards[zztBoardGetCurrent(world)]));