Correctly calculate file size using number of blocks

This commit is contained in:
Derek Chiang 2013-12-09 02:11:11 -05:00
parent 9eae93e8a1
commit a228acbb50

View file

@ -26,7 +26,8 @@ static VERSION: &'static str = "1.0.0";
struct Options { struct Options {
all: bool, all: bool,
max_depth: Option<uint>, max_depth: Option<uint>,
total: bool total: bool,
separate_dirs: bool,
} }
fn du(path: &Path, options_arc: Arc<Options>, depth: uint) -> ~[Arc<FileStat>] { fn du(path: &Path, options_arc: Arc<Options>, depth: uint) -> ~[Arc<FileStat>] {
@ -40,6 +41,7 @@ fn du(path: &Path, options_arc: Arc<Options>, depth: uint) -> ~[Arc<FileStat>] {
true => { true => {
let stat = f.stat(); let stat = f.stat();
my_stat.size += stat.size; my_stat.size += stat.size;
my_stat.unstable.blocks += stat.unstable.blocks;
if options.all { if options.all {
stats.push(Arc::new(stat)) stats.push(Arc::new(stat))
} }
@ -54,8 +56,9 @@ fn du(path: &Path, options_arc: Arc<Options>, depth: uint) -> ~[Arc<FileStat>] {
for future in futures.mut_iter() { for future in futures.mut_iter() {
for stat_arc in future.get().move_rev_iter() { for stat_arc in future.get().move_rev_iter() {
let stat = stat_arc.get(); let stat = stat_arc.get();
if stat.path.dir_path() == my_stat.path { if !options.separate_dirs && stat.path.dir_path() == my_stat.path {
my_stat.size += stat.size; my_stat.size += stat.size;
my_stat.unstable.blocks += stat.unstable.blocks;
} }
if options.max_depth == None || depth < options.max_depth.unwrap() { if options.max_depth == None || depth < options.max_depth.unwrap() {
stats.push(stat_arc.clone()); stats.push(stat_arc.clone());
@ -74,11 +77,11 @@ fn main() {
let opts = ~[ let opts = ~[
// In task // In task
groups::optflag("a", "all", " write counts for all files, not just directories"), groups::optflag("a", "all", " write counts for all files, not just directories"),
// // In main
// groups::optflag("", "apparent-size", "print apparent sizes, rather than disk usage;
// although the apparent size is usually smaller, it may be larger due to holes
// in ('sparse') files, internal fragmentation, indirect blocks, and the like"),
// In main // In main
groups::optflag("", "apparent-size", "print apparent sizes, rather than disk usage;
although the apparent size is usually smaller, it may be larger due to holes
in ('sparse') files, internal fragmentation, indirect blocks, and the like"),
// // In main
// groups::optopt("B", "block-size", "scale sizes by SIZE before printing them. // groups::optopt("B", "block-size", "scale sizes by SIZE before printing them.
// E.g., '-BM' prints sizes in units of 1,048,576 bytes. See SIZE format below.", // E.g., '-BM' prints sizes in units of 1,048,576 bytes. See SIZE format below.",
// "SIZE"), // "SIZE"),
@ -190,7 +193,8 @@ ers of 1000).");
}, },
(false, None) => None (false, None) => None
}, },
total: matches.opt_present("total") total: matches.opt_present("total"),
separate_dirs: matches.opt_present("S"),
}; };
let strs = matches.free.clone(); let strs = matches.free.clone();
@ -201,10 +205,17 @@ ers of 1000).");
let options_arc = Arc::new(options); let options_arc = Arc::new(options);
let MB = 1024 * 1024; let MB = match matches.opt_present("si") {
let KB = 1024; true => 1000 * 1000,
false => 1024 * 1024,
};
let KB = match matches.opt_present("si") {
true => 1000,
false => 1024,
};
let convert_size = |size: u64| -> ~str { let convert_size = |size: u64| -> ~str {
if matches.opt_present("human-readable") { if matches.opt_present("human-readable") || matches.opt_present("si") {
if size > MB { if size > MB {
format!("{:.1f}MB", (size as f64) / (MB as f64)) format!("{:.1f}MB", (size as f64) / (MB as f64))
} else if size > KB { } else if size > KB {
@ -221,6 +232,11 @@ ers of 1000).");
} }
}; };
let line_separator = match matches.opt_present("0") {
true => "\0",
false => "\n",
};
let mut grand_total = 0; let mut grand_total = 0;
for path_str in strs.iter() { for path_str in strs.iter() {
let path = Path::init(path_str.clone()); let path = Path::init(path_str.clone());
@ -229,16 +245,24 @@ ers of 1000).");
let len = len.unwrap(); let len = len.unwrap();
for (index, stat_arc) in iter.enumerate() { for (index, stat_arc) in iter.enumerate() {
let stat = stat_arc.get(); let stat = stat_arc.get();
println!("{:<10} {}", convert_size(stat.size), stat.path.display()); let size = match matches.opt_present("apparent-size") {
true => stat.size,
// C's stat is such that each block is assume to be 512 bytes
// See: http://linux.die.net/man/2/stat
false => stat.unstable.blocks * 512,
};
print!("{:<10} {}", convert_size(size), stat.path.display());
print(line_separator);
if options.total && index == (len - 1) { if options.total && index == (len - 1) {
// The last element will be the total size of the the path under // The last element will be the total size of the the path under
// path_str. We add it to the grand total. // path_str. We add it to the grand total.
grand_total += stat.size; grand_total += size;
} }
} }
} }
if options.total { if options.total {
println!("{:<10} total", convert_size(grand_total)); print!("{:<10} total", convert_size(grand_total));
print(line_separator);
} }
} }