Page 1 of 1

KevEdit patch to avoid eating files on crash

Posted: Sun Jul 04, 2010 5:21 am
by premchai21
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!

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)]));

Posted: Sun Jul 04, 2010 2:26 pm
by Commodore
make a build and upload it. not all of us have c compilers.

Posted: Sun Jul 04, 2010 3:42 pm
by Quantum P.
Just out of curiosity, what kind of stuff have you been doing in KevEdit? Except for the DOS version, it's been pretty stable for me.

Posted: Sun Jul 04, 2010 6:32 pm
by premchai21
Quantum P. wrote:Just out of curiosity, what kind of stuff have you been doing in KevEdit? Except for the DOS version, it's been pretty stable for me.
Commodore wrote:make a build and upload it. not all of us have c compilers.
I'd wager that most of you who don't have C compilers also don't use AMD64 GNU/Linux as a primary platform, and that the unusual-for-the-task word size may be the trigger for whatever bugs are causing it to crash in the first place. I don't normally upload binaries for that by themselves because people get horribly confused when the executables don't run on their machines, but if that's actually going to be useful, then so be it. If you're asking for some other platform, I don't presently have the resources to allocate to compiling and testing for that, so you may have to get someone else to do it or else wait a long time.

Posted: Mon Jul 05, 2010 8:33 pm
by Commodore
you would wager correctly

Posted: Sun Aug 22, 2010 11:54 pm
by Surlent
I'll have to keep this in mind. Perhaps I can do something within the next few months. Assuming I do manage to keep this in mind, of course.