mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
feat(list): support list and decompress 7z files with password
This commit is contained in:
parent
512d2445b2
commit
75e16510df
663
Cargo.lock
generated
663
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@ num_cpus = "1.16.0"
|
||||
once_cell = "1.19.0"
|
||||
rayon = "1.10.0"
|
||||
same-file = "1.0.6"
|
||||
sevenz-rust = { version = "0.6.1", features = ["compress"] }
|
||||
sevenz-rust = { version = "0.6.1", features = ["compress", "aes256"] }
|
||||
snap = "1.1.1"
|
||||
tar = "0.4.41"
|
||||
tempfile = "3.10.1"
|
||||
|
@ -5,9 +5,13 @@ use std::{
|
||||
io::{self, Read, Seek, Write},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use bstr::ByteSlice;
|
||||
|
||||
use fs_err as fs;
|
||||
use same_file::Handle;
|
||||
use sevenz_rust::SevenZArchiveEntry;
|
||||
use unrar::Archive;
|
||||
use zstd::zstd_safe::WriteBuf;
|
||||
|
||||
use crate::{
|
||||
error::FinalError,
|
||||
@ -17,6 +21,7 @@ use crate::{
|
||||
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
|
||||
},
|
||||
};
|
||||
use crate::list::FileInArchive;
|
||||
|
||||
pub fn compress_sevenz<W>(
|
||||
files: &[PathBuf],
|
||||
@ -96,12 +101,13 @@ where
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn decompress_sevenz<R>(reader: R, output_path: &Path, quiet: bool) -> crate::Result<usize>
|
||||
pub fn decompress_sevenz<R>(reader: R, output_path: &Path, password: Option<impl AsRef<[u8]>>, quiet: bool) -> crate::Result<usize>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
let mut count: usize = 0;
|
||||
sevenz_rust::decompress_with_extract_fn(reader, output_path, |entry, reader, path| {
|
||||
|
||||
let entry_extract_fn = |entry: &SevenZArchiveEntry, reader: &mut dyn Read, path: &PathBuf| {
|
||||
count += 1;
|
||||
// Manually handle writing all files from 7z archive, due to library exluding empty files
|
||||
use std::io::BufWriter;
|
||||
@ -146,11 +152,42 @@ where
|
||||
Some(ft::FileTime::from_system_time(entry.last_modified_date().into())),
|
||||
Some(ft::FileTime::from_system_time(entry.creation_date().into())),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
.unwrap_or_default();
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
})?;
|
||||
};
|
||||
|
||||
let password = password.as_ref().map(|p| p.as_ref());
|
||||
|
||||
match password {
|
||||
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(reader, output_path, sevenz_rust::Password::from(password.to_str().unwrap()), entry_extract_fn)?,
|
||||
None => sevenz_rust::decompress_with_extract_fn(reader, output_path, entry_extract_fn)?,
|
||||
};
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
/// List contents of `archive_path`, returning a vector of archive entries
|
||||
pub fn list_archive(archive_path: &Path, password: Option<impl AsRef<[u8]>>) -> impl Iterator<Item = crate::Result<FileInArchive>>
|
||||
{
|
||||
let reader = fs::File::open(archive_path).unwrap();
|
||||
let password = password.as_ref().map(|p| p.as_ref());
|
||||
|
||||
let mut files = Vec::new();
|
||||
|
||||
let entry_extract_fn = |entry: &SevenZArchiveEntry, _: &mut dyn Read, _: &PathBuf| {
|
||||
files.push(Ok(FileInArchive {
|
||||
path: entry.name().into(),
|
||||
is_dir: entry.is_directory(),
|
||||
}));
|
||||
Ok(true)
|
||||
};
|
||||
|
||||
match password {
|
||||
Some(password) => sevenz_rust::decompress_with_extract_fn_and_password(reader, ".", sevenz_rust::Password::from(password.to_str().unwrap()), entry_extract_fn).unwrap(),
|
||||
None => sevenz_rust::decompress_with_extract_fn(reader, ".", entry_extract_fn).unwrap(),
|
||||
};
|
||||
|
||||
files.into_iter()
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ pub fn decompress_file(
|
||||
io::copy(&mut reader, &mut vec)?;
|
||||
|
||||
if let ControlFlow::Continue(files) = smart_unpack(
|
||||
|output_dir| crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, quiet),
|
||||
|output_dir| crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, password, quiet),
|
||||
output_dir,
|
||||
&output_file_path,
|
||||
question_policy,
|
||||
|
@ -2,6 +2,7 @@ use std::{
|
||||
io::{self, BufReader, Read},
|
||||
path::Path,
|
||||
};
|
||||
use std::io::Seek;
|
||||
|
||||
use fs_err as fs;
|
||||
|
||||
@ -12,6 +13,7 @@ use crate::{
|
||||
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue},
|
||||
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
||||
};
|
||||
use crate::archive::sevenz;
|
||||
|
||||
/// File at input_file_path is opened for reading, example: "archive.tar.gz"
|
||||
/// formats contains each format necessary for decompression, example: [Gz, Tar] (in decompression order)
|
||||
@ -108,16 +110,7 @@ pub fn list_archive_contents(
|
||||
}
|
||||
}
|
||||
|
||||
let mut files = Vec::new();
|
||||
|
||||
sevenz_rust::decompress_file_with_extract_fn(archive_path, ".", |entry, _, _| {
|
||||
files.push(Ok(FileInArchive {
|
||||
path: entry.name().into(),
|
||||
is_dir: entry.is_directory(),
|
||||
}));
|
||||
Ok(true)
|
||||
})?;
|
||||
Box::new(files.into_iter())
|
||||
Box::new(sevenz::list_archive(archive_path, password))
|
||||
}
|
||||
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
|
||||
panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!");
|
||||
|
Loading…
x
Reference in New Issue
Block a user