use crate::error::{check_errno_with_path, Result};
use crate::fs::Ext4Fs;
use crate::types::FileType;
use ext4_lwext4_sys::{ext4_dir, ext4_dir_close, ext4_dir_entry_next, ext4_dir_entry_rewind, ext4_dir_open};
pub struct Dir<'a> {
#[allow(dead_code)]
fs: &'a Ext4Fs,
inner: ext4_dir,
}
impl<'a> Dir<'a> {
pub(crate) fn open(fs: &'a Ext4Fs, path: &str) -> Result<Self> {
let full_path = fs.make_path(path)?;
let mut inner = ext4_dir::default();
let ret = unsafe { ext4_dir_open(&mut inner, full_path.as_ptr()) };
check_errno_with_path(ret, path)?;
Ok(Self { fs, inner })
}
pub fn next_entry(&mut self) -> Option<Result<DirEntry>> {
let entry_ptr = unsafe { ext4_dir_entry_next(&mut self.inner) };
if entry_ptr.is_null() {
return None;
}
let entry = unsafe { &*entry_ptr };
let name_len = entry.name_length as usize;
let name_bytes = &entry.name[..name_len];
let name = match String::from_utf8(name_bytes.to_vec()) {
Ok(s) => s,
Err(_) => {
String::from_utf8_lossy(name_bytes).into_owned()
}
};
Some(Ok(DirEntry {
name,
inode: entry.inode as u64,
file_type: FileType::from_raw(entry.inode_type),
}))
}
pub fn rewind(&mut self) {
unsafe {
ext4_dir_entry_rewind(&mut self.inner);
}
}
}
impl Drop for Dir<'_> {
fn drop(&mut self) {
unsafe {
ext4_dir_close(&mut self.inner);
}
}
}
impl<'a> Iterator for Dir<'a> {
type Item = Result<DirEntry>;
fn next(&mut self) -> Option<Self::Item> {
self.next_entry()
}
}
#[derive(Debug, Clone)]
pub struct DirEntry {
pub name: String,
pub inode: u64,
pub file_type: FileType,
}
impl DirEntry {
pub fn name(&self) -> &str {
&self.name
}
pub fn inode(&self) -> u64 {
self.inode
}
pub fn file_type(&self) -> FileType {
self.file_type
}
pub fn is_file(&self) -> bool {
self.file_type.is_file()
}
pub fn is_dir(&self) -> bool {
self.file_type.is_dir()
}
pub fn is_symlink(&self) -> bool {
self.file_type.is_symlink()
}
}