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
55/// Delete a single path using the specified mode.
56pub fn delete_path(path: &Path, mode: DeleteMode) -> Result<()> {
57    if !path.exists() {
58        return Ok(());
59    }
60
61    match mode {
62        DeleteMode::Trash => {
63            trash::delete(path).map_err(|e| Error::Trash(e.to_string()))?;
64        }
65        DeleteMode::Permanent => {
66            if path.is_dir() {
67                std::fs::remove_dir_all(path).map_err(|e| Error::io(path, e))?;
68            } else {
69                std::fs::remove_file(path).map_err(|e| Error::io(path, e))?;
70            }
71        }
72        DeleteMode::DryRun => {
73            // No-op
74        }
75    }
76
77    Ok(())
78}