1use alloc::{borrow::ToOwned, string::String, sync::Arc};
2use core::{
3 mem,
4 ops::{Deref, DerefMut},
5};
6
7use hashbrown::HashMap;
8
9use super::DirEntry;
10use crate::{
11 MetadataUpdate, Mountpoint, Mutex, MutexGuard, NodeOps, NodePermission, NodeType, VfsError,
12 VfsResult,
13 path::{DOT, DOTDOT, MAX_NAME_LEN, verify_entry_name},
14};
15
16pub trait DirEntrySink {
18 fn accept(&mut self, name: &str, ino: u64, node_type: NodeType, offset: u64) -> bool;
26}
27
28impl<F: FnMut(&str, u64, NodeType, u64) -> bool> DirEntrySink for F {
29 fn accept(&mut self, name: &str, ino: u64, node_type: NodeType, offset: u64) -> bool {
30 self(name, ino, node_type, offset)
31 }
32}
33
34type DirChildren = HashMap<String, DirEntry>;
35
36pub trait DirNodeOps: NodeOps {
37 fn read_dir(&self, offset: u64, sink: &mut dyn DirEntrySink) -> VfsResult<usize>;
44
45 fn lookup(&self, name: &str) -> VfsResult<DirEntry>;
47
48 fn is_cacheable(&self) -> bool {
59 true
60 }
61
62 fn create(
64 &self,
65 name: &str,
66 node_type: NodeType,
67 permission: NodePermission,
68 ) -> VfsResult<DirEntry>;
69
70 fn link(&self, name: &str, node: &DirEntry) -> VfsResult<DirEntry>;
72
73 fn unlink(&self, name: &str) -> VfsResult<()>;
78
79 fn rename(&self, src_name: &str, dst_dir: &DirNode, dst_name: &str) -> VfsResult<()>;
91}
92
93#[derive(Debug, Clone)]
97pub struct OpenOptions {
98 pub create: bool,
99 pub create_new: bool,
100 pub node_type: NodeType,
101 pub permission: NodePermission,
102 pub user: Option<(u32, u32)>, }
104
105impl Default for OpenOptions {
106 fn default() -> Self {
107 Self {
108 create: false,
109 create_new: false,
110 node_type: NodeType::RegularFile,
111 permission: NodePermission::default(),
112 user: None,
113 }
114 }
115}
116
117pub struct DirNode {
118 ops: Arc<dyn DirNodeOps>,
119 cache: Mutex<DirChildren>,
120 pub(crate) mountpoint: Mutex<Option<Arc<Mountpoint>>>,
121}
122
123impl Deref for DirNode {
124 type Target = dyn NodeOps;
125
126 fn deref(&self) -> &Self::Target {
127 &*self.ops
128 }
129}
130
131impl From<DirNode> for Arc<dyn NodeOps> {
132 fn from(node: DirNode) -> Self {
133 node.ops.clone()
134 }
135}
136
137impl DirNode {
138 pub fn new(ops: Arc<dyn DirNodeOps>) -> Self {
139 Self {
140 ops,
141 cache: Mutex::default(),
142 mountpoint: Mutex::default(),
143 }
144 }
145
146 pub fn inner(&self) -> &Arc<dyn DirNodeOps> {
147 &self.ops
148 }
149
150 pub fn downcast<T: DirNodeOps>(&self) -> VfsResult<Arc<T>> {
151 self.ops
152 .clone()
153 .into_any()
154 .downcast()
155 .map_err(|_| VfsError::InvalidInput)
156 }
157
158 fn forget_entry(children: &mut DirChildren, name: &str) {
159 if let Some(entry) = children.remove(name)
160 && let Ok(dir) = entry.as_dir()
161 {
162 dir.forget();
163 }
164 }
165
166 fn lookup_locked(&self, name: &str, children: &mut DirChildren) -> VfsResult<DirEntry> {
167 use hashbrown::hash_map::Entry;
168 match children.entry(name.to_owned()) {
169 Entry::Occupied(e) => Ok(e.get().clone()),
170 Entry::Vacant(e) => {
171 let node = self.ops.lookup(name)?;
172 if self.ops.is_cacheable() {
173 e.insert(node.clone());
174 }
175 Ok(node)
176 }
177 }
178 }
179
180 pub fn lookup(&self, name: &str) -> VfsResult<DirEntry> {
182 if name.len() > MAX_NAME_LEN {
183 return Err(VfsError::NameTooLong);
184 }
185 if self.ops.is_cacheable() {
187 self.lookup_locked(name, &mut self.cache.lock())
188 } else {
189 self.ops.lookup(name)
190 }
191 }
192
193 pub fn lookup_cache(&self, name: &str) -> Option<DirEntry> {
195 if self.ops.is_cacheable() {
196 self.cache.lock().get(name).cloned()
197 } else {
198 None
199 }
200 }
201
202 pub fn insert_cache(&self, name: String, entry: DirEntry) -> Option<DirEntry> {
204 if self.ops.is_cacheable() {
205 self.cache.lock().insert(name, entry)
206 } else {
207 None
208 }
209 }
210
211 pub fn read_dir(&self, offset: u64, sink: &mut dyn DirEntrySink) -> VfsResult<usize> {
212 self.ops.read_dir(offset, sink)
213 }
214
215 pub fn link(&self, name: &str, node: &DirEntry) -> VfsResult<DirEntry> {
217 verify_entry_name(name)?;
218
219 self.ops.link(name, node).inspect(|entry| {
220 self.cache.lock().insert(name.to_owned(), entry.clone());
221 })
222 }
223
224 pub fn unlink(&self, name: &str, is_dir: bool) -> VfsResult<()> {
226 verify_entry_name(name)?;
227
228 let mut children = self.cache.lock();
229 let entry = self.lookup_locked(name, &mut children)?;
230 match (entry.is_dir(), is_dir) {
231 (true, false) => return Err(VfsError::IsADirectory),
232 (false, true) => return Err(VfsError::NotADirectory),
233 _ => {}
234 }
235
236 self.ops.unlink(name).inspect(|_| {
237 Self::forget_entry(&mut children, name);
238 })
239 }
240
241 pub fn has_children(&self) -> VfsResult<bool> {
243 let mut has_children = false;
244 self.read_dir(0, &mut |name: &str, _, _, _| {
245 if name != DOT && name != DOTDOT {
246 has_children = true;
247 false
248 } else {
249 true
250 }
251 })?;
252 Ok(has_children)
253 }
254
255 fn create_locked(
256 &self,
257 name: &str,
258 node_type: NodeType,
259 permission: NodePermission,
260 children: &mut DirChildren,
261 ) -> VfsResult<DirEntry> {
262 let entry = self.ops.create(name, node_type, permission)?;
263 children.insert(name.to_owned(), entry.clone());
264 Ok(entry)
265 }
266
267 pub fn create(
269 &self,
270 name: &str,
271 node_type: NodeType,
272 permission: NodePermission,
273 ) -> VfsResult<DirEntry> {
274 verify_entry_name(name)?;
275 self.create_locked(name, node_type, permission, &mut self.cache.lock())
276 }
277
278 fn lock_both_cache<'a>(
279 &'a self,
280 other: &'a Self,
281 ) -> (
282 MutexGuard<'a, DirChildren>,
283 Option<MutexGuard<'a, DirChildren>>,
284 ) {
285 let src_children = self.cache.lock();
286 let dst_children = if core::ptr::eq(self, other) {
287 None
288 } else {
289 Some(other.cache.lock())
290 };
291 (src_children, dst_children)
292 }
293
294 pub fn rename(&self, src_name: &str, dst_dir: &Self, dst_name: &str) -> VfsResult<()> {
296 verify_entry_name(src_name)?;
297 verify_entry_name(dst_name)?;
298
299 let (mut src_children, mut dst_children) = self.lock_both_cache(dst_dir);
300
301 let src = self.lookup_locked(src_name, &mut src_children)?;
302 if let Ok(dst) = dst_dir.lookup_locked(
303 dst_name,
304 dst_children
305 .as_mut()
306 .map_or_else(|| src_children.deref_mut(), DerefMut::deref_mut),
307 ) {
308 if src.node_type() == NodeType::Directory {
309 if let Ok(dir) = dst.as_dir()
310 && dir.has_children()?
311 {
312 return Err(VfsError::DirectoryNotEmpty);
313 }
314 } else if dst.node_type() == NodeType::Directory {
315 return Err(VfsError::IsADirectory);
316 }
317 }
318 drop(src_children);
319 drop(dst_children);
320
321 self.ops.rename(src_name, dst_dir, dst_name).inspect(|_| {
322 let (mut src_children, mut dst_children) = self.lock_both_cache(dst_dir);
323 Self::forget_entry(&mut src_children, src_name);
324 Self::forget_entry(
325 dst_children
326 .as_mut()
327 .map_or_else(|| src_children.deref_mut(), DerefMut::deref_mut),
328 dst_name,
329 );
330 })
331 }
332
333 pub fn open_file(&self, name: &str, options: &OpenOptions) -> VfsResult<DirEntry> {
335 verify_entry_name(name)?;
336
337 let mut children = self.cache.lock();
338 match self.lookup_locked(name, &mut children) {
339 Ok(val) => {
340 if options.create_new {
341 return Err(VfsError::AlreadyExists);
342 }
343 return Ok(val);
344 }
345 Err(err) if err.canonicalize() == VfsError::NotFound && options.create => {}
346 Err(err) => return Err(err),
347 }
348 let entry =
349 self.create_locked(name, options.node_type, options.permission, &mut children)?;
350 if options.user.is_some() {
351 entry.update_metadata(MetadataUpdate {
352 owner: options.user,
353 ..Default::default()
354 })?;
355 }
356 Ok(entry)
357 }
358
359 pub fn mountpoint(&self) -> Option<Arc<Mountpoint>> {
360 self.mountpoint.lock().clone()
361 }
362
363 pub fn is_mountpoint(&self) -> bool {
364 self.mountpoint.lock().is_some()
365 }
366
367 pub(crate) fn forget(&self) {
370 for (_, child) in mem::take(self.cache.lock().deref_mut()) {
371 if let Ok(dir) = child.as_dir() {
372 dir.forget();
373 }
374 }
375 }
376}