changeset: 90095:6370d44013f7 branch: 3.3 parent: 90071:cb3a8abc0870 parent: 90094:9186f4a18584 user: Benjamin Peterson date: Tue Apr 01 19:17:57 2014 -0400 files: Doc/library/os.rst Lib/os.py Lib/test/test_os.py Misc/NEWS description: merge 3.2 (#21082) diff -r cb3a8abc0870 -r 6370d44013f7 Doc/library/os.rst --- a/Doc/library/os.rst Mon Mar 31 13:46:26 2014 -0400 +++ b/Doc/library/os.rst Tue Apr 01 19:17:57 2014 -0400 @@ -1563,11 +1563,8 @@ The default *mode* is ``0o777`` (octal). On some systems, *mode* is ignored. Where it is used, the current umask value is first masked out. - If *exist_ok* is ``False`` (the default), an :exc:`OSError` is raised if - the target directory already exists. If *exist_ok* is ``True`` an - :exc:`OSError` is still raised if the umask-masked *mode* is different from - the existing mode, on systems where the mode is used. :exc:`OSError` will - also be raised if the directory creation fails. + If *exist_ok* is ``False`` (the default), an :exc:`OSError` is raised if the + target directory already exists. .. note:: @@ -1579,6 +1576,13 @@ .. versionadded:: 3.2 The *exist_ok* parameter. + .. versionchanged:: 3.3.6 + + Before Python 3.3.6, if *exist_ok* was ``True`` and the directory existed, + :func:`makedirs` would still raise an error if *mode* did not match the + mode of the existing directory. Since this behavior was impossible to + implement safely, it was removed in Python 3.3.6. See :issue:`21082`. + .. function:: mkfifo(path, mode=0o666, *, dir_fd=None) diff -r cb3a8abc0870 -r 6370d44013f7 Lib/os.py --- a/Lib/os.py Mon Mar 31 13:46:26 2014 -0400 +++ b/Lib/os.py Tue Apr 01 19:17:57 2014 -0400 @@ -230,23 +230,16 @@ SEEK_CUR = 1 SEEK_END = 2 - -def _get_masked_mode(mode): - mask = umask(0) - umask(mask) - return mode & ~mask - # Super directory utilities. # (Inspired by Eric Raymond; the doc strings are mostly his) def makedirs(name, mode=0o777, exist_ok=False): """makedirs(path [, mode=0o777][, exist_ok=False]) - Super-mkdir; create a leaf directory and all intermediate ones. - Works like mkdir, except that any intermediate path segment (not - just the rightmost) will be created if it does not exist. If the - target directory with the same mode as we specified already exists, - raises an OSError if exist_ok is False, otherwise no exception is + Super-mkdir; create a leaf directory and all intermediate ones. Works like + mkdir, except that any intermediate path segment (not just the rightmost) + will be created if it does not exist. If the target directory already + exists, raise an OSError if exist_ok is False. Otherwise no exception is raised. This is recursive. """ @@ -268,20 +261,7 @@ try: mkdir(name, mode) except OSError as e: - dir_exists = path.isdir(name) - expected_mode = _get_masked_mode(mode) - if dir_exists: - # S_ISGID is automatically copied by the OS from parent to child - # directories on mkdir. Don't consider it being set to be a mode - # mismatch as mkdir does not unset it when not specified in mode. - actual_mode = st.S_IMODE(lstat(name).st_mode) & ~st.S_ISGID - else: - actual_mode = -1 - if not (e.errno == errno.EEXIST and exist_ok and dir_exists and - actual_mode == expected_mode): - if dir_exists and actual_mode != expected_mode: - e.strerror += ' (mode %o != expected mode %o)' % ( - actual_mode, expected_mode) + if not exist_ok or e.errno != errno.EEXIST or not path.isdir(name): raise def removedirs(name): diff -r cb3a8abc0870 -r 6370d44013f7 Lib/test/test_os.py --- a/Lib/test/test_os.py Mon Mar 31 13:46:26 2014 -0400 +++ b/Lib/test/test_os.py Tue Apr 01 19:17:57 2014 -0400 @@ -872,7 +872,7 @@ os.makedirs(path, mode) self.assertRaises(OSError, os.makedirs, path, mode) self.assertRaises(OSError, os.makedirs, path, mode, exist_ok=False) - self.assertRaises(OSError, os.makedirs, path, 0o776, exist_ok=True) + os.makedirs(path, 0o776, exist_ok=True) os.makedirs(path, mode=mode, exist_ok=True) os.umask(old_mask) @@ -898,9 +898,8 @@ os.makedirs(path, mode, exist_ok=True) # remove the bit. os.chmod(path, stat.S_IMODE(os.lstat(path).st_mode) & ~S_ISGID) - with self.assertRaises(OSError): - # Should fail when the bit is not already set when demanded. - os.makedirs(path, mode | S_ISGID, exist_ok=True) + # May work even when the bit is not already set when demanded. + os.makedirs(path, mode | S_ISGID, exist_ok=True) finally: os.umask(old_mask) diff -r cb3a8abc0870 -r 6370d44013f7 Misc/NEWS --- a/Misc/NEWS Mon Mar 31 13:46:26 2014 -0400 +++ b/Misc/NEWS Tue Apr 01 19:17:57 2014 -0400 @@ -15,6 +15,9 @@ - Issue #20633: Replace relative import by absolute import. +- Issue #21082: In os.makedirs, do not set the process-wide umask. Note this + changes behavior of makedirs when exist_ok=True. + - Issue #20875: Prevent possible gzip "'read' is not defined" NameError. Patch by Claudiu Popa.