1use crate::{fat::FatType, Attributes, BlockIdx, ClusterId, DirEntry, ShortFileName, Timestamp};
4use byteorder::{ByteOrder, LittleEndian};
5
6pub 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> {
45 pub(crate) const LEN: usize = 32;
46 pub(crate) const LEN_U32: u32 = 32;
47
48 define_field!(raw_attr, u8, 11);
49 define_field!(create_time, u16, 14);
50 define_field!(create_date, u16, 16);
51 define_field!(last_access_data, u16, 18);
52 define_field!(first_cluster_hi, u16, 20);
53 define_field!(write_time, u16, 22);
54 define_field!(write_date, u16, 24);
55 define_field!(first_cluster_lo, u16, 26);
56 define_field!(file_size, u32, 28);
57
58 pub fn new(data: &[u8]) -> OnDiskDirEntry {
61 OnDiskDirEntry { data }
62 }
63
64 pub fn is_end(&self) -> bool {
66 self.data[0] == 0x00
67 }
68
69 pub fn is_valid(&self) -> bool {
71 !self.is_end() && (self.data[0] != 0xE5)
72 }
73
74 pub fn is_lfn(&self) -> bool {
76 let attributes = Attributes::create_from_fat(self.raw_attr());
77 attributes.is_lfn()
78 }
79
80 pub fn lfn_contents(&self) -> Option<(bool, u8, u8, [u16; 13])> {
82 if self.is_lfn() {
83 let is_start = (self.data[0] & 0x40) != 0;
84 let sequence = self.data[0] & 0x1F;
85 let csum = self.data[13];
86 let buffer = [
87 LittleEndian::read_u16(&self.data[1..=2]),
88 LittleEndian::read_u16(&self.data[3..=4]),
89 LittleEndian::read_u16(&self.data[5..=6]),
90 LittleEndian::read_u16(&self.data[7..=8]),
91 LittleEndian::read_u16(&self.data[9..=10]),
92 LittleEndian::read_u16(&self.data[14..=15]),
93 LittleEndian::read_u16(&self.data[16..=17]),
94 LittleEndian::read_u16(&self.data[18..=19]),
95 LittleEndian::read_u16(&self.data[20..=21]),
96 LittleEndian::read_u16(&self.data[22..=23]),
97 LittleEndian::read_u16(&self.data[24..=25]),
98 LittleEndian::read_u16(&self.data[28..=29]),
99 LittleEndian::read_u16(&self.data[30..=31]),
100 ];
101 Some((is_start, sequence, csum, buffer))
102 } else {
103 None
104 }
105 }
106
107 pub fn matches(&self, sfn: &ShortFileName) -> bool {
109 self.data[0..11] == sfn.contents
110 }
111
112 pub fn first_cluster_fat32(&self) -> ClusterId {
114 let cluster_no =
115 (u32::from(self.first_cluster_hi()) << 16) | u32::from(self.first_cluster_lo());
116 ClusterId(cluster_no)
117 }
118
119 fn first_cluster_fat16(&self) -> ClusterId {
121 let cluster_no = u32::from(self.first_cluster_lo());
122 ClusterId(cluster_no)
123 }
124
125 pub fn get_entry(
127 &self,
128 fat_type: FatType,
129 entry_block: BlockIdx,
130 entry_offset: u32,
131 ) -> DirEntry {
132 let attributes = Attributes::create_from_fat(self.raw_attr());
133 let mut result = DirEntry {
134 name: ShortFileName {
135 contents: [0u8; 11],
136 },
137 mtime: Timestamp::from_fat(self.write_date(), self.write_time()),
138 ctime: Timestamp::from_fat(self.create_date(), self.create_time()),
139 attributes,
140 cluster: {
141 let cluster = if fat_type == FatType::Fat32 {
142 self.first_cluster_fat32()
143 } else {
144 self.first_cluster_fat16()
145 };
146 if cluster == ClusterId::EMPTY && attributes.is_directory() {
147 ClusterId::ROOT_DIR
149 } else {
150 cluster
151 }
152 },
153 size: self.file_size(),
154 entry_block,
155 entry_offset,
156 };
157 result.name.contents.copy_from_slice(&self.data[0..11]);
158 result
159 }
160}
161
162