blob: d5faf117a12ebb3eb65460d04d996ddb50d6a511 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::{
task::CurrentTask,
vfs::{
emit_dotdot, fileops_impl_directory, unbounded_seek, DirectoryEntryType, DirentSink,
FileObject, FileOps, FsString, SeekTarget,
},
};
use starnix_sync::{FileOpsCore, Locked};
use starnix_uapi::{errors::Errno, ino_t, off_t};
/// A directory entry used for [`VecDirectory`].
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct VecDirectoryEntry {
/// The type of the directory entry (directory, regular, socket, etc).
pub entry_type: DirectoryEntryType,
/// The name of the directory entry.
pub name: FsString,
/// Optional inode associated with the entry. If `None`, the entry will be auto-assigned one.
pub inode: Option<ino_t>,
}
/// A FileOps that iterates over a vector of [`VecDirectoryEntry`].
pub struct VecDirectory(Vec<VecDirectoryEntry>);
impl VecDirectory {
pub fn new_file(entries: Vec<VecDirectoryEntry>) -> Box<dyn FileOps> {
Box::new(Self(entries))
}
}
impl FileOps for VecDirectory {
fileops_impl_directory!();
fn seek(
&self,
_file: &FileObject,
_current_task: &CurrentTask,
current_offset: off_t,
target: SeekTarget,
) -> Result<off_t, Errno> {
unbounded_seek(current_offset, target)
}
fn readdir(
&self,
_locked: &mut Locked<'_, FileOpsCore>,
file: &FileObject,
_current_task: &CurrentTask,
sink: &mut dyn DirentSink,
) -> Result<(), Errno> {
emit_dotdot(file, sink)?;
// Skip through the entries until the current offset is reached.
// Subtract 2 from the offset to account for `.` and `..`.
for entry in self.0.iter().skip(sink.offset() as usize - 2) {
// Assign an inode if one wasn't set.
let inode = entry.inode.unwrap_or_else(|| file.fs.next_node_id());
sink.add(inode, sink.offset() + 1, entry.entry_type, entry.name.as_ref())?;
}
Ok(())
}
}