feat: enhance safety and crash resilience in file operations; add fsync to critical writes and checks for path traversal
This commit is contained in:
@@ -50,13 +50,16 @@ impl Session {
|
||||
self.session_dir(base_dir).join("conversation.json")
|
||||
}
|
||||
|
||||
/// Persist this session's metadata to `session.json`, atomically.
|
||||
/// Persist this session's metadata to `session.json`, atomically
|
||||
/// with fsync for crash safety.
|
||||
///
|
||||
/// Flow: ensure the session directory exists → serialize to pretty
|
||||
/// JSON → write to `session.json.tmp` → rename over `session.json`.
|
||||
/// JSON → write to `session.json.tmp` → fsync → rename over
|
||||
/// `session.json` → fsync parent directory.
|
||||
///
|
||||
/// Why: write-then-rename avoids a torn/partial `session.json` if
|
||||
/// interrupted mid-write.
|
||||
/// interrupted mid-write; fsync before rename ensures the data is
|
||||
/// on disk before the rename makes it visible.
|
||||
///
|
||||
/// Return: `Ok(())` on success, or an `io::Error` from any step.
|
||||
pub fn save(&self, base_dir: &Path) -> std::io::Result<()> {
|
||||
@@ -66,7 +69,10 @@ impl Session {
|
||||
let data = serde_json::to_string_pretty(self)?;
|
||||
let tmp = dir.join("session.json.tmp");
|
||||
std::fs::write(&tmp, data)?;
|
||||
let f = std::fs::File::open(&tmp)?;
|
||||
f.sync_all()?;
|
||||
std::fs::rename(&tmp, path)?;
|
||||
let _ = std::fs::File::open(&dir).and_then(|d| d.sync_all());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user