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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions