Przeglądaj źródła

feat: Support for displaying blocksize on directories

Robert Minsk 2 lat temu
rodzic
commit
2c4d6751c5
2 zmienionych plików z 42 dodań i 24 usunięć
  1. 29 12
      src/fs/file.rs
  2. 13 12
      src/fs/recursive_size.rs

+ 29 - 12
src/fs/file.rs

@@ -29,8 +29,10 @@ use super::mounts::MountedFs;
 
 // Mutex::new is const but HashMap::new is not const requiring us to use lazy
 // initialization. Replace with std::sync::LazyLock when it is stable.
+// Maps (device_id, inode) => (size_in_bytes, size_in_blocks)
+#[allow(clippy::type_complexity)]
 #[cfg(unix)]
-static DIRECTORY_SIZE_CACHE: Lazy<Mutex<HashMap<(u64, u64), u64>>> =
+static DIRECTORY_SIZE_CACHE: Lazy<Mutex<HashMap<(u64, u64), (u64, u64)>>> =
     Lazy::new(|| Mutex::new(HashMap::new()));
 
 /// A **File** is a wrapper around one of Rust’s `PathBuf` values, along with
@@ -137,9 +139,9 @@ impl<'dir> File<'dir> {
             parent_dir,
             is_all_all,
             deref_links,
+            recursive_size,
             extended_attributes,
             absolute_path,
-            recursive_size,
         };
 
         if total_size {
@@ -472,6 +474,10 @@ impl<'dir> File<'dir> {
                 FileTarget::Ok(f) => f.blocksize(),
                 _ => f::Blocksize::None,
             }
+        } else if self.is_directory() {
+            self.recursive_size.map_or(f::Blocksize::None, |_, blocks| {
+                f::Blocksize::Some(blocks * 512)
+            })
         } else if self.is_file() {
             // Note that metadata.blocks returns the number of blocks
             // for 512 byte blocks according to the POSIX standard
@@ -527,7 +533,8 @@ impl<'dir> File<'dir> {
                 _ => f::Size::None,
             }
         } else if self.is_directory() {
-            self.recursive_size.map_or(f::Size::None, f::Size::Some)
+            self.recursive_size
+                .map_or(f::Size::None, |bytes, _| f::Size::Some(bytes))
         } else if self.is_char_device() || self.is_block_device() {
             let device_id = self.metadata.rdev();
 
@@ -563,7 +570,6 @@ impl<'dir> File<'dir> {
         }
     }
 
-
     /// Calculate the total directory size recursively.  If not a directory `None`
     /// will be returned.  The directory size is cached for recursive directory
     /// listing.
@@ -572,21 +578,32 @@ impl<'dir> File<'dir> {
         if self.is_directory() {
             let key = (self.metadata.dev(), self.metadata.ino());
             if let Some(size) = DIRECTORY_SIZE_CACHE.lock().unwrap().get(&key) {
-                return RecursiveSize::Some(*size);
+                return RecursiveSize::Some(size.0, size.1);
             }
             Dir::read_dir(self.path.clone()).map_or(RecursiveSize::Unknown, |dir| {
                 let mut size = 0;
+                let mut blocks = 0;
                 for file in dir
                     .files(super::DotFilter::Dotfiles, None, false, false, true)
                     .flatten()
                 {
-                    size += match file.recursive_directory_size() {
-                        RecursiveSize::Some(s) => s,
-                        _ => file.metadata.size(),
+                    match file.recursive_directory_size() {
+                        RecursiveSize::Some(bytes, blks) => {
+                            size += bytes;
+                            blocks += blks;
+                        }
+                        RecursiveSize::Unknown => {}
+                        RecursiveSize::None => {
+                            size += file.metadata.size();
+                            blocks += file.metadata.blocks();
+                        }
                     }
                 }
-                DIRECTORY_SIZE_CACHE.lock().unwrap().insert(key, size);
-                RecursiveSize::Some(size)
+                DIRECTORY_SIZE_CACHE
+                    .lock()
+                    .unwrap()
+                    .insert(key, (size, blocks));
+                RecursiveSize::Some(size, blocks)
             })
         } else {
             RecursiveSize::None
@@ -606,13 +623,13 @@ impl<'dir> File<'dir> {
     /// of a directory when `total_size` is used.
     #[inline]
     pub fn length(&self) -> u64 {
-        self.recursive_size.unwrap_or(self.metadata.len())
+        self.recursive_size.unwrap_bytes_or(self.metadata.len())
     }
 
     /// Is the file is using recursive size calculation
     #[inline]
     pub fn is_recursive_size(&self) -> bool {
-        ! self.recursive_size.is_none()
+        !self.recursive_size.is_none()
     }
 
     /// Determines if the directory is empty or not.

+ 13 - 12
src/fs/recursive_size.rs

@@ -7,8 +7,9 @@ pub enum RecursiveSize {
     None,
     /// Size should be computed but has not been computed yet
     Unknown,
-    /// Size has been computed
-    Some(u64),
+    /// Size has been computed.  First field is size in bytes and second field
+    /// is size in blocks
+    Some(u64, u64),
 }
 
 impl RecursiveSize {
@@ -39,14 +40,14 @@ impl RecursiveSize {
     /// ```
     /// use eza::fs::recursive_size::RecursiveSize;
     ///
-    /// assert_eq!(RecursiveSize::None.unwrap_or(1), 1);
-    /// assert_eq!(RecursiveSize::Unknown.unwrap_or(1), 1);
-    /// assert_eq!(RecursiveSize::Some(2).unwrap_or(1), 2);
+    /// assert_eq!(RecursiveSize::None.unwrap_bytes_or(1), 1);
+    /// assert_eq!(RecursiveSize::Unknown.unwrap_bytes_or(1), 1);
+    /// assert_eq!(RecursiveSize::Some(2, 3).unwrap_bytes_or(1), 2);
     /// ```
     #[inline]
-    pub const fn unwrap_or(self, default: u64) -> u64 {
+    pub const fn unwrap_bytes_or(self, default: u64) -> u64 {
         match self {
-            Self::Some(x) => x,
+            Self::Some(bytes, _blocks) => bytes,
             _ => default,
         }
     }
@@ -59,16 +60,16 @@ impl RecursiveSize {
     /// ```
     /// use eza::fs::recursive_size::RecursiveSize;
     ///
-    /// assert_eq!(RecursiveSize::None.map_or(None, |s| Some(s * 2)), None);
-    /// assert_eq!(RecursiveSize::Unknown.map_or(None, |s| Some(s * 2)), None);
-    /// assert_eq!(RecursiveSize::Some(2).map_or(None, |s| Some(s * 2)), Some(4));
+    /// assert_eq!(RecursiveSize::None.map_or(None, |s, _| Some(s * 2)), None);
+    /// assert_eq!(RecursiveSize::Unknown.map_or(None, |s, _| Some(s * 2)), None);
+    /// assert_eq!(RecursiveSize::Some(2, 3).map_or(None, |s, _| Some(s * 2)), Some(4));
     #[inline]
     pub fn map_or<U, F>(self, default: U, f: F) -> U
     where
-        F: FnOnce(u64) -> U,
+        F: FnOnce(u64, u64) -> U,
     {
         match self {
-            RecursiveSize::Some(x) => f(x),
+            RecursiveSize::Some(bytes, blocks) => f(bytes, blocks),
             _ => default,
         }
     }