use std::io::{Error, ErrorKind, Read};
use byteorder::{LittleEndian, ReadBytesExt};
use super::constants::{DOTDOT_DIR_NAME, DOT_DIR_NAME};
const EXT4_NAME_LEN: usize = 255;
#[derive(Debug)]
pub struct DirEntry {
inode: u32,
rec_len: u16,
name_len: u16,
name: Vec<u8>,
}
impl DirEntry {
}
#[derive(Debug)]
pub struct DirEntry2 {
inode: u32,
rec_len: u16,
name_len: u8,
file_type: u8,
name: Vec<u8>,
}
impl DirEntry2 {
pub fn get_name(&self) -> String {
String::from_utf8_lossy(&self.name).to_string()
}
}
#[derive(Debug)]
pub struct DirEntryTail {
reserved_zero1: u32,
pub(crate) rec_len: u16,
reserved_zero2: u8,
reserved_ft: u8,
checksum: u32,
}
#[derive(Debug)]
pub enum DirEntryEnum {
DirEntry(DirEntry),
DirEntry2(DirEntry2),
DirEntryTail(DirEntryTail),
}
impl DirEntryEnum {
pub fn get_rec_len(&self) -> u16 {
match self {
DirEntryEnum::DirEntry(e) => e.rec_len,
DirEntryEnum::DirEntry2(e) => e.rec_len,
DirEntryEnum::DirEntryTail(e) => e.rec_len,
}
}
pub fn get_ino(&self) -> Option<u32> {
match self {
DirEntryEnum::DirEntry(e) => Some(e.inode),
DirEntryEnum::DirEntry2(e) => Some(e.inode),
DirEntryEnum::DirEntryTail(_) => None,
}
}
pub fn get_name_str(&self) -> String {
let name = match self {
DirEntryEnum::DirEntry(e) => e.name.clone(),
DirEntryEnum::DirEntry2(e) => e.name.clone(),
DirEntryEnum::DirEntryTail(_) => vec![],
};
String::from_utf8_lossy(&name).to_string()
}
pub fn is_dot(&self) -> bool {
match self {
DirEntryEnum::DirEntry(e) => e.name == DOT_DIR_NAME,
DirEntryEnum::DirEntry2(e) => e.name == DOT_DIR_NAME,
DirEntryEnum::DirEntryTail(_) => false,
}
}
pub fn is_dotdot(&self) -> bool {
match self {
DirEntryEnum::DirEntry(e) => e.name == DOTDOT_DIR_NAME,
DirEntryEnum::DirEntry2(e) => e.name == DOTDOT_DIR_NAME,
DirEntryEnum::DirEntryTail(_) => false,
}
}
pub fn from_reader(
mut reader: impl Read,
feature_incompat_filetype: bool,
) -> Result<Self, std::io::Error> {
let inode = reader.read_u32::<LittleEndian>()?;
let rec_len = reader.read_u16::<LittleEndian>()?;
if inode == 0 && rec_len == 12 {
let reserved_zero2 = reader.read_u8()?;
let reserved_ft = reader.read_u8()?;
if reserved_zero2 != 0 || reserved_ft != 0xDE {
return Err(Error::new(
ErrorKind::Other,
format!(
"Invalid dir entry tail: reserved_zero2={} reserved_ft={}",
reserved_zero2, reserved_ft
),
));
}
let checksum = reader.read_u32::<LittleEndian>()?;
return Ok(Self::DirEntryTail(DirEntryTail {
reserved_zero1: inode,
rec_len,
reserved_zero2,
reserved_ft,
checksum,
}));
}
let (entry, name_len) = if feature_incompat_filetype {
let name_len = reader.read_u8()?;
let file_type = reader.read_u8()?;
let mut name = vec![0; name_len as usize];
reader.read_exact(&mut name)?;
(
Self::DirEntry2(DirEntry2 {
inode,
rec_len,
name_len,
file_type,
name,
}),
name_len as u16,
)
} else {
let name_len = reader.read_u16::<LittleEndian>()?;
let mut name = vec![0; name_len as usize];
reader.read_exact(&mut name)?;
(
Self::DirEntry(DirEntry {
inode,
rec_len,
name_len,
name,
}),
name_len,
)
};
let real_len = name_len as u16 + 8;
let align = rec_len - real_len;
let mut discard = vec![0; align as usize];
reader.read_exact(&mut discard)?;
Ok(entry)
}
}
pub struct DxRoot {}