From d7af07d549de1835ef0081f5cebba61a606f0bed Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Mitsis Poiitidis Date: Sat, 15 Mar 2025 14:01:30 +0200 Subject: [PATCH] Gracefully fail if savegame fails to save, detect all load errors --- src/liberty/save/GenericGameStorage.cpp | 41 ++++++++++++++++----- src/liberty/save/PCSave.cpp | 45 +++++++++++++++-------- src/miami/save/GenericGameStorage.cpp | 41 ++++++++++++++++----- src/miami/save/PCSave.cpp | 48 ++++++++++++++++--------- 4 files changed, 125 insertions(+), 50 deletions(-) diff --git a/src/liberty/save/GenericGameStorage.cpp b/src/liberty/save/GenericGameStorage.cpp index e4ba7472..b5b9064b 100644 --- a/src/liberty/save/GenericGameStorage.cpp +++ b/src/liberty/save/GenericGameStorage.cpp @@ -74,6 +74,10 @@ uint32 TimeToStayFadedBeforeFadeOut = 1750; do {\ size = C_PcSave::PcClassLoadRoutine(file, work_buff); \ if (!size) {\ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_READ; \ + if (!CloseFile(file)) { \ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE; \ + } \ return false; \ } \ buf = work_buff;\ @@ -95,8 +99,12 @@ do {\ MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\ save_func(buf, &size);\ CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\ - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\ + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) { \ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; \ + if (!CloseFile(file)) \ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; \ return false;\ + } \ totalSize += buf - work_buff;\ } while (0) @@ -195,8 +203,12 @@ GenericSave(int file) postsize = buf; CTheScripts::SaveAllScripts(buf, &size); CopySizeAndPreparePointer(presize, buf, postsize, reserved, size); - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + if (!CloseFile(file)) + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; return false; + } totalSize = buf - work_buff; @@ -232,15 +244,19 @@ GenericSave(int file) if (size > sizeof(work_buff)) size = sizeof(work_buff); if (size > 4) { - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size)) + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size)) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + if (!CloseFile(file)) + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; return false; + } totalSize += size; } } // Write checksum and close - CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum)); - if (CFileMgr::GetErrorReadWrite(file)) { + bool err = CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum)) != sizeof(CheckSum); + if (err || CFileMgr::GetErrorReadWrite(file)) { PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; if (!CloseFile(file)) PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; @@ -269,9 +285,17 @@ GenericLoad() CDate dummy; // unused CPad::ResetCheats(); file = CFileMgr::OpenFile(LoadFileName, "rb"); - assert(file != 0); + if (file == 0) { + return false; + } size = C_PcSave::PcClassLoadRoutine(file, work_buff); - assert(size != 0); + if (!size) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_READ; + if (!CloseFile(file)) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE; + } + return false; + } buf = (work_buff + 0x40); ReadDataFromBufferPointer(buf, saveSize); #ifdef MISSION_REPLAY // a hack to keep compatibility but get new data from save @@ -563,10 +587,9 @@ RestoreForStartLoad() } uint32_t size = C_PcSave::PcClassLoadRoutine(file, work_buff); - assert(size != 0); uint8 *buf = work_buff; - if (CFileMgr::GetErrorReadWrite(file)) { + if (size == 0 || CFileMgr::GetErrorReadWrite(file)) { PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_READ; if (!CloseFile(file)) PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE; diff --git a/src/liberty/save/PCSave.cpp b/src/liberty/save/PCSave.cpp index 723f5698..2a16fd7d 100644 --- a/src/liberty/save/PCSave.cpp +++ b/src/liberty/save/PCSave.cpp @@ -61,8 +61,10 @@ C_PcSave::SaveSlot(int32 slot) #endif DoGameSpecificStuffBeforeSave(); if (GenericSave(file)) { - if (!!CFileMgr::CloseFile(file)) + if (!!CFileMgr::CloseFile(file)) { nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; + return false; + } return true; } @@ -74,23 +76,26 @@ C_PcSave::SaveSlot(int32 slot) uint32_t C_PcSave::PcClassLoadRoutine(int32 file, uint8 *data) { uint32 size; - CFileMgr::Read(file, (char*)&size, sizeof(size)); + bool err = CFileMgr::Read(file, (char*)&size, sizeof(size)) != sizeof(size); + if (err) { + return 0; + } assert(data == work_buff); if (!(size & 0x80000000)) { assert(align4bytes(size) == size); - CFileMgr::Read(file, (char*)data, align4bytes(size)); - if (CFileMgr::GetErrorReadWrite(file)) { + err = CFileMgr::Read(file, (char*)data, align4bytes(size)) != align4bytes(size); + if (err || CFileMgr::GetErrorReadWrite(file)) { return 0; } return size; } else { size &= ~0x80000000; uint8* compressed = (uint8*)malloc(size); - CFileMgr::Read(file, (const char*)compressed, size); - if (CFileMgr::GetErrorReadWrite(file)) { + err = CFileMgr::Read(file, (const char*)compressed, size) != size; + if (err || CFileMgr::GetErrorReadWrite(file)) { free(compressed); return 0; } @@ -120,26 +125,36 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size) if (crv == LZO_E_OK) { uint32_t compressed_size32 = compressed_size | 0x80000000; - CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)); - if (CFileMgr::GetErrorReadWrite(file)) { + bool err = CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)) != sizeof(compressed_size32); + if (err || CFileMgr::GetErrorReadWrite(file)) { free(compressed); nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); return false; } - CFileMgr::Write(file, (const char*)compressed, compressed_size); + err = CFileMgr::Write(file, (const char*)compressed, compressed_size) != compressed_size; free(compressed); - } else if (crv == LZO_E_NOT_COMPRESSIBLE) { - free(compressed); - uint32_t compressed_size32 = size; - CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)); - if (CFileMgr::GetErrorReadWrite(file)) { + if (err || CFileMgr::GetErrorReadWrite(file)) { + nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); + return false; + } + } else if (crv == LZO_E_NOT_COMPRESSIBLE) { + free(compressed); + uint32_t compressed_size32 = size; + bool err = CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)) != sizeof(compressed_size32); + if (err || CFileMgr::GetErrorReadWrite(file)) { + nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); + return false; + } + err = CFileMgr::Write(file, (const char*)data, align4bytes(size)) != align4bytes(size); + if (err || CFileMgr::GetErrorReadWrite(file)) { nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); return false; } - CFileMgr::Write(file, (const char*)data, align4bytes(size)); } else { free(compressed); return false; diff --git a/src/miami/save/GenericGameStorage.cpp b/src/miami/save/GenericGameStorage.cpp index aada56d3..64cc6859 100644 --- a/src/miami/save/GenericGameStorage.cpp +++ b/src/miami/save/GenericGameStorage.cpp @@ -98,6 +98,10 @@ PopulateRadioStationPositionList() do {\ size = C_PcSave::PcClassLoadRoutine(file, work_buff); \ if (!size) {\ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_READ; \ + if (!CloseFile(file)) { \ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE; \ + } \ return false; \ } \ buf = work_buff;\ @@ -121,8 +125,12 @@ do {\ save_func(buf, &size);\ debug(msg"== %i \n", size);\ CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\ - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\ + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) { \ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; \ + if (!CloseFile(file)) \ + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; \ return false;\ + } \ totalSize += buf - work_buff;\ } while (0) @@ -223,8 +231,12 @@ GenericSave(int file) CTheScripts::SaveAllScripts(buf, &size); debug("ScriptSize== %i \n", size); CopySizeAndPreparePointer(presize, buf, postsize, reserved, size); - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff)) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + if (!CloseFile(file)) + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; return false; + } totalSize = buf - work_buff; @@ -263,15 +275,19 @@ GenericSave(int file) if (size > sizeof(work_buff)) size = sizeof(work_buff); if (size > 4) { - if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size)) + if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size)) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + if (!CloseFile(file)) + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; return false; + } totalSize += size; } } // Write checksum and close - CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum)); - if (CFileMgr::GetErrorReadWrite(file)) { + bool err = CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum)) != sizeof(CheckSum); + if (err || CFileMgr::GetErrorReadWrite(file)) { PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; if (!CloseFile(file)) PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; @@ -302,9 +318,17 @@ GenericLoad() CPad::ResetCheats(); file = CFileMgr::OpenFile(LoadFileName, "rb"); - assert(file != 0); + if (file == 0) { + return false; + } size = C_PcSave::PcClassLoadRoutine(file, work_buff); - assert(size != 0); + if (!size) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_READ; + if (!CloseFile(file)) { + PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE; + } + return false; + } buf = (work_buff + 0x40); ReadDataFromBufferPointer(buf, saveSize); @@ -615,10 +639,9 @@ RestoreForStartLoad() } uint32_t size = C_PcSave::PcClassLoadRoutine(file, work_buff); - assert(size != 0); uint8 *buf = work_buff; - if (CFileMgr::GetErrorReadWrite(file)) { + if (size == 0 || CFileMgr::GetErrorReadWrite(file)) { PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_READ; if (!CloseFile(file)) PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE; diff --git a/src/miami/save/PCSave.cpp b/src/miami/save/PCSave.cpp index d7e6b492..6d6fac90 100644 --- a/src/miami/save/PCSave.cpp +++ b/src/miami/save/PCSave.cpp @@ -60,15 +60,17 @@ C_PcSave::SaveSlot(int32 slot) #endif DoGameSpecificStuffBeforeSave(); if (GenericSave(file)) { - if (!!CFileMgr::CloseFile(file)) + if (!!CFileMgr::CloseFile(file)) { nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; + return 2; + } return 0; } return 2; } PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CREATE; - return false; + return 2; } bool @@ -82,26 +84,36 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size) if (crv == LZO_E_OK) { uint32_t compressed_size32 = compressed_size | 0x80000000; - CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)); - if (CFileMgr::GetErrorReadWrite(file)) { + bool err = CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)) != sizeof(compressed_size32); + if (err || CFileMgr::GetErrorReadWrite(file)) { free(compressed); nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); return false; } - CFileMgr::Write(file, (const char*)compressed, compressed_size); + err = CFileMgr::Write(file, (const char*)compressed, compressed_size) != compressed_size; free(compressed); - } else if (crv == LZO_E_NOT_COMPRESSIBLE) { - free(compressed); - uint32_t compressed_size32 = size; - CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)); - if (CFileMgr::GetErrorReadWrite(file)) { + if (err || CFileMgr::GetErrorReadWrite(file)) { + nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); + return false; + } + } else if (crv == LZO_E_NOT_COMPRESSIBLE) { + free(compressed); + uint32_t compressed_size32 = size; + bool err = CFileMgr::Write(file, (const char*)&compressed_size32, sizeof(compressed_size32)) != sizeof(compressed_size32); + if (err || CFileMgr::GetErrorReadWrite(file)) { + nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; + strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); + return false; + } + err = CFileMgr::Write(file, (const char*)data, align4bytes(size)) != align4bytes(size); + if (err || CFileMgr::GetErrorReadWrite(file)) { nErrorCode = SAVESTATUS_ERR_SAVE_WRITE; strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1); return false; } - CFileMgr::Write(file, (const char*)data, align4bytes(size)); } else { free(compressed); return false; @@ -125,23 +137,25 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size) uint32_t C_PcSave::PcClassLoadRoutine(int32 file, uint8 *data) { uint32 size; - CFileMgr::Read(file, (char*)&size, sizeof(size)); + bool err = CFileMgr::Read(file, (char*)&size, sizeof(size)) != sizeof(size); + if (err) { + return 0; + } - assert(data == work_buff); if (!(size & 0x80000000)) { assert(align4bytes(size) == size); - CFileMgr::Read(file, (char*)data, align4bytes(size)); - if (CFileMgr::GetErrorReadWrite(file)) { + err = CFileMgr::Read(file, (char*)data, align4bytes(size)) != align4bytes(size); + if (err || CFileMgr::GetErrorReadWrite(file)) { return 0; } return size; } else { size &= ~0x80000000; uint8* compressed = (uint8*)malloc(size); - CFileMgr::Read(file, (const char*)compressed, size); - if (CFileMgr::GetErrorReadWrite(file)) { + err = CFileMgr::Read(file, (const char*)compressed, size) != size; + if (err || CFileMgr::GetErrorReadWrite(file)) { free(compressed); return 0; }