reformat code using `cargo fmt`

master
WangRunji 6 years ago
parent ae77625e23
commit 89e9dde1ec

@ -1,8 +1,8 @@
# rcore-fs
[![Build Status](https://travis-ci.org/wangrunji0408/rcore-fs.svg?branch=master)](https://travis-ci.org/wangrunji0408/rcore-fs)
[![Build Status](https://travis-ci.org/rcore-os/rcore-fs.svg?branch=master)](https://travis-ci.org/rcore-os/rcore-fs)
The file system module for [rCore OS](https://github.com/wangrunji0408/RustOS).
The file system module for [rCore OS](https://github.com/rcore-os/rCore).
## Sub-projects

@ -1,4 +1,7 @@
use fuse::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyWrite, ReplyStatfs, Request};
use fuse::{
FileAttr, FileType, Filesystem, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry,
ReplyStatfs, ReplyWrite, Request,
};
use rcore_fs::vfs;
use std::collections::btree_map::BTreeMap;
use std::ffi::OsStr;
@ -6,7 +9,7 @@ use std::sync::Arc;
//use log::*;
use time::Timespec;
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
pub struct VfsFuse {
fs: Arc<vfs::FileSystem>,
@ -55,8 +58,8 @@ impl VfsFuse {
}
}
fn trans_error(err: vfs::FsError) -> i32 {
use vfs::FsError::*;
use libc::*;
use vfs::FsError::*;
match err {
NotSupported => ENOSYS,
EntryNotFound => ENOENT,
@ -74,19 +77,23 @@ impl VfsFuse {
}
}
fn get_inode(&self, ino: u64) -> vfs::Result<&Arc<vfs::INode>> {
self.inodes.get(&(ino as usize)).ok_or(vfs::FsError::EntryNotFound)
self.inodes
.get(&(ino as usize))
.ok_or(vfs::FsError::EntryNotFound)
}
}
/// Helper macro to reply error when VFS operation fails
macro_rules! try_vfs {
($reply:expr, $expr:expr) => (match $expr {
Ok(val) => val,
Err(err) => {
$reply.error(Self::trans_error(err));
return;
($reply:expr, $expr:expr) => {
match $expr {
Ok(val) => val,
Err(err) => {
$reply.error(Self::trans_error(err));
return;
}
}
});
};
}
impl Filesystem for VfsFuse {
@ -111,7 +118,15 @@ impl Filesystem for VfsFuse {
reply.attr(&TTL, &attr);
}
fn mknod(&mut self, _req: &Request, parent: u64, name: &OsStr, mode: u32, _rdev: u32, reply: ReplyEntry) {
fn mknod(
&mut self,
_req: &Request,
parent: u64,
name: &OsStr,
mode: u32,
_rdev: u32,
reply: ReplyEntry,
) {
let name = name.to_str().unwrap();
let inode = try_vfs!(reply, self.get_inode(parent));
let target = try_vfs!(reply, inode.create(name, vfs::FileType::File, mode));
@ -141,7 +156,15 @@ impl Filesystem for VfsFuse {
self.unlink(req, parent, name, reply);
}
fn rename(&mut self, _req: &Request, parent: u64, name: &OsStr, newparent: u64, newname: &OsStr, reply: ReplyEmpty) {
fn rename(
&mut self,
_req: &Request,
parent: u64,
name: &OsStr,
newparent: u64,
newname: &OsStr,
reply: ReplyEmpty,
) {
let name = name.to_str().unwrap();
let newname = newname.to_str().unwrap();
let parent = try_vfs!(reply, self.get_inode(parent));
@ -150,7 +173,14 @@ impl Filesystem for VfsFuse {
reply.ok();
}
fn link(&mut self, _req: &Request, ino: u64, newparent: u64, newname: &OsStr, reply: ReplyEntry) {
fn link(
&mut self,
_req: &Request,
ino: u64,
newparent: u64,
newname: &OsStr,
reply: ReplyEntry,
) {
let newname = newname.to_str().unwrap();
let inode = try_vfs!(reply, self.get_inode(ino));
let newparent = try_vfs!(reply, self.get_inode(newparent));
@ -160,7 +190,15 @@ impl Filesystem for VfsFuse {
reply.entry(&TTL, &attr, 0);
}
fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, size: u32, reply: ReplyData) {
fn read(
&mut self,
_req: &Request,
ino: u64,
_fh: u64,
offset: i64,
size: u32,
reply: ReplyData,
) {
let inode = try_vfs!(reply, self.get_inode(ino));
let mut data = Vec::<u8>::new();
data.resize(size as usize, 0);
@ -168,7 +206,16 @@ impl Filesystem for VfsFuse {
reply.data(data.as_slice());
}
fn write(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, data: &[u8], _flags: u32, reply: ReplyWrite) {
fn write(
&mut self,
_req: &Request,
ino: u64,
_fh: u64,
offset: i64,
data: &[u8],
_flags: u32,
reply: ReplyWrite,
) {
let inode = try_vfs!(reply, self.get_inode(ino));
let len = try_vfs!(reply, inode.write_at(offset as usize, data));
reply.written(len as u32);
@ -190,7 +237,14 @@ impl Filesystem for VfsFuse {
reply.ok();
}
fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
fn readdir(
&mut self,
_req: &Request,
ino: u64,
_fh: u64,
offset: i64,
mut reply: ReplyDirectory,
) {
let inode = try_vfs!(reply, self.get_inode(ino));
let info = try_vfs!(reply, inode.metadata());
let count = info.size;
@ -209,8 +263,15 @@ impl Filesystem for VfsFuse {
fn statfs(&mut self, _req: &Request, _ino: u64, reply: ReplyStatfs) {
let info = self.fs.info();
reply.statfs(info.blocks as u64, info.bfree as u64, info.bavail as u64,
info.files as u64, info.ffree as u64, info.bsize as u32,
info.namemax as u32, info.frsize as u32);
reply.statfs(
info.blocks as u64,
info.bfree as u64,
info.bavail as u64,
info.files as u64,
info.ffree as u64,
info.bsize as u32,
info.namemax as u32,
info.frsize as u32,
);
}
}

@ -1,2 +1,2 @@
pub mod fuse;
pub mod zip;
pub mod zip;

@ -58,47 +58,41 @@ fn main() {
let fs: Arc<FileSystem> = match opt.fs.as_str() {
"sfs" => {
let file = OpenOptions::new().read(true).write(true).create(true)
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&opt.image)
.expect("failed to open image");
let device = Mutex::new(file);
const MAX_SPACE: usize = 0x1000 * 0x1000 * 8; // 128MB (4K bitmap)
match create {
true => sfs::SimpleFileSystem::create(Arc::new(device), MAX_SPACE),
false => sfs::SimpleFileSystem::open(Arc::new(device))
.expect("failed to open sfs"),
false => sfs::SimpleFileSystem::open(Arc::new(device)).expect("failed to open sfs"),
}
}
"sefs" => {
std::fs::create_dir_all(&opt.image).unwrap();
let device = sefs::dev::StdStorage::new(&opt.image);
match create {
true => {
sefs::SEFS::create(Box::new(device), &StdTimeProvider)
.expect("failed to create sefs")
}
false => {
sefs::SEFS::open(Box::new(device), &StdTimeProvider)
.expect("failed to open sefs")
}
true => sefs::SEFS::create(Box::new(device), &StdTimeProvider)
.expect("failed to create sefs"),
false => sefs::SEFS::open(Box::new(device), &StdTimeProvider)
.expect("failed to open sefs"),
}
}
_ => panic!("unsupported file system"),
};
match opt.cmd {
Cmd::Mount => {
fuse::mount(VfsFuse::new(fs), &opt.dir, &[])
.expect("failed to mount fs");
fuse::mount(VfsFuse::new(fs), &opt.dir, &[]).expect("failed to mount fs");
}
Cmd::Zip => {
zip_dir(&opt.dir, fs.root_inode())
.expect("failed to zip fs");
zip_dir(&opt.dir, fs.root_inode()).expect("failed to zip fs");
}
Cmd::Unzip => {
std::fs::create_dir(&opt.dir)
.expect("failed to create dir");
unzip_dir(&opt.dir, fs.root_inode())
.expect("failed to unzip fs");
std::fs::create_dir(&opt.dir).expect("failed to create dir");
unzip_dir(&opt.dir, fs.root_inode()).expect("failed to unzip fs");
}
}
}

@ -1,12 +1,12 @@
use std::error::Error;
use std::fs;
use std::io::{Read, Write};
use std::mem::uninitialized;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::sync::Arc;
use std::error::Error;
use std::os::unix::ffi::OsStrExt;
use rcore_fs::vfs::{INode, FileType};
use rcore_fs::vfs::{FileType, INode};
const DEFAULT_MODE: u32 = 0o664;
const BUF_SIZE: usize = 0x1000;

@ -5,8 +5,8 @@ use rcore_fs::vfs::FsError;
#[cfg(any(test, feature = "std"))]
pub use self::std_impl::*;
pub mod std_impl;
pub mod sgx_impl;
pub mod std_impl;
/// A file stores a normal file or directory.
///
@ -19,11 +19,19 @@ pub trait File: Send + Sync {
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) }
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) }
if len == buf.len() {
Ok(())
} else {
Err(DeviceError)
}
}
}

@ -3,7 +3,7 @@
use std::boxed::Box;
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
use std::sgxfs::{OpenOptions, remove, SgxFile as File};
use std::sgxfs::{remove, OpenOptions, SgxFile as File};
use std::sync::SgxMutex as Mutex;
use std::time::{SystemTime, UNIX_EPOCH};
use std::untrusted::time::SystemTimeEx; // FIXME: use trusted ime
@ -11,7 +11,7 @@ use std::untrusted::time::SystemTimeEx; // FIXME: use trusted ime
use rcore_fs::dev::TimeProvider;
use rcore_fs::vfs::Timespec;
use super::{DeviceError, DevResult};
use super::{DevResult, DeviceError};
pub struct SgxStorage {
path: PathBuf,
@ -19,8 +19,10 @@ pub struct SgxStorage {
impl SgxStorage {
pub fn new(path: impl AsRef<Path>) -> Self {
// assert!(path.as_ref().is_dir());
SgxStorage { path: path.as_ref().to_path_buf() }
// assert!(path.as_ref().is_dir());
SgxStorage {
path: path.as_ref().to_path_buf(),
}
}
}
@ -30,7 +32,10 @@ impl super::Storage for SgxStorage {
path.push(format!("{}", file_id));
// TODO: key
let key = [0u8; 16];
let file = OpenOptions::new().read(true).update(true).open_ex(path, &key)?;
let file = OpenOptions::new()
.read(true)
.update(true)
.open_ex(path, &key)?;
Ok(Box::new(LockedFile(Mutex::new(file))))
}
@ -39,7 +44,10 @@ impl super::Storage for SgxStorage {
path.push(format!("{}", file_id));
// TODO: key
let key = [0u8; 16];
let file = OpenOptions::new().write(true).update(true).open_ex(path, &key)?;
let file = OpenOptions::new()
.write(true)
.update(true)
.open_ex(path, &key)?;
Ok(Box::new(LockedFile(Mutex::new(file))))
}

@ -1,10 +1,10 @@
#![cfg(any(test, feature = "std"))]
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions, remove_file};
use std::io::{Read, Write, Seek, SeekFrom};
use super::{DevResult, DeviceError};
use spin::Mutex;
use super::{DeviceError, DevResult};
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
pub struct StdStorage {
path: PathBuf,
@ -13,7 +13,9 @@ pub struct StdStorage {
impl StdStorage {
pub fn new(path: impl AsRef<Path>) -> Self {
assert!(path.as_ref().is_dir());
StdStorage { path: path.as_ref().to_path_buf() }
StdStorage {
path: path.as_ref().to_path_buf(),
}
}
}
@ -28,7 +30,11 @@ impl super::Storage for StdStorage {
fn create(&self, file_id: usize) -> DevResult<Box<super::File>> {
let mut path = self.path.to_path_buf();
path.push(format!("{}", file_id));
let file = OpenOptions::new().read(true).write(true).create(true).open(path)?;
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)?;
Ok(Box::new(Mutex::new(file)))
}

@ -6,7 +6,13 @@ extern crate alloc;
#[macro_use]
extern crate sgx_tstd as std;
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::fmt::{Debug, Error, Formatter};
use core::mem::uninitialized;
@ -21,8 +27,8 @@ use spin::RwLock;
use self::dev::*;
use self::structs::*;
mod structs;
pub mod dev;
mod structs;
/// Helper methods for `File`
impl File {
@ -64,7 +70,11 @@ pub struct INodeImpl {
impl Debug for INodeImpl {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "INode {{ id: {}, disk: {:?} }}", self.id, self.disk_inode)
write!(
f,
"INode {{ id: {}, disk: {:?} }}",
self.id, self.disk_inode
)
}
}
@ -80,21 +90,28 @@ impl INodeImpl {
.map(|(entry, id)| (entry.id as INodeId, id))
}
fn get_file_inode_id(&self, name: &str) -> Option<INodeId> {
self.get_file_inode_and_entry_id(name).map(|(inode_id, _)| inode_id)
self.get_file_inode_and_entry_id(name)
.map(|(inode_id, _)| inode_id)
}
/// Init dir content. Insert 2 init entries.
/// This do not init nlinks, please modify the nlinks in the invoker.
fn dirent_init(&self, parent: INodeId) -> vfs::Result<()> {
self.disk_inode.write().blocks = 2;
// Insert entries: '.' '..'
self.file.write_direntry(0, &DiskEntry {
id: self.id as u32,
name: Str256::from("."),
})?;
self.file.write_direntry(1, &DiskEntry {
id: parent as u32,
name: Str256::from(".."),
})?;
self.file.write_direntry(
0,
&DiskEntry {
id: self.id as u32,
name: Str256::from("."),
},
)?;
self.file.write_direntry(
1,
&DiskEntry {
id: parent as u32,
name: Str256::from(".."),
},
)?;
Ok(())
}
fn dirent_append(&self, entry: &DiskEntry) -> vfs::Result<()> {
@ -156,9 +173,18 @@ impl vfs::INode for INodeImpl {
mode: disk_inode.mode,
type_: vfs::FileType::from(disk_inode.type_.clone()),
blocks: disk_inode.blocks as usize,
atime: Timespec { sec: disk_inode.atime as i64, nsec: 0 },
mtime: Timespec { sec: disk_inode.mtime as i64, nsec: 0 },
ctime: Timespec { sec: disk_inode.ctime as i64, nsec: 0 },
atime: Timespec {
sec: disk_inode.atime as i64,
nsec: 0,
},
mtime: Timespec {
sec: disk_inode.mtime as i64,
nsec: 0,
},
ctime: Timespec {
sec: disk_inode.ctime as i64,
nsec: 0,
},
nlinks: disk_inode.nlinks as usize,
uid: disk_inode.uid as usize,
gid: disk_inode.gid as usize,
@ -175,7 +201,9 @@ impl vfs::INode for INodeImpl {
fn sync_all(&self) -> vfs::Result<()> {
let mut disk_inode = self.disk_inode.write();
if disk_inode.dirty() {
self.fs.meta_file.write_block(self.id, disk_inode.as_buf())?;
self.fs
.meta_file
.write_block(self.id, disk_inode.as_buf())?;
disk_inode.sync();
}
Ok(())
@ -225,7 +253,7 @@ impl vfs::INode for INodeImpl {
inode.nlinks_inc();
if type_ == FileType::Dir {
inode.nlinks_inc(); //for .
self.nlinks_inc(); //for ..
self.nlinks_inc(); //for ..
}
Ok(inode)
@ -233,19 +261,21 @@ impl vfs::INode for INodeImpl {
fn unlink(&self, name: &str) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir)
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
return Err(FsError::DirRemoved);
}
if name == "." {
return Err(FsError::IsDir)
return Err(FsError::IsDir);
}
if name == ".." {
return Err(FsError::IsDir)
return Err(FsError::IsDir);
}
let (inode_id, entry_id) = self.get_file_inode_and_entry_id(name).ok_or(FsError::EntryNotFound)?;
let (inode_id, entry_id) = self
.get_file_inode_and_entry_id(name)
.ok_or(FsError::EntryNotFound)?;
let inode = self.fs.get_inode(inode_id);
let type_ = inode.disk_inode.read().type_;
@ -253,13 +283,13 @@ impl vfs::INode for INodeImpl {
// only . and ..
assert!(inode.disk_inode.read().blocks >= 2);
if inode.disk_inode.read().blocks > 2 {
return Err(FsError::DirNotEmpty)
return Err(FsError::DirNotEmpty);
}
}
inode.nlinks_dec();
if type_ == FileType::Dir {
inode.nlinks_dec(); //for .
self.nlinks_dec(); //for ..
self.nlinks_dec(); //for ..
}
self.dirent_remove(entry_id)?;
@ -268,15 +298,17 @@ impl vfs::INode for INodeImpl {
fn link(&self, name: &str, other: &Arc<INode>) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir)
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
return Err(FsError::DirRemoved);
}
if !self.get_file_inode_id(name).is_none() {
return Err(FsError::EntryExist);
}
let child = other.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
let child = other
.downcast_ref::<INodeImpl>()
.ok_or(FsError::NotSameFs)?;
if !Arc::ptr_eq(&self.fs, &child.fs) {
return Err(FsError::NotSameFs);
}
@ -293,7 +325,7 @@ impl vfs::INode for INodeImpl {
}
fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_!=vfs::FileType::Dir {
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
@ -306,7 +338,9 @@ impl vfs::INode for INodeImpl {
return Err(FsError::IsDir);
}
let dest = target.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
let dest = target
.downcast_ref::<INodeImpl>()
.ok_or(FsError::NotSameFs)?;
let dest_info = dest.metadata()?;
if !Arc::ptr_eq(&self.fs, &dest.fs) {
return Err(FsError::NotSameFs);
@ -321,7 +355,8 @@ impl vfs::INode for INodeImpl {
return Err(FsError::EntryExist);
}
let (inode_id, entry_id) = self.get_file_inode_and_entry_id(old_name)
let (inode_id, entry_id) = self
.get_file_inode_and_entry_id(old_name)
.ok_or(FsError::EntryNotFound)?;
if info.inode == dest_info.inode {
// rename: in place modify name
@ -352,17 +387,17 @@ impl vfs::INode for INodeImpl {
fn find(&self, name: &str) -> vfs::Result<Arc<vfs::INode>> {
let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir)
return Err(FsError::NotDir);
}
let inode_id = self.get_file_inode_id(name).ok_or(FsError::EntryNotFound)?;
Ok(self.fs.get_inode(inode_id))
}
fn get_entry(&self, id: usize) -> vfs::Result<String> {
if self.disk_inode.read().type_ != FileType::Dir {
return Err(FsError::NotDir)
return Err(FsError::NotDir);
}
if id >= self.disk_inode.read().blocks as usize {
return Err(FsError::EntryNotFound)
return Err(FsError::EntryNotFound);
};
let entry = self.file.read_direntry(id)?;
Ok(String::from(entry.name.as_ref()))
@ -378,7 +413,8 @@ impl vfs::INode for INodeImpl {
impl Drop for INodeImpl {
/// Auto sync when drop
fn drop(&mut self) {
self.sync_all().expect("Failed to sync when dropping the SEFS Inode");
self.sync_all()
.expect("Failed to sync when dropping the SEFS Inode");
if self.disk_inode.read().nlinks <= 0 {
self.disk_inode.write().sync();
self.fs.free_block(self.id);
@ -387,7 +423,6 @@ impl Drop for INodeImpl {
}
}
/// Simple Encrypt File System
pub struct SEFS {
/// on-disk superblock
@ -408,7 +443,10 @@ pub struct SEFS {
impl SEFS {
/// Load SEFS
pub fn open(device: Box<Storage>, time_provider: &'static TimeProvider) -> vfs::Result<Arc<Self>> {
pub fn open(
device: Box<Storage>,
time_provider: &'static TimeProvider,
) -> vfs::Result<Arc<Self>> {
let meta_file = device.open(0)?;
let super_block = meta_file.load_struct::<SuperBlock>(BLKN_SUPER)?;
if !super_block.check() {
@ -424,10 +462,14 @@ impl SEFS {
meta_file,
time_provider,
self_ptr: Weak::default(),
}.wrap())
}
.wrap())
}
/// Create a new SEFS
pub fn create(device: Box<Storage>, time_provider: &'static TimeProvider) -> vfs::Result<Arc<Self>> {
pub fn create(
device: Box<Storage>,
time_provider: &'static TimeProvider,
) -> vfs::Result<Arc<Self>> {
let blocks = BLKBITS;
let super_block = SuperBlock {
@ -454,14 +496,15 @@ impl SEFS {
meta_file,
time_provider,
self_ptr: Weak::default(),
}.wrap();
}
.wrap();
// Init root INode
let root = sefs.new_inode(FileType::Dir, 0o777)?;
assert_eq!(root.id, BLKN_ROOT);
root.dirent_init(BLKN_ROOT)?;
root.nlinks_inc(); //for .
root.nlinks_inc(); //for ..(root's parent is itself)
root.nlinks_inc(); //for .
root.nlinks_inc(); //for ..(root's parent is itself)
root.sync_all()?;
Ok(sefs)
@ -474,7 +517,9 @@ impl SEFS {
let fs = Arc::new(self);
let weak = Arc::downgrade(&fs);
let ptr = Arc::into_raw(fs) as *mut Self;
unsafe { (*ptr).self_ptr = weak; }
unsafe {
(*ptr).self_ptr = weak;
}
unsafe { Arc::from_raw(ptr) }
}
@ -486,9 +531,9 @@ impl SEFS {
let mut super_block = self.super_block.write();
if super_block.unused_blocks == 0 {
free_map.set(block_id, true);
return None
return None;
}
super_block.unused_blocks -= 1; // will not underflow
super_block.unused_blocks -= 1; // will not underflow
}
id
}
@ -502,7 +547,12 @@ impl SEFS {
/// Create a new INode struct, then insert it to self.inodes
/// Private used for load or create INode
fn _new_inode(&self, id: INodeId, disk_inode: Dirty<DiskINode>, create: bool) -> Arc<INodeImpl> {
fn _new_inode(
&self,
id: INodeId,
disk_inode: Dirty<DiskINode>,
create: bool,
) -> Arc<INodeImpl> {
let inode = Arc::new(INodeImpl {
id,
disk_inode: RwLock::new(disk_inode),
@ -550,9 +600,11 @@ impl SEFS {
}
fn flush_weak_inodes(&self) {
let mut inodes = self.inodes.write();
let remove_ids: Vec<_> = inodes.iter().filter(|(_, inode)| {
inode.upgrade().is_none()
}).map(|(&id, _)| id).collect();
let remove_ids: Vec<_> = inodes
.iter()
.filter(|(_, inode)| inode.upgrade().is_none())
.map(|(&id, _)| id)
.collect();
for id in remove_ids.iter() {
inodes.remove(&id);
}
@ -564,12 +616,14 @@ impl vfs::FileSystem for SEFS {
fn sync(&self) -> vfs::Result<()> {
let mut super_block = self.super_block.write();
if super_block.dirty() {
self.meta_file.write_all_at(super_block.as_buf(), BLKSIZE * BLKN_SUPER)?;
self.meta_file
.write_all_at(super_block.as_buf(), BLKSIZE * BLKN_SUPER)?;
super_block.sync();
}
let mut free_map = self.free_map.write();
if free_map.dirty() {
self.meta_file.write_all_at(free_map.as_buf(), BLKSIZE * BLKN_FREEMAP)?;
self.meta_file
.write_all_at(free_map.as_buf(), BLKSIZE * BLKN_FREEMAP)?;
free_map.sync();
}
self.flush_weak_inodes();
@ -593,8 +647,8 @@ impl vfs::FileSystem for SEFS {
blocks: sb.blocks as usize,
bfree: sb.unused_blocks as usize,
bavail: sb.unused_blocks as usize,
files: sb.blocks as usize, // inaccurate
ffree: sb.unused_blocks as usize, // inaccurate
files: sb.blocks as usize, // inaccurate
ffree: sb.unused_blocks as usize, // inaccurate
namemax: MAX_FNAME_LEN,
}
}
@ -603,7 +657,8 @@ impl vfs::FileSystem for SEFS {
impl Drop for SEFS {
/// Auto sync when drop
fn drop(&mut self) {
self.sync().expect("Failed to sync when dropping the SimpleFileSystem");
self.sync()
.expect("Failed to sync when dropping the SimpleFileSystem");
}
}

@ -1,9 +1,9 @@
//! On-disk structures in SEFS
use core::slice;
use core::mem::{size_of_val, size_of};
use core::fmt::{Debug, Formatter, Error};
use alloc::str;
use core::fmt::{Debug, Error, Formatter};
use core::mem::{size_of, size_of_val};
use core::slice;
use static_assertions::const_assert;
/// On-disk superblock
@ -53,7 +53,6 @@ pub struct DiskEntry {
#[repr(C)]
pub struct Str256(pub [u8; 256]);
impl AsRef<str> for Str256 {
fn as_ref(&self) -> &str {
let len = self.0.iter().enumerate().find(|(_, &b)| b == 0).unwrap().0;

@ -6,7 +6,12 @@ extern crate alloc;
#[macro_use]
extern crate log;
use alloc::{collections::BTreeMap, string::String, sync::{Arc, Weak}, vec::Vec};
use alloc::{
collections::BTreeMap,
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use core::any::Any;
use core::fmt::{Debug, Error, Formatter};
use core::mem::uninitialized;
@ -43,7 +48,7 @@ trait DeviceExt: Device {
/// Load struct `T` from given block in device
fn load_struct<T: AsBuf>(&self, id: BlockId) -> vfs::Result<T> {
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)
}
}
@ -61,7 +66,11 @@ pub struct INodeImpl {
impl Debug for INodeImpl {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "INode {{ id: {}, disk: {:?} }}", self.id, self.disk_inode)
write!(
f,
"INode {{ id: {}, disk: {:?} }}",
self.id, self.disk_inode
)
}
}
@ -70,10 +79,8 @@ impl INodeImpl {
fn get_disk_block_id(&self, file_block_id: BlockId) -> vfs::Result<BlockId> {
let disk_inode = self.disk_inode.read();
match file_block_id {
id if id >= disk_inode.blocks as BlockId =>
Err(FsError::InvalidParam),
id if id < NDIRECT =>
Ok(disk_inode.direct[id] as BlockId),
id if id >= disk_inode.blocks as BlockId => Err(FsError::InvalidParam),
id if id < NDIRECT => Ok(disk_inode.direct[id] as BlockId),
id if id < NDIRECT + BLK_NENTRY => {
let mut disk_block_id: u32 = 0;
self.fs.device.read_block(
@ -88,8 +95,7 @@ impl INodeImpl {
}
fn set_disk_block_id(&self, file_block_id: BlockId, disk_block_id: BlockId) -> vfs::Result<()> {
match file_block_id {
id if id >= self.disk_inode.read().blocks as BlockId =>
Err(FsError::InvalidParam),
id if id >= self.disk_inode.read().blocks as BlockId => Err(FsError::InvalidParam),
id if id < NDIRECT => {
self.disk_inode.write().direct[id] = disk_block_id as u32;
Ok(())
@ -111,28 +117,40 @@ impl INodeImpl {
(0..self.disk_inode.read().blocks)
.map(|i| {
let mut entry: DiskEntry = unsafe { uninitialized() };
self._read_at(i as usize * BLKSIZE, entry.as_buf_mut()).unwrap();
self._read_at(i as usize * BLKSIZE, entry.as_buf_mut())
.unwrap();
(entry, i)
})
.find(|(entry, _)| entry.name.as_ref() == name)
.map(|(entry, id)| (entry.id as INodeId, id as usize))
}
fn get_file_inode_id(&self, name: &str) -> Option<INodeId> {
self.get_file_inode_and_entry_id(name).map(|(inode_id, _)| inode_id)
self.get_file_inode_and_entry_id(name)
.map(|(inode_id, _)| inode_id)
}
/// Init dir content. Insert 2 init entries.
/// This do not init nlinks, please modify the nlinks in the invoker.
fn init_dir_entry(&self, parent: INodeId) -> vfs::Result<()> {
// Insert entries: '.' '..'
self._resize(BLKSIZE * 2)?;
self._write_at(BLKSIZE * 1, DiskEntry {
id: parent as u32,
name: Str256::from(".."),
}.as_buf()).unwrap();
self._write_at(BLKSIZE * 0, DiskEntry {
id: self.id as u32,
name: Str256::from("."),
}.as_buf()).unwrap();
self._write_at(
BLKSIZE * 1,
DiskEntry {
id: parent as u32,
name: Str256::from(".."),
}
.as_buf(),
)
.unwrap();
self._write_at(
BLKSIZE * 0,
DiskEntry {
id: self.id as u32,
name: Str256::from("."),
}
.as_buf(),
)
.unwrap();
Ok(())
}
/// remove a page in middle of file and insert the last page here, useful for dirent remove
@ -157,7 +175,7 @@ impl INodeImpl {
use core::cmp::{Ord, Ordering};
let old_blocks = self.disk_inode.read().blocks;
match blocks.cmp(&old_blocks) {
Ordering::Equal => {} // Do nothing
Ordering::Equal => {} // Do nothing
Ordering::Greater => {
{
let mut disk_inode = self.disk_inode.write();
@ -218,7 +236,8 @@ impl INodeImpl {
// 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
fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize>
where F: FnMut(&Arc<Device>, &BlockRange, usize) -> vfs::Result<()>
where
F: FnMut(&Arc<Device>, &BlockRange, usize) -> vfs::Result<()>,
{
let size = self._size();
let iter = BlockIter {
@ -239,7 +258,11 @@ impl INodeImpl {
/// Read content, no matter what type it is
fn _read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
self._io_at(offset, offset + buf.len(), |device, range, offset| {
device.read_block(range.block, range.begin, &mut buf[offset..offset + range.len()])
device.read_block(
range.block,
range.begin,
&mut buf[offset..offset + range.len()],
)
})
}
/// Write content, no matter what type it is
@ -267,7 +290,9 @@ impl INodeImpl {
impl vfs::INode for INodeImpl {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
if self.disk_inode.read().type_ != FileType::File && self.disk_inode.read().type_ != FileType::SymLink {
if self.disk_inode.read().type_ != FileType::File
&& self.disk_inode.read().type_ != FileType::SymLink
{
return Err(FsError::NotFile);
}
self._read_at(offset, buf)
@ -316,7 +341,9 @@ impl vfs::INode for INodeImpl {
fn sync_all(&self) -> vfs::Result<()> {
let mut disk_inode = self.disk_inode.write();
if disk_inode.dirty() {
self.fs.device.write_block(self.id, 0, disk_inode.as_buf())?;
self.fs
.device
.write_block(self.id, 0, disk_inode.as_buf())?;
disk_inode.sync();
}
Ok(())
@ -325,18 +352,20 @@ impl vfs::INode for INodeImpl {
self.sync_all()
}
fn resize(&self, len: usize) -> vfs::Result<()> {
if self.disk_inode.read().type_ != FileType::File && self.disk_inode.read().type_ != FileType::SymLink {
if self.disk_inode.read().type_ != FileType::File
&& self.disk_inode.read().type_ != FileType::SymLink
{
return Err(FsError::NotFile);
}
self._resize(len)
}
fn create(&self, name: &str, type_: vfs::FileType, _mode: u32) -> vfs::Result<Arc<vfs::INode>> {
let info = self.metadata()?;
if info.type_!=vfs::FileType::Dir {
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
return Err(FsError::DirRemoved);
}
// Ensure the name is not exist
@ -363,27 +392,29 @@ impl vfs::INode for INodeImpl {
inode.nlinks_inc();
if type_ == vfs::FileType::Dir {
inode.nlinks_inc(); //for .
self.nlinks_inc(); //for ..
self.nlinks_inc(); //for ..
}
Ok(inode)
}
fn unlink(&self, name: &str) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir)
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
return Err(FsError::DirRemoved);
}
if name == "." {
return Err(FsError::IsDir)
return Err(FsError::IsDir);
}
if name == ".." {
return Err(FsError::IsDir)
return Err(FsError::IsDir);
}
let (inode_id, entry_id) = self.get_file_inode_and_entry_id(name).ok_or(FsError::EntryNotFound)?;
let (inode_id, entry_id) = self
.get_file_inode_and_entry_id(name)
.ok_or(FsError::EntryNotFound)?;
let inode = self.fs.get_inode(inode_id);
let type_ = inode.disk_inode.read().type_;
@ -391,13 +422,13 @@ impl vfs::INode for INodeImpl {
// only . and ..
assert!(inode.disk_inode.read().blocks >= 2);
if inode.disk_inode.read().blocks > 2 {
return Err(FsError::DirNotEmpty)
return Err(FsError::DirNotEmpty);
}
}
inode.nlinks_dec();
if type_ == FileType::Dir {
inode.nlinks_dec(); //for .
self.nlinks_dec(); //for ..
self.nlinks_dec(); //for ..
}
self.remove_dirent_page(entry_id)?;
@ -405,16 +436,18 @@ impl vfs::INode for INodeImpl {
}
fn link(&self, name: &str, other: &Arc<INode>) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir)
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
return Err(FsError::DirRemoved);
}
if !self.get_file_inode_id(name).is_none() {
return Err(FsError::EntryExist);
}
let child = other.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
let child = other
.downcast_ref::<INodeImpl>()
.ok_or(FsError::NotSameFs)?;
if !Arc::ptr_eq(&self.fs, &child.fs) {
return Err(FsError::NotSameFs);
}
@ -433,7 +466,7 @@ impl vfs::INode for INodeImpl {
}
fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_!=vfs::FileType::Dir {
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
@ -446,7 +479,9 @@ impl vfs::INode for INodeImpl {
return Err(FsError::IsDir);
}
let dest = target.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
let dest = target
.downcast_ref::<INodeImpl>()
.ok_or(FsError::NotSameFs)?;
let dest_info = dest.metadata()?;
if !Arc::ptr_eq(&self.fs, &dest.fs) {
return Err(FsError::NotSameFs);
@ -461,7 +496,8 @@ impl vfs::INode for INodeImpl {
return Err(FsError::EntryExist);
}
let (inode_id, entry_id) = self.get_file_inode_and_entry_id(old_name)
let (inode_id, entry_id) = self
.get_file_inode_and_entry_id(old_name)
.ok_or(FsError::EntryNotFound)?;
if info.inode == dest_info.inode {
// rename: in place modify name
@ -494,21 +530,22 @@ impl vfs::INode for INodeImpl {
}
fn find(&self, name: &str) -> vfs::Result<Arc<vfs::INode>> {
let info = self.metadata()?;
if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir)
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
let inode_id = self.get_file_inode_id(name).ok_or(FsError::EntryNotFound)?;
Ok(self.fs.get_inode(inode_id))
}
fn get_entry(&self, id: usize) -> vfs::Result<String> {
if self.disk_inode.read().type_!=FileType::Dir {
return Err(FsError::NotDir)
if self.disk_inode.read().type_ != FileType::Dir {
return Err(FsError::NotDir);
}
if id >= self.disk_inode.read().blocks as usize {
return Err(FsError::EntryNotFound)
return Err(FsError::EntryNotFound);
};
let mut entry: DiskEntry = unsafe { uninitialized() };
self._read_at(id as usize * BLKSIZE, entry.as_buf_mut()).unwrap();
self._read_at(id as usize * BLKSIZE, entry.as_buf_mut())
.unwrap();
Ok(String::from(entry.name.as_ref()))
}
fn fs(&self) -> Arc<vfs::FileSystem> {
@ -522,7 +559,8 @@ impl vfs::INode for INodeImpl {
impl Drop for INodeImpl {
/// Auto sync when drop
fn drop(&mut self) {
self.sync_all().expect("Failed to sync when dropping the SimpleFileSystem Inode");
self.sync_all()
.expect("Failed to sync when dropping the SimpleFileSystem Inode");
if self.disk_inode.read().nlinks <= 0 {
self._resize(0).unwrap();
self.disk_inode.write().sync();
@ -531,7 +569,6 @@ impl Drop for INodeImpl {
}
}
/// filesystem for sfs
///
/// ## 内部可变性
@ -566,7 +603,8 @@ impl SimpleFileSystem {
inodes: RwLock::new(BTreeMap::new()),
device,
self_ptr: Weak::default(),
}.wrap())
}
.wrap())
}
/// Create a new SFS on blank disk
pub fn create(device: Arc<Device>, space: usize) -> Arc<Self> {
@ -594,13 +632,14 @@ impl SimpleFileSystem {
inodes: RwLock::new(BTreeMap::new()),
device,
self_ptr: Weak::default(),
}.wrap();
}
.wrap();
// Init root INode
let root = sfs._new_inode(BLKN_ROOT, Dirty::new_dirty(DiskINode::new_dir()));
root.init_dir_entry(BLKN_ROOT).unwrap();
root.nlinks_inc(); //for .
root.nlinks_inc(); //for ..(root's parent is itself)
root.nlinks_inc(); //for .
root.nlinks_inc(); //for ..(root's parent is itself)
root.sync_all().unwrap();
sfs
@ -613,7 +652,9 @@ impl SimpleFileSystem {
let fs = Arc::new(self);
let weak = Arc::downgrade(&fs);
let ptr = Arc::into_raw(fs) as *mut Self;
unsafe { (*ptr).self_ptr = weak; }
unsafe {
(*ptr).self_ptr = weak;
}
unsafe { Arc::from_raw(ptr) }
}
@ -623,11 +664,11 @@ impl SimpleFileSystem {
let id = free_map.alloc();
if let Some(block_id) = id {
let mut super_block = self.super_block.write();
if super_block.unused_blocks==0 {
if super_block.unused_blocks == 0 {
free_map.set(block_id, true);
return None
return None;
}
super_block.unused_blocks -= 1; // will not underflow
super_block.unused_blocks -= 1; // will not underflow
trace!("alloc block {:#x}", block_id);
}
id
@ -689,9 +730,11 @@ impl SimpleFileSystem {
}
fn flush_weak_inodes(&self) {
let mut inodes = self.inodes.write();
let remove_ids: Vec<_> = inodes.iter().filter(|(_, inode)| {
inode.upgrade().is_none()
}).map(|(&id, _)| id).collect();
let remove_ids: Vec<_> = inodes
.iter()
.filter(|(_, inode)| inode.upgrade().is_none())
.map(|(&id, _)| id)
.collect();
for id in remove_ids.iter() {
inodes.remove(&id);
}
@ -703,12 +746,16 @@ impl vfs::FileSystem for SimpleFileSystem {
fn sync(&self) -> vfs::Result<()> {
let mut super_block = self.super_block.write();
if super_block.dirty() {
self.device.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();
}
let mut free_map = self.free_map.write();
if free_map.dirty() {
self.device.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();
}
self.flush_weak_inodes();
@ -732,8 +779,8 @@ impl vfs::FileSystem for SimpleFileSystem {
blocks: sb.blocks as usize,
bfree: sb.unused_blocks as usize,
bavail: sb.unused_blocks as usize,
files: sb.blocks as usize, // inaccurate
ffree: sb.unused_blocks as usize, // inaccurate
files: sb.blocks as usize, // inaccurate
ffree: sb.unused_blocks as usize, // inaccurate
namemax: MAX_FNAME_LEN,
}
}
@ -742,7 +789,8 @@ impl vfs::FileSystem for SimpleFileSystem {
impl Drop for SimpleFileSystem {
/// Auto sync when drop
fn drop(&mut self) {
self.sync().expect("Failed to sync when dropping the SimpleFileSystem");
self.sync()
.expect("Failed to sync when dropping the SimpleFileSystem");
}
}

@ -1,9 +1,9 @@
//! On-disk structures in SFS
use core::slice;
use core::mem::{size_of_val, size_of};
use core::fmt::{Debug, Formatter, Error};
use alloc::str;
use core::fmt::{Debug, Error, Formatter};
use core::mem::{size_of, size_of_val};
use core::slice;
use static_assertions::const_assert;
/// On-disk superblock

@ -1,28 +1,27 @@
extern crate std;
use crate::*;
use rcore_fs::vfs::{FileSystem, FileType, Metadata, Result, Timespec};
use std::fs::{self, OpenOptions};
use std::mem::uninitialized;
use std::sync::Arc;
use std::sync::Mutex;
use std::mem::uninitialized;
use crate::*;
use rcore_fs::vfs::{FileSystem, Result, FileType, Metadata, Timespec};
fn _open_sample_file() -> Arc<SimpleFileSystem> {
fs::copy("sfs.img", "test.img").expect("failed to open sfs.img");
let file = OpenOptions::new()
.read(true).write(true).open("test.img")
.read(true)
.write(true)
.open("test.img")
.expect("failed to open test.img");
SimpleFileSystem::open(Arc::new(Mutex::new(file)))
.expect("failed to open SFS")
SimpleFileSystem::open(Arc::new(Mutex::new(file))).expect("failed to open SFS")
}
fn _create_new_sfs() -> Arc<SimpleFileSystem> {
let file = tempfile::tempfile()
.expect("failed to create file");
let file = tempfile::tempfile().expect("failed to create file");
SimpleFileSystem::create(Arc::new(Mutex::new(file)), 32 * 4096)
}
#[test]
#[ignore]
fn open_sample_file() {
@ -41,21 +40,24 @@ fn create_file() -> Result<()> {
let root = sfs.root_inode();
let file1 = root.create("file1", FileType::File, 0o777)?;
assert_eq!(file1.metadata()?, Metadata {
inode: 5,
size: 0,
type_: FileType::File,
mode: 0o777,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
nlinks: 1,
uid: 0,
ctime: Timespec { sec: 0, nsec: 0 },
gid: 0,
blk_size: 4096,
dev: 0,
});
assert_eq!(
file1.metadata()?,
Metadata {
inode: 5,
size: 0,
type_: FileType::File,
mode: 0o777,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
nlinks: 1,
uid: 0,
ctime: Timespec { sec: 0, nsec: 0 },
gid: 0,
blk_size: 4096,
dev: 0,
}
);
sfs.sync()?;
Ok(())
@ -75,7 +77,11 @@ fn resize() -> Result<()> {
let mut data1: [u8; SIZE2] = unsafe { uninitialized() };
let len = file1.read_at(0, data1.as_mut())?;
assert_eq!(len, SIZE1, "wrong size returned by read_at()");
assert_eq!(&data1[..SIZE1], &[0u8; SIZE1][..], "expanded data should be 0");
assert_eq!(
&data1[..SIZE1],
&[0u8; SIZE1][..],
"expanded data should be 0"
);
sfs.sync()?;
Ok(())
@ -83,23 +89,23 @@ fn resize() -> Result<()> {
#[test]
fn resize_on_dir_should_panic() -> Result<()> {
let sfs = _create_new_sfs();
let root = sfs.root_inode();
assert!(root.resize(4096).is_err());
sfs.sync()?;
let sfs = _create_new_sfs();
let root = sfs.root_inode();
assert!(root.resize(4096).is_err());
sfs.sync()?;
Ok(())
Ok(())
}
#[test]
fn resize_too_large_should_panic() -> Result<()> {
let sfs = _create_new_sfs();
let root = sfs.root_inode();
let file1 = root.create("file1", FileType::File, 0o777)?;
assert!(file1.resize(1 << 28).is_err());
sfs.sync()?;
let sfs = _create_new_sfs();
let root = sfs.root_inode();
let file1 = root.create("file1", FileType::File, 0o777)?;
assert!(file1.resize(1 << 28).is_err());
sfs.sync()?;
Ok(())
Ok(())
}
#[test]
@ -110,23 +116,50 @@ fn create_then_lookup() -> Result<()> {
assert!(Arc::ptr_eq(&root.lookup(".")?, &root), "failed to find .");
assert!(Arc::ptr_eq(&root.lookup("..")?, &root), "failed to find ..");
let file1 = root.create("file1", FileType::File, 0o777)
let file1 = root
.create("file1", FileType::File, 0o777)
.expect("failed to create file1");
assert!(Arc::ptr_eq(&root.lookup("file1")?, &file1), "failed to find file1");
assert!(
Arc::ptr_eq(&root.lookup("file1")?, &file1),
"failed to find file1"
);
assert!(root.lookup("file2").is_err(), "found non-existent file");
let dir1 = root.create("dir1", FileType::Dir, 0o777)
let dir1 = root
.create("dir1", FileType::Dir, 0o777)
.expect("failed to create dir1");
let file2 = dir1.create("file2", FileType::File, 0o777)
let file2 = dir1
.create("file2", FileType::File, 0o777)
.expect("failed to create /dir1/file2");
assert!(Arc::ptr_eq(&root.lookup("dir1/file2")?, &file2), "failed to find dir1/file2");
assert!(Arc::ptr_eq(&dir1.lookup("..")?, &root), "failed to find .. from dir1");
assert!(Arc::ptr_eq(&dir1.lookup("../dir1/file2")?, &file2), "failed to find dir1/file2 by relative");
assert!(Arc::ptr_eq(&dir1.lookup("/dir1/file2")?, &file2), "failed to find dir1/file2 by absolute");
assert!(Arc::ptr_eq(&dir1.lookup("/dir1/../dir1/file2")?, &file2), "failed to find dir1/file2 by absolute");
assert!(Arc::ptr_eq(&dir1.lookup("../../..//dir1/../dir1/file2")?, &file2), "failed to find dir1/file2 by more than one ..");
assert!(Arc::ptr_eq(&dir1.lookup("..//dir1/file2")?, &file2), "failed to find dir1/file2 by weird relative");
assert!(
Arc::ptr_eq(&root.lookup("dir1/file2")?, &file2),
"failed to find dir1/file2"
);
assert!(
Arc::ptr_eq(&dir1.lookup("..")?, &root),
"failed to find .. from dir1"
);
assert!(
Arc::ptr_eq(&dir1.lookup("../dir1/file2")?, &file2),
"failed to find dir1/file2 by relative"
);
assert!(
Arc::ptr_eq(&dir1.lookup("/dir1/file2")?, &file2),
"failed to find dir1/file2 by absolute"
);
assert!(
Arc::ptr_eq(&dir1.lookup("/dir1/../dir1/file2")?, &file2),
"failed to find dir1/file2 by absolute"
);
assert!(
Arc::ptr_eq(&dir1.lookup("../../..//dir1/../dir1/file2")?, &file2),
"failed to find dir1/file2 by more than one .."
);
assert!(
Arc::ptr_eq(&dir1.lookup("..//dir1/file2")?, &file2),
"failed to find dir1/file2 by weird relative"
);
sfs.sync()?;
Ok(())
@ -137,38 +170,72 @@ fn test_symlinks() -> Result<()> {
let sfs = _create_new_sfs();
let root = sfs.root_inode();
let file1 = root.create("file1", FileType::File, 0o777)
let file1 = root
.create("file1", FileType::File, 0o777)
.expect("failed to create file1");
assert!(Arc::ptr_eq(&root.lookup("file1")?, &file1), "failed to find file1");
assert!(
Arc::ptr_eq(&root.lookup("file1")?, &file1),
"failed to find file1"
);
let link1 = root.create("link1", FileType::SymLink, 0o777)
let link1 = root
.create("link1", FileType::SymLink, 0o777)
.expect("failed to create link1");
let data = "file1".as_bytes();
link1.resize(data.len())?;
link1.write_at(0, data)?;
let link2 = root.create("link2", FileType::SymLink, 0o777)
let link2 = root
.create("link2", FileType::SymLink, 0o777)
.expect("failed to create link2");
let data = "link1".as_bytes();
link2.resize(data.len())?;
link2.write_at(0, data)?;
assert!(Arc::ptr_eq(&root.lookup("link1")?, &link1), "failed to find link1 by relative");
assert!(Arc::ptr_eq(&root.lookup_follow("link1", 1)?, &file1), "failed to find file1 by link1");
assert!(Arc::ptr_eq(&root.lookup_follow("link2", 0)?, &link2), "failed to find link2 by link2");
assert!(Arc::ptr_eq(&root.lookup_follow("link2", 1)?, &link1), "failed to find link1 by link2");
assert!(Arc::ptr_eq(&root.lookup_follow("link2", 2)?, &file1), "failed to find file1 by link2");
let link3 = root.create("link3", FileType::SymLink, 0o777)
assert!(
Arc::ptr_eq(&root.lookup("link1")?, &link1),
"failed to find link1 by relative"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link1", 1)?, &file1),
"failed to find file1 by link1"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link2", 0)?, &link2),
"failed to find link2 by link2"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link2", 1)?, &link1),
"failed to find link1 by link2"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link2", 2)?, &file1),
"failed to find file1 by link2"
);
let link3 = root
.create("link3", FileType::SymLink, 0o777)
.expect("failed to create link3");
let data = "/link2".as_bytes();
link3.resize(data.len())?;
link3.write_at(0, data)?;
assert!(Arc::ptr_eq(&root.lookup_follow("link3", 0)?, &link3), "failed to find link3 by link3");
assert!(Arc::ptr_eq(&root.lookup_follow("link3", 1)?, &link2), "failed to find link2 by link3");
assert!(Arc::ptr_eq(&root.lookup_follow("link3", 2)?, &link1), "failed to find link1 by link3");
assert!(Arc::ptr_eq(&root.lookup_follow("link3", 3)?, &file1), "failed to find file1 by link2");
assert!(
Arc::ptr_eq(&root.lookup_follow("link3", 0)?, &link3),
"failed to find link3 by link3"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link3", 1)?, &link2),
"failed to find link2 by link3"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link3", 2)?, &link1),
"failed to find link1 by link3"
);
assert!(
Arc::ptr_eq(&root.lookup_follow("link3", 3)?, &file1),
"failed to find file1 by link2"
);
sfs.sync()?;
Ok(())
@ -381,4 +448,4 @@ fn nlinks() -> Result<()> {
sfs.sync()?;
Ok(())
}
}

@ -24,7 +24,9 @@ pub trait BlockDevice: Send + Sync {
macro_rules! try0 {
($len:expr, $res:expr) => {
if !$res {return Some($len);}
if !$res {
return Some($len);
}
};
}
@ -114,7 +116,8 @@ mod test {
#[test]
fn read() {
let buf: Mutex<[u8; 16]> = Mutex::new([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];
// all inside
@ -141,16 +144,25 @@ mod test {
// all inside
let ret = Device::write_at(&buf, 3, &res);
assert_eq!(ret, Some(6));
assert_eq!(*buf.lock().unwrap(), [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(
*buf.lock().unwrap(),
[0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0]
);
// partly inside
let ret = Device::write_at(&buf, 11, &res);
assert_eq!(ret, Some(5));
assert_eq!(*buf.lock().unwrap(), [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]);
assert_eq!(
*buf.lock().unwrap(),
[0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]
);
// all outside
let ret = Device::write_at(&buf, 16, &res);
assert_eq!(ret, Some(0));
assert_eq!(*buf.lock().unwrap(), [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]);
assert_eq!(
*buf.lock().unwrap(),
[0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]
);
}
}
}

@ -1,5 +1,5 @@
use core::fmt::{Debug, Error, Formatter};
use core::ops::{Deref, DerefMut};
use core::fmt::{Debug, Formatter, Error};
/// Dirty wraps a value of type T with functions similiar to that of a Read/Write
/// lock but simply sets a dirty flag on write(), reset on read()
@ -63,8 +63,7 @@ impl<T> Drop for Dirty<T> {
impl<T: Debug> Debug for Dirty<T> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let tag = if self.dirty {"Dirty"} else {"Clean"};
let tag = if self.dirty { "Dirty" } else { "Clean" };
write!(f, "[{}] {:?}", tag, self.value)
}
}

@ -1,5 +1,5 @@
use crate::vfs::{INode, Result, Metadata};
use alloc::{sync::Arc, string::String};
use crate::vfs::{INode, Metadata, Result};
use alloc::{string::String, sync::Arc};
pub struct File {
inode: Arc<INode>,
@ -10,7 +10,12 @@ pub struct File {
impl File {
pub fn new(inode: Arc<INode>, readable: bool, writable: bool) -> Self {
File { inode, offset: 0, readable, writable }
File {
inode,
offset: 0,
readable,
writable,
}
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
@ -34,4 +39,4 @@ impl File {
pub fn get_entry(&self, id: usize) -> Result<String> {
self.inode.get_entry(id)
}
}
}

@ -4,8 +4,8 @@
extern crate alloc;
pub mod dev;
pub mod dirty;
pub mod file;
pub mod util;
pub mod vfs;
pub mod dev;
pub mod file;

@ -39,9 +39,18 @@ impl Iterator for BlockIter {
let block_size = 1usize << self.block_size_log2;
let block = self.begin / block_size;
let begin = self.begin % block_size;
let end = if block == self.end / block_size { self.end % block_size } else { block_size };
let end = if block == self.end / block_size {
self.end % block_size
} else {
block_size
};
self.begin += end - begin;
Some(BlockRange { block, begin, end, block_size_log2 })
Some(BlockRange {
block,
begin,
end,
block_size_log2,
})
}
}
@ -51,10 +60,38 @@ mod test {
#[test]
fn block_iter() {
let mut iter = BlockIter { begin: 0x123, end: 0x2018, block_size_log2: 12 };
assert_eq!(iter.next(), Some(BlockRange { block: 0, begin: 0x123, end: 0x1000, block_size_log2: 12 }));
assert_eq!(iter.next(), Some(BlockRange { block: 1, begin: 0, end: 0x1000, block_size_log2: 12 }));
assert_eq!(iter.next(), Some(BlockRange { block: 2, begin: 0, end: 0x18, block_size_log2: 12 }));
let mut iter = BlockIter {
begin: 0x123,
end: 0x2018,
block_size_log2: 12,
};
assert_eq!(
iter.next(),
Some(BlockRange {
block: 0,
begin: 0x123,
end: 0x1000,
block_size_log2: 12
})
);
assert_eq!(
iter.next(),
Some(BlockRange {
block: 1,
begin: 0,
end: 0x1000,
block_size_log2: 12
})
);
assert_eq!(
iter.next(),
Some(BlockRange {
block: 2,
begin: 0,
end: 0x18,
block_size_log2: 12
})
);
assert_eq!(iter.next(), None);
}
}
}

@ -1,7 +1,7 @@
use alloc::{vec::Vec, string::String, sync::Arc};
use alloc::{string::String, sync::Arc, vec::Vec};
use core::any::Any;
use core::result;
use core::fmt;
use core::result;
use core::str;
/// Abstract operations on a inode.
@ -43,9 +43,7 @@ impl INode {
if info.type_ != FileType::Dir {
return Err(FsError::NotDir);
}
(0..info.size).map(|i| {
self.get_entry(i)
}).collect()
(0..info.size).map(|i| self.get_entry(i)).collect()
}
/// Lookup path from current INode, and do not follow symlinks
@ -67,7 +65,10 @@ impl INode {
}
// handle absolute path
if let Some('/') = rest_path.chars().next() {
return self.fs().root_inode().lookup_follow(&path[1..], follow_times);
return self
.fs()
.root_inode()
.lookup_follow(&path[1..], follow_times);
}
let name;
match rest_path.find('/') {
@ -91,7 +92,10 @@ impl INode {
if let Ok(path) = str::from_utf8(&content[..len]) {
if let Some('/') = path.chars().next() {
// absolute link
return result.fs().root_inode().lookup_follow(&path[1..], follow_times);
return result
.fs()
.root_inode()
.lookup_follow(&path[1..], follow_times);
} else {
// relative link
// result remains unchanged
@ -103,7 +107,7 @@ impl INode {
} else {
result = inode
}
},
}
};
}
Ok(result)
@ -153,7 +157,7 @@ pub struct Metadata {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Timespec {
pub sec: i64,
pub nsec: i32
pub nsec: i32,
}
#[derive(Debug, Eq, PartialEq)]
@ -194,18 +198,18 @@ pub struct FsInfo {
// We also panic when we can not parse the fs on disk normally
#[derive(Debug)]
pub enum FsError {
NotSupported,//E_UNIMP, or E_INVAL
NotFile,//E_ISDIR
IsDir,//E_ISDIR, used only in link
NotDir,//E_NOTDIR
EntryNotFound,//E_NOENT
EntryExist,//E_EXIST
NotSameFs,//E_XDEV
InvalidParam,//E_INVAL
NoDeviceSpace,//E_NOSPC, but is defined and not used in the original ucore, which uses E_NO_MEM
DirRemoved,//E_NOENT, when the current dir was remove by a previous unlink
DirNotEmpty,//E_NOTEMPTY
WrongFs,//E_INVAL, when we find the content on disk is wrong when opening the device
NotSupported, //E_UNIMP, or E_INVAL
NotFile, //E_ISDIR
IsDir, //E_ISDIR, used only in link
NotDir, //E_NOTDIR
EntryNotFound, //E_NOENT
EntryExist, //E_EXIST
NotSameFs, //E_XDEV
InvalidParam, //E_INVAL
NoDeviceSpace, //E_NOSPC, but is defined and not used in the original ucore, which uses E_NO_MEM
DirRemoved, //E_NOENT, when the current dir was remove by a previous unlink
DirNotEmpty, //E_NOTEMPTY
WrongFs, //E_INVAL, when we find the content on disk is wrong when opening the device
DeviceError,
}

Loading…
Cancel
Save