1use alloc::ffi::CString;
6use alloc::vec::Vec;
7use core::fmt::Debug;
8
9use deku::{DekuError, DekuRead, DekuWrite};
10
11use super::Ext2;
12use super::error::Ext2Error;
13use crate::arch::u32_to_usize;
14use crate::dev::Device;
15use crate::dev::address::Address;
16use crate::error::Error;
17use crate::fs::file::Type;
18
19#[derive(Debug, Clone, DekuRead, DekuWrite)]
21#[deku(endian = "little")]
22pub struct Entry {
23 pub inode: u32,
25
26 pub rec_len: u16,
28
29 pub name_len: u8,
31
32 pub file_type: u8,
35
36 #[deku(
38 bytes_read = "*name_len",
39 map = "|bytes: Vec<u8>| -> Result<_, DekuError> { CString::new(bytes).map_err(|_| DekuError::Io(deku::no_std_io::ErrorKind::InvalidData)) }"
40 )]
41 pub name: CString,
42}
43
44#[repr(u8)]
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum FileType {
50 Unknown = 0,
52
53 RegFile = 1,
55
56 Dir = 2,
58
59 ChrDev = 3,
61
62 BlkDev = 4,
64
65 Fifo = 5,
67
68 Sock = 6,
70
71 Symlink = 7,
73}
74
75impl From<u8> for FileType {
76 fn from(value: u8) -> Self {
77 match value {
78 1 => Self::RegFile,
79 2 => Self::Dir,
80 3 => Self::ChrDev,
81 4 => Self::BlkDev,
82 5 => Self::Fifo,
83 6 => Self::Sock,
84 7 => Self::Symlink,
85 _ => Self::Unknown,
86 }
87 }
88}
89
90impl From<FileType> for u8 {
91 fn from(value: FileType) -> Self {
92 value as Self
93 }
94}
95
96impl From<Type> for FileType {
97 fn from(value: Type) -> Self {
98 match value {
99 Type::Regular => Self::RegFile,
100 Type::Directory => Self::Dir,
101 Type::SymbolicLink => Self::Symlink,
102 Type::Fifo => Self::Fifo,
103 Type::CharacterDevice => Self::ChrDev,
104 Type::BlockDevice => Self::BlkDev,
105 Type::Socket => Self::Sock,
106 }
107 }
108}
109
110impl TryFrom<FileType> for Type {
111 type Error = Ext2Error;
112
113 fn try_from(value: FileType) -> Result<Self, Self::Error> {
114 match value {
115 FileType::Unknown => Err(Ext2Error::UnknownEntryFileType),
116 FileType::RegFile => Ok(Self::Regular),
117 FileType::Dir => Ok(Self::Directory),
118 FileType::ChrDev => Ok(Self::CharacterDevice),
119 FileType::BlkDev => Ok(Self::BlockDevice),
120 FileType::Fifo => Ok(Self::Fifo),
121 FileType::Sock => Ok(Self::Socket),
122 FileType::Symlink => Ok(Self::SymbolicLink),
123 }
124 }
125}
126
127impl Entry {
128 pub fn parse<Dev: Device>(fs: &Ext2<Dev>, starting_addr: Address) -> Result<Self, Error<Ext2Error>> {
136 let mut device = fs.device.lock();
137 device
138 .read_from_bytes(starting_addr, u32_to_usize(fs.superblock().block_size()))
139 .map_err(Into::into)
140 }
141
142 #[must_use]
149 pub fn minimal_size(&self) -> u16 {
150 let minimal_size = u16::try_from(8 + self.name.to_bytes_with_nul().len()).expect("Ill-formed directory entry");
151 minimal_size + (4 - ((minimal_size - 1) % 4 + 1))
152 }
153
154 #[must_use]
161 pub fn free_space(&self) -> u16 {
162 self.rec_len - u16::try_from(8 + self.name.to_bytes_with_nul().len()).expect("Ill-formed directory entry")
163 }
164
165 #[must_use]
167 pub fn as_bytes(&self) -> Vec<u8> {
168 let mut bytes = Vec::new();
169
170 bytes.append(&mut self.inode.to_le_bytes().to_vec());
171 bytes.append(&mut self.rec_len.to_le_bytes().to_vec());
172 bytes.push(self.name_len);
173 bytes.push(self.file_type);
174 bytes.append(&mut self.name.to_bytes_with_nul().to_vec());
175
176 bytes
177 }
178}