feat: add basic fat32 read functionality
This commit is contained in:
Generated
+9
@@ -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"
|
||||
|
||||
@@ -11,6 +11,7 @@ edition = "2018"
|
||||
members = [
|
||||
"fs/vfs",
|
||||
"fs/memfs",
|
||||
"fs/fat32",
|
||||
"libcommon",
|
||||
"kernel",
|
||||
"libusr",
|
||||
|
||||
@@ -107,6 +107,7 @@ endif
|
||||
test:
|
||||
cd fs/vfs && cargo test
|
||||
cd fs/memfs && cargo test
|
||||
cd fs/fat32 && cargo test
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
|
||||
@@ -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" }
|
||||
@@ -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],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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!()
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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 {}
|
||||
|
||||
Reference in New Issue
Block a user