use std::{
io,
path::{Component, Path},
};
use crate::EngineError;
pub fn write_tar_sync(root_dir: &Path, out: &mut impl io::Write) -> Result<u64, io::Error> {
let mut builder = tar::Builder::new(out);
builder.follow_symlinks(false);
builder.append_dir_all(".", root_dir)?;
builder.finish()?;
Ok(0)
}
pub fn extract_tar_sync(input: impl io::Read, output_dir: &Path) -> Result<(), EngineError> {
let mut archive = tar::Archive::new(input);
for entry in archive.entries().map_err(EngineError::Io)? {
let mut entry = entry.map_err(EngineError::Io)?;
let entry_path = entry.path().map_err(EngineError::Io)?;
if entry_path.is_absolute() {
return Err(EngineError::PathTraversal);
}
for component in entry_path.components() {
if matches!(component, Component::ParentDir) {
return Err(EngineError::PathTraversal);
}
}
let dest = output_dir.join(&entry_path);
if !dest.starts_with(output_dir) {
return Err(EngineError::PathTraversal);
}
entry.unpack(&dest).map_err(EngineError::Io)?;
}
Ok(())
}
pub fn estimate_dir_size(root_dir: &Path) -> u64 {
walkdir::WalkDir::new(root_dir)
.follow_links(false)
.into_iter()
.filter_map(std::result::Result::ok)
.filter(|e| e.file_type().is_file())
.filter_map(|e| e.metadata().ok())
.map(|m| m.len())
.sum()
}