axfs_devfs/
dir.rs

1use alloc::collections::BTreeMap;
2use alloc::sync::{Arc, Weak};
3use axfs_vfs::{VfsDirEntry, VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType};
4use axfs_vfs::{VfsError, VfsResult};
5use spin::RwLock;
6
7/// The directory node in the device filesystem.
8///
9/// It implements [`axfs_vfs::VfsNodeOps`].
10pub struct DirNode {
11    parent: RwLock<Weak<dyn VfsNodeOps>>,
12    children: RwLock<BTreeMap<&'static str, VfsNodeRef>>,
13}
14
15impl DirNode {
16    pub(super) fn new(parent: Option<&VfsNodeRef>) -> Arc<Self> {
17        let parent = parent.map_or(Weak::<Self>::new() as _, Arc::downgrade);
18        Arc::new(Self {
19            parent: RwLock::new(parent),
20            children: RwLock::new(BTreeMap::new()),
21        })
22    }
23
24    pub(super) fn set_parent(&self, parent: Option<&VfsNodeRef>) {
25        *self.parent.write() = parent.map_or(Weak::<Self>::new() as _, Arc::downgrade);
26    }
27
28    /// Create a subdirectory at this directory.
29    pub fn mkdir(self: &Arc<Self>, name: &'static str) -> Arc<Self> {
30        let parent = self.clone() as VfsNodeRef;
31        let node = Self::new(Some(&parent));
32        self.children.write().insert(name, node.clone());
33        node
34    }
35
36    /// Add a node to this directory.
37    pub fn add(&self, name: &'static str, node: VfsNodeRef) {
38        self.children.write().insert(name, node);
39    }
40}
41
42impl VfsNodeOps for DirNode {
43    fn get_attr(&self) -> VfsResult<VfsNodeAttr> {
44        Ok(VfsNodeAttr::new_dir(4096, 0))
45    }
46
47    fn parent(&self) -> Option<VfsNodeRef> {
48        self.parent.read().upgrade()
49    }
50
51    fn lookup(self: Arc<Self>, path: &str) -> VfsResult<VfsNodeRef> {
52        let (name, rest) = split_path(path);
53        let node = match name {
54            "" | "." => Ok(self.clone() as VfsNodeRef),
55            ".." => self.parent().ok_or(VfsError::NotFound),
56            _ => self
57                .children
58                .read()
59                .get(name)
60                .cloned()
61                .ok_or(VfsError::NotFound),
62        }?;
63
64        if let Some(rest) = rest {
65            node.lookup(rest)
66        } else {
67            Ok(node)
68        }
69    }
70
71    fn read_dir(&self, start_idx: usize, dirents: &mut [VfsDirEntry]) -> VfsResult<usize> {
72        let children = self.children.read();
73        let mut children = children.iter().skip(start_idx.max(2) - 2);
74        for (i, ent) in dirents.iter_mut().enumerate() {
75            match i + start_idx {
76                0 => *ent = VfsDirEntry::new(".", VfsNodeType::Dir),
77                1 => *ent = VfsDirEntry::new("..", VfsNodeType::Dir),
78                _ => {
79                    if let Some((name, node)) = children.next() {
80                        *ent = VfsDirEntry::new(name, node.get_attr().unwrap().file_type());
81                    } else {
82                        return Ok(i);
83                    }
84                }
85            }
86        }
87        Ok(dirents.len())
88    }
89
90    fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult {
91        log::debug!("create {ty:?} at devfs: {path}");
92        let (name, rest) = split_path(path);
93        if let Some(rest) = rest {
94            match name {
95                "" | "." => self.create(rest, ty),
96                ".." => self.parent().ok_or(VfsError::NotFound)?.create(rest, ty),
97                _ => self
98                    .children
99                    .read()
100                    .get(name)
101                    .ok_or(VfsError::NotFound)?
102                    .create(rest, ty),
103            }
104        } else if name.is_empty() || name == "." || name == ".." {
105            Ok(()) // already exists
106        } else {
107            Err(VfsError::PermissionDenied) // do not support to create nodes dynamically
108        }
109    }
110
111    fn remove(&self, path: &str) -> VfsResult {
112        log::debug!("remove at devfs: {path}");
113        let (name, rest) = split_path(path);
114        if let Some(rest) = rest {
115            match name {
116                "" | "." => self.remove(rest),
117                ".." => self.parent().ok_or(VfsError::NotFound)?.remove(rest),
118                _ => self
119                    .children
120                    .read()
121                    .get(name)
122                    .ok_or(VfsError::NotFound)?
123                    .remove(rest),
124            }
125        } else {
126            Err(VfsError::PermissionDenied) // do not support to remove nodes dynamically
127        }
128    }
129
130    axfs_vfs::impl_vfs_dir_default! {}
131}
132
133fn split_path(path: &str) -> (&str, Option<&str>) {
134    let trimmed_path = path.trim_start_matches('/');
135    trimmed_path.find('/').map_or((trimmed_path, None), |n| {
136        (&trimmed_path[..n], Some(&trimmed_path[n + 1..]))
137    })
138}