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