@@ -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