@@ -696,6 +696,9 @@ pub trait FileExt {
696
696
/// Copy the entire contents of `self` to `to`. This uses operating system
697
697
/// specific fast paths if available.
698
698
fn copy_to ( & self , to : & File ) -> io:: Result < u64 > ;
699
+
700
+ /// Update timestamps (both access and modification) to the current time.
701
+ fn update_timestamps ( & self ) -> io:: Result < ( ) > ;
699
702
}
700
703
701
704
impl FileExt for File {
@@ -764,6 +767,16 @@ impl FileExt for File {
764
767
}
765
768
Ok ( written)
766
769
}
770
+
771
+ fn update_timestamps ( & self ) -> io:: Result < ( ) > {
772
+ use nix:: sys:: { stat:: futimens, time:: TimeSpec } ;
773
+
774
+ let now = TimeSpec :: from ( libc:: timespec {
775
+ tv_nsec : libc:: UTIME_NOW ,
776
+ tv_sec : 0 ,
777
+ } ) ;
778
+ retry_eintr ! ( futimens( self . as_raw_fd( ) , & now, & now, ) . map_err( map_nix_error) )
779
+ }
767
780
}
768
781
769
782
fn to_cstr < P : openat:: AsPath > ( path : P ) -> io:: Result < P :: Buffer > {
@@ -775,7 +788,8 @@ fn to_cstr<P: openat::AsPath>(path: P) -> io::Result<P::Buffer> {
775
788
mod tests {
776
789
use super :: * ;
777
790
use std:: path:: { Path , PathBuf } ;
778
- use std:: { error, result} ;
791
+ use std:: time:: Duration ;
792
+ use std:: { error, result, thread} ;
779
793
use tempfile;
780
794
781
795
type Result < T > = result:: Result < T , Box < dyn error:: Error > > ;
@@ -905,18 +919,34 @@ mod tests {
905
919
906
920
#[ test]
907
921
fn test_update_timestamps ( ) {
922
+ // File timestamps can not be updated faster than kernel ticking granularity,
923
+ // so this test has to artificially sleep through several timer interrupts.
924
+ const TICKING_PAUSE : Duration = Duration :: from_millis ( 100 ) ;
925
+
908
926
let td = tempfile:: tempdir ( ) . unwrap ( ) ;
909
927
let d = openat:: Dir :: open ( td. path ( ) ) . unwrap ( ) ;
910
- d. ensure_dir ( "foo" , 0o755 ) . unwrap ( ) ;
911
- let before = d. metadata ( "foo" ) . unwrap ( ) ;
912
- // File timestamps can not be updated faster than kernel ticking granularity,
913
- // so this artificially sleeps through several timer interrupts.
914
- std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
915
928
916
- d. update_timestamps ( "foo" ) . unwrap ( ) ;
917
- let after = d. metadata ( "foo" ) . unwrap ( ) ;
918
- if before. stat ( ) . st_mtime == after. stat ( ) . st_mtime {
919
- assert_ne ! ( before. stat( ) . st_mtime_nsec, after. stat( ) . st_mtime_nsec) ;
929
+ {
930
+ d. ensure_dir ( "foo" , 0o755 ) . unwrap ( ) ;
931
+ let before = d. metadata ( "foo" ) . unwrap ( ) ;
932
+ thread:: sleep ( TICKING_PAUSE ) ;
933
+ d. update_timestamps ( "foo" ) . unwrap ( ) ;
934
+ let after = d. metadata ( "foo" ) . unwrap ( ) ;
935
+ if before. stat ( ) . st_mtime == after. stat ( ) . st_mtime {
936
+ assert_ne ! ( before. stat( ) . st_mtime_nsec, after. stat( ) . st_mtime_nsec) ;
937
+ }
938
+ }
939
+ {
940
+ use nix:: sys:: stat:: fstat;
941
+
942
+ let bar = d. update_file ( "bar" , 0o644 ) . unwrap ( ) ;
943
+ let before = fstat ( bar. as_raw_fd ( ) ) . unwrap ( ) ;
944
+ thread:: sleep ( TICKING_PAUSE ) ;
945
+ bar. update_timestamps ( ) . unwrap ( ) ;
946
+ let after = fstat ( bar. as_raw_fd ( ) ) . unwrap ( ) ;
947
+ if before. st_mtime == after. st_mtime {
948
+ assert_ne ! ( before. st_mtime_nsec, after. st_mtime_nsec) ;
949
+ }
920
950
}
921
951
}
922
952
0 commit comments