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
| 1119 | * it hang. On Windows we additionally skip reparse points before |
| 1120 | * descending as a best-effort early-out. */ |
| 1121 | static int pkgmap_walk_dir(const char *abs_dir, const char *rel_dir, cbm_pkg_entries_t *entries, |
| 1122 | int depth, char **excluded_dirs, int excluded_count) { |
| 1123 | if (depth >= PKGMAP_WALK_MAX_DEPTH) { |
| 1124 | cbm_log_info("pkgmap.walk", "depth_cap", rel_dir && rel_dir[0] ? rel_dir : "."); |
| 1125 | return 0; |
| 1126 | } |
| 1127 | cbm_dir_t *dir = cbm_opendir(abs_dir); |
| 1128 | if (!dir) { |
| 1129 | return 0; |
| 1130 | } |
| 1131 | int parsed = 0; |
| 1132 | cbm_dirent_t *entry; |
| 1133 | while ((entry = cbm_readdir(dir)) != NULL) { |
| 1134 | const char *name = entry->name; |
| 1135 | if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) { |
| 1136 | continue; |
| 1137 | } |
| 1138 | char abs_path[PKGMAP_PATH_BUF]; |
| 1139 | char rel_path[PKGMAP_PATH_BUF]; |
| 1140 | snprintf(abs_path, sizeof(abs_path), "%s/%s", abs_dir, name); |
| 1141 | if (rel_dir && rel_dir[0]) { |
| 1142 | snprintf(rel_path, sizeof(rel_path), "%s/%s", rel_dir, name); |
| 1143 | } else { |
| 1144 | snprintf(rel_path, sizeof(rel_path), "%s", name); |
| 1145 | } |
| 1146 | struct stat st; |
| 1147 | if (pkgmap_safe_stat(abs_path, &st) != 0) { |
| 1148 | continue; |
| 1149 | } |
| 1150 | if (S_ISDIR(st.st_mode)) { |
| 1151 | if (cbm_should_skip_dir(name, CBM_MODE_FULL) || |
| 1152 | cbm_pipeline_relpath_is_excluded(rel_path, excluded_dirs, excluded_count)) { |
| 1153 | continue; |
| 1154 | } |
| 1155 | #ifdef _WIN32 |
| 1156 | /* Don't follow Windows directory junctions — they can form |
| 1157 | * cycles. The depth bound is the hard guarantee; this just |
| 1158 | * avoids wasted descent. (POSIX symlinks are already skipped by |
| 1159 | * pkgmap_safe_stat's S_ISLNK check.) */ |
| 1160 | if (pkgmap_is_reparse_point(abs_path)) { |
| 1161 | continue; |
| 1162 | } |
| 1163 | #endif |
| 1164 | parsed += pkgmap_walk_dir(abs_path, rel_path, entries, depth + 1, excluded_dirs, |
| 1165 | excluded_count); |
| 1166 | continue; |
| 1167 | } |
| 1168 | if (!S_ISREG(st.st_mode)) { |
| 1169 | continue; |
| 1170 | } |
| 1171 | if (!is_pkgmap_manifest_basename(name)) { |
| 1172 | continue; |
| 1173 | } |
| 1174 | int source_len = 0; |
| 1175 | char *source = pkgmap_read_file(abs_path, &source_len); |
| 1176 | if (!source) { |
| 1177 | continue; |
| 1178 | } |
no test coverage detected