split SFS & SEFS to crates

master
WangRunji 6 years ago
parent 32a3a8c8b1
commit 170cc932be

@ -1,5 +1,7 @@
[workspace] [workspace]
members = [ members = [
"rcore-fs", "rcore-fs",
"rcore-fs-sfs",
"rcore-fs-sefs",
"rcore-fs-fuse" "rcore-fs-fuse"
] ]

@ -12,3 +12,5 @@ fuse = "0.3"
structopt = "0.2" structopt = "0.2"
env_logger = "0.3" env_logger = "0.3"
rcore-fs = { path = "../rcore-fs", features = ["std"] } rcore-fs = { path = "../rcore-fs", features = ["std"] }
rcore-fs-sfs = { path = "../rcore-fs-sfs", features = ["std"] }
rcore-fs-sefs = { path = "../rcore-fs-sefs", features = ["std"] }

@ -9,7 +9,9 @@ use fuse::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory,
use structopt::StructOpt; use structopt::StructOpt;
use time::Timespec; use time::Timespec;
use rcore_fs::{sfs, sefs, vfs}; use rcore_fs::vfs;
use rcore_fs_sfs as sfs;
use rcore_fs_sefs as sefs;
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
@ -230,12 +232,12 @@ fn main() {
// let img = OpenOptions::new().read(true).write(true).open(&opt.image) // let img = OpenOptions::new().read(true).write(true).open(&opt.image)
// .expect("failed to open image"); // .expect("failed to open image");
let sfs = if opt.image.is_dir() { let sfs = if opt.image.is_dir() {
let img = sefs::std_impl::StdStorage::new(&opt.image); let img = sefs::dev::StdStorage::new(&opt.image);
sefs::SEFS::open(Box::new(img)) sefs::SEFS::open(Box::new(img))
.expect("failed to open sefs") .expect("failed to open sefs")
} else { } else {
std::fs::create_dir_all(&opt.image).unwrap(); std::fs::create_dir_all(&opt.image).unwrap();
let img = sefs::std_impl::StdStorage::new(&opt.image); let img = sefs::dev::StdStorage::new(&opt.image);
sefs::SEFS::create(Box::new(img)) sefs::SEFS::create(Box::new(img))
.expect("failed to create sefs") .expect("failed to create sefs")
}; };

@ -0,0 +1,19 @@
[package]
name = "rcore-fs-sefs"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
edition = "2018"
[dependencies]
rcore-fs = { path = "../rcore-fs" }
static_assertions = "0.3"
spin = "0.4"
log = "0.4"
[dependencies.bitvec]
version = "0.9"
default-features = false
features = ["alloc"]
[features]
std = ["rcore-fs/std"]

@ -0,0 +1,44 @@
use alloc::boxed::Box;
use rcore_fs::vfs::FsError;
pub use self::std_impl::*;
mod std_impl;
/// A file stores a normal file or directory.
///
/// The interface is same as `std::fs::File`.
pub trait File: Send + Sync {
fn read_at(&self, buf: &mut [u8], offset: usize) -> DevResult<usize>;
fn write_at(&self, buf: &[u8], offset: usize) -> DevResult<usize>;
fn set_len(&self, len: usize) -> DevResult<()>;
fn flush(&self) -> DevResult<()>;
fn read_exact_at(&self, buf: &mut [u8], offset: usize) -> DevResult<()> {
let len = self.read_at(buf, offset)?;
if len == buf.len() { Ok(()) } else { Err(DeviceError) }
}
fn write_all_at(&self, buf: &[u8], offset: usize) -> DevResult<()> {
let len = self.write_at(buf, offset)?;
if len == buf.len() { Ok(()) } else { Err(DeviceError) }
}
}
/// The collection of all files in the FS.
pub trait Storage: Send + Sync {
fn open(&self, file_id: usize) -> DevResult<Box<File>>;
fn create(&self, file_id: usize) -> DevResult<Box<File>>;
fn remove(&self, file_id: usize) -> DevResult<()>;
}
#[derive(Debug)]
pub struct DeviceError;
pub type DevResult<T> = Result<T, DeviceError>;
impl From<DeviceError> for FsError {
fn from(_: DeviceError) -> Self {
FsError::DeviceError
}
}

@ -1,56 +1,25 @@
#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![feature(alloc)]
extern crate alloc;
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::{Arc, Weak}, vec::Vec}; use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::{Arc, Weak}, vec::Vec};
use core::any::Any; use core::any::Any;
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
use core::mem::uninitialized; use core::mem::uninitialized;
use bitvec::BitVec; use bitvec::BitVec;
use log::*; //use log::*;
use spin::{Mutex, RwLock}; use spin::RwLock;
use crate::dirty::Dirty; use rcore_fs::dirty::Dirty;
use crate::vfs::{self, FileSystem, FsError, INode, Timespec}; use rcore_fs::vfs::{self, FileSystem, FsError, INode, Timespec};
use self::dev::*;
use self::structs::*; use self::structs::*;
mod structs; mod structs;
pub mod std_impl; pub mod dev;
/// A file stores a normal file or directory.
///
/// The interface is same as `std::fs::File`.
pub trait File: Send + Sync {
fn read_at(&self, buf: &mut [u8], offset: usize) -> DevResult<usize>;
fn write_at(&self, buf: &[u8], offset: usize) -> DevResult<usize>;
fn set_len(&self, len: usize) -> DevResult<()>;
fn flush(&self) -> DevResult<()>;
fn read_exact_at(&self, buf: &mut [u8], offset: usize) -> DevResult<()> {
let len = self.read_at(buf, offset)?;
if len == buf.len() { Ok(()) } else { Err(DeviceError) }
}
fn write_all_at(&self, buf: &[u8], offset: usize) -> DevResult<()> {
let len = self.write_at(buf, offset)?;
if len == buf.len() { Ok(()) } else { Err(DeviceError) }
}
}
/// The collection of all files in the FS.
pub trait Storage: Send + Sync {
fn open(&self, file_id: usize) -> DevResult<Box<File>>;
fn create(&self, file_id: usize) -> DevResult<Box<File>>;
fn remove(&self, file_id: usize) -> DevResult<()>;
}
#[derive(Debug)]
pub struct DeviceError;
pub type DevResult<T> = Result<T, DeviceError>;
impl From<DeviceError> for FsError {
fn from(_: DeviceError) -> Self {
FsError::DeviceError
}
}
/// Helper methods for `File` /// Helper methods for `File`
impl File { impl File {
@ -413,7 +382,7 @@ impl Drop for INodeImpl {
if self.disk_inode.read().nlinks <= 0 { if self.disk_inode.read().nlinks <= 0 {
self.disk_inode.write().sync(); self.disk_inode.write().sync();
self.fs.free_block(self.id); self.fs.free_block(self.id);
self.fs.device.remove(self.id); self.fs.device.remove(self.id).unwrap();
} }
} }
} }

@ -0,0 +1,24 @@
[package]
name = "rcore-fs-sfs"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
edition = "2018"
[[bin]]
name = "mksfs"
path = "src/bin/mksfs.rs"
required-features = ["std"]
[dependencies]
rcore-fs = { path = "../rcore-fs" }
static_assertions = "0.3"
spin = "0.4"
log = "0.4"
[dependencies.bitvec]
version = "0.9"
default-features = false
features = ["alloc"]
[features]
std = ["rcore-fs/std"]

@ -3,8 +3,10 @@ use std::fs;
use std::io::{Read, Write, Result}; use std::io::{Read, Write, Result};
use std::path::Path; use std::path::Path;
use std::mem::uninitialized; use std::mem::uninitialized;
use std::sync::Arc; use std::sync::{Arc, Mutex};
use rcore_fs::{sfs::SimpleFileSystem, vfs::*};
use rcore_fs::vfs::*;
use rcore_fs_sfs::SimpleFileSystem;
fn main() -> Result<()> { fn main() -> Result<()> {
let args: Vec<_> = env::args().collect(); let args: Vec<_> = env::args().collect();
@ -23,6 +25,7 @@ fn main() -> Result<()> {
fn zip(path: &Path, img_path: &Path) -> Result<()> { fn zip(path: &Path, img_path: &Path) -> Result<()> {
let img = fs::OpenOptions::new().read(true).write(true).create(true).open(img_path)?; let img = fs::OpenOptions::new().read(true).write(true).create(true).open(img_path)?;
let img = Mutex::new(img);
let sfs = SimpleFileSystem::create(Box::new(img), 0x1000000); let sfs = SimpleFileSystem::create(Box::new(img), 0x1000000);
let inode = sfs.root_inode(); let inode = sfs.root_inode();
zip_dir(path, inode)?; zip_dir(path, inode)?;
@ -59,6 +62,7 @@ fn zip_dir(path: &Path, inode: Arc<INode>) -> Result<()> {
fn unzip(path: &Path, img_path: &Path) -> Result<()> { fn unzip(path: &Path, img_path: &Path) -> Result<()> {
let img = fs::File::open(img_path)?; let img = fs::File::open(img_path)?;
let img = Mutex::new(img);
let sfs = SimpleFileSystem::open(Box::new(img)).expect("Failed to open sfs"); let sfs = SimpleFileSystem::open(Box::new(img)).expect("Failed to open sfs");
let inode = sfs.root_inode(); let inode = sfs.root_inode();
fs::create_dir(&path)?; fs::create_dir(&path)?;

@ -1,3 +1,9 @@
#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![feature(alloc)]
#![feature(const_str_len)]
extern crate alloc;
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::{Arc, Weak}, vec::Vec}; use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::{Arc, Weak}, vec::Vec};
use core::any::Any; use core::any::Any;
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
@ -5,34 +11,26 @@ use core::mem::uninitialized;
use bitvec::BitVec; use bitvec::BitVec;
use log::*; use log::*;
use spin::{Mutex, RwLock}; use spin::RwLock;
use crate::dirty::Dirty; use rcore_fs::dev::Device;
use crate::util::*; use rcore_fs::dirty::Dirty;
use crate::vfs::{self, FileSystem, FsError, INode, Timespec}; use rcore_fs::util::*;
use rcore_fs::vfs::{self, FileSystem, FsError, INode, Timespec};
use self::structs::*; use self::structs::*;
mod structs; mod structs;
mod std_impl;
mod blocked_device;
/// Interface for FS to read & write
/// TODO: use std::io::{Read, Write}
pub trait Device: Send {
fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option<usize>;
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize>;
}
impl Device { trait DeviceExt: Device {
fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> vfs::Result<()> { fn read_block(&self, id: BlockId, offset: usize, buf: &mut [u8]) -> vfs::Result<()> {
debug_assert!(offset + buf.len() <= BLKSIZE); debug_assert!(offset + buf.len() <= BLKSIZE);
match self.read_at(id * BLKSIZE + offset, buf) { match self.read_at(id * BLKSIZE + offset, buf) {
Some(len) if len == buf.len() => Ok(()), Some(len) if len == buf.len() => Ok(()),
_ => panic!(), _ => panic!(),
} }
} }
fn write_block(&mut self, id: BlockId, offset: usize, buf: &[u8]) -> vfs::Result<()> { fn write_block(&self, id: BlockId, offset: usize, buf: &[u8]) -> vfs::Result<()> {
debug_assert!(offset + buf.len() <= BLKSIZE); debug_assert!(offset + buf.len() <= BLKSIZE);
match self.write_at(id * BLKSIZE + offset, buf) { match self.write_at(id * BLKSIZE + offset, buf) {
Some(len) if len == buf.len() => Ok(()), Some(len) if len == buf.len() => Ok(()),
@ -40,12 +38,14 @@ impl Device {
} }
} }
/// Load struct `T` from given block in device /// Load struct `T` from given block in device
fn load_struct<T: AsBuf>(&mut self, id: BlockId) -> vfs::Result<T> { fn load_struct<T: AsBuf>(&self, id: BlockId) -> vfs::Result<T> {
let mut s: T = unsafe { uninitialized() }; let mut s: T = unsafe { uninitialized() };
self.read_block(id, 0, s.as_buf_mut()).map(|_|{s}) self.read_block(id, 0, s.as_buf_mut()).map(|_|{s})
} }
} }
impl DeviceExt for Device {}
/// inode for sfs /// inode for sfs
pub struct INodeImpl { pub struct INodeImpl {
/// inode number /// inode number
@ -73,7 +73,7 @@ impl INodeImpl {
Ok(disk_inode.direct[id] as BlockId), Ok(disk_inode.direct[id] as BlockId),
id if id < NDIRECT + BLK_NENTRY => { id if id < NDIRECT + BLK_NENTRY => {
let mut disk_block_id: u32 = 0; let mut disk_block_id: u32 = 0;
self.fs.device.lock().read_block( self.fs.device.read_block(
disk_inode.indirect as usize, disk_inode.indirect as usize,
ENTRY_SIZE * (id - NDIRECT), ENTRY_SIZE * (id - NDIRECT),
disk_block_id.as_buf_mut(), disk_block_id.as_buf_mut(),
@ -93,7 +93,7 @@ impl INodeImpl {
} }
id if id < NDIRECT + BLK_NENTRY => { id if id < NDIRECT + BLK_NENTRY => {
let disk_block_id = disk_block_id as u32; let disk_block_id = disk_block_id as u32;
self.fs.device.lock().write_block( self.fs.device.write_block(
self.disk_inode.read().indirect as usize, self.disk_inode.read().indirect as usize,
ENTRY_SIZE * (id - NDIRECT), ENTRY_SIZE * (id - NDIRECT),
disk_block_id.as_buf(), disk_block_id.as_buf(),
@ -215,7 +215,7 @@ impl INodeImpl {
// Note: the _\w*_at method always return begin>size?0:begin<end?0:(min(size,end)-begin) when success // Note: the _\w*_at method always return begin>size?0:begin<end?0:(min(size,end)-begin) when success
/// Read/Write content, no matter what type it is /// Read/Write content, no matter what type it is
fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize> fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize>
where F: FnMut(&mut Box<Device>, &BlockRange, usize) -> vfs::Result<()> where F: FnMut(&Box<Device>, &BlockRange, usize) -> vfs::Result<()>
{ {
let size = self._size(); let size = self._size();
let iter = BlockIter { let iter = BlockIter {
@ -228,7 +228,7 @@ impl INodeImpl {
let mut buf_offset = 0usize; let mut buf_offset = 0usize;
for mut range in iter { for mut range in iter {
range.block = self.get_disk_block_id(range.block)?; range.block = self.get_disk_block_id(range.block)?;
f(&mut *self.fs.device.lock(), &range, buf_offset)?; f(&self.fs.device, &range, buf_offset)?;
buf_offset += range.len(); buf_offset += range.len();
} }
Ok(buf_offset) Ok(buf_offset)
@ -299,7 +299,7 @@ impl vfs::INode for INodeImpl {
fn sync(&self) -> vfs::Result<()> { fn sync(&self) -> vfs::Result<()> {
let mut disk_inode = self.disk_inode.write(); let mut disk_inode = self.disk_inode.write();
if disk_inode.dirty() { if disk_inode.dirty() {
self.fs.device.lock().write_block(self.id, 0, disk_inode.as_buf())?; self.fs.device.write_block(self.id, 0, disk_inode.as_buf())?;
disk_inode.sync(); disk_inode.sync();
} }
Ok(()) Ok(())
@ -543,14 +543,14 @@ pub struct SimpleFileSystem {
/// inode list /// inode list
inodes: RwLock<BTreeMap<INodeId, Weak<INodeImpl>>>, inodes: RwLock<BTreeMap<INodeId, Weak<INodeImpl>>>,
/// device /// device
device: Mutex<Box<Device>>, device: Box<Device>,
/// Pointer to self, used by INodes /// Pointer to self, used by INodes
self_ptr: Weak<SimpleFileSystem>, self_ptr: Weak<SimpleFileSystem>,
} }
impl SimpleFileSystem { impl SimpleFileSystem {
/// Load SFS from device /// Load SFS from device
pub fn open(mut device: Box<Device>) -> vfs::Result<Arc<Self>> { pub fn open(device: Box<Device>) -> vfs::Result<Arc<Self>> {
let super_block = device.load_struct::<SuperBlock>(BLKN_SUPER).unwrap(); let super_block = device.load_struct::<SuperBlock>(BLKN_SUPER).unwrap();
if !super_block.check() { if !super_block.check() {
return Err(FsError::WrongFs); return Err(FsError::WrongFs);
@ -561,7 +561,7 @@ impl SimpleFileSystem {
super_block: RwLock::new(Dirty::new(super_block)), super_block: RwLock::new(Dirty::new(super_block)),
free_map: RwLock::new(Dirty::new(BitVec::from(free_map.as_ref()))), free_map: RwLock::new(Dirty::new(BitVec::from(free_map.as_ref()))),
inodes: RwLock::new(BTreeMap::new()), inodes: RwLock::new(BTreeMap::new()),
device: Mutex::new(device), device,
self_ptr: Weak::default(), self_ptr: Weak::default(),
}.wrap()) }.wrap())
} }
@ -589,7 +589,7 @@ impl SimpleFileSystem {
super_block: RwLock::new(Dirty::new_dirty(super_block)), super_block: RwLock::new(Dirty::new_dirty(super_block)),
free_map: RwLock::new(Dirty::new_dirty(free_map)), free_map: RwLock::new(Dirty::new_dirty(free_map)),
inodes: RwLock::new(BTreeMap::new()), inodes: RwLock::new(BTreeMap::new()),
device: Mutex::new(device), device,
self_ptr: Weak::default(), self_ptr: Weak::default(),
}.wrap(); }.wrap();
@ -661,7 +661,7 @@ impl SimpleFileSystem {
} }
} }
// Load if not in set, or is weak ref. // Load if not in set, or is weak ref.
let disk_inode = Dirty::new(self.device.lock().load_struct::<DiskINode>(id).unwrap()); let disk_inode = Dirty::new(self.device.load_struct::<DiskINode>(id).unwrap());
self._new_inode(id, disk_inode) self._new_inode(id, disk_inode)
} }
/// Create a new INode file /// Create a new INode file
@ -694,12 +694,12 @@ impl vfs::FileSystem for SimpleFileSystem {
fn sync(&self) -> vfs::Result<()> { fn sync(&self) -> vfs::Result<()> {
let mut super_block = self.super_block.write(); let mut super_block = self.super_block.write();
if super_block.dirty() { if super_block.dirty() {
self.device.lock().write_at(BLKSIZE * BLKN_SUPER, super_block.as_buf()).unwrap(); self.device.write_at(BLKSIZE * BLKN_SUPER, super_block.as_buf()).unwrap();
super_block.sync(); super_block.sync();
} }
let mut free_map = self.free_map.write(); let mut free_map = self.free_map.write();
if free_map.dirty() { if free_map.dirty() {
self.device.lock().write_at(BLKSIZE * BLKN_FREEMAP, free_map.as_buf()).unwrap(); self.device.write_at(BLKSIZE * BLKN_FREEMAP, free_map.as_buf()).unwrap();
free_map.sync(); free_map.sync();
} }
self.flush_weak_inodes(); self.flush_weak_inodes();

@ -4,21 +4,6 @@ version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>", "Ben Pig Chu <benpichu@gmail.com>"] authors = ["WangRunji <wangrunji0408@163.com>", "Ben Pig Chu <benpichu@gmail.com>"]
edition = "2018" edition = "2018"
[[bin]]
name = "mksfs"
path = "src/bin/mksfs.rs"
required-features = ["std"]
[dependencies]
static_assertions = "0.3"
spin = "0.4"
log = "0.4"
[dependencies.bitvec]
version = "0.9"
default-features = false
features = ["alloc"]
[dev-dependencies] [dev-dependencies]
tempfile = "3" tempfile = "3"

@ -1,11 +1,19 @@
use crate::util::*; use crate::util::*;
use super::Device;
mod std_impl;
/// Interface for FS to read & write
/// TODO: use std::io::{Read, Write}
pub trait Device: Send + Sync {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Option<usize>;
fn write_at(&self, offset: usize, buf: &[u8]) -> Option<usize>;
}
/// Device which can only R/W in blocks /// Device which can only R/W in blocks
pub trait BlockedDevice: Send { pub trait BlockDevice: Send + Sync {
const BLOCK_SIZE_LOG2: u8; const BLOCK_SIZE_LOG2: u8;
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool; fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool;
fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool; fn write_at(&self, block_id: usize, buf: &[u8]) -> bool;
} }
macro_rules! try0 { macro_rules! try0 {
@ -14,9 +22,9 @@ macro_rules! try0 {
}; };
} }
/// Helper functions to R/W BlockedDevice in bytes /// Helper functions to R/W BlockDevice in bytes
impl<T: BlockedDevice> Device for T { impl<T: BlockDevice> Device for T {
fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option<usize> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Option<usize> {
let iter = BlockIter { let iter = BlockIter {
begin: offset, begin: offset,
end: offset + buf.len(), end: offset + buf.len(),
@ -29,13 +37,13 @@ impl<T: BlockedDevice> Device for T {
let buf = &mut buf[range.origin_begin() - offset..range.origin_end() - offset]; let buf = &mut buf[range.origin_begin() - offset..range.origin_end() - offset];
if range.is_full() { if range.is_full() {
// Read to target buf directly // Read to target buf directly
try0!(len, BlockedDevice::read_at(self, range.block, buf)); try0!(len, BlockDevice::read_at(self, range.block, buf));
} else { } else {
use core::mem::uninitialized; use core::mem::uninitialized;
let mut block_buf: [u8; 4096] = unsafe { uninitialized() }; let mut block_buf: [u8; 4096] = unsafe { uninitialized() };
assert!(Self::BLOCK_SIZE_LOG2 <= 12); assert!(Self::BLOCK_SIZE_LOG2 <= 12);
// Read to local buf first // Read to local buf first
try0!(len, BlockedDevice::read_at(self, range.block, &mut block_buf)); try0!(len, BlockDevice::read_at(self, range.block, &mut block_buf));
// Copy to target buf then // Copy to target buf then
buf.copy_from_slice(&mut block_buf[range.begin..range.end]); buf.copy_from_slice(&mut block_buf[range.begin..range.end]);
} }
@ -43,7 +51,7 @@ impl<T: BlockedDevice> Device for T {
Some(buf.len()) Some(buf.len())
} }
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize> { fn write_at(&self, offset: usize, buf: &[u8]) -> Option<usize> {
let iter = BlockIter { let iter = BlockIter {
begin: offset, begin: offset,
end: offset + buf.len(), end: offset + buf.len(),
@ -56,17 +64,17 @@ impl<T: BlockedDevice> Device for T {
let buf = &buf[range.origin_begin() - offset..range.origin_end() - offset]; let buf = &buf[range.origin_begin() - offset..range.origin_end() - offset];
if range.is_full() { if range.is_full() {
// Write to target buf directly // Write to target buf directly
try0!(len, BlockedDevice::write_at(self, range.block, buf)); try0!(len, BlockDevice::write_at(self, range.block, buf));
} else { } else {
use core::mem::uninitialized; use core::mem::uninitialized;
let mut block_buf: [u8; 4096] = unsafe { uninitialized() }; let mut block_buf: [u8; 4096] = unsafe { uninitialized() };
assert!(Self::BLOCK_SIZE_LOG2 <= 12); assert!(Self::BLOCK_SIZE_LOG2 <= 12);
// Read to local buf first // Read to local buf first
try0!(len, BlockedDevice::read_at(self, range.block, &mut block_buf)); try0!(len, BlockDevice::read_at(self, range.block, &mut block_buf));
// Write to local buf // Write to local buf
block_buf[range.begin..range.end].copy_from_slice(buf); block_buf[range.begin..range.end].copy_from_slice(buf);
// Write back to target buf // Write back to target buf
try0!(len, BlockedDevice::write_at(self, range.block, &block_buf)); try0!(len, BlockDevice::write_at(self, range.block, &block_buf));
} }
} }
Some(buf.len()) Some(buf.len())
@ -76,65 +84,66 @@ impl<T: BlockedDevice> Device for T {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use std::sync::Mutex;
impl BlockedDevice for [u8; 16] { impl BlockDevice for Mutex<[u8; 16]> {
const BLOCK_SIZE_LOG2: u8 = 2; const BLOCK_SIZE_LOG2: u8 = 2;
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool { fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool {
if block_id >= 4 { if block_id >= 4 {
return false; return false;
} }
let begin = block_id << 2; let begin = block_id << 2;
buf[..4].copy_from_slice(&mut self[begin..begin + 4]); buf[..4].copy_from_slice(&mut self.lock()[begin..begin + 4]);
true true
} }
fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool { fn write_at(&self, block_id: usize, buf: &[u8]) -> bool {
if block_id >= 4 { if block_id >= 4 {
return false; return false;
} }
let begin = block_id << 2; let begin = block_id << 2;
self[begin..begin + 4].copy_from_slice(&buf[..4]); self.lock()[begin..begin + 4].copy_from_slice(&buf[..4]);
true true
} }
} }
#[test] #[test]
fn read() { fn read() {
let mut buf: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; let buf: Mutex<[u8; 16]> = Mutex::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
let mut res: [u8; 6] = [0; 6]; let mut res: [u8; 6] = [0; 6];
// all inside // all inside
let ret = Device::read_at(&mut buf, 3, &mut res); let ret = Device::read_at(&buf, 3, &mut res);
assert_eq!(ret, Some(6)); assert_eq!(ret, Some(6));
assert_eq!(res, [3, 4, 5, 6, 7, 8]); assert_eq!(res, [3, 4, 5, 6, 7, 8]);
// partly inside // partly inside
let ret = Device::read_at(&mut buf, 11, &mut res); let ret = Device::read_at(&buf, 11, &mut res);
assert_eq!(ret, Some(5)); assert_eq!(ret, Some(5));
assert_eq!(res, [11, 12, 13, 14, 15, 8]); assert_eq!(res, [11, 12, 13, 14, 15, 8]);
// all outside // all outside
let ret = Device::read_at(&mut buf, 16, &mut res); let ret = Device::read_at(&buf, 16, &mut res);
assert_eq!(ret, Some(0)); assert_eq!(ret, Some(0));
assert_eq!(res, [11, 12, 13, 14, 15, 8]); assert_eq!(res, [11, 12, 13, 14, 15, 8]);
} }
#[test] #[test]
fn write() { fn write() {
let mut buf: [u8; 16] = [0; 16]; let buf: Mutex<[u8; 16]> = Mutex::new([0; 16]);
let res: [u8; 6] = [3, 4, 5, 6, 7, 8]; let res: [u8; 6] = [3, 4, 5, 6, 7, 8];
// all inside // all inside
let ret = Device::write_at(&mut buf, 3, &res); let ret = Device::write_at(&buf, 3, &res);
assert_eq!(ret, Some(6)); assert_eq!(ret, Some(6));
assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0]);
// partly inside // partly inside
let ret = Device::write_at(&mut buf, 11, &res); let ret = Device::write_at(&buf, 11, &res);
assert_eq!(ret, Some(5)); assert_eq!(ret, Some(5));
assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]); assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]);
// all outside // all outside
let ret = Device::write_at(&mut buf, 16, &res); let ret = Device::write_at(&buf, 16, &res);
assert_eq!(ret, Some(0)); assert_eq!(ret, Some(0));
assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]); assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]);
} }

@ -0,0 +1,27 @@
#![cfg(any(test, feature = "std"))]
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::sync::Mutex;
use super::Device;
impl Device for Mutex<File> {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Option<usize> {
let offset = offset as u64;
let mut file = self.lock().unwrap();
match file.seek(SeekFrom::Start(offset)) {
Ok(real_offset) if real_offset == offset => file.read(buf).ok(),
_ => None,
}
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Option<usize> {
let offset = offset as u64;
let mut file = self.lock().unwrap();
match file.seek(SeekFrom::Start(offset)) {
Ok(real_offset) if real_offset == offset => file.write(buf).ok(),
_ => None,
}
}
}

@ -4,11 +4,10 @@
extern crate alloc; extern crate alloc;
mod dirty; pub mod dirty;
mod util; pub mod util;
pub mod vfs; pub mod vfs;
pub mod sfs; pub mod dev;
pub mod sefs;
pub mod file; pub mod file;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

@ -1,23 +0,0 @@
#![cfg(any(test, feature = "std"))]
use std::fs::File;
use std::io::{Read, Write, Seek, SeekFrom};
use super::Device;
impl Device for File {
fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option<usize> {
let offset = offset as u64;
match self.seek(SeekFrom::Start(offset)) {
Ok(real_offset) if real_offset == offset => self.read(buf).ok(),
_ => None,
}
}
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize> {
let offset = offset as u64;
match self.seek(SeekFrom::Start(offset)) {
Ok(real_offset) if real_offset == offset => self.write(buf).ok(),
_ => None,
}
}
}
Loading…
Cancel
Save