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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/// compute consolidated data for directories: modified date, size, and count.
/// A cache is used to avoid recomputing the same directories again and again.
/// On unix, hard links are checked to avoid counting twice an inode.
mod sum_computation;
use {
crate::{
app::*,
task_sync::Dam,
},
ahash::AHashMap,
once_cell::sync::Lazy,
std::{
ops::AddAssign,
path::{Path, PathBuf},
sync::Mutex,
},
};
pub const DEFAULT_THREAD_COUNT: usize = 5;
static SUM_CACHE: Lazy<Mutex<AHashMap<PathBuf, FileSum>>> = Lazy::new(|| {
Mutex::new(AHashMap::default())
});
pub fn clear_cache() {
SUM_CACHE.lock().unwrap().clear();
}
/// Reduction of counts, dates and sizes on a file or directory
#[derive(Debug, Copy, Clone)]
pub struct FileSum {
real_size: u64, // bytes, the space it takes on disk
count: usize, // number of files
modified: u32, // seconds from Epoch to last modification, or 0 if there was an error
sparse: bool, // only for non directories: tells whether the file is sparse
}
impl FileSum {
pub fn new(
real_size: u64,
sparse: bool,
count: usize,
modified: u32,
) -> Self {
Self { real_size, count, modified, sparse }
}
pub fn zero() -> Self {
Self::new(0, false, 0, 0)
}
pub fn incr(&mut self) {
self.count += 1;
}
/// return the sum of the given file, which is assumed
/// to be a normal file (ie not a directory)
pub fn from_file(path: &Path) -> Self {
sum_computation::compute_file_sum(path)
}
/// Return the sum of the directory, either by computing it of by
/// fetching it from cache.
/// If the lifetime expires before complete computation, None is returned.
pub fn from_dir(path: &Path, dam: &Dam, con: &AppContext) -> Option<Self> {
let mut sum_cache = SUM_CACHE.lock().unwrap();
match sum_cache.get(path) {
Some(sum) => Some(*sum),
None => {
let sum = time!(
"sum computation",
path,
sum_computation::compute_dir_sum(path, &mut sum_cache, dam, con),
);
if let Some(sum) = sum {
sum_cache.insert(PathBuf::from(path), sum);
}
sum
}
}
}
pub fn part_of_size(self, total: Self) -> f32 {
if total.real_size == 0 {
0.0
} else {
self.real_size as f32 / total.real_size as f32
}
}
/// return the number of files (normally at least 1)
pub fn to_count(self) -> usize {
self.count
}
/// return the number of seconds from Epoch to last modification,
/// or 0 if the computation failed
pub fn to_seconds(self) -> u32 {
self.modified
}
/// return the size in bytes
pub fn to_size(self) -> u64 {
self.real_size
}
pub fn to_valid_seconds(self) -> Option<i64> {
if self.modified != 0 {
Some(self.modified as i64)
} else {
None
}
}
/// tell whether the file has holes (in which case the size displayed by
/// other tools may be greater than the "real" one returned by broot).
/// Not computed (return false) on windows or for directories.
pub fn is_sparse(self) -> bool {
self.sparse
}
}
impl AddAssign for FileSum {
#[allow(clippy::suspicious_op_assign_impl)]
fn add_assign(&mut self, other: Self) {
*self = Self::new(
self.real_size + other.real_size,
self.sparse | other.sparse,
self.count + other.count,
self.modified.max(other.modified),
);
}
}