rm_rs/
core.rs

1use std::{
2    fs,
3    io::{self, ErrorKind},
4    path::{Path, PathBuf},
5};
6
7#[derive(Debug, Clone, Copy)]
8pub enum RemoveMode {
9    Files,
10    FilesAndDirectories,
11    Recursive,
12}
13
14fn is_directory(path: &Path) -> io::Result<bool> {
15    Ok(fs::symlink_metadata(path)?.is_dir())
16}
17
18fn remove_file(path: &Path) -> io::Result<()> {
19    if is_directory(path)? {
20        Err(io::Error::new(ErrorKind::Other, "Is a directory"))
21    } else {
22        fs::remove_file(path)
23    }
24}
25
26fn remove_file_or_directory(path: &Path) -> io::Result<()> {
27    if is_directory(path)? {
28        fs::remove_dir(path)
29    } else {
30        fs::remove_file(path)
31    }
32}
33
34fn remove_recursively(path: &Path) -> io::Result<()> {
35    if is_directory(path)? {
36        fs::remove_dir_all(path)
37    } else {
38        fs::remove_file(path)
39    }
40}
41
42fn remove_aux(
43    paths: Vec<PathBuf>,
44    ignore_not_found: bool,
45    operation: impl Fn(&Path) -> io::Result<()>,
46) -> io::Result<()> {
47    let mut result = Ok(());
48
49    for path in paths {
50        if let Err(error) = operation(&path) {
51            if ignore_not_found && matches!(error.kind(), ErrorKind::NotFound) {
52                continue;
53            }
54
55            eprintln!("{}: {}", path.display(), error);
56            result = Err(error);
57        }
58    }
59
60    result
61}
62
63pub fn remove(mode: RemoveMode, paths: Vec<PathBuf>, ignore_not_found: bool) -> io::Result<()> {
64    use RemoveMode as Mode;
65
66    match mode {
67        Mode::Files => remove_aux(paths, ignore_not_found, remove_file),
68        Mode::FilesAndDirectories => remove_aux(paths, ignore_not_found, remove_file_or_directory),
69        Mode::Recursive => remove_aux(paths, ignore_not_found, remove_recursively),
70    }
71}