@@ -51,6 +51,7 @@ fs::unlink(&path);
5151
5252use c_str:: ToCStr ;
5353use clone:: Clone ;
54+ use container:: Container ;
5455use iter:: Iterator ;
5556use super :: { Reader , Writer , Seek } ;
5657use super :: { SeekStyle , Read , Write , Open , IoError , Truncate ,
@@ -62,6 +63,7 @@ use result::{Ok, Err};
6263use path;
6364use path:: { Path , GenericPath } ;
6465use vec:: { OwnedVector , ImmutableVector } ;
66+ use vec_ng:: Vec ;
6567
6668/// Unconstrained file access type that exposes read and write operations
6769///
@@ -557,16 +559,47 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> {
557559/// This function will return an `Err` value if an error happens. See
558560/// `file::unlink` and `fs::readdir` for possible error conditions.
559561pub fn rmdir_recursive ( path : & Path ) -> IoResult < ( ) > {
560- let children = try!( readdir ( path) ) ;
561- for child in children. iter ( ) {
562- if child. is_dir ( ) {
563- try!( rmdir_recursive ( child) ) ;
564- } else {
565- try!( unlink ( child) ) ;
562+ let mut rm_stack = Vec :: new ( ) ;
563+ rm_stack. push ( path. clone ( ) ) ;
564+
565+ while !rm_stack. is_empty ( ) {
566+ let children = try!( readdir ( rm_stack. last ( ) . unwrap ( ) ) ) ;
567+ let mut has_child_dir = false ;
568+
569+ // delete all regular files in the way and push subdirs
570+ // on the stack
571+ for child in children. move_iter ( ) {
572+ // FIXME(#12795) we should use lstat in all cases
573+ let child_type = match cfg ! ( windows) {
574+ true => try!( stat ( & child) ) . kind ,
575+ false => try!( lstat ( & child) ) . kind
576+ } ;
577+
578+ if child_type == io:: TypeDirectory {
579+ rm_stack. push ( child) ;
580+ has_child_dir = true ;
581+ } else {
582+ // we can carry on safely if the file is already gone
583+ // (eg: deleted by someone else since readdir)
584+ match unlink ( & child) {
585+ Ok ( ( ) ) => ( ) ,
586+ Err ( ref e) if e. kind == io:: FileNotFound => ( ) ,
587+ Err ( e) => return Err ( e)
588+ }
589+ }
590+ }
591+
592+ // if no subdir was found, let's pop and delete
593+ if !has_child_dir {
594+ match rmdir ( & rm_stack. pop ( ) . unwrap ( ) ) {
595+ Ok ( ( ) ) => ( ) ,
596+ Err ( ref e) if e. kind == io:: FileNotFound => ( ) ,
597+ Err ( e) => return Err ( e)
598+ }
566599 }
567600 }
568- // Directory should now be empty
569- rmdir ( path )
601+
602+ Ok ( ( ) )
570603}
571604
572605/// Changes the timestamps for a file's last modification and access time.
0 commit comments