feat: add basic fat32 read functionality

This commit is contained in:
2021-10-29 11:31:05 +03:00
parent b6a0710f0c
commit 9f62396ebc
16 changed files with 695 additions and 202 deletions
Generated
+9
View File
@@ -56,6 +56,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fat32"
version = "0.1.0"
dependencies = [
"error",
"libcommon",
"vfs",
]
[[package]]
name = "fdt-rs"
version = "0.4.3"
+1
View File
@@ -11,6 +11,7 @@ edition = "2018"
members = [
"fs/vfs",
"fs/memfs",
"fs/fat32",
"libcommon",
"kernel",
"libusr",
+1
View File
@@ -107,6 +107,7 @@ endif
test:
cd fs/vfs && cargo test
cd fs/memfs && cargo test
cd fs/fat32 && cargo test
clean:
cargo clean
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "fat32"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
vfs = { path = "../vfs" }
libcommon = { path = "../../libcommon" }
error = { path = "../../error" }
+218
View File
@@ -0,0 +1,218 @@
use crate::{Bpb, FileInode};
use alloc::{borrow::ToOwned, boxed::Box, string::String};
use core::ffi::c_void;
use error::Errno;
use libcommon::{read_le16, read_le32};
use vfs::{BlockDevice, Vnode, VnodeImpl, VnodeKind, VnodeRef};
pub struct DirectoryInode {
pub cluster: u32,
}
pub struct FatIterator<'a> {
dev: &'a dyn BlockDevice,
sector: u32,
sector_off: usize,
len: u32,
lfn: [u8; 128],
lfn_len: u8,
buf: [u8; 512],
}
#[derive(Debug)]
pub struct Dirent {
pub name: String,
pub size: u32,
pub attrs: u8,
pub cluster: u32,
}
impl VnodeImpl for DirectoryInode {
fn create(
&mut self,
_parent: VnodeRef,
_name: &str,
_kind: VnodeKind,
) -> Result<VnodeRef, Errno> {
todo!()
}
fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> {
todo!()
}
fn lookup(&mut self, parent: VnodeRef, name: &str) -> Result<VnodeRef, Errno> {
let fs = parent.fs().unwrap();
let dirent = {
let dev = fs.clone().dev().unwrap();
let fs_data = fs.data();
let bpb: &Bpb = fs_data.as_ref().and_then(|e| e.downcast_ref()).unwrap();
let sector = bpb.cluster_base_sector(self.cluster);
FatIterator::new(dev, sector, bpb.sectors_per_cluster)
.find(|ent| ent.name == name)
.ok_or(Errno::DoesNotExist)
}?;
let kind = if dirent.attrs & 0x10 != 0 {
VnodeKind::Directory
} else {
VnodeKind::Regular
};
let vnode = Vnode::new(&dirent.name, kind, Vnode::SEEKABLE);
if kind == VnodeKind::Directory {
vnode.set_data(Box::new(DirectoryInode {
cluster: dirent.cluster,
}));
} else {
vnode.set_data(Box::new(FileInode {
cluster: dirent.cluster,
size: dirent.size,
}));
}
Ok(vnode)
}
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
todo!()
}
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
todo!()
}
fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result<usize, Errno> {
todo!()
}
fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result<usize, Errno> {
todo!()
}
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
todo!()
}
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
todo!()
}
fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result<isize, Errno> {
todo!()
}
}
impl Iterator for FatIterator<'_> {
type Item = Dirent;
fn next(&mut self) -> Option<Dirent> {
loop {
if self.len == 0 {
return None;
}
if self.sector_off == 0 {
self.dev
.read(self.sector as usize * 512, &mut self.buf)
.unwrap();
}
while self.sector_off < 512 {
let off = self.sector_off;
if self.buf[off] == 0 {
self.len = 0;
return None;
}
self.sector_off += 32;
// Check for LFN entries
if self.buf[off + 11] == 0x0F {
let lfn_order = self.buf[off];
let lfn_index = (lfn_order & 0x3F) as usize;
assert!(lfn_index > 0);
let mut lfn8 = [0u8; 13];
for j in 0..5 {
lfn8[j] = self.buf[off + 1 + j * 2];
}
for j in 0..6 {
lfn8[j + 5] = self.buf[off + 14 + j * 2];
}
for j in 0..2 {
lfn8[j + 11] = self.buf[off + 28 + j * 2];
}
let len = lfn8.iter().position(|&c| c == 0).unwrap_or(13);
let off = (lfn_index - 1) * 13;
if lfn_order & 0x40 != 0 {
// Last entry
self.lfn_len = (off + len) as u8;
} else {
assert_eq!(len, 13);
}
self.lfn[off..off + len].copy_from_slice(&lfn8[..len]);
} else {
let size = read_le32(&self.buf[off + 28..]);
let attrs = self.buf[off + 11];
let cluster = ((read_le16(&self.buf[off + 20..]) as u32) << 16)
| (read_le16(&self.buf[off + 26..]) as u32);
if self.lfn_len != 0 {
let len = self.lfn_len as usize;
self.lfn_len = 0;
return Some(Dirent {
name: core::str::from_utf8(&self.lfn[..len as usize])
.unwrap()
.to_owned(),
attrs,
size,
cluster,
});
} else {
let len = self.buf[off..off + 11]
.iter()
.position(|&c| (c == 0) || (c == b' '))
.unwrap_or(11);
let name =
core::str::from_utf8(&self.buf[off..off + core::cmp::min(len, 8)])
.unwrap()
.to_owned();
let ext = if len > 8 {
".".to_owned()
+ core::str::from_utf8(&self.buf[off + 8..off + len]).unwrap()
} else {
"".to_owned()
};
return Some(Dirent {
name: name + &ext,
attrs,
size,
cluster,
});
}
}
}
self.sector_off = 0;
self.len -= 1;
self.sector += 1;
}
}
}
impl FatIterator<'_> {
pub fn new(dev: &'static dyn BlockDevice, sector: u32, sectors_per_cluster: u8) -> Self {
Self {
dev,
sector,
len: sectors_per_cluster as u32,
sector_off: 0,
lfn_len: 0,
lfn: [0; 128],
buf: [0; 512],
}
}
}
+80
View File
@@ -0,0 +1,80 @@
use vfs::{VnodeImpl, VnodeRef, VnodeKind};
use core::ffi::c_void;
use error::Errno;
use crate::Bpb;
pub struct FileInode {
pub cluster: u32,
pub size: u32
}
impl VnodeImpl for FileInode {
fn create(&mut self, _at: VnodeRef, _name: &str, _kind: VnodeKind) -> Result<VnodeRef, Errno> {
panic!()
}
fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> {
panic!()
}
fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
panic!()
}
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Ok(0)
}
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
todo!()
}
fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
let size = self.size as usize;
if pos >= size {
return Ok(0);
}
let fs = node.fs().unwrap();
let dev = fs.clone().dev().unwrap();
let fs_data = fs.data();
let bpb: &Bpb = fs_data.as_ref().and_then(|e| e.downcast_ref()).unwrap();
let base_sector = bpb.cluster_base_sector(self.cluster);
let mut rem = core::cmp::min(size - pos, data.len());
let mut off = 0usize;
let mut buf = [0; 512];
while rem != 0 {
let sector_index = (pos + off) / 512;
let sector_offset = (pos + off) % 512;
let count = core::cmp::min(rem, 512 - sector_offset);
dev.read((base_sector as usize + sector_index) * 512, &mut buf)?;
let src = &buf[sector_offset..sector_offset + count];
let dst = &mut data[off..off + count];
dst.copy_from_slice(src);
rem -= count;
off += count;
}
Ok(off)
}
fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result<usize, Errno> {
todo!()
}
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
todo!()
}
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
todo!()
}
fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result<isize, Errno> {
todo!()
}
}
+163
View File
@@ -0,0 +1,163 @@
#![no_std]
#[cfg(test)]
#[macro_use]
extern crate std;
extern crate alloc;
use alloc::{rc::Rc, boxed::Box};
use core::any::Any;
use core::cell::{Ref, RefCell};
use error::Errno;
use libcommon::{read_le16, read_le32};
use vfs::{BlockDevice, Filesystem, Vnode, VnodeKind, VnodeRef};
pub mod dir;
pub use dir::{Dirent as FatEntry, FatIterator, DirectoryInode};
pub mod file;
pub use file::FileInode;
#[derive(Debug)]
struct Bpb {
sectors_per_cluster: u8,
reserved_sectors: u16,
fat_count: u8,
sectors_per_fat: u32,
}
pub struct Fat32 {
bpb: RefCell<Bpb>,
root: RefCell<Option<VnodeRef>>,
dev: &'static dyn BlockDevice,
}
impl Bpb {
pub const fn cluster_base_sector(&self, cluster: u32) -> u32 {
let first_data_sector = self.reserved_sectors as u32
+ (self.fat_count as u32 * self.sectors_per_fat as u32);
((cluster - 2) * self.sectors_per_cluster as u32) + first_data_sector
}
}
impl Filesystem for Fat32 {
fn root(self: Rc<Self>) -> Result<VnodeRef, Errno> {
self.root.borrow().clone().ok_or(Errno::DoesNotExist)
}
fn dev(self: Rc<Self>) -> Option<&'static dyn BlockDevice> {
Some(self.dev)
}
fn data(&self) -> Option<Ref<dyn Any>> {
Some(self.bpb.borrow())
}
}
impl Fat32 {
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind, cluster: u32) -> VnodeRef {
let res = Vnode::new(name, kind, Vnode::SEEKABLE);
res.set_fs(self.clone());
res.set_data(match kind {
VnodeKind::Directory => Box::new(DirectoryInode { cluster }),
_ => todo!(),
});
res
}
pub fn open(dev: &'static dyn BlockDevice) -> Result<Rc<Self>, Errno> {
let mut buf = [0u8; 512];
dev.read(0, &mut buf)?;
if buf[0x42] != 0x28 && buf[0x42] != 0x29 {
panic!("Not a FAT32");
}
let root_cluster = read_le32(&buf[44..]);
let res = Rc::new(Self {
bpb: RefCell::new(Bpb {
fat_count: buf[16],
reserved_sectors: read_le16(&buf[14..]),
sectors_per_cluster: buf[13],
sectors_per_fat: read_le32(&buf[36..]),
}),
dev,
root: RefCell::new(None),
});
*res.root.borrow_mut() = Some(res.clone().create_node(
"",
VnodeKind::Directory,
root_cluster,
));
Ok(res)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use libcommon::{Read as LRead};
use vfs::Ioctx;
struct FileBlockDevice {
file: RefCell<Option<File>>,
}
impl FileBlockDevice {
pub const fn new() -> Self {
Self {
file: RefCell::new(None),
}
}
pub fn open(&self, path: &str) {
*self.file.borrow_mut() = Some(File::open(path).unwrap());
}
}
impl BlockDevice for FileBlockDevice {
fn read(&self, pos: usize, buf: &mut [u8]) -> Result<(), Errno> {
let mut borrow = self.file.borrow_mut();
let file = borrow.as_mut().unwrap();
file.seek(SeekFrom::Start(pos as u64)).unwrap();
if file.read(buf).unwrap() != buf.len() {
Err(Errno::InvalidArgument)
} else {
Ok(())
}
}
fn write(&self, _pos: usize, _buf: &[u8]) -> Result<(), Errno> {
todo!()
}
}
unsafe impl Sync for FileBlockDevice {}
#[test]
fn test_fat32_open() {
static DEV: FileBlockDevice = FileBlockDevice::new();
DEV.open("test/test0.img");
let fs = Fat32::open(&DEV).unwrap();
let root = fs.root().unwrap();
let ioctx = Ioctx::new(root);
let mut buf = [0u8; 512];
let node0 = ioctx.find(None, "FILENAME.TXT").unwrap();
let mut file = node0.open().unwrap();
let count = file.read(&mut buf).unwrap();
assert_eq!(count, 15);
assert_eq!(&buf[..15], b"This is a file\n");
}
}
Binary file not shown.
+13 -13
View File
@@ -40,14 +40,16 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
}
#[cfg(feature = "cow")]
pub fn is_cow(&self) -> bool {
!self.cow_source.is_null()
pub unsafe fn new_copy_on_write(alloc: A, cow_source: *const u8, cow_len: usize) -> Self {
let mut res = Bvec::new(alloc);
res.cow_source = cow_source;
res.size = cow_len;
res
}
#[cfg(feature = "cow")]
pub unsafe fn setup_cow(&mut self, src: *const u8, size: usize) {
self.cow_source = src;
self.size = size;
pub fn is_cow(&self) -> bool {
!self.cow_source.is_null()
}
pub const fn size(&self) -> usize {
@@ -305,12 +307,13 @@ mod cow_tests {
#[test]
fn bvec_write_copy_simple() {
let mut bvec = Bvec::new(TestAlloc {});
//let mut bvec = Bvec::new(TestAlloc {});
let mut buf = [0u8; 512];
let source_data = b"This is initial data\n";
unsafe {
bvec.setup_cow(source_data.as_ptr(), source_data.len());
}
//unsafe {
// bvec.setup_cow(source_data.as_ptr(), source_data.len());
//}
let mut bvec = unsafe { Bvec::new_copy_on_write(TestAlloc {}, source_data.as_ptr(), source_data.len()) };
assert!(bvec.is_cow());
assert_eq!(bvec.size(), source_data.len());
assert_eq!(bvec.capacity, 0);
@@ -327,15 +330,12 @@ mod cow_tests {
#[test]
fn bvec_write_copy_l0() {
let mut bvec = Bvec::new(TestAlloc {});
let mut source_data = [0u8; 4096 * 2 - 2];
let mut buf = [0u8; 512];
for i in 0..source_data.len() {
source_data[i] = (i & 0xFF) as u8;
}
unsafe {
bvec.setup_cow(source_data.as_ptr(), source_data.len());
}
let mut bvec = unsafe { Bvec::new_copy_on_write(TestAlloc {}, source_data.as_ptr(), source_data.len()) };
assert!(bvec.is_cow());
assert_eq!(bvec.size(), source_data.len());
assert_eq!(bvec.capacity, 0);
+85 -58
View File
@@ -12,11 +12,12 @@ extern crate alloc;
extern crate std;
use alloc::{boxed::Box, rc::Rc};
use core::cell::RefCell;
use core::cell::{RefCell, Ref};
use core::ffi::c_void;
use error::Errno;
use libcommon::path_component_left;
use vfs::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef};
use libcommon::*;
use vfs::{Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef, BlockDevice};
use core::any::Any;
pub mod block;
pub use block::{BlockAllocator, BlockRef};
@@ -36,14 +37,17 @@ pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> {
pub struct DirInode;
struct SetupFileParam {
data: &'static [u8],
}
const FILE_SETUP_COW: u64 = 0x1001;
impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
fn create(&mut self, _parent: VnodeRef, _node: VnodeRef) -> Result<(), Errno> {
fn create(
&mut self,
_parent: VnodeRef,
_name: &str,
_kind: VnodeKind,
) -> Result<VnodeRef, Errno> {
panic!()
}
fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
panic!()
}
@@ -75,24 +79,23 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
Ok(self.data.size())
}
fn ioctl(&mut self, _node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
match cmd {
#[cfg(feature = "cow")]
FILE_SETUP_COW => {
let data = unsafe { (value as *mut SetupFileParam).as_ref().unwrap() };
unsafe {
self.data.setup_cow(data.data.as_ptr(), data.data.len());
}
Ok(0)
}
_ => Err(Errno::InvalidArgument),
}
fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result<isize, Errno> {
todo!()
}
}
impl VnodeImpl for DirInode {
fn create(&mut self, _parent: VnodeRef, _node: VnodeRef) -> Result<(), Errno> {
Ok(())
fn create(
&mut self,
_parent: VnodeRef,
_name: &str,
_kind: VnodeKind,
) -> Result<VnodeRef, Errno> {
todo!()
}
fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
panic!()
}
fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> {
@@ -133,20 +136,28 @@ impl<A: BlockAllocator + Copy + 'static> Filesystem for Ramfs<A> {
self.root.borrow().clone().ok_or(Errno::DoesNotExist)
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind, Vnode::SEEKABLE);
let data: Box<dyn VnodeImpl> = match kind {
VnodeKind::Regular => Box::new(FileInode {
data: Bvec::new(self.alloc),
}),
VnodeKind::Directory => Box::new(DirInode {}),
};
node.set_data(VnodeData {
fs: self,
node: data,
});
Ok(node)
fn data(&self) -> Option<Ref<dyn Any>> {
None
}
fn dev(self: Rc<Self>) -> Option<&'static dyn BlockDevice> {
None
}
// fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
// let node = Vnode::new(name, kind, Vnode::SEEKABLE);
// let data: Box<dyn VnodeImpl> = match kind {
// VnodeKind::Regular => Box::new(FileInode {
// data: Bvec::new(self.alloc),
// }),
// VnodeKind::Directory => Box::new(DirInode {}),
// };
// node.set_data(VnodeData {
// fs: self,
// node: data,
// });
// Ok(node)
// }
}
impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
@@ -159,22 +170,28 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
Ok(res)
}
fn create_node_initial(self: Rc<Self>, name: &str, kind: VnodeKind) -> VnodeRef {
let node = Vnode::new(name, kind, Vnode::SEEKABLE);
node.set_fs(self.clone());
match kind {
VnodeKind::Directory => node.set_data(Box::new(DirInode {})),
VnodeKind::Regular => {}
};
node
}
fn make_path(
self: Rc<Self>,
at: VnodeRef,
path: &str,
kind: VnodeKind,
do_create: bool,
) -> Result<VnodeRef, Errno> {
if path.is_empty() {
return Ok(at);
}
let (element, rest) = path_component_left(path);
assert!(!element.is_empty());
let node_kind = if rest.is_empty() {
kind
} else {
VnodeKind::Directory
};
let node = at.lookup(element);
let node = match node {
Some(node) => node,
@@ -182,7 +199,10 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
if !do_create {
return Err(Errno::DoesNotExist);
}
let node = self.clone().create_node(element, node_kind)?;
// TODO use at.create() instead?
let node = self
.clone()
.create_node_initial(element, VnodeKind::Directory);
at.attach(node.clone());
node
}
@@ -191,38 +211,45 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
if rest.is_empty() {
Ok(node)
} else {
self.make_path(node, rest, kind, do_create)
self.make_path(node, rest, do_create)
}
}
unsafe fn load_tar(self: Rc<Self>, base: *const u8, size: usize) -> Result<VnodeRef, Errno> {
let root = self.clone().create_node("", VnodeKind::Directory)?;
let root = self.clone().create_node_initial("", VnodeKind::Directory);
// 1. Create all the paths in TAR
for block in TarIterator::new(base, base.add(size)) {
let node =
self.clone()
.make_path(root.clone(), block.path()?, block.node_kind(), true)?;
let (dirname, basename) = path_component_right(block.path()?);
let parent = self.clone().make_path(root.clone(), dirname, true)?;
let node = self
.clone()
.create_node_initial(basename, block.node_kind());
assert_eq!(node.kind(), block.node_kind());
parent.attach(node);
}
// 2. Setup data blocks
for block in TarIterator::new(base, base.add(size)) {
if block.is_file() {
let node = self.clone().make_path(
root.clone(),
block.path()?,
block.node_kind(),
false,
)?;
// Will not create any dirs
let node = self.clone().make_path(root.clone(), block.path()?, false)?;
assert_eq!(node.kind(), block.node_kind());
#[cfg(feature = "cow")]
{
let mut param = SetupFileParam { data: block.data() };
node.ioctl(FILE_SETUP_COW, &mut param as *mut _ as *mut _)?;
let data = block.data();
node.set_data(Box::new(FileInode {
data: Bvec::new_copy_on_write(self.alloc, data.as_ptr(), data.len()),
}));
}
#[cfg(not(feature = "cow"))]
{
node.set_data(Box::new(FileInode {
data: Bvec::new(self.alloc)
}));
let size = block.size();
node.truncate(size)?;
if node.write(0, block.data())? != size {
+11 -21
View File
@@ -79,23 +79,28 @@ impl File {
#[cfg(test)]
mod tests {
use super::*;
use crate::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef};
use crate::{Vnode, VnodeImpl, VnodeKind, VnodeRef};
use alloc::boxed::Box;
use alloc::rc::Rc;
use core::ffi::c_void;
pub struct DummyInode;
pub struct DummyFs;
impl VnodeImpl for DummyInode {
fn create(&mut self, _at: VnodeRef, _node: VnodeRef) -> Result<(), Errno> {
Err(Errno::NotImplemented)
fn create(&mut self, _at: VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind, 0);
node.set_data(Box::new(DummyInode {}));
Ok(node)
}
fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> {
Err(Errno::NotImplemented)
}
fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
todo!()
}
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Ok(0)
}
@@ -138,25 +143,10 @@ mod tests {
}
}
impl Filesystem for DummyFs {
fn root(self: Rc<Self>) -> Result<VnodeRef, Errno> {
todo!()
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind, 0);
node.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: self,
});
Ok(node)
}
}
#[test]
fn test_normal_read() {
let fs = Rc::new(DummyFs {});
let node = fs.create_node("", VnodeKind::Regular).unwrap();
let node = Vnode::new("", VnodeKind::Regular, 0);
node.set_data(Box::new(DummyInode {}));
let mut file = node.open().unwrap();
match &file.inner {
+5 -2
View File
@@ -1,8 +1,11 @@
use crate::{VnodeKind, VnodeRef};
use crate::{VnodeRef, BlockDevice};
use core::cell::Ref;
use core::any::Any;
use alloc::rc::Rc;
use error::Errno;
pub trait Filesystem {
fn root(self: Rc<Self>) -> Result<VnodeRef, Errno>;
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno>;
fn dev(self: Rc<Self>) -> Option<&'static dyn BlockDevice>;
fn data<'a>(&'a self) -> Option<Ref<'a, dyn Any>>;
}
+20 -36
View File
@@ -40,7 +40,7 @@ impl Ioctx {
}
assert!(!element.is_empty());
let node = at.lookup(element).ok_or(Errno::DoesNotExist)?;
let node = at.lookup_or_load(element)?;
if rest.is_empty() {
Ok(node)
@@ -62,55 +62,58 @@ impl Ioctx {
self._find(at, path)
}
pub fn mkdir(&self, at: Option<VnodeRef>, path: &str, mode: FileMode) -> Result<(), Errno> {
pub fn mkdir(&self, at: Option<VnodeRef>, path: &str, mode: FileMode) -> Result<VnodeRef, Errno> {
let (parent, name) = path_component_right(path);
let parent_node = self.find(at, parent)?;
parent_node.mkdir(name, mode).map(|_| ())
self.find(at, parent)?.mkdir(name, mode)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind};
use crate::{Vnode, VnodeImpl, VnodeKind};
use alloc::{boxed::Box, rc::Rc};
use core::ffi::c_void;
pub struct DummyInode;
pub struct DummyFs;
impl VnodeImpl for DummyInode {
fn create(&mut self, _at: VnodeRef, _node: VnodeRef) -> Result<(), Errno> {
Err(Errno::NotImplemented)
fn create(&mut self, _at: VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let vnode = Vnode::new(name, kind, 0);
vnode.set_data(Box::new(DummyInode {}));
Ok(vnode)
}
fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
Err(Errno::DoesNotExist)
}
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
todo!()
}
fn ioctl(
@@ -119,23 +122,8 @@ mod tests {
_cmd: u64,
_value: *mut c_void,
) -> Result<isize, Errno> {
Err(Errno::NotImplemented)
}
}
impl Filesystem for DummyFs {
fn root(self: Rc<Self>) -> Result<VnodeRef, Errno> {
todo!()
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind, 0);
node.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: self,
});
Ok(node)
}
}
#[test]
@@ -220,14 +208,10 @@ mod tests {
#[test]
fn test_mkdir() {
let fs = Rc::new(DummyFs {});
let root = Vnode::new("", VnodeKind::Directory, 0);
let ioctx = Ioctx::new(root.clone());
root.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: fs.clone(),
});
root.set_data(Box::new(DummyInode {}));
assert!(ioctx.mkdir(None, "/dir0", FileMode::default_dir()).is_ok());
assert_eq!(
+67 -69
View File
@@ -18,13 +18,6 @@ pub struct TreeNode {
children: Vec<VnodeRef>,
}
pub struct VnodeData {
// Filesystem itself
pub fs: Rc<dyn Filesystem>,
// Something like "inode" struct + "ops" table
pub node: Box<dyn VnodeImpl>,
}
pub struct VnodeProps {
mode: FileMode,
}
@@ -37,12 +30,15 @@ pub struct Vnode {
kind: VnodeKind,
flags: u32,
pub data: RefCell<Option<VnodeData>>,
fs: RefCell<Option<Rc<dyn Filesystem>>>,
data: RefCell<Option<Box<dyn VnodeImpl>>>,
}
pub trait VnodeImpl {
fn create(&mut self, at: VnodeRef, node: VnodeRef) -> Result<(), Errno>;
// Directory-only operations
fn create(&mut self, at: VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno>;
fn remove(&mut self, at: VnodeRef, name: &str) -> Result<(), Errno>;
fn lookup(&mut self, at: VnodeRef, name: &str) -> Result<VnodeRef, Errno>;
fn open(&mut self, node: VnodeRef /* TODO open mode */) -> Result<usize, Errno>;
fn close(&mut self, node: VnodeRef) -> Result<(), Errno>;
@@ -70,18 +66,27 @@ impl Vnode {
parent: None,
children: Vec::new(),
}),
fs: RefCell::new(None),
data: RefCell::new(None),
})
}
pub fn set_data(&self, data: VnodeData) {
pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
*self.data.borrow_mut() = Some(data);
}
pub fn data(&self) -> RefMut<Option<VnodeData>> {
pub fn set_fs(&self, fs: Rc<dyn Filesystem>) {
*self.fs.borrow_mut() = Some(fs);
}
pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
self.data.borrow_mut()
}
pub fn fs(&self) -> Option<Rc<dyn Filesystem>> {
self.fs.borrow().clone()
}
pub fn is_directory(&self) -> bool {
self.kind == VnodeKind::Directory
}
@@ -134,26 +139,40 @@ impl Vnode {
.cloned()
}
pub fn lookup_or_load(self: &VnodeRef, name: &str) -> Result<VnodeRef, Errno> {
if let Some(node) = self.lookup(name) {
return Ok(node);
}
if let Some(ref mut data) = *self.data() {
let vnode = data.lookup(self.clone(), name)?;
if let Some(fs) = self.fs() {
vnode.set_fs(fs);
}
self.attach(vnode.clone());
Ok(vnode)
} else {
Err(Errno::NotImplemented)
}
}
pub fn mkdir(self: &VnodeRef, name: &str, mode: FileMode) -> Result<VnodeRef, Errno> {
if self.kind != VnodeKind::Directory {
return Err(Errno::NotADirectory);
}
if self.lookup(name).is_some() {
return Err(Errno::AlreadyExists);
}
match self.lookup_or_load(name) {
Err(Errno::DoesNotExist) => {},
Ok(_) => return Err(Errno::AlreadyExists),
e => return e,
};
if let Some(ref mut data) = *self.data.borrow_mut() {
let vnode = data.fs.clone().create_node(name, VnodeKind::Directory)?;
vnode.props.borrow_mut().mode = mode;
if let Err(err) = data.node.create(self.clone(), vnode.clone()) {
if err != Errno::NotImplemented {
return Err(err);
}
if let Some(ref mut data) = *self.data() {
let vnode = data.create(self.clone(), name, VnodeKind::Directory)?;
if let Some(fs) = self.fs() {
vnode.set_fs(fs);
}
vnode.props.borrow_mut().mode = mode;
self.attach(vnode.clone());
Ok(vnode)
} else {
@@ -166,15 +185,9 @@ impl Vnode {
return Err(Errno::NotADirectory);
}
if let Some(ref mut data) = *self.data.borrow_mut() {
if let Some(ref mut data) = *self.data() {
let vnode = self.lookup(name).ok_or(Errno::DoesNotExist)?;
if let Err(err) = data.node.remove(self.clone(), name) {
if err != Errno::NotImplemented {
return Err(err);
}
}
data.remove(self.clone(), name)?;
vnode.detach();
Ok(())
} else {
@@ -187,8 +200,8 @@ impl Vnode {
return Err(Errno::IsADirectory);
}
if let Some(ref mut data) = *self.data.borrow_mut() {
let pos = data.node.open(self.clone())?;
if let Some(ref mut data) = *self.data() {
let pos = data.open(self.clone())?;
Ok(File::normal(self.clone(), pos))
} else {
Err(Errno::NotImplemented)
@@ -200,8 +213,8 @@ impl Vnode {
return Err(Errno::IsADirectory);
}
if let Some(ref mut data) = *self.data.borrow_mut() {
data.node.read(self.clone(), pos, buf)
if let Some(ref mut data) = *self.data() {
data.read(self.clone(), pos, buf)
} else {
Err(Errno::NotImplemented)
}
@@ -212,8 +225,8 @@ impl Vnode {
return Err(Errno::IsADirectory);
}
if let Some(ref mut data) = *self.data.borrow_mut() {
data.node.write(self.clone(), pos, buf)
if let Some(ref mut data) = *self.data() {
data.write(self.clone(), pos, buf)
} else {
Err(Errno::NotImplemented)
}
@@ -224,24 +237,24 @@ impl Vnode {
return Err(Errno::IsADirectory);
}
if let Some(ref mut data) = *self.data.borrow_mut() {
data.node.truncate(self.clone(), size)
if let Some(ref mut data) = *self.data() {
data.truncate(self.clone(), size)
} else {
Err(Errno::NotImplemented)
}
}
pub fn size(self: &VnodeRef) -> Result<usize, Errno> {
if let Some(ref mut data) = *self.data.borrow_mut() {
data.node.size(self.clone())
if let Some(ref mut data) = *self.data() {
data.size(self.clone())
} else {
Err(Errno::NotImplemented)
}
}
pub fn ioctl(self: &VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
if let Some(ref mut data) = *self.data.borrow_mut() {
data.node.ioctl(self.clone(), cmd, value)
if let Some(ref mut data) = *self.data() {
data.ioctl(self.clone(), cmd, value)
} else {
Err(Errno::NotImplemented)
}
@@ -257,18 +270,22 @@ impl fmt::Debug for Vnode {
#[cfg(test)]
mod tests {
use super::*;
use crate::Filesystem;
pub struct DummyInode;
pub struct DummyFs;
impl VnodeImpl for DummyInode {
fn create(&mut self, _at: VnodeRef, _node: VnodeRef) -> Result<(), Errno> {
Err(Errno::NotImplemented)
fn create(&mut self, _at: VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind, 0);
node.set_data(Box::new(DummyInode {}));
Ok(node)
}
fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> {
Err(Errno::NotImplemented)
Ok(())
}
fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
Err(Errno::DoesNotExist)
}
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
@@ -305,21 +322,6 @@ mod tests {
}
}
impl Filesystem for DummyFs {
fn root(self: Rc<Self>) -> Result<VnodeRef, Errno> {
todo!()
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind, 0);
node.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: self,
});
Ok(node)
}
}
#[test]
fn test_parent() {
let root = Vnode::new("", VnodeKind::Directory, 0);
@@ -333,13 +335,9 @@ mod tests {
#[test]
fn test_mkdir_unlink() {
let fs = Rc::new(DummyFs {});
let root = Vnode::new("", VnodeKind::Directory, 0);
root.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: fs.clone(),
});
root.set_data(Box::new(DummyInode {}));
let node = root.mkdir("test", FileMode::default_dir()).unwrap();
+1 -1
View File
@@ -59,7 +59,7 @@ pub fn local_timer() -> &'static GenericTimer {
}
static IRQCHIP: Bcm283xIrqchip = Bcm283xIrqchip::new();
static EMMC: MassMediaController = unsafe { MassMediaController::new(EMMC_BASE) };
pub static EMMC: MassMediaController = unsafe { MassMediaController::new(EMMC_BASE) };
static UART: Pl011 = unsafe { Pl011::new(UART_BASE, UART_IRQ) };
pub(self) static BCM_MBOX: Bcm283xMailbox = unsafe { Bcm283xMailbox::new(BCM_MBOX_BASE) };
static LOCAL_TIMER: GenericTimer = GenericTimer::new(LOCAL_TIMER_IRQ);
+10 -2
View File
@@ -30,12 +30,20 @@ pub fn path_component_left(path: &str) -> (&str, &str) {
}
pub fn path_component_right(path: &str) -> (&str, &str) {
if let Some((left, right)) = path.rsplit_once('/') {
if let Some((left, right)) = path.trim_end_matches('/').rsplit_once('/') {
(left.trim_end_matches('/'), right)
} else {
(path, "")
("", path)
}
}
pub fn read_le32(src: &[u8]) -> u32 {
(src[0] as u32) | ((src[1] as u32) << 8) | ((src[2] as u32) << 16) | ((src[3] as u32) << 24)
}
pub fn read_le16(src: &[u8]) -> u16 {
(src[0] as u16) | ((src[1] as u16) << 8)
}
#[cfg(test)]
mod tests {}