diff --git a/apps/gridcraft-cli/src/check.rs b/apps/gridcraft-cli/src/check.rs index 5fc37b14c..f5b699b6d 100644 --- a/apps/gridcraft-cli/src/check.rs +++ b/apps/gridcraft-cli/src/check.rs @@ -278,7 +278,7 @@ fn collect_inputs(inputs: &[String]) -> Discovery { } /// Returns false only when the global file budget stops traversal. -fn walk(dir: &Path, depth: usize, out: &mut Discovery, seen: &mut std::collections::HashSet) -> bool { +fn walk(dir: &Path, depth: usize, out: &mut Discovery, seen: &mut std::collections::HashSet<(u64, u64)>) -> bool { // A directory is visited once by identity (dev+inode on unix): several links to the same // directory are aliases, not exponential branches of the scan. Other platforms keep the // depth cap only. @@ -286,8 +286,7 @@ fn walk(dir: &Path, depth: usize, out: &mut Discovery, seen: &mut std::collectio { use std::os::unix::fs::MetadataExt as _; if let Ok(m) = std::fs::metadata(dir) - && let Some(id) = m.dev().checked_mul(1 << 60).and_then(|d| d.checked_add(m.ino())) - && !seen.insert(id) + && !seen.insert((m.dev(), m.ino())) { return true; } diff --git a/xtask/src/stats.rs b/xtask/src/stats.rs index 462f1c7de..2c5778d55 100644 --- a/xtask/src/stats.rs +++ b/xtask/src/stats.rs @@ -13,7 +13,10 @@ struct Counts { proptests: usize, } -fn walk(dir: &Path, c: &mut Counts, seen: &mut std::collections::HashSet, budget: &mut usize) { +/// Larger files (or devices behind a symlink) are not source files and are not read. +const MAX_SOURCE_BYTES: u64 = 16 << 20; + +fn walk(dir: &Path, c: &mut Counts, seen: &mut std::collections::HashSet<(u64, u64)>, budget: &mut usize) { if *budget == 0 { // Hard stop for pathological trees: two directory symlinks pointing at each other // would otherwise be walked exponentially. @@ -22,9 +25,9 @@ fn walk(dir: &Path, c: &mut Counts, seen: &mut std::collections::HashSet, b // Directory identities (dev+inode on unix) make a symlink to a visited directory a // no-op, not another exponential branch of the scan. #[cfg(unix)] - let id = std::fs::metadata(dir).ok().and_then(|m| m.dev().checked_mul(1 << 60).and_then(|d| d.checked_add(m.ino()))); + let id = std::fs::metadata(dir).ok().map(|m| (m.dev(), m.ino())); #[cfg(not(unix))] - let id: Option = None; + let id: Option<(u64, u64)> = None; if let Some(id) = id && !seen.insert(id) { @@ -45,6 +48,7 @@ fn walk(dir: &Path, c: &mut Counts, seen: &mut std::collections::HashSet, b walk(&p, c, seen, budget); } } else if name.ends_with(".rs") + && p.metadata().is_ok_and(|m| m.is_file() && m.len() <= MAX_SOURCE_BYTES) && let Ok(s) = std::fs::read_to_string(&p) { c.files += 1;