Skip to content

Desktop atomic writes: fsync temp file + parent directory before/after rename for true crash durability #357

Description

@qnbs

Raised by chatgpt-codex-connector during the #354 review correction loop (thread: #354 (comment) area — see PR #354 for full context).

The gap

services/fs/fsCore.ts's writeTextFileAtomic/writeFileAtomic (added in #354) write to a temp file then rename over the final path, closing the "torn/partial write" class of bug. But in the abrupt power-loss scenario specifically, this isn't a complete durability guarantee: awaiting @tauri-apps/plugin-fs's writeTextFile/writeFile only completes the equivalent of write_all() — it doesn't call fsync/sync_all(), and a rename is not itself a durability barrier on most filesystems. The OS can still hold the new content (and the directory-entry update from the rename) in a page cache buffer that hasn't hit stable storage. A reboot at exactly the wrong moment could in theory expose an empty, partial, or still-the-old-file state despite the JS-level await having already resolved.

Why not fixed in #354

The real fix needs a Rust-side Tauri command (JS-level plugin-fs doesn't expose fsync control): open the temp file, write, sync_all(), close, rename, then open and sync the parent directory too (POSIX best practice for a rename to be durable, not just atomic). This is meaningfully more surface area than a JS-only PR — new Rust command, capability wiring, and it can't be meaningfully tested in this environment (no practical way to build/run a packaged Tauri desktop app here to verify real fsync behavior under simulated power loss).

Scope for whoever picks this up

  • New Tauri command (e.g. write_file_durable) in src-tauri/src/commands/, wrapping write + sync_all() + rename + parent-dir sync.
  • Register in lib.rs, wire capability permissions.
  • Swap fsCore.ts's writeTextFileAtomic/writeFileAtomic to call it via invoke() instead of the plugin-fs JS API, on Tauri only (web build has no equivalent concept).
  • Needs rust-check (PR ci: add required Rust/Tauri compile gate on pull requests #353's new CI gate) to at least catch compile/lint issues; real durability behavior can only be verified on a packaged build under actual (or simulated, e.g. SIGKILL mid-write in a controlled test) power-loss conditions.

Lower priority than the torn-write fix already shipped in #354 — this hardens an already-real improvement further, it doesn't fix a regression.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions