feat: support decompress and list zip file

This commit is contained in:
ttyS3 2024-03-24 06:25:25 +00:00 committed by João Marcos
parent 75e16510df
commit d21db763f1
5 changed files with 93 additions and 10 deletions

67
Cargo.lock generated
View File

@ -110,6 +110,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bit-set"
version = "0.5.3"
@ -353,6 +359,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "core_affinity"
version = "0.8.1"
@ -455,6 +467,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
@ -639,6 +652,15 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "ignore"
version = "0.4.22"
@ -951,6 +973,29 @@ dependencies = [
"syn",
]
[[package]]
name = "password-hash"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "pbkdf2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
dependencies = [
"digest",
"hmac",
"password-hash",
"sha2",
]
[[package]]
name = "pin-project"
version = "1.1.5"
@ -1246,6 +1291,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.8"
@ -1319,6 +1375,12 @@ dependencies = [
"syn",
]
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.77"
@ -1743,10 +1805,15 @@ version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
dependencies = [
"aes",
"byteorder",
"constant_time_eq",
"crc32fast",
"crossbeam-utils",
"flate2",
"hmac",
"pbkdf2",
"sha1",
"time",
]

View File

@ -34,7 +34,7 @@ tempfile = "3.10.1"
time = { version = "0.3.36", default-features = false }
unrar = { version = "0.5.6", optional = true }
xz2 = "0.1.7"
zip = { version = "0.6.6", default-features = false, features = ["time"] }
zip = { version = "0.6.6", default-features = false, features = ["time", "aes-crypto"] }
zstd = { version = "0.13.2", default-features = false, features = ["zstdmt"]}
[target.'cfg(not(unix))'.dependencies]

View File

@ -9,12 +9,14 @@ use std::{
sync::mpsc,
thread,
};
use bstr::ByteSlice;
use filetime_creation::{set_file_mtime, FileTime};
use fs_err as fs;
use same_file::Handle;
use time::OffsetDateTime;
use zip::{read::ZipFile, DateTime, ZipArchive};
use zip::{self, read::ZipFile, DateTime, ZipArchive};
use zip::result::InvalidPassword;
use crate::{
error::FinalError,
@ -28,7 +30,7 @@ use crate::{
/// Unpacks the archive given by `archive` into the folder given by `output_folder`.
/// Assumes that output_folder is empty
pub fn unpack_archive<R>(mut archive: ZipArchive<R>, output_folder: &Path, quiet: bool) -> crate::Result<usize>
pub fn unpack_archive<R>(mut archive: ZipArchive<R>, output_folder: &Path, password: Option<impl AsRef<[u8]>>, quiet: bool) -> crate::Result<usize>
where
R: Read + Seek,
{
@ -36,8 +38,14 @@ where
let mut unpacked_files = 0;
let password = password.as_ref().map(|p| p.as_ref().to_owned());
for idx in 0..archive.len() {
let mut file = archive.by_index(idx)?;
let mut file = match password.clone() {
Some(password) => archive.by_index_decrypt(idx, password.to_owned().as_bytes()).unwrap()
.map_err(|_| zip::result::ZipError::UnsupportedArchive("Password required to decrypt file"))?,
None => archive.by_index(idx)?,
};
let file_path = match file.enclosed_name() {
Some(path) => path.to_owned(),
None => continue,
@ -92,7 +100,7 @@ where
}
/// List contents of `archive`, returning a vector of archive entries
pub fn list_archive<R>(mut archive: ZipArchive<R>) -> impl Iterator<Item = crate::Result<FileInArchive>>
pub fn list_archive<R>(mut archive: ZipArchive<R>, password: Option<impl AsRef<[u8]>>) -> impl Iterator<Item = crate::Result<FileInArchive>>
where
R: Read + Seek + Send + 'static,
{
@ -105,11 +113,19 @@ where
}
}
let password = password.as_ref().map(|p| p.as_ref().to_owned());
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
for idx in 0..archive.len() {
let maybe_file_in_archive = (|| {
let file = match archive.by_index(idx) {
let zip_result = match password.clone() {
Some(password) => archive.by_index_decrypt(idx, password.to_owned().clone().as_bytes()).unwrap()
.map_err(|_| zip::result::ZipError::UnsupportedArchive("Password required to decrypt file")),
None => archive.by_index(idx),
};
let file = match zip_result {
Ok(f) => f,
Err(e) => return Some(Err(e.into())),
};

View File

@ -63,7 +63,7 @@ pub fn decompress_file(
};
let zip_archive = zip::ZipArchive::new(reader)?;
let files_unpacked = if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet),
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, password, quiet),
output_dir,
&output_file_path,
question_policy,
@ -157,7 +157,7 @@ pub fn decompress_file(
let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?;
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet),
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, password, quiet),
output_dir,
&output_file_path,
question_policy,

View File

@ -35,7 +35,7 @@ pub fn list_archive_contents(
// Any other Zip decompression done can take up the whole RAM and freeze ouch.
if let &[Zip] = formats.as_slice() {
let zip_archive = zip::ZipArchive::new(reader)?;
let files = crate::archive::zip::list_archive(zip_archive);
let files = crate::archive::zip::list_archive(zip_archive, password);
list::list_files(archive_path, files, list_options)?;
return Ok(());
@ -82,7 +82,7 @@ pub fn list_archive_contents(
io::copy(&mut reader, &mut vec)?;
let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?;
Box::new(crate::archive::zip::list_archive(zip_archive))
Box::new(crate::archive::zip::list_archive(zip_archive, password))
}
#[cfg(feature = "unrar")]
Rar => {