summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/posixpath.py26
-rw-r--r--Lib/test/test_posixpath.py17
-rw-r--r--Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst2
3 files changed, 32 insertions, 13 deletions
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index b4547d7..c04c628 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -471,26 +471,26 @@ symbolic links encountered in the path."""
if not stat.S_ISLNK(st.st_mode):
path = newpath
continue
+ if newpath in seen:
+ # Already seen this path
+ path = seen[newpath]
+ if path is not None:
+ # use cached value
+ continue
+ # The symlink is not resolved, so we must have a symlink loop.
+ if strict:
+ # Raise OSError(errno.ELOOP)
+ os.stat(newpath)
+ path = newpath
+ continue
+ target = os.readlink(newpath)
except OSError:
if strict:
raise
path = newpath
continue
# Resolve the symbolic link
- if newpath in seen:
- # Already seen this path
- path = seen[newpath]
- if path is not None:
- # use cached value
- continue
- # The symlink is not resolved, so we must have a symlink loop.
- if strict:
- # Raise OSError(errno.ELOOP)
- os.stat(newpath)
- path = newpath
- continue
seen[newpath] = None # not resolved symlink
- target = os.readlink(newpath)
if target.startswith(sep):
# Symlink target is absolute; reset resolved path.
path = sep
diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py
index 32a20ef..5c27b7b 100644
--- a/Lib/test/test_posixpath.py
+++ b/Lib/test/test_posixpath.py
@@ -660,6 +660,23 @@ class PosixPathTest(unittest.TestCase):
safe_rmdir(ABSTFN + "/k")
safe_rmdir(ABSTFN)
+ @os_helper.skip_unless_symlink
+ @skip_if_ABSTFN_contains_backslash
+ @unittest.skipIf(os.chmod not in os.supports_follow_symlinks, "Can't set symlink permissions")
+ def test_realpath_unreadable_symlink(self):
+ try:
+ os.symlink(ABSTFN+"1", ABSTFN)
+ os.chmod(ABSTFN, 0o000, follow_symlinks=False)
+ self.assertEqual(realpath(ABSTFN), ABSTFN)
+ self.assertEqual(realpath(ABSTFN + '/foo'), ABSTFN + '/foo')
+ self.assertEqual(realpath(ABSTFN + '/../foo'), dirname(ABSTFN) + '/foo')
+ self.assertEqual(realpath(ABSTFN + '/foo/..'), ABSTFN)
+ with self.assertRaises(PermissionError):
+ realpath(ABSTFN, strict=True)
+ finally:
+ os.chmod(ABSTFN, 0o755, follow_symlinks=False)
+ os.unlink(ABSTFN)
+
def test_relpath(self):
(real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
try:
diff --git a/Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst b/Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst
new file mode 100644
index 0000000..37e27a6
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-01-22-24-05.gh-issue-110863.GjYBbq.rst
@@ -0,0 +1,2 @@
+:func:`os.path.realpath` now suppresses any :exc:`OSError` from
+:func:`os.readlink` when *strict* mode is disabled (the default).