summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2023-02-23 07:54:18 +0100
committerSebastian Thiel <sebastian.thiel@icloud.com>2023-02-23 07:54:38 +0100
commit31dacad6f723f379a2d12417d65177faccd67b76 (patch)
tree435060ad65b91e16e8eccc3c0f00ebb5fd0eef6e
parente6c10c5b311ad25d010f18d51f150d34bf62b815 (diff)
parentdbc9845c7d63d7c113f9f61b91da99ff0b249ad2 (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.rs2
-rw-r--r--src/common.rs24
-rw-r--r--src/traverse.rs2
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()
{