Skip to content

Commit

Permalink
Merge pull request #2 from Mic92/fix-atomic-write
Browse files Browse the repository at this point in the history
Fix atomic write
  • Loading branch information
nikstur authored Sep 9, 2024
2 parents 122e54f + 54b0fbf commit b9f7007
Showing 1 changed file with 23 additions and 9 deletions.
32 changes: 23 additions & 9 deletions rust/userborn/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,33 @@ use anyhow::{Context, Result};
///
/// This increases the atomicity of the write.
pub fn atomic_write(path: impl AsRef<Path>, buffer: impl AsRef<[u8]>, mode: u32) -> Result<()> {
let mut tmp_path = path.as_ref().as_os_str().to_os_string();
tmp_path.push(".tmp");
let mut i = 0;

let mut file = fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.mode(mode)
.open(&tmp_path)
.with_context(|| format!("Failed to open {tmp_path:?}"))?;
let (mut file, tmp_path) = loop {
let mut tmp_path = path.as_ref().as_os_str().to_os_string();
tmp_path.push(format!(".tmp{i}"));

let res = fs::OpenOptions::new()
.write(true)
.create_new(true)
.truncate(true)
.mode(mode)
.open(&tmp_path);
match res {
Ok(file) => break (file, tmp_path),
Err(err) => {
if err.kind() != std::io::ErrorKind::AlreadyExists {
return Err(err).context(format!("Failed to open temporary file {tmp_path:?}"));
}
}
}
i += 1;
};

file.write_all(buffer.as_ref())
.with_context(|| format!("Failed to write to {tmp_path:?}"))?;
file.sync_all()
.with_context(|| format!("Failed to sync the temporary file {tmp_path:?}"))?;

fs::rename(&tmp_path, &path)
.with_context(|| format!("Failed to rename {tmp_path:?} to {:?}", path.as_ref()))?;
Expand Down

0 comments on commit b9f7007

Please sign in to comment.