use crate::{
Fmt,
error::{ArchiveError, Result},
human_size,
};
use path_clean::PathClean;
use std::path::Path;
fn write_file_entry(output_path: &Path, file: &crate::File) -> Result<()> {
let output_path = output_path.clean();
if let Some(dir) = output_path.parent()
&& !dir.as_os_str().is_empty()
&& !dir.exists()
{
std::fs::create_dir_all(dir).map_err(|e| {
ArchiveError::io_context(e, format!("failed to create directory '{}'", dir.display()))
})?;
}
if file.is_dir {
if !output_path.exists() {
std::fs::create_dir_all(&output_path).map_err(|e| {
ArchiveError::io_context(
e,
format!("failed to create directory '{}'", output_path.display()),
)
})?;
}
return Ok(());
}
std::fs::write(&output_path, &file.buffer).map_err(|e| {
ArchiveError::io_context(
e,
format!("failed to write file '{}'", output_path.display()),
)
})?;
#[cfg(unix)]
if let Some(mode) = file.mode {
use std::os::unix::fs::PermissionsExt;
if let Err(e) =
std::fs::set_permissions(&output_path, std::fs::Permissions::from_mode(mode))
{
eprintln!(
"Warning: Failed to set permissions for '{}': {}",
output_path.display(),
e
);
}
}
Ok(())
}
pub fn handle_decompression(input: &str, output: &str, fmt: Fmt) -> Result<()> {
let buffer = std::fs::read(input).map_err(|e| {
ArchiveError::io_context(e, format!("failed to read input file '{}'", input))
})?;
let files = fmt.decode(buffer)?;
let mut total_size = 0;
let file_count = files.len();
for file in &files {
total_size += file.buffer.len();
}
println!("{} of {} files", human_size(total_size), file_count);
println!("Decompressing to {}", output);
if fmt.is_single_file() {
if let Some(file) = files.first() {
write_file_entry(Path::new(output), file)?;
}
println!("Decompression complete!");
return Ok(());
}
for file in &files {
let output_path = Path::new(output).clean();
let output_path = output_path.join(&file.path).clean();
let dir = output_path
.parent()
.expect("Failed to get parent directory");
if !dir.exists() {
std::fs::create_dir_all(dir).map_err(|e| {
ArchiveError::io_context(
e,
format!("failed to create directory '{}'", dir.display()),
)
})?;
}
if file.is_dir && !output_path.exists() {
std::fs::create_dir_all(&output_path).map_err(|e| {
ArchiveError::io_context(
e,
format!("failed to create directory '{}'", output_path.display()),
)
})?;
}
if !file.is_dir && !file.buffer.is_empty() {
std::fs::write(&output_path, &file.buffer).map_err(|e| {
ArchiveError::io_context(
e,
format!("failed to write file '{}'", output_path.display()),
)
})?;
}
#[cfg(unix)]
if let Some(mode) = file.mode {
use std::os::unix::fs::PermissionsExt;
if let Err(e) =
std::fs::set_permissions(&output_path, std::fs::Permissions::from_mode(mode))
{
eprintln!(
"Warning: Failed to set permissions for '{}': {}",
output_path.display(),
e
);
}
}
}
println!("Decompression complete!");
Ok(())
}