affs_read/
types.rs

1//! Core types for AFFS.
2
3/// Block device trait for reading blocks from storage.
4///
5/// Implement this trait for your storage medium (file, memory, hardware, etc.).
6pub trait BlockDevice {
7    /// Read a single 512-byte block.
8    ///
9    /// # Arguments
10    /// * `block` - Block number to read
11    /// * `buf` - Buffer to read into (must be exactly 512 bytes)
12    ///
13    /// # Returns
14    /// `Ok(())` on success, `Err(())` on failure.
15    #[allow(clippy::result_unit_err)]
16    fn read_block(&self, block: u32, buf: &mut [u8; 512]) -> Result<(), ()>;
17}
18
19/// Sector device trait for reading 512-byte sectors.
20///
21/// This is used for variable block size support, where the filesystem
22/// block size may be larger than 512 bytes. The reader will read
23/// multiple sectors to assemble a full block.
24pub trait SectorDevice {
25    /// Read a single 512-byte sector.
26    ///
27    /// # Arguments
28    /// * `sector` - Sector number to read
29    /// * `buf` - Buffer to read into (must be exactly 512 bytes)
30    ///
31    /// # Returns
32    /// `Ok(())` on success, `Err(())` on failure.
33    #[allow(clippy::result_unit_err)]
34    fn read_sector(&self, sector: u64, buf: &mut [u8; 512]) -> Result<(), ()>;
35}
36
37/// Blanket implementation: any BlockDevice is also a SectorDevice.
38impl<T: BlockDevice> SectorDevice for T {
39    fn read_sector(&self, sector: u64, buf: &mut [u8; 512]) -> Result<(), ()> {
40        self.read_block(sector as u32, buf)
41    }
42}
43
44/// Filesystem type.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum FsType {
47    /// Original File System.
48    Ofs,
49    /// Fast File System.
50    Ffs,
51}
52
53impl FsType {
54    /// Returns the data payload size per block.
55    #[inline]
56    pub const fn data_block_size(self) -> usize {
57        match self {
58            Self::Ofs => crate::OFS_DATA_SIZE,
59            Self::Ffs => crate::FFS_DATA_SIZE,
60        }
61    }
62}
63
64/// Entry type in the filesystem.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum EntryType {
67    /// Root directory.
68    Root,
69    /// Directory.
70    Dir,
71    /// File.
72    File,
73    /// Hard link to file.
74    HardLinkFile,
75    /// Hard link to directory.
76    HardLinkDir,
77    /// Soft link.
78    SoftLink,
79}
80
81impl EntryType {
82    /// Create from secondary type value.
83    pub const fn from_sec_type(sec_type: i32) -> Option<Self> {
84        match sec_type {
85            crate::ST_ROOT => Some(Self::Root),
86            crate::ST_DIR => Some(Self::Dir),
87            crate::ST_FILE => Some(Self::File),
88            crate::ST_LFILE => Some(Self::HardLinkFile),
89            crate::ST_LDIR => Some(Self::HardLinkDir),
90            crate::ST_LSOFT => Some(Self::SoftLink),
91            _ => None,
92        }
93    }
94
95    /// Returns true if this is a directory type.
96    #[inline]
97    pub const fn is_dir(self) -> bool {
98        matches!(self, Self::Root | Self::Dir | Self::HardLinkDir)
99    }
100
101    /// Returns true if this is a file type.
102    #[inline]
103    pub const fn is_file(self) -> bool {
104        matches!(self, Self::File | Self::HardLinkFile)
105    }
106}
107
108/// Filesystem flags.
109#[derive(Debug, Clone, Copy, Default)]
110pub struct FsFlags {
111    /// International mode enabled.
112    pub intl: bool,
113    /// Directory cache enabled.
114    pub dircache: bool,
115}
116
117impl FsFlags {
118    /// Create flags from DOS type byte.
119    #[inline]
120    pub const fn from_dos_type(dos_type: u8) -> Self {
121        Self {
122            intl: (dos_type & crate::DOSFS_INTL) != 0,
123            dircache: (dos_type & crate::DOSFS_DIRCACHE) != 0,
124        }
125    }
126}
127
128/// Access permissions.
129#[derive(Debug, Clone, Copy, Default)]
130pub struct Access(pub u32);
131
132impl Access {
133    /// Create from raw access value.
134    #[inline]
135    pub const fn new(raw: u32) -> Self {
136        Self(raw)
137    }
138
139    /// Check if delete is protected (inverted in AFFS).
140    #[inline]
141    pub const fn is_delete_protected(self) -> bool {
142        (self.0 & crate::ACC_DELETE) != 0
143    }
144
145    /// Check if execute is protected.
146    #[inline]
147    pub const fn is_execute_protected(self) -> bool {
148        (self.0 & crate::ACC_EXECUTE) != 0
149    }
150
151    /// Check if write is protected.
152    #[inline]
153    pub const fn is_write_protected(self) -> bool {
154        (self.0 & crate::ACC_WRITE) != 0
155    }
156
157    /// Check if read is protected.
158    #[inline]
159    pub const fn is_read_protected(self) -> bool {
160        (self.0 & crate::ACC_READ) != 0
161    }
162
163    /// Check if archived flag is set.
164    #[inline]
165    pub const fn is_archived(self) -> bool {
166        (self.0 & crate::ACC_ARCHIVE) != 0
167    }
168
169    /// Check if pure (re-entrant) flag is set.
170    #[inline]
171    pub const fn is_pure(self) -> bool {
172        (self.0 & crate::ACC_PURE) != 0
173    }
174
175    /// Check if script flag is set.
176    #[inline]
177    pub const fn is_script(self) -> bool {
178        (self.0 & crate::ACC_SCRIPT) != 0
179    }
180
181    /// Check if hold flag is set.
182    #[inline]
183    pub const fn is_hold(self) -> bool {
184        (self.0 & crate::ACC_HOLD) != 0
185    }
186}