diff options
author | Sebastian Thiel <sebastian.thiel@icloud.com> | 2023-02-23 07:54:18 +0100 |
---|---|---|
committer | Sebastian Thiel <sebastian.thiel@icloud.com> | 2023-02-23 07:54:38 +0100 |
commit | 31dacad6f723f379a2d12417d65177faccd67b76 (patch) | |
tree | 435060ad65b91e16e8eccc3c0f00ebb5fd0eef6e | |
parent | e6c10c5b311ad25d010f18d51f150d34bf62b815 (diff) | |
parent | dbc9845c7d63d7c113f9f61b91da99ff0b249ad2 (diff) |
fix: `-x` is applied to traversal as well.
Previously `dua` would cross filesystems for traversal and simply not
yield them, which somewhat defeated the purpose.
Now it will avoid traversing into filesystem entries that are on a different
filesystem, which should improve its performance visibly whenever multiple
filesystems are involved.
-rw-r--r-- | src/aggregate.rs | 2 | ||||
-rw-r--r-- | src/common.rs | 24 | ||||
-rw-r--r-- | src/traverse.rs | 2 |
3 files changed, 18 insertions, 10 deletions
diff --git a/src/aggregate.rs b/src/aggregate.rs index a724a57..6e1cc2f 100644 --- a/src/aggregate.rs +++ b/src/aggregate.rs @@ -97,7 +97,7 @@ pub fn aggregate( continue; } }; - for entry in walk_options.iter_from_path(path.as_ref()) { + for entry in walk_options.iter_from_path(path.as_ref(), device_id) { stats.entries_traversed += 1; progress.throttled(|out| { write!(out, "Enumerating {} entries\r", stats.entries_traversed).ok(); diff --git a/src/common.rs b/src/common.rs index f5f862e..5eb094e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,3 +1,4 @@ +use crate::crossdev; use crate::traverse::{EntryData, Tree, TreeIndex}; use byte_unit::{n_gb_bytes, n_gib_bytes, n_mb_bytes, n_mib_bytes, ByteUnit}; use std::path::PathBuf; @@ -130,8 +131,8 @@ pub struct WalkOptions { type WalkDir = jwalk::WalkDirGeneric<((), Option<Result<std::fs::Metadata, jwalk::Error>>)>; impl WalkOptions { - pub(crate) fn iter_from_path(&self, path: &Path) -> WalkDir { - WalkDir::new(path) + pub(crate) fn iter_from_path(&self, root: &Path, root_device_id: u64) -> WalkDir { + WalkDir::new(root) .follow_links(false) .sort(match self.sorting { TraversalSorting::None => false, @@ -140,16 +141,23 @@ impl WalkOptions { .skip_hidden(false) .process_read_dir({ let ignore_dirs = self.ignore_dirs.clone(); + let cross_filesystems = self.cross_filesystems; move |_, _, _, dir_entry_results| { dir_entry_results.iter_mut().for_each(|dir_entry_result| { if let Ok(dir_entry) = dir_entry_result { + let metadata = dir_entry.metadata(); + if dir_entry.file_type.is_file() || dir_entry.file_type().is_symlink() { - dir_entry.client_state = Some(dir_entry.metadata()); - } - if dir_entry.file_type.is_dir() - && ignore_dirs.contains(&dir_entry.path()) - { - dir_entry.read_children_path = None; + dir_entry.client_state = Some(metadata); + } else if dir_entry.file_type.is_dir() { + let ok_for_fs = cross_filesystems + || metadata + .as_ref() + .map(|m| crossdev::is_same_device(root_device_id, m)) + .unwrap_or(true); + if !ok_for_fs || ignore_dirs.contains(&dir_entry.path()) { + dir_entry.read_children_path = None; + } } } }) diff --git a/src/traverse.rs b/src/traverse.rs index 1bbece4..f61ab41 100644 --- a/src/traverse.rs +++ b/src/traverse.rs @@ -103,7 +103,7 @@ impl Traversal { } }; for (eid, entry) in walk_options - .iter_from_path(path.as_ref()) + .iter_from_path(path.as_ref(), device_id) .into_iter() .enumerate() { |