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 }