zip-rs does not support symbolic link yet(https://github.com/zip-rs/zip/issues/77). However it is possible by using public APIs as below.
use std::fs; use std::io; fn main() { std::process::exit(real_main()); } fn real_main() -> i32 { let args: Vec<_> = std::env::args().collect(); if args.len() < 2 { println!("Usage: {} <filename>", args[0]); return 1; } let fname = std::path::Path::new(&*args[1]); let file = fs::File::open(&fname).unwrap(); let mut archive = zip::ZipArchive::new(file).unwrap(); for i in 0..archive.len() { let mut file = archive.by_index(i).unwrap(); let outpath = match file.enclosed_name() { Some(path) => path.to_owned(), None => continue, }; { let comment = file.comment(); if !comment.is_empty() { println!("File {} comment: {}", i, comment); } } if (&*file.name()).ends_with('/') { println!("File {} extracted to \"{}\"", i, outpath.display()); fs::create_dir_all(&outpath).unwrap(); } else { println!( "File {} extracted to \"{}\" ({} bytes)", i, outpath.display(), file.size() ); if let Some(p) = outpath.parent() { if !p.exists() { fs::create_dir_all(&p).unwrap(); } } let is_symlink = if cfg!(unix) { const S_IFLINK: u32 = 0o120000; file.unix_mode().unwrap() & S_IFLINK == S_IFLINK } else { false }; if is_symlink { #[cfg(unix)] { use std::io::Read; use std::os::unix::fs; let mut data = Vec::new(); file.read_to_end(&mut data).unwrap(); let original = String::from_utf8(data).unwrap(); fs::symlink(original, outpath).unwrap(); } } else { let mut outfile = fs::File::create(&outpath).unwrap(); io::copy(&mut file, &mut outfile).unwrap(); // Get and Set permissions #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; if let Some(mode) = file.unix_mode() { fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).unwrap(); } } } } } return 0; }