@@ -2499,6 +2499,15 @@ unsafe fn split_at_spare_mut_with_len(
}
}
+impl<T: Clone> Vec<T> {
+ /// Try to clone the vector using the global allocator
+ #[inline]
+ #[stable(feature = "kernel", since = "1.0.0")]
+ pub fn try_clone(&self) -> Result<Self, TryReserveError> {
+ self.try_clone_in(Global)
+ }
+}
+
impl<T: Clone, A: Allocator> Vec<T, A> {
/// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
///
@@ -2623,6 +2632,14 @@ pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveErr
self.try_spec_extend(other.iter())
}
+ /// Tries to clone the vector using the given allocator
+ #[stable(feature = "kernel", since = "1.0.0")]
+ pub fn try_clone_in(&self, allocator: A) -> Result<Self, TryReserveError> {
+ let mut new_vec = Vec::try_with_capacity_in(self.len(), allocator)?;
+ new_vec.try_extend_from_slice(&self)?;
+ Ok(new_vec)
+ }
+
/// Copies elements from `src` range to the end of the vector.
///
/// # Panics
@@ -781,7 +781,9 @@ impl SuperParams {
///
/// The superblock is a newly-created one and this is the only active pointer to it.
pub struct NewSuperBlock<'a, T: Type + ?Sized, S = NeedsInit> {
- sb: &'a mut SuperBlock<T>,
+ /// Pointer to the superblock; this fields is public so puzzlefs can call
+ /// try_new_dcache_dir_inode when populating the directory hierarchy
+ pub sb: &'a mut SuperBlock<T>,
// This also forces `'a` to be invariant.
_p: PhantomData<&'a mut &'a S>,
@@ -6,16 +6,19 @@
use kernel::mount::Vfsmount;
use kernel::prelude::*;
use kernel::{
- c_str, file, fmt, fs,
+ c_str, file, fs,
io_buffer::IoBufferWriter,
- str::CString,
sync::{Arc, ArcBorrow},
};
mod puzzle;
// Required by the autogenerated '_capnp.rs' files
+use puzzle::inode::PuzzleFS;
+use puzzle::types::{Inode, InodeMode, MetadataBlob};
use puzzle::{manifest_capnp, metadata_capnp};
+use kernel::fs::{DEntry, INodeParams, NeedsRoot, NewSuperBlock, RootDEntry};
+
module_fs! {
type: PuzzleFsModule,
name: "puzzlefs",
@@ -27,7 +30,6 @@
#[derive(Debug)]
struct PuzzlefsInfo {
- base_path: CString,
vfs_mount: Arc<Vfsmount>,
}
@@ -55,9 +57,81 @@ fn try_new() -> Result {
}
}
+fn puzzlefs_populate_dir(
+ sb: &NewSuperBlock<'_, PuzzleFsModule, NeedsRoot>,
+ pfs: &PuzzleFS,
+ parent: &DEntry<PuzzleFsModule>,
+ ino: u64,
+ name: &CStr,
+ recursion: usize,
+) -> Result {
+ if recursion == 0 {
+ return Err(E2BIG);
+ }
+
+ let inode = Arc::try_new(pfs.find_inode(ino).map_err(|_| EINVAL)?)?;
+ match &inode.mode {
+ InodeMode::File { chunks: _ } => {
+ let params = INodeParams {
+ mode: inode.permissions,
+ ino: inode.ino,
+ value: inode.clone(),
+ };
+ let creator = fs::file_creator::<_, FsFile>();
+ let inode = creator(sb, params)?;
+ sb.try_new_dentry(inode, parent, name)?;
+ }
+ InodeMode::Dir { dir_list } => {
+ let params = INodeParams {
+ mode: inode.permissions,
+ ino: inode.ino,
+ value: inode.clone(),
+ };
+
+ let new_dentry;
+ let new_parent = if name.as_bytes() != c_str!("").as_bytes() {
+ let dcache_inode = sb.sb.try_new_dcache_dir_inode(params)?;
+ new_dentry = sb.try_new_dentry(dcache_inode, parent, name)?;
+ &new_dentry
+ } else {
+ parent
+ };
+
+ for entry in &dir_list.entries {
+ let mut name = entry.name.try_clone()?;
+ // append NUL terminator
+ name.try_push(0)?;
+ let name = CStr::from_bytes_with_nul(&name)?;
+ puzzlefs_populate_dir(sb, pfs, new_parent, entry.ino, name, recursion - 1)?;
+ }
+ }
+ _ => todo!(),
+ }
+
+ Ok(())
+}
+
+/// Creates a new root dentry populated with the given entries.
+fn try_new_populated_root_puzzlefs_dentry(
+ sb: &NewSuperBlock<'_, PuzzleFsModule, NeedsRoot>,
+ pfs: &PuzzleFS,
+ root_value: <PuzzleFsModule as fs::Type>::INodeData,
+) -> Result<RootDEntry<PuzzleFsModule>> {
+ let root_inode = sb.sb.try_new_dcache_dir_inode(INodeParams {
+ mode: 0o755,
+ ino: root_value.ino,
+ value: root_value,
+ })?;
+ let root = sb.try_new_root_dentry(root_inode)?;
+ let ino = 1u64;
+ puzzlefs_populate_dir(sb, pfs, &root, ino, c_str!(""), 10)?;
+ Ok(root)
+}
+
impl fs::Type for PuzzleFsModule {
type Context = Self;
- type INodeData = &'static [u8];
+ // this is Arc so it can be cloned in puzzlefs_populate_dir
+ type INodeData = Arc<Inode>;
type Data = Box<PuzzlefsInfo>;
const SUPER_TYPE: fs::Super = fs::Super::Independent;
const NAME: &'static CStr = c_str!("puzzlefs");
@@ -65,41 +139,35 @@ impl fs::Type for PuzzleFsModule {
const DCACHE_BASED: bool = true;
fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self>) -> Result<&fs::SuperBlock<Self>> {
- let base_path = CString::try_from_fmt(fmt!("hello world"))?;
- pr_info!("base_path {:?}\n", base_path);
let vfs_mount = Vfsmount::new_private_mount(c_str!("/home/puzzlefs_oci"))?;
pr_info!("vfs_mount {:?}\n", vfs_mount);
+ let arc_vfs_mount = Arc::try_new(vfs_mount)?;
+
let sb = sb.init(
Box::try_new(PuzzlefsInfo {
- base_path,
- vfs_mount: Arc::try_new(vfs_mount)?,
+ vfs_mount: arc_vfs_mount.clone(),
})?,
&fs::SuperParams {
magic: 0x72757374,
..fs::SuperParams::DEFAULT
},
)?;
- let root = sb.try_new_populated_root_dentry(
- &[],
- kernel::fs_entries![
- file("test1", 0o600, "abc\n".as_bytes(), FsFile),
- file("test2", 0o600, "def\n".as_bytes(), FsFile),
- char("test3", 0o600, [].as_slice(), (10, 125)),
- sock("test4", 0o755, [].as_slice()),
- fifo("test5", 0o755, [].as_slice()),
- block("test6", 0o755, [].as_slice(), (1, 1)),
- dir(
- "dir1",
- 0o755,
- [].as_slice(),
- [
- file("test1", 0o600, "abc\n".as_bytes(), FsFile),
- file("test2", 0o600, "def\n".as_bytes(), FsFile),
- ]
- ),
- ],
+
+ let file = file::RegularFile::from_path_in_root_mnt(
+ &arc_vfs_mount,
+ c_str!("997eed138af30d187e87d682dd2ae9f240fae78f668907a0519460b397c82467"),
+ file::flags::O_RDONLY.try_into().unwrap(),
+ 0,
)?;
+
+ // TODO: figure out how to go from WireFormatError to kernel::error::Error
+ let metadata = MetadataBlob::new(file).map_err(|_| EINVAL)?;
+
+ let mut puzzlefs = PuzzleFS::new(metadata).map_err(|_| EINVAL)?;
+ let root_inode = Arc::try_new(puzzlefs.find_inode(1).map_err(|_| EINVAL)?)?;
+
+ let root = try_new_populated_root_puzzlefs_dentry(&sb, &mut puzzlefs, root_inode)?;
let sb = sb.init_root(root)?;
Ok(sb)
}
@@ -110,7 +178,7 @@ fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self>) -> Result<&fs::SuperBl
#[vtable]
impl file::Operations for FsFile {
// must be the same as INodeData
- type OpenData = &'static [u8];
+ type OpenData = Arc<Inode>;
type Filesystem = PuzzleFsModule;
// this is an Arc because Data must be ForeignOwnable and the only implementors of it are Box,
// Arc and (); we cannot pass a reference to read, so we share Vfsmount using and Arc
@@ -126,14 +194,19 @@ fn open(
fn read(
data: ArcBorrow<'_, Vfsmount>,
- file: &file::File,
+ _file: &file::File,
writer: &mut impl IoBufferWriter,
offset: u64,
) -> Result<usize> {
- file::read_from_slice(
- file.inode::<PuzzleFsModule>().ok_or(EINVAL)?.fs_data(),
- writer,
- offset,
- )
+ let mut buf = Vec::try_with_capacity(writer.len())?;
+ buf.try_resize(writer.len(), 0)?;
+ let file = file::RegularFile::from_path_in_root_mnt(
+ &data,
+ c_str!("data"),
+ file::flags::O_RDONLY.try_into().unwrap(),
+ 0,
+ )?;
+ let nr_bytes_read = file.read_with_offset(&mut buf[..], offset)?;
+ file::read_from_slice(&buf[..nr_bytes_read], writer, 0)
}
}