From 3ae19e21681bdc76afe3a5156bcc5345f04ecf94 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Wed, 30 Apr 2025 15:30:57 +0200 Subject: [PATCH] fix(backup): work with temporary file while writing json metadata file --- CHANGELOG.md | 5 +++++ backup/src/manager/mod.rs | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5305b42..810214c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev) +## Fixed + +* Fix bug where JSON metadata file can be corrupted if crash occurs while + writing (data is now written to a temporary file before atomically renaming) + ## [0.4.1](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.4.1) ### Changed diff --git a/backup/src/manager/mod.rs b/backup/src/manager/mod.rs index ec91a3d..f8bbc73 100644 --- a/backup/src/manager/mod.rs +++ b/backup/src/manager/mod.rs @@ -122,10 +122,24 @@ where } /// Write the in-memory state to disk. + /// + /// The state is first written to a temporary file before being (atomically, depending on the + /// file system) renamed to the final path. pub fn save(&self) -> io::Result<()> { - let json_file = File::create(self.backup_dir.join(Self::METADATA_FILE))?; + let dest_path = self.backup_dir.join(Self::METADATA_FILE); + + let dest_ext = dest_path + .extension() + .map(|ext| ext.to_string_lossy().to_string()) + .unwrap_or(String::new()); + let temp_path = dest_path.with_extension(format!("{dest_ext}.temp")); + + let json_file = File::create(&temp_path)?; serde_json::to_writer(json_file, &self.chains)?; + // Rename temp file to the destination path after writing was successful + std::fs::rename(temp_path, dest_path)?; + Ok(()) }