From b0e971891ed43c8735dc3ce6468df8642136f80c Mon Sep 17 00:00:00 2001 From: bootandy Date: Tue, 20 Mar 2018 16:12:34 -0400 Subject: [PATCH 1/3] Fix basic message --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 4630eac..b78ac7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,7 +71,7 @@ struct Dir { 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") From 4d1f881c17ac31579ead16ba4aafdcce2d0cc1b2 Mon Sep 17 00:00:00 2001 From: bootandy Date: Wed, 21 Mar 2018 19:13:26 -0400 Subject: [PATCH 2/3] fix: inodes are only unique with dev First iteration adding dev to inodes to form a tuple to go into our 'have we seen this before' hashset. inodes are not unique across partitions --- src/main.rs | 86 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/src/main.rs b/src/main.rs index b78ac7b..97e3d1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,6 +80,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(); @@ -90,13 +95,14 @@ 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); } -fn get_dir_tree(filenames: &Vec<&str>) -> (bool, Vec) { +fn get_dir_tree(filenames: &Vec<&str>, apparent_size: bool) -> (bool, Vec) { let mut permissions = true; let mut results = vec![]; for b in filenames { @@ -104,16 +110,16 @@ 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: String) -> (bool, Node) { - let mut inodes: HashSet = HashSet::new(); - let (hp, result) = examine_dir(fs::read_dir(&loc), &mut inodes); +fn examine_dir_str(loc: String, 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.dir.size); @@ -129,42 +135,77 @@ fn examine_dir_str(loc: String) -> (bool, Node) { ) } +#[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.ino(), md.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; @@ -174,18 +215,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.dir.size); result.push(Node { From f72a67132c553900a6f82672632c9556aa863f09 Mon Sep 17 00:00:00 2001 From: bootandy Date: Wed, 21 Mar 2018 19:50:13 -0400 Subject: [PATCH 3/3] Remove commented out code --- src/main.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 97e3d1e..f797730 100644 --- a/src/main.rs +++ b/src/main.rs @@ -282,13 +282,6 @@ fn find_big_ones<'a>(l: &'a Vec, max_to_show: usize) -> Vec<&Node> { .collect(); new_l.extend(b_list); new_l.sort(); - /*println!( - "{:?} -------------------", - new_l - .iter() - .map(|a| a.dir.size.to_string() + ": " + &a.dir.name) - .collect::>() - );*/ } if new_l.len() > max_to_show { new_l[0..max_to_show + 1].to_vec() @@ -390,8 +383,6 @@ fn print_this_node(node_to_print: &Node, is_biggest: bool, depth: u8, indentatio fn human_readable_number(size: u64) -> (String) { let units = vec!["T", "G", "M", "K"]; //make static - //return format!("{}B", size); - for (i, u) in units.iter().enumerate() { let marker = 1024u64.pow((units.len() - i) as u32); if size >= marker {