Skip to content

fix(sync): exclude symlinked files from discovery results#2849

Merged
tusharmath merged 2 commits intomainfrom
symlink-ignore
Apr 5, 2026
Merged

fix(sync): exclude symlinked files from discovery results#2849
tusharmath merged 2 commits intomainfrom
symlink-ignore

Conversation

@tusharmath
Copy link
Copy Markdown
Collaborator

@tusharmath tusharmath commented Apr 5, 2026

Summary

Exclude symlinked files from file discovery results in both the filesystem walker and the filter_and_resolve pipeline, ensuring only real files are ever indexed or synced.

Context

Both the Walker (used for general directory traversal) and filter_and_resolve (used for the sync pipeline via git or walker-based discovery) could previously surface symlinks as indexable files. This caused problems because symlinks may point to files outside the workspace, create circular paths, or be dangling (pointing to non-existent targets) — all of which are invalid inputs for the indexing and sync pipeline.

Changes

  • forge_walker: Added a symlink guard in get_blocking() using entry.path_is_symlink() from the ignore crate's DirEntry, which correctly identifies symlinks without following them. Both regular and dangling symlinks are filtered out before any further processing.
  • forge_services/fd: Added an is_symlink() helper that uses symlink_metadata() (which does not follow the link) and wired it into filter_and_resolve() as an early filter before the extension check. This covers symlinks surfaced by git-based discovery as well as walker-based discovery.

Key Implementation Details

  • path_is_symlink() in the walker relies on the ignore::DirEntry API, which reads the symlink bit from the directory entry without stat-following — making it safe and efficient even for dangling symlinks.
  • symlink_metadata() in fd.rs is the POSIX equivalent (lstat); it returns the metadata of the link itself rather than its target, so dangling links are still correctly identified and excluded.
  • Symlink filtering is applied as the first step in filter_and_resolve, before the extension allow-list filter, so no unnecessary filesystem work is done on links.

Testing

Tests were added for all symlink scenarios in both crates:

forge_walker:

cargo test -p forge_walker test_walker_excludes_symlinks
cargo test -p forge_walker test_walker_excludes_dangling_symlinks

forge_services:

cargo test -p forge_services test_filter_and_resolve_excludes_symlinks
cargo test -p forge_services test_filter_and_resolve_excludes_dangling_symlinks
cargo test -p forge_services test_filter_and_resolve_excludes_symlinks_to_directories

Or run all tests at once:

cargo insta test --accept

@github-actions github-actions bot added the type: fix Iterations on existing features or infrastructure. label Apr 5, 2026
@tusharmath tusharmath changed the title fix(walker,fd): exclude symlinked files from discovery results fix(sync): exclude symlinked files from discovery results Apr 5, 2026
@tusharmath tusharmath merged commit 09fbef3 into main Apr 5, 2026
12 checks passed
@tusharmath tusharmath deleted the symlink-ignore branch April 5, 2026 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: fix Iterations on existing features or infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant