DEV Community

Masih Maafi
Masih Maafi

Posted on

Rustidian: checking for another writer before saving a note

Rustidian is a native notes app for Markdown files that I am building in Rust. This post shows how it saves a note without overwriting what another editor wrote.

Rustidian keeps notes as ordinary files. That means a second editor can write the same note while I have unsaved changes. A temporary file avoids a partial write, but the save must also check whether the text it replaces has changed.

This is a reading of the save path in the published 0.1.6 source. Here is the mechanism and its limit.

Remember what the edit started from

A pending save holds the edited text and the original text it expects to replace. Before writing, I read the note from disk and compare it with that original. This excerpt is from PendingSave::write:

let current = fs::read_to_string(&self.absolute).map_err(|e| {
    format!("Note was removed or cannot be read. Your changes are still open: {e}")
})?;
if current != self.original {
    return Err("This note changed outside Rustidian. Save your edits to a new note, or keep them here while reviewing the disk version. Nothing was overwritten.".into());
}
Enter fullscreen mode Exit fullscreen mode

If the disk text differs, the save returns an error. The app keeps the edited document open. I can review the disk version and preserve my edits separately.

Prepare the replacement beside the note

If the first comparison passes, prepare_file creates a temporary file in the note's directory. It writes the edited bytes, copies the note's permissions and calls sync_all on the temporary file.

Before replacing the note, the save reads the disk text again. This catches a change that arrived while the temporary file was being written. A mismatch returns an error; a match lets the temporary file replace the note.

The two checks serve different moments: before preparing the write, and after preparing it. The temporary file serves a different purpose: the replacement uses a prepared file rather than writing the new text directly over the old one.

The remaining race

There is still a gap between the second comparison and replacement. Another writer could change the file in that gap. These checks do not establish exclusive ownership of the file, and I would not treat this as a guarantee for simultaneous writers.

The distinction matters when reviewing a save routine: checking for a conflict and replacing a file atomically solve different parts of the problem. This implementation does both, with a remaining race between them.

Read it or try the released app

The tagged save code contains the comparisons and replacement. The app's save handling shows how the result reaches the open document.

For Linux x86_64 with glibc 2.39 or newer (Ubuntu 24.04 or newer), download the Debian package and checksums, then use the README's commands:

sha256sum --check --ignore-missing SHA256SUMS
sudo apt install ./rustidian-linux-amd64.deb
rustidian
Enter fullscreen mode Exit fullscreen mode

Try a copy of your notes first. The tagged README has the setup instructions and current feature limits.

Top comments (0)