diff options
author | Barney Gale <barney.gale@gmail.com> | 2023-09-26 16:57:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-26 16:57:17 (GMT) |
commit | ecd813f054e0dee890d484b8210e202175abd632 (patch) | |
tree | d3f337b83ab0936b04c00f34f2f3a30e96d78405 /Lib | |
parent | 859618c8cd5de86a975e68d7e5d20c04bc5db2e5 (diff) | |
download | cpython-ecd813f054e0dee890d484b8210e202175abd632.zip cpython-ecd813f054e0dee890d484b8210e202175abd632.tar.gz cpython-ecd813f054e0dee890d484b8210e202175abd632.tar.bz2 |
GH-109187: Improve symlink loop handling in `pathlib.Path.resolve()` (GH-109192)
Treat symlink loops like other errors: in strict mode, raise `OSError`, and
in non-strict mode, do not raise any exception.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/pathlib.py | 21 | ||||
-rw-r--r-- | Lib/test/test_pathlib.py | 13 |
2 files changed, 9 insertions, 25 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py index f4ec315..bd5f61b 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1230,26 +1230,7 @@ class Path(PurePath): normalizing it. """ - def check_eloop(e): - winerror = getattr(e, 'winerror', 0) - if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME: - raise RuntimeError("Symlink loop from %r" % e.filename) - - try: - s = os.path.realpath(self, strict=strict) - except OSError as e: - check_eloop(e) - raise - p = self.with_segments(s) - - # In non-strict mode, realpath() doesn't raise on symlink loops. - # Ensure we get an exception by calling stat() - if not strict: - try: - p.stat() - except OSError as e: - check_eloop(e) - return p + return self.with_segments(os.path.realpath(self, strict=strict)) def owner(self): """ diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 09df3fe..484a5e6 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -3178,10 +3178,11 @@ class PosixPathTest(PathTest): self.assertEqual(str(P('//a').absolute()), '//a') self.assertEqual(str(P('//a/b').absolute()), '//a/b') - def _check_symlink_loop(self, *args, strict=True): + def _check_symlink_loop(self, *args): path = self.cls(*args) - with self.assertRaises(RuntimeError): - print(path.resolve(strict)) + with self.assertRaises(OSError) as cm: + path.resolve(strict=True) + self.assertEqual(cm.exception.errno, errno.ELOOP) @unittest.skipIf( is_emscripten or is_wasi, @@ -3240,7 +3241,8 @@ class PosixPathTest(PathTest): os.symlink('linkZ/../linkZ', join('linkZ')) self._check_symlink_loop(BASE, 'linkZ') # Non-strict - self._check_symlink_loop(BASE, 'linkZ', 'foo', strict=False) + p = self.cls(BASE, 'linkZ', 'foo') + self.assertEqual(p.resolve(strict=False), p) # Loops with absolute symlinks. os.symlink(join('linkU/inside'), join('linkU')) self._check_symlink_loop(BASE, 'linkU') @@ -3249,7 +3251,8 @@ class PosixPathTest(PathTest): os.symlink(join('linkW/../linkW'), join('linkW')) self._check_symlink_loop(BASE, 'linkW') # Non-strict - self._check_symlink_loop(BASE, 'linkW', 'foo', strict=False) + q = self.cls(BASE, 'linkW', 'foo') + self.assertEqual(q.resolve(strict=False), q) def test_glob(self): P = self.cls |