Recursive filesystem walker that finds and parses package manifest * files independently of the main discovery filter. The main discovery * filter intentionally hides package.json / composer.json etc. from * code indexing (they're config, not source), but pass_pkgmap still * needs to read them to resolve workspace imports. Skips directories * matched by the shared cbm_should_skip_dir helper s
| 845 | * it hang. On Windows we additionally skip reparse points before |
| 846 | * descending as a best-effort early-out. */ |
| 847 | static int pkgmap_walk_dir(const char *abs_dir, const char *rel_dir, cbm_pkg_entries_t *entries, |
| 848 | int depth, char **excluded_dirs, int excluded_count) { |
| 849 | if (depth >= PKGMAP_WALK_MAX_DEPTH) { |
| 850 | cbm_log_info("pkgmap.walk", "depth_cap", rel_dir && rel_dir[0] ? rel_dir : "."); |
| 851 | return 0; |
| 852 | } |
| 853 | cbm_dir_t *dir = cbm_opendir(abs_dir); |
| 854 | if (!dir) { |
| 855 | return 0; |
| 856 | } |
| 857 | int parsed = 0; |
| 858 | cbm_dirent_t *entry; |
| 859 | while ((entry = cbm_readdir(dir)) != NULL) { |
| 860 | const char *name = entry->name; |
| 861 | if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) { |
| 862 | continue; |
| 863 | } |
| 864 | char abs_path[PKGMAP_PATH_BUF]; |
| 865 | char rel_path[PKGMAP_PATH_BUF]; |
| 866 | snprintf(abs_path, sizeof(abs_path), "%s/%s", abs_dir, name); |
| 867 | if (rel_dir && rel_dir[0]) { |
| 868 | snprintf(rel_path, sizeof(rel_path), "%s/%s", rel_dir, name); |
| 869 | } else { |
| 870 | snprintf(rel_path, sizeof(rel_path), "%s", name); |
| 871 | } |
| 872 | struct stat st; |
| 873 | if (pkgmap_safe_stat(abs_path, &st) != 0) { |
| 874 | continue; |
| 875 | } |
| 876 | if (S_ISDIR(st.st_mode)) { |
| 877 | if (cbm_should_skip_dir(name, CBM_MODE_FULL) || |
| 878 | cbm_pipeline_relpath_is_excluded(rel_path, excluded_dirs, excluded_count)) { |
| 879 | continue; |
| 880 | } |
| 881 | #ifdef _WIN32 |
| 882 | /* Don't follow Windows directory junctions — they can form |
| 883 | * cycles. The depth bound is the hard guarantee; this just |
| 884 | * avoids wasted descent. (POSIX symlinks are already skipped by |
| 885 | * pkgmap_safe_stat's S_ISLNK check.) */ |
| 886 | if (pkgmap_is_reparse_point(abs_path)) { |
| 887 | continue; |
| 888 | } |
| 889 | #endif |
| 890 | parsed += pkgmap_walk_dir(abs_path, rel_path, entries, depth + 1, excluded_dirs, |
| 891 | excluded_count); |
| 892 | continue; |
| 893 | } |
| 894 | if (!S_ISREG(st.st_mode)) { |
| 895 | continue; |
| 896 | } |
| 897 | if (!is_pkgmap_manifest_basename(name)) { |
| 898 | continue; |
| 899 | } |
| 900 | int source_len = 0; |
| 901 | char *source = pkgmap_read_file(abs_path, &source_len); |
| 902 | if (!source) { |
| 903 | continue; |
| 904 | } |
no test coverage detected