summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/archive.rs44
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,