starnix_core/vfs/pseudo/
vec_directory.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::task::CurrentTask;
6use crate::vfs::{
7    DirectoryEntryType, DirentSink, FileObject, FileOps, FsString, emit_dotdot,
8    fileops_impl_directory, fileops_impl_noop_sync, fileops_impl_unbounded_seek,
9};
10use starnix_sync::{FileOpsCore, Locked};
11use starnix_uapi::errors::Errno;
12use starnix_uapi::ino_t;
13
14/// A directory entry used for [`VecDirectory`].
15#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
16pub struct VecDirectoryEntry {
17    /// The type of the directory entry (directory, regular, socket, etc).
18    pub entry_type: DirectoryEntryType,
19
20    /// The name of the directory entry.
21    pub name: FsString,
22
23    /// Optional inode associated with the entry. If `None`, the entry will be auto-assigned one.
24    pub inode: Option<ino_t>,
25}
26
27/// A FileOps that iterates over a vector of [`VecDirectoryEntry`].
28pub struct VecDirectory(Vec<VecDirectoryEntry>);
29
30impl VecDirectory {
31    pub fn new_file(entries: Vec<VecDirectoryEntry>) -> Box<dyn FileOps> {
32        Box::new(Self(entries))
33    }
34}
35
36impl FileOps for VecDirectory {
37    fileops_impl_directory!();
38    fileops_impl_noop_sync!();
39    fileops_impl_unbounded_seek!();
40
41    fn readdir(
42        &self,
43        _locked: &mut Locked<FileOpsCore>,
44        file: &FileObject,
45        _current_task: &CurrentTask,
46        sink: &mut dyn DirentSink,
47    ) -> Result<(), Errno> {
48        emit_dotdot(file, sink)?;
49
50        // Skip through the entries until the current offset is reached.
51        // Subtract 2 from the offset to account for `.` and `..`.
52        for entry in self.0.iter().skip(sink.offset() as usize - 2) {
53            // Assign an inode if one wasn't set.
54            let inode = entry.inode.unwrap_or_else(|| file.fs.allocate_ino());
55            sink.add(inode, sink.offset() + 1, entry.entry_type, entry.name.as_ref())?;
56        }
57        Ok(())
58    }
59}