Skip to content

Commit 3b99d6b

Browse files
authored
Rollup merge of #149538 - Ayush1325:uefi-fs-time-fix, r=joboet
std: sys: fs: uefi: Make time in FileAttr optional At least on OVMF, some files copied over from linux file system seem to have invalid time (year = 1980 and everything else 0). Since Rust allows time to be optional, and we can return error, that seems to be the way to go for now. `@rustbot` label +O-UEFI
2 parents c67a779 + 1331c35 commit 3b99d6b

File tree

2 files changed

+50
-37
lines changed

2 files changed

+50
-37
lines changed

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

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ pub struct File(!);
1818
pub struct FileAttr {
1919
attr: u64,
2020
size: u64,
21-
accessed: SystemTime,
22-
modified: SystemTime,
23-
created: SystemTime,
21+
file_time: FileTimes,
22+
created: Option<SystemTime>,
2423
}
2524

2625
pub struct ReadDir(!);
@@ -66,24 +65,31 @@ impl FileAttr {
6665
}
6766

6867
pub fn modified(&self) -> io::Result<SystemTime> {
69-
Ok(self.modified)
68+
self.file_time
69+
.modified
70+
.ok_or(io::const_error!(io::ErrorKind::InvalidData, "modification time is not valid"))
7071
}
7172

7273
pub fn accessed(&self) -> io::Result<SystemTime> {
73-
Ok(self.accessed)
74+
self.file_time
75+
.accessed
76+
.ok_or(io::const_error!(io::ErrorKind::InvalidData, "last access time is not valid"))
7477
}
7578

7679
pub fn created(&self) -> io::Result<SystemTime> {
77-
Ok(self.created)
80+
self.created
81+
.ok_or(io::const_error!(io::ErrorKind::InvalidData, "creation time is not valid"))
7882
}
7983

8084
fn from_uefi(info: helpers::UefiBox<file::Info>) -> Self {
8185
unsafe {
8286
Self {
8387
attr: (*info.as_ptr()).attribute,
8488
size: (*info.as_ptr()).file_size,
85-
modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time),
86-
accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time),
89+
file_time: FileTimes {
90+
modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time),
91+
accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time),
92+
},
8793
created: uefi_fs::uefi_to_systemtime((*info.as_ptr()).create_time),
8894
}
8995
}
@@ -627,9 +633,9 @@ mod uefi_fs {
627633

628634
/// EDK2 FAT driver uses EFI_UNSPECIFIED_TIMEZONE to represent localtime. So for proper
629635
/// conversion to SystemTime, we use the current time to get the timezone in such cases.
630-
pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> SystemTime {
636+
pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option<SystemTime> {
631637
time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
632-
time::system_time_internal::now().unwrap().timezone
638+
time::system_time_internal::now().timezone
633639
} else {
634640
time.timezone
635641
};
@@ -639,7 +645,7 @@ mod uefi_fs {
639645
/// Convert to UEFI Time with the current timezone.
640646
#[expect(dead_code)]
641647
fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time {
642-
let now = time::system_time_internal::now().unwrap();
648+
let now = time::system_time_internal::now();
643649
time.to_uefi_loose(now.timezone, now.daylight)
644650
}
645651
}

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

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
2424
daylight: 0,
2525
pad1: 0,
2626
pad2: 0,
27-
});
27+
})
28+
.unwrap();
2829

2930
const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
3031
year: 9999,
@@ -38,7 +39,8 @@ const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
3839
daylight: 0,
3940
pad1: 0,
4041
pad2: 0,
41-
});
42+
})
43+
.unwrap();
4244

4345
impl Instant {
4446
pub fn now() -> Instant {
@@ -68,8 +70,11 @@ impl Instant {
6870
}
6971

7072
impl SystemTime {
71-
pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self {
72-
Self(system_time_internal::from_uefi(&t))
73+
pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option<Self> {
74+
match system_time_internal::from_uefi(&t) {
75+
Some(x) => Some(Self(x)),
76+
None => None,
77+
}
7378
}
7479

7580
pub(crate) const fn to_uefi(
@@ -96,9 +101,8 @@ impl SystemTime {
96101
}
97102

98103
pub fn now() -> SystemTime {
99-
system_time_internal::now()
100-
.map(Self::from_uefi)
101-
.unwrap_or_else(|| panic!("time not implemented on this platform"))
104+
Self::from_uefi(system_time_internal::now())
105+
.expect("time incorrectly implemented on this platform")
102106
}
103107

104108
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
@@ -129,38 +133,41 @@ pub(crate) mod system_time_internal {
129133
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
130134
const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64;
131135

132-
pub(crate) fn now() -> Option<Time> {
133-
let runtime_services: NonNull<RuntimeServices> = helpers::runtime_services()?;
136+
pub(crate) fn now() -> Time {
137+
let runtime_services: NonNull<RuntimeServices> =
138+
helpers::runtime_services().expect("Runtime services are not available");
134139
let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
135140
let r = unsafe {
136141
((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut())
137142
};
138143
if r.is_error() {
139-
return None;
144+
panic!("time not implemented on this platform");
140145
}
141146

142-
Some(unsafe { t.assume_init() })
147+
unsafe { t.assume_init() }
143148
}
144149

145150
/// This algorithm is a modified form of the one described in the post
146151
/// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
147152
///
148153
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
149154
/// epoch used in the original algorithm.
150-
pub(crate) const fn from_uefi(t: &Time) -> Duration {
151-
assert!(t.month <= 12 && t.month != 0);
152-
assert!(t.year >= 1900 && t.year <= 9999);
153-
assert!(t.day <= 31 && t.day != 0);
154-
155-
assert!(t.second < 60);
156-
assert!(t.minute < 60);
157-
assert!(t.hour < 24);
158-
assert!(t.nanosecond < 1_000_000_000);
159-
160-
assert!(
161-
(t.timezone <= 1440 && t.timezone >= -1440)
162-
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
163-
);
155+
pub(crate) const fn from_uefi(t: &Time) -> Option<Duration> {
156+
if !(t.month <= 12
157+
&& t.month != 0
158+
&& t.year >= 1900
159+
&& t.year <= 9999
160+
&& t.day <= 31
161+
&& t.day != 0
162+
&& t.second < 60
163+
&& t.minute <= 60
164+
&& t.hour < 24
165+
&& t.nanosecond < 1_000_000_000
166+
&& ((t.timezone <= 1440 && t.timezone >= -1440)
167+
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE))
168+
{
169+
return None;
170+
}
164171

165172
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
166173

@@ -188,7 +195,7 @@ pub(crate) mod system_time_internal {
188195
// Calculate the offset from 1/1/1900 at timezone -1440 min
189196
let epoch = localtime_epoch.checked_add_signed(normalized_timezone).unwrap();
190197

191-
Duration::new(epoch, t.nanosecond)
198+
Some(Duration::new(epoch, t.nanosecond))
192199
}
193200

194201
/// This algorithm is a modified version of the one described in the post:

0 commit comments

Comments
 (0)