impl basic FUSE that support 'ls' 'cat'

master
WangRunji 6 years ago
parent 48b3c2618a
commit 1eb25f7422

@ -13,6 +13,7 @@ required-features = ["std"]
bit-vec = { default-features = false, git = "https://github.com/AltSysrq/bit-vec.git" } # default-features contains 'std'
static_assertions = "0.3"
spin = "0.4"
time = "0.1"
[features]
std = []

@ -0,0 +1,14 @@
[package]
name = "rcore-fs-fuse"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
edition = "2018"
[dependencies]
time = "0.1"
libc = "0.2"
log = "0.4"
fuse = "0.3"
structopt = "0.2"
env_logger = "0.3"
simple-filesystem = { path = "..", features = ["std"] }

@ -0,0 +1,137 @@
use std::collections::btree_map::BTreeMap;
use std::ffi::OsStr;
use std::fs::OpenOptions;
use std::path::PathBuf;
use std::sync::Arc;
use fuse::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, Request};
use libc;
use structopt::StructOpt;
use time::Timespec;
use log::*;
use simple_filesystem::{sfs, vfs};
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
struct VfsWrapper<T: vfs::FileSystem> {
fs: Arc<T>,
inodes: BTreeMap<usize, Arc<vfs::INode>>,
}
impl<T: vfs::FileSystem> VfsWrapper<T> {
fn new(fs: Arc<T>) -> Self {
let mut inodes = BTreeMap::new();
inodes.insert(1, fs.root_inode());
VfsWrapper { fs, inodes }
}
fn trans_attr(info: vfs::FileInfo) -> FileAttr {
FileAttr {
ino: info.inode as u64,
size: info.size as u64,
blocks: info.blocks as u64,
atime: info.atime,
mtime: info.mtime,
ctime: info.ctime,
crtime: Timespec::new(0, 0),
kind: Self::trans_type(info.type_),
perm: info.mode,
nlink: info.nlinks as u32,
uid: info.uid as u32,
gid: info.gid as u32,
rdev: 0,
flags: 0,
}
}
fn trans_type(type_: vfs::FileType) -> FileType {
match type_ {
vfs::FileType::File => FileType::RegularFile,
vfs::FileType::Dir => FileType::Directory,
}
}
fn get_inode(&self, ino: u64) -> vfs::Result<&Arc<vfs::INode>> {
self.inodes.get(&(ino as usize)).ok_or(vfs::FsError::EntryNotFound)
}
}
macro_rules! try_vfs {
($reply:expr, $expr:expr) => (match $expr {
Ok(val) => val,
Err(err) => {
let error_code = match err {
vfs::FsError::EntryNotFound => libc::ENOENT,
_ => libc::EINVAL,
};
$reply.error(error_code);
return;
}
});
}
impl<T: vfs::FileSystem> Filesystem for VfsWrapper<T> {
fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
info!("lookup parent={} name={}", parent, name.to_str().unwrap());
let inode = try_vfs!(reply, self.get_inode(parent));
let target = try_vfs!(reply, inode.lookup(name.to_str().unwrap()));
let info = try_vfs!(reply, target.info());
self.inodes.insert(info.inode, target);
let attr = Self::trans_attr(info);
reply.entry(&TTL, &attr, 0);
}
fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
info!("getattr ino={}", ino);
let inode = try_vfs!(reply, self.get_inode(ino));
let info = try_vfs!(reply, inode.info());
let attr = Self::trans_attr(info);
reply.attr(&TTL, &attr);
}
fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, size: u32, reply: ReplyData) {
info!("read ino={} offset={} size={}", ino, offset, size);
let inode = try_vfs!(reply, self.get_inode(ino));
let mut data = Vec::<u8>::new();
data.resize(size as usize, 0);
try_vfs!(reply, inode.read_at(offset as usize, data.as_mut_slice()));
reply.data(data.as_slice());
}
fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
info!("readdir ino={}, offset={}", ino, offset);
let inode = try_vfs!(reply, self.get_inode(ino));
let info = try_vfs!(reply, inode.info());
let count = info.size;
for i in offset as usize..count {
let name = inode.get_entry(i).unwrap();
let inode = try_vfs!(reply, inode.find(name.as_str()));
let info = try_vfs!(reply, inode.info());
let kind = Self::trans_type(info.type_);
let full = reply.add(info.inode as u64, i as i64 + 1, kind, name);
if full {
break;
}
}
reply.ok();
}
}
#[derive(Debug, StructOpt)]
struct Opt {
/// Image file
#[structopt(parse(from_os_str))]
image: PathBuf,
/// Mount point
#[structopt(parse(from_os_str))]
mount_point: PathBuf,
}
fn main() {
env_logger::init().unwrap();
let opt = Opt::from_args();
let img = OpenOptions::new().read(true).write(true).open(&opt.image)
.expect("failed to open image");
let sfs = sfs::SimpleFileSystem::open(Box::new(img))
.expect("failed to open sfs");
fuse::mount(VfsWrapper::new(sfs), &opt.mount_point, &[])
.expect("failed to mount fs");
}

@ -17,8 +17,8 @@ macro_rules! eprintln {
mod dirty;
mod util;
mod blocked_device;
mod vfs;
mod sfs;
pub mod vfs;
pub mod sfs;
pub mod file;
mod structs;
#[cfg(test)]

@ -1,14 +1,17 @@
use bit_vec::BitVec;
use alloc::{boxed::Box, vec::Vec, collections::BTreeMap, sync::{Arc, Weak}, string::String};
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;
use core::slice;
use core::fmt::{Debug, Formatter, Error};
use core::any::Any;
use bit_vec::BitVec;
use spin::{Mutex, RwLock};
use time::Timespec;
use crate::dirty::Dirty;
use crate::structs::*;
use crate::vfs::{self, Device, INode, FileSystem, FsError};
use crate::util::*;
use crate::vfs::{self, Device, FileSystem, FsError, INode};
impl Device {
fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> vfs::Result<()> {
@ -265,15 +268,21 @@ impl vfs::INode for INodeImpl {
fn info(&self) -> vfs::Result<vfs::FileInfo> {
let disk_inode = self.disk_inode.read();
Ok(vfs::FileInfo {
inode: self.id,
size: match disk_inode.type_ {
FileType::File => disk_inode.size as usize,
FileType::Dir => disk_inode.blocks as usize,
_ => panic!("Unknown file type"),
},
mode: 0,
mode: 0o777,
type_: vfs::FileType::from(disk_inode.type_.clone()),
blocks: disk_inode.blocks as usize,
atime: Timespec::new(0, 0),
mtime: Timespec::new(0, 0),
ctime: Timespec::new(0, 0),
nlinks: disk_inode.nlinks as usize,
uid: 0,
gid: 0,
})
}
fn sync(&self) -> vfs::Result<()> {

@ -1,6 +1,7 @@
use alloc::{vec::Vec, string::String, sync::Arc};
use core::any::Any;
use core::result;
use time::Timespec;
/// Interface for FS to read & write
/// TODO: use std::io::{Read, Write}
@ -80,15 +81,34 @@ impl INode {
#[derive(Debug, Eq, PartialEq)]
pub struct FileInfo {
// Note: for normal file size is the actuate file size
// for directory this is count of dirent.
/// Inode number
pub inode: usize,
/// Size in bytes
///
/// SFS Note: for normal file size is the actuate file size
/// for directory this is count of dirent.
pub size: usize,
pub mode: u32,
pub type_: FileType,
/// Size in blocks
pub blocks: usize,
// Note: different from linux, "." and ".." count in nlinks
// this is same as original ucore.
/// Time of last access
pub atime: Timespec,
/// Time of last modification
pub mtime: Timespec,
/// Time of last change
pub ctime: Timespec,
/// Type of file
pub type_: FileType,
/// Permission
pub mode: u16,
/// Number of hard links
///
/// SFS Note: different from linux, "." and ".." count in nlinks
/// this is same as original ucore.
pub nlinks: usize,
/// User id
pub uid: usize,
/// Group id
pub gid: usize,
}
#[derive(Debug, Eq, PartialEq)]

Loading…
Cancel
Save