1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
extern crate stacker;
use std::fs;
use std::io;
use std::path::Path;
#[cfg(target_os = "windows")]
fn fix_permissions(path: &Path) -> io::Result<()> {
let mut permissions = fs::metadata(&path)?.permissions();
permissions.set_readonly(false);
fs::set_permissions(&path, permissions)
}
#[cfg(not(target_os = "windows"))]
fn fix_permissions(_: &Path) -> io::Result<()> {
Ok(())
}
pub fn force_remove_all<P: AsRef<Path>>(path: P, ignore_not_existing: bool) -> io::Result<()> {
let path = path.as_ref();
if ignore_not_existing && !path.exists() {
return Ok(())
}
fix_permissions(path)?;
if fs::remove_file(path).is_ok() {
Ok(())
} else if fs::remove_dir(path).is_ok() {
Ok(())
} else {
for child in fs::read_dir(&path)? {
let child = child?;
let path = child.path();
stacker::maybe_grow(4 * 1024, 16 * 1024, ||
force_remove_all(&path, false),
)?;
}
fs::remove_dir(path)
}
}
#[cfg(not(target_os = "windows"))]
#[cfg(test)]
mod tests {
use std::process::Command;
fn rm_rf_success() -> bool {
Command::new("rm").arg("-rf").arg("target").output().unwrap().status.success()
}
fn rust_remove_success() -> bool {
super::force_remove_all("target", true).is_ok()
}
fn clean() {
Command::new("sh").arg("-c").arg("chmod 777 target; rm -rf target").output().unwrap();
}
fn test_eq_behavior_fn<F>(up: &F, test_name: &str) where F: Fn() -> () {
std::env::set_current_dir("target").unwrap();
clean();
up();
let rm_success = rm_rf_success();
clean();
up();
let rust_success = rust_remove_success();
clean();
eprintln!("Running test {}. `rm -rf` success: {}, `force_remove` success: {}",
test_name, rm_success, rust_success);
assert_eq!(rm_success, rust_success,
"`rm -rf` and `force_remove` behaved differently for test: {}",
test_name
);
std::env::set_current_dir("..").unwrap();
}
fn test_eq_behavior(up: &str) {
test_eq_behavior_fn(&|| {
assert!(Command::new("sh").arg("-c").arg(up).status().unwrap().success());
}, up);
}
#[test]
fn behavior_test() {
test_eq_behavior("touch target");
test_eq_behavior("touch target; chmod 000 target");
test_eq_behavior("touch target; chmod 777 target");
test_eq_behavior("mkdir target");
test_eq_behavior("mkdir target; chmod 000 target");
test_eq_behavior("mkdir target; chmod 777 target");
test_eq_behavior("mkdir -p target/subdir; chmod 000 target");
test_eq_behavior("mkdir -p target/subdir; chmod 777 target");
test_eq_behavior("mkdir -p target/subdir; chmod 444 target");
test_eq_behavior("mkdir -p target/subdir; chmod 222 target");
test_eq_behavior("mkdir -p target/subdir; chmod 111 target");
test_eq_behavior("");
}
}