]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-38894: Fix pathlib.Path.glob in the presence of symlinks and insufficient permiss...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 7 Mar 2020 18:11:24 +0000 (10:11 -0800)
committerGitHub <noreply@github.com>
Sat, 7 Mar 2020 18:11:24 +0000 (10:11 -0800)
Co-authored-by: Matt Wozniski <mwozniski@bloomberg.net>
(cherry picked from commit eb7560a73d46800e4ade4a8869139b48e6c92811)

Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
Lib/pathlib.py
Lib/test/test_pathlib.py
Misc/NEWS.d/next/Core and Builtins/2020-03-06-21-04-39.bpo-38894.nfcGKv.rst [new file with mode: 0644]

index 015370a860e656f6bec1fe7c576cb81a10be0e04..d188026bcde840b6f035f859b16a2e73f94f0101 100644 (file)
@@ -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):
index 97fc5d8ad783829f502455952a3941648669ed71..36226948222d642b1cdbcb20ba88ac757ba62c2e 100644 (file)
@@ -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)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-03-06-21-04-39.bpo-38894.nfcGKv.rst b/Misc/NEWS.d/next/Core and Builtins/2020-03-06-21-04-39.bpo-38894.nfcGKv.rst
new file mode 100644 (file)
index 0000000..a937b8e
--- /dev/null
@@ -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.