Skip to main content

diskard_core/
cleaner.rs

1use std::path::Path;
2
3use crate::error::{Error, Result};
4use crate::finding::Finding;
5
6/// How to delete files.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum DeleteMode {
9    /// Move to system trash (default, recoverable).
10    Trash,
11    /// Permanently delete (irreversible).
12    Permanent,
13    /// Only show what would be deleted.
14    DryRun,
15}
16
17/// Results from a clean operation.
18pub struct CleanResult {
19    pub deleted_count: usize,
20    pub freed_bytes: u64,
21    pub errors: Vec<(String, String)>,
22}
23
24/// Delete the given findings using the specified mode.
25pub fn clean(findings: &[Finding], mode: DeleteMode) -> Result<CleanResult> {
26    let mut deleted_count = 0;
27    let mut freed_bytes = 0;
28    let mut errors: Vec<(String, String)> = Vec::new();
29
30    for finding in findings {
31        if mode == DeleteMode::DryRun {
32            deleted_count += 1;
33            freed_bytes += finding.size_bytes;
34            continue;
35        }
36
37        match delete_path(&finding.path, mode) {
38            Ok(()) => {
39                deleted_count += 1;
40                freed_bytes += finding.size_bytes;
41            }
42            Err(e) => {
43                errors.push((finding.path.display().to_string(), e.to_string()));
44            }
45        }
46    }
47
48    Ok(CleanResult {
49        deleted_count,
50        freed_bytes,
51        errors,
52    })
53}
54
55fn delete_path(path: &Path, mode: DeleteMode) -> Result<()> {
56    if !path.exists() {
57        return Ok(());
58    }
59
60    match mode {
61        DeleteMode::Trash => {
62            trash::delete(path).map_err(|e| Error::Trash(e.to_string()))?;
63        }
64        DeleteMode::Permanent => {
65            if path.is_dir() {
66                std::fs::remove_dir_all(path).map_err(|e| Error::io(path, e))?;
67            } else {
68                std::fs::remove_file(path).map_err(|e| Error::io(path, e))?;
69            }
70        }
71        DeleteMode::DryRun => {
72            // No-op
73        }
74    }
75
76    Ok(())
77}