From 05e59c575ff9cb0571cf7edbcb17bf57f143f72d Mon Sep 17 00:00:00 2001 From: Benjamin Nguyen Date: Wed, 19 Apr 2023 17:15:42 -0700 Subject: [PATCH 1/2] show hardlinks but don't duplicate file size count --- src/render/context/mod.rs | 4 +-- src/render/disk_usage/file_size.rs | 6 ++-- src/render/tree/mod.rs | 46 +++++++++++++++++++----------- tests/hardlink.rs | 38 ++++++++++++++++++++++++ tests/hardlinks/kadath.txt | 1 + 5 files changed, 73 insertions(+), 22 deletions(-) create mode 100644 tests/hardlink.rs create mode 100644 tests/hardlinks/kadath.txt diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs index c589ec67..7a9cf420 100644 --- a/src/render/context/mod.rs +++ b/src/render/context/mod.rs @@ -255,10 +255,10 @@ impl Context { /// Determines whether or not it's appropriate to display color in output based on /// `--no-color`, `--force-color`, and whether or not stdout is connected to a tty. /// - /// If `--force-color` is true then this will always evaluate to `false`. + /// If `--force-color` is `true` then this will always evaluate to `false`. pub const fn no_color(&self) -> bool { if self.force_color { - return false + return false; } self.no_color || !self.stdout_is_tty diff --git a/src/render/disk_usage/file_size.rs b/src/render/disk_usage/file_size.rs index 233ad6ac..5270921c 100644 --- a/src/render/disk_usage/file_size.rs +++ b/src/render/disk_usage/file_size.rs @@ -194,9 +194,9 @@ impl FileSize { } } -impl AddAssign for FileSize { - fn add_assign(&mut self, rhs: u64) { - self.bytes += rhs; +impl AddAssign<&Self> for FileSize { + fn add_assign(&mut self, rhs: &Self) { + self.bytes += rhs.bytes; } } diff --git a/src/render/tree/mod.rs b/src/render/tree/mod.rs index 994ce8e1..6d4ea856 100644 --- a/src/render/tree/mod.rs +++ b/src/render/tree/mod.rs @@ -1,7 +1,10 @@ -use crate::render::{ - context::{error::Error as CtxError, Context}, - disk_usage::file_size::FileSize, - styles, +use crate::{ + fs::inode::Inode, + render::{ + context::{error::Error as CtxError, Context}, + disk_usage::file_size::FileSize, + styles, + }, }; use count::FileCount; use error::Error; @@ -128,8 +131,6 @@ where let res = s.spawn(move || { let mut tree = Arena::new(); let mut branches: HashMap> = HashMap::new(); - let mut inodes = HashSet::new(); - let mut root_id = None; while let Ok(TraversalState::Ongoing(node)) = rx.recv() { @@ -146,13 +147,6 @@ where } } - // If a hard-link is already accounted for, skip all subsequent ones. - if let Some(inode) = node.inode() { - if inode.nlink > 1 && !inodes.insert(inode) { - continue; - } - } - let parent = node.parent_path().ok_or(Error::ExpectedParent)?.to_owned(); let node_id = tree.new_node(node); @@ -168,8 +162,16 @@ where let root = root_id.ok_or(Error::MissingRoot)?; let node_comparator = node::cmp::comparator(ctx); + let mut inodes = HashSet::new(); - Self::assemble_tree(&mut tree, root, &mut branches, &node_comparator, ctx); + Self::assemble_tree( + &mut tree, + root, + &mut branches, + &node_comparator, + &mut inodes, + ctx, + ); if ctx.prune { Self::prune_directories(root, &mut tree); @@ -199,6 +201,7 @@ where current_node_id: NodeId, branches: &mut HashMap>, node_comparator: &NodeComparator, + inode_set: &mut HashSet, ctx: &Context, ) { let current_node = tree[current_node_id].get_mut(); @@ -216,11 +219,20 @@ where }; if is_dir { - Self::assemble_tree(tree, index, branches, node_comparator, ctx); + Self::assemble_tree(tree, index, branches, node_comparator, inode_set, ctx); + } + + let node = tree[index].get(); + + // If a hard-link is already accounted for then don't increment parent dir size. + if let Some(inode) = node.inode() { + if inode.nlink > 1 && !inode_set.insert(inode) { + continue; + } } - if let Some(file_size) = tree[index].get().file_size() { - dir_size += file_size.bytes; + if let Some(file_size) = node.file_size() { + dir_size += file_size; } } diff --git a/tests/hardlink.rs b/tests/hardlink.rs new file mode 100644 index 00000000..ddb64488 --- /dev/null +++ b/tests/hardlink.rs @@ -0,0 +1,38 @@ +use indoc::indoc; +use std::{env::current_dir, error::Error, fs}; + +mod utils; + +#[test] +fn hardlink() -> Result<(), Box> { + let current_dir = current_dir()?; + + let src = current_dir + .join("tests") + .join("hardlinks") + .join("kadath.txt"); + + let link = current_dir + .join("tests") + .join("hardlinks") + .join("curwin.hpl"); + + fs::hard_link(&src, &link)?; + + let out = utils::run_cmd(&["--sort", "name", "tests/hardlinks"]); + + fs::remove_file(&link)?; + + assert_eq!( + out, + indoc!( + "157 B hardlinks + 157 B ├─ curwin.hpl + 157 B └─ kadath.txt + + 2 files" + ) + ); + + Ok(()) +} diff --git a/tests/hardlinks/kadath.txt b/tests/hardlinks/kadath.txt new file mode 100644 index 00000000..a6e0404e --- /dev/null +++ b/tests/hardlinks/kadath.txt @@ -0,0 +1 @@ +“It was a song, but not the song of any voice. Night and the spheres sang it, and it was old when space and Nyarlathotep and the Other Gods were born.” From 5a9857703852d7229b9c225f7ab643e80ed1f2a9 Mon Sep 17 00:00:00 2001 From: Benjamin Nguyen Date: Wed, 19 Apr 2023 17:17:17 -0700 Subject: [PATCH 2/2] fix format --- tests/hardlink.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hardlink.rs b/tests/hardlink.rs index ddb64488..56cc0d7e 100644 --- a/tests/hardlink.rs +++ b/tests/hardlink.rs @@ -26,7 +26,7 @@ fn hardlink() -> Result<(), Box> { assert_eq!( out, indoc!( - "157 B hardlinks + "157 B hardlinks 157 B ├─ curwin.hpl 157 B └─ kadath.txt