GH-90208: Suppress OSError exceptions from pathlib.Path.glob() (GH-104141)

`pathlib.Path.glob()` now suppresses all OSError exceptions, except
those raised from calling `is_dir()` on the top-level path.

Previously, `glob()` suppressed ENOENT, ENOTDIR, EBADF and ELOOP
errors and their Windows equivalents. PermissionError was also
suppressed unless it occurred when calling `is_dir()` on the
top-level path. However, the selector would abort prematurely
if a PermissionError was raised, and so `glob()` could return
incomplete results.
This commit is contained in:
Barney Gale 2023-05-11 01:01:39 +01:00 committed by GitHub
parent 373bca0cc5
commit 94f30c7557
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 45 deletions

View file

@ -142,25 +142,21 @@ class _WildcardSelector(_Selector):
# avoid exhausting file descriptors when globbing deep trees.
with scandir(parent_path) as scandir_it:
entries = list(scandir_it)
except OSError:
pass
else:
for entry in entries:
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
except OSError:
continue
name = entry.name
if self.match(name):
path = parent_path._make_child_relpath(name)
for p in self.successor._select_from(path, scandir):
yield p
except PermissionError:
return
class _RecursiveWildcardSelector(_Selector):
@ -175,28 +171,25 @@ class _RecursiveWildcardSelector(_Selector):
# avoid exhausting file descriptors when globbing deep trees.
with scandir(parent_path) as scandir_it:
entries = list(scandir_it)
except OSError:
pass
else:
for entry in entries:
entry_is_dir = False
try:
entry_is_dir = entry.is_dir(follow_symlinks=False)
except OSError as e:
if not _ignore_error(e):
raise
except OSError:
pass
if entry_is_dir:
path = parent_path._make_child_relpath(entry.name)
for p in self._iterate_directories(path, scandir):
yield p
except PermissionError:
return
def _select_from(self, parent_path, scandir):
try:
successor_select = self.successor._select_from
for starting_point in self._iterate_directories(parent_path, scandir):
for p in successor_select(starting_point, scandir):
yield p
except PermissionError:
return
successor_select = self.successor._select_from
for starting_point in self._iterate_directories(parent_path, scandir):
for p in successor_select(starting_point, scandir):
yield p
class _DoubleRecursiveWildcardSelector(_RecursiveWildcardSelector):