From 0d7d9ebd000152eb0107b0fbf540d4b37cd48b1c Mon Sep 17 00:00:00 2001 From: Ridzzz0Alam Date: Mon, 26 Oct 2026 11:46:23 +0100 Subject: [PATCH] M1: stamp the file before reading it, so a change made during the read isn't missed (#1330) Open and Revert to saved recorded the file's size and modification time after reading it: a change written in between would be stamped as already loaded and a later save would replace it. Taking the stamp first makes such a change refuse the next save instead (CodeRabbit on #1374). --- crates/engine/src/cmd/file.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/file.rs b/crates/engine/src/cmd/file.rs index 2511d92f..e9caaa63 100644 --- a/crates/engine/src/cmd/file.rs +++ b/crates/engine/src/cmd/file.rs @@ -159,6 +159,8 @@ pub fn specs() -> Vec { }), spec!("file.revert", "Revert to saved", "{} leave the live session first, if any", false, |s, _| { let path = s.ds()?.path.clone().ok_or_else(|| EngineError::Disabled("file.revert".into(), "the file was never saved".into()))?; + // Stamped before reading: a change made during the read makes the next save refuse. + let on_disk = crate::library::stat(&path).ok(); let (loaded, _) = load_path(&path, None)?; let i = s.active; let uid = s.ds()?.uid; @@ -167,7 +169,7 @@ pub fn specs() -> Vec { .with_versions(loaded.versions) .with_branches(loaded.branches) .with_images_left_in_file(&path, loaded.images_past_budget); - slot.note_on_disk(); + slot.on_disk = on_disk; } // Edits on its branch tabs are reverted too. crate::branches::close_tabs(s, uid, None); @@ -946,6 +948,8 @@ fn open(s: &mut Session, p: &Value) -> Result { remember(s, &path); return Ok(json!({"index": i})); } + // Stamped before reading: a change made during the read makes the next save refuse. + let on_disk = crate::library::stat(&path).ok(); let (loaded, rest) = load_path(&path, variables.as_ref())?; remember(s, &path); let native = !rest && matches!(ext(&path).as_str(), "figcraft" | "json"); @@ -963,7 +967,7 @@ fn open(s: &mut Session, p: &Value) -> Result { .with_versions(loaded.versions) .with_branches(loaded.branches) .with_images_left_in_file(&path, images_left_out); - ds.note_on_disk(); + ds.on_disk = on_disk.filter(|_| native); s.docs.push(ds); s.active = s.docs.len() - 1; let mut out = json!({"index": s.active, "summary": summary});