@@ -7,24 +7,21 @@ use clap::{Arg, ArgAction, ArgMatches, Command, builder::PossibleValue};
77use glob:: Pattern ;
88use std:: collections:: { HashMap , HashSet } ;
99use std:: env;
10- #[ cfg( not( windows) ) ]
1110use std:: fs:: Metadata ;
1211use std:: fs:: { self , DirEntry , File } ;
1312use std:: io:: { BufRead , BufReader , stdout} ;
1413#[ cfg( not( windows) ) ]
1514use std:: os:: unix:: fs:: MetadataExt ;
1615#[ cfg( windows) ]
17- use std:: os:: windows:: fs:: MetadataExt ;
18- #[ cfg( windows) ]
1916use std:: os:: windows:: io:: AsRawHandle ;
2017use std:: path:: { Path , PathBuf } ;
2118use std:: str:: FromStr ;
2219use std:: sync:: mpsc;
2320use std:: thread;
24- use std:: time:: { Duration , UNIX_EPOCH } ;
2521use thiserror:: Error ;
2622use uucore:: display:: { Quotable , print_verbatim} ;
2723use uucore:: error:: { FromIo , UError , UResult , USimpleError , set_exit_code} ;
24+ use uucore:: fsext:: { MetadataTimeField , metadata_get_time} ;
2825use uucore:: line_ending:: LineEnding ;
2926use uucore:: locale:: { get_message, get_message_with_args} ;
3027use uucore:: parser:: parse_glob;
@@ -87,7 +84,7 @@ struct StatPrinter {
8784 threshold : Option < Threshold > ,
8885 apparent_size : bool ,
8986 size_format : SizeFormat ,
90- time : Option < Time > ,
87+ time : Option < MetadataTimeField > ,
9188 time_format : String ,
9289 line_ending : LineEnding ,
9390 summarize : bool ,
@@ -101,13 +98,6 @@ enum Deref {
10198 None ,
10299}
103100
104- #[ derive( Clone , Copy ) ]
105- enum Time {
106- Accessed ,
107- Modified ,
108- Created ,
109- }
110-
111101#[ derive( Clone ) ]
112102enum SizeFormat {
113103 HumanDecimal ,
@@ -123,14 +113,11 @@ struct FileInfo {
123113
124114struct Stat {
125115 path : PathBuf ,
126- is_dir : bool ,
127116 size : u64 ,
128117 blocks : u64 ,
129118 inodes : u64 ,
130119 inode : Option < FileInfo > ,
131- created : Option < u64 > ,
132- accessed : u64 ,
133- modified : u64 ,
120+ metadata : Metadata ,
134121}
135122
136123impl Stat {
@@ -157,69 +144,27 @@ impl Stat {
157144 fs:: symlink_metadata ( path)
158145 } ?;
159146
160- #[ cfg( not( windows) ) ]
161- {
162- let file_info = FileInfo {
163- file_id : metadata. ino ( ) as u128 ,
164- dev_id : metadata. dev ( ) ,
165- } ;
166-
167- Ok ( Self {
168- path : path. to_path_buf ( ) ,
169- is_dir : metadata. is_dir ( ) ,
170- size : if metadata. is_dir ( ) { 0 } else { metadata. len ( ) } ,
171- blocks : metadata. blocks ( ) ,
172- inodes : 1 ,
173- inode : Some ( file_info) ,
174- created : birth_u64 ( & metadata) ,
175- accessed : metadata. atime ( ) as u64 ,
176- modified : metadata. mtime ( ) as u64 ,
177- } )
178- }
179-
180- #[ cfg( windows) ]
181- {
182- let size_on_disk = get_size_on_disk ( path) ;
183- let file_info = get_file_info ( path) ;
184-
185- Ok ( Self {
186- path : path. to_path_buf ( ) ,
187- is_dir : metadata. is_dir ( ) ,
188- size : if metadata. is_dir ( ) { 0 } else { metadata. len ( ) } ,
189- blocks : size_on_disk / 1024 * 2 ,
190- inodes : 1 ,
191- inode : file_info,
192- created : windows_creation_time_to_unix_time ( metadata. creation_time ( ) ) ,
193- accessed : windows_time_to_unix_time ( metadata. last_access_time ( ) ) ,
194- modified : windows_time_to_unix_time ( metadata. last_write_time ( ) ) ,
195- } )
196- }
147+ let file_info = get_file_info ( path, & metadata) ;
148+ let blocks = get_blocks ( path, & metadata) ;
149+
150+ Ok ( Self {
151+ path : path. to_path_buf ( ) ,
152+ size : if metadata. is_dir ( ) { 0 } else { metadata. len ( ) } ,
153+ blocks,
154+ inodes : 1 ,
155+ inode : file_info,
156+ metadata,
157+ } )
197158 }
198159}
199160
200- #[ cfg( windows) ]
201- /// <https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html#tymethod.last_access_time>
202- /// "The returned 64-bit value [...] which represents the number of 100-nanosecond intervals since January 1, 1601 (UTC)."
203- /// "If the underlying filesystem does not support last access time, the returned value is 0."
204- fn windows_time_to_unix_time ( win_time : u64 ) -> u64 {
205- ( win_time / 10_000_000 ) . saturating_sub ( 11_644_473_600 )
206- }
207-
208- #[ cfg( windows) ]
209- fn windows_creation_time_to_unix_time ( win_time : u64 ) -> Option < u64 > {
210- ( win_time / 10_000_000 ) . checked_sub ( 11_644_473_600 )
211- }
212-
213161#[ cfg( not( windows) ) ]
214- fn birth_u64 ( meta : & Metadata ) -> Option < u64 > {
215- meta. created ( )
216- . ok ( )
217- . and_then ( |t| t. duration_since ( UNIX_EPOCH ) . ok ( ) )
218- . map ( |e| e. as_secs ( ) )
162+ fn get_blocks ( _path : & Path , metadata : & Metadata ) -> u64 {
163+ metadata. blocks ( )
219164}
220165
221166#[ cfg( windows) ]
222- fn get_size_on_disk ( path : & Path ) -> u64 {
167+ fn get_blocks ( path : & Path , _metadata : & Metadata ) -> u64 {
223168 let mut size_on_disk = 0 ;
224169
225170 // bind file so it stays in scope until end of function
@@ -244,11 +189,19 @@ fn get_size_on_disk(path: &Path) -> u64 {
244189 }
245190 }
246191
247- size_on_disk
192+ size_on_disk / 1024 * 2
193+ }
194+
195+ #[ cfg( not( windows) ) ]
196+ fn get_file_info ( _path : & Path , metadata : & Metadata ) -> Option < FileInfo > {
197+ Some ( FileInfo {
198+ file_id : metadata. ino ( ) as u128 ,
199+ dev_id : metadata. dev ( ) ,
200+ } )
248201}
249202
250203#[ cfg( windows) ]
251- fn get_file_info ( path : & Path ) -> Option < FileInfo > {
204+ fn get_file_info ( path : & Path , _metadata : & Metadata ) -> Option < FileInfo > {
252205 let mut result = None ;
253206
254207 let Ok ( file) = File :: open ( path) else {
@@ -306,7 +259,7 @@ fn du(
306259 seen_inodes : & mut HashSet < FileInfo > ,
307260 print_tx : & mpsc:: Sender < UResult < StatPrintInfo > > ,
308261) -> Result < Stat , Box < mpsc:: SendError < UResult < StatPrintInfo > > > > {
309- if my_stat. is_dir {
262+ if my_stat. metadata . is_dir ( ) {
310263 let read = match fs:: read_dir ( & my_stat. path ) {
311264 Ok ( read) => read,
312265 Err ( e) => {
@@ -367,7 +320,7 @@ fn du(
367320 seen_inodes. insert ( inode) ;
368321 }
369322
370- if this_stat. is_dir {
323+ if this_stat. metadata . is_dir ( ) {
371324 if options. one_file_system {
372325 if let ( Some ( this_inode) , Some ( my_inode) ) =
373326 ( this_stat. inode , my_stat. inode )
@@ -435,9 +388,6 @@ enum DuError {
435388 ] ) ) ) ]
436389 InvalidTimeStyleArg ( String ) ,
437390
438- #[ error( "{}" , get_message( "du-error-invalid-time-arg" ) ) ]
439- InvalidTimeArg ,
440-
441391 #[ error( "{}" , get_message_with_args( "du-error-invalid-glob" , HashMap :: from( [ ( "error" . to_string( ) , _0. to_string( ) ) ] ) ) ) ]
442392 InvalidGlob ( String ) ,
443393}
@@ -448,7 +398,6 @@ impl UError for DuError {
448398 Self :: InvalidMaxDepthArg ( _)
449399 | Self :: SummarizeDepthConflict ( _)
450400 | Self :: InvalidTimeStyleArg ( _)
451- | Self :: InvalidTimeArg
452401 | Self :: InvalidGlob ( _) => 1 ,
453402 }
454403 }
@@ -577,11 +526,13 @@ impl StatPrinter {
577526 fn print_stat ( & self , stat : & Stat , size : u64 ) -> UResult < ( ) > {
578527 print ! ( "{}\t " , self . convert_size( size) ) ;
579528
580- if let Some ( time) = self . time {
581- let secs = get_time_secs ( time, stat) ?;
582- let time = UNIX_EPOCH + Duration :: from_secs ( secs) ;
583- uucore:: time:: format_system_time ( & mut stdout ( ) , time, & self . time_format , true ) ?;
584- print ! ( "\t " ) ;
529+ if let Some ( md_time) = & self . time {
530+ if let Some ( time) = metadata_get_time ( & stat. metadata , * md_time) {
531+ uucore:: time:: format_system_time ( & mut stdout ( ) , time, & self . time_format , true ) ?;
532+ print ! ( "\t " ) ;
533+ } else {
534+ print ! ( "???\t " ) ;
535+ }
585536 }
586537
587538 print_verbatim ( & stat. path ) . unwrap ( ) ;
@@ -697,12 +648,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
697648 } ;
698649
699650 let time = matches. contains_id ( options:: TIME ) . then ( || {
700- match matches. get_one :: < String > ( options:: TIME ) . map ( AsRef :: as_ref) {
701- None | Some ( "ctime" | "status" ) => Time :: Modified ,
702- Some ( "access" | "atime" | "use" ) => Time :: Accessed ,
703- Some ( "birth" | "creation" ) => Time :: Created ,
704- _ => unreachable ! ( "should be caught by clap" ) ,
705- }
651+ matches
652+ . get_one :: < String > ( options:: TIME )
653+ . map_or ( MetadataTimeField :: Modification , |s| s. as_str ( ) . into ( ) )
706654 } ) ;
707655
708656 let size_format = if matches. get_flag ( options:: HUMAN_READABLE ) {
@@ -853,14 +801,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
853801 Ok ( ( ) )
854802}
855803
856- fn get_time_secs ( time : Time , stat : & Stat ) -> Result < u64 , DuError > {
857- match time {
858- Time :: Modified => Ok ( stat. modified ) ,
859- Time :: Accessed => Ok ( stat. accessed ) ,
860- Time :: Created => stat. created . ok_or ( DuError :: InvalidTimeArg ) ,
861- }
862- }
863-
864804fn parse_time_style ( s : Option < & str > ) -> UResult < & str > {
865805 match s {
866806 Some ( s) => match s {
0 commit comments