Stat a path, skipping symlinks (POSIX) and junctions / reparse points * (Windows). Returns 0 on success, -1 to skip. Skipping reparse points keeps * discovery from walking through a junction that points outside the project * root, mirroring the POSIX S_ISLNK skip. */
| 611 | * discovery from walking through a junction that points outside the project |
| 612 | * root, mirroring the POSIX S_ISLNK skip. */ |
| 613 | static int safe_stat(const char *abs_path, struct stat *st) { |
| 614 | #ifdef _WIN32 |
| 615 | wchar_t *wpath = cbm_utf8_to_wide(abs_path); |
| 616 | if (wpath) { |
| 617 | DWORD attr = GetFileAttributesW(wpath); |
| 618 | free(wpath); |
| 619 | if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) { |
| 620 | return CBM_NOT_FOUND; |
| 621 | } |
| 622 | } |
| 623 | return wide_stat(abs_path, st); |
| 624 | #else |
| 625 | if (lstat(abs_path, st) != 0) { |
| 626 | return CBM_NOT_FOUND; |
| 627 | } |
| 628 | if (S_ISLNK(st->st_mode)) { |
| 629 | return CBM_NOT_FOUND; |
| 630 | } |
| 631 | return 0; |
| 632 | #endif |
| 633 | } |
| 634 | |
| 635 | /* Process a single regular file entry during directory walk. */ |
| 636 | static void walk_dir_process_file(const char *abs_path, const char *rel_path, const char *name, |
no test coverage detected