Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7407267

Browse filesBrowse files
miss-islingtonbarneygalenineteendo
authored
[3.13] GH-118447: Fix handling of unreadable symlinks in os.path.realpath() (GH-118489) (#119163)
(cherry picked from commit caf6064) Co-authored-by: Barney Gale <barney.gale@gmail.com> Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
1 parent 9129614 commit 7407267
Copy full SHA for 7407267

File tree

3 files changed

+32
-13
lines changed
Filter options

3 files changed

+32
-13
lines changed

‎Lib/posixpath.py

Copy file name to clipboardExpand all lines: Lib/posixpath.py
+13-13Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -471,26 +471,26 @@ def realpath(filename, *, strict=False):
471471
if not stat.S_ISLNK(st.st_mode):
472472
path = newpath
473473
continue
474+
if newpath in seen:
475+
# Already seen this path
476+
path = seen[newpath]
477+
if path is not None:
478+
# use cached value
479+
continue
480+
# The symlink is not resolved, so we must have a symlink loop.
481+
if strict:
482+
# Raise OSError(errno.ELOOP)
483+
os.stat(newpath)
484+
path = newpath
485+
continue
486+
target = os.readlink(newpath)
474487
except OSError:
475488
if strict:
476489
raise
477490
path = newpath
478491
continue
479492
# Resolve the symbolic link
480-
if newpath in seen:
481-
# Already seen this path
482-
path = seen[newpath]
483-
if path is not None:
484-
# use cached value
485-
continue
486-
# The symlink is not resolved, so we must have a symlink loop.
487-
if strict:
488-
# Raise OSError(errno.ELOOP)
489-
os.stat(newpath)
490-
path = newpath
491-
continue
492493
seen[newpath] = None # not resolved symlink
493-
target = os.readlink(newpath)
494494
if target.startswith(sep):
495495
# Symlink target is absolute; reset resolved path.
496496
path = sep

‎Lib/test/test_posixpath.py

Copy file name to clipboardExpand all lines: Lib/test/test_posixpath.py
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,23 @@ def test_realpath_resolve_first(self):
660660
safe_rmdir(ABSTFN + "/k")
661661
safe_rmdir(ABSTFN)
662662

663+
@os_helper.skip_unless_symlink
664+
@skip_if_ABSTFN_contains_backslash
665+
@unittest.skipIf(os.chmod not in os.supports_follow_symlinks, "Can't set symlink permissions")
666+
def test_realpath_unreadable_symlink(self):
667+
try:
668+
os.symlink(ABSTFN+"1", ABSTFN)
669+
os.chmod(ABSTFN, 0o000, follow_symlinks=False)
670+
self.assertEqual(realpath(ABSTFN), ABSTFN)
671+
self.assertEqual(realpath(ABSTFN + '/foo'), ABSTFN + '/foo')
672+
self.assertEqual(realpath(ABSTFN + '/../foo'), dirname(ABSTFN) + '/foo')
673+
self.assertEqual(realpath(ABSTFN + '/foo/..'), ABSTFN)
674+
with self.assertRaises(PermissionError):
675+
realpath(ABSTFN, strict=True)
676+
finally:
677+
os.chmod(ABSTFN, 0o755, follow_symlinks=False)
678+
os.unlink(ABSTFN)
679+
663680
def test_relpath(self):
664681
(real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
665682
try:
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`os.path.realpath` now suppresses any :exc:`OSError` from
2+
:func:`os.readlink` when *strict* mode is disabled (the default).

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.