1use crate::{
4 fat::{FatType, LfnEntry},
5 Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp,
6};
7use byteorder::{ByteOrder, LittleEndian};
8
9pub struct OnDiskDirEntry<'a> {
11 data: &'a [u8],
12}
13
14impl<'a> core::fmt::Debug for OnDiskDirEntry<'a> {
15 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
16 write!(f, "OnDiskDirEntry<")?;
17 write!(f, "raw_attr = {}", self.raw_attr())?;
18 write!(f, ", create_time = {}", self.create_time())?;
19 write!(f, ", create_date = {}", self.create_date())?;
20 write!(f, ", last_access_data = {}", self.last_access_data())?;
21 write!(f, ", first_cluster_hi = {}", self.first_cluster_hi())?;
22 write!(f, ", write_time = {}", self.write_time())?;
23 write!(f, ", write_date = {}", self.write_date())?;
24 write!(f, ", first_cluster_lo = {}", self.first_cluster_lo())?;
25 write!(f, ", file_size = {}", self.file_size())?;
26 write!(f, ", is_end = {}", self.is_end())?;
27 write!(f, ", is_valid = {}", self.is_valid())?;
28 write!(f, ", is_lfn = {}", self.is_lfn())?;
29 write!(
30 f,
31 ", first_cluster_fat32 = {:?}",
32 self.first_cluster_fat32()
33 )?;
34 write!(
35 f,
36 ", first_cluster_fat16 = {:?}",
37 self.first_cluster_fat16()
38 )?;
39 write!(f, ">")?;
40 Ok(())
41 }
42}
43
44impl<'a> OnDiskDirEntry<'a> {
47 pub(crate) const LEN: usize = 32;
48 pub(crate) const LEN_U32: u32 = 32;
49
50 define_field!(raw_attr, u8, 11);
51 define_field!(create_time, u16, 14);
52 define_field!(create_date, u16, 16);
53 define_field!(last_access_data, u16, 18);
54 define_field!(first_cluster_hi, u16, 20);
55 define_field!(write_time, u16, 22);
56 define_field!(write_date, u16, 24);
57 define_field!(first_cluster_lo, u16, 26);
58 define_field!(file_size, u32, 28);
59
60 pub fn new(data: &[u8]) -> OnDiskDirEntry {
63 OnDiskDirEntry { data }
64 }
65
66 pub fn is_end(&self) -> bool {
68 self.data[0] == 0x00
69 }
70
71 pub fn is_valid(&self) -> bool {
73 !self.is_end() && (self.data[0] != 0xE5)
74 }
75
76 pub fn is_lfn(&self) -> bool {
78 let attributes = Attributes::create_from_fat(self.raw_attr());
79 attributes.is_lfn()
80 }
81
82 pub fn lfn_contents(&self) -> Option<LfnEntry> {
84 if self.is_lfn() {
85 let mut buffer = [' '; 13];
86 let is_start = (self.data[0] & 0x40) != 0;
87 let sequence = self.data[0] & 0x1F;
88 let checksum = self.data[13];
89 buffer[0] =
91 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[1..=2]))).unwrap();
92 buffer[1] =
93 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[3..=4]))).unwrap();
94 buffer[2] =
95 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[5..=6]))).unwrap();
96 buffer[3] =
97 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[7..=8]))).unwrap();
98 buffer[4] = core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[9..=10])))
99 .unwrap();
100 buffer[5] =
101 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[14..=15])))
102 .unwrap();
103 buffer[6] =
104 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[16..=17])))
105 .unwrap();
106 buffer[7] =
107 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[18..=19])))
108 .unwrap();
109 buffer[8] =
110 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[20..=21])))
111 .unwrap();
112 buffer[9] =
113 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[22..=23])))
114 .unwrap();
115 buffer[10] =
116 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[24..=25])))
117 .unwrap();
118 buffer[11] =
119 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[28..=29])))
120 .unwrap();
121 buffer[12] =
122 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[30..=31])))
123 .unwrap();
124 Some(LfnEntry {
125 is_start,
126 sequence,
127 checksum,
128 buffer,
129 })
130 } else {
131 None
132 }
133 }
134
135 pub fn matches(&self, sfn: &ShortFileName) -> bool {
137 self.data[0..11] == sfn.contents
138 }
139
140 pub fn first_cluster_fat32(&self) -> ClusterId {
142 let cluster_no =
143 (u32::from(self.first_cluster_hi()) << 16) | u32::from(self.first_cluster_lo());
144 ClusterId(cluster_no)
145 }
146
147 fn first_cluster_fat16(&self) -> ClusterId {
149 let cluster_no = u32::from(self.first_cluster_lo());
150 ClusterId(cluster_no)
151 }
152
153 pub fn get_entry(
155 &self,
156 fat_type: FatType,
157 entry_block: BlockIdx,
158 entry_offset: u32,
159 ) -> DirEntry {
160 let mut result = DirEntry {
161 name: ShortFileName {
162 contents: [0u8; 11],
163 },
164 mtime: Timestamp::from_fat(self.write_date(), self.write_time()),
165 ctime: Timestamp::from_fat(self.create_date(), self.create_time()),
166 attributes: Attributes::create_from_fat(self.raw_attr()),
167 cluster: if fat_type == FatType::Fat32 {
168 self.first_cluster_fat32()
169 } else {
170 self.first_cluster_fat16()
171 },
172 size: self.file_size(),
173 entry_block,
174 entry_offset,
175 };
176 result.name.contents.copy_from_slice(&self.data[0..11]);
177 result
178 }
179}