diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2023-12-05 13:44:49 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-05 13:44:49 (GMT) |
commit | 23920a0843f48c4f4be4a31b56ee2e44c058099b (patch) | |
tree | 3cfe703c898b0d3ab111fbf25a15afd28df28fb4 | |
parent | 80c314c9cef7f10e6000474d045986bae0a6d6f2 (diff) | |
download | cpython-23920a0843f48c4f4be4a31b56ee2e44c058099b.zip cpython-23920a0843f48c4f4be4a31b56ee2e44c058099b.tar.gz cpython-23920a0843f48c4f4be4a31b56ee2e44c058099b.tar.bz2 |
[3.11] bpo-43153: Don't mask `PermissionError` with `NotADirectoryError` during tempdirectory cleanup (GH-29940) (GH-112754)
(cherry picked from commit 8cdfee1bb902fd1e38d79170b751ef13a0907262)
Co-authored-by: Ken Jin <kenjin@python.org>
Co-authored-by: andrei kulakov <andrei.avk@gmail.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
-rw-r--r-- | Lib/tempfile.py | 28 | ||||
-rw-r--r-- | Lib/test/test_tempfile.py | 11 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst | 4 |
3 files changed, 41 insertions, 2 deletions
diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 480c172..aace11f 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -41,6 +41,7 @@ import warnings as _warnings import io as _io import os as _os import shutil as _shutil +import stat as _stat import errno as _errno from random import Random as _Random import sys as _sys @@ -876,8 +877,31 @@ class TemporaryDirectory: try: _os.unlink(path) - # PermissionError is raised on FreeBSD for directories - except (IsADirectoryError, PermissionError): + except IsADirectoryError: + cls._rmtree(path, ignore_errors=ignore_errors) + except PermissionError: + # The PermissionError handler was originally added for + # FreeBSD in directories, but it seems that it is raised + # on Windows too. + # bpo-43153: Calling _rmtree again may + # raise NotADirectoryError and mask the PermissionError. + # So we must re-raise the current PermissionError if + # path is not a directory. + try: + st = _os.lstat(path) + except OSError: + if ignore_errors: + return + raise + if (_stat.S_ISLNK(st.st_mode) or + not _stat.S_ISDIR(st.st_mode) or + (hasattr(st, 'st_file_attributes') and + st.st_file_attributes & _stat.FILE_ATTRIBUTE_REPARSE_POINT and + st.st_reparse_tag == _stat.IO_REPARSE_TAG_MOUNT_POINT) + ): + if ignore_errors: + return + raise cls._rmtree(path, ignore_errors=ignore_errors) except FileNotFoundError: pass diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 2632e77..1242ec7 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1533,6 +1533,17 @@ class TestTemporaryDirectory(BaseTestCase): temp_path.exists(), f"TemporaryDirectory {temp_path!s} exists after cleanup") + @unittest.skipUnless(os.name == "nt", "Only on Windows.") + def test_explicit_cleanup_correct_error(self): + with tempfile.TemporaryDirectory() as working_dir: + temp_dir = self.do_create(dir=working_dir) + with open(os.path.join(temp_dir.name, "example.txt"), 'wb'): + # Previously raised NotADirectoryError on some OSes + # (e.g. Windows). See bpo-43153. + with self.assertRaises(PermissionError): + temp_dir.cleanup() + + @os_helper.skip_unless_symlink def test_cleanup_with_symlink_to_a_directory(self): # cleanup() should not follow symlinks to directories (issue #12464) diff --git a/Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst b/Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst new file mode 100644 index 0000000..7800e0a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst @@ -0,0 +1,4 @@ +On Windows, ``tempfile.TemporaryDirectory`` previously masked a +``PermissionError`` with ``NotADirectoryError`` during directory cleanup. It +now correctly raises ``PermissionError`` if errors are not ignored. Patch by +Andrei Kulakov and Ken Jin. |