Add support for xz format

Signed-off-by: trivernis <trivernis@protonmail.com>
main
trivernis 3 years ago
parent d19c0e432d
commit ad83f38056
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

2
.gitignore vendored

@ -4,4 +4,6 @@
*.gz *.gz
*.xz *.xz
*.zip *.zip
test.txt
out out
out.txt

26
Cargo.lock generated

@ -97,6 +97,12 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "build_const"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.4.3"
@ -229,6 +235,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crc"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
dependencies = [
"build_const",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.3.2" version = "1.3.2"
@ -276,6 +291,7 @@ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"color-eyre", "color-eyre",
"lzma-rs",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"zip", "zip",
@ -401,6 +417,16 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "lzma-rs"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aba8ecb0450dfabce4ad72085eed0a75dffe8f21f7ada05638564ea9db2d7fb1"
dependencies = [
"byteorder",
"crc",
]
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"

@ -13,6 +13,7 @@ anyhow = "1.0.57"
color-eyre = "0.6.1" color-eyre = "0.6.1"
tracing = "0.1.34" tracing = "0.1.34"
zip = "0.6.2" zip = "0.6.2"
lzma-rs = "0.2.0"
tracing-subscriber = {version = "0.3.11", features = ["env-filter"]} tracing-subscriber = {version = "0.3.11", features = ["env-filter"]}
[dependencies.clap] [dependencies.clap]

@ -1,5 +1,8 @@
mod tar;
mod xz;
mod zip; mod zip;
use crate::format::xz::XZFormat;
use crate::format::zip::ZipFormat; use crate::format::zip::ZipFormat;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use std::fs::File; use std::fs::File;
@ -8,7 +11,7 @@ use std::path::Path;
pub enum Format { pub enum Format {
Zip(ZipFormat), Zip(ZipFormat),
Xz, Xz(XZFormat),
Gz, Gz,
Tar, Tar,
} }
@ -26,7 +29,11 @@ pub trait FileFormat: Sized {
impl FileFormat for Format { impl FileFormat for Format {
fn parse(file: &FileObject) -> Result<Self> { fn parse(file: &FileObject) -> Result<Self> {
if let Ok(zip) = ZipFormat::parse(file) { if let Ok(zip) = ZipFormat::parse(file) {
tracing::info!("Detected zip format");
Ok(Self::Zip(zip)) Ok(Self::Zip(zip))
} else if let Ok(xz) = XZFormat::parse(file) {
tracing::info!("Detected xz format");
Ok(Self::Xz(xz))
} else { } else {
bail!("Unknown file format"); bail!("Unknown file format");
} }
@ -35,6 +42,7 @@ impl FileFormat for Format {
fn extract(&self, file: &Path, output: &Path) -> Result<()> { fn extract(&self, file: &Path, output: &Path) -> Result<()> {
match self { match self {
Format::Zip(zip) => zip.extract(file, output), Format::Zip(zip) => zip.extract(file, output),
Format::Xz(xz) => xz.extract(file, output),
_ => bail!("Not implemented"), _ => bail!("Not implemented"),
} }
} }

@ -0,0 +1,36 @@
use crate::format::{FileFormat, FileObject};
use anyhow::{bail, Context};
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::path::Path;
pub const XZ_HEADER: &[u8] = &[0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00];
pub struct XZFormat;
impl FileFormat for XZFormat {
fn parse(file: &FileObject) -> anyhow::Result<Self> {
if file.header.starts_with(XZ_HEADER) {
if !file.ext.ends_with("xz") && !file.ext.ends_with("lzma") && !file.ext.ends_with("7z")
{
tracing::warn!("The file has a xz signature but not a xz extension.");
}
Ok(Self)
} else {
bail!("Not an xz file");
}
}
fn extract(&self, file: &Path, output: &Path) -> anyhow::Result<()> {
if output.is_dir() {
bail!("The given output is a directory");
}
let mut reader = BufReader::new(File::open(&file).context("Opening input file")?);
let mut output = File::create(&output).context("Creating output file")?;
tracing::debug!("Decompressing file {file:?} to output {output:?}");
lzma_rs::xz_decompress(&mut reader, &mut output).context("Decompressing file")?;
Ok(())
}
}

@ -22,6 +22,9 @@ impl FileFormat for ZipFormat {
} }
fn extract(&self, file: &Path, output: &Path) -> Result<()> { fn extract(&self, file: &Path, output: &Path) -> Result<()> {
if output.is_file() {
bail!("The given output is a file");
}
let file = File::open(file)?; let file = File::open(file)?;
let mut archive = ZipArchive::new(file).context("Opening zip file")?; let mut archive = ZipArchive::new(file).context("Opening zip file")?;
tracing::info!("Zip file with {} entries", archive.len()); tracing::info!("Zip file with {} entries", archive.len());

@ -2,4 +2,3 @@
/// Compression Methods /// Compression Methods
pub const GZIP_HEADER: &[u8] = &[0x1f, 0x8b]; pub const GZIP_HEADER: &[u8] = &[0x1f, 0x8b];
pub const XZ_HEADER: &[u8] = &[0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00];

@ -32,12 +32,6 @@ fn main() {
let args: Args = Args::parse(); let args: Args = Args::parse();
match args.operation { match args.operation {
Operation::Extract { output, file } => { Operation::Extract { output, file } => {
if !output.exists() {
fs::create_dir_all(&output).expect("Failed to create output directory");
}
if output.is_file() {
panic!("The given output path is a file");
}
let format = parse_format(&file).expect("Failed to parse file format"); let format = parse_format(&file).expect("Failed to parse file format");
format format
.extract(&file, &output) .extract(&file, &output)

Loading…
Cancel
Save