reformat code using `cargo fmt`

master
WangRunji 6 years ago
parent ae77625e23
commit 89e9dde1ec

@ -1,8 +1,8 @@
# rcore-fs # 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 ## 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 rcore_fs::vfs;
use std::collections::btree_map::BTreeMap; use std::collections::btree_map::BTreeMap;
use std::ffi::OsStr; use std::ffi::OsStr;
@ -6,7 +9,7 @@ use std::sync::Arc;
//use log::*; //use log::*;
use time::Timespec; 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 { pub struct VfsFuse {
fs: Arc<vfs::FileSystem>, fs: Arc<vfs::FileSystem>,
@ -55,8 +58,8 @@ impl VfsFuse {
} }
} }
fn trans_error(err: vfs::FsError) -> i32 { fn trans_error(err: vfs::FsError) -> i32 {
use vfs::FsError::*;
use libc::*; use libc::*;
use vfs::FsError::*;
match err { match err {
NotSupported => ENOSYS, NotSupported => ENOSYS,
EntryNotFound => ENOENT, EntryNotFound => ENOENT,
@ -74,19 +77,23 @@ impl VfsFuse {
} }
} }
fn get_inode(&self, ino: u64) -> vfs::Result<&Arc<vfs::INode>> { 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 /// Helper macro to reply error when VFS operation fails
macro_rules! try_vfs { macro_rules! try_vfs {
($reply:expr, $expr:expr) => (match $expr { ($reply:expr, $expr:expr) => {
Ok(val) => val, match $expr {
Err(err) => { Ok(val) => val,
$reply.error(Self::trans_error(err)); Err(err) => {
return; $reply.error(Self::trans_error(err));
return;
}
} }
}); };
} }
impl Filesystem for VfsFuse { impl Filesystem for VfsFuse {
@ -111,7 +118,15 @@ impl Filesystem for VfsFuse {
reply.attr(&TTL, &attr); 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 name = name.to_str().unwrap();
let inode = try_vfs!(reply, self.get_inode(parent)); let inode = try_vfs!(reply, self.get_inode(parent));
let target = try_vfs!(reply, inode.create(name, vfs::FileType::File, mode)); 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); 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 name = name.to_str().unwrap();
let newname = newname.to_str().unwrap(); let newname = newname.to_str().unwrap();
let parent = try_vfs!(reply, self.get_inode(parent)); let parent = try_vfs!(reply, self.get_inode(parent));
@ -150,7 +173,14 @@ impl Filesystem for VfsFuse {
reply.ok(); 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 newname = newname.to_str().unwrap();
let inode = try_vfs!(reply, self.get_inode(ino)); let inode = try_vfs!(reply, self.get_inode(ino));
let newparent = try_vfs!(reply, self.get_inode(newparent)); let newparent = try_vfs!(reply, self.get_inode(newparent));
@ -160,7 +190,15 @@ impl Filesystem for VfsFuse {
reply.entry(&TTL, &attr, 0); 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 inode = try_vfs!(reply, self.get_inode(ino));
let mut data = Vec::<u8>::new(); let mut data = Vec::<u8>::new();
data.resize(size as usize, 0); data.resize(size as usize, 0);
@ -168,7 +206,16 @@ impl Filesystem for VfsFuse {
reply.data(data.as_slice()); 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 inode = try_vfs!(reply, self.get_inode(ino));
let len = try_vfs!(reply, inode.write_at(offset as usize, data)); let len = try_vfs!(reply, inode.write_at(offset as usize, data));
reply.written(len as u32); reply.written(len as u32);
@ -190,7 +237,14 @@ impl Filesystem for VfsFuse {
reply.ok(); 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 inode = try_vfs!(reply, self.get_inode(ino));
let info = try_vfs!(reply, inode.metadata()); let info = try_vfs!(reply, inode.metadata());
let count = info.size; let count = info.size;
@ -209,8 +263,15 @@ impl Filesystem for VfsFuse {
fn statfs(&mut self, _req: &Request, _ino: u64, reply: ReplyStatfs) { fn statfs(&mut self, _req: &Request, _ino: u64, reply: ReplyStatfs) {
let info = self.fs.info(); let info = self.fs.info();
reply.statfs(info.blocks as u64, info.bfree as u64, info.bavail as u64, reply.statfs(
info.files as u64, info.ffree as u64, info.bsize as u32, info.blocks as u64,
info.namemax as u32, info.frsize as u32); 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 fuse;
pub mod zip; pub mod zip;

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

@ -5,8 +5,8 @@ use rcore_fs::vfs::FsError;
#[cfg(any(test, feature = "std"))] #[cfg(any(test, feature = "std"))]
pub use self::std_impl::*; pub use self::std_impl::*;
pub mod std_impl;
pub mod sgx_impl; pub mod sgx_impl;
pub mod std_impl;
/// A file stores a normal file or directory. /// 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<()> { fn read_exact_at(&self, buf: &mut [u8], offset: usize) -> DevResult<()> {
let len = self.read_at(buf, offset)?; 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<()> { fn write_all_at(&self, buf: &[u8], offset: usize) -> DevResult<()> {
let len = self.write_at(buf, offset)?; 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::boxed::Box;
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf}; 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::sync::SgxMutex as Mutex;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use std::untrusted::time::SystemTimeEx; // FIXME: use trusted ime 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::dev::TimeProvider;
use rcore_fs::vfs::Timespec; use rcore_fs::vfs::Timespec;
use super::{DeviceError, DevResult}; use super::{DevResult, DeviceError};
pub struct SgxStorage { pub struct SgxStorage {
path: PathBuf, path: PathBuf,
@ -19,8 +19,10 @@ pub struct SgxStorage {
impl SgxStorage { impl SgxStorage {
pub fn new(path: impl AsRef<Path>) -> Self { pub fn new(path: impl AsRef<Path>) -> Self {
// assert!(path.as_ref().is_dir()); // assert!(path.as_ref().is_dir());
SgxStorage { path: path.as_ref().to_path_buf() } SgxStorage {
path: path.as_ref().to_path_buf(),
}
} }
} }
@ -30,7 +32,10 @@ impl super::Storage for SgxStorage {
path.push(format!("{}", file_id)); path.push(format!("{}", file_id));
// TODO: key // TODO: key
let key = [0u8; 16]; 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)))) Ok(Box::new(LockedFile(Mutex::new(file))))
} }
@ -39,7 +44,10 @@ impl super::Storage for SgxStorage {
path.push(format!("{}", file_id)); path.push(format!("{}", file_id));
// TODO: key // TODO: key
let key = [0u8; 16]; 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)))) Ok(Box::new(LockedFile(Mutex::new(file))))
} }

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

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

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

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

@ -24,7 +24,9 @@ pub trait BlockDevice: Send + Sync {
macro_rules! try0 { macro_rules! try0 {
($len:expr, $res:expr) => { ($len:expr, $res:expr) => {
if !$res {return Some($len);} if !$res {
return Some($len);
}
}; };
} }
@ -114,7 +116,8 @@ mod test {
#[test] #[test]
fn read() { 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]; let mut res: [u8; 6] = [0; 6];
// all inside // all inside
@ -141,16 +144,25 @@ mod test {
// all inside // all inside
let ret = Device::write_at(&buf, 3, &res); let ret = Device::write_at(&buf, 3, &res);
assert_eq!(ret, Some(6)); 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 // partly inside
let ret = Device::write_at(&buf, 11, &res); let ret = Device::write_at(&buf, 11, &res);
assert_eq!(ret, Some(5)); 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 // all outside
let ret = Device::write_at(&buf, 16, &res); let ret = Device::write_at(&buf, 16, &res);
assert_eq!(ret, Some(0)); 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::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 /// 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() /// 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> { impl<T: Debug> Debug for Dirty<T> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { 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) write!(f, "[{}] {:?}", tag, self.value)
} }
} }

@ -1,5 +1,5 @@
use crate::vfs::{INode, Result, Metadata}; use crate::vfs::{INode, Metadata, Result};
use alloc::{sync::Arc, string::String}; use alloc::{string::String, sync::Arc};
pub struct File { pub struct File {
inode: Arc<INode>, inode: Arc<INode>,
@ -10,7 +10,12 @@ pub struct File {
impl File { impl File {
pub fn new(inode: Arc<INode>, readable: bool, writable: bool) -> Self { 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> { 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> { pub fn get_entry(&self, id: usize) -> Result<String> {
self.inode.get_entry(id) self.inode.get_entry(id)
} }
} }

@ -4,8 +4,8 @@
extern crate alloc; extern crate alloc;
pub mod dev;
pub mod dirty; pub mod dirty;
pub mod file;
pub mod util; pub mod util;
pub mod vfs; 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_size = 1usize << self.block_size_log2;
let block = self.begin / block_size; let block = self.begin / block_size;
let begin = 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; 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] #[test]
fn block_iter() { fn block_iter() {
let mut iter = BlockIter { begin: 0x123, end: 0x2018, block_size_log2: 12 }; let mut iter = BlockIter {
assert_eq!(iter.next(), Some(BlockRange { block: 0, begin: 0x123, end: 0x1000, block_size_log2: 12 })); begin: 0x123,
assert_eq!(iter.next(), Some(BlockRange { block: 1, begin: 0, end: 0x1000, block_size_log2: 12 })); end: 0x2018,
assert_eq!(iter.next(), Some(BlockRange { block: 2, begin: 0, end: 0x18, block_size_log2: 12 })); 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); 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::any::Any;
use core::result;
use core::fmt; use core::fmt;
use core::result;
use core::str; use core::str;
/// Abstract operations on a inode. /// Abstract operations on a inode.
@ -43,9 +43,7 @@ impl INode {
if info.type_ != FileType::Dir { if info.type_ != FileType::Dir {
return Err(FsError::NotDir); return Err(FsError::NotDir);
} }
(0..info.size).map(|i| { (0..info.size).map(|i| self.get_entry(i)).collect()
self.get_entry(i)
}).collect()
} }
/// Lookup path from current INode, and do not follow symlinks /// Lookup path from current INode, and do not follow symlinks
@ -67,7 +65,10 @@ impl INode {
} }
// handle absolute path // handle absolute path
if let Some('/') = rest_path.chars().next() { 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; let name;
match rest_path.find('/') { match rest_path.find('/') {
@ -91,7 +92,10 @@ impl INode {
if let Ok(path) = str::from_utf8(&content[..len]) { if let Ok(path) = str::from_utf8(&content[..len]) {
if let Some('/') = path.chars().next() { if let Some('/') = path.chars().next() {
// absolute link // 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 { } else {
// relative link // relative link
// result remains unchanged // result remains unchanged
@ -103,7 +107,7 @@ impl INode {
} else { } else {
result = inode result = inode
} }
}, }
}; };
} }
Ok(result) Ok(result)
@ -153,7 +157,7 @@ pub struct Metadata {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Timespec { pub struct Timespec {
pub sec: i64, pub sec: i64,
pub nsec: i32 pub nsec: i32,
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -194,18 +198,18 @@ pub struct FsInfo {
// We also panic when we can not parse the fs on disk normally // We also panic when we can not parse the fs on disk normally
#[derive(Debug)] #[derive(Debug)]
pub enum FsError { pub enum FsError {
NotSupported,//E_UNIMP, or E_INVAL NotSupported, //E_UNIMP, or E_INVAL
NotFile,//E_ISDIR NotFile, //E_ISDIR
IsDir,//E_ISDIR, used only in link IsDir, //E_ISDIR, used only in link
NotDir,//E_NOTDIR NotDir, //E_NOTDIR
EntryNotFound,//E_NOENT EntryNotFound, //E_NOENT
EntryExist,//E_EXIST EntryExist, //E_EXIST
NotSameFs,//E_XDEV NotSameFs, //E_XDEV
InvalidParam,//E_INVAL InvalidParam, //E_INVAL
NoDeviceSpace,//E_NOSPC, but is defined and not used in the original ucore, which uses E_NO_MEM 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 DirRemoved, //E_NOENT, when the current dir was remove by a previous unlink
DirNotEmpty,//E_NOTEMPTY DirNotEmpty, //E_NOTEMPTY
WrongFs,//E_INVAL, when we find the content on disk is wrong when opening the device WrongFs, //E_INVAL, when we find the content on disk is wrong when opening the device
DeviceError, DeviceError,
} }

Loading…
Cancel
Save