42 lines
1.3 KiB
Rust
42 lines
1.3 KiB
Rust
use std::{fs, io::{self}, path::{Path, PathBuf}};
|
|
use zip::read::ZipArchive;
|
|
|
|
pub fn extract_zip(src: &Path, dest: &Path) -> io::Result<()> {
|
|
let file = fs::File::open(src)?;
|
|
let mut archive = ZipArchive::new(file)?;
|
|
fs::create_dir_all(dest)?;
|
|
|
|
for i in 0..archive.len() {
|
|
let mut entry = archive.by_index(i)?;
|
|
let outpath = dest.join(sanitize_path(entry.name()));
|
|
|
|
if entry.is_dir() {
|
|
fs::create_dir_all(&outpath)?;
|
|
} else {
|
|
if let Some(p) = outpath.parent() { fs::create_dir_all(p)?; }
|
|
let mut outfile = fs::File::create(&outpath)?;
|
|
io::copy(&mut entry, &mut outfile)?;
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
if let Some(mode) = entry.unix_mode() {
|
|
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode))?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn sanitize_path(name: &str) -> PathBuf {
|
|
let path = Path::new(name);
|
|
let mut clean = PathBuf::new();
|
|
for comp in path.components() {
|
|
use std::path::Component::*;
|
|
match comp {
|
|
Normal(c) => clean.push(c),
|
|
CurDir | ParentDir | RootDir | Prefix(_) => { /* skip */ }
|
|
}
|
|
}
|
|
clean
|
|
}
|