about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorDavid Roundy <roundyd@physics.oregonstate.edu>2015-12-01 17:29:56 -0500
committerDawid Ciężarkiewicz <dpc@dpc.pw>2017-03-17 20:15:05 -0700
commitdb00ba9eb2afa1a3db24e208cbd63125d0157090 (patch)
treeb2554b6282dc721e64292a50ed88cd4a810df6a6 /src/libstd
parenta559452b05c20041a27f518d262573c56b876b64 (diff)
downloadrust-db00ba9eb2afa1a3db24e208cbd63125d0157090.tar.gz
rust-db00ba9eb2afa1a3db24e208cbd63125d0157090.zip
Fix race condition in fs::create_dir_all
It is more robust to not fail if any directory in a path was created
concurrently. This change lifts rustc internal `create_dir_racy` that
was created to handle such conditions to be new `create_dir_all`
implementation.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/fs.rs24
1 files changed, 20 insertions, 4 deletions
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index b074e8b86b9..bb8b4064fab 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1534,6 +1534,12 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// error conditions for when a directory is being created (after it is
 /// determined to not exist) are outlined by `fs::create_dir`.
 ///
+/// Notable exception is made for situations where any of the directories
+/// specified in the `path` could not be created as it was created concurrently.
+/// Such cases are considered success. In other words: calling `create_dir_all`
+/// concurrently from multiple threads or processes is guaranteed to not fail
+/// due to race itself.
+///
 /// # Examples
 ///
 /// ```
@@ -1769,11 +1775,21 @@ impl DirBuilder {
     }
 
     fn create_dir_all(&self, path: &Path) -> io::Result<()> {
-        if path == Path::new("") || path.is_dir() { return Ok(()) }
-        if let Some(p) = path.parent() {
-            self.create_dir_all(p)?
+        match self.inner.mkdir(path) {
+            Ok(()) => return Ok(()),
+            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()),
+            Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
+            Err(e) => return Err(e),
+        }
+        match path.parent() {
+            Some(p) => try!(create_dir_all(p)),
+            None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")),
+        }
+        match self.inner.mkdir(path) {
+            Ok(()) => Ok(()),
+            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
+            Err(e) => Err(e),
         }
-        self.inner.mkdir(path)
     }
 }