Skip to content

Commit dcdb578

Browse files
committed
fix(pathlib): avoid zero-inode samefile matches
1 parent 5fd2be0 commit dcdb578

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

src/_pytest/pathlib.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,4 +1095,10 @@ def samefile_nofollow(p1: Path, p2: Path) -> bool:
10951095
10961096
Unlike Path.samefile(), does not resolve symlinks.
10971097
"""
1098-
return os.path.samestat(p1.lstat(), p2.lstat())
1098+
s1, s2 = p1.lstat(), p2.lstat()
1099+
# Some network filesystems report a zero inode for every path. In that
1100+
# case samestat() cannot distinguish different files and would make every
1101+
# collected path match the requested one.
1102+
if not s1.st_ino or not s2.st_ino:
1103+
return False
1104+
return os.path.samestat(s1, s2)

testing/test_pathlib.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from _pytest.pathlib import resolve_pkg_root_and_module_name
4040
from _pytest.pathlib import safe_exists
4141
from _pytest.pathlib import scandir
42+
from _pytest.pathlib import samefile_nofollow
4243
from _pytest.pathlib import spec_matches_module_path
4344
from _pytest.pathlib import symlink_or_skip
4445
from _pytest.pathlib import visit
@@ -570,6 +571,20 @@ def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> N
570571
assert getattr(module, "foo")() == 42
571572

572573

574+
@pytest.mark.parametrize("inodes", [(0, 0), (0, 1), (1, 0)])
575+
def test_samefile_nofollow_rejects_zero_inodes(
576+
inodes: tuple[int, int], monkeypatch: MonkeyPatch
577+
) -> None:
578+
stats = [unittest.mock.Mock(st_ino=inode) for inode in inodes]
579+
lstat = unittest.mock.Mock(side_effect=stats)
580+
samestat = unittest.mock.Mock(return_value=True)
581+
monkeypatch.setattr(Path, "lstat", lstat)
582+
monkeypatch.setattr(os.path, "samestat", samestat)
583+
584+
assert not samefile_nofollow(Path("first"), Path("second"))
585+
samestat.assert_not_called()
586+
587+
573588
def test_scandir_with_non_existent_directory() -> None:
574589
# Test with a directory that does not exist
575590
non_existent_dir = "path_to_non_existent_dir"

0 commit comments

Comments
 (0)