Let an Explicit Config Save Bypass the Back-Off and Lock the Scan's Failure Cleanup

The ten-second back-off after a failed config write sat inside save()
itself, so the save on exit could return without writing and lose the
session's changes; it gates only the idle-time save now, through
save_due(), and an explicit save always tries.

The preset scan's failure handlers removed a broken preset and its .info
after the per-file guard had ended, so another instance's fresh copy of
that file could be deleted from under it; they take the guard too. A
lock that is acquired ends the cool-down a timeout started, rather than
letting every guard for the rest of it proceed unlocked whenever the
lock is momentarily held. The lock file's identity is checked on every
acquisition, one stat, since a handle to a replaced file locks nothing
anyone else can see. Write access on Windows is probed with an open for
writing, which sees ACLs where _waccess sees only the read-only
attribute, and a temporary name too long for the filesystem falls back
to an in-place write for a new file as well as an existing one. The lock
tests restore the knobs they change however they end.
This commit is contained in:
Hanif Koh
2026-09-24 23:52:29 +08:00
parent b7102a524b
commit a4c925a445
8 changed files with 31 additions and 20 deletions
+4 -2
View File
@@ -131,6 +131,9 @@ public:
// Does this config need to be saved?
bool dirty() const { return m_dirty; }
// False for ten seconds after a failed write, so the idle handler does not
// repeat a hopeless attempt on every event; an explicit save() always tries.
bool save_due() const { return std::chrono::steady_clock::now() >= m_retry_save_at; }
void set_dirty() { m_dirty = true; }
@@ -458,8 +461,7 @@ private:
bool write_config_file(const std::string &path, std::string body, const std::string &checksum_source);
bool m_dirty;
// After a failed write, save() does nothing until this point, so the idle
// handler does not repeat the attempt on every event.
// After a failed write, save_due() is false until this point.
std::chrono::steady_clock::time_point m_retry_save_at{};
// Original version found in the ini file before it was overwritten
Semver m_orig_version;