@@ -83,6 +83,7 @@ struct TraversalOptions {
83
83
dereference : Deref ,
84
84
count_links : bool ,
85
85
verbose : bool ,
86
+ excludes : Vec < Pattern > ,
86
87
}
87
88
88
89
#[ derive( Clone ) ]
@@ -92,13 +93,7 @@ struct PrintingOptions {
92
93
max_depth : Option < usize > ,
93
94
threshold : Option < Threshold > ,
94
95
apparent_size : bool ,
95
- // TODO: the size conversion fields should be unified
96
- si : bool ,
97
- bytes : bool ,
98
- human_readable : bool ,
99
- block_size_1k : bool ,
100
- block_size_1m : bool ,
101
- block_size : u64 ,
96
+ size_format : SizeFormat ,
102
97
time : Option < Time > ,
103
98
time_format : String ,
104
99
line_ending : LineEnding ,
@@ -118,6 +113,12 @@ enum Time {
118
113
Created ,
119
114
}
120
115
116
+ #[ derive( Clone ) ]
117
+ enum SizeFormat {
118
+ Human ( u64 ) ,
119
+ BlockSize ( u64 ) ,
120
+ }
121
+
121
122
#[ derive( PartialEq , Eq , Hash , Clone , Copy ) ]
122
123
struct FileInfo {
123
124
file_id : u128 ,
@@ -298,7 +299,7 @@ fn read_block_size(s: Option<&str>) -> UResult<u64> {
298
299
fn choose_size ( options : & PrintingOptions , stat : & Stat ) -> u64 {
299
300
if options. inodes {
300
301
stat. inodes
301
- } else if options. apparent_size || options . bytes {
302
+ } else if options. apparent_size {
302
303
stat. size
303
304
} else {
304
305
// The st_blocks field indicates the number of blocks allocated to the file, 512-byte units.
@@ -314,7 +315,6 @@ fn du(
314
315
options : & TraversalOptions ,
315
316
depth : usize ,
316
317
seen_inodes : & mut HashSet < FileInfo > ,
317
- exclude : & [ Pattern ] ,
318
318
print_tx : & mpsc:: Sender < UResult < StatPrintInfo > > ,
319
319
) -> Result < Stat , Box < mpsc:: SendError < UResult < StatPrintInfo > > > > {
320
320
if my_stat. is_dir {
@@ -334,7 +334,7 @@ fn du(
334
334
match Stat :: new ( & entry. path ( ) , options) {
335
335
Ok ( this_stat) => {
336
336
// We have an exclude list
337
- for pattern in exclude {
337
+ for pattern in & options . excludes {
338
338
// Look at all patterns with both short and long paths
339
339
// if we have 'du foo' but search to exclude 'foo/bar'
340
340
// we need the full path
@@ -370,14 +370,8 @@ fn du(
370
370
}
371
371
}
372
372
373
- let this_stat = du (
374
- this_stat,
375
- options,
376
- depth + 1 ,
377
- seen_inodes,
378
- exclude,
379
- print_tx,
380
- ) ?;
373
+ let this_stat =
374
+ du ( this_stat, options, depth + 1 , seen_inodes, print_tx) ?;
381
375
382
376
if !options. separate_dirs {
383
377
my_stat. size += this_stat. size ;
@@ -413,52 +407,6 @@ fn du(
413
407
Ok ( my_stat)
414
408
}
415
409
416
- fn convert_size_human ( size : u64 , multiplier : u64 , _block_size : u64 ) -> String {
417
- for & ( unit, power) in & UNITS {
418
- let limit = multiplier. pow ( power) ;
419
- if size >= limit {
420
- return format ! ( "{:.1}{}" , ( size as f64 ) / ( limit as f64 ) , unit) ;
421
- }
422
- }
423
- if size == 0 {
424
- return "0" . to_string ( ) ;
425
- }
426
- format ! ( "{size}B" )
427
- }
428
-
429
- fn convert_size_b ( size : u64 , _multiplier : u64 , _block_size : u64 ) -> String {
430
- format ! ( "{}" , ( ( size as f64 ) / ( 1_f64 ) ) . ceil( ) )
431
- }
432
-
433
- fn convert_size_k ( size : u64 , multiplier : u64 , _block_size : u64 ) -> String {
434
- format ! ( "{}" , ( ( size as f64 ) / ( multiplier as f64 ) ) . ceil( ) )
435
- }
436
-
437
- fn convert_size_m ( size : u64 , multiplier : u64 , _block_size : u64 ) -> String {
438
- format ! (
439
- "{}" ,
440
- ( ( size as f64 ) / ( ( multiplier * multiplier) as f64 ) ) . ceil( )
441
- )
442
- }
443
-
444
- fn convert_size_other ( size : u64 , _multiplier : u64 , block_size : u64 ) -> String {
445
- format ! ( "{}" , ( ( size as f64 ) / ( block_size as f64 ) ) . ceil( ) )
446
- }
447
-
448
- fn get_convert_size_fn ( options : & PrintingOptions ) -> Box < dyn Fn ( u64 , u64 , u64 ) -> String + Send > {
449
- if options. human_readable || options. si {
450
- Box :: new ( convert_size_human)
451
- } else if options. bytes {
452
- Box :: new ( convert_size_b)
453
- } else if options. block_size_1k {
454
- Box :: new ( convert_size_k)
455
- } else if options. block_size_1m {
456
- Box :: new ( convert_size_m)
457
- } else {
458
- Box :: new ( convert_size_other)
459
- }
460
- }
461
-
462
410
#[ derive( Debug ) ]
463
411
enum DuError {
464
412
InvalidMaxDepthArg ( String ) ,
@@ -557,26 +505,11 @@ struct StatPrintInfo {
557
505
struct StatPrinter {
558
506
summarize : bool ,
559
507
options : PrintingOptions ,
560
- convert_size : Box < dyn Fn ( u64 ) -> String + Send > ,
561
508
}
562
509
563
510
impl StatPrinter {
564
511
fn new ( options : PrintingOptions , summarize : bool ) -> UResult < Self > {
565
- let multiplier: u64 = if options. si { 1000 } else { 1024 } ;
566
-
567
- let convert_size_fn = get_convert_size_fn ( & options) ;
568
-
569
- let convert_size: Box < dyn Fn ( u64 ) -> String + Send > = if options. inodes {
570
- Box :: new ( |size : u64 | size. to_string ( ) )
571
- } else {
572
- Box :: new ( move |size : u64 | convert_size_fn ( size, multiplier, options. block_size ) )
573
- } ;
574
-
575
- Ok ( Self {
576
- summarize,
577
- options,
578
- convert_size,
579
- } )
512
+ Ok ( Self { summarize, options } )
580
513
}
581
514
582
515
fn print_stats ( & self , rx : & mpsc:: Receiver < UResult < StatPrintInfo > > ) -> UResult < ( ) > {
@@ -613,21 +546,42 @@ impl StatPrinter {
613
546
}
614
547
615
548
if self . options . total {
616
- print ! ( "{}\t total" , ( self . convert_size) ( grand_total) ) ;
549
+ print ! ( "{}\t total" , self . convert_size( grand_total) ) ;
617
550
print ! ( "{}" , self . options. line_ending) ;
618
551
}
619
552
620
553
Ok ( ( ) )
621
554
}
622
555
556
+ fn convert_size ( & self , size : u64 ) -> String {
557
+ if self . options . inodes {
558
+ return size. to_string ( ) ;
559
+ }
560
+ match self . options . size_format {
561
+ SizeFormat :: Human ( multiplier) => {
562
+ for & ( unit, power) in & UNITS {
563
+ let limit = multiplier. pow ( power) ;
564
+ if size >= limit {
565
+ return format ! ( "{:.1}{}" , ( size as f64 ) / ( limit as f64 ) , unit) ;
566
+ }
567
+ }
568
+ if size == 0 {
569
+ return "0" . to_string ( ) ;
570
+ }
571
+ format ! ( "{size}B" )
572
+ }
573
+ SizeFormat :: BlockSize ( block_size) => div_ceil ( size, block_size) . to_string ( ) ,
574
+ }
575
+ }
576
+
623
577
fn print_stat ( & self , stat : & Stat , size : u64 ) -> UResult < ( ) > {
624
578
if let Some ( time) = self . options . time {
625
579
let secs = get_time_secs ( time, stat) ?;
626
580
let tm = DateTime :: < Local > :: from ( UNIX_EPOCH + Duration :: from_secs ( secs) ) ;
627
581
let time_str = tm. format ( & self . options . time_format ) . to_string ( ) ;
628
- print ! ( "{}\t {}\t " , ( self . convert_size) ( size) , time_str) ;
582
+ print ! ( "{}\t {}\t " , self . convert_size( size) , time_str) ;
629
583
} else {
630
- print ! ( "{}\t " , ( self . convert_size) ( size) ) ;
584
+ print ! ( "{}\t " , self . convert_size( size) ) ;
631
585
}
632
586
633
587
print_verbatim ( & stat. path ) . unwrap ( ) ;
@@ -637,6 +591,13 @@ impl StatPrinter {
637
591
}
638
592
}
639
593
594
+ // This can be replaced with u64::div_ceil once it is stabilized.
595
+ // This implementation approach is optimized for when `b` is a constant,
596
+ // particularly a power of two.
597
+ pub fn div_ceil ( a : u64 , b : u64 ) -> u64 {
598
+ ( a + b - 1 ) / b
599
+ }
600
+
640
601
#[ uucore:: main]
641
602
#[ allow( clippy:: cognitive_complexity) ]
642
603
pub fn uumain ( args : impl uucore:: Args ) -> UResult < ( ) > {
@@ -671,11 +632,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
671
632
}
672
633
} ) ;
673
634
674
- let block_size = read_block_size (
675
- matches
676
- . get_one :: < String > ( options:: BLOCK_SIZE )
677
- . map ( |s| s. as_str ( ) ) ,
678
- ) ?;
635
+ let size_format = if matches. get_flag ( options:: HUMAN_READABLE ) {
636
+ SizeFormat :: Human ( 1024 )
637
+ } else if matches. get_flag ( options:: SI ) {
638
+ SizeFormat :: Human ( 1000 )
639
+ } else if matches. get_flag ( options:: BYTES ) {
640
+ SizeFormat :: BlockSize ( 1 )
641
+ } else if matches. get_flag ( options:: BLOCK_SIZE_1K ) {
642
+ SizeFormat :: BlockSize ( 1024 )
643
+ } else if matches. get_flag ( options:: BLOCK_SIZE_1M ) {
644
+ SizeFormat :: BlockSize ( 1024 * 1024 )
645
+ } else {
646
+ SizeFormat :: BlockSize ( read_block_size (
647
+ matches
648
+ . get_one :: < String > ( options:: BLOCK_SIZE )
649
+ . map ( AsRef :: as_ref) ,
650
+ ) ?)
651
+ } ;
679
652
680
653
let traversal_options = TraversalOptions {
681
654
all : matches. get_flag ( options:: ALL ) ,
@@ -691,13 +664,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
691
664
} ,
692
665
count_links : matches. get_flag ( options:: COUNT_LINKS ) ,
693
666
verbose : matches. get_flag ( options:: VERBOSE ) ,
667
+ excludes : build_exclude_patterns ( & matches) ?,
694
668
} ;
695
669
696
670
let printing_options = PrintingOptions {
697
671
max_depth,
672
+ size_format,
698
673
total : matches. get_flag ( options:: TOTAL ) ,
699
674
inodes : matches. get_flag ( options:: INODES ) ,
700
- si : matches. get_flag ( options:: SI ) ,
701
675
threshold : matches
702
676
. get_one :: < String > ( options:: THRESHOLD )
703
677
. map ( |s| {
@@ -706,13 +680,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
706
680
} )
707
681
} )
708
682
. transpose ( ) ?,
709
- apparent_size : matches. get_flag ( options:: APPARENT_SIZE ) ,
710
- bytes : matches. get_flag ( options:: BYTES ) ,
683
+ apparent_size : matches. get_flag ( options:: APPARENT_SIZE ) || matches. get_flag ( options:: BYTES ) ,
711
684
time,
712
- block_size,
713
- human_readable : matches. get_flag ( options:: HUMAN_READABLE ) ,
714
- block_size_1k : matches. get_flag ( options:: BLOCK_SIZE_1K ) ,
715
- block_size_1m : matches. get_flag ( options:: BLOCK_SIZE_1M ) ,
716
685
time_format : parse_time_style ( matches. get_one :: < String > ( "time-style" ) . map ( |s| s. as_str ( ) ) ) ?
717
686
. to_string ( ) ,
718
687
line_ending : LineEnding :: from_zero_flag ( matches. get_flag ( options:: NULL ) ) ,
@@ -729,13 +698,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
729
698
let ( print_tx, rx) = mpsc:: channel :: < UResult < StatPrintInfo > > ( ) ;
730
699
let printing_thread = thread:: spawn ( move || stat_printer. print_stats ( & rx) ) ;
731
700
732
- let excludes = build_exclude_patterns ( & matches) ?;
733
-
734
701
' loop_file: for path in files {
735
702
// Skip if we don't want to ignore anything
736
- if !& excludes. is_empty ( ) {
703
+ if !& traversal_options . excludes . is_empty ( ) {
737
704
let path_string = path. to_string_lossy ( ) ;
738
- for pattern in & excludes {
705
+ for pattern in & traversal_options . excludes {
739
706
if pattern. matches ( & path_string) {
740
707
// if the directory is ignored, leave early
741
708
if traversal_options. verbose {
@@ -753,15 +720,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
753
720
if let Some ( inode) = stat. inode {
754
721
seen_inodes. insert ( inode) ;
755
722
}
756
- let stat = du (
757
- stat,
758
- & traversal_options,
759
- 0 ,
760
- & mut seen_inodes,
761
- & excludes,
762
- & print_tx,
763
- )
764
- . map_err ( |e| USimpleError :: new ( 1 , e. to_string ( ) ) ) ?;
723
+ let stat = du ( stat, & traversal_options, 0 , & mut seen_inodes, & print_tx)
724
+ . map_err ( |e| USimpleError :: new ( 1 , e. to_string ( ) ) ) ?;
765
725
766
726
print_tx
767
727
. send ( Ok ( StatPrintInfo { stat, depth : 0 } ) )
0 commit comments