parent
62827eb7bb
commit
ffa42fcc55
@ -0,0 +1,222 @@
|
|||||||
|
use fuse::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyWrite, ReplyStatfs, Request};
|
||||||
|
use rcore_fs::vfs;
|
||||||
|
use std::collections::btree_map::BTreeMap;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
//use log::*;
|
||||||
|
use time::Timespec;
|
||||||
|
|
||||||
|
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
|
||||||
|
|
||||||
|
pub struct VfsFuse {
|
||||||
|
fs: Arc<vfs::FileSystem>,
|
||||||
|
inodes: BTreeMap<usize, Arc<vfs::INode>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VfsFuse {
|
||||||
|
pub fn new(fs: Arc<vfs::FileSystem>) -> Self {
|
||||||
|
let mut inodes = BTreeMap::new();
|
||||||
|
inodes.insert(1, fs.root_inode());
|
||||||
|
VfsFuse { fs, inodes }
|
||||||
|
}
|
||||||
|
fn trans_time(time: vfs::Timespec) -> Timespec {
|
||||||
|
Timespec {
|
||||||
|
sec: time.sec,
|
||||||
|
nsec: time.nsec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn trans_attr(info: vfs::Metadata) -> FileAttr {
|
||||||
|
FileAttr {
|
||||||
|
ino: info.inode as u64,
|
||||||
|
size: info.size as u64,
|
||||||
|
blocks: info.blocks as u64,
|
||||||
|
atime: Self::trans_time(info.atime),
|
||||||
|
mtime: Self::trans_time(info.mtime),
|
||||||
|
ctime: Self::trans_time(info.ctime),
|
||||||
|
crtime: Timespec { sec: 0, nsec: 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,
|
||||||
|
vfs::FileType::SymLink => FileType::Symlink,
|
||||||
|
vfs::FileType::CharDevice => FileType::CharDevice,
|
||||||
|
vfs::FileType::BlockDevice => FileType::BlockDevice,
|
||||||
|
vfs::FileType::NamedPipe => FileType::NamedPipe,
|
||||||
|
vfs::FileType::Socket => FileType::Socket,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn trans_error(err: vfs::FsError) -> i32 {
|
||||||
|
use vfs::FsError::*;
|
||||||
|
use libc::*;
|
||||||
|
match err {
|
||||||
|
NotSupported => ENOSYS,
|
||||||
|
EntryNotFound => ENOENT,
|
||||||
|
EntryExist => EEXIST,
|
||||||
|
IsDir => EISDIR,
|
||||||
|
NotFile => EISDIR,
|
||||||
|
NotDir => ENOTDIR,
|
||||||
|
NotSameFs => EXDEV,
|
||||||
|
InvalidParam => EINVAL,
|
||||||
|
NoDeviceSpace => ENOSPC,
|
||||||
|
DirRemoved => ENOENT,
|
||||||
|
DirNotEmpty => ENOTEMPTY,
|
||||||
|
WrongFs => EINVAL,
|
||||||
|
_ => EINVAL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_inode(&self, ino: u64) -> vfs::Result<&Arc<vfs::INode>> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Filesystem for VfsFuse {
|
||||||
|
fn destroy(&mut self, _req: &Request) {
|
||||||
|
self.inodes.clear();
|
||||||
|
self.fs.sync().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
|
||||||
|
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.metadata());
|
||||||
|
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) {
|
||||||
|
let inode = try_vfs!(reply, self.get_inode(ino));
|
||||||
|
let info = try_vfs!(reply, inode.metadata());
|
||||||
|
let attr = Self::trans_attr(info);
|
||||||
|
reply.attr(&TTL, &attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
let info = try_vfs!(reply, target.metadata());
|
||||||
|
self.inodes.insert(info.inode, target);
|
||||||
|
let attr = Self::trans_attr(info);
|
||||||
|
reply.entry(&TTL, &attr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mkdir(&mut self, _req: &Request, parent: u64, name: &OsStr, mode: 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::Dir, mode));
|
||||||
|
let info = try_vfs!(reply, target.metadata());
|
||||||
|
let attr = Self::trans_attr(info);
|
||||||
|
reply.entry(&TTL, &attr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlink(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEmpty) {
|
||||||
|
let name = name.to_str().unwrap();
|
||||||
|
let parent = try_vfs!(reply, self.get_inode(parent));
|
||||||
|
try_vfs!(reply, parent.unlink(name));
|
||||||
|
reply.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rmdir(&mut self, req: &Request, parent: u64, name: &OsStr, reply: ReplyEmpty) {
|
||||||
|
self.unlink(req, parent, name, reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
if parent == newparent {
|
||||||
|
let parent = try_vfs!(reply, self.get_inode(parent));
|
||||||
|
try_vfs!(reply, parent.rename(name, newname));
|
||||||
|
} else {
|
||||||
|
let parent = try_vfs!(reply, self.get_inode(parent));
|
||||||
|
let newparent = try_vfs!(reply, self.get_inode(newparent));
|
||||||
|
try_vfs!(reply, parent.move_(name, newparent, newname));
|
||||||
|
}
|
||||||
|
reply.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
try_vfs!(reply, newparent.link(newname, inode));
|
||||||
|
let info = try_vfs!(reply, inode.metadata());
|
||||||
|
let attr = Self::trans_attr(info);
|
||||||
|
reply.entry(&TTL, &attr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
try_vfs!(reply, inode.read_at(offset as usize, data.as_mut_slice()));
|
||||||
|
reply.data(data.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 info = try_vfs!(reply, inode.metadata());
|
||||||
|
let end = offset as usize + data.len();
|
||||||
|
if end > info.size {
|
||||||
|
try_vfs!(reply, inode.resize(end));
|
||||||
|
}
|
||||||
|
let len = try_vfs!(reply, inode.write_at(offset as usize, data));
|
||||||
|
reply.written(len as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self, _req: &Request, ino: u64, _fh: u64, _lock_owner: u64, reply: ReplyEmpty) {
|
||||||
|
let inode = try_vfs!(reply, self.get_inode(ino));
|
||||||
|
try_vfs!(reply, inode.sync());
|
||||||
|
reply.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&mut self, _req: &Request, ino: u64, _fh: u64, _datasync: bool, reply: ReplyEmpty) {
|
||||||
|
let inode = try_vfs!(reply, self.get_inode(ino));
|
||||||
|
try_vfs!(reply, inode.sync());
|
||||||
|
reply.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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.metadata());
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,222 +1,2 @@
|
|||||||
use fuse::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyWrite, ReplyStatfs, Request};
|
pub mod fuse;
|
||||||
use rcore_fs::vfs;
|
pub mod zip;
|
||||||
use std::collections::btree_map::BTreeMap;
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
//use log::*;
|
|
||||||
use time::Timespec;
|
|
||||||
|
|
||||||
const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second
|
|
||||||
|
|
||||||
pub struct VfsFuse<T: vfs::FileSystem> {
|
|
||||||
fs: Arc<T>,
|
|
||||||
inodes: BTreeMap<usize, Arc<vfs::INode>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: vfs::FileSystem> VfsFuse<T> {
|
|
||||||
pub fn new(fs: Arc<T>) -> Self {
|
|
||||||
let mut inodes = BTreeMap::new();
|
|
||||||
inodes.insert(1, fs.root_inode());
|
|
||||||
VfsFuse { fs, inodes }
|
|
||||||
}
|
|
||||||
fn trans_time(time: vfs::Timespec) -> Timespec {
|
|
||||||
Timespec {
|
|
||||||
sec: time.sec,
|
|
||||||
nsec: time.nsec,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn trans_attr(info: vfs::Metadata) -> FileAttr {
|
|
||||||
FileAttr {
|
|
||||||
ino: info.inode as u64,
|
|
||||||
size: info.size as u64,
|
|
||||||
blocks: info.blocks as u64,
|
|
||||||
atime: Self::trans_time(info.atime),
|
|
||||||
mtime: Self::trans_time(info.mtime),
|
|
||||||
ctime: Self::trans_time(info.ctime),
|
|
||||||
crtime: Timespec { sec: 0, nsec: 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,
|
|
||||||
vfs::FileType::SymLink => FileType::Symlink,
|
|
||||||
vfs::FileType::CharDevice => FileType::CharDevice,
|
|
||||||
vfs::FileType::BlockDevice => FileType::BlockDevice,
|
|
||||||
vfs::FileType::NamedPipe => FileType::NamedPipe,
|
|
||||||
vfs::FileType::Socket => FileType::Socket,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn trans_error(err: vfs::FsError) -> i32 {
|
|
||||||
use vfs::FsError::*;
|
|
||||||
use libc::*;
|
|
||||||
match err {
|
|
||||||
NotSupported => ENOSYS,
|
|
||||||
EntryNotFound => ENOENT,
|
|
||||||
EntryExist => EEXIST,
|
|
||||||
IsDir => EISDIR,
|
|
||||||
NotFile => EISDIR,
|
|
||||||
NotDir => ENOTDIR,
|
|
||||||
NotSameFs => EXDEV,
|
|
||||||
InvalidParam => EINVAL,
|
|
||||||
NoDeviceSpace => ENOSPC,
|
|
||||||
DirRemoved => ENOENT,
|
|
||||||
DirNotEmpty => ENOTEMPTY,
|
|
||||||
WrongFs => EINVAL,
|
|
||||||
_ => EINVAL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn get_inode(&self, ino: u64) -> vfs::Result<&Arc<vfs::INode>> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: vfs::FileSystem> Filesystem for VfsFuse<T> {
|
|
||||||
fn destroy(&mut self, _req: &Request) {
|
|
||||||
self.inodes.clear();
|
|
||||||
self.fs.sync().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
|
|
||||||
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.metadata());
|
|
||||||
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) {
|
|
||||||
let inode = try_vfs!(reply, self.get_inode(ino));
|
|
||||||
let info = try_vfs!(reply, inode.metadata());
|
|
||||||
let attr = Self::trans_attr(info);
|
|
||||||
reply.attr(&TTL, &attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
let info = try_vfs!(reply, target.metadata());
|
|
||||||
self.inodes.insert(info.inode, target);
|
|
||||||
let attr = Self::trans_attr(info);
|
|
||||||
reply.entry(&TTL, &attr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkdir(&mut self, _req: &Request, parent: u64, name: &OsStr, mode: 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::Dir, mode));
|
|
||||||
let info = try_vfs!(reply, target.metadata());
|
|
||||||
let attr = Self::trans_attr(info);
|
|
||||||
reply.entry(&TTL, &attr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlink(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEmpty) {
|
|
||||||
let name = name.to_str().unwrap();
|
|
||||||
let parent = try_vfs!(reply, self.get_inode(parent));
|
|
||||||
try_vfs!(reply, parent.unlink(name));
|
|
||||||
reply.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rmdir(&mut self, req: &Request, parent: u64, name: &OsStr, reply: ReplyEmpty) {
|
|
||||||
self.unlink(req, parent, name, reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
if parent == newparent {
|
|
||||||
let parent = try_vfs!(reply, self.get_inode(parent));
|
|
||||||
try_vfs!(reply, parent.rename(name, newname));
|
|
||||||
} else {
|
|
||||||
let parent = try_vfs!(reply, self.get_inode(parent));
|
|
||||||
let newparent = try_vfs!(reply, self.get_inode(newparent));
|
|
||||||
try_vfs!(reply, parent.move_(name, newparent, newname));
|
|
||||||
}
|
|
||||||
reply.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
try_vfs!(reply, newparent.link(newname, inode));
|
|
||||||
let info = try_vfs!(reply, inode.metadata());
|
|
||||||
let attr = Self::trans_attr(info);
|
|
||||||
reply.entry(&TTL, &attr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
try_vfs!(reply, inode.read_at(offset as usize, data.as_mut_slice()));
|
|
||||||
reply.data(data.as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
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 info = try_vfs!(reply, inode.metadata());
|
|
||||||
let end = offset as usize + data.len();
|
|
||||||
if end > info.size {
|
|
||||||
try_vfs!(reply, inode.resize(end));
|
|
||||||
}
|
|
||||||
let len = try_vfs!(reply, inode.write_at(offset as usize, data));
|
|
||||||
reply.written(len as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self, _req: &Request, ino: u64, _fh: u64, _lock_owner: u64, reply: ReplyEmpty) {
|
|
||||||
let inode = try_vfs!(reply, self.get_inode(ino));
|
|
||||||
try_vfs!(reply, inode.sync());
|
|
||||||
reply.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fsync(&mut self, _req: &Request, ino: u64, _fh: u64, _datasync: bool, reply: ReplyEmpty) {
|
|
||||||
let inode = try_vfs!(reply, self.get_inode(ino));
|
|
||||||
try_vfs!(reply, inode.sync());
|
|
||||||
reply.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
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.metadata());
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +1,104 @@
|
|||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use rcore_fs::dev::std_impl::StdTimeProvider;
|
||||||
|
use rcore_fs::vfs::FileSystem;
|
||||||
|
use rcore_fs_fuse::fuse::VfsFuse;
|
||||||
|
use rcore_fs_fuse::zip::{unzip_dir, zip_dir};
|
||||||
use rcore_fs_sefs as sefs;
|
use rcore_fs_sefs as sefs;
|
||||||
use rcore_fs_sfs as sfs;
|
use rcore_fs_sfs as sfs;
|
||||||
use rcore_fs_fuse::VfsFuse;
|
|
||||||
use rcore_fs::dev::std_impl::StdTimeProvider;
|
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
|
/// Command
|
||||||
|
#[structopt(subcommand)]
|
||||||
|
cmd: Cmd,
|
||||||
|
|
||||||
/// Image file
|
/// Image file
|
||||||
#[structopt(parse(from_os_str))]
|
#[structopt(parse(from_os_str))]
|
||||||
image: PathBuf,
|
image: PathBuf,
|
||||||
/// Mount point
|
|
||||||
|
/// Target directory
|
||||||
#[structopt(parse(from_os_str))]
|
#[structopt(parse(from_os_str))]
|
||||||
mount_point: PathBuf,
|
dir: PathBuf,
|
||||||
|
|
||||||
|
/// File system: [sfs | sefs]
|
||||||
|
#[structopt(short = "f", long = "fs", default_value = "sfs")]
|
||||||
|
fs: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
enum Cmd {
|
||||||
|
/// Create a new <image> for <dir>
|
||||||
|
#[structopt(name = "zip")]
|
||||||
|
Zip,
|
||||||
|
|
||||||
|
/// Unzip data from given <image> to <dir>
|
||||||
|
#[structopt(name = "unzip")]
|
||||||
|
Unzip,
|
||||||
|
|
||||||
|
/// Mount <image> to <dir>
|
||||||
|
#[structopt(name = "mount")]
|
||||||
|
Mount,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init().unwrap();
|
env_logger::init().unwrap();
|
||||||
let opt = Opt::from_args();
|
let opt = Opt::from_args();
|
||||||
// let img = OpenOptions::new().read(true).write(true).open(&opt.image)
|
|
||||||
// .expect("failed to open image");
|
// open or create
|
||||||
let sfs = if opt.image.is_dir() {
|
let create = match opt.cmd {
|
||||||
let img = sefs::dev::StdStorage::new(&opt.image);
|
Cmd::Mount => !opt.image.is_dir() && !opt.image.is_file(),
|
||||||
sefs::SEFS::open(Box::new(img), &StdTimeProvider)
|
Cmd::Zip => true,
|
||||||
.expect("failed to open sefs")
|
Cmd::Unzip => false,
|
||||||
} else {
|
};
|
||||||
std::fs::create_dir_all(&opt.image).unwrap();
|
|
||||||
let img = sefs::dev::StdStorage::new(&opt.image);
|
let fs: Arc<FileSystem> = match opt.fs.as_str() {
|
||||||
sefs::SEFS::create(Box::new(img), &StdTimeProvider)
|
"sfs" => {
|
||||||
.expect("failed to create sefs")
|
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(Box::new(device), MAX_SPACE),
|
||||||
|
false => sfs::SimpleFileSystem::open(Box::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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("unsupported file system"),
|
||||||
};
|
};
|
||||||
fuse::mount(VfsFuse::new(sfs), &opt.mount_point, &[])
|
match opt.cmd {
|
||||||
.expect("failed to mount fs");
|
Cmd::Mount => {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue