mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 10:00:27 +02:00
Save Config.toml through a temporary file and rename
The in-game settings bar rewrote Config.toml in place with a truncating open, so a crash or a full SD card mid-save could leave it empty or cut short. Settings are now written beside the file and renamed over it, and a file that exists but can't be read is no longer rewritten from nothing. Ported from BlackAndBlue95/Strikers-WiiCompiled 435daf3e (the runtime_config.h part only). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NKSMYZU43wUfYtm1sxGsC
This commit is contained in:
1 file changed
+38
-13
@@ -1064,14 +1064,24 @@ inline const std::optional<std::string>& ControllerButton(size_t index) {
|
||||
// user-specific paths. This is used by the in-game F10 settings bar.
|
||||
inline bool WriteSetting(std::string_view section, std::string_view key, std::string_view value) {
|
||||
const auto path = ResolveConfigPath();
|
||||
std::ifstream input(path);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
while (std::getline(input, line)) {
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
std::error_code existsError;
|
||||
if (std::filesystem::exists(path, existsError)) {
|
||||
// A file that's there but can't be read is not an empty one: rewriting it from nothing
|
||||
// would throw away every other setting.
|
||||
std::ifstream input(path);
|
||||
std::string line;
|
||||
while (input && std::getline(input, line)) {
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
if (!input.eof()) {
|
||||
std::cerr << "[runtime-config] Unable to read " << PathToUtf8(path) << "; not saving "
|
||||
<< key << std::endl;
|
||||
return false;
|
||||
}
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
|
||||
const std::string normalizedSection = Trim(section);
|
||||
@@ -1124,19 +1134,34 @@ inline bool WriteSetting(std::string_view section, std::string_view key, std::st
|
||||
}
|
||||
}
|
||||
|
||||
// Written beside the file and renamed over it, so a crash or a full disk mid-write leaves the
|
||||
// old file whole rather than a truncated one.
|
||||
std::error_code ec;
|
||||
if (path.has_parent_path()) {
|
||||
std::filesystem::create_directories(path.parent_path(), ec);
|
||||
}
|
||||
std::ofstream output(path, std::ios::trunc);
|
||||
if (!output) {
|
||||
std::cerr << "[runtime-config] Unable to write " << PathToUtf8(path) << std::endl;
|
||||
std::filesystem::path temporary = path;
|
||||
temporary += ".tmp";
|
||||
{
|
||||
std::ofstream output(temporary, std::ios::trunc);
|
||||
for (const auto& outputLine : lines) {
|
||||
output << outputLine << '\n';
|
||||
}
|
||||
output.close();
|
||||
if (!output) {
|
||||
std::cerr << "[runtime-config] Unable to write " << PathToUtf8(temporary) << std::endl;
|
||||
std::filesystem::remove(temporary, ec);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::filesystem::rename(temporary, path, ec);
|
||||
if (ec) {
|
||||
std::cerr << "[runtime-config] Unable to replace " << PathToUtf8(path) << ": " << ec.message()
|
||||
<< std::endl;
|
||||
std::filesystem::remove(temporary, ec);
|
||||
return false;
|
||||
}
|
||||
for (const auto& outputLine : lines) {
|
||||
output << outputLine << '\n';
|
||||
}
|
||||
return static_cast<bool>(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string FormatString(std::string_view value) {
|
||||
|
||||
Reference in new issue
Block a user