1mod dir;
2mod file;
3
4use alloc::{
5 borrow::ToOwned,
6 string::String,
7 sync::{Arc, Weak},
8 vec,
9 vec::Vec,
10};
11use bitflags::bitflags;
12use core::{
13 any::{Any, TypeId},
14 fmt, iter,
15 ops::Deref,
16 task::Context,
17};
18use smallvec::SmallVec;
19
20use axpoll::{IoEvents, Pollable};
21pub use dir::*;
22pub use file::*;
23use inherit_methods_macro::inherit_methods;
24
25use crate::{
26 FilesystemOps, Metadata, MetadataUpdate, Mutex, MutexGuard, NodeType, VfsError, VfsResult,
27 path::PathBuf,
28};
29
30bitflags! {
31 #[derive(Debug, Clone, Copy)]
32 pub struct NodeFlags: u32 {
33 const STREAM = 0x0001;
39
40 const NON_CACHEABLE = 0x0002;
45
46 const ALWAYS_CACHE = 0x0004;
51
52 const BLOCKING = 0x0008;
57 }
58}
59
60#[allow(clippy::len_without_is_empty)]
62pub trait NodeOps: Send + Sync + 'static {
63 fn inode(&self) -> u64;
65
66 fn metadata(&self) -> VfsResult<Metadata>;
68
69 fn update_metadata(&self, update: MetadataUpdate) -> VfsResult<()>;
71
72 fn filesystem(&self) -> &dyn FilesystemOps;
74
75 fn len(&self) -> VfsResult<u64> {
77 self.metadata().map(|m| m.size)
78 }
79
80 fn sync(&self, data_only: bool) -> VfsResult<()>;
82
83 fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
85
86 fn flags(&self) -> NodeFlags {
88 NodeFlags::empty()
89 }
90}
91
92enum Node {
93 File(FileNode),
94 Dir(DirNode),
95}
96
97impl Node {
98 pub fn clone_inner(&self) -> Arc<dyn NodeOps> {
99 match self {
100 Node::File(file) => file.inner().clone(),
101 Node::Dir(dir) => dir.inner().clone(),
102 }
103 }
104}
105
106impl Deref for Node {
107 type Target = dyn NodeOps;
108
109 fn deref(&self) -> &Self::Target {
110 match &self {
111 Node::File(file) => file.deref(),
112 Node::Dir(dir) => dir.deref(),
113 }
114 }
115}
116
117impl fmt::Debug for Node {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 match self {
120 Node::File(file) => write!(f, "FileNode({})", file.inode()),
121 Node::Dir(dir) => write!(f, "DirNode({})", dir.inode()),
122 }
123 }
124}
125
126pub type ReferenceKey = (usize, String);
127
128#[derive(Debug)]
129pub struct Reference {
130 parent: Option<DirEntry>,
131 name: String,
132}
133
134impl Reference {
135 pub fn new(parent: Option<DirEntry>, name: String) -> Self {
136 Self { parent, name }
137 }
138
139 pub fn root() -> Self {
140 Self::new(None, String::new())
141 }
142
143 pub fn key(&self) -> ReferenceKey {
144 let address = self
145 .parent
146 .as_ref()
147 .map_or(0, |it| Arc::as_ptr(&it.0) as usize);
148 (address, self.name.clone())
149 }
150}
151
152#[derive(Default)]
153pub struct TypeMap(SmallVec<[(TypeId, Arc<dyn Any + Send + Sync>); 2]>);
154impl TypeMap {
155 pub fn new() -> Self {
156 Self::default()
157 }
158
159 pub fn insert<T: Any + Send + Sync>(&mut self, value: T) {
160 self.0.push((TypeId::of::<T>(), Arc::new(value)));
161 }
162
163 pub fn get<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
164 self.0
165 .iter()
166 .find_map(|(id, value)| {
167 if id == &TypeId::of::<T>() {
168 Some(value.clone())
169 } else {
170 None
171 }
172 })
173 .and_then(|value| value.downcast().ok())
174 }
175
176 pub fn get_or_insert_with<T: Any + Send + Sync>(&mut self, f: impl FnOnce() -> T) -> Arc<T> {
177 if let Some(value) = self.get::<T>() {
178 value
179 } else {
180 let value = f();
181 self.insert(value);
182 self.get::<T>().unwrap()
183 }
184 }
185}
186
187struct Inner {
188 node: Node,
189 node_type: NodeType,
190 reference: Reference,
191 user_data: Mutex<TypeMap>,
192}
193
194impl fmt::Debug for Inner {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 f.debug_struct("Inner")
197 .field("node", &self.node)
198 .field("node_type", &self.node_type)
199 .field("reference", &self.reference)
200 .finish()
201 }
202}
203
204#[derive(Debug, Clone)]
205pub struct DirEntry(Arc<Inner>);
206
207#[derive(Debug, Clone)]
208pub struct WeakDirEntry(Weak<Inner>);
209
210impl WeakDirEntry {
211 pub fn upgrade(&self) -> Option<DirEntry> {
212 self.0.upgrade().map(DirEntry)
213 }
214}
215
216impl From<Node> for Arc<dyn NodeOps> {
217 fn from(node: Node) -> Self {
218 match node {
219 Node::File(file) => file.into(),
220 Node::Dir(dir) => dir.into(),
221 }
222 }
223}
224
225#[inherit_methods(from = "self.0.node")]
226impl DirEntry {
227 pub fn inode(&self) -> u64;
228
229 pub fn filesystem(&self) -> &dyn FilesystemOps;
230
231 pub fn update_metadata(&self, update: MetadataUpdate) -> VfsResult<()>;
232
233 #[allow(clippy::len_without_is_empty)]
234 pub fn len(&self) -> VfsResult<u64>;
235
236 pub fn flags(&self) -> NodeFlags;
237
238 pub fn sync(&self, data_only: bool) -> VfsResult<()>;
239}
240
241impl DirEntry {
242 pub fn new_file(node: FileNode, node_type: NodeType, reference: Reference) -> Self {
243 Self(Arc::new(Inner {
244 node: Node::File(node),
245 node_type,
246 reference,
247 user_data: Mutex::default(),
248 }))
249 }
250
251 pub fn new_dir(node_fn: impl FnOnce(WeakDirEntry) -> DirNode, reference: Reference) -> Self {
252 Self(Arc::new_cyclic(|this| Inner {
253 node: Node::Dir(node_fn(WeakDirEntry(this.clone()))),
254 node_type: NodeType::Directory,
255 reference,
256 user_data: Mutex::default(),
257 }))
258 }
259
260 pub fn metadata(&self) -> VfsResult<Metadata> {
261 self.0.node.metadata().map(|mut metadata| {
262 metadata.node_type = self.0.node_type;
263 metadata
264 })
265 }
266
267 pub fn downcast<T: NodeOps>(&self) -> VfsResult<Arc<T>> {
268 self.0
269 .node
270 .clone_inner()
271 .into_any()
272 .downcast()
273 .map_err(|_| VfsError::InvalidInput)
274 }
275
276 pub fn downgrade(&self) -> WeakDirEntry {
277 WeakDirEntry(Arc::downgrade(&self.0))
278 }
279
280 pub fn key(&self) -> ReferenceKey {
281 self.0.reference.key()
282 }
283
284 pub fn node_type(&self) -> NodeType {
285 self.0.node_type
286 }
287
288 pub fn parent(&self) -> Option<Self> {
289 self.0.reference.parent.clone()
290 }
291
292 pub fn name(&self) -> &str {
293 &self.0.reference.name
294 }
295
296 pub fn is_root_of_mount(&self) -> bool {
298 self.0.reference.parent.is_none()
299 }
300
301 pub fn is_ancestor_of(&self, other: &Self) -> VfsResult<bool> {
302 let mut current = other.clone();
303 loop {
304 if current.ptr_eq(self) {
305 return Ok(true);
306 }
307 if let Some(parent) = current.parent() {
308 current = parent;
309 } else {
310 break;
311 }
312 }
313 Ok(false)
314 }
315
316 pub(crate) fn collect_absolute_path(&self, components: &mut Vec<String>) {
317 let mut current = self.clone();
318 loop {
319 components.push(current.name().to_owned());
320 if let Some(parent) = current.parent() {
321 current = parent;
322 } else {
323 break;
324 }
325 }
326 }
327
328 pub fn absolute_path(&self) -> VfsResult<PathBuf> {
329 let mut components = vec![];
330 self.collect_absolute_path(&mut components);
331 Ok(iter::once("/")
332 .chain(components.iter().map(String::as_str).rev())
333 .collect())
334 }
335
336 pub fn is_file(&self) -> bool {
337 matches!(self.0.node, Node::File(_))
338 }
339
340 pub fn is_dir(&self) -> bool {
341 matches!(self.0.node, Node::Dir(_))
342 }
343
344 pub fn as_file(&self) -> VfsResult<&FileNode> {
345 match &self.0.node {
346 Node::File(file) => Ok(file),
347 _ => Err(VfsError::IsADirectory),
348 }
349 }
350
351 pub fn as_dir(&self) -> VfsResult<&DirNode> {
352 match &self.0.node {
353 Node::Dir(dir) => Ok(dir),
354 _ => Err(VfsError::NotADirectory),
355 }
356 }
357
358 pub fn ptr_eq(&self, other: &Self) -> bool {
359 Arc::ptr_eq(&self.0, &other.0)
360 }
361
362 pub fn as_ptr(&self) -> usize {
363 Arc::as_ptr(&self.0) as usize
364 }
365
366 pub fn read_link(&self) -> VfsResult<String> {
367 if self.node_type() != NodeType::Symlink {
368 return Err(VfsError::InvalidData);
369 }
370 let file = self.as_file()?;
371 let mut buf = vec![0; file.len()? as usize];
372 file.read_at(&mut buf, 0)?;
373 String::from_utf8(buf).map_err(|_| VfsError::InvalidData)
374 }
375
376 pub fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult<usize> {
377 match &self.0.node {
378 Node::File(file) => file.ioctl(cmd, arg),
379 Node::Dir(_) => Err(VfsError::NotATty),
380 }
381 }
382
383 pub fn user_data(&self) -> MutexGuard<'_, TypeMap> {
384 self.0.user_data.lock()
385 }
386}
387
388impl Pollable for DirEntry {
389 fn poll(&self) -> IoEvents {
390 match &self.0.node {
391 Node::File(file) => file.poll(),
392 Node::Dir(_dir) => IoEvents::IN | IoEvents::OUT,
393 }
394 }
395
396 fn register(&self, context: &mut Context<'_>, events: IoEvents) {
397 match &self.0.node {
398 Node::File(file) => file.register(context, events),
399 Node::Dir(_) => {}
400 }
401 }
402}