Skip to content

FS durability API: fsync(path) and sync() - #46

Merged
dsent merged 1 commit into
aldum:devfrom
Vadim1987:feat/fs-durability
Jul 22, 2026
Merged

FS durability API: fsync(path) and sync()#46
dsent merged 1 commit into
aldum:devfrom
Vadim1987:feat/fs-durability

Conversation

@Vadim1987

Copy link
Copy Markdown

Platform-level half of the durable-writes work, split out of #45 at
dsent's request — this is shared FS API, not editor code.
Adds FS.fsync(path) and FS.sync() over a pcall-guarded LuaJIT FFI cdef,
degrading to a no-op where the syscalls are unavailable, plus
whole-filesystem sync on love.quit and on focus/visible loss. FS.write
stays async by contract (bulk deploy/clone and writefile must not stall
on the card); durability is an explicit opt-in for callers that promise
it — the editor's accept path in #45 is the first consumer.
Motivated by real data loss on the device's exfat-dirsync SD card:
the directory entry survived a force-stop while the contents vanished.
#45 depends on this (its tail carries the same API commit so the branch
stays self-contained; merging this first will dedup cleanly).

Platform-level half of the durable-writes work, split out
of the editor series at the maintainer level: this is
shared FS API, not editor code.

- util/filesystem.lua: FS.fsync(path) and FS.sync() over
  a pcall-guarded LuaJIT FFI cdef (open/fsync/close/
  sync), degrading to a no-op where the syscalls are
  unavailable. FS.write stays async by contract — bulk
  deploy/clone and the user-facing writefile must not
  stall on the card — with durability as an explicit
  opt-in for callers that promise it. Vendored nativefs
  is untouched.
- controller/controller.lua: whole-filesystem sync() on
  love.quit, plus focus(false)/visible(false) handlers,
  previously skipped, that sync when the app goes to
  the background.

Split from c5866b2 (the editor's per-accept fsync and
save-failure refusal follow in the editor series, which
consumes this API).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011WEJighCCuSFparAVqjsWH
local function focus(f)
if not f then FS.sync() end
end
love.focus = focus

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this for? Do we have multi-app scenarios?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, probably just over-defensiveness that is typical for Claude. Should we remove it?

@aldum aldum left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I did not think OS-level disk flushes were the abstraction level we needed to operate at, but alas, better than losing data.
I do have a question though, how does (or not) this work on other platforms, like JS/WASM?
(not a blocker, just interested)

@dsent

dsent commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

@aldum I'll put it into my backlog to test with web and Linux versions.

@dsent
dsent merged commit 9cb27e0 into aldum:dev Jul 22, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants