|
1 | 1 | #[macro_use] |
2 | 2 | extern crate chainsaw; |
3 | 3 |
|
| 4 | +use rayon::prelude::*; |
4 | 5 | use std::fs::{self, File}; |
5 | 6 | use std::io::BufRead; |
6 | 7 | use std::path::PathBuf; |
| 8 | +use std::sync::Arc; |
7 | 9 | use std::{collections::HashSet, io::BufReader}; |
8 | 10 |
|
9 | 11 | use anyhow::{Context, Result}; |
@@ -403,8 +405,7 @@ fn run() -> Result<()> { |
403 | 405 | } |
404 | 406 | cs_eprintln!( |
405 | 407 | "[+] Dumping the contents of forensic artefacts from: {} (extensions: {})", |
406 | | - path |
407 | | - .iter() |
| 408 | + path.iter() |
408 | 409 | .map(|r| r.display().to_string()) |
409 | 410 | .collect::<Vec<_>>() |
410 | 411 | .join(", "), |
@@ -940,37 +941,62 @@ fn run() -> Result<()> { |
940 | 941 | if json { |
941 | 942 | cs_print!("["); |
942 | 943 | } |
943 | | - let mut hits = 0; |
944 | | - for file in &files { |
945 | | - for res in searcher.search(file)?.iter() { |
946 | | - let hit = match res { |
947 | | - Ok(hit) => hit, |
948 | | - Err(e) => { |
949 | | - if skip_errors { |
950 | | - continue; |
| 944 | + |
| 945 | + let total_hits = Arc::new(std::sync::Mutex::new(0)); |
| 946 | + |
| 947 | + files.par_iter().try_for_each(|file| { |
| 948 | + match searcher.search(file) { |
| 949 | + Ok(mut results) => { |
| 950 | + for res in results.iter() { |
| 951 | + let hit = match res { |
| 952 | + Ok(hit) => hit, |
| 953 | + Err(e) => { |
| 954 | + return Err(anyhow::anyhow!( |
| 955 | + "Failed to search file {} - {} (Use --skip-errors to continue processing)", |
| 956 | + file.display(), |
| 957 | + e |
| 958 | + )); |
| 959 | + } |
| 960 | + }; |
| 961 | + |
| 962 | + // Create lock before dealing with JSON print sequence |
| 963 | + let mut hit_count = total_hits.lock().expect("Failed to lock total_hits mutex"); |
| 964 | + |
| 965 | + if json { |
| 966 | + if *hit_count != 0 { |
| 967 | + cs_print!(","); |
| 968 | + } |
| 969 | + cs_print_json!(&hit)?; |
| 970 | + } else if jsonl { |
| 971 | + cs_print_json!(&hit)?; |
| 972 | + cs_println!(); |
| 973 | + } else { |
| 974 | + cs_println!("---"); |
| 975 | + cs_print_yaml!(&hit)?; |
951 | 976 | } |
952 | | - anyhow::bail!("Failed to search file... - {}", e); |
| 977 | + *hit_count += 1; |
953 | 978 | } |
954 | | - }; |
955 | | - if json { |
956 | | - if hits != 0 { |
957 | | - cs_print!(","); |
958 | | - } |
959 | | - cs_print_json!(&hit)?; |
960 | | - } else if jsonl { |
961 | | - cs_print_json!(&hit)?; |
962 | | - cs_println!(); |
963 | | - } else { |
964 | | - cs_println!("---"); |
965 | | - cs_print_yaml!(&hit)?; |
966 | 979 | } |
967 | | - hits += 1; |
| 980 | + Err(e) => { |
| 981 | + return Err(anyhow::anyhow!( |
| 982 | + "Failed to search file {} - {} (Use --skip-errors to continue processing)", |
| 983 | + file.display(), |
| 984 | + e |
| 985 | + )); |
| 986 | + } |
968 | 987 | } |
969 | | - } |
| 988 | + |
| 989 | + |
| 990 | + Ok(()) |
| 991 | + })?; |
| 992 | + |
970 | 993 | if json { |
971 | 994 | cs_println!("]"); |
972 | 995 | } |
973 | | - cs_eprintln!("[+] Found {} hits", hits); |
| 996 | + cs_eprintln!( |
| 997 | + "[+] Found {} hits", |
| 998 | + *total_hits.lock().expect("Failed to lock total_hits mutex") |
| 999 | + ); |
974 | 1000 | } |
975 | 1001 | Command::Analyse { cmd } => { |
976 | 1002 | match cmd { |
|
0 commit comments