1use chrono::offset::TimeZone;
6use chrono::Local;
7use fatfs::{DateTime, FatfsError};
8use std::io::{self, ErrorKind};
9use zx::Status;
10
11pub fn dos_to_unix_time(dos_time: DateTime) -> u64 {
13 let datetime = chrono::DateTime::<Local>::from(dos_time);
14 datetime.timestamp_nanos_opt().unwrap() as u64
15}
16
17pub fn unix_to_dos_time(timestamp: u64) -> DateTime {
19 DateTime::from(Local.timestamp_nanos(timestamp as i64))
20}
21
22pub fn fatfs_error_to_status(error: io::Error) -> Status {
23 match error.kind() {
24 ErrorKind::AddrInUse => Status::ADDRESS_IN_USE,
25 ErrorKind::AddrNotAvailable => Status::UNAVAILABLE,
26 ErrorKind::AlreadyExists => Status::ALREADY_EXISTS,
27 ErrorKind::BrokenPipe => Status::PEER_CLOSED,
28 ErrorKind::ConnectionAborted => Status::CONNECTION_ABORTED,
29 ErrorKind::ConnectionRefused => Status::CONNECTION_REFUSED,
30 ErrorKind::ConnectionReset => Status::CONNECTION_RESET,
31 ErrorKind::Interrupted => Status::INTERRUPTED_RETRY,
32 ErrorKind::InvalidData => Status::IO_INVALID,
33 ErrorKind::InvalidInput => Status::INVALID_ARGS,
34 ErrorKind::NotConnected => Status::NOT_CONNECTED,
35 ErrorKind::NotFound => Status::NOT_FOUND,
36 ErrorKind::PermissionDenied => Status::ACCESS_DENIED,
37 ErrorKind::TimedOut => Status::TIMED_OUT,
38 ErrorKind::UnexpectedEof => Status::BUFFER_TOO_SMALL,
39 ErrorKind::WouldBlock => Status::BAD_STATE,
40 ErrorKind::WriteZero => Status::NO_SPACE,
41 ErrorKind::Other => {
42 error
43 .into_inner()
44 .and_then(|b| b.downcast::<FatfsError>().ok())
45 .map(|b| {
46 match *b {
47 FatfsError::UnknownVersion => Status::NOT_SUPPORTED,
49 FatfsError::InvalidBootSectorSig => Status::NOT_SUPPORTED,
50 FatfsError::VolumeTooSmall => Status::NO_SPACE,
51 FatfsError::IsDirectory => Status::NOT_FILE,
53 FatfsError::NotDirectory => Status::NOT_DIR,
54 FatfsError::DirectoryNotEmpty => Status::NOT_EMPTY,
55 FatfsError::FileNameTooLong => Status::BAD_PATH,
56 FatfsError::FileNameEmpty => Status::BAD_PATH,
57 FatfsError::FileNameBadCharacter => Status::BAD_PATH,
58 FatfsError::TooManySectors => Status::OUT_OF_RANGE,
60 FatfsError::NoSpace => Status::NO_SPACE,
62 _ => Status::INVALID_ARGS,
66 }
67 })
68 .unwrap_or(Status::IO)
69 }
70 _ => Status::IO,
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use fatfs::{Date, Time};
78
79 fn dos_datetime(
80 year: u16,
81 month: u16,
82 day: u16,
83 hour: u16,
84 min: u16,
85 sec: u16,
86 millis: u16,
87 ) -> DateTime {
88 DateTime { date: Date { year, month, day }, time: Time { hour, min, sec, millis } }
89 }
90
91 const NS_PER_MS: u64 = 1_000_000;
92
93 fn ms_to_ns(ts: u64) -> u64 {
94 ts * NS_PER_MS
95 }
96
97 #[fuchsia::test]
98 fn test_dos_to_unix_time() {
99 let earliest_time = dos_datetime(1980, 1, 1, 0, 0, 0, 0);
100 assert_eq!(dos_to_unix_time(earliest_time), ms_to_ns(315532800000));
101
102 let latest_time = dos_datetime(2107, 12, 31, 23, 59, 59, 999);
103 assert_eq!(dos_to_unix_time(latest_time), ms_to_ns(4354819199999));
104
105 let time = dos_datetime(2038, 1, 19, 3, 14, 7, 0);
106 assert_eq!(dos_to_unix_time(time), ms_to_ns(2147483647000));
107 }
108
109 #[fuchsia::test]
110 fn test_unix_to_dos_time() {
111 let earliest_time = dos_datetime(1980, 1, 1, 0, 0, 0, 0);
112 assert_eq!(earliest_time, unix_to_dos_time(ms_to_ns(315532800000)));
113
114 let latest_time = dos_datetime(2107, 12, 31, 23, 59, 59, 999);
115 assert_eq!(latest_time, unix_to_dos_time(ms_to_ns(4354819199999)));
116
117 let time = dos_datetime(2038, 1, 19, 3, 14, 7, 0);
118 assert_eq!(time, unix_to_dos_time(ms_to_ns(2147483647000)));
119 }
120}