diff options
| author | David Roundy <roundyd@physics.oregonstate.edu> | 2015-12-01 17:29:56 -0500 |
|---|---|---|
| committer | Dawid Ciężarkiewicz <dpc@dpc.pw> | 2017-03-17 20:15:05 -0700 |
| commit | db00ba9eb2afa1a3db24e208cbd63125d0157090 (patch) | |
| tree | b2554b6282dc721e64292a50ed88cd4a810df6a6 /src/libstd | |
| parent | a559452b05c20041a27f518d262573c56b876b64 (diff) | |
| download | rust-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.rs | 24 |
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) } } |
