mirror of
https://github.com/ouch-org/ouch.git
synced 2025-07-18 23:50:35 +00:00
feat: add listing support for squashfs
This commit is contained in:
parent
945ffde551
commit
bcdff0f46b
281
Cargo.lock
generated
281
Cargo.lock
generated
@ -126,6 +126,24 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backhand"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c45726a83c67f85d931ef28d331cbc4108b179e06359ed84944313dfc2bb9ce1"
|
||||
dependencies = [
|
||||
"deku",
|
||||
"flate2",
|
||||
"lz4_flex",
|
||||
"rayon",
|
||||
"solana-nohash-hasher",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
"xxhash-rust",
|
||||
"zstd",
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
@ -181,6 +199,18 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
@ -284,7 +314,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"bytesize",
|
||||
"libbzip3-sys",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -520,6 +550,66 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deku"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f476a022dcfbb013d1365734a42e05b6aca967ebe0d3bb38170086abd9ea3324"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"deku_derive",
|
||||
"no_std_io2",
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deku_derive"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb216d425bdf810c165a8ae1649523033e88b5f795480ccec63926295541b084"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
@ -570,6 +660,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
@ -616,6 +712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"libz-rs-sys",
|
||||
"libz-sys",
|
||||
"miniz_oxide",
|
||||
]
|
||||
@ -648,6 +745,12 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
@ -728,9 +831,15 @@ dependencies = [
|
||||
"libz-sys",
|
||||
"num_cpus",
|
||||
"snap",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@ -770,6 +879,12 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.23"
|
||||
@ -786,6 +901,16 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "infer"
|
||||
version = "0.16.0"
|
||||
@ -937,6 +1062,15 @@ dependencies = [
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-rs-sys"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "902bc563b5d65ad9bba616b490842ef0651066a1a1dc3ce1087113ffcb873c8d"
|
||||
dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.21"
|
||||
@ -1036,6 +1170,15 @@ dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no_std_io2"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c2b9acd47481ab557a89a5665891be79e43cce8a29ad77aa9419d7be5a7c06a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@ -1095,6 +1238,7 @@ version = "0.6.1"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"atty",
|
||||
"backhand",
|
||||
"brotli",
|
||||
"bstr",
|
||||
"bytesize",
|
||||
@ -1213,6 +1357,12 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
@ -1286,6 +1436,15 @@ dependencies = [
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
@ -1330,6 +1489,12 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@ -1595,6 +1760,12 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b"
|
||||
|
||||
[[package]]
|
||||
name = "solana-nohash-hasher"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
@ -1667,6 +1838,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.44"
|
||||
@ -1716,7 +1893,16 @@ version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1730,6 +1916,17 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
@ -1760,6 +1957,54 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "twox-hash"
|
||||
version = "1.6.3"
|
||||
@ -2058,6 +2303,15 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
@ -2067,6 +2321,15 @@ dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.4.0"
|
||||
@ -2078,6 +2341,12 @@ dependencies = [
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xxhash-rust"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
|
||||
|
||||
[[package]]
|
||||
name = "xz2"
|
||||
version = "0.1.7"
|
||||
@ -2152,6 +2421,12 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b20717f0917c908dc63de2e44e97f1e6b126ca58d0e391cee86d504eb8fbd05"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
|
@ -15,6 +15,8 @@ description = "A command-line utility for easily compressing and decompressing f
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.14"
|
||||
# FIXME: `xz` features cannot be enabled because it uses `lzma-sys` which cannot co-exist with our dependency `xz2`.
|
||||
backhand = { version = "0.23.0", default-features = false, features = ["parallel", "gzip", "lz4", "zstd"] }
|
||||
brotli = "7.0.0"
|
||||
bstr = { version = "1.10.0", default-features = false, features = ["std"] }
|
||||
bytesize = "1.3.0"
|
||||
|
@ -7,5 +7,6 @@ pub mod rar;
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
pub mod rar_stub;
|
||||
pub mod sevenz;
|
||||
pub mod squashfs;
|
||||
pub mod tar;
|
||||
pub mod zip;
|
||||
|
23
src/archive/squashfs.rs
Normal file
23
src/archive/squashfs.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::path::Path;
|
||||
|
||||
use backhand::{FilesystemReader, InnerNode};
|
||||
|
||||
use crate::list::FileInArchive;
|
||||
|
||||
pub fn list_archive<'a>(archive: FilesystemReader<'a>) -> impl Iterator<Item = crate::Result<FileInArchive>> + 'a {
|
||||
archive.root.nodes.into_iter().filter_map(move |f| {
|
||||
// The reported paths are absolute, and include the root directory `/`.
|
||||
// To be consistent with outputs of other formats, we strip the prefix `/` and ignore the root directory.
|
||||
if f.fullpath == Path::new("/") {
|
||||
return None;
|
||||
}
|
||||
Some(Ok(FileInArchive {
|
||||
is_dir: matches!(f.inner, InnerNode::Dir(_)),
|
||||
path: f
|
||||
.fullpath
|
||||
.strip_prefix("/")
|
||||
.expect("paths must be absolute")
|
||||
.to_path_buf(),
|
||||
}))
|
||||
})
|
||||
}
|
@ -5,10 +5,9 @@ use std::{
|
||||
|
||||
use fs_err as fs;
|
||||
|
||||
use super::warn_user_about_loading_sevenz_in_memory;
|
||||
use crate::{
|
||||
archive,
|
||||
commands::warn_user_about_loading_zip_in_memory,
|
||||
commands::warn_user_about_loading_in_memory,
|
||||
extension::{split_first_compression_format, CompressionFormat::*, Extension},
|
||||
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue, FileVisibilityPolicy},
|
||||
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
||||
@ -96,7 +95,7 @@ pub fn compress_files(
|
||||
let win_size = 22; // default to 2^22 = 4 MiB window size
|
||||
Box::new(brotli::CompressorWriter::new(encoder, BUFFER_CAPACITY, level, win_size))
|
||||
}
|
||||
Tar | Zip | Rar | SevenZip => unreachable!(),
|
||||
Tar | Zip | Rar | SevenZip | Squashfs => unreachable!(),
|
||||
};
|
||||
Ok(encoder)
|
||||
};
|
||||
@ -125,13 +124,14 @@ pub fn compress_files(
|
||||
)?;
|
||||
writer.flush()?;
|
||||
}
|
||||
Squashfs => todo!(),
|
||||
Zip => {
|
||||
if !formats.is_empty() {
|
||||
// Locking necessary to guarantee that warning and question
|
||||
// messages stay adjacent
|
||||
let _locks = lock_and_flush_output_stdio();
|
||||
|
||||
warn_user_about_loading_zip_in_memory();
|
||||
warn_user_about_loading_in_memory(".zip");
|
||||
if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
|
||||
return Ok(false);
|
||||
}
|
||||
@ -163,7 +163,7 @@ pub fn compress_files(
|
||||
// messages stay adjacent
|
||||
let _locks = lock_and_flush_output_stdio();
|
||||
|
||||
warn_user_about_loading_sevenz_in_memory();
|
||||
warn_user_about_loading_in_memory(".7z");
|
||||
if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use fs_err as fs;
|
||||
#[cfg(not(feature = "bzip3"))]
|
||||
use crate::archive;
|
||||
use crate::{
|
||||
commands::{warn_user_about_loading_sevenz_in_memory, warn_user_about_loading_zip_in_memory},
|
||||
commands::warn_user_about_loading_in_memory,
|
||||
extension::{
|
||||
split_first_compression_format,
|
||||
CompressionFormat::{self, *},
|
||||
@ -65,7 +65,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
{
|
||||
let mut vec = vec![];
|
||||
let reader: Box<dyn ReadSeek> = if input_is_stdin {
|
||||
warn_user_about_loading_zip_in_memory();
|
||||
warn_user_about_loading_in_memory(".zip");
|
||||
io::copy(&mut io::stdin(), &mut vec)?;
|
||||
Box::new(io::Cursor::new(vec))
|
||||
} else {
|
||||
@ -132,7 +132,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
|
||||
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
|
||||
Brotli => Box::new(brotli::Decompressor::new(decoder, BUFFER_CAPACITY)),
|
||||
Tar | Zip | Rar | SevenZip => decoder,
|
||||
Tar | Zip | Rar | SevenZip | Squashfs => decoder,
|
||||
};
|
||||
Ok(decoder)
|
||||
};
|
||||
@ -174,13 +174,14 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Squashfs => todo!(),
|
||||
Zip => {
|
||||
if options.formats.len() > 1 {
|
||||
// Locking necessary to guarantee that warning and question
|
||||
// messages stay adjacent
|
||||
let _locks = lock_and_flush_output_stdio();
|
||||
|
||||
warn_user_about_loading_zip_in_memory();
|
||||
warn_user_about_loading_in_memory(".zip");
|
||||
if !user_wants_to_continue(
|
||||
options.input_file_path,
|
||||
options.question_policy,
|
||||
@ -252,7 +253,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
// messages stay adjacent
|
||||
let _locks = lock_and_flush_output_stdio();
|
||||
|
||||
warn_user_about_loading_sevenz_in_memory();
|
||||
warn_user_about_loading_in_memory(".7z");
|
||||
if !user_wants_to_continue(
|
||||
options.input_file_path,
|
||||
options.question_policy,
|
||||
|
@ -7,7 +7,7 @@ use fs_err as fs;
|
||||
|
||||
use crate::{
|
||||
archive,
|
||||
commands::warn_user_about_loading_zip_in_memory,
|
||||
commands::warn_user_about_loading_in_memory,
|
||||
extension::CompressionFormat::{self, *},
|
||||
list::{self, FileInArchive, ListOptions},
|
||||
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue},
|
||||
@ -38,6 +38,13 @@ pub fn list_archive_contents(
|
||||
list::list_files(archive_path, files, list_options)?;
|
||||
return Ok(());
|
||||
}
|
||||
if let &[Squashfs] = formats.as_slice() {
|
||||
let reader = BufReader::with_capacity(BUFFER_CAPACITY, reader);
|
||||
let archive = backhand::FilesystemReader::from_reader(reader)?;
|
||||
let files = crate::archive::squashfs::list_archive(archive);
|
||||
list::list_files(archive_path, files, list_options)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Will be used in decoder chaining
|
||||
let reader = BufReader::with_capacity(BUFFER_CAPACITY, reader);
|
||||
@ -61,7 +68,7 @@ pub fn list_archive_contents(
|
||||
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
|
||||
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
|
||||
Brotli => Box::new(brotli::Decompressor::new(decoder, BUFFER_CAPACITY)),
|
||||
Tar | Zip | Rar | SevenZip => unreachable!("should be treated by caller"),
|
||||
Tar | Zip | Rar | SevenZip | Squashfs => unreachable!("should be treated by caller"),
|
||||
};
|
||||
Ok(decoder)
|
||||
};
|
||||
@ -78,13 +85,15 @@ pub fn list_archive_contents(
|
||||
let archive_format = misplaced_archive_format.unwrap_or(formats[0]);
|
||||
let files: Box<dyn Iterator<Item = crate::Result<FileInArchive>>> = match archive_format {
|
||||
Tar => Box::new(crate::archive::tar::list_archive(tar::Archive::new(reader))),
|
||||
Zip => {
|
||||
Zip | Squashfs => {
|
||||
let is_zip = matches!(archive_format, Zip);
|
||||
|
||||
if formats.len() > 1 {
|
||||
// Locking necessary to guarantee that warning and question
|
||||
// messages stay adjacent
|
||||
let _locks = lock_and_flush_output_stdio();
|
||||
|
||||
warn_user_about_loading_zip_in_memory();
|
||||
warn_user_about_loading_in_memory(if is_zip { ".zip" } else { ".sqfs" });
|
||||
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
|
||||
return Ok(());
|
||||
}
|
||||
@ -92,9 +101,14 @@ pub fn list_archive_contents(
|
||||
|
||||
let mut vec = vec![];
|
||||
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, password))
|
||||
let reader = io::Cursor::new(vec);
|
||||
if is_zip {
|
||||
let zip_archive = zip::ZipArchive::new(reader)?;
|
||||
Box::new(crate::archive::zip::list_archive(zip_archive, password))
|
||||
} else {
|
||||
let archive = backhand::FilesystemReader::from_reader(reader)?;
|
||||
Box::new(crate::archive::squashfs::list_archive(archive))
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "unrar")]
|
||||
Rar => {
|
||||
@ -116,7 +130,7 @@ pub fn list_archive_contents(
|
||||
// messages stay adjacent
|
||||
let _locks = lock_and_flush_output_stdio();
|
||||
|
||||
warn_user_about_loading_zip_in_memory();
|
||||
warn_user_about_loading_in_memory(".7z");
|
||||
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -25,24 +25,15 @@ use crate::{
|
||||
CliArgs, QuestionPolicy,
|
||||
};
|
||||
|
||||
/// Warn the user that (de)compressing this .zip archive might freeze their system.
|
||||
fn warn_user_about_loading_zip_in_memory() {
|
||||
const ZIP_IN_MEMORY_LIMITATION_WARNING: &str = "\n \
|
||||
The format '.zip' is limited by design and cannot be (de)compressed with encoding streams.\n \
|
||||
When chaining '.zip' with other formats, all (de)compression needs to be done in-memory\n \
|
||||
Careful, you might run out of RAM if the archive is too large!";
|
||||
|
||||
eprintln!("{}[WARNING]{}: {ZIP_IN_MEMORY_LIMITATION_WARNING}", *ORANGE, *RESET);
|
||||
}
|
||||
|
||||
/// Warn the user that (de)compressing this .7z archive might freeze their system.
|
||||
fn warn_user_about_loading_sevenz_in_memory() {
|
||||
const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n \
|
||||
The format '.7z' is limited by design and cannot be (de)compressed with encoding streams.\n \
|
||||
When chaining '.7z' with other formats, all (de)compression needs to be done in-memory\n \
|
||||
Careful, you might run out of RAM if the archive is too large!";
|
||||
|
||||
eprintln!("{}[WARNING]{}: {SEVENZ_IN_MEMORY_LIMITATION_WARNING}", *ORANGE, *RESET);
|
||||
/// Warn the user that (de)compressing this format might freeze their system.
|
||||
fn warn_user_about_loading_in_memory(ext: &str) {
|
||||
eprintln!(
|
||||
"{}[WARNING]{}:\n \
|
||||
The format '{ext}' is limited by design and cannot be (de)compressed with encoding streams.\n \
|
||||
When chaining '{ext}' with other formats, all (de)compression needs to be done in-memory\n \
|
||||
Careful, you might run out of RAM if the archive is too large!",
|
||||
*ORANGE, *RESET
|
||||
);
|
||||
}
|
||||
|
||||
/// This function checks what command needs to be run and performs A LOT of ahead-of-time checks
|
||||
|
23
src/error.rs
23
src/error.rs
@ -47,6 +47,10 @@ pub enum Error {
|
||||
UnsupportedFormat { reason: String },
|
||||
/// Invalid password provided
|
||||
InvalidPassword { reason: String },
|
||||
/// From backhand::BackhandError
|
||||
InvalidSquashfs { reason: String },
|
||||
/// From backhand::BackhandError
|
||||
UnsupportedSquashfs { reason: String },
|
||||
}
|
||||
|
||||
/// Alias to std's Result with ouch's Error
|
||||
@ -158,8 +162,10 @@ impl From<Error> for FinalError {
|
||||
Error::Lz4Error { reason } => FinalError::with_title(reason),
|
||||
Error::AlreadyExists { error_title } => FinalError::with_title(error_title).detail("File already exists"),
|
||||
Error::InvalidZipArchive(reason) => FinalError::with_title("Invalid zip archive").detail(reason),
|
||||
Error::InvalidSquashfs { reason } => FinalError::with_title("Invalid squashfs").detail(reason),
|
||||
Error::PermissionDenied { error_title } => FinalError::with_title(error_title).detail("Permission denied"),
|
||||
Error::UnsupportedZipArchive(reason) => FinalError::with_title("Unsupported zip archive").detail(reason),
|
||||
Error::UnsupportedSquashfs { reason } => FinalError::with_title("Unsupported squashfs").detail(reason),
|
||||
Error::InvalidFormatFlag { reason, text } => {
|
||||
FinalError::with_title(format!("Failed to parse `--format {}`", os_str_to_str(&text)))
|
||||
.detail(reason)
|
||||
@ -227,6 +233,23 @@ impl From<zip::result::ZipError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<backhand::BackhandError> for Error {
|
||||
fn from(err: backhand::BackhandError) -> Self {
|
||||
use backhand::BackhandError;
|
||||
match err {
|
||||
BackhandError::StdIo(io_err) => Self::from(io_err),
|
||||
err @ (BackhandError::UnsupportedCompression(_) | BackhandError::UnsupportedInode(_)) => {
|
||||
Self::UnsupportedSquashfs {
|
||||
reason: err.to_string(),
|
||||
}
|
||||
}
|
||||
err => Self::InvalidSquashfs {
|
||||
reason: err.to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unrar")]
|
||||
impl From<unrar::error::UnrarError> for Error {
|
||||
fn from(err: unrar::error::UnrarError) -> Self {
|
||||
|
@ -102,6 +102,14 @@ pub enum CompressionFormat {
|
||||
SevenZip,
|
||||
/// .br
|
||||
Brotli,
|
||||
/// .squashfs, .sqfs
|
||||
//
|
||||
// Note: There is not canonical extension for squashfs, we pick the two semi-official ones:
|
||||
// - `.squashfs`: The most popular one from a quick search on GitHub. Also used by some distros.
|
||||
// https://github.com/NixOS/nixpkgs/blob/6576d979e9a64d870b1f298a5c598116891a6c25/nixos/modules/installer/cd-dvd/iso-image.nix#L797
|
||||
// - `.sqfs`: Mentioned in `man mksquashfs` by squashfs-tools, the reference implementation.
|
||||
// https://github.com/plougher/squashfs-tools/blob/9f9bbd79016ff04967800f4301c7a9d0024c0c91/Documentation/manpages/mksquashfs.1#L494
|
||||
Squashfs,
|
||||
}
|
||||
|
||||
impl CompressionFormat {
|
||||
@ -109,7 +117,7 @@ impl CompressionFormat {
|
||||
pub fn archive_format(&self) -> bool {
|
||||
// Keep this match like that without a wildcard `_` so we don't forget to update it
|
||||
match self {
|
||||
Tar | Zip | Rar | SevenZip => true,
|
||||
Tar | Zip | Rar | SevenZip | Squashfs => true,
|
||||
Gzip => false,
|
||||
Bzip => false,
|
||||
Bzip3 => false,
|
||||
@ -144,6 +152,7 @@ fn to_extension(ext: &[u8]) -> Option<Extension> {
|
||||
b"rar" => &[Rar],
|
||||
b"7z" => &[SevenZip],
|
||||
b"br" => &[Brotli],
|
||||
b"sqfs" | b"squashfs" => &[Squashfs],
|
||||
_ => return None,
|
||||
},
|
||||
ext.to_str_lossy(),
|
||||
|
@ -158,6 +158,10 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
|
||||
fn is_sevenz(buf: &[u8]) -> bool {
|
||||
buf.starts_with(&[0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])
|
||||
}
|
||||
fn is_squashfs(buf: &[u8]) -> bool {
|
||||
// Ref: https://dr-emann.github.io/squashfs/squashfs.html#_the_superblock
|
||||
buf.starts_with(b"hsqs")
|
||||
}
|
||||
|
||||
let buf = {
|
||||
let mut buf = [0; 270];
|
||||
@ -195,6 +199,8 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
|
||||
Some(Extension::new(&[Rar], "rar"))
|
||||
} else if is_sevenz(&buf) {
|
||||
Some(Extension::new(&[SevenZip], "7z"))
|
||||
} else if is_squashfs(&buf) {
|
||||
Some(Extension::new(&[Squashfs], "sqfs"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user