diff options
author | andy.boot <bootandy@gmail.com> | 2021-07-15 18:25:21 +0100 |
---|---|---|
committer | andy.boot <bootandy@gmail.com> | 2021-07-16 14:13:12 +0100 |
commit | f6e36aba52ae5d25350870f5d5a48f2c23f4b2d5 (patch) | |
tree | 1a06e8ee968b563cd7b434aa82c8795fb10fb850 | |
parent | c286b8ba97a36a730aab5b923f58a4bc9e1ae6ef (diff) |
Feature: Re-introduce -x flag to limit filesystem
-x flag allows dust to limit itself to the current filesystem
-rw-r--r-- | src/dirwalker.rs | 32 | ||||
-rw-r--r-- | src/main.rs | 16 | ||||
-rw-r--r-- | src/utils.rs | 19 |
3 files changed, 60 insertions, 7 deletions
diff --git a/src/dirwalker.rs b/src/dirwalker.rs index a156752..61e93d6 100644 --- a/src/dirwalker.rs +++ b/src/dirwalker.rs @@ -13,9 +13,12 @@ use std::collections::HashSet; use crate::node::build_node; use std::fs::DirEntry; +use crate::platform::get_metadata; + pub fn walk_it( dirs: HashSet<PathBuf>, ignore_directories: HashSet<PathBuf>, + allowed_filesystems: HashSet<u64>, use_apparent_size: bool, by_filecount: bool, ignore_hidden: bool, @@ -27,9 +30,9 @@ pub fn walk_it( .filter_map(|d| { let n = walk( d, - false, &permissions_flag, &ignore_directories, + &allowed_filesystems, use_apparent_size, by_filecount, ignore_hidden, @@ -75,22 +78,32 @@ fn clean_inodes( }); } -// todo: check for filesystem too fn ignore_file( entry: &DirEntry, ignore_hidden: bool, ignore_directories: &HashSet<PathBuf>, + allowed_filesystems: &HashSet<u64>, ) -> bool { let is_dot_file = entry.file_name().to_str().unwrap_or("").starts_with('.'); let is_ignored_path = ignore_directories.contains(&entry.path()); + + if !allowed_filesystems.is_empty() { + let size_inode_device = get_metadata(&entry.path(), false); + + if let Some((_size, Some((_id, dev)))) = size_inode_device { + if !allowed_filesystems.contains(&dev) { + return true; + } + } + } (is_dot_file && ignore_hidden) || is_ignored_path } fn walk( dir: PathBuf, - is_symlink: bool, permissions_flag: &AtomicBool, ignore_directories: &HashSet<PathBuf>, + allowed_filesystems: &HashSet<u64>, use_apparent_size: bool, by_filecount: bool, ignore_hidden: bool, @@ -107,16 +120,21 @@ fn walk( // rayon doesn't parallelise as well giving a 3X performance drop // hence we unravel the recursion a bit - // return walk(entry.path(), permissions_flag, ignore_directories, use_apparent_size, by_filecount, ignore_hidden); + // return walk(entry.path(), permissions_flag, ignore_directories, allowed_filesystems, use_apparent_size, by_filecount, ignore_hidden); - if !ignore_file(&entry, ignore_hidden, &ignore_directories) { + if !ignore_file( + &entry, + ignore_hidden, + &ignore_directories, + &allowed_filesystems, + ) { if let Ok(data) = entry.file_type() { if data.is_dir() && !data.is_symlink() { return walk( entry.path(), - data.is_symlink(), permissions_flag, ignore_directories, + allowed_filesystems, use_apparent_size, by_filecount, ignore_hidden, @@ -140,7 +158,7 @@ fn walk( } else { permissions_flag.store(true, atomic::Ordering::Relaxed); } - build_node(dir, children, use_apparent_size, is_symlink, by_filecount) + build_node(dir, children, use_apparent_size, false, by_filecount) } mod tests { diff --git a/src/main.rs b/src/main.rs index 3f9b155..b65443b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use filter::{get_biggest, get_by_depth}; use std::cmp::max; use std::path::PathBuf; use terminal_size::{terminal_size, Height, Width}; +use utils::get_filesystem_devices; use utils::simplify_dir_names; mod dirwalker; @@ -108,6 +109,12 @@ fn main() { .help("Exclude any file or directory with this name"), ) .arg( + Arg::with_name("limit_filesystem") + .short("x") + .long("limit-filesystem") + .help("Only count the files and directories on the same filesystem as the supplied directory"), + ) + .arg( Arg::with_name("display_apparent_size") .short("s") .long("apparent-size") @@ -191,8 +198,16 @@ fn main() { let by_filecount = options.is_present("by_filecount"); let ignore_hidden = options.is_present("ignore_hidden"); + let limit_filesystem = options.is_present("limit_filesystem"); let simplified_dirs = simplify_dir_names(target_dirs); + let allowed_filesystems = { + if limit_filesystem { + get_filesystem_devices(simplified_dirs.iter()) + } else { + HashSet::new() + } + }; let ignored_full_path: HashSet<PathBuf> = ignore_directories .into_iter() @@ -202,6 +217,7 @@ fn main() { let (nodes, errors) = walk_it( simplified_dirs, ignored_full_path, + allowed_filesystems, use_apparent_size, by_filecount, ignore_hidden, diff --git a/src/utils.rs b/src/utils.rs index 8d58728..35f7098 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,9 @@ +use platform::get_metadata; use std::collections::HashSet; use std::path::{Path, PathBuf}; +use crate::platform; + fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool { let parent = parent.as_ref(); let child = child.as_ref(); @@ -33,6 +36,22 @@ pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf> top_level_names } +pub fn get_filesystem_devices<'a, P: IntoIterator<Item = &'a PathBuf>>(paths: P) -> HashSet<u64> { + // Gets the device ids for the filesystems which are used by the argument paths + paths + .into_iter() + .filter_map(|p| { + let meta = get_metadata(&p, false); + + if let Some((_size, Some((_id, dev)))) = meta { + Some(dev) + } else { + None + } + }) + .collect() +} + pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf { // normalize path ... // 1. removing repeated separators |