diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 5763d7862f5ae..966fb2ae834b6 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -18,6 +18,8 @@ pub struct File(!); pub struct FileAttr { attr: u64, size: u64, + created: r_efi::efi::Time, + times: FileTimes, } pub struct ReadDir(!); @@ -33,7 +35,10 @@ pub struct OpenOptions { } #[derive(Copy, Clone, Debug, Default)] -pub struct FileTimes {} +pub struct FileTimes { + accessed: r_efi::efi::Time, + modified: r_efi::efi::Time, +} #[derive(Clone, PartialEq, Eq, Debug)] // Bool indicates if file is readonly @@ -60,15 +65,15 @@ impl FileAttr { } pub fn modified(&self) -> io::Result { - unsupported() + Ok(SystemTime::from_uefi(self.times.modified)) } pub fn accessed(&self) -> io::Result { - unsupported() + Ok(SystemTime::from_uefi(self.times.accessed)) } pub fn created(&self) -> io::Result { - unsupported() + Ok(SystemTime::from_uefi(self.created)) } } @@ -92,8 +97,13 @@ impl FilePermissions { } impl FileTimes { - pub fn set_accessed(&mut self, _t: SystemTime) {} - pub fn set_modified(&mut self, _t: SystemTime) {} + pub fn set_accessed(&mut self, t: SystemTime) { + self.accessed = t.to_uefi_loose(self.accessed.timezone, self.accessed.daylight); + } + + pub fn set_modified(&mut self, t: SystemTime) { + self.modified = t.to_uefi_loose(self.modified.timezone, self.modified.daylight); + } } impl FileType { diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs index 56ca999cc7e99..ad6c13c72f274 100644 --- a/library/std/src/sys/pal/uefi/tests.rs +++ b/library/std/src/sys/pal/uefi/tests.rs @@ -8,6 +8,20 @@ use crate::time::Duration; const SECS_IN_MINUTE: u64 = 60; +const MAX_UEFI_TIME: Duration = from_uefi(r_efi::efi::Time { + year: 9999, + month: 12, + day: 31, + hour: 23, + minute: 59, + second: 59, + nanosecond: 999_999_999, + timezone: 1440, + daylight: 0, + pad1: 0, + pad2: 0, +}); + #[test] fn align() { // UEFI ABI specifies that allocation alignment minimum is always 8. So this can be @@ -44,7 +58,7 @@ fn systemtime_start() { }; assert_eq!(from_uefi(&t), Duration::new(0, 0)); assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap()); - assert!(to_uefi(&from_uefi(&t), 0, 0).is_none()); + assert!(to_uefi(&from_uefi(&t), 0, 0).is_err()); } #[test] @@ -64,7 +78,7 @@ fn systemtime_utc_start() { }; assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0)); assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap()); - assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some()); + assert!(to_uefi(&from_uefi(&t), -1440, 0).is_err()); } #[test] @@ -82,8 +96,44 @@ fn systemtime_end() { daylight: 0, pad2: 0, }; - assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some()); - assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none()); + assert!(to_uefi(&from_uefi(&t), 1440, 0).is_ok()); + assert!(to_uefi(&from_uefi(&t), 1439, 0).is_err()); +} + +#[test] +fn min_time() { + let inp = Duration::from_secs(1440 * SECS_IN_MINUTE); + let new_tz = to_uefi(&inp, 1440, 0).err().unwrap(); + assert_eq!(new_tz, 0); + assert!(to_uefi(&inp, new_tz, 0).is_ok()); + + let inp = Duration::from_secs(1450 * SECS_IN_MINUTE); + let new_tz = to_uefi(&inp, 1440, 0).err().unwrap(); + assert_eq!(new_tz, 10); + assert!(to_uefi(&inp, new_tz, 0).is_ok()); + + let inp = Duration::from_secs(1450 * SECS_IN_MINUTE + 10); + let new_tz = to_uefi(&inp, 1440, 0).err().unwrap(); + assert_eq!(new_tz, 9); + assert!(to_uefi(&inp, new_tz, 0).is_ok()); +} + +#[test] +fn max_time() { + let inp = MAX_UEFI_TIME; + let new_tz = to_uefi(&inp, -1440, 0).err().unwrap(); + assert_eq!(new_tz, 1440); + assert!(to_uefi(&inp, new_tz, 0).is_ok()); + + let inp = MAX_UEFI_TIME - Duration::from_secs(1440 * SECS_IN_MINUTE); + let new_tz = to_uefi(&inp, -1440, 0).err().unwrap(); + assert_eq!(new_tz, 0); + assert!(to_uefi(&inp, new_tz, 0).is_ok()); + + let inp = MAX_UEFI_TIME - Duration::from_secs(1440 * SECS_IN_MINUTE + 10); + let new_tz = to_uefi(&inp, -1440, 0).err().unwrap(); + assert_eq!(new_tz, 0); + assert!(to_uefi(&inp, new_tz, 0).is_ok()); } // UEFI IoSlice and IoSliceMut Tests diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index a5ab76903274d..e97ebdfc1e720 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -1,5 +1,7 @@ use crate::time::Duration; +const SECS_IN_MINUTE: u64 = 60; + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); @@ -70,11 +72,23 @@ impl SystemTime { Self(system_time_internal::from_uefi(&t)) } - #[expect(dead_code)] - pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option { + pub(crate) const fn to_uefi( + self, + timezone: i16, + daylight: u8, + ) -> Result { system_time_internal::to_uefi(&self.0, timezone, daylight) } + /// Create UEFI Time with the closes timezone (minute offset) that still allows the time to be + /// represented. + pub(crate) fn to_uefi_loose(self, timezone: i16, daylight: u8) -> r_efi::efi::Time { + match self.to_uefi(timezone, daylight) { + Ok(x) => x, + Err(tz) => self.to_uefi(tz, daylight).unwrap(), + } + } + pub fn now() -> SystemTime { system_time_internal::now() .unwrap_or_else(|| panic!("time not implemented on this platform")) @@ -104,7 +118,6 @@ pub(crate) mod system_time_internal { use crate::mem::MaybeUninit; use crate::ptr::NonNull; - const SECS_IN_MINUTE: u64 = 60; const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60; const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE; @@ -180,7 +193,10 @@ pub(crate) mod system_time_internal { /// /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX /// epoch used in the original algorithm. - pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option