axfs_vfs/
structs.rs

1/// Filesystem attributes.
2///
3/// Currently not used.
4#[non_exhaustive]
5pub struct FileSystemInfo;
6
7/// Node (file/directory) attributes.
8#[allow(dead_code)]
9#[derive(Debug, Clone, Copy)]
10pub struct VfsNodeAttr {
11    /// File permission mode.
12    mode: VfsNodePerm,
13    /// File type.
14    ty: VfsNodeType,
15    /// Total size, in bytes.
16    size: u64,
17    /// Number of 512B blocks allocated.
18    blocks: u64,
19}
20
21bitflags::bitflags! {
22    /// Node (file/directory) permission mode.
23    #[derive(Debug, Clone, Copy)]
24    pub struct VfsNodePerm: u16 {
25        /// Owner has read permission.
26        const OWNER_READ = 0o400;
27        /// Owner has write permission.
28        const OWNER_WRITE = 0o200;
29        /// Owner has execute permission.
30        const OWNER_EXEC = 0o100;
31
32        /// Group has read permission.
33        const GROUP_READ = 0o40;
34        /// Group has write permission.
35        const GROUP_WRITE = 0o20;
36        /// Group has execute permission.
37        const GROUP_EXEC = 0o10;
38
39        /// Others have read permission.
40        const OTHER_READ = 0o4;
41        /// Others have write permission.
42        const OTHER_WRITE = 0o2;
43        /// Others have execute permission.
44        const OTHER_EXEC = 0o1;
45    }
46}
47
48/// Node (file/directory) type.
49#[repr(u8)]
50#[derive(Debug, Clone, Copy, Eq, PartialEq)]
51pub enum VfsNodeType {
52    /// FIFO (named pipe)
53    Fifo = 0o1,
54    /// Character device
55    CharDevice = 0o2,
56    /// Directory
57    Dir = 0o4,
58    /// Block device
59    BlockDevice = 0o6,
60    /// Regular file
61    File = 0o10,
62    /// Symbolic link
63    SymLink = 0o12,
64    /// Socket
65    Socket = 0o14,
66}
67
68/// Directory entry.
69pub struct VfsDirEntry {
70    d_type: VfsNodeType,
71    d_name: [u8; 63],
72}
73
74impl VfsNodePerm {
75    /// Returns the default permission for a file.
76    ///
77    /// The default permission is `0o666` (owner/group/others can read and write).
78    pub const fn default_file() -> Self {
79        Self::from_bits_truncate(0o666)
80    }
81
82    /// Returns the default permission for a directory.
83    ///
84    /// The default permission is `0o755` (owner can read, write and execute,
85    /// group/others can read and execute).
86    pub const fn default_dir() -> Self {
87        Self::from_bits_truncate(0o755)
88    }
89
90    /// Returns the underlying raw `st_mode` bits that contain the standard
91    /// Unix permissions for this file.
92    pub const fn mode(&self) -> u32 {
93        self.bits() as u32
94    }
95
96    /// Returns a 9-bytes string representation of the permission.
97    ///
98    /// For example, `0o755` is represented as `rwxr-xr-x`.
99    pub const fn rwx_buf(&self) -> [u8; 9] {
100        let mut perm = [b'-'; 9];
101        if self.contains(Self::OWNER_READ) {
102            perm[0] = b'r';
103        }
104        if self.contains(Self::OWNER_WRITE) {
105            perm[1] = b'w';
106        }
107        if self.contains(Self::OWNER_EXEC) {
108            perm[2] = b'x';
109        }
110        if self.contains(Self::GROUP_READ) {
111            perm[3] = b'r';
112        }
113        if self.contains(Self::GROUP_WRITE) {
114            perm[4] = b'w';
115        }
116        if self.contains(Self::GROUP_EXEC) {
117            perm[5] = b'x';
118        }
119        if self.contains(Self::OTHER_READ) {
120            perm[6] = b'r';
121        }
122        if self.contains(Self::OTHER_WRITE) {
123            perm[7] = b'w';
124        }
125        if self.contains(Self::OTHER_EXEC) {
126            perm[8] = b'x';
127        }
128        perm
129    }
130
131    /// Whether the owner has read permission.
132    pub const fn owner_readable(&self) -> bool {
133        self.contains(Self::OWNER_READ)
134    }
135
136    /// Whether the owner has write permission.
137    pub const fn owner_writable(&self) -> bool {
138        self.contains(Self::OWNER_WRITE)
139    }
140
141    /// Whether the owner has execute permission.
142    pub const fn owner_executable(&self) -> bool {
143        self.contains(Self::OWNER_EXEC)
144    }
145}
146
147impl VfsNodeType {
148    /// Tests whether this node type represents a regular file.
149    pub const fn is_file(self) -> bool {
150        matches!(self, Self::File)
151    }
152
153    /// Tests whether this node type represents a directory.
154    pub const fn is_dir(self) -> bool {
155        matches!(self, Self::Dir)
156    }
157
158    /// Tests whether this node type represents a symbolic link.
159    pub const fn is_symlink(self) -> bool {
160        matches!(self, Self::SymLink)
161    }
162
163    /// Returns `true` if this node type is a block device.
164    pub const fn is_block_device(self) -> bool {
165        matches!(self, Self::BlockDevice)
166    }
167
168    /// Returns `true` if this node type is a char device.
169    pub const fn is_char_device(self) -> bool {
170        matches!(self, Self::CharDevice)
171    }
172
173    /// Returns `true` if this node type is a fifo.
174    pub const fn is_fifo(self) -> bool {
175        matches!(self, Self::Fifo)
176    }
177
178    /// Returns `true` if this node type is a socket.
179    pub const fn is_socket(self) -> bool {
180        matches!(self, Self::Socket)
181    }
182
183    /// Returns a character representation of the node type.
184    ///
185    /// For example, `d` for directory, `-` for regular file, etc.
186    pub const fn as_char(self) -> char {
187        match self {
188            Self::Fifo => 'p',
189            Self::CharDevice => 'c',
190            Self::Dir => 'd',
191            Self::BlockDevice => 'b',
192            Self::File => '-',
193            Self::SymLink => 'l',
194            Self::Socket => 's',
195        }
196    }
197}
198
199impl VfsNodeAttr {
200    /// Creates a new `VfsNodeAttr` with the given permission mode, type, size
201    /// and number of blocks.
202    pub const fn new(mode: VfsNodePerm, ty: VfsNodeType, size: u64, blocks: u64) -> Self {
203        Self {
204            mode,
205            ty,
206            size,
207            blocks,
208        }
209    }
210
211    /// Creates a new `VfsNodeAttr` for a file, with the default file permission.
212    pub const fn new_file(size: u64, blocks: u64) -> Self {
213        Self {
214            mode: VfsNodePerm::default_file(),
215            ty: VfsNodeType::File,
216            size,
217            blocks,
218        }
219    }
220
221    /// Creates a new `VfsNodeAttr` for a directory, with the default directory
222    /// permission.
223    pub const fn new_dir(size: u64, blocks: u64) -> Self {
224        Self {
225            mode: VfsNodePerm::default_dir(),
226            ty: VfsNodeType::Dir,
227            size,
228            blocks,
229        }
230    }
231
232    /// Returns the size of the node.
233    pub const fn size(&self) -> u64 {
234        self.size
235    }
236
237    /// Returns the number of blocks the node occupies on the disk.
238    pub const fn blocks(&self) -> u64 {
239        self.blocks
240    }
241
242    /// Returns the permission of the node.
243    pub const fn perm(&self) -> VfsNodePerm {
244        self.mode
245    }
246
247    /// Sets the permission of the node.
248    pub fn set_perm(&mut self, perm: VfsNodePerm) {
249        self.mode = perm
250    }
251
252    /// Returns the type of the node.
253    pub const fn file_type(&self) -> VfsNodeType {
254        self.ty
255    }
256
257    /// Whether the node is a file.
258    pub const fn is_file(&self) -> bool {
259        self.ty.is_file()
260    }
261
262    /// Whether the node is a directory.
263    pub const fn is_dir(&self) -> bool {
264        self.ty.is_dir()
265    }
266}
267
268impl VfsDirEntry {
269    /// Creates an empty `VfsDirEntry`.
270    pub const fn default() -> Self {
271        Self {
272            d_type: VfsNodeType::File,
273            d_name: [0; 63],
274        }
275    }
276
277    /// Creates a new `VfsDirEntry` with the given name and type.
278    pub fn new(name: &str, ty: VfsNodeType) -> Self {
279        let mut d_name = [0; 63];
280        if name.len() > d_name.len() {
281            log::warn!(
282                "directory entry name too long: {} > {}",
283                name.len(),
284                d_name.len()
285            );
286        }
287        d_name[..name.len()].copy_from_slice(name.as_bytes());
288        Self { d_type: ty, d_name }
289    }
290
291    /// Returns the type of the entry.
292    pub fn entry_type(&self) -> VfsNodeType {
293        self.d_type
294    }
295
296    /// Converts the name of the entry to a byte slice.
297    pub fn name_as_bytes(&self) -> &[u8] {
298        let len = self
299            .d_name
300            .iter()
301            .position(|&c| c == 0)
302            .unwrap_or(self.d_name.len());
303        &self.d_name[..len]
304    }
305}