Home

dev / openkara

publicthedavidweng/OpenKara· sync paused
Overview Code History Branches Pull requestsIssuesInsights
main
HomeOverview Code PRsIssues

fix(config): atomic write + corruption recovery to end the boot brick (#208) (#211)

2 months ago

cd520d8
Authored
Davy7/25/2026, 7:10:47 PM
* fix(config): atomic write + corruption recovery to end the boot brick (#208)

`save_config` truncated-then-wrote config.json in place with a plain
`fs::write` — no temp file, no fsync, no atomic rename. A kill, OS sleep,
or power loss mid-write (or a concurrent settings save) left config.json
0-length or partial. `load_config` then returned `Err` on any parse
failure and `setup_app` propagated it with `?`, aborting Tauri startup.
The result was an unrecoverable boot brick from a single interrupted
save: all settings lost AND the app refused to launch on every run.

- save_config now writes to a unique sibling temp, fsyncs it, atomically
  renames over config.json, then fsyncs the parent dir — reusing the
  write-temp + fsync + rename pattern from remote::atomic_download. A
  crash at any point leaves the previous config fully intact or the new
  one fully written, never a truncated file. Unique temp names also make
  two racing saves unable to interleave bytes into one renamed file.
- load_config now quarantines an unparseable config.json to
  config.json.corrupt-<unix-millis>, logs a warning, and returns
  Ok(None) so callers fall back to defaults instead of erroring. This
  covers 0-length, truncated, and garbage files.
- setup_app treats any config load error as recoverable (defaults +
  warning) rather than `?`-aborting startup.

Tests: corrupt/empty config recovers to Ok(None) and is quarantined;
post-recovery save round-trips; an interrupted save (bytes only in the
temp) leaves the committed config byte-for-byte intact; successful saves
leave no temp residue and overwrite cleanly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(settings): inject persistence failure at the config directory (#208)

The two EQ persistence-failure tests made config.json itself read-only to
force save_config to fail. The atomic write introduced in this branch
replaces config.json via a temp-file + rename, and on Unix rename is
governed by the directory's write bit, not the target file's — so a
read-only file no longer fails the save. The tests saw an unexpected
success and panicked (settings.rs:955/:1013), and the coordinator revert
command was never sent, panicking the responder task (settings.rs:677/:696).

Switch the injection to a read-only config directory (0o555), which fails
the atomic save's temp-file create and genuinely drives the
persist-fail -> coordinator-revert path. Directory permissions are
restored afterward so TempDir cleanup succeeds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

Parentf1afa6e

3 files changed
  • src-tauri/src/app_runtime.rs+15−6
  • src-tauri/src/commands/settings.rs+29−24
  • src-tauri/src/config.rs+280−3