Add support for bzip3

Closes #398
Signed-off-by: Jonas Frei <freijon@pm.me>
This commit is contained in:
Jonas Frei 2023-09-20 21:18:27 +02:00 committed by João Marcos
parent 362418364f
commit ba9f9c00f3
9 changed files with 198 additions and 21 deletions

178
Cargo.lock generated
View File

@ -116,6 +116,28 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bindgen"
version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885"
dependencies = [
"bitflags 1.3.2",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 1.0.109",
"which",
]
[[package]]
name = "bit-set"
version = "0.5.3"
@ -205,6 +227,12 @@ version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
[[package]]
name = "bytesize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
[[package]]
name = "bzip2"
version = "0.4.4"
@ -226,6 +254,18 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "bzip3"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a396e70a91080ca308fe4d37ebf2d15b444beef3b53853d9e36110b3a331e82e"
dependencies = [
"byteorder",
"bytesize",
"libbzip3-sys",
"thiserror",
]
[[package]]
name = "cbc"
version = "0.1.2"
@ -246,6 +286,15 @@ dependencies = [
"shlex",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfb"
version = "0.7.3"
@ -282,6 +331,17 @@ dependencies = [
"inout",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "4.5.20"
@ -322,7 +382,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -601,6 +661,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
version = "0.4.15"
@ -661,6 +727,15 @@ dependencies = [
"digest",
]
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "ignore"
version = "0.4.23"
@ -748,12 +823,40 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libbzip3-sys"
version = "0.3.3+1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb2f193373a540601f16a3375d351d685e4ca288c766fe35ce035874c2711f1"
dependencies = [
"bindgen",
"cc",
"cfg-if",
"regex",
]
[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "libloading"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "libm"
version = "0.2.8"
@ -846,6 +949,12 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.0"
@ -864,6 +973,16 @@ dependencies = [
"getrandom",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nt-time"
version = "0.8.1"
@ -913,7 +1032,9 @@ dependencies = [
"assert_cmd",
"atty",
"bstr",
"bytesize",
"bzip2",
"bzip3",
"clap",
"clap_complete",
"clap_mangen",
@ -970,7 +1091,7 @@ dependencies = [
"regex",
"regex-syntax",
"structmeta",
"syn",
"syn 2.0.77",
]
[[package]]
@ -996,6 +1117,12 @@ dependencies = [
"sha2",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pin-project"
version = "1.1.5"
@ -1013,7 +1140,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1211,6 +1338,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.35"
@ -1268,7 +1401,7 @@ checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1361,7 +1494,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1372,7 +1505,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1381,6 +1514,17 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.77"
@ -1431,7 +1575,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1451,7 +1595,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1606,7 +1750,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
"wasm-bindgen-shared",
]
@ -1628,7 +1772,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -1639,6 +1783,18 @@ version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "widestring"
version = "1.1.0"
@ -1796,7 +1952,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]

View File

@ -13,7 +13,9 @@ description = "A command-line utility for easily compressing and decompressing f
[dependencies]
atty = "0.2.14"
bstr = { version = "1.10.0", default-features = false, features = ["std"] }
bytesize = "1.3.0"
bzip2 = "0.4.4"
bzip3 = "0.8.1"
clap = { version = "4.5.20", features = ["derive", "env"] }
filetime_creation = "0.2"
flate2 = { version = "1.0.30", default-features = false }

View File

@ -111,9 +111,9 @@ Output:
# Supported formats
| Format | `.tar` | `.zip` | `7z` | `.gz` | `.xz`, `.lzma` | `.bz`, `.bz2` | `.lz4` | `.sz` (Snappy) | `.zst` | `.rar` |
|:---------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| Supported | ✓ | ✓¹ | ✓¹ | ✓² | ✓ | ✓ | ✓ | ✓² | ✓² | ✓³ |
| Format | `.tar` | `.zip` | `7z` | `.gz` | `.xz`, `.lzma` | `.bz`, `.bz2` | `.bz3` | `.lz4` | `.sz` (Snappy) | `.zst` | `.rar` |
|:---------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| Supported | ✓ | ✓¹ | ✓¹ | ✓² | ✓ | ✓ | ✓ | ✓ | ✓² | ✓² | ✓³ |
✓: Supports compression and decompression.
@ -176,7 +176,9 @@ Otherwise, you'll need these libraries installed on your system:
* [liblzma](https://www.7-zip.org/sdk.html)
* [libbz2](https://www.sourceware.org/bzip2)
* [libbz3](https://github.com/kspalaiologos/bzip3)
* [libz](https://www.zlib.net)
>>>>>>> 066184e (Add support for bzip3)
These should be available in your system's package manager.

View File

@ -5,7 +5,7 @@ use clap::{Parser, ValueHint};
// Ouch command line options (docstrings below are part of --help)
/// A command-line utility for easily compressing and decompressing files and directories.
///
/// Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, lz4, sz (Snappy), zst and rar.
/// Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst and rar.
///
/// Repository: https://github.com/ouch-org/ouch
#[derive(Parser, Debug, PartialEq)]

View File

@ -56,6 +56,10 @@ pub fn compress_files(
encoder,
level.map_or_else(Default::default, |l| bzip2::Compression::new((l as u32).clamp(1, 9))),
)),
Bzip3 => Box::new(
// Unwrap is safe when using a valid block size
bzip3::write::Bz3Encoder::new(encoder, bytesize::ByteSize::mib(5).0 as usize).unwrap(),
),
Lz4 => Box::new(lz4_flex::frame::FrameEncoder::new(encoder).auto_finish()),
Lzma => Box::new(xz2::write::XzEncoder::new(
encoder,
@ -91,7 +95,7 @@ pub fn compress_files(
}
match first_format {
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd => {
writer = chain_writer_encoder(&first_format, writer)?;
let mut reader = fs::File::open(&files[0]).unwrap();

View File

@ -100,6 +100,7 @@ pub fn decompress_file(
let decoder: Box<dyn Read> = match format {
Gzip => Box::new(flate2::read::GzDecoder::new(decoder)),
Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)),
Bzip3 => Box::new(bzip3::read::Bz3Decoder::new(decoder).unwrap()),
Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
@ -116,7 +117,7 @@ pub fn decompress_file(
}
let files_unpacked = match first_extension {
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd => {
reader = chain_reader_decoder(&first_extension, reader)?;
let mut writer = match utils::ask_to_create_file(&output_file_path, question_policy)? {

View File

@ -50,6 +50,7 @@ pub fn list_archive_contents(
let decoder: Box<dyn Read + Send> = match format {
Gzip => Box::new(flate2::read::GzDecoder::new(decoder)),
Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)),
Bzip3 => Box::new(bzip3::read::Bz3Decoder::new(decoder).unwrap()),
Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
@ -111,7 +112,7 @@ pub fn list_archive_contents(
Box::new(sevenz::list_archive(archive_path, password)?)
}
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
Gzip | Bzip | Bzip3 | 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!");
}
};

View File

@ -26,9 +26,9 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst"];
#[cfg(not(feature = "unrar"))]
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, 7z";
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z";
#[cfg(feature = "unrar")]
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar, 7z";
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z";
pub const PRETTY_SUPPORTED_ALIASES: &str = "tgz, tbz, tlz4, txz, tzlma, tsz, tzst";
@ -77,13 +77,15 @@ pub enum CompressionFormat {
Gzip,
/// .bz .bz2
Bzip,
/// .bz3
Bzip3,
/// .lz4
Lz4,
/// .xz .lzma
Lzma,
/// .sz
Snappy,
/// tar, tgz, tbz, tbz2, txz, tlz4, tlzma, tsz, tzst
/// tar, tgz, tbz, tbz2, tbz3, txz, tlz4, tlzma, tsz, tzst
Tar,
/// .zst
Zstd,
@ -104,6 +106,7 @@ impl CompressionFormat {
Tar | Zip | Rar | SevenZip => true,
Gzip => false,
Bzip => false,
Bzip3 => false,
Lz4 => false,
Lzma => false,
Snappy => false,
@ -118,12 +121,14 @@ fn to_extension(ext: &[u8]) -> Option<Extension> {
b"tar" => &[Tar],
b"tgz" => &[Tar, Gzip],
b"tbz" | b"tbz2" => &[Tar, Bzip],
b"tbz3" => &[Tar, Bzip3],
b"tlz4" => &[Tar, Lz4],
b"txz" | b"tlzma" => &[Tar, Lzma],
b"tsz" => &[Tar, Snappy],
b"tzst" => &[Tar, Zstd],
b"zip" => &[Zip],
b"bz" | b"bz2" => &[Bzip],
b"bz3" => &[Bzip3],
b"gz" => &[Gzip],
b"lz4" => &[Lz4],
b"xz" | b"lzma" => &[Lzma],

View File

@ -82,6 +82,9 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
fn is_bz2(buf: &[u8]) -> bool {
buf.starts_with(&[0x42, 0x5A, 0x68])
}
fn is_bz3(buf: &[u8]) -> bool {
buf.starts_with(bzip3::MAGIC_NUMBER)
}
fn is_xz(buf: &[u8]) -> bool {
buf.starts_with(&[0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00])
}
@ -125,6 +128,8 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
Some(Extension::new(&[Gzip], "gz"))
} else if is_bz2(&buf) {
Some(Extension::new(&[Bzip], "bz2"))
} else if is_bz3(&buf) {
Some(Extension::new(&[Bzip3], "bz3"))
} else if is_xz(&buf) {
Some(Extension::new(&[Lzma], "xz"))
} else if is_lz4(&buf) {
@ -143,6 +148,7 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
}
/// Returns true if a path is a symlink.
///
/// This is the same as the nightly <https://doc.rust-lang.org/std/path/struct.Path.html#method.is_symlink>
/// Useful to detect broken symlinks when compressing. (So we can safely ignore them)
pub fn is_symlink(path: &Path) -> bool {