From 723546a56b4d27e6855b550d642ce4676c52b493 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 27 Apr 2024 18:25:59 -0500 Subject: [PATCH 1/4] Add exception messages to data load I_Errors --- src/g_gamedata.cpp | 7 +++++++ src/k_profiles.cpp | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index e4a2b6b7a..14ad25d1a 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -434,6 +434,13 @@ void srb2::load_ng_gamedata() json parsed = json::from_ubjson(remainder_as_u8); js = parsed.template get(); } + catch (const std::exception& ex) + { + const char* gdfolder = G_GameDataFolder(); + const char* what = ex.what(); + I_Error("Game data is corrupt.\nDelete %s (maybe in %s) and try again.\n\nException: %s", gamedatafilename, gdfolder, what); + return; + } catch (...) { const char* gdfolder = G_GameDataFolder(); diff --git a/src/k_profiles.cpp b/src/k_profiles.cpp index eb5371f98..1d8a9a8f8 100644 --- a/src/k_profiles.cpp +++ b/src/k_profiles.cpp @@ -398,9 +398,14 @@ void PR_LoadProfiles(void) json parsed = json::from_ubjson(remainder_as_u8); js = parsed.template get(); } + catch (const std::exception& ex) + { + I_Error("Profiles file is corrupt.\n\nException: %s", ex.what()); + return; + } catch (...) { - I_Error("Profiles file is corrupt"); + I_Error("Profiles file is corrupt."); return; } From ed2036432b6907820a1585f419c6d2d119cfa3dd Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 27 Apr 2024 19:20:11 -0500 Subject: [PATCH 2/4] Use raw file IO instead of buffered when saving --- src/g_gamedata.cpp | 11 ++++------- src/k_profiles.cpp | 17 +++++++---------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 14ad25d1a..6fe481c5e 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -294,17 +294,14 @@ void srb2::save_ng_gamedata() { std::string tmpsavepathstring = tmpsavepath.string(); srb2::io::FileStream file {tmpsavepathstring, srb2::io::FileStreamMode::kWrite}; - srb2::io::BufferedOutputStream bos {std::move(file)}; // The header is necessary to validate during loading. - srb2::io::write(static_cast(GD_VERSION_MAJOR), bos); // major - srb2::io::write(static_cast(GD_VERSION_MINOR), bos); // minor/flags - srb2::io::write(static_cast(gamedata->evercrashed), bos); // dirty (crash recovery) + srb2::io::write(static_cast(GD_VERSION_MAJOR), file); // major + srb2::io::write(static_cast(GD_VERSION_MINOR), file); // minor/flags + srb2::io::write(static_cast(gamedata->evercrashed), file); // dirty (crash recovery) std::vector ubjson = json::to_ubjson(ng); - srb2::io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson))); - bos.flush(); - file = bos.stream(); + srb2::io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson))); file.close(); } catch (const srb2::io::FileStreamException& ex) diff --git a/src/k_profiles.cpp b/src/k_profiles.cpp index 1d8a9a8f8..cc15ee1af 100644 --- a/src/k_profiles.cpp +++ b/src/k_profiles.cpp @@ -320,17 +320,14 @@ void PR_SaveProfiles(void) try { io::FileStream file {tmppath, io::FileStreamMode::kWrite}; - io::BufferedOutputStream bos {std::move(file)}; - io::write(static_cast(0x52494E47), bos, io::Endian::kBE); // "RING" - io::write(static_cast(0x5052464C), bos, io::Endian::kBE); // "PRFL" - io::write(static_cast(0), bos); // reserved1 - io::write(static_cast(0), bos); // reserved2 - io::write(static_cast(0), bos); // reserved3 - io::write(static_cast(0), bos); // reserved4 - io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson))); - bos.flush(); - file = bos.stream(); + io::write(static_cast(0x52494E47), file, io::Endian::kBE); // "RING" + io::write(static_cast(0x5052464C), file, io::Endian::kBE); // "PRFL" + io::write(static_cast(0), file); // reserved1 + io::write(static_cast(0), file); // reserved2 + io::write(static_cast(0), file); // reserved3 + io::write(static_cast(0), file); // reserved4 + io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson))); file.close(); fs::rename(tmppath, realpath); From bc524cd0e981d702016e94edfb3e8f8c3cc000f0 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 27 Apr 2024 19:27:00 -0500 Subject: [PATCH 3/4] Show exception message in profile saving --- src/g_gamedata.cpp | 3 ++- src/k_profiles.cpp | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 6fe481c5e..45b9c6384 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -304,7 +305,7 @@ void srb2::save_ng_gamedata() srb2::io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson))); file.close(); } - catch (const srb2::io::FileStreamException& ex) + catch (const std::exception& ex) { CONS_Alert(CONS_ERROR, "NG Gamedata save failed: %s\n", ex.what()); } diff --git a/src/k_profiles.cpp b/src/k_profiles.cpp index cc15ee1af..1dd491efc 100644 --- a/src/k_profiles.cpp +++ b/src/k_profiles.cpp @@ -12,6 +12,7 @@ /// \brief implements methods for profiles etc. #include +#include #include @@ -332,6 +333,10 @@ void PR_SaveProfiles(void) fs::rename(tmppath, realpath); } + catch (const std::exception& ex) + { + I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?\n\nException: %s", ex.what()); + } catch (...) { I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?"); From 0025e0fcfa2b214592d825bb6cbde93db72bbcd8 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 29 Apr 2024 13:38:46 -0500 Subject: [PATCH 4/4] Add random number to temp file names Mitigates against multiple instances trying to write to the same tmp file at the same time. --- src/g_gamedata.cpp | 3 ++- src/k_profiles.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 45b9c6384..bd2939c75 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -287,7 +287,8 @@ void srb2::save_ng_gamedata() std::string gamedataname_s {gamedatafilename}; fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)}; - fs::path tmpsavepath {fmt::format("{}/{}.tmp", srb2home, gamedataname_s)}; + int random_number = rand(); + fs::path tmpsavepath {fmt::format("{}/{}_{}.tmp", srb2home, gamedataname_s, random_number)}; json ngdata_json = ng; diff --git a/src/k_profiles.cpp b/src/k_profiles.cpp index 1dd491efc..89354bb1c 100644 --- a/src/k_profiles.cpp +++ b/src/k_profiles.cpp @@ -316,7 +316,8 @@ void PR_SaveProfiles(void) std::vector ubjson = json::to_ubjson(ng); std::string realpath = fmt::format("{}/{}", srb2home, PROFILESFILE); - std::string tmppath = fmt::format("{}.tmp", realpath); + int random_number = rand(); + std::string tmppath = fmt::format("{}_{}.tmp", realpath, random_number); try {