1use crate::scanner::{walker::age_days, FsNode};
2use serde::Serialize;
3use std::path::PathBuf;
4
5#[derive(Debug, Clone, Serialize)]
6pub struct StaleFile {
7 pub path: PathBuf,
8 pub size: u64,
9 pub days_since_access: i64,
10}
11
12pub fn stale_files(root: &FsNode, min_days: i64, min_size: u64) -> Vec<StaleFile> {
13 let mut files = Vec::new();
14 root.flatten_files(&mut files);
15 let mut out: Vec<StaleFile> = files.into_iter()
16 .filter(|f| f.size >= min_size)
17 .filter_map(|f| {
18 let acc = f.accessed?;
19 let days = age_days(acc);
20 if days >= min_days {
21 Some(StaleFile { path: f.path.clone(), size: f.size, days_since_access: days })
22 } else {
23 None
24 }
25 })
26 .collect();
27 out.sort_by(|a, b| b.size.cmp(&a.size));
28 out
29}
30
31pub fn old_files(root: &FsNode, min_days: i64) -> Vec<StaleFile> {
32 let mut files = Vec::new();
33 root.flatten_files(&mut files);
34 let mut out: Vec<StaleFile> = files.into_iter()
35 .filter_map(|f| {
36 let m = f.modified?;
37 let days = age_days(m);
38 if days >= min_days {
39 Some(StaleFile { path: f.path.clone(), size: f.size, days_since_access: days })
40 } else {
41 None
42 }
43 })
44 .collect();
45 out.sort_by(|a, b| b.days_since_access.cmp(&a.days_since_access));
46 out
47}
48
49pub fn zero_byte_files(root: &FsNode) -> Vec<PathBuf> {
50 let mut files = Vec::new();
51 root.flatten_files(&mut files);
52 files.into_iter().filter(|f| f.size == 0 && f.apparent_size == 0).map(|f| f.path.clone()).collect()
53}
54
55pub fn empty_dirs(node: &FsNode, out: &mut Vec<PathBuf>) {
56 if !node.is_dir { return; }
57 if node.children.is_empty() {
58 out.push(node.path.clone());
59 return;
60 }
61 for c in &node.children {
62 empty_dirs(c, out);
63 }
64}