util: make ensuredirs safer against races
authorBryan O'Sullivan <bryano@fb.com>
Wed, 13 Feb 2013 12:20:10 -0800
changeset 18678 423eee0b0b14
parent 18677 539210ed2069
child 18680 15711d9d8b2c
util: make ensuredirs safer against races
mercurial/scmutil.py
mercurial/util.py
--- a/mercurial/scmutil.py	Wed Feb 13 11:07:01 2013 -0800
+++ b/mercurial/scmutil.py	Wed Feb 13 12:20:10 2013 -0800
@@ -306,8 +306,7 @@
             # to a directory. Let the posixfile() call below raise IOError.
             if basename:
                 if atomictemp:
-                    if not os.path.isdir(dirname):
-                        util.ensuredirs(dirname, self.createmode)
+                    util.ensuredirs(dirname, self.createmode)
                     return util.atomictempfile(f, mode, self.createmode)
                 try:
                     if 'w' in mode:
@@ -325,8 +324,7 @@
                     if e.errno != errno.ENOENT:
                         raise
                     nlink = 0
-                    if not os.path.isdir(dirname):
-                        util.ensuredirs(dirname, self.createmode)
+                    util.ensuredirs(dirname, self.createmode)
                 if nlink > 0:
                     if self._trustnlink is None:
                         self._trustnlink = nlink > 1 or util.checknlink(f)
@@ -345,9 +343,7 @@
         except OSError:
             pass
 
-        dirname = os.path.dirname(linkname)
-        if not os.path.exists(dirname):
-            util.ensuredirs(dirname, self.createmode)
+        util.ensuredirs(os.path.dirname(linkname), self.createmode)
 
         if self._cansymlink:
             try:
--- a/mercurial/util.py	Wed Feb 13 11:07:01 2013 -0800
+++ b/mercurial/util.py	Wed Feb 13 12:20:10 2013 -0800
@@ -882,13 +882,20 @@
 
 def ensuredirs(name, mode=None):
     """race-safe recursive directory creation"""
+    if os.path.isdir(name):
+        return
+    parent = os.path.dirname(os.path.abspath(name))
+    if parent != name:
+        ensuredirs(parent, mode)
     try:
-        makedirs(name, mode)
+        os.mkdir(name)
     except OSError, err:
         if err.errno == errno.EEXIST and os.path.isdir(name):
             # someone else seems to have won a directory creation race
             return
         raise
+    if mode is not None:
+        os.chmod(name, mode)
 
 def readfile(path):
     fp = open(path, 'rb')