diff --git a/senbei-cli/src/main.rs b/senbei-cli/src/main.rs index f861f10..2c226bd 100644 --- a/senbei-cli/src/main.rs +++ b/senbei-cli/src/main.rs @@ -106,7 +106,7 @@ fn print_help() { ); println!( " --scan-all probe every file in a folder, including ones the scan\n\ - \x20 pre-filter skips (under 4128 bytes, or a bulk-asset\n\ - \x20 extension like .ab/.xml/.acb). Much slower on game trees." + \x20 pre-filter skips (under 4128 bytes, extensionless,\n\ + \x20 or a bulk-asset extension). Much slower on large trees." ); } diff --git a/senbei-io/src/job.rs b/senbei-io/src/job.rs index 32d315a..bf51120 100644 --- a/senbei-io/src/job.rs +++ b/senbei-io/src/job.rs @@ -387,9 +387,9 @@ pub fn run_folder_v( /// /// When `scan_all` is true every regular file under `root` is opened and /// content-probed, instead of skipping ones the free directory metadata already -/// rules out (too small to hold a Crackproof key table, or a bulk-asset -/// extension). See [`crate::scan::find_targets_opts`] — exhaustive scanning is -/// dramatically slower on asset-heavy game trees and finds the same targets. +/// rules out (extensionless, too small to hold a Crackproof key table, or a +/// bulk-asset extension). See [`crate::scan::find_targets_opts`] — exhaustive +/// scanning is dramatically slower on asset-heavy trees. pub fn run_folder_opts( root: &Path, out_dir: Option<&Path>, diff --git a/senbei-io/src/scan.rs b/senbei-io/src/scan.rs index 43f46ee..8f3bbed 100644 --- a/senbei-io/src/scan.rs +++ b/senbei-io/src/scan.rs @@ -28,12 +28,11 @@ const MIN_SIZE: u64 = 4128; /// File extensions that are bulk data by construction and can never be a PE /// image or an il2cpp metadata blob. /// -/// This is deliberately a **deny**-list, not an allow-list: the default is to -/// probe, so anything unrecognised is still opened. Targets are recognised by -/// content, not extension, and can carry arbitrary names — there is no closed -/// set of target extensions an allow-list of `exe`/`dll` could enumerate. -/// Only extensions that are bulk asset or text formats by construction appear -/// here. +/// This is deliberately a **deny**-list, not an executable allow-list: unknown +/// extensions are still probed. Extensionless files are handled separately by +/// [`denied_name`] because asset stores commonly contain tens of thousands of +/// extensionless chunks; exhaustive probing remains available through +/// `--scan-all`. /// /// Set `SENBEI_SCAN_ALL=1` (or pass `--scan-all`) to probe every file regardless. const DENY_EXT: &[&str] = &[ @@ -90,11 +89,12 @@ const DENY_EXT: &[&str] = &[ "sr", ]; -/// Whether `path`'s extension is on [`DENY_EXT`]. Extensionless files are never -/// denied (they could be anything). -fn denied_ext(path: &Path) -> bool { +/// Whether `path` can be skipped from its name alone. Extensionless files and +/// files whose extension is on [`DENY_EXT`] are not opened during a default +/// scan. `--scan-all` remains available when exhaustive probing is required. +fn denied_name(path: &Path) -> bool { let Some(ext) = path.extension() else { - return false; + return true; }; let Some(ext) = ext.to_str() else { return false; @@ -206,12 +206,17 @@ pub fn find_targets_opts(root: &Path, scan_all: bool) -> (Vec, Vec