Skip to content

Commit 6637ec8

Browse files
committed
uefi: fs: Add file times plumbing
- Add FileTimes implementation. Signed-off-by: Ayush Singh <[email protected]>
1 parent d9dba3a commit 6637ec8

File tree

3 files changed

+110
-19
lines changed

3 files changed

+110
-19
lines changed

library/std/src/sys/fs/uefi.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub struct File(!);
1818
pub struct FileAttr {
1919
attr: u64,
2020
size: u64,
21+
created: r_efi::efi::Time,
22+
times: FileTimes,
2123
}
2224

2325
pub struct ReadDir(!);
@@ -33,7 +35,10 @@ pub struct OpenOptions {
3335
}
3436

3537
#[derive(Copy, Clone, Debug, Default)]
36-
pub struct FileTimes {}
38+
pub struct FileTimes {
39+
accessed: r_efi::efi::Time,
40+
modified: r_efi::efi::Time,
41+
}
3742

3843
#[derive(Clone, PartialEq, Eq, Debug)]
3944
// Bool indicates if file is readonly
@@ -60,15 +65,15 @@ impl FileAttr {
6065
}
6166

6267
pub fn modified(&self) -> io::Result<SystemTime> {
63-
unsupported()
68+
Ok(SystemTime::from_uefi(self.times.modified))
6469
}
6570

6671
pub fn accessed(&self) -> io::Result<SystemTime> {
67-
unsupported()
72+
Ok(SystemTime::from_uefi(self.times.accessed))
6873
}
6974

7075
pub fn created(&self) -> io::Result<SystemTime> {
71-
unsupported()
76+
Ok(SystemTime::from_uefi(self.created))
7277
}
7378
}
7479

@@ -92,8 +97,13 @@ impl FilePermissions {
9297
}
9398

9499
impl FileTimes {
95-
pub fn set_accessed(&mut self, _t: SystemTime) {}
96-
pub fn set_modified(&mut self, _t: SystemTime) {}
100+
pub fn set_accessed(&mut self, t: SystemTime) {
101+
self.accessed = t.to_uefi_loose(self.accessed.timezone, self.accessed.daylight);
102+
}
103+
104+
pub fn set_modified(&mut self, t: SystemTime) {
105+
self.modified = t.to_uefi_loose(self.modified.timezone, self.modified.daylight);
106+
}
97107
}
98108

99109
impl FileType {

library/std/src/sys/pal/uefi/tests.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ use crate::time::Duration;
88

99
const SECS_IN_MINUTE: u64 = 60;
1010

11+
const MAX_UEFI_TIME: Duration = from_uefi(r_efi::efi::Time {
12+
year: 9999,
13+
month: 12,
14+
day: 31,
15+
hour: 23,
16+
minute: 59,
17+
second: 59,
18+
nanosecond: 999_999_999,
19+
timezone: 1440,
20+
daylight: 0,
21+
pad1: 0,
22+
pad2: 0,
23+
});
24+
1125
#[test]
1226
fn align() {
1327
// UEFI ABI specifies that allocation alignment minimum is always 8. So this can be
@@ -44,7 +58,7 @@ fn systemtime_start() {
4458
};
4559
assert_eq!(from_uefi(&t), Duration::new(0, 0));
4660
assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap());
47-
assert!(to_uefi(&from_uefi(&t), 0, 0).is_none());
61+
assert!(to_uefi(&from_uefi(&t), 0, 0).is_err());
4862
}
4963

5064
#[test]
@@ -64,7 +78,7 @@ fn systemtime_utc_start() {
6478
};
6579
assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0));
6680
assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap());
67-
assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some());
81+
assert!(to_uefi(&from_uefi(&t), -1440, 0).is_err());
6882
}
6983

7084
#[test]
@@ -82,8 +96,44 @@ fn systemtime_end() {
8296
daylight: 0,
8397
pad2: 0,
8498
};
85-
assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some());
86-
assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none());
99+
assert!(to_uefi(&from_uefi(&t), 1440, 0).is_ok());
100+
assert!(to_uefi(&from_uefi(&t), 1439, 0).is_err());
101+
}
102+
103+
#[test]
104+
fn min_time() {
105+
let inp = Duration::from_secs(1440 * SECS_IN_MINUTE);
106+
let new_tz = to_uefi(&inp, 1440, 0).err().unwrap();
107+
assert_eq!(new_tz, 0);
108+
assert!(to_uefi(&inp, new_tz, 0).is_ok());
109+
110+
let inp = Duration::from_secs(1450 * SECS_IN_MINUTE);
111+
let new_tz = to_uefi(&inp, 1440, 0).err().unwrap();
112+
assert_eq!(new_tz, 10);
113+
assert!(to_uefi(&inp, new_tz, 0).is_ok());
114+
115+
let inp = Duration::from_secs(1450 * SECS_IN_MINUTE + 10);
116+
let new_tz = to_uefi(&inp, 1440, 0).err().unwrap();
117+
assert_eq!(new_tz, 9);
118+
assert!(to_uefi(&inp, new_tz, 0).is_ok());
119+
}
120+
121+
#[test]
122+
fn max_time() {
123+
let inp = MAX_UEFI_TIME;
124+
let new_tz = to_uefi(&inp, -1440, 0).err().unwrap();
125+
assert_eq!(new_tz, 1440);
126+
assert!(to_uefi(&inp, new_tz, 0).is_ok());
127+
128+
let inp = MAX_UEFI_TIME - Duration::from_secs(1440 * SECS_IN_MINUTE);
129+
let new_tz = to_uefi(&inp, -1440, 0).err().unwrap();
130+
assert_eq!(new_tz, 0);
131+
assert!(to_uefi(&inp, new_tz, 0).is_ok());
132+
133+
let inp = MAX_UEFI_TIME - Duration::from_secs(1440 * SECS_IN_MINUTE + 10);
134+
let new_tz = to_uefi(&inp, -1440, 0).err().unwrap();
135+
assert_eq!(new_tz, 0);
136+
assert!(to_uefi(&inp, new_tz, 0).is_ok());
87137
}
88138

89139
// UEFI IoSlice and IoSliceMut Tests

library/std/src/sys/pal/uefi/time.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::time::Duration;
22

3+
const SECS_IN_MINUTE: u64 = 60;
4+
35
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
46
pub struct Instant(Duration);
57

@@ -70,11 +72,23 @@ impl SystemTime {
7072
Self(system_time_internal::from_uefi(&t))
7173
}
7274

73-
#[expect(dead_code)]
74-
pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option<r_efi::efi::Time> {
75+
pub(crate) const fn to_uefi(
76+
self,
77+
timezone: i16,
78+
daylight: u8,
79+
) -> Result<r_efi::efi::Time, i16> {
7580
system_time_internal::to_uefi(&self.0, timezone, daylight)
7681
}
7782

83+
/// Create UEFI Time with the closes timezone (minute offset) that still allows the time to be
84+
/// represented.
85+
pub(crate) fn to_uefi_loose(self, timezone: i16, daylight: u8) -> r_efi::efi::Time {
86+
match self.to_uefi(timezone, daylight) {
87+
Ok(x) => x,
88+
Err(tz) => self.to_uefi(tz, daylight).unwrap(),
89+
}
90+
}
91+
7892
pub fn now() -> SystemTime {
7993
system_time_internal::now()
8094
.unwrap_or_else(|| panic!("time not implemented on this platform"))
@@ -104,7 +118,6 @@ pub(crate) mod system_time_internal {
104118
use crate::mem::MaybeUninit;
105119
use crate::ptr::NonNull;
106120

107-
const SECS_IN_MINUTE: u64 = 60;
108121
const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
109122
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
110123
const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE;
@@ -180,7 +193,10 @@ pub(crate) mod system_time_internal {
180193
///
181194
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
182195
/// epoch used in the original algorithm.
183-
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option<Time> {
196+
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Result<Time, i16> {
197+
const MIN_IN_HOUR: u64 = 60;
198+
const MIN_IN_DAY: u64 = MIN_IN_HOUR * 24;
199+
184200
// Check timzone validity
185201
assert!(timezone <= 1440 && timezone >= -1440);
186202

@@ -189,7 +205,11 @@ pub(crate) mod system_time_internal {
189205
dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();
190206

191207
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
192-
let Some(secs) = secs.checked_sub(TIMEZONE_DELTA) else { return None };
208+
let Some(secs) = secs.checked_sub(TIMEZONE_DELTA) else {
209+
let new_tz =
210+
(secs / SECS_IN_MINUTE - if secs % SECS_IN_MINUTE == 0 { 0 } else { 1 }) as i16;
211+
return Err(new_tz);
212+
};
193213

194214
let days = secs / SECS_IN_DAY;
195215
let remaining_secs = secs % SECS_IN_DAY;
@@ -212,9 +232,10 @@ pub(crate) mod system_time_internal {
212232
let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
213233
let second = (remaining_secs % SECS_IN_MINUTE) as u8;
214234

215-
// Check Bounds
216-
if y >= 1900 && y <= 9999 {
217-
Some(Time {
235+
// At this point, invalid time will be greater than MAX representable time. It cannot be less
236+
// than minimum time since we already take care of that case above.
237+
if y <= 9999 {
238+
Ok(Time {
218239
year: y as u16,
219240
month: m as u8,
220241
day: d as u8,
@@ -228,7 +249,17 @@ pub(crate) mod system_time_internal {
228249
pad2: 0,
229250
})
230251
} else {
231-
None
252+
assert!(y == 10000);
253+
assert!(m == 1);
254+
255+
let delta = ((d - 1) as u64 * MIN_IN_DAY
256+
+ hour as u64 * MIN_IN_HOUR
257+
+ minute as u64
258+
+ if second == 0 { 0 } else { 1 }) as i16;
259+
let new_tz = timezone + delta;
260+
261+
assert!(new_tz <= 1440 && new_tz >= -1440);
262+
Err(new_tz)
232263
}
233264
}
234265
}

0 commit comments

Comments
 (0)