mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 19:45:29 +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"
|
once_cell = "1.19.0"
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
same-file = "1.0.6"
|
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"
|
snap = "1.1.1"
|
||||||
tar = "0.4.41"
|
tar = "0.4.41"
|
||||||
tempfile = "3.10.1"
|
tempfile = "3.10.1"
|
||||||
|
@ -5,9 +5,13 @@ use std::{
|
|||||||
io::{self, Read, Seek, Write},
|
io::{self, Read, Seek, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
use bstr::ByteSlice;
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use same_file::Handle;
|
use same_file::Handle;
|
||||||
|
use sevenz_rust::SevenZArchiveEntry;
|
||||||
|
use unrar::Archive;
|
||||||
|
use zstd::zstd_safe::WriteBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::FinalError,
|
error::FinalError,
|
||||||
@ -17,6 +21,7 @@ use crate::{
|
|||||||
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
|
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::list::FileInArchive;
|
||||||
|
|
||||||
pub fn compress_sevenz<W>(
|
pub fn compress_sevenz<W>(
|
||||||
files: &[PathBuf],
|
files: &[PathBuf],
|
||||||
@ -96,12 +101,13 @@ where
|
|||||||
Ok(bytes)
|
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
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
let mut count: usize = 0;
|
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;
|
count += 1;
|
||||||
// Manually handle writing all files from 7z archive, due to library exluding empty files
|
// Manually handle writing all files from 7z archive, due to library exluding empty files
|
||||||
use std::io::BufWriter;
|
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.last_modified_date().into())),
|
||||||
Some(ft::FileTime::from_system_time(entry.creation_date().into())),
|
Some(ft::FileTime::from_system_time(entry.creation_date().into())),
|
||||||
)
|
)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true)
|
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)
|
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)?;
|
io::copy(&mut reader, &mut vec)?;
|
||||||
|
|
||||||
if let ControlFlow::Continue(files) = smart_unpack(
|
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_dir,
|
||||||
&output_file_path,
|
&output_file_path,
|
||||||
question_policy,
|
question_policy,
|
||||||
|
@ -2,6 +2,7 @@ use std::{
|
|||||||
io::{self, BufReader, Read},
|
io::{self, BufReader, Read},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
use std::io::Seek;
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ use crate::{
|
|||||||
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue},
|
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue},
|
||||||
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
||||||
};
|
};
|
||||||
|
use crate::archive::sevenz;
|
||||||
|
|
||||||
/// File at input_file_path is opened for reading, example: "archive.tar.gz"
|
/// 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)
|
/// 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();
|
Box::new(sevenz::list_archive(archive_path, password))
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
|
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!");
|
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