revision 1042:0fd066956482
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 1042:0fd066956482 |
parent | 1041:5fcc39857c5c |
child | 1043:ec716f2b8ffb |
author | nkeynes |
date | Fri Jun 26 13:53:54 2009 +0000 (14 years ago) |
Do the save-to-temp and rename thing when saving VMUs, for the sake of limiting corruption possibilities
src/util.c | view | annotate | diff | log | ||
src/vmu/vmuvol.c | view | annotate | diff | log |
1.1 --- a/src/util.c Fri Jun 26 05:47:04 2009 +00001.2 +++ b/src/util.c Fri Jun 26 13:53:54 2009 +00001.3 @@ -82,7 +82,7 @@1.4 return len;1.5 }1.7 -void fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )1.8 +int fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )1.9 {1.10 uLongf size = sz*count;1.11 uLongf csize = ((int)(size*1.001))+13;1.12 @@ -91,8 +91,15 @@1.13 assert( status == Z_OK );1.14 uint32_t wsize = (uint32_t)csize;1.15 fwrite( &wsize, sizeof(wsize), 1, f );1.16 - fwrite( tmp, csize, 1, f );1.17 + int written = fwrite( tmp, csize, 1, f );1.18 g_free(tmp);1.19 +1.20 + /* Could be finer-grained, but this is enough to know it succeeded/failed */1.21 + if( written == 1 ) {1.22 + return count;1.23 + } else {1.24 + return 0;1.25 + }1.26 }1.28 int fread_gzip( void *p, size_t sz, size_t count, FILE *f )
2.1 --- a/src/vmu/vmuvol.c Fri Jun 26 05:47:04 2009 +00002.2 +++ b/src/vmu/vmuvol.c Fri Jun 26 13:53:54 2009 +00002.3 @@ -19,12 +19,14 @@2.4 #include <glib/gmem.h>2.5 #include <glib/gstrfuncs.h>2.6 #include <string.h>2.7 +#include <unistd.h>2.8 #include <stdio.h>2.9 #include <fcntl.h>2.10 #include <errno.h>2.12 #include "vmu/vmuvol.h"2.13 #include "dream.h"2.14 +#include "lxpaths.h"2.16 #define VMU_MAX_PARTITIONS 2562.17 #define VMU_MAX_BLOCKS 65536 /* Actually slightly less than this, but it'll do */2.18 @@ -187,18 +189,22 @@2.19 };2.22 -2.23 gboolean vmu_volume_save( const gchar *filename, vmu_volume_t vol, gboolean create_only )2.24 {2.25 struct vmu_file_header head;2.26 struct vmu_chunk_header chunk;2.27 int i;2.28 -2.29 - FILE *f = fopen( filename, (create_only ? "wx" : "w") ); /* Portable? */2.30 - if( f == NULL ) {2.31 +2.32 + gchar *tempfile = get_filename_at(filename, ".XXXXXXXX.vmu");2.33 + int fd = mkstemps( tempfile, 4 );2.34 + if( fd == -1 ) {2.35 + g_free(tempfile);2.36 return FALSE;2.37 }2.39 + FILE *f = fdopen( fd, "w+" );2.40 +2.41 +2.42 /* File header */2.43 memcpy( head.magic, VMU_FILE_MAGIC, 16 );2.44 head.version = VMU_FILE_VERSION;2.45 @@ -222,19 +228,31 @@2.46 for( i=0; i< vol->part_count; i++ ) {2.47 memcpy( chunk.name, "DATA", 4 );2.48 chunk.length = 0;2.49 - fwrite( &chunk, sizeof(chunk), 1, f );2.50 + if( fwrite( &chunk, sizeof(chunk), 1, f ) != 1 ) goto cleanup;2.51 long posn = ftell(f);2.52 - fwrite( &vol->part[i].block_count, sizeof(vol->part[i].block_count), 1, f );2.53 + if( fwrite( &vol->part[i].block_count, sizeof(vol->part[i].block_count), 1, f ) != 1 ) goto cleanup;2.54 fwrite_gzip( vol->part[i].blocks, vol->part[i].block_count, VMU_BLOCK_SIZE, f );2.55 long end = ftell(f);2.56 fseek( f, posn - sizeof(chunk.length), SEEK_SET );2.57 chunk.length = end-posn;2.58 - fwrite( &chunk.length, sizeof(chunk.length), 1, f );2.59 + if( fwrite( &chunk.length, sizeof(chunk.length), 1, f ) != 1 ) goto cleanup;2.60 fseek( f, end, SEEK_SET );2.61 }2.62 fclose(f);2.63 +2.64 + if( rename(tempfile, filename) != 0 )2.65 + goto cleanup;2.66 +2.67 + /* All good */2.68 vol->dirty = FALSE;2.69 + g_free(tempfile);2.70 return TRUE;2.71 +2.72 +cleanup:2.73 + fclose(f);2.74 + unlink(tempfile);2.75 + g_free(tempfile);2.76 + return FALSE;2.77 }2.79 vmu_volume_t vmu_volume_load( const gchar *filename )
.