diff options
Diffstat (limited to 'src/archive.rs')
| -rw-r--r-- | src/archive.rs | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/src/archive.rs b/src/archive.rs index 70392fa..9a899bf 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; -use std::fs::{self, File}; +use std::fs::{self, File, OpenOptions}; use std::os::unix::fs::MetadataExt; -use std::path::Path; +use std::path::{Path, PathBuf}; use anyhow::{bail, Context, Result}; use tar::{Builder, EntryType, Header}; @@ -26,16 +26,42 @@ impl NativeTarWriter { } let output = output.as_ref(); - let file = File::create(output).with_context(|| format!("create archive {}", output.display()))?; - let mut archive = Builder::new(file); - append_tree(&mut archive, rootfs, Path::new(""), &mut BTreeMap::new())?; - archive - .finish() - .with_context(|| format!("finish archive {}", output.display()))?; - Ok(()) + let temporary = temporary_output_path(output)?; + let result = (|| { + let file = OpenOptions::new() + .write(true) + .create_new(true) + .open(&temporary) + .with_context(|| format!("create temporary archive {}", temporary.display()))?; + let mut archive = Builder::new(file); + append_tree(&mut archive, rootfs, Path::new(""), &mut BTreeMap::new())?; + archive + .finish() + .with_context(|| format!("finish archive {}", temporary.display()))?; + fs::rename(&temporary, output).with_context(|| { + format!( + "publish completed archive {} as {}", + temporary.display(), + output.display() + ) + }) + })(); + if result.is_err() { + let _ = fs::remove_file(&temporary); + } + result } } +fn temporary_output_path(output: &Path) -> Result<PathBuf> { + let name = output + .file_name() + .ok_or_else(|| anyhow::anyhow!("archive output path has no filename: {}", output.display()))?; + let mut temporary_name = name.to_os_string(); + temporary_name.push(".partial"); + Ok(output.with_file_name(temporary_name)) +} + fn append_tree( archive: &mut Builder<File>, rootfs: &Path, |