@@ -313,8 +313,11 @@ pub struct FilePermissions {
313313    mode :  mode_t , 
314314} 
315315
316- #[ derive( Copy ,  Clone ) ]  
317- pub  struct  FileTimes ( [ libc:: timespec ;  2 ] ) ; 
316+ #[ derive( Copy ,  Clone ,  Debug ,  Default ) ]  
317+ pub  struct  FileTimes  { 
318+     accessed :  Option < SystemTime > , 
319+     modified :  Option < SystemTime > , 
320+ } 
318321
319322#[ derive( Copy ,  Clone ,  PartialEq ,  Eq ,  Hash ,  Debug ) ]  
320323pub  struct  FileType  { 
@@ -512,45 +515,11 @@ impl FilePermissions {
512515
513516impl  FileTimes  { 
514517    pub  fn  set_accessed ( & mut  self ,  t :  SystemTime )  { 
515-         self . 0 [ 0 ]  = t . t . to_timespec ( ) . expect ( "Invalid system time" ) ; 
518+         self . accessed  = Some ( t ) ; 
516519    } 
517520
518521    pub  fn  set_modified ( & mut  self ,  t :  SystemTime )  { 
519-         self . 0 [ 1 ]  = t. t . to_timespec ( ) . expect ( "Invalid system time" ) ; 
520-     } 
521- } 
522- 
523- struct  TimespecDebugAdapter < ' a > ( & ' a  libc:: timespec ) ; 
524- 
525- impl  fmt:: Debug  for  TimespecDebugAdapter < ' _ >  { 
526-     fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
527-         f. debug_struct ( "timespec" ) 
528-             . field ( "tv_sec" ,  & self . 0 . tv_sec ) 
529-             . field ( "tv_nsec" ,  & self . 0 . tv_nsec ) 
530-             . finish ( ) 
531-     } 
532- } 
533- 
534- impl  fmt:: Debug  for  FileTimes  { 
535-     fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
536-         f. debug_struct ( "FileTimes" ) 
537-             . field ( "accessed" ,  & TimespecDebugAdapter ( & self . 0 [ 0 ] ) ) 
538-             . field ( "modified" ,  & TimespecDebugAdapter ( & self . 0 [ 1 ] ) ) 
539-             . finish ( ) 
540-     } 
541- } 
542- 
543- impl  Default  for  FileTimes  { 
544-     fn  default ( )  -> Self  { 
545-         // Redox doesn't appear to support `UTIME_OMIT`, so we stub it out here, and always return 
546-         // an error in `set_times`. 
547-         // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore 
548-         // the same as for Redox. 
549-         #[ cfg( any( target_os = "redox" ,  target_os = "espidf" ,  target_os = "horizon" ) ) ]  
550-         let  omit = libc:: timespec  {  tv_sec :  0 ,  tv_nsec :  0  } ; 
551-         #[ cfg( not( any( target_os = "redox" ,  target_os = "espidf" ,  target_os = "horizon" ) ) ) ]  
552-         let  omit = libc:: timespec  {  tv_sec :  0 ,  tv_nsec :  libc:: UTIME_OMIT  as  _  } ; 
553-         Self ( [ omit;  2 ] ) 
522+         self . modified  = Some ( t) ; 
554523    } 
555524} 
556525
@@ -1084,6 +1053,17 @@ impl File {
10841053    } 
10851054
10861055    pub  fn  set_times ( & self ,  times :  FileTimes )  -> io:: Result < ( ) >  { 
1056+         #[ cfg( not( any( target_os = "redox" ,  target_os = "espidf" ,  target_os = "horizon" ) ) ) ]  
1057+         let  to_timespec = |time :  Option < SystemTime > | { 
1058+             match  time { 
1059+                 Some ( time)  if  let  Some ( ts)  = time. t . to_timespec ( )  => Ok ( ts) , 
1060+                 Some ( time)  if  time > crate :: sys:: time:: UNIX_EPOCH  => Err ( io:: const_io_error!( io:: ErrorKind :: InvalidInput ,  "timestamp is too large to set as a file time" ) ) , 
1061+                 Some ( _)  => Err ( io:: const_io_error!( io:: ErrorKind :: InvalidInput ,  "timestamp is too small to set as a file time" ) ) , 
1062+                 None  => Ok ( libc:: timespec  {  tv_sec :  0 ,  tv_nsec :  libc:: UTIME_OMIT  as  _  } ) , 
1063+             } 
1064+         } ; 
1065+         #[ cfg( not( any( target_os = "redox" ,  target_os = "espidf" ,  target_os = "horizon" ) ) ) ]  
1066+         let  times = [ to_timespec ( times. accessed ) ?,  to_timespec ( times. modified ) ?] ; 
10871067        cfg_if:: cfg_if! { 
10881068            if  #[ cfg( any( target_os = "redox" ,  target_os = "espidf" ,  target_os = "horizon" ) ) ]  { 
10891069                // Redox doesn't appear to support `UTIME_OMIT`. 
@@ -1099,7 +1079,7 @@ impl File {
10991079                cvt( unsafe  { 
11001080                    weak!( fn  futimens( c_int,  * const  libc:: timespec)  -> c_int) ; 
11011081                    match  futimens. get( )  { 
1102-                         Some ( futimens)  => futimens( self . as_raw_fd( ) ,  times. 0 . as_ptr( ) ) , 
1082+                         Some ( futimens)  => futimens( self . as_raw_fd( ) ,  times. as_ptr( ) ) , 
11031083                        #[ cfg( target_os = "macos" ) ] 
11041084                        None  => { 
11051085                            fn  ts_to_tv( ts:  & libc:: timespec)  -> libc:: timeval { 
@@ -1108,7 +1088,7 @@ impl File {
11081088                                    tv_usec:  ( ts. tv_nsec / 1000 )  as  _
11091089                                } 
11101090                            } 
1111-                             let  timevals = [ ts_to_tv( & times. 0 [ 0 ] ) ,  ts_to_tv( & times. 0 [ 1 ] ) ] ; 
1091+                             let  timevals = [ ts_to_tv( & times[ 0 ] ) ,  ts_to_tv( & times[ 1 ] ) ] ; 
11121092                            libc:: futimes( self . as_raw_fd( ) ,  timevals. as_ptr( ) ) 
11131093                        } 
11141094                        // futimes requires even newer Android. 
@@ -1121,7 +1101,7 @@ impl File {
11211101                } ) ?; 
11221102                Ok ( ( ) ) 
11231103            }  else { 
1124-                 cvt( unsafe  {  libc:: futimens( self . as_raw_fd( ) ,  times. 0 . as_ptr( ) )  } ) ?; 
1104+                 cvt( unsafe  {  libc:: futimens( self . as_raw_fd( ) ,  times. as_ptr( ) )  } ) ?; 
11251105                Ok ( ( ) ) 
11261106            } 
11271107        } 
0 commit comments