fix(server/game): write saves through a temp file

This commit is contained in:
capyb2222 committed 2026-09-12 20:30:27 -07:00
1 parent c16c95db94
commit cc7ec21ab9
2 files changed
+35 -6

No files matched your search

+25 -6
View File
@@ -175,15 +175,34 @@ std::string readFile(const std::string& path, bool* ok) {
}
bool writeFile(const std::string& path, std::string_view data) {
std::filesystem::path p(path);
if (p.has_parent_path()) {
std::filesystem::path target(path);
std::error_code ec;
std::filesystem::create_directories(p.parent_path(), ec);
}
std::ofstream out(path, std::ios::binary | std::ios::trunc);
if (target.has_parent_path()) std::filesystem::create_directories(target.parent_path(), ec);
auto writeTo = [data](const std::filesystem::path& file) {
std::ofstream out(file, std::ios::binary | std::ios::trunc);
if (!out) return false;
out.write(data.data(), static_cast<std::streamsize>(data.size()));
return out.good();
out.close();
return !out.fail();
};
// Written beside the target and moved over it in one step, so a crash mid-write leaves
// the old file whole instead of cut short.
std::filesystem::path temp = target;
temp += ".tmp";
if (writeTo(temp)) {
#ifdef _WIN32
if (MoveFileExW(temp.c_str(), target.c_str(), MOVEFILE_REPLACE_EXISTING)) return true;
#else
std::filesystem::rename(temp, target, ec);
if (!ec) return true;
#endif
}
std::filesystem::remove(temp, ec);
// Something is holding the target in a way that blocks the move; a direct write still
// beats dropping the save.
return writeTo(target);
}
std::string executableDir() {
+10
View File
@@ -311,6 +311,15 @@ void testLogFormat() {
"the banner names its rows");
}
void testSafeWrite() {
const std::string path = "build/test-safe-write.json";
check(util::writeFile(path, "first"), "a file writes");
check(util::writeFile(path, "second, and longer"), "and overwrites");
bool ok = false;
check(util::readFile(path, &ok) == "second, and longer" && ok, "with the new content whole");
check(!util::fileExists(path + ".tmp"), "leaving no temp file behind");
}
} // namespace
int main() {
@@ -324,6 +333,7 @@ int main() {
testLineupCmdIds();
testIdleTimeout();
testLogFormat();
testSafeWrite();
testFillPresence();
testLargeMessage();
testAgainstProtoc();