summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2023-12-05 13:44:49 (GMT)
committerGitHub <noreply@github.com>2023-12-05 13:44:49 (GMT)
commit23920a0843f48c4f4be4a31b56ee2e44c058099b (patch)
tree3cfe703c898b0d3ab111fbf25a15afd28df28fb4
parent80c314c9cef7f10e6000474d045986bae0a6d6f2 (diff)
downloadcpython-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.py28
-rw-r--r--Lib/test/test_tempfile.py11
-rw-r--r--Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst4
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.