From 90a1adac54c083026d81eddc9e74b1d64754e5af Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Sun, 24 Sep 2023 11:27:59 +0200 Subject: [PATCH] tool: fix atomic write Atomic write works by first writing a temporary file, then syncing that temporary file to ensure it is fully on disk before the program can continue, and in the last step renaming the temporary file to the target. The middle step was missing, which is likely to lead to a truncated target file being present after power loss. Add this step. Furthermore, even with this fix, atomicity is not fully guaranteed, because FAT32 can become corrupted after power loss due to its design shortcomings. Even though we cannot really do anything about this case, adjust the comment to at least acknowledge the situation. --- rust/tool/systemd/src/install.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/rust/tool/systemd/src/install.rs b/rust/tool/systemd/src/install.rs index b04ad1b..2db01a7 100644 --- a/rust/tool/systemd/src/install.rs +++ b/rust/tool/systemd/src/install.rs @@ -465,17 +465,29 @@ fn assemble_kernel_cmdline(init: &Path, kernel_params: Vec) -> Vec Result<()> { - let to_tmp = to.with_extension(".tmp"); - - fs::copy(from, &to_tmp) - .with_context(|| format!("Failed to copy from {from:?} to {to_tmp:?}",))?; - - fs::rename(&to_tmp, to).with_context(|| { - format!("Failed to move temporary file {to_tmp:?} to final location {to:?}") - }) + let tmp = to.with_extension(".tmp"); + { + let mut from_file = + File::open(from).with_context(|| format!("Failed to read the source file {from:?}"))?; + let mut tmp_file = File::create(&tmp) + .with_context(|| format!("Failed to create the temporary file {tmp:?}"))?; + std::io::copy(&mut from_file, &mut tmp_file).with_context(|| { + format!("Failed to copy from {from:?} to the temporary file {tmp:?}") + })?; + tmp_file + .sync_all() + .with_context(|| format!("Failed to sync the temporary file {tmp:?}"))?; + } + fs::rename(&tmp, to) + .with_context(|| format!("Failed to move temporary file {tmp:?} to target {to:?}")) } /// Set the octal permission bits of the specified file.