starnix_core/vfs/
memory_directory.rs1use crate::task::CurrentTask;
6use crate::vfs::{
7 DirEntryChildKey, DirectoryEntryType, DirentSink, FileObject, FileOps, SeekTarget,
8 default_seek, fileops_impl_directory, fileops_impl_noop_sync,
9};
10use fuchsia_rcu::RcuReadScope;
11use starnix_sync::{LockDepMutex, MemoryDirectoryReaddirPositionLock};
12use starnix_uapi::errors::Errno;
13use starnix_uapi::{error, off_t};
14use std::ops::Bound;
15
16pub struct MemoryDirectoryFile {
17 readdir_position: LockDepMutex<Bound<DirEntryChildKey>, MemoryDirectoryReaddirPositionLock>,
31}
32
33impl MemoryDirectoryFile {
34 pub fn new() -> MemoryDirectoryFile {
35 MemoryDirectoryFile { readdir_position: Bound::Unbounded.into() }
36 }
37}
38
39pub fn emit_dotdot(file: &FileObject, sink: &mut dyn DirentSink) -> Result<(), Errno> {
44 if sink.offset() == 0 {
45 sink.add(file.node().ino, 1, DirectoryEntryType::DIR, ".".into())?;
46 }
47 if sink.offset() == 1 {
48 sink.add(
49 file.name.entry.parent_or_self().node.ino,
50 2,
51 DirectoryEntryType::DIR,
52 "..".into(),
53 )?;
54 }
55 Ok(())
56}
57
58impl FileOps for MemoryDirectoryFile {
59 fileops_impl_directory!();
60 fileops_impl_noop_sync!();
61
62 fn seek(
63 &self,
64 file: &FileObject,
65 _current_task: &CurrentTask,
66 current_offset: off_t,
67 target: SeekTarget,
68 ) -> Result<off_t, Errno> {
69 let new_offset = default_seek(current_offset, target, || error!(EINVAL))?;
70 if current_offset == new_offset {
72 return Ok(new_offset);
73 }
74
75 let mut readdir_position = self.readdir_position.lock();
76
77 if new_offset <= 2 {
79 *readdir_position = Bound::Unbounded;
80 } else {
81 file.name.entry.get_children(|children| {
82 let count = (new_offset - 2) as usize;
83 *readdir_position = children
84 .iter()
85 .take(count)
86 .next_back()
87 .map_or(Bound::Unbounded, |(name, _)| Bound::Excluded(name.clone()));
88 });
89 }
90
91 Ok(new_offset)
92 }
93
94 fn readdir(
95 &self,
96 file: &FileObject,
97 _current_task: &CurrentTask,
98 sink: &mut dyn DirentSink,
99 ) -> Result<(), Errno> {
100 emit_dotdot(file, sink)?;
101
102 let mut readdir_position = self.readdir_position.lock();
103 let scope = RcuReadScope::new();
104 file.name.entry.get_children(|children| {
105 for (name, maybe_entry) in children.range((readdir_position.clone(), Bound::Unbounded))
106 {
107 if let Some(entry) = maybe_entry.upgrade() {
108 sink.add(
109 entry.node.ino,
110 sink.offset() + 1,
111 DirectoryEntryType::from_mode(entry.node.info().mode),
112 entry.local_name(&scope),
113 )?;
114 *readdir_position = Bound::Excluded(name.clone());
115 }
116 }
117 Ok(())
118 })
119 }
120}