foxygit / doom Log in
commit 974228a52920aeb89b3f1f19184aa9ffcc037ef5
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sat Apr 19 13:43:17 2008 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sat Apr 19 13:43:17 2008 +0000

    Don't successfully save a savegame if a buffer overrun occurs, and don't
    overwrite the existing savegame.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 1119
---
 NEWS          |  3 +++
 src/g_game.c  | 30 +++++++++++++++++++++---------
 src/p_saveg.c | 27 ++++++++++++++++++++++++++-
 src/p_saveg.h |  4 ++++
 4 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 805fee13..a9a9a5c7 100644
--- a/NEWS
+++ b/NEWS
@@ -32,6 +32,9 @@
      * The default startup delay has been set to one second, to allow
        time for the screen to settle before starting the game (some
        monitors have a delay before they come back on after changing modes).
+     * If a savegame buffer overrun occurs, the savegame does not get saved
+       and existing savegames are not overwritten (same behaviour as
+       Vanilla).

     Bugs fixed:
      * Desync with STRAIN demos and dehacked Misc values not being set
diff --git a/src/g_game.c b/src/g_game.c
index c9e3879f..4f7a3d43 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1485,21 +1485,25 @@ G_SaveGame

 void G_DoSaveGame (void)
 {
-    char	name[100];
-    char*	description;
-
-    strcpy(name, P_SaveGameFile(savegameslot));
+    char *savegame_file;
+    char *temp_savegame_file;

-    description = savedescription;
-
-    save_stream = fopen(name, "wb");
+    temp_savegame_file = P_TempSaveGameFile();
+    savegame_file = P_SaveGameFile(savegameslot);
+
+    // Open the savegame file for writing.  We write to a temporary file
+    // and then rename it at the end if it was successfully written.
+    // This prevents an existing savegame from being overwritten by
+    // a corrupted one, or if a savegame buffer overrun occurs.
+
+    save_stream = fopen(temp_savegame_file, "wb");

     if (save_stream == NULL)
     {
         return;
     }

-    P_WriteSaveGameHeader(description);
+    P_WriteSaveGameHeader(savedescription);

     P_ArchivePlayers ();
     P_ArchiveWorld ();
@@ -1516,11 +1520,19 @@ void G_DoSaveGame (void)
         I_Error ("Savegame buffer overrun");
     }

+    // Finish up, close the savegame file.
+
     fclose(save_stream);

+    // Now rename the temporary savegame file to the actual savegame
+    // file, overwriting the old savegame if there was one there.
+
+    remove(savegame_file);
+    rename(temp_savegame_file, savegame_file);
+
     gameaction = ga_nothing;
     strcpy(savedescription, "");
-
+
     players[consoleplayer].message = DEH_String(GGSAVED);

     // draw the pattern into the back screen
diff --git a/src/p_saveg.c b/src/p_saveg.c
index afd3852d..40b5f988 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -44,11 +44,36 @@
 FILE *save_stream;
 int savegamelength;

+// Get the filename of a temporary file to write the savegame to.  After
+// the file has been successfully saved, it will be renamed to the
+// real file.
+
+char *P_TempSaveGameFile(void)
+{
+    static char *filename = NULL;
+
+    if (filename == NULL)
+    {
+        filename = malloc(strlen(savegamedir) + 32);
+    }
+
+    sprintf(filename, "%stemp.dsg", savegamedir);
+
+    return filename;
+}
+
+// Get the filename of the save game file to use for the specified slot.
+
 char *P_SaveGameFile(int slot)
 {
-    static char filename[256];
+    static char *filename = NULL;
     char basename[32];

+    if (filename == NULL)
+    {
+        filename = malloc(strlen(savegamedir) + 32);
+    }
+
     sprintf(basename, DEH_String(SAVEGAMENAME "%d.dsg"), slot);

     sprintf(filename, "%s%s", savegamedir, basename);
diff --git a/src/p_saveg.h b/src/p_saveg.h
index 6f95585e..3a96cc3e 100644
--- a/src/p_saveg.h
+++ b/src/p_saveg.h
@@ -34,6 +34,10 @@

 #define SAVESTRINGSIZE 24

+// temporary filename to use while saving.
+
+char *P_TempSaveGameFile(void);
+
 // filename to use for a savegame slot

 char *P_SaveGameFile(int slot);