2021-09-10 01:42:49 +00:00
|
|
|
//! Main/scanner process impls
|
|
|
|
|
2021-09-11 15:28:45 +00:00
|
|
|
use crate::analyze::analyze;
|
2021-09-10 01:42:49 +00:00
|
|
|
use crate::cli_options::ScanOpt;
|
2021-09-11 02:44:32 +00:00
|
|
|
use crate::file_results::FileResults;
|
2021-09-10 01:42:49 +00:00
|
|
|
use crate::ser_bridge::SerBridge;
|
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
|
|
|
use path_slash::PathExt;
|
|
|
|
use rayon::prelude::*;
|
|
|
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
use walkdir::{DirEntry, WalkDir};
|
|
|
|
|
|
|
|
use std::env;
|
|
|
|
use std::ffi::OsStr;
|
|
|
|
use std::process::Command;
|
|
|
|
use std::time::Instant;
|
|
|
|
|
|
|
|
pub fn find_files(root: &Path, ignore: &[String]) -> Vec<DirEntry> {
|
|
|
|
let progress = ProgressBar::new_spinner();
|
|
|
|
let mut results = Vec::new();
|
|
|
|
|
|
|
|
for entry in WalkDir::new(root)
|
|
|
|
.follow_links(true)
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|e| e.ok())
|
|
|
|
{
|
|
|
|
let f_name = entry.file_name().to_string_lossy();
|
|
|
|
|
|
|
|
if f_name.ends_with(".swf") && !ignore.iter().any(|x| x == &f_name) {
|
|
|
|
results.push(entry);
|
|
|
|
progress.set_message(format!("Searching for swf files... {}", results.len()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
progress.finish_with_message(format!("Found {} swf files to scan", results.len()));
|
|
|
|
results
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn scan_file<P: AsRef<OsStr>>(exec_path: P, file: DirEntry, name: String) -> FileResults {
|
|
|
|
let start = Instant::now();
|
2021-09-11 02:44:32 +00:00
|
|
|
let mut file_results = FileResults::new(&name);
|
2021-09-10 01:42:49 +00:00
|
|
|
|
|
|
|
let subproc = Command::new(exec_path)
|
|
|
|
.args(&[
|
|
|
|
"execute-report",
|
|
|
|
&file.path().to_string_lossy().into_owned(),
|
|
|
|
])
|
|
|
|
.output();
|
|
|
|
match subproc {
|
|
|
|
Ok(output) => {
|
|
|
|
let mut reader = csv::Reader::from_reader(&output.stdout[..]);
|
|
|
|
for row in reader.deserialize::<FileResults>() {
|
|
|
|
match row {
|
|
|
|
Ok(child_results) => {
|
2021-09-11 14:34:46 +00:00
|
|
|
let FileResults {
|
|
|
|
name: _name,
|
|
|
|
hash,
|
|
|
|
progress,
|
|
|
|
testing_time,
|
|
|
|
compressed_len,
|
|
|
|
uncompressed_len,
|
|
|
|
error,
|
|
|
|
compression,
|
|
|
|
version,
|
|
|
|
stage_size,
|
|
|
|
frame_rate,
|
|
|
|
num_frames,
|
|
|
|
use_direct_blit,
|
|
|
|
use_gpu,
|
|
|
|
use_network_sandbox,
|
|
|
|
vm_type,
|
|
|
|
} = child_results;
|
|
|
|
|
|
|
|
file_results.hash = hash;
|
|
|
|
file_results.progress = progress;
|
|
|
|
file_results.testing_time = testing_time;
|
|
|
|
file_results.compressed_len = compressed_len;
|
|
|
|
file_results.uncompressed_len = uncompressed_len;
|
|
|
|
file_results.error = error;
|
|
|
|
file_results.compression = compression;
|
|
|
|
file_results.version = version;
|
|
|
|
file_results.stage_size = stage_size;
|
|
|
|
file_results.frame_rate = frame_rate;
|
|
|
|
file_results.num_frames = num_frames;
|
|
|
|
file_results.use_direct_blit = use_direct_blit;
|
|
|
|
file_results.use_gpu = use_gpu;
|
|
|
|
file_results.use_network_sandbox = use_network_sandbox;
|
|
|
|
file_results.vm_type = vm_type;
|
2021-09-10 01:42:49 +00:00
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
file_results.error = Some(e.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !output.stderr.is_empty() {
|
|
|
|
let panic_error = String::from_utf8_lossy(&output.stderr).into_owned();
|
|
|
|
file_results.error = Some(
|
|
|
|
file_results
|
|
|
|
.error
|
|
|
|
.map(|e| format!("{}\n{}", e, panic_error))
|
|
|
|
.unwrap_or(panic_error),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => file_results.error = Some(e.to_string()),
|
|
|
|
}
|
|
|
|
|
|
|
|
file_results.testing_time = start.elapsed().as_millis();
|
|
|
|
|
|
|
|
file_results
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The main scanner process.
|
|
|
|
///
|
|
|
|
/// Should be called with parsed options corresponding to the `scan` command.
|
|
|
|
pub fn scan_main(opt: ScanOpt) -> Result<(), std::io::Error> {
|
2021-09-10 22:45:41 +00:00
|
|
|
let binary_path = env::current_exe()?;
|
|
|
|
let to_scan = find_files(&opt.input_path, &opt.ignore);
|
|
|
|
let total = to_scan.len() as u64;
|
|
|
|
let progress = ProgressBar::new(total);
|
|
|
|
let mut writer = csv::Writer::from_path(opt.output_path.clone())?;
|
|
|
|
|
|
|
|
progress.set_style(
|
|
|
|
ProgressStyle::default_bar()
|
|
|
|
.template(
|
|
|
|
"[{elapsed_precise}] {bar:40.cyan/blue} [{eta_precise}] {pos:>7}/{len:7} {msg}",
|
|
|
|
)
|
|
|
|
.progress_chars("##-"),
|
|
|
|
);
|
|
|
|
|
|
|
|
let input_path = opt.input_path;
|
2021-09-11 15:59:29 +00:00
|
|
|
let closure_progress = progress;
|
2021-09-10 22:45:41 +00:00
|
|
|
|
|
|
|
let result_iter = to_scan
|
|
|
|
.into_par_iter()
|
|
|
|
.map(move |file| {
|
|
|
|
let name = file
|
|
|
|
.path()
|
|
|
|
.strip_prefix(&input_path)
|
|
|
|
.unwrap_or_else(|_| file.path())
|
|
|
|
.to_slash_lossy();
|
|
|
|
let result = scan_file(&binary_path, file, name.clone());
|
|
|
|
|
|
|
|
closure_progress.inc(1);
|
|
|
|
closure_progress.set_message(name);
|
|
|
|
|
|
|
|
result
|
|
|
|
})
|
2021-09-11 15:28:45 +00:00
|
|
|
.ser_bridge()
|
|
|
|
.map(|result| {
|
|
|
|
if let Err(e) = writer.serialize(result.clone()) {
|
|
|
|
eprintln!("{}", e);
|
|
|
|
};
|
2021-09-10 01:42:49 +00:00
|
|
|
|
2021-09-11 15:28:45 +00:00
|
|
|
result
|
|
|
|
});
|
2021-09-10 01:42:49 +00:00
|
|
|
|
2021-09-11 15:28:45 +00:00
|
|
|
analyze(result_iter);
|
2021-09-10 22:45:41 +00:00
|
|
|
|
|
|
|
Ok(())
|
2021-09-10 01:42:49 +00:00
|
|
|
}
|