diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index b7c53eb72..39af3d7e1 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -28,6 +28,7 @@ use std::os::windows::io::AsRawHandle; #[cfg(windows)] use std::path::Path; use std::path::PathBuf; +use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::InvalidEncodingHandling; @@ -56,6 +57,7 @@ mod options { pub const BLOCK_SIZE_1M: &str = "m"; pub const SEPARATE_DIRS: &str = "S"; pub const SUMMARIZE: &str = "s"; + pub const THRESHOLD: &str = "threshold"; pub const SI: &str = "si"; pub const TIME: &str = "time"; pub const TIME_STYLE: &str = "time-style"; @@ -510,6 +512,17 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .long(options::ONE_FILE_SYSTEM) .help("skip directories on different file systems") ) + .arg( + Arg::with_name(options::THRESHOLD) + .short("t") + .long(options::THRESHOLD) + .alias("th") + .value_name("SIZE") + .number_of_values(1) + .allow_hyphen_values(true) + .help("exclude entries smaller than SIZE if positive, \ + or entries greater than SIZE if negative") + ) // .arg( // Arg::with_name("") // .short("x") @@ -586,6 +599,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let block_size = u64::try_from(read_block_size(matches.value_of(options::BLOCK_SIZE))).unwrap(); + let threshold = match matches.value_of(options::THRESHOLD) { + Some(s) => Threshold::from_str(s) + .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::THRESHOLD))), + None => Threshold(None, false), + }; + let multiplier: u64 = if matches.is_present(options::SI) { 1000 } else { @@ -654,6 +673,10 @@ Try '{} --help' for more information.", // See: http://linux.die.net/man/2/stat stat.blocks * 512 }; + if threshold.should_exclude(size) { + continue; + } + if matches.is_present(options::TIME) { let tm = { let secs = { @@ -720,6 +743,35 @@ Try '{} --help' for more information.", 0 } +struct Threshold(Option, bool); + +impl FromStr for Threshold { + type Err = ParseSizeError; + + fn from_str(s: &str) -> std::result::Result { + let offset = if s.starts_with('-') || s.starts_with('+') { + 1 + } else { + 0 + }; + let sz = parse_size(&s[offset..])?; + + Ok(Threshold( + Some(u64::try_from(sz).unwrap()), + s.starts_with('-'), + )) + } +} + +impl Threshold { + fn should_exclude(&self, sz: u64) -> bool { + match *self { + Threshold(Some(th), is_upper) => (is_upper && sz > th) || (!is_upper && sz < th), + Threshold(None, _) => false, + } + } +} + fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String { // NOTE: // GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection