mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
feat: support decompress and list zip file
This commit is contained in:
parent
75e16510df
commit
d21db763f1
67
Cargo.lock
generated
67
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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())),
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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 => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user