diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 3145bed..78e9314 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -47,20 +47,23 @@ pub fn unpack_archive( } /// List contents of `archive`, returning a vector of archive entries -pub fn list_archive(reader: Box) -> crate::Result> { - let mut archive = tar::Archive::new(reader); +pub fn list_archive( + archive: tar::Archive, +) -> crate::Result>> { + // NOTE: tar::Archive::entries takes a &mut self + // This makes returning an iterator impossible + // Current workaround is just to leak the archive + // This can be replaced when upstream add `into_entries` function that consumes the archive + let archive = Box::leak(Box::new(archive)); - let mut files = vec![]; - for file in archive.entries()? { + Ok(archive.entries()?.map(|file| { let file = file?; let path = file.path()?.into_owned(); let is_dir = file.header().entry_type().is_dir(); - files.push(FileInArchive { path, is_dir }); - } - - Ok(files) + Ok(FileInArchive { path, is_dir }) + })) } /// Compresses the archives given by `input_filenames` into the file given previously to `writer`. diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 30dee2e..d93e2bf 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -80,23 +80,24 @@ where } /// List contents of `archive`, returning a vector of archive entries -pub fn list_archive(mut archive: ZipArchive) -> crate::Result> +pub fn list_archive(mut archive: ZipArchive) -> impl Iterator> where - R: Read + Seek, + R: Read + Seek + 'static, { - let mut files = vec![]; - for idx in 0..archive.len() { - let file = archive.by_index(idx)?; + (0..archive.len()).filter_map(move |idx| { + let file = match archive.by_index(idx) { + Ok(f) => f, + Err(e) => return Some(Err(e.into())), + }; let path = match file.enclosed_name() { Some(path) => path.to_owned(), - None => continue, + None => return None, }; let is_dir = file.is_dir(); - files.push(FileInArchive { path, is_dir }); - } - Ok(files) + Some(Ok(FileInArchive { path, is_dir })) + }) } /// Compresses the archives given by `input_filenames` into the file given previously to `writer`. diff --git a/src/commands.rs b/src/commands.rs index 5de0743..304fca6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -20,7 +20,7 @@ use crate::{ Extension, }, info, - list::{self, ListOptions}, + list::{self, FileInArchive, ListOptions}, progress::Progress, utils::{ self, concatenate_os_str_list, dir_is_empty, nice_directory_display, to_utf, try_infer_extension, @@ -580,8 +580,9 @@ 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)?; - list::list_files(archive_path, files, list_options); + let files = crate::archive::zip::list_archive(zip_archive); + list::list_files(archive_path, files, list_options)?; + return Ok(()); } @@ -607,8 +608,8 @@ fn list_archive_contents( reader = chain_reader_decoder(format, reader)?; } - let files = match formats[0] { - Tar => crate::archive::tar::list_archive(reader)?, + let files: Box>> = match formats[0] { + Tar => Box::new(crate::archive::tar::list_archive(tar::Archive::new(reader))?), Zip => { eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); eprintln!( @@ -626,13 +627,13 @@ fn list_archive_contents( io::copy(&mut reader, &mut vec)?; let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?; - crate::archive::zip::list_archive(zip_archive)? + Box::new(crate::archive::zip::list_archive(zip_archive)) } 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!"); } }; - list::list_files(archive_path, files, list_options); + list::list_files(archive_path, files, list_options)?; Ok(()) } diff --git a/src/list.rs b/src/list.rs index 1549b30..fa8d148 100644 --- a/src/list.rs +++ b/src/list.rs @@ -22,16 +22,24 @@ pub struct FileInArchive { } /// Actually print the files -pub fn list_files(archive: &Path, files: Vec, list_options: ListOptions) { +/// Returns an Error, if one of the files can't be read +pub fn list_files( + archive: &Path, + files: impl IntoIterator>, + list_options: ListOptions, +) -> crate::Result<()> { println!("Archive: {}", archive.display()); + if list_options.tree { - let tree: Tree = files.into_iter().collect(); + let tree: Tree = files.into_iter().collect::>()?; tree.print(); } else { - for FileInArchive { path, is_dir } in files { + for file in files { + let FileInArchive { path, is_dir } = file?; print_entry(path.display(), is_dir); } } + Ok(()) } /// Print an entry and highlight directories, either by coloring them