1use crate::error::{check_errno_with_path, Result};
4use crate::fs::Ext4Fs;
5use crate::types::FileType;
6use ext4_lwext4_sys::{ext4_dir, ext4_dir_close, ext4_dir_entry_next, ext4_dir_entry_rewind, ext4_dir_open};
7
8pub struct Dir<'a> {
12 #[allow(dead_code)]
13 fs: &'a Ext4Fs,
14 inner: ext4_dir,
15}
16
17impl<'a> Dir<'a> {
18 pub(crate) fn open(fs: &'a Ext4Fs, path: &str) -> Result<Self> {
20 let full_path = fs.make_path(path)?;
21 let mut inner = ext4_dir::default();
22
23 let ret = unsafe { ext4_dir_open(&mut inner, full_path.as_ptr()) };
24 check_errno_with_path(ret, path)?;
25
26 Ok(Self { fs, inner })
27 }
28
29 pub fn next_entry(&mut self) -> Option<Result<DirEntry>> {
31 let entry_ptr = unsafe { ext4_dir_entry_next(&mut self.inner) };
32
33 if entry_ptr.is_null() {
34 return None;
35 }
36
37 let entry = unsafe { &*entry_ptr };
38
39 let name_len = entry.name_length as usize;
41 let name_bytes = &entry.name[..name_len];
42 let name = match String::from_utf8(name_bytes.to_vec()) {
43 Ok(s) => s,
44 Err(_) => {
45 String::from_utf8_lossy(name_bytes).into_owned()
47 }
48 };
49
50 Some(Ok(DirEntry {
51 name,
52 inode: entry.inode as u64,
53 file_type: FileType::from_raw(entry.inode_type),
54 }))
55 }
56
57 pub fn rewind(&mut self) {
59 unsafe {
60 ext4_dir_entry_rewind(&mut self.inner);
61 }
62 }
63}
64
65impl Drop for Dir<'_> {
66 fn drop(&mut self) {
67 unsafe {
68 ext4_dir_close(&mut self.inner);
69 }
70 }
71}
72
73impl<'a> Iterator for Dir<'a> {
74 type Item = Result<DirEntry>;
75
76 fn next(&mut self) -> Option<Self::Item> {
77 self.next_entry()
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct DirEntry {
84 pub name: String,
86 pub inode: u64,
88 pub file_type: FileType,
90}
91
92impl DirEntry {
93 pub fn name(&self) -> &str {
95 &self.name
96 }
97
98 pub fn inode(&self) -> u64 {
100 self.inode
101 }
102
103 pub fn file_type(&self) -> FileType {
105 self.file_type
106 }
107
108 pub fn is_file(&self) -> bool {
110 self.file_type.is_file()
111 }
112
113 pub fn is_dir(&self) -> bool {
115 self.file_type.is_dir()
116 }
117
118 pub fn is_symlink(&self) -> bool {
120 self.file_type.is_symlink()
121 }
122}