embedded_fat/filesystem/
directory.rs

1use core::convert::TryFrom;
2
3use crate::blockdevice::BlockIdx;
4use crate::fat::{FatType, OnDiskDirEntry};
5use crate::filesystem::{Attributes, ClusterId, SearchId, ShortFileName, Timestamp};
6
7/// Represents a directory entry, which tells you about
8/// other files and directories.
9#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
10#[derive(Debug, PartialEq, Eq, Clone)]
11pub struct DirEntry {
12    /// The name of the file
13    pub name: ShortFileName,
14    /// When the file was last modified
15    pub mtime: Timestamp,
16    /// When the file was first created
17    pub ctime: Timestamp,
18    /// The file attributes (Read Only, Archive, etc)
19    pub attributes: Attributes,
20    /// The starting cluster of the file. The FAT tells us the following Clusters.
21    pub cluster: ClusterId,
22    /// The size of the file in bytes.
23    pub size: u32,
24    /// The disk block of this entry
25    pub entry_block: BlockIdx,
26    /// The offset on its block (in bytes)
27    pub entry_offset: u32,
28}
29
30/// Represents an open directory on disk.
31///
32/// Do NOT drop this object! It doesn't hold a reference to the Volume Manager
33/// it was created from and if you drop it, the VolumeManager will think you
34/// still have the directory open, and it won't let you open the directory
35/// again.
36///
37/// Instead you must pass it to [`crate::VolumeManager::close_dir`] to close it
38/// cleanly.
39///
40/// If you want your directories to close themselves on drop, create your own
41/// `Directory` type that wraps this one and also holds a `VolumeManager`
42/// reference. You'll then also need to put your `VolumeManager` in some kind of
43/// Mutex or RefCell, and deal with the fact you can't put them both in the same
44/// struct any more because one refers to the other. Basically, it's complicated
45/// and there's a reason we did it this way.
46#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
47#[derive(Debug, Copy, Clone, PartialEq, Eq)]
48pub struct Directory(pub(crate) SearchId);
49
50/// Holds information about an open file on disk
51#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
52#[derive(Debug, Clone)]
53pub(crate) struct DirectoryInfo {
54    /// Unique ID for this directory.
55    pub(crate) directory_id: Directory,
56    /// The starting point of the directory listing.
57    pub(crate) cluster: ClusterId,
58}
59
60impl DirEntry {
61    pub(crate) fn serialize(&self, fat_type: FatType) -> [u8; OnDiskDirEntry::LEN] {
62        let mut data = [0u8; OnDiskDirEntry::LEN];
63        data[0..11].copy_from_slice(&self.name.contents);
64        data[11] = self.attributes.0;
65        // 12: Reserved. Must be set to zero
66        // 13: CrtTimeTenth, not supported, set to zero
67        data[14..18].copy_from_slice(&self.ctime.serialize_to_fat()[..]);
68        // 0 + 18: LastAccDate, not supported, set to zero
69        let cluster_number = self.cluster.0;
70        let cluster_hi = if fat_type == FatType::Fat16 {
71            [0u8; 2]
72        } else {
73            // Safe due to the AND operation
74            u16::try_from((cluster_number >> 16) & 0x0000_FFFF)
75                .unwrap()
76                .to_le_bytes()
77        };
78        data[20..22].copy_from_slice(&cluster_hi[..]);
79        data[22..26].copy_from_slice(&self.mtime.serialize_to_fat()[..]);
80        // Safe due to the AND operation
81        let cluster_lo = u16::try_from(cluster_number & 0x0000_FFFF)
82            .unwrap()
83            .to_le_bytes();
84        data[26..28].copy_from_slice(&cluster_lo[..]);
85        data[28..32].copy_from_slice(&self.size.to_le_bytes()[..]);
86        data
87    }
88
89    pub(crate) fn new(
90        name: ShortFileName,
91        attributes: Attributes,
92        cluster: ClusterId,
93        ctime: Timestamp,
94        entry_block: BlockIdx,
95        entry_offset: u32,
96    ) -> Self {
97        Self {
98            name,
99            mtime: ctime,
100            ctime,
101            attributes,
102            cluster,
103            size: 0,
104            entry_block,
105            entry_offset,
106        }
107    }
108}