Skip to content

Commit 49ca2f4

Browse files
authored
Merge pull request #156 from sricharanreddycheruku/batch7-no-follow-symlink-loops
Avoid following symlink targets when link traversal is disabled
2 parents 4c5a226 + 3a9864c commit 49ca2f4

5 files changed

Lines changed: 32 additions & 1 deletion

File tree

‎CHANGES.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Bug fixes:
3434
- `Issue #146`_: pattern_to_regex raises on three lines git accepts (bare '!', '! ', lone '\').
3535
- `Pull #147`_: Match directory entries with directory-only patterns. `PathSpec.match_entries()` and `.match_tree_entries()` will now match directory entries as directory paths (i.e., with a trailing `/`), instead of as file paths (no trailing `/`).
3636
- `Pull #149`_: Handle directory-open errors through on_error during tree walks.
37+
- `Pull #156`_: Avoid following symbolic link targets when checking file types in ``iter_tree_files(follow_links=False)``.
3738

3839

3940
.. _`Issue #116`: https://github.com/cpburnz/python-pathspec/issues/116
@@ -54,6 +55,7 @@ Bug fixes:
5455
.. _`Pull #147`: https://github.com/cpburnz/python-pathspec/pull/147
5556
.. _`Pull #149`: https://github.com/cpburnz/python-pathspec/pull/149
5657
.. _`Pull #150`: https://github.com/cpburnz/python-pathspec/pull/150
58+
.. _`Pull #150`: https://github.com/cpburnz/python-pathspec/pull/156
5759

5860

5961
1.1.1 (2026-04-26)

‎CHANGES_1.in.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Bug fixes:
3131
- `Issue #146`_: pattern_to_regex raises on three lines git accepts (bare '!', '! ', lone '\').
3232
- `Pull #147`_: Match directory entries with directory-only patterns. `PathSpec.match_entries()` and `.match_tree_entries()` will now match directory entries as directory paths (i.e., with a trailing `/`), instead of as file paths (no trailing `/`).
3333
- `Pull #149`_: Handle directory-open errors through on_error during tree walks.
34+
- `Pull #156`_: Avoid following symbolic link targets when checking file types in ``iter_tree_files(follow_links=False)``.
3435

3536

3637
.. _`Issue #116`: https://github.com/cpburnz/python-pathspec/issues/116
@@ -51,6 +52,7 @@ Bug fixes:
5152
.. _`Pull #147`: https://github.com/cpburnz/python-pathspec/pull/147
5253
.. _`Pull #149`: https://github.com/cpburnz/python-pathspec/pull/149
5354
.. _`Pull #150`: https://github.com/cpburnz/python-pathspec/pull/150
55+
.. _`Pull #150`: https://github.com/cpburnz/python-pathspec/pull/156
5456

5557

5658
1.1.1 (2026-04-26)

‎README-dist.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ Major changes:
236236

237237
Bug fixes:
238238

239+
- Avoid following symbolic link targets when checking file types in ``iter_tree_files(follow_links=False)``.
240+
239241
- `Pull #123`_: Ignore invalid gitignore bracket ranges for `GitIgnoreSpec`.
240242

241243

‎pathspec/util.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ def _iter_tree_files_next(
476476
# files.
477477
yield from _iter_tree_files_next(root_full, node_rel, memo, on_error, follow_links)
478478

479-
elif node_ent.is_file():
479+
elif node_ent.is_file(follow_symlinks=follow_links):
480480
# Child node is a file, yield it.
481481
yield node_rel
482482

‎tests/test_01_util.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,31 @@ def test_02_link_8_no_follow_links_2_files(self):
624624
'DirX',
625625
])))
626626

627+
def test_02_link_9_no_follow_loop_links_2_files(self):
628+
"""
629+
Unfollowed links with cyclic targets are yielded without inspecting targets.
630+
"""
631+
self.require_symlink()
632+
for case, links in [
633+
('Self', [('Loop', 'Loop')]),
634+
('Pair', [('First', 'Second'), ('Second', 'First')]),
635+
]:
636+
with self.subTest(case=case):
637+
self.make_dirs([case, f'{case}/Dir'])
638+
self.make_files([f'{case}/kept.txt', f'{case}/Dir/child.txt'])
639+
self.make_links([
640+
(f'{case}/{link}', f'{case}/{target}')
641+
for link, target in links
642+
])
643+
errors = []
644+
results = set(iter_tree_files(
645+
self.temp_dir / case, follow_links=False, on_error=errors.append,
646+
))
647+
self.assertEqual(results, {
648+
'kept.txt', ospath('Dir/child.txt'), *[link for link, _ in links],
649+
})
650+
self.assertEqual(errors, [])
651+
627652
def test_03_subdir_1_from_filesystem_root(self):
628653
"""
629654
raverse only the requested subtree when the root ends in a separator.

0 commit comments

Comments
 (0)