3d0d477
# This is a backport of following upstream patch:
3d0d477
# HG changeset patch
3d0d477
# User Benjamin Peterson <benjamin@python.org>
3d0d477
# Date 1396394277 14400
3d0d477
# Node ID 6370d44013f7e7e0892dd7f78b91d3a929e2d343
3d0d477
# Parent  cb3a8abc0870d8d81a3521b3c8f397c5ccc73d7d# Parent  9186f4a18584f5038a9f875f2a7a3194ee46a571
3d0d477
merge 3.2 (#21082)
3d0d477
3d0d477
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
3d0d477
--- a/Doc/library/os.rst
3d0d477
+++ b/Doc/library/os.rst
3d0d477
@@ -1563,11 +1563,8 @@ features:
3d0d477
    The default *mode* is ``0o777`` (octal).  On some systems, *mode* is
3d0d477
    ignored.  Where it is used, the current umask value is first masked out.
3d0d477
 
3d0d477
-   If *exists_ok* is ``False`` (the default), an :exc:`OSError` is raised if
3d0d477
-   the target directory already exists.  If *exists_ok* is ``True`` an
3d0d477
-   :exc:`OSError` is still raised if the umask-masked *mode* is different from
3d0d477
-   the existing mode, on systems where the mode is used.  :exc:`OSError` will
3d0d477
-   also be raised if the directory creation fails.
3d0d477
+   If *exist_ok* is ``False`` (the default), an :exc:`OSError` is raised if the
3d0d477
+   target directory already exists.
3d0d477
 
3d0d477
    .. note::
3d0d477
 
3d0d477
diff --git a/Lib/os.py b/Lib/os.py
3d0d477
--- a/Lib/os.py
3d0d477
+++ b/Lib/os.py
3d0d477
@@ -230,23 +230,16 @@ SEEK_SET = 0
3d0d477
 SEEK_CUR = 1
3d0d477
 SEEK_END = 2
3d0d477
 
3d0d477
-
3d0d477
-def _get_masked_mode(mode):
3d0d477
-    mask = umask(0)
3d0d477
-    umask(mask)
3d0d477
-    return mode & ~mask
3d0d477
-
3d0d477
 # Super directory utilities.
3d0d477
 # (Inspired by Eric Raymond; the doc strings are mostly his)
3d0d477
 
3d0d477
 def makedirs(name, mode=0o777, exist_ok=False):
3d0d477
     """makedirs(path [, mode=0o777][, exist_ok=False])
3d0d477
 
3d0d477
-    Super-mkdir; create a leaf directory and all intermediate ones.
3d0d477
-    Works like mkdir, except that any intermediate path segment (not
3d0d477
-    just the rightmost) will be created if it does not exist. If the
3d0d477
-    target directory with the same mode as we specified already exists,
3d0d477
-    raises an OSError if exist_ok is False, otherwise no exception is
3d0d477
+    Super-mkdir; create a leaf directory and all intermediate ones.  Works like
3d0d477
+    mkdir, except that any intermediate path segment (not just the rightmost)
3d0d477
+    will be created if it does not exist. If the target directory already
3d0d477
+    exists, raise an OSError if exist_ok is False. Otherwise no exception is
3d0d477
     raised.  This is recursive.
3d0d477
 
3d0d477
     """
3d0d477
@@ -268,20 +261,7 @@ def makedirs(name, mode=0o777, exist_ok=
3d0d477
     try:
3d0d477
         mkdir(name, mode)
3d0d477
     except OSError as e:
3d0d477
-        dir_exists = path.isdir(name)
3d0d477
-        expected_mode = _get_masked_mode(mode)
3d0d477
-        if dir_exists:
3d0d477
-            # S_ISGID is automatically copied by the OS from parent to child
3d0d477
-            # directories on mkdir.  Don't consider it being set to be a mode
3d0d477
-            # mismatch as mkdir does not unset it when not specified in mode.
3d0d477
-            actual_mode = st.S_IMODE(lstat(name).st_mode) & ~st.S_ISGID
3d0d477
-        else:
3d0d477
-            actual_mode = -1
3d0d477
-        if not (e.errno == errno.EEXIST and exist_ok and dir_exists and
3d0d477
-                actual_mode == expected_mode):
3d0d477
-            if dir_exists and actual_mode != expected_mode:
3d0d477
-                e.strerror += ' (mode %o != expected mode %o)' % (
3d0d477
-                        actual_mode, expected_mode)
3d0d477
+        if not exist_ok or e.errno != errno.EEXIST or not path.isdir(name):
3d0d477
             raise
3d0d477
 
3d0d477
 def removedirs(name):
3d0d477
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
3d0d477
--- a/Lib/test/test_os.py
3d0d477
+++ b/Lib/test/test_os.py
3d0d477
@@ -872,7 +872,7 @@ class MakedirTests(unittest.TestCase):
3d0d477
         os.makedirs(path, mode)
3d0d477
         self.assertRaises(OSError, os.makedirs, path, mode)
3d0d477
         self.assertRaises(OSError, os.makedirs, path, mode, exist_ok=False)
3d0d477
-        self.assertRaises(OSError, os.makedirs, path, 0o776, exist_ok=True)
3d0d477
+        os.makedirs(path, 0o776, exist_ok=True)
3d0d477
         os.makedirs(path, mode=mode, exist_ok=True)
3d0d477
         os.umask(old_mask)
3d0d477
 
3d0d477
@@ -898,9 +898,8 @@ class MakedirTests(unittest.TestCase):
3d0d477
             os.makedirs(path, mode, exist_ok=True)
3d0d477
             # remove the bit.
3d0d477
             os.chmod(path, stat.S_IMODE(os.lstat(path).st_mode) & ~S_ISGID)
3d0d477
-            with self.assertRaises(OSError):
3d0d477
-                # Should fail when the bit is not already set when demanded.
3d0d477
-                os.makedirs(path, mode | S_ISGID, exist_ok=True)
3d0d477
+            # May work even when the bit is not already set when demanded.
3d0d477
+            os.makedirs(path, mode | S_ISGID, exist_ok=True)
3d0d477
         finally:
3d0d477
             os.umask(old_mask)
3d0d477