1use crate::blockdevice::BlockIdx;
2use crate::fat::{FatType, OnDiskDirEntry};
3use crate::filesystem::{Attributes, ClusterId, Handle, LfnBuffer, ShortFileName, Timestamp};
4use crate::{Error, RawVolume, VolumeManager};
5
6use super::ToShortFileName;
7
8#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
10#[derive(Debug, PartialEq, Eq, Clone)]
11pub struct DirEntry {
12 pub name: ShortFileName,
14 pub mtime: Timestamp,
16 pub ctime: Timestamp,
18 pub attributes: Attributes,
20 pub cluster: ClusterId,
22 pub size: u32,
24 pub entry_block: BlockIdx,
26 pub entry_offset: u32,
28}
29
30#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
47#[derive(Debug, Copy, Clone, PartialEq, Eq)]
48pub struct RawDirectory(pub(crate) Handle);
49
50impl RawDirectory {
51 pub fn to_directory<
53 D,
54 T,
55 const MAX_DIRS: usize,
56 const MAX_FILES: usize,
57 const MAX_VOLUMES: usize,
58 >(
59 self,
60 volume_mgr: &VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>,
61 ) -> Directory<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
62 where
63 D: crate::BlockDevice,
64 T: crate::TimeSource,
65 {
66 Directory::new(self, volume_mgr)
67 }
68}
69
70pub struct Directory<
79 'a,
80 D,
81 T,
82 const MAX_DIRS: usize,
83 const MAX_FILES: usize,
84 const MAX_VOLUMES: usize,
85> where
86 D: crate::BlockDevice,
87 T: crate::TimeSource,
88{
89 raw_directory: RawDirectory,
90 volume_mgr: &'a VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>,
91}
92
93impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
94 Directory<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
95where
96 D: crate::BlockDevice,
97 T: crate::TimeSource,
98{
99 pub fn new(
101 raw_directory: RawDirectory,
102 volume_mgr: &'a VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>,
103 ) -> Directory<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> {
104 Directory {
105 raw_directory,
106 volume_mgr,
107 }
108 }
109
110 pub fn open_dir<N>(
114 &self,
115 name: N,
116 ) -> Result<Directory<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>, Error<D::Error>>
117 where
118 N: ToShortFileName,
119 {
120 let d = self.volume_mgr.open_dir(self.raw_directory, name)?;
121 Ok(d.to_directory(self.volume_mgr))
122 }
123
124 pub fn change_dir<N>(&mut self, name: N) -> Result<(), Error<D::Error>>
128 where
129 N: ToShortFileName,
130 {
131 let d = self.volume_mgr.open_dir(self.raw_directory, name)?;
132 self.volume_mgr.close_dir(self.raw_directory).unwrap();
133 self.raw_directory = d;
134 Ok(())
135 }
136
137 pub fn find_directory_entry<N>(&self, name: N) -> Result<DirEntry, Error<D::Error>>
139 where
140 N: ToShortFileName,
141 {
142 self.volume_mgr
143 .find_directory_entry(self.raw_directory, name)
144 }
145
146 pub fn iterate_dir<F>(&self, func: F) -> Result<(), Error<D::Error>>
158 where
159 F: FnMut(&DirEntry),
160 {
161 self.volume_mgr.iterate_dir(self.raw_directory, func)
162 }
163
164 pub fn iterate_dir_lfn<F>(
180 &self,
181 lfn_buffer: &mut LfnBuffer<'_>,
182 func: F,
183 ) -> Result<(), Error<D::Error>>
184 where
185 F: FnMut(&DirEntry, Option<&str>),
186 {
187 self.volume_mgr
188 .iterate_dir_lfn(self.raw_directory, lfn_buffer, func)
189 }
190
191 pub fn open_file_in_dir<N>(
193 &self,
194 name: N,
195 mode: crate::Mode,
196 ) -> Result<crate::File<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>, crate::Error<D::Error>>
197 where
198 N: super::ToShortFileName,
199 {
200 let f = self
201 .volume_mgr
202 .open_file_in_dir(self.raw_directory, name, mode)?;
203 Ok(f.to_file(self.volume_mgr))
204 }
205
206 pub fn delete_file_in_dir<N>(&self, name: N) -> Result<(), Error<D::Error>>
208 where
209 N: ToShortFileName,
210 {
211 self.volume_mgr.delete_file_in_dir(self.raw_directory, name)
212 }
213
214 pub fn make_dir_in_dir<N>(&self, name: N) -> Result<(), Error<D::Error>>
216 where
217 N: ToShortFileName,
218 {
219 self.volume_mgr.make_dir_in_dir(self.raw_directory, name)
220 }
221
222 pub fn to_raw_directory(self) -> RawDirectory {
224 let d = self.raw_directory;
225 core::mem::forget(self);
226 d
227 }
228
229 pub fn close(self) -> Result<(), Error<D::Error>> {
234 let result = self.volume_mgr.close_dir(self.raw_directory);
235 core::mem::forget(self);
236 result
237 }
238}
239
240impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> Drop
241 for Directory<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
242where
243 D: crate::BlockDevice,
244 T: crate::TimeSource,
245{
246 fn drop(&mut self) {
247 _ = self.volume_mgr.close_dir(self.raw_directory)
248 }
249}
250
251impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
252 core::fmt::Debug for Directory<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
253where
254 D: crate::BlockDevice,
255 T: crate::TimeSource,
256{
257 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258 write!(f, "Directory({})", self.raw_directory.0 .0)
259 }
260}
261
262#[cfg(feature = "defmt-log")]
263impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
264 defmt::Format for Directory<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
265where
266 D: crate::BlockDevice,
267 T: crate::TimeSource,
268{
269 fn format(&self, fmt: defmt::Formatter) {
270 defmt::write!(fmt, "Directory({})", self.raw_directory.0 .0)
271 }
272}
273
274#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
276#[derive(Debug, Clone)]
277pub(crate) struct DirectoryInfo {
278 pub(crate) raw_directory: RawDirectory,
280 pub(crate) raw_volume: RawVolume,
282 pub(crate) cluster: ClusterId,
284}
285
286impl DirEntry {
287 pub(crate) fn serialize(&self, fat_type: FatType) -> [u8; OnDiskDirEntry::LEN] {
288 let mut data = [0u8; OnDiskDirEntry::LEN];
289 data[0..11].copy_from_slice(&self.name.contents);
290 data[11] = self.attributes.0;
291 data[14..18].copy_from_slice(&self.ctime.serialize_to_fat()[..]);
294 let cluster_number = self.cluster.0;
296 let cluster_hi = if fat_type == FatType::Fat16 {
297 [0u8; 2]
298 } else {
299 (((cluster_number >> 16) & 0x0000_FFFF) as u16).to_le_bytes()
301 };
302 data[20..22].copy_from_slice(&cluster_hi[..]);
303 data[22..26].copy_from_slice(&self.mtime.serialize_to_fat()[..]);
304 let cluster_lo = ((cluster_number & 0x0000_FFFF) as u16).to_le_bytes();
306 data[26..28].copy_from_slice(&cluster_lo[..]);
307 data[28..32].copy_from_slice(&self.size.to_le_bytes()[..]);
308 data
309 }
310
311 pub(crate) fn new(
312 name: ShortFileName,
313 attributes: Attributes,
314 cluster: ClusterId,
315 ctime: Timestamp,
316 entry_block: BlockIdx,
317 entry_offset: u32,
318 ) -> Self {
319 Self {
320 name,
321 mtime: ctime,
322 ctime,
323 attributes,
324 cluster,
325 size: 0,
326 entry_block,
327 entry_offset,
328 }
329 }
330}
331
332