|
|
@@ -15,6 +15,7 @@ use log::*;
|
|
|
use crate::fs::dir::Dir;
|
|
|
use crate::fs::feature::xattr;
|
|
|
use crate::fs::feature::xattr::{Attribute, FileAttributes};
|
|
|
+use crate::fs::RECURSIVE_SIZE_HASHMAP;
|
|
|
use crate::fs::fields as f;
|
|
|
|
|
|
use super::mounts::all_mounts;
|
|
|
@@ -514,6 +515,58 @@ impl<'dir> File<'dir> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Recursive folder size
|
|
|
+ #[cfg(unix)]
|
|
|
+ pub fn recursive_size(&self) -> f::Size {
|
|
|
+ if self.is_directory() {
|
|
|
+ let dir = match Dir::read_dir(self.path.clone()) {
|
|
|
+ Ok(v) => v,
|
|
|
+ Err(_) => return f::Size::None
|
|
|
+ };
|
|
|
+ let mut recursive_size: u64 = 0;
|
|
|
+ let files = dir.files(super::DotFilter::Dotfiles, None, false, false);
|
|
|
+ for fileresult in files {
|
|
|
+ let file = match fileresult {
|
|
|
+ Ok(f) => f,
|
|
|
+ _ => continue
|
|
|
+ };
|
|
|
+ if file.is_file() {
|
|
|
+ recursive_size += file.metadata.size();
|
|
|
+ } else {
|
|
|
+ recursive_size += match file.recursive_size() {
|
|
|
+ f::Size::Some(s) => s,
|
|
|
+ _ => file.metadata.size()
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ RECURSIVE_SIZE_HASHMAP.lock().unwrap().insert(self.metadata.ino(), recursive_size);
|
|
|
+ f::Size::Some(recursive_size)
|
|
|
+ } else if self.is_char_device() || self.is_block_device() {
|
|
|
+ let device_id = self.metadata.rdev();
|
|
|
+
|
|
|
+ // MacOS and Linux have different arguments and return types for the
|
|
|
+ // functions major and minor. On Linux the try_into().unwrap() and
|
|
|
+ // the "as u32" cast are not needed. We turn off the warning to
|
|
|
+ // allow it to compile cleanly on Linux.
|
|
|
+ #[allow(trivial_numeric_casts)]
|
|
|
+ #[allow(clippy::unnecessary_cast)]
|
|
|
+ #[allow(clippy::useless_conversion)]
|
|
|
+ f::Size::DeviceIDs(f::DeviceIDs {
|
|
|
+ // SAFETY: Calling libc function to decompose the device_id
|
|
|
+ major: unsafe { libc::major(device_id.try_into().unwrap()) } as u32,
|
|
|
+ minor: unsafe { libc::minor(device_id.try_into().unwrap()) } as u32,
|
|
|
+ })
|
|
|
+ } else if self.is_link() && self.deref_links {
|
|
|
+ match self.link_target() {
|
|
|
+ FileTarget::Ok(f) => f::Size::Some(f.metadata.size()),
|
|
|
+ _ => f::Size::None,
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ f::Size::Some(self.metadata.len())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/// Returns the size of the file or indicates no size if it's a directory.
|
|
|
///
|
|
|
/// For Windows platforms, the size of directories is not computed and will
|