1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
use std::fs::{self, File};
use std::io;
use std::path::PathBuf;
use anyhow::*;
use log::*;
use memmap2::Mmap;
use rayon::prelude::*;
use structopt::*;
use piz::read::*;
#[derive(Debug, StructOpt)]
#[structopt(name = "unzip", about = "Dumps a .zip file into the current directory")]
struct Opt {
/// Pass multiple times for additional verbosity (info, debug, trace)
#[structopt(short, long, parse(from_occurrences))]
verbosity: usize,
/// Change to the given directory before perfoming any operations.
#[structopt(short = "C", long)]
directory: Option<PathBuf>,
/// Prints the tree of files in the ZIP archive instead of extracting them.
#[structopt(short = "n", long)]
dry_run: bool,
#[structopt(name("ZIP file"))]
zip_path: PathBuf,
}
fn main() -> Result<()> {
let args = Opt::from_args();
let mut errlog = stderrlog::new();
errlog.verbosity(args.verbosity + 1);
errlog.init()?;
if let Some(chto) = args.directory {
std::env::set_current_dir(&chto)
.with_context(|| format!("Couldn't set working directory to {}", chto.display()))?;
}
info!("Memory mapping {:#?}", &args.zip_path);
let zip_file = File::open(&args.zip_path).context("Couldn't open zip file")?;
let mapping = unsafe { Mmap::map(&zip_file).context("Couldn't mmap zip file")? };
let archive = ZipArchive::with_prepended_data(&mapping)
.context("Couldn't load archive")?
.0;
let tree = as_tree(archive.entries())?;
if args.dry_run {
print_tree(&tree)
} else {
read_zip(&tree, &archive)
}
}
fn print_tree(tree: &DirectoryContents) -> Result<()> {
for entry in tree.traverse() {
println!("{}", entry.metadata().path);
}
Ok(())
}
fn read_zip(tree: &DirectoryContents, archive: &ZipArchive) -> Result<()> {
tree.files().par_bridge().try_for_each(|entry| {
if let Some(parent) = entry.path.parent() {
fs::create_dir_all(parent)
.with_context(|| format!("Couldn't create directory {}", parent))?;
}
let mut reader = archive.read(entry)?;
let mut sink = File::create(&*entry.path)
.with_context(|| format!("Couldn't create file {}", entry.path))?;
io::copy(&mut reader, &mut sink)?;
Ok(())
})
}
|