fix(persistence): atomic + owner-only settings/address-book writes
settings.json and addressbook.json were written in place with a bare ofstream — a crash or power loss mid-write truncated the file, and on the next launch the parse failure silently reset every preference (hidden/favorite addresses, labels, pool workers, language, theme, lite-server list) because the next save overwrote the corrupt file with defaults. Add Platform::writeFileAtomically() (temp file -> fsync -> atomic rename; dir fsync on POSIX, MoveFileEx on Windows; optional owner-only 0600) and route both saves through it. On a parse failure, quarantine the unreadable settings file to settings.json.corrupt-<ts> instead of clobbering it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <filesystem>
|
||||
|
||||
#include "../util/logger.h"
|
||||
#include "../util/platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h>
|
||||
@@ -113,20 +114,16 @@ bool AddressBook::save()
|
||||
j["entries"].push_back(e);
|
||||
}
|
||||
|
||||
// Ensure directory exists
|
||||
fs::path p(file_path_);
|
||||
fs::create_directories(p.parent_path());
|
||||
|
||||
std::ofstream file(file_path_);
|
||||
if (!file.is_open()) {
|
||||
DEBUG_LOGF("Could not open address book for writing: %s\n", file_path_.c_str());
|
||||
// Atomic + durable: temp file + fsync + rename, so a crash mid-write can't
|
||||
// truncate addressbook.json (which is fully rewritten on every entry change).
|
||||
// Owner-only (0600) — it holds the user's saved contacts.
|
||||
if (!util::Platform::writeFileAtomically(file_path_, j.dump(2), /*restrictPermissions=*/true)) {
|
||||
DEBUG_LOGF("Could not write address book: %s\n", file_path_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
file << j.dump(2);
|
||||
DEBUG_LOGF("Address book saved: %zu entries\n", entries_.size());
|
||||
return true;
|
||||
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG_LOGF("Error saving address book: %s\n", e.what());
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user