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};
|
||||
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<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);
|
||||
}
|
||||
}
|
||||
pub mod fuse;
|
||||
pub mod zip;
|
@ -1,38 +1,104 @@
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
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_sfs as sfs;
|
||||
use rcore_fs_fuse::VfsFuse;
|
||||
use rcore_fs::dev::std_impl::StdTimeProvider;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Opt {
|
||||
/// Command
|
||||
#[structopt(subcommand)]
|
||||
cmd: Cmd,
|
||||
|
||||
/// Image file
|
||||
#[structopt(parse(from_os_str))]
|
||||
image: PathBuf,
|
||||
/// Mount point
|
||||
|
||||
/// Target directory
|
||||
#[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() {
|
||||
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 = if opt.image.is_dir() {
|
||||
let img = sefs::dev::StdStorage::new(&opt.image);
|
||||
sefs::SEFS::open(Box::new(img), &StdTimeProvider)
|
||||
.expect("failed to open sefs")
|
||||
} else {
|
||||
std::fs::create_dir_all(&opt.image).unwrap();
|
||||
let img = sefs::dev::StdStorage::new(&opt.image);
|
||||
sefs::SEFS::create(Box::new(img), &StdTimeProvider)
|
||||
.expect("failed to create sefs")
|
||||
|
||||
// open or create
|
||||
let create = match opt.cmd {
|
||||
Cmd::Mount => !opt.image.is_dir() && !opt.image.is_file(),
|
||||
Cmd::Zip => true,
|
||||
Cmd::Unzip => false,
|
||||
};
|
||||
|
||||
let fs: Arc<FileSystem> = match opt.fs.as_str() {
|
||||
"sfs" => {
|
||||
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, &[])
|
||||
.expect("failed to mount fs");
|
||||
match opt.cmd {
|
||||
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