(
root: &Path,
follow_symlinks: bool,
seen_data_dirs: &mut HashSet<PathBuf>,
stores: &mut Vec<StoreInventory>,
skipped: &mut Vec<SkippedPath>,
)
| 176 | } |
| 177 | |
| 178 | async fn scan_root( |
| 179 | root: &Path, |
| 180 | follow_symlinks: bool, |
| 181 | seen_data_dirs: &mut HashSet<PathBuf>, |
| 182 | stores: &mut Vec<StoreInventory>, |
| 183 | skipped: &mut Vec<SkippedPath>, |
| 184 | ) -> Result<()> { |
| 185 | let mut visited = HashSet::new(); |
| 186 | let mut work = vec![root.to_path_buf()]; |
| 187 | |
| 188 | while let Some(dir) = work.pop() { |
| 189 | let visit_key = if follow_symlinks { |
| 190 | dir.canonicalize().unwrap_or_else(|_| dir.clone()) |
| 191 | } else { |
| 192 | dir.clone() |
| 193 | }; |
| 194 | if !visited.insert(visit_key) { |
| 195 | continue; |
| 196 | } |
| 197 | |
| 198 | inspect_data_dir_candidate( |
| 199 | &dir, |
| 200 | TRACEDECAY_DIR, |
| 201 | follow_symlinks, |
| 202 | seen_data_dirs, |
| 203 | stores, |
| 204 | skipped, |
| 205 | StoreRole::CodeProjectStore, |
| 206 | ) |
| 207 | .await?; |
| 208 | |
| 209 | let Ok(entries) = std::fs::read_dir(&dir) else { |
| 210 | continue; |
| 211 | }; |
| 212 | for entry in entries.flatten() { |
| 213 | let Ok(file_type) = entry.file_type() else { |
| 214 | continue; |
| 215 | }; |
| 216 | let path = entry.path(); |
| 217 | if file_type.is_symlink() && !follow_symlinks { |
| 218 | skipped.push(SkippedPath { |
| 219 | path, |
| 220 | reason: "symlink".to_string(), |
| 221 | }); |
| 222 | continue; |
| 223 | } |
| 224 | if file_type.is_symlink() { |
| 225 | let Ok(meta) = entry.metadata() else { |
| 226 | continue; |
| 227 | }; |
| 228 | if !meta.is_dir() { |
| 229 | continue; |
| 230 | } |
| 231 | } else if !file_type.is_dir() { |
| 232 | continue; |
| 233 | } |
| 234 | let name = entry.file_name(); |
| 235 | let name = name.to_string_lossy(); |
no test coverage detected