1use alloc::{
9 collections::BTreeMap, string::{String, ToString}, sync::{Arc, Weak}, vec::Vec
10};
11use spin::RwLock;
12use core::{any::Any, fmt::Debug};
13use core::fmt;
14
15use crate::fs::{FileSystemError, FileSystemErrorKind, FileMetadata, FileObject, FileType};
16
17#[derive(Debug, Clone)]
19pub struct DirectoryEntryInternal {
20 pub name: String,
21 pub file_type: FileType,
22 pub file_id: u64,
23}
24
25pub type FileSystemRef = Arc<dyn FileSystemOperations>;
27
28pub struct VfsEntry {
38 parent: RwLock<Weak<VfsEntry>>,
40
41 name: String,
43
44 node: Arc<dyn VfsNode>,
46
47 children: RwLock<BTreeMap<String, Weak<VfsEntry>>>,
49}
50
51impl VfsEntry {
52 pub fn new(
54 parent: Option<Weak<VfsEntry>>,
55 name: String,
56 node: Arc<dyn VfsNode>,
57 ) -> Arc<Self> {
58 debug_assert!(node.filesystem().is_some(), "VfsEntry::new - node.filesystem() is None for name '{}'", name);
60 debug_assert!(node.filesystem().unwrap().upgrade().is_some(), "VfsEntry::new - node.filesystem().upgrade() failed for name '{}'", name);
61
62 Arc::new(Self {
63 parent: RwLock::new(parent.unwrap_or_else(|| Weak::new())),
64 name,
65 node,
66 children: RwLock::new(BTreeMap::new()),
67 })
68 }
69
70 pub fn name(&self) -> &String {
72 &self.name
73 }
74
75 pub fn node(&self) -> Arc<dyn VfsNode> {
77 Arc::clone(&self.node)
78 }
79
80 pub fn parent(&self) -> Option<Arc<VfsEntry>> {
82 self.parent.read().upgrade()
83 }
84
85 pub fn set_parent(&self, parent: Weak<VfsEntry>) {
86 *self.parent.write() = parent;
87 }
88
89 pub fn add_child(self: &Arc<Self>, name: String, child: Arc<VfsEntry>) {
91 child.set_parent(Arc::downgrade(self));
92 let mut children = self.children.write();
93 children.insert(name, Arc::downgrade(&child));
94 }
95
96 pub fn get_child(&self, name: &String) -> Option<Arc<VfsEntry>> {
98 let mut children = self.children.write();
99
100 if let Some(weak_ref) = children.get(name) {
102 if let Some(strong_ref) = weak_ref.upgrade() {
103 return Some(strong_ref);
104 } else {
105 children.remove(name);
107 }
108 }
109
110 None
111 }
112
113 pub fn remove_child(&self, name: &String) -> Option<Arc<VfsEntry>> {
115 let mut children = self.children.write();
116 if let Some(weak_ref) = children.remove(name) {
117 weak_ref.upgrade()
118 } else {
119 None
120 }
121 }
122
123 pub fn cleanup_cache(&self) {
125 let mut children = self.children.write();
126 children.retain(|_, weak_ref| weak_ref.strong_count() > 0);
127 }
128}
129
130impl Clone for VfsEntry {
131 fn clone(&self) -> Self {
132 Self {
133 parent: RwLock::new(self.parent.read().clone()),
134 name: self.name.clone(),
135 node: Arc::clone(&self.node),
136 children: RwLock::new(self.children.read().clone()),
137 }
138 }
139}
140
141impl fmt::Debug for VfsEntry {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.debug_struct("VfsEntry")
144 .field("name", &self.name)
145 .field("node", &self.node)
146 .field("children_count", &self.children.read().len())
147 .finish()
148 }
149}
150
151pub trait VfsNode: Send + Sync + Any {
156 fn id(&self) -> u64;
158
159 fn filesystem(&self) -> Option<Weak<dyn FileSystemOperations>>;
161
162 fn metadata(&self) -> Result<FileMetadata, FileSystemError>;
164
165 fn file_type(&self) -> Result<FileType, FileSystemError> {
167 Ok(self.metadata()?.file_type)
168 }
169
170 fn as_any(&self) -> &dyn Any;
172
173 fn is_directory(&self) -> Result<bool, FileSystemError> {
175 Ok(self.file_type()? == FileType::Directory)
176 }
177
178 fn is_symlink(&self) -> Result<bool, FileSystemError> {
180 Ok(matches!(self.file_type()?, FileType::SymbolicLink(_)))
181 }
182
183 fn read_link(&self) -> Result<String, FileSystemError> {
185 Err(FileSystemError::new(
186 crate::fs::FileSystemErrorKind::NotSupported,
187 "Not a symbolic link"
188 ))
189 }
190}
191
192impl fmt::Debug for dyn VfsNode {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 f.debug_struct("VfsNode")
196 .field("id", &self.id())
197 .field("file_type", &self.file_type().unwrap_or(FileType::Unknown))
198 .field("metadata", &self.metadata())
199 .field("filesystem", &self.filesystem().and_then(|fs| fs.upgrade().map(|fs| fs.name().to_string())))
200 .finish()
201 }
202}
203
204pub trait FileSystemOperations: Send + Sync {
210 fn lookup(
215 &self,
216 parent_node: &Arc<dyn VfsNode>,
217 name: &String,
218 ) -> Result<Arc<dyn VfsNode>, FileSystemError>;
219
220 fn open(
225 &self,
226 node: &Arc<dyn VfsNode>,
227 flags: u32,
228 ) -> Result<Arc<dyn FileObject>, FileSystemError>;
229
230 fn create(
232 &self,
233 parent_node: &Arc<dyn VfsNode>,
234 name: &String,
235 file_type: FileType,
236 mode: u32,
237 ) -> Result<Arc<dyn VfsNode>, FileSystemError>;
238
239 fn remove(
241 &self,
242 parent_node: &Arc<dyn VfsNode>,
243 name: &String,
244 ) -> Result<(), FileSystemError>;
245
246 fn readdir(
248 &self,
249 node: &Arc<dyn VfsNode>,
250 ) -> Result<Vec<DirectoryEntryInternal>, FileSystemError>;
251
252 fn root_node(&self) -> Arc<dyn VfsNode>;
254
255 fn name(&self) -> &str;
257
258 fn is_read_only(&self) -> bool {
260 false
261 }
262
263 fn create_hardlink(
283 &self,
284 link_parent: &Arc<dyn VfsNode>,
285 link_name: &String,
286 target_node: &Arc<dyn VfsNode>,
287 ) -> Result<Arc<dyn VfsNode>, FileSystemError> {
288 let _ = (link_parent, link_name, target_node);
290 Err(FileSystemError::new(
291 FileSystemErrorKind::NotSupported,
292 "Hard links not supported by this filesystem"
293 ))
294 }
295
296}
297
298impl fmt::Debug for dyn FileSystemOperations {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 f.debug_struct("FileSystemOperations")
301 .field("name", &self.name())
302 .field("root", &self.root_node())
303 .finish()
304 }
305}