From c127580057f7a9b32beb8124218c15fa3dcaf6f0 Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Wed, 21 Mar 2018 23:47:37 -0700 Subject: [PATCH] Bring over dev/inode pair changes from bootandy's repo --- src/main.rs | 10 +++++-- src/utils.rs | 78 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/main.rs b/src/main.rs index 66c4592..655bd05 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use clap::{App, AppSettings, Arg}; static DEFAULT_NUMBER_OF_LINES: &'static str = "15"; fn main() { - let options = App::new("Trailing args example") + let options = App::new("Dust") .setting(AppSettings::TrailingVarArg) .arg( Arg::with_name("number_of_lines") @@ -19,6 +19,11 @@ fn main() { .takes_value(true) .default_value(DEFAULT_NUMBER_OF_LINES), ) + .arg( + Arg::with_name("use_apparent_size") + .short("s") + .help("If set will use file length. Otherwise we use blocks"), + ) .arg(Arg::with_name("inputs").multiple(true)) .get_matches(); @@ -29,8 +34,9 @@ fn main() { } }; let number_of_lines = value_t!(options.value_of("number_of_lines"), usize).unwrap(); + let use_apparent_size = options.is_present("use_apparent_size"); - let (permissions, results) = get_dir_tree(&filenames); + let (permissions, results) = get_dir_tree(&filenames, use_apparent_size); let slice_it = find_big_ones(&results, number_of_lines); display(permissions, &slice_it); } diff --git a/src/utils.rs b/src/utils.rs index 7153961..c0215ba 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,7 +10,7 @@ use dust::{DirEnt, Node}; extern crate ansi_term; use self::ansi_term::Colour::Fixed; -pub fn get_dir_tree(filenames: &Vec<&str>) -> (bool, Vec) { +pub fn get_dir_tree(filenames: &Vec<&str>, apparent_size: bool) -> (bool, Vec) { let mut permissions = true; let mut results = vec![]; for &b in filenames { @@ -18,58 +18,93 @@ pub fn get_dir_tree(filenames: &Vec<&str>) -> (bool, Vec) { while new_name.chars().last() == Some('/') && new_name.len() != 1 { new_name.pop(); } - let (hp, data) = examine_dir_str(&new_name); + let (hp, data) = examine_dir_str(&new_name, apparent_size); permissions = permissions && hp; results.push(data); } (permissions, results) } -fn examine_dir_str(loc: &str) -> (bool, Node) { - let mut inodes: HashSet = HashSet::new(); - let (hp, result) = examine_dir(fs::read_dir(loc), &mut inodes); +fn examine_dir_str(loc: &str, apparent_size: bool) -> (bool, Node) { + let mut inodes: HashSet<(u64, u64)> = HashSet::new(); + let (hp, result) = examine_dir(fs::read_dir(loc), apparent_size, &mut inodes); // This needs to be folded into the below recursive call somehow let new_size = result.iter().fold(0, |a, b| a + b.entry().size()); (hp, Node::new(DirEnt::new(loc, new_size), result)) } +#[cfg(not(target_os = "macos"))] +fn get_block_size() -> u64 { + 1024 +} + +#[cfg(target_os = "macos")] +fn get_block_size() -> u64 { + 512 +} + #[cfg(target_os = "linux")] -fn get_metadata_blocks_and_inode(d: &std::fs::DirEntry) -> Option<(u64, u64)> { +fn get_metadata(d: &std::fs::DirEntry, s: bool) -> Option<(u64, Option<(u64, u64)>)> { use std::os::linux::fs::MetadataExt; match d.metadata().ok() { - Some(md) => Some((md.len(), md.st_ino())), + Some(md) => { + let inode = Some((md.st_ino(), md.st_dev())); + if s { + Some((md.len(), inode)) + } else { + Some((md.st_blocks() * get_block_size(), inode)) + } + } None => None, } } #[cfg(target_os = "unix")] -fn get_metadata_blocks_and_inode(d: &std::fs::DirEntry) -> Option<(u64, u64)> { +fn get_metadata(d: &std::fs::DirEntry, s: bool) -> Option<(u64, Option<(u64, u64)>)> { use std::os::unix::fs::MetadataExt; match d.metadata().ok() { - Some(md) => Some((md.len(), md.ino())), + Some(md) => { + let inode = Some((md.ino(), md.dev())); + if s { + Some((md.len(), inode)) + } else { + Some((md.blocks() * get_block_size(), inode)) + } + } None => None, } } #[cfg(target_os = "macos")] -fn get_metadata_blocks_and_inode(d: &std::fs::DirEntry) -> Option<(u64, u64)> { +fn get_metadata(d: &std::fs::DirEntry, s: bool) -> Option<(u64, Option<(u64, u64)>)> { use std::os::macos::fs::MetadataExt; match d.metadata().ok() { - Some(md) => Some((md.len(), md.st_ino())), + Some(md) => { + let inode = Some((md.st_ino(), md.st_dev())); + if s { + Some((md.len(), inode)) + } else { + Some((md.st_blocks() * get_block_size(), inode)) + } + } None => None, } } #[cfg(not(any(target_os = "linux", target_os = "unix", target_os = "macos")))] -fn get_metadata_blocks_and_inode(_d: &std::fs::DirEntry) -> Option<(u64, u64)> { - match _d.metadata().ok() { - Some(md) => Some((md.len(), 0)), //move to option not 0 +fn get_metadata(d: &std::fs::DirEntry, _apparent: bool) -> Option<(u64, Option<(u64, u64)>)> { + match d.metadata().ok() { + Some(md) => Some((md.len(), None)), None => None, } } -fn examine_dir(a_dir: io::Result, inodes: &mut HashSet) -> (bool, Vec) { +fn examine_dir( + a_dir: io::Result, + apparent_size: bool, + inodes: &mut HashSet<(u64, u64)>, +) -> (bool, Vec) { let mut result = vec![]; let mut have_permission = true; @@ -79,18 +114,21 @@ fn examine_dir(a_dir: io::Result, inodes: &mut HashSet) -> (bool, match dd { Ok(d) => { let file_type = d.file_type().ok(); - let maybe_size_and_inode = get_metadata_blocks_and_inode(&d); + let maybe_size_and_inode = get_metadata(&d, apparent_size); match (file_type, maybe_size_and_inode) { (Some(file_type), Some((size, inode))) => { let s = d.path().to_string_lossy().to_string(); - if inodes.contains(&inode) { - continue; + if let Some(inode_dev_pair) = inode { + if inodes.contains(&inode_dev_pair) { + continue; + } + inodes.insert(inode_dev_pair); } - inodes.insert(inode); if d.path().is_dir() && !file_type.is_symlink() { - let (hp, recursive) = examine_dir(fs::read_dir(d.path()), inodes); + let (hp, recursive) = + examine_dir(fs::read_dir(d.path()), apparent_size, inodes); have_permission = have_permission && hp; let new_size = recursive.iter().fold(size, |a, b| a + b.entry().size());