#[derive(Debug)]
pub struct Ext4DirEntryInfo<'a> {
pub inode: u32,
pub file_type: u8,
pub name: &'a [u8],
}
impl<'a> Ext4DirEntryInfo<'a> {
pub fn parse_from_bytes(data: &'a [u8]) -> Option<Self> {
if data.len() < 8 {
return None;
}
let inode = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
if inode == 0 {
return None;
}
let rec_len = u16::from_le_bytes([data[4], data[5]]);
let name_len = data[6] as usize;
let file_type = data[7];
if rec_len < 8 || name_len > 255 || data.len() < 8 + name_len {
return None;
}
let name = &data[8..8 + name_len];
Some(Ext4DirEntryInfo {
inode,
file_type,
name,
})
}
pub fn name_str(&self) -> Option<&str> {
core::str::from_utf8(self.name).ok()
}
pub fn is_dot(&self) -> bool {
self.name == b"."
}
pub fn is_dotdot(&self) -> bool {
self.name == b".."
}
}
pub struct DirEntryIterator<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> DirEntryIterator<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data, offset: 0 }
}
}
impl<'a> Iterator for DirEntryIterator<'a> {
type Item = (Ext4DirEntryInfo<'a>, u16);
fn next(&mut self) -> Option<Self::Item> {
while self.offset < self.data.len() {
let remaining = &self.data[self.offset..];
if remaining.len() < 8 {
return None;
}
let rec_len = u16::from_le_bytes([remaining[4], remaining[5]]);
if rec_len < 8 || rec_len as usize > remaining.len() {
return None;
}
let entry_data = &remaining[..rec_len as usize];
self.offset += rec_len as usize;
if let Some(entry_info) = Ext4DirEntryInfo::parse_from_bytes(entry_data) {
return Some((entry_info, rec_len));
}
}
None
}
}