From 3ac0e68275cfd12c8d92e08602155d707b04e58d Mon Sep 17 00:00:00 2001 From: specCon18 Date: Wed, 30 Aug 2023 11:37:18 -0400 Subject: [PATCH] Can now untar --- Cargo.lock | 33 +++++++++++++++++ Cargo.toml | 1 + src/main.rs | 102 ++++++++++++++++++++++++---------------------------- 3 files changed, 81 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac97b32..b178713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,6 +230,7 @@ dependencies = [ "eyre", "indicatif", "rayon", + "tar", ] [[package]] @@ -242,6 +243,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.48.0", +] + [[package]] name = "gimli" version = "0.27.3" @@ -521,6 +534,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -759,3 +783,12 @@ name = "windows_x86_64_msvc" version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1" + +[[package]] +name = "xattr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +dependencies = [ + "libc", +] diff --git a/Cargo.toml b/Cargo.toml index f51b2d5..5db2c5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ crossterm = "0.27.0" eyre = "0.6.8" indicatif = "0.17.6" rayon = "1.7.0" +tar = "0.4.40" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5da0554..b46e22a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,80 +1,72 @@ -use clap::{App, Arg}; -use crossterm::style::{Color, Print, ResetColor, SetForegroundColor,ExecutableCommand}; use indicatif::{ProgressBar, ProgressStyle}; -use std::{io::stdout, path::Path, process::Command}; +use std::{ + io, + path::Path, + fs::{self, File}, +}; +use rayon::prelude::*; +use tar::Archive; fn main() -> color_eyre::eyre::Result<()> { color_eyre::install()?; - let app = App::new("extract") - .arg( - Arg::with_name("files") - .required(true) - .multiple(true) - .help("Files to be extracted"), + + let app = clap::App::new("extract") + .arg( + clap::Arg::with_name("files") + .required(true) + .multiple(true) + .help("Files to be extracted"), ); -let matches = app.get_matches(); + let matches = app.get_matches(); let files: Vec<_> = matches.values_of("files").unwrap().collect(); + let pb = ProgressBar::new(files.len() as u64); - pb.set_style(ProgressStyle::default_bar() - .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")? - .progress_chars("#>-")); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")?, + ); files.par_iter().for_each(|file| { - if let Err(err) = extract_file(file) { - // You can handle the error here, perhaps by printing a message. + if let Err(err) = extract_file(file, "output_directory/") { println!("Error extracting file '{}': {}", file, err); } pb.inc(1); }); - pb.finish_with_message("All files extracted successfully!"); Ok(()) } +fn extract_tar(file: &str, output_dir: &str) -> color_eyre::eyre::Result<()> { + let tar_file = File::open(file)?; + let mut a = Archive::new(tar_file); -fn extract_file(file: &str) -> color_eyre::eyre::Result<()> { - if !Path::new(file).exists() { - return Err(color_eyre::eyre::eyre!("'{}' - file does not exist", file)); - } + for i in a.entries()? { + let mut i = i?; + let entry_path = i.header().path()?; + let full_path = Path::new(output_dir).join(entry_path); - let command = match Path::new(file).extension().and_then(|s| s.to_str()) { - Some("tar") | Some("tar.gz") | Some("tar.xz") | Some("tbz2") | Some("tgz") | Some("txz") => "tar", - Some("lzma") => "unlzma", - Some("bz2") => "bunzip2", - Some("rar") => "unrar", - Some("gz") => "gunzip", - Some("zip") => "unzip", - Some("z") => "uncompress", - Some("7z") | Some("arj") | Some("cab") | Some("chm") | Some("deb") | Some("dmg") | Some("iso") | Some("lzh") | Some("msi") | Some("rpm") | Some("udf") | Some("wim") | Some("xar") => "7z", - Some("xz") => "unxz", - Some("exe") => "cabextract", - _ => { - println!("extract: '{}' - unknown archive method", file); - return Ok(()); + if i.header().entry_type().is_dir() { + fs::create_dir_all(&full_path)?; + } else { + fs::create_dir_all(&full_path.parent().unwrap())?; + + let mut file = File::create(&full_path)?; + io::copy(&mut i, &mut file)?; } - }; - - let args = match command { - "tar" => vec!["xvf", file], - "unrar" => vec!["x", "-ad", file], - "7z" => vec!["x", file], - _ => vec![file], - }; - - let output = Command::new(command).args(&args).output()?; - - if !output.status.success() { - let mut stdout = stdout(); - stdout - .execute(SetForegroundColor(Color::Red))? - .execute(Print(format!( - "Failed to extract '{}', command returned error\n", - file - )))? - .execute(ResetColor)?; - return Err(eyre::eyre!("Extraction failed for {}", file)); } Ok(()) } + +fn extract_file(file: &str, output_dir: &str) -> color_eyre::eyre::Result<()> { + if !Path::new(file).exists() { + return Err(color_eyre::eyre::eyre!("'{}' - file does not exist", file)); + } + if let Some("tar") = Path::new(file).extension().and_then(|s| s.to_str()) { + extract_tar(file, output_dir)?; + } else { + println!("extract: '{}' - unknown archive method", file); + } + Ok(()) +} \ No newline at end of file