2 io::{self, BufReader, Read},
9 commands::warn_user_about_loading_zip_in_memory,
10 extension::CompressionFormat::{self, *},
11 list::{self, FileInArchive, ListOptions},
12 utils::user_wants_to_continue,
13 QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
16 // File at input_file_path is opened for reading, example: "archive.tar.gz"
17 // formats contains each format necessary for decompression, example: [Gz, Tar] (in decompression order)
18 pub fn list_archive_contents(
20 formats: Vec<CompressionFormat>,
21 list_options: ListOptions,
22 question_policy: QuestionPolicy,
23 ) -> crate::Result<()> {
24 let reader = fs::File::open(archive_path)?;
26 // Zip archives are special, because they require io::Seek, so it requires it's logic separated
27 // from decoder chaining.
29 // This is the only case where we can read and unpack it directly, without having to do
30 // in-memory decompression/copying first.
32 // Any other Zip decompression done can take up the whole RAM and freeze ouch.
33 if let &[Zip] = formats.as_slice() {
34 let zip_archive = zip::ZipArchive::new(reader)?;
35 let files = crate::archive::zip::list_archive(zip_archive);
36 list::list_files(archive_path, files, list_options)?;
41 // Will be used in decoder chaining
42 let reader = BufReader::with_capacity(BUFFER_CAPACITY, reader);
43 let mut reader: Box<dyn Read + Send> = Box::new(reader);
45 // Grab previous decoder and wrap it inside of a new one
46 let chain_reader_decoder =
47 |format: &CompressionFormat, decoder: Box<dyn Read + Send>| -> crate::Result<Box<dyn Read + Send>> {
48 let decoder: Box<dyn Read + Send> = match format {
49 Gzip => Box::new(flate2::read::GzDecoder::new(decoder)),
50 Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)),
51 Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
52 Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
53 Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
54 Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
55 Tar | Zip | Rar | SevenZip => unreachable!(),
60 for format in formats.iter().skip(1).rev() {
61 reader = chain_reader_decoder(format, reader)?;
64 let files: Box<dyn Iterator<Item = crate::Result<FileInArchive>>> = match formats[0] {
65 Tar => Box::new(crate::archive::tar::list_archive(tar::Archive::new(reader))),
67 if formats.len() > 1 {
68 warn_user_about_loading_zip_in_memory();
70 if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
76 io::copy(&mut reader, &mut vec)?;
77 let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?;
79 Box::new(crate::archive::zip::list_archive(zip_archive))
82 if formats.len() > 1 {
83 let mut temp_file = tempfile::NamedTempFile::new()?;
84 io::copy(&mut reader, &mut temp_file)?;
85 Box::new(crate::archive::rar::list_archive(temp_file.path()))
87 Box::new(crate::archive::rar::list_archive(archive_path))
91 if formats.len() > 1 {
92 warn_user_about_loading_zip_in_memory();
93 if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
98 let mut files = Vec::new();
100 sevenz_rust::decompress_file_with_extract_fn(archive_path, ".", |entry, _, _| {
101 files.push(Ok(FileInArchive {
102 path: entry.name().into(),
103 is_dir: entry.is_directory(),
107 Box::new(files.into_iter())
109 Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
110 panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!");
113 list::list_files(archive_path, files, list_options)?;