Skip to content

Commit 4081c14

Browse files
committed
create_dir_all() operates iteratively instead of recursively
1 parent 34a8c73 commit 4081c14

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

‎library/std/src/fs.rs‎

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3333,26 +3333,42 @@ impl DirBuilder {
33333333
return Ok(());
33343334
}
33353335

3336-
match self.inner.mkdir(path) {
3337-
Ok(()) => return Ok(()),
3338-
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
3339-
Err(_) if path.is_dir() => return Ok(()),
3340-
Err(e) => return Err(e),
3341-
}
3342-
match path.parent() {
3343-
Some(p) => self.create_dir_all(p)?,
3344-
None => {
3345-
return Err(io::const_error!(
3346-
io::ErrorKind::Uncategorized,
3347-
"failed to create whole tree",
3348-
));
3336+
let ancestors = path.ancestors();
3337+
let mut uncreated_dirs = 0;
3338+
3339+
for ancestor in ancestors {
3340+
// for relative paths like "foo/bar", the parent of
3341+
// "foo" will be "" which there's no need to invoke
3342+
// a mkdir syscall on
3343+
if ancestor == Path::new("") {
3344+
break;
3345+
}
3346+
3347+
match self.inner.mkdir(ancestor) {
3348+
Ok(()) => break,
3349+
Err(e) if e.kind() == io::ErrorKind::NotFound => uncreated_dirs += 1,
3350+
// we check if the err is AlreadyExists for two reasons
3351+
// - in case the path exists as a *file*
3352+
// - and to avoid calls to .is_dir() in case of other errs
3353+
// (i.e. PermissionDenied)
3354+
Err(e) if e.kind() == io::ErrorKind::AlreadyExists && ancestor.is_dir() => break,
3355+
Err(e) => return Err(e),
33493356
}
33503357
}
3351-
match self.inner.mkdir(path) {
3352-
Ok(()) => Ok(()),
3353-
Err(_) if path.is_dir() => Ok(()),
3354-
Err(e) => Err(e),
3358+
3359+
// collect only the uncreated directories w/o letting the vec resize
3360+
let mut uncreated_dirs_vec = Vec::with_capacity(uncreated_dirs);
3361+
uncreated_dirs_vec.extend(ancestors.take(uncreated_dirs));
3362+
3363+
for uncreated_dir in uncreated_dirs_vec.iter().rev() {
3364+
if let Err(e) = self.inner.mkdir(uncreated_dir) {
3365+
if e.kind() != io::ErrorKind::AlreadyExists || !uncreated_dir.is_dir() {
3366+
return Err(e);
3367+
}
3368+
}
33553369
}
3370+
3371+
Ok(())
33563372
}
33573373
}
33583374

0 commit comments

Comments
 (0)