67 lines
1.9 KiB
Rust
67 lines
1.9 KiB
Rust
use memmap2::Mmap;
|
|
use once_cell::sync::Lazy;
|
|
use rayon::prelude::*;
|
|
use regex::Regex;
|
|
use serde_json::json;
|
|
use std::{
|
|
collections::BTreeMap,
|
|
env, fs,
|
|
fs::File,
|
|
path::{Path, PathBuf},
|
|
};
|
|
use walkdir::WalkDir;
|
|
use xxhash_rust::xxh3::xxh3_64;
|
|
|
|
static RE: Lazy<Regex> = Lazy::new(|| {
|
|
Regex::new(r"(metin2\.exe|granny2\.dll|SpeedTreeRT\.dll|BGM[/\\].*|lib[/\\].*|pack[/\\].*)")
|
|
.unwrap()
|
|
});
|
|
|
|
fn hash_file(path: &Path, base_path: &String) -> (String, String) {
|
|
let file = File::open(path).expect("Failed to open file");
|
|
let mmap = unsafe { Mmap::map(&file).expect("Failed to mmap file") };
|
|
let hash = xxh3_64(&mmap);
|
|
let hash_str = hash.to_string();
|
|
|
|
let filename = path.to_str().unwrap().to_string().replace(base_path, "");
|
|
(filename, hash_str)
|
|
}
|
|
|
|
fn collect_files(folder: &Path) -> Vec<PathBuf> {
|
|
WalkDir::new(folder)
|
|
.into_iter()
|
|
.filter_map(|e| e.ok())
|
|
.filter(|e| e.path().is_file() && RE.is_match(e.path().to_str().unwrap()))
|
|
.map(|e| e.path().to_path_buf())
|
|
.collect()
|
|
}
|
|
|
|
fn main() -> std::io::Result<()> {
|
|
use std::time::Instant;
|
|
let now = Instant::now();
|
|
|
|
let args: Vec<String> = env::args().collect();
|
|
if args.len() != 2 {
|
|
eprintln!("Usage: {} <folder>", args[0]);
|
|
std::process::exit(1);
|
|
}
|
|
|
|
let folder = Path::new(&args[1]);
|
|
if !folder.is_dir() {
|
|
eprintln!("Error: '{}' is not a directory", folder.display());
|
|
std::process::exit(1);
|
|
}
|
|
|
|
let files = collect_files(folder);
|
|
|
|
let results: BTreeMap<String, String> =
|
|
files.par_iter().map(|f| hash_file(f, &args[1])).collect();
|
|
|
|
let json_output = json!({ "checksums": results });
|
|
|
|
fs::write("checksum.json", serde_json::to_string_pretty(&json_output)?)?;
|
|
let elapsed = now.elapsed();
|
|
println!("Generated 'checksum', elapsed {:.2?}", elapsed);
|
|
Ok(())
|
|
}
|