bpo-38894: Fix pathlib.Path.glob in the presence of symlinks and insufficient permissions (GH-18815)
Co-authored-by: Matt Wozniski <mwozniski@bloomberg.net>
(cherry picked from commit eb7560a73d
)
Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
This commit is contained in:
parent
92b72788ec
commit
928b4dd0ed
|
@ -529,23 +529,26 @@ class _WildcardSelector(_Selector):
|
|||
try:
|
||||
entries = list(scandir(parent_path))
|
||||
for entry in entries:
|
||||
entry_is_dir = False
|
||||
try:
|
||||
entry_is_dir = entry.is_dir()
|
||||
except OSError as e:
|
||||
if not _ignore_error(e):
|
||||
raise
|
||||
if not self.dironly or entry_is_dir:
|
||||
name = entry.name
|
||||
if self.match(name):
|
||||
path = parent_path._make_child_relpath(name)
|
||||
for p in self.successor._select_from(path, is_dir, exists, scandir):
|
||||
yield p
|
||||
if self.dironly:
|
||||
try:
|
||||
# "entry.is_dir()" can raise PermissionError
|
||||
# in some cases (see bpo-38894), which is not
|
||||
# among the errors ignored by _ignore_error()
|
||||
if not entry.is_dir():
|
||||
continue
|
||||
except OSError as e:
|
||||
if not _ignore_error(e):
|
||||
raise
|
||||
continue
|
||||
name = entry.name
|
||||
if self.match(name):
|
||||
path = parent_path._make_child_relpath(name)
|
||||
for p in self.successor._select_from(path, is_dir, exists, scandir):
|
||||
yield p
|
||||
except PermissionError:
|
||||
return
|
||||
|
||||
|
||||
|
||||
class _RecursiveWildcardSelector(_Selector):
|
||||
|
||||
def __init__(self, pat, child_parts, flavour):
|
||||
|
|
|
@ -1508,6 +1508,42 @@ class _BasePathTest(object):
|
|||
self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
|
||||
self.assertEqual(set(p.glob("../xyzzy")), set())
|
||||
|
||||
@support.skip_unless_symlink
|
||||
def test_glob_permissions(self):
|
||||
# See bpo-38894
|
||||
P = self.cls
|
||||
base = P(BASE) / 'permissions'
|
||||
base.mkdir()
|
||||
|
||||
file1 = base / "file1"
|
||||
file1.touch()
|
||||
file2 = base / "file2"
|
||||
file2.touch()
|
||||
|
||||
subdir = base / "subdir"
|
||||
|
||||
file3 = base / "file3"
|
||||
file3.symlink_to(subdir / "other")
|
||||
|
||||
# Patching is needed to avoid relying on the filesystem
|
||||
# to return the order of the files as the error will not
|
||||
# happen if the symlink is the last item.
|
||||
|
||||
with mock.patch("os.scandir") as scandir:
|
||||
scandir.return_value = sorted(os.scandir(base))
|
||||
self.assertEqual(len(set(base.glob("*"))), 3)
|
||||
|
||||
subdir.mkdir()
|
||||
|
||||
with mock.patch("os.scandir") as scandir:
|
||||
scandir.return_value = sorted(os.scandir(base))
|
||||
self.assertEqual(len(set(base.glob("*"))), 4)
|
||||
|
||||
subdir.chmod(000)
|
||||
|
||||
with mock.patch("os.scandir") as scandir:
|
||||
scandir.return_value = sorted(os.scandir(base))
|
||||
self.assertEqual(len(set(base.glob("*"))), 4)
|
||||
|
||||
def _check_resolve(self, p, expected, strict=True):
|
||||
q = p.resolve(strict)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Fix a bug that was causing incomplete results when calling
|
||||
``pathlib.Path.glob`` in the presence of symlinks that point
|
||||
to files where the user does not have read access. Patch by Pablo
|
||||
Galindo and Matt Wozniski.
|
Loading…
Reference in New Issue