Skip to content

Commit f94bd1c

Browse files
committed
add retry support to recursive_remove
1 parent efb1e3d commit f94bd1c

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

src/build_helper/src/fs/mod.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@ where
2929
/// unspecified if this helper is called concurrently.
3030
/// - This helper is not robust against TOCTOU problems.
3131
///
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`.
3633
#[track_caller]
3734
pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> {
3835
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+
4043
#[cfg(windows)]
4144
let is_dir_like = |meta: &fs::Metadata| {
4245
use std::os::windows::fs::FileTypeExt;
@@ -45,11 +48,30 @@ pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> {
4548
#[cfg(not(windows))]
4649
let is_dir_like = fs::Metadata::is_dir;
4750

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+
}
5272
}
73+
74+
Ok(())
5375
}
5476

5577
fn try_remove_op_set_perms<'p, Op>(mut op: Op, path: &'p Path, metadata: Metadata) -> io::Result<()>

0 commit comments

Comments
 (0)