diff options
author | Barney Gale <barney.gale@gmail.com> | 2024-08-23 19:03:11 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-23 19:03:11 (GMT) |
commit | d7ae4dc5c14bc014ca0c056dab54c86ba8f395cb (patch) | |
tree | 3efe697566e955e5825c726586942c0d8a30e633 /Lib/test | |
parent | bf1b5d323bdb6b1609c6f4b31dcaed621e5d0e2f (diff) | |
download | cpython-d7ae4dc5c14bc014ca0c056dab54c86ba8f395cb.zip cpython-d7ae4dc5c14bc014ca0c056dab54c86ba8f395cb.tar.gz cpython-d7ae4dc5c14bc014ca0c056dab54c86ba8f395cb.tar.bz2 |
GH-73991: Disallow copying directory into itself via `pathlib.Path.copy()` (#122924)
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_pathlib/test_pathlib_abc.py | 111 |
1 files changed, 103 insertions, 8 deletions
diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py index f222fd5..5b71475 100644 --- a/Lib/test/test_pathlib/test_pathlib_abc.py +++ b/Lib/test/test_pathlib/test_pathlib_abc.py @@ -1501,19 +1501,20 @@ class DummyPath(PathBase): raise FileNotFoundError(errno.ENOENT, "File not found", path) def mkdir(self, mode=0o777, parents=False, exist_ok=False): - path = str(self.resolve()) - if path in self._directories: + path = str(self.parent.resolve() / self.name) + parent = str(self.parent.resolve()) + if path in self._directories or path in self._symlinks: if exist_ok: return else: raise FileExistsError(errno.EEXIST, "File exists", path) try: if self.name: - self._directories[str(self.parent)].add(self.name) + self._directories[parent].add(self.name) self._directories[path] = set() except KeyError: if not parents: - raise FileNotFoundError(errno.ENOENT, "File not found", str(self.parent)) from None + raise FileNotFoundError(errno.ENOENT, "File not found", parent) from None self.parent.mkdir(parents=True, exist_ok=True) self.mkdir(mode, parents=False, exist_ok=exist_ok) @@ -1759,6 +1760,32 @@ class DummyPathTest(DummyPurePathTest): self.assertEqual(source.readlink(), target.readlink()) @needs_symlinks + def test_copy_symlink_to_itself(self): + base = self.cls(self.base) + source = base / 'linkA' + self.assertRaises(OSError, source.copy, source) + + @needs_symlinks + def test_copy_symlink_to_existing_symlink(self): + base = self.cls(self.base) + source = base / 'copySource' + target = base / 'copyTarget' + source.symlink_to(base / 'fileA') + target.symlink_to(base / 'dirC') + self.assertRaises(OSError, source.copy, target) + self.assertRaises(OSError, source.copy, target, follow_symlinks=False) + + @needs_symlinks + def test_copy_symlink_to_existing_directory_symlink(self): + base = self.cls(self.base) + source = base / 'copySource' + target = base / 'copyTarget' + source.symlink_to(base / 'fileA') + target.symlink_to(base / 'dirC') + self.assertRaises(OSError, source.copy, target) + self.assertRaises(OSError, source.copy, target, follow_symlinks=False) + + @needs_symlinks def test_copy_directory_symlink_follow_symlinks_false(self): base = self.cls(self.base) source = base / 'linkB' @@ -1769,6 +1796,42 @@ class DummyPathTest(DummyPurePathTest): self.assertTrue(target.is_symlink()) self.assertEqual(source.readlink(), target.readlink()) + @needs_symlinks + def test_copy_directory_symlink_to_itself(self): + base = self.cls(self.base) + source = base / 'linkB' + self.assertRaises(OSError, source.copy, source) + self.assertRaises(OSError, source.copy, source, follow_symlinks=False) + + @needs_symlinks + def test_copy_directory_symlink_into_itself(self): + base = self.cls(self.base) + source = base / 'linkB' + target = base / 'linkB' / 'copyB' + self.assertRaises(OSError, source.copy, target) + self.assertRaises(OSError, source.copy, target, follow_symlinks=False) + self.assertFalse(target.exists()) + + @needs_symlinks + def test_copy_directory_symlink_to_existing_symlink(self): + base = self.cls(self.base) + source = base / 'copySource' + target = base / 'copyTarget' + source.symlink_to(base / 'dirC') + target.symlink_to(base / 'fileA') + self.assertRaises(FileExistsError, source.copy, target) + self.assertRaises(FileExistsError, source.copy, target, follow_symlinks=False) + + @needs_symlinks + def test_copy_directory_symlink_to_existing_directory_symlink(self): + base = self.cls(self.base) + source = base / 'copySource' + target = base / 'copyTarget' + source.symlink_to(base / 'dirC' / 'dirD') + target.symlink_to(base / 'dirC') + self.assertRaises(FileExistsError, source.copy, target) + self.assertRaises(FileExistsError, source.copy, target, follow_symlinks=False) + def test_copy_file_to_existing_file(self): base = self.cls(self.base) source = base / 'fileA' @@ -1782,8 +1845,7 @@ class DummyPathTest(DummyPurePathTest): base = self.cls(self.base) source = base / 'fileA' target = base / 'dirA' - with self.assertRaises(OSError): - source.copy(target) + self.assertRaises(OSError, source.copy, target) @needs_symlinks def test_copy_file_to_existing_symlink(self): @@ -1823,6 +1885,13 @@ class DummyPathTest(DummyPurePathTest): self.assertTrue(target.exists()) self.assertEqual(target.read_bytes(), b'') + def test_copy_file_to_itself(self): + base = self.cls(self.base) + source = base / 'empty' + source.write_bytes(b'') + self.assertRaises(OSError, source.copy, source) + self.assertRaises(OSError, source.copy, source, follow_symlinks=False) + def test_copy_dir_simple(self): base = self.cls(self.base) source = base / 'dirC' @@ -1909,6 +1978,28 @@ class DummyPathTest(DummyPurePathTest): self.assertTrue(target.joinpath('fileC').read_text(), "this is file C\n") + def test_copy_dir_to_itself(self): + base = self.cls(self.base) + source = base / 'dirC' + self.assertRaises(OSError, source.copy, source) + self.assertRaises(OSError, source.copy, source, follow_symlinks=False) + + def test_copy_dir_to_itself_on_error(self): + base = self.cls(self.base) + source = base / 'dirC' + errors = [] + source.copy(source, on_error=errors.append) + self.assertEqual(len(errors), 1) + self.assertIsInstance(errors[0], OSError) + + def test_copy_dir_into_itself(self): + base = self.cls(self.base) + source = base / 'dirC' + target = base / 'dirC' / 'dirD' / 'copyC' + self.assertRaises(OSError, source.copy, target) + self.assertRaises(OSError, source.copy, target, follow_symlinks=False) + self.assertFalse(target.exists()) + def test_copy_missing_on_error(self): base = self.cls(self.base) source = base / 'foo' @@ -2876,8 +2967,12 @@ class DummyPathWithSymlinks(DummyPath): raise FileNotFoundError(errno.ENOENT, "File not found", path) def symlink_to(self, target, target_is_directory=False): - self._directories[str(self.parent)].add(self.name) - self._symlinks[str(self)] = str(target) + path = str(self.parent.resolve() / self.name) + parent = str(self.parent.resolve()) + if path in self._symlinks: + raise FileExistsError(errno.EEXIST, "File exists", path) + self._directories[parent].add(self.name) + self._symlinks[path] = str(target) class DummyPathWithSymlinksTest(DummyPathTest): |