axfs_ng_vfs/node/
mod.rs

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        /// Indicates that this file behaves like a stream.
34        ///
35        /// Presence of this flag could inform the higher layers to omit
36        /// maintaining a position for this file. `read_at` and `write_at` would
37        /// be called with zero offset instead.
38        const STREAM = 0x0001;
39
40        /// Indicates that this file should not be cached.
41        ///
42        /// For instance, files in `/proc` or `/sys` may contain dynamic data
43        /// that should not be cached.
44        const NON_CACHEABLE = 0x0002;
45
46        /// Indicates that this file should always be cached.
47        ///
48        /// For instance, files in tmpfs relies on page caching and do not have
49        /// a backing device.
50        const ALWAYS_CACHE = 0x0004;
51
52        /// Indicates that operations on this file are always blocking.
53        ///
54        /// This could prevent higher layers from attempting to add unnecessary
55        /// non-blocking handling.
56        const BLOCKING = 0x0008;
57    }
58}
59
60/// Filesystem node operationss
61#[allow(clippy::len_without_is_empty)]
62pub trait NodeOps: Send + Sync + 'static {
63    /// Gets the inode number of the node.
64    fn inode(&self) -> u64;
65
66    /// Gets the metadata of the node.
67    fn metadata(&self) -> VfsResult<Metadata>;
68
69    /// Updates the metadata of the node.
70    fn update_metadata(&self, update: MetadataUpdate) -> VfsResult<()>;
71
72    /// Gets the filesystem
73    fn filesystem(&self) -> &dyn FilesystemOps;
74
75    /// Gets the size of the node.
76    fn len(&self) -> VfsResult<u64> {
77        self.metadata().map(|m| m.size)
78    }
79
80    /// Synchronizes the file to disk.
81    fn sync(&self, data_only: bool) -> VfsResult<()>;
82
83    /// Casts the node to a `&dyn core::any::Any`.
84    fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
85
86    /// Returns the flags of the node.
87    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    /// Checks if the entry is a root of a mount point.
297    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}