]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-25803: Avoid incorrect errors raised by Path.mkdir(exist_ok=True) (#805)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 24 Mar 2017 18:51:53 +0000 (20:51 +0200)
committerGitHub <noreply@github.com>
Fri, 24 Mar 2017 18:51:53 +0000 (20:51 +0200)
when the OS gives priority to errors such as EACCES over EEXIST.

Lib/pathlib.py
Lib/test/test_pathlib.py
Misc/NEWS

index 9f347216b183a957e6202cf2a09b021bf56ead92..8c1cb96bad3075575f3873fe20c608ce129d9eff 100644 (file)
@@ -1220,25 +1220,23 @@ class Path(PurePath):
         os.close(fd)
 
     def mkdir(self, mode=0o777, parents=False, exist_ok=False):
+        """
+        Create a new directory at this given path.
+        """
         if self._closed:
             self._raise_closed()
-        if not parents:
-            try:
-                self._accessor.mkdir(self, mode)
-            except FileExistsError:
-                if not exist_ok or not self.is_dir():
-                    raise
-        else:
-            try:
-                self._accessor.mkdir(self, mode)
-            except FileExistsError:
-                if not exist_ok or not self.is_dir():
-                    raise
-            except OSError as e:
-                if e.errno != ENOENT or self.parent == self:
-                    raise
-                self.parent.mkdir(parents=True)
-                self._accessor.mkdir(self, mode)
+        try:
+            self._accessor.mkdir(self, mode)
+        except FileNotFoundError:
+            if not parents or self.parent == self:
+                raise
+            self.parent.mkdir(parents=True)
+            self._accessor.mkdir(self, mode)
+        except OSError:
+            # Cannot rely on checking for EEXIST, since the operating system
+            # could give priority to other errors like EACCES or EROFS
+            if not exist_ok or not self.is_dir():
+                raise
 
     def chmod(self, mode):
         """
index 88a93e5802c1cbe48dfc0e07da0f52cf992b8b93..3ff9726d4359ec5457d9c2efb7d982bb74d84fdf 100644 (file)
@@ -1776,6 +1776,11 @@ class _BasePathTest(object):
         self.assertTrue(p.exists())
         self.assertEqual(p.stat().st_ctime, st_ctime_first)
 
+    def test_mkdir_exist_ok_root(self):
+        # Issue #25803: A drive root could raise PermissionError on Windows
+        self.cls('/').resolve().mkdir(exist_ok=True)
+        self.cls('/').resolve().mkdir(parents=True, exist_ok=True)
+
     @only_nt    # XXX: not sure how to test this on POSIX
     def test_mkdir_with_unknown_drive(self):
         for d in 'ZYXWVUTSRQPONMLKJIHGFEDCBA':
index bd43227804dce7a8fbb51da22290a13ac4c017f9..9b0414a8e57b448bfb13c13271d50810aa0e674d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -287,6 +287,9 @@ Extension Modules
 Library
 -------
 
+- bpo-25803: Avoid incorrect errors raised by Path.mkdir(exist_ok=True)
+  when the OS gives priority to errors such as EACCES over EEXIST.
+
 - bpo-29861: Release references to tasks, their arguments and their results
   as soon as they are finished in multiprocessing.Pool.