@@ -29,14 +29,17 @@ where
29
29
/// unspecified if this helper is called concurrently.
30
30
/// - This helper is not robust against TOCTOU problems.
31
31
///
32
- /// FIXME: this implementation is insufficiently robust to replace bootstrap's clean `rm_rf`
33
- /// implementation:
34
- ///
35
- /// - This implementation currently does not perform retries.
32
+ /// FIXME: Audit whether this implementation is robust enough to replace bootstrap's clean `rm_rf`.
36
33
#[ track_caller]
37
34
pub fn recursive_remove < P : AsRef < Path > > ( path : P ) -> io:: Result < ( ) > {
38
35
let path = path. as_ref ( ) ;
39
- let metadata = fs:: symlink_metadata ( path) ?;
36
+
37
+ let metadata = match fs:: symlink_metadata ( path) {
38
+ Ok ( m) => m,
39
+ Err ( e) if e. kind ( ) == io:: ErrorKind :: NotFound => return Ok ( ( ) ) ,
40
+ Err ( e) => return Err ( e) ,
41
+ } ;
42
+
40
43
#[ cfg( windows) ]
41
44
let is_dir_like = |meta : & fs:: Metadata | {
42
45
use std:: os:: windows:: fs:: FileTypeExt ;
@@ -45,11 +48,30 @@ pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> {
45
48
#[ cfg( not( windows) ) ]
46
49
let is_dir_like = fs:: Metadata :: is_dir;
47
50
48
- if is_dir_like ( & metadata) {
49
- fs:: remove_dir_all ( path)
50
- } else {
51
- try_remove_op_set_perms ( fs:: remove_file, path, metadata)
51
+ const MAX_RETRIES : usize = 5 ;
52
+ const RETRY_DELAY_MS : u64 = 10 ;
53
+
54
+ let try_remove = || {
55
+ if is_dir_like ( & metadata) {
56
+ fs:: remove_dir_all ( path)
57
+ } else {
58
+ try_remove_op_set_perms ( fs:: remove_file, path, metadata. clone ( ) )
59
+ }
60
+ } ;
61
+
62
+ for attempt in 0 ..MAX_RETRIES {
63
+ match try_remove ( ) {
64
+ Ok ( ( ) ) => return Ok ( ( ) ) ,
65
+ Err ( e) if e. kind ( ) == io:: ErrorKind :: NotFound => return Ok ( ( ) ) ,
66
+ Err ( _) if attempt < MAX_RETRIES - 1 => {
67
+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( RETRY_DELAY_MS ) ) ;
68
+ continue ;
69
+ }
70
+ Err ( e) => return Err ( e) ,
71
+ }
52
72
}
73
+
74
+ Ok ( ( ) )
53
75
}
54
76
55
77
fn try_remove_op_set_perms < ' p , Op > ( mut op : Op , path : & ' p Path , metadata : Metadata ) -> io:: Result < ( ) >
0 commit comments