ls/ll works now
This commit is contained in:
parent
bdcda26d77
commit
d36a717b11
5 changed files with 333 additions and 87 deletions
|
|
@ -1,6 +1,3 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use fat_bits::FatFs;
|
use fat_bits::FatFs;
|
||||||
use fat_bits::dir::DirEntry;
|
use fat_bits::dir::DirEntry;
|
||||||
use fat_bits::fat::Fatty as _;
|
use fat_bits::fat::Fatty as _;
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,15 @@ use std::ffi::c_int;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use fat_bits::dir::DirEntry;
|
use fat_bits::dir::DirEntry;
|
||||||
use fuser::Filesystem;
|
use fuser::{FileType, Filesystem};
|
||||||
use libc::{EIO, ENOENT, ENOSYS, EPERM};
|
use libc::{EINVAL, EIO, ENOENT, ENOSYS, ENOTDIR};
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
|
|
||||||
use crate::FatFuse;
|
use crate::FatFuse;
|
||||||
use crate::inode::Inode;
|
use crate::inode::Inode;
|
||||||
|
|
||||||
|
const TTL: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
impl Filesystem for FatFuse {
|
impl Filesystem for FatFuse {
|
||||||
fn init(
|
fn init(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -32,14 +34,18 @@ impl Filesystem for FatFuse {
|
||||||
|
|
||||||
let Some(name) = name.to_str() else {
|
let Some(name) = name.to_str() else {
|
||||||
// TODO: add proper handling of non-utf8 strings
|
// TODO: add proper handling of non-utf8 strings
|
||||||
|
debug!("cannot convert OsStr {:?} to str", name);
|
||||||
reply.error(ENOSYS);
|
reply.error(ENOSYS);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("looking up file {} with parent ino {}", name, parent);
|
||||||
|
|
||||||
let Some(parent_inode) = self.get_inode(parent) else {
|
let Some(parent_inode) = self.get_inode(parent) else {
|
||||||
// parent inode does not exist
|
// parent inode does not exist
|
||||||
// TODO: how can we make sure this does not happed?
|
// TODO: how can we make sure this does not happed?
|
||||||
// TODO: panic?
|
// TODO: panic?
|
||||||
|
debug!("could not find inode for parent ino {}", parent);
|
||||||
reply.error(EIO);
|
reply.error(EIO);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -67,29 +73,33 @@ impl Filesystem for FatFuse {
|
||||||
}) {
|
}) {
|
||||||
Ok(dir_entry) => dir_entry,
|
Ok(dir_entry) => dir_entry,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
debug!("error: {}", err);
|
||||||
reply.error(err);
|
reply.error(err);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let inode = match self.get_inode_by_first_cluster(dir_entry.first_cluster()) {
|
// let inode = match self.get_inode_by_first_cluster(dir_entry.first_cluster()) {
|
||||||
Some(inode) => inode,
|
// Some(inode) => inode,
|
||||||
None => {
|
// None => {
|
||||||
// no inode found, make a new one
|
// // no inode found, make a new one
|
||||||
|
// let ino = self.next_ino();
|
||||||
|
|
||||||
let ino = self.next_ino();
|
// let inode = Inode::new(&self.fat_fs, &dir_entry, ino, self.uid, self.gid);
|
||||||
|
|
||||||
let inode = Inode::new(&self.fat_fs, dir_entry, ino, self.uid, self.gid);
|
// self.insert_inode(inode)
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
self.insert_inode(inode)
|
let inode = self.get_or_make_inode_by_dir_entry(&dir_entry);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let attr = inode.file_attr();
|
let attr = inode.file_attr();
|
||||||
let generation = inode.generation();
|
let generation = inode.generation();
|
||||||
|
|
||||||
reply.entry(&Duration::from_secs(1), &attr, generation as u64);
|
reply.entry(&TTL, &attr, generation as u64);
|
||||||
|
|
||||||
|
inode.refcount_inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forget(&mut self, _req: &fuser::Request<'_>, ino: u64, nlookup: u64) {
|
fn forget(&mut self, _req: &fuser::Request<'_>, ino: u64, nlookup: u64) {
|
||||||
|
|
@ -99,18 +109,9 @@ impl Filesystem for FatFuse {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let ref_count = inode.ref_count_mut();
|
// *ref_count = ref_count.saturating_sub(nlookup);
|
||||||
|
|
||||||
if *ref_count < nlookup {
|
if inode.refcount_dec(nlookup) == 0 {
|
||||||
debug!(
|
|
||||||
"tried to forget {} refs of inode {}, but ref_count is only {}",
|
|
||||||
nlookup, ino, *ref_count
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
*ref_count = ref_count.saturating_sub(nlookup);
|
|
||||||
|
|
||||||
if *ref_count == 0 {
|
|
||||||
// no more references, drop inode
|
// no more references, drop inode
|
||||||
self.drop_inode(ino);
|
self.drop_inode(ino);
|
||||||
}
|
}
|
||||||
|
|
@ -123,8 +124,28 @@ impl Filesystem for FatFuse {
|
||||||
fh: Option<u64>,
|
fh: Option<u64>,
|
||||||
reply: fuser::ReplyAttr,
|
reply: fuser::ReplyAttr,
|
||||||
) {
|
) {
|
||||||
warn!("[Not Implemented] getattr(ino: {:#x?}, fh: {:#x?})", ino, fh);
|
// warn!("[Not Implemented] getattr(ino: {:#x?}, fh: {:#x?})", ino, fh);
|
||||||
reply.error(ENOSYS);
|
// reply.error(ENOSYS);
|
||||||
|
|
||||||
|
let inode = if let Some(fh) = fh {
|
||||||
|
let Some(inode) = self.get_inode_by_fh(fh) else {
|
||||||
|
reply.error(EIO);
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
inode
|
||||||
|
} else if let Some(inode) = self.get_inode(ino) {
|
||||||
|
inode
|
||||||
|
} else {
|
||||||
|
reply.error(EIO);
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let attr = inode.file_attr();
|
||||||
|
|
||||||
|
reply.attr(&TTL, &attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setattr(
|
fn setattr(
|
||||||
|
|
@ -232,27 +253,19 @@ impl Filesystem for FatFuse {
|
||||||
reply.error(ENOSYS);
|
reply.error(ENOSYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link(
|
fn open(&mut self, _req: &fuser::Request<'_>, ino: u64, _flags: i32, reply: fuser::ReplyOpen) {
|
||||||
&mut self,
|
if !self.inode_table.contains_key(&ino) {
|
||||||
_req: &fuser::Request<'_>,
|
reply.error(EINVAL);
|
||||||
ino: u64,
|
return;
|
||||||
newparent: u64,
|
}
|
||||||
newname: &std::ffi::OsStr,
|
|
||||||
reply: fuser::ReplyEntry,
|
let fh = self.next_fh();
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"[Not Implemented] link(ino: {:#x?}, newparent: {:#x?}, newname: {:?})",
|
|
||||||
ino, newparent, newname
|
|
||||||
);
|
|
||||||
reply.error(EPERM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(old_ino) = self.ino_by_fh.insert(fh, ino) {
|
if let Some(old_ino) = self.ino_by_fh.insert(fh, ino) {
|
||||||
debug!("fh {} was associated with ino {}, now with ino {}", fh, old_ino, ino);
|
debug!("fh {} was associated with ino {}, now with ino {}", fh, old_ino, ino);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(&mut self, _req: &fuser::Request<'_>, _ino: u64, _flags: i32, reply: fuser::ReplyOpen) {
|
reply.opened(fh, 0);
|
||||||
reply.opened(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(
|
fn read(
|
||||||
|
|
@ -343,11 +356,17 @@ impl Filesystem for FatFuse {
|
||||||
fn opendir(
|
fn opendir(
|
||||||
&mut self,
|
&mut self,
|
||||||
_req: &fuser::Request<'_>,
|
_req: &fuser::Request<'_>,
|
||||||
_ino: u64,
|
ino: u64,
|
||||||
_flags: i32,
|
_flags: i32,
|
||||||
reply: fuser::ReplyOpen,
|
reply: fuser::ReplyOpen,
|
||||||
) {
|
) {
|
||||||
reply.opened(0, 0);
|
let fh = self.next_fh();
|
||||||
|
|
||||||
|
if let Some(old_ino) = self.ino_by_fh.insert(fh, ino) {
|
||||||
|
debug!("fh {} was already associated with ino {}, now with ino {}", fh, old_ino, ino);
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.opened(fh, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readdir(
|
fn readdir(
|
||||||
|
|
@ -356,10 +375,79 @@ impl Filesystem for FatFuse {
|
||||||
ino: u64,
|
ino: u64,
|
||||||
fh: u64,
|
fh: u64,
|
||||||
offset: i64,
|
offset: i64,
|
||||||
reply: fuser::ReplyDirectory,
|
mut reply: fuser::ReplyDirectory,
|
||||||
) {
|
) {
|
||||||
warn!("[Not Implemented] readdir(ino: {:#x?}, fh: {}, offset: {})", ino, fh, offset);
|
let Ok(mut offset): Result<usize, _> = offset.try_into() else {
|
||||||
reply.error(ENOSYS);
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(inode) = self.get_inode_by_fh(fh) else {
|
||||||
|
debug!("could not find inode accociated with fh {} (ino: {})", fh, ino);
|
||||||
|
|
||||||
|
reply.error(EINVAL);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if inode.ino() != ino {
|
||||||
|
debug!(
|
||||||
|
"ino {} of inode associated with fh {} does not match given ino {}",
|
||||||
|
inode.ino(),
|
||||||
|
fh,
|
||||||
|
ino
|
||||||
|
);
|
||||||
|
|
||||||
|
reply.error(EINVAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut _next_idx = 1;
|
||||||
|
let mut next_offset = || {
|
||||||
|
let next_idx = _next_idx;
|
||||||
|
_next_idx += 1;
|
||||||
|
next_idx
|
||||||
|
};
|
||||||
|
|
||||||
|
if inode.is_root() {
|
||||||
|
if offset == 0 {
|
||||||
|
debug!("adding . to root dir");
|
||||||
|
if reply.add(1, next_offset(), FileType::Directory, ".") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset == 0 {
|
||||||
|
debug!("adding .. to root dir");
|
||||||
|
if reply.add(1, next_offset(), FileType::Directory, "..") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(dir_iter) = inode.dir_iter(&self.fat_fs) else {
|
||||||
|
reply.error(ENOTDIR);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// need to drop dir_iter here so we can borrow self mut again
|
||||||
|
// also skip over `offset` entries
|
||||||
|
let dirs: Vec<DirEntry> = dir_iter.skip(offset).collect();
|
||||||
|
|
||||||
|
for dir_entry in dirs {
|
||||||
|
let name = dir_entry.name_string().unwrap_or("<invalid>".into());
|
||||||
|
|
||||||
|
let inode: &Inode = self.get_or_make_inode_by_dir_entry(&dir_entry);
|
||||||
|
|
||||||
|
debug!("adding entry {} (ino: {})", name, inode.ino());
|
||||||
|
if reply.add(ino, next_offset(), inode.kind().into(), name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readdirplus(
|
fn readdirplus(
|
||||||
|
|
@ -380,11 +468,34 @@ impl Filesystem for FatFuse {
|
||||||
fn releasedir(
|
fn releasedir(
|
||||||
&mut self,
|
&mut self,
|
||||||
_req: &fuser::Request<'_>,
|
_req: &fuser::Request<'_>,
|
||||||
_ino: u64,
|
ino: u64,
|
||||||
_fh: u64,
|
fh: u64,
|
||||||
_flags: i32,
|
_flags: i32,
|
||||||
reply: fuser::ReplyEmpty,
|
reply: fuser::ReplyEmpty,
|
||||||
) {
|
) {
|
||||||
|
let Some(ino) = self.ino_by_fh.remove(&fh) else {
|
||||||
|
debug!("can't find inode {} by fh {}", ino, fh);
|
||||||
|
|
||||||
|
reply.error(EIO);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(inode) = self.inode_table.get(&ino) else {
|
||||||
|
debug!("ino {} not associated with an inode", ino);
|
||||||
|
|
||||||
|
reply.ok();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if inode.ino() != ino {
|
||||||
|
debug!(
|
||||||
|
"inode with ino {}, associated with fh {}, does not have expected ino {}",
|
||||||
|
inode.ino(),
|
||||||
|
fh,
|
||||||
|
ino
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
reply.ok();
|
reply.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use fat_bits::FatFs;
|
||||||
use fat_bits::dir::DirEntry;
|
use fat_bits::dir::DirEntry;
|
||||||
use fuser::FileAttr;
|
use fuser::FileAttr;
|
||||||
use libc::ENOTDIR;
|
use libc::ENOTDIR;
|
||||||
|
use log::debug;
|
||||||
use rand::{Rng, SeedableRng as _};
|
use rand::{Rng, SeedableRng as _};
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
|
@ -91,7 +92,7 @@ impl Inode {
|
||||||
((secs as u32) << 16) | rand as u32
|
((secs as u32) << 16) | rand as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(fat_fs: &FatFs, dir_entry: DirEntry, ino: u64, uid: u32, gid: u32) -> Inode {
|
pub fn new(fat_fs: &FatFs, dir_entry: &DirEntry, ino: u64, uid: u32, gid: u32) -> Inode {
|
||||||
assert!(dir_entry.is_file() || dir_entry.is_dir());
|
assert!(dir_entry.is_file() || dir_entry.is_dir());
|
||||||
|
|
||||||
let generation = Self::new_generation();
|
let generation = Self::new_generation();
|
||||||
|
|
@ -114,6 +115,12 @@ impl Inode {
|
||||||
let mtime = datetime_to_system(dir_entry.write_time());
|
let mtime = datetime_to_system(dir_entry.write_time());
|
||||||
let crtime = datetime_to_system(dir_entry.create_time());
|
let crtime = datetime_to_system(dir_entry.create_time());
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"creating new inode: ino: {} name: {}",
|
||||||
|
ino,
|
||||||
|
dir_entry.name_string().unwrap_or("<invalid>".into())
|
||||||
|
);
|
||||||
|
|
||||||
Inode {
|
Inode {
|
||||||
ino,
|
ino,
|
||||||
generation,
|
generation,
|
||||||
|
|
@ -131,6 +138,28 @@ impl Inode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn root_inode(fat_fs: &FatFs, uid: u32, gid: u32) -> Inode {
|
||||||
|
// let generation = Self::new_generation();
|
||||||
|
|
||||||
|
let root_cluster = fat_fs.bpb().root_cluster().unwrap_or(0);
|
||||||
|
|
||||||
|
Inode {
|
||||||
|
ino: 1,
|
||||||
|
generation: 0,
|
||||||
|
ref_count: 0,
|
||||||
|
size: 0,
|
||||||
|
block_size: fat_fs.bpb().bytes_per_sector() as u32,
|
||||||
|
kind: Kind::Dir,
|
||||||
|
read_only: false,
|
||||||
|
atime: SystemTime::UNIX_EPOCH,
|
||||||
|
mtime: SystemTime::UNIX_EPOCH,
|
||||||
|
crtime: SystemTime::UNIX_EPOCH,
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
|
first_cluster: root_cluster,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ino(&self) -> u64 {
|
pub fn ino(&self) -> u64 {
|
||||||
self.ino
|
self.ino
|
||||||
}
|
}
|
||||||
|
|
@ -143,14 +172,37 @@ impl Inode {
|
||||||
self.ref_count
|
self.ref_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ref_count_mut(&mut self) -> &mut u64 {
|
pub fn refcount_inc(&mut self) {
|
||||||
&mut self.ref_count
|
self.ref_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn refcount_dec(&mut self, n: u64) -> u64 {
|
||||||
|
if self.ref_count < n {
|
||||||
|
debug!(
|
||||||
|
"inode {}: tried to decrement refcount by {}, but is only {}",
|
||||||
|
self.ino(),
|
||||||
|
n,
|
||||||
|
self.ref_count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ref_count = self.ref_count.saturating_sub(n);
|
||||||
|
|
||||||
|
self.ref_count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> Kind {
|
||||||
|
self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first_cluster(&self) -> u32 {
|
pub fn first_cluster(&self) -> u32 {
|
||||||
self.first_cluster
|
self.first_cluster
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_root(&self) -> bool {
|
||||||
|
self.ino == ROOT_INO
|
||||||
|
}
|
||||||
|
|
||||||
pub fn file_attr(&self) -> FileAttr {
|
pub fn file_attr(&self) -> FileAttr {
|
||||||
let perm = if self.read_only { 0o555 } else { 0o777 };
|
let perm = if self.read_only { 0o555 } else { 0o777 };
|
||||||
|
|
||||||
|
|
@ -180,7 +232,7 @@ impl Inode {
|
||||||
return Err(ENOTDIR);
|
return Err(ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ino == ROOT_INO {
|
if self.is_root() {
|
||||||
// root dir
|
// root dir
|
||||||
|
|
||||||
return Ok(fat_fs.root_dir_iter());
|
return Ok(fat_fs.root_dir_iter());
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
mod fuse;
|
mod fuse;
|
||||||
mod inode;
|
mod inode;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
|
use fat_bits::dir::DirEntry;
|
||||||
use fat_bits::{FatFs, SliceLike};
|
use fat_bits::{FatFs, SliceLike};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
|
|
@ -18,11 +17,25 @@ pub struct FatFuse {
|
||||||
gid: u32,
|
gid: u32,
|
||||||
|
|
||||||
next_ino: u64,
|
next_ino: u64,
|
||||||
next_fd: u32,
|
next_fh: u64,
|
||||||
|
|
||||||
inode_table: BTreeMap<u64, Inode>,
|
inode_table: BTreeMap<u64, Inode>,
|
||||||
|
|
||||||
ino_by_first_cluster: BTreeMap<u32, u64>,
|
ino_by_first_cluster: BTreeMap<u32, u64>,
|
||||||
|
ino_by_fh: BTreeMap<u64, u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FatFuse {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
println!("inode_table: {}", self.inode_table.len());
|
||||||
|
|
||||||
|
println!("ino_by_first_cluster: {}", self.ino_by_first_cluster.len());
|
||||||
|
for (&first_cluster, &ino) in self.ino_by_first_cluster.iter() {
|
||||||
|
println!("{} -> {}", first_cluster, ino);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("ino_by_fh: {}", self.ino_by_fh.len());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FatFuse {
|
impl FatFuse {
|
||||||
|
|
@ -35,17 +48,24 @@ impl FatFuse {
|
||||||
|
|
||||||
let fat_fs = FatFs::load(data)?;
|
let fat_fs = FatFs::load(data)?;
|
||||||
|
|
||||||
// TODO: build and insert root dir inode
|
let mut fat_fuse = FatFuse {
|
||||||
|
|
||||||
Ok(FatFuse {
|
|
||||||
fat_fs,
|
fat_fs,
|
||||||
uid,
|
uid,
|
||||||
gid,
|
gid,
|
||||||
next_ino: 2, // 0 is reserved and 1 is root
|
next_ino: 2, // 0 is reserved and 1 is root
|
||||||
next_fd: 0,
|
next_fh: 0,
|
||||||
inode_table: BTreeMap::new(),
|
inode_table: BTreeMap::new(),
|
||||||
ino_by_first_cluster: BTreeMap::new(),
|
ino_by_first_cluster: BTreeMap::new(),
|
||||||
})
|
ino_by_fh: BTreeMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: build and insert root dir inode
|
||||||
|
|
||||||
|
let root_inode = Inode::root_inode(&fat_fuse.fat_fs, uid, gid);
|
||||||
|
|
||||||
|
fat_fuse.insert_inode(root_inode);
|
||||||
|
|
||||||
|
Ok(fat_fuse)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_ino(&mut self) -> u64 {
|
fn next_ino(&mut self) -> u64 {
|
||||||
|
|
@ -58,6 +78,16 @@ impl FatFuse {
|
||||||
ino
|
ino
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_fh(&mut self) -> u64 {
|
||||||
|
let fh = self.next_fh;
|
||||||
|
|
||||||
|
assert!(!self.ino_by_fh.contains_key(&fh));
|
||||||
|
|
||||||
|
self.next_fh += 1;
|
||||||
|
|
||||||
|
fh
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_inode(&mut self, inode: Inode) -> &mut Inode {
|
fn insert_inode(&mut self, inode: Inode) -> &mut Inode {
|
||||||
let ino = inode.ino();
|
let ino = inode.ino();
|
||||||
let generation = inode.generation();
|
let generation = inode.generation();
|
||||||
|
|
@ -81,8 +111,6 @@ impl FatFuse {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let old_ino = self.ino_by_first_cluster.insert(first_cluster, ino);
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"inserted new inode with ino {} and generation {} (first cluster: {})",
|
"inserted new inode with ino {} and generation {} (first cluster: {})",
|
||||||
ino, generation, first_cluster
|
ino, generation, first_cluster
|
||||||
|
|
@ -92,14 +120,18 @@ impl FatFuse {
|
||||||
debug!("ejected inode {} {}", old_inode.ino(), old_inode.generation());
|
debug!("ejected inode {} {}", old_inode.ino(), old_inode.generation());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(old_ino) = old_ino {
|
if first_cluster != 0 {
|
||||||
debug!("ejected old {} -> {} cluster to ino mapping", first_cluster, old_ino);
|
if let Some(old_ino) = self.ino_by_first_cluster.insert(first_cluster, ino) {
|
||||||
|
debug!("ejected old {} -> {} cluster to ino mapping", first_cluster, old_ino);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new_inode
|
new_inode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drop_inode(&mut self, ino: u64) {
|
fn drop_inode(&mut self, ino: u64) {
|
||||||
|
debug!("dropping ino {}", ino);
|
||||||
|
|
||||||
let Some(inode) = self.inode_table.remove(&ino) else {
|
let Some(inode) = self.inode_table.remove(&ino) else {
|
||||||
debug!("tried to drop inode with ino {}, but was not in table", ino);
|
debug!("tried to drop inode with ino {}, but was not in table", ino);
|
||||||
|
|
||||||
|
|
@ -108,30 +140,30 @@ impl FatFuse {
|
||||||
|
|
||||||
let first_cluster = inode.first_cluster();
|
let first_cluster = inode.first_cluster();
|
||||||
|
|
||||||
let entry = self.ino_by_first_cluster.entry(first_cluster);
|
if first_cluster != 0 {
|
||||||
|
let entry = self.ino_by_first_cluster.entry(first_cluster);
|
||||||
|
|
||||||
match entry {
|
match entry {
|
||||||
std::collections::btree_map::Entry::Vacant(_) => debug!(
|
std::collections::btree_map::Entry::Vacant(_) => debug!(
|
||||||
"removed inode with ino {} from table, but it's first cluster did not point to any ino",
|
"removed inode with ino {} from table, but it's first cluster did not point to any ino",
|
||||||
ino
|
ino
|
||||||
),
|
),
|
||||||
std::collections::btree_map::Entry::Occupied(occupied_entry) => {
|
std::collections::btree_map::Entry::Occupied(occupied_entry) => {
|
||||||
let found_ino = *occupied_entry.get();
|
let found_ino = *occupied_entry.get();
|
||||||
|
|
||||||
if found_ino == ino {
|
if found_ino == ino {
|
||||||
// matches our inode, remove it
|
// matches our inode, remove it
|
||||||
occupied_entry.remove();
|
occupied_entry.remove();
|
||||||
} else {
|
} else {
|
||||||
// does not match removed inode, leave it as is
|
// does not match removed inode, leave it as is
|
||||||
debug!(
|
debug!(
|
||||||
"removed inode with ino {} from table, but it's first cluster pointer to ino {} instead",
|
"removed inode with ino {} from table, but it's first cluster pointer to ino {} instead",
|
||||||
ino, found_ino
|
ino, found_ino
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_inode(&self, ino: u64) -> Option<&Inode> {
|
fn get_inode(&self, ino: u64) -> Option<&Inode> {
|
||||||
|
|
@ -142,7 +174,31 @@ impl FatFuse {
|
||||||
self.inode_table.get_mut(&ino)
|
self.inode_table.get_mut(&ino)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_or_make_inode_by_dir_entry(&mut self, dir_entry: &DirEntry) -> &mut Inode {
|
||||||
|
if self
|
||||||
|
.get_inode_by_first_cluster_mut(dir_entry.first_cluster())
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return self
|
||||||
|
.get_inode_by_first_cluster_mut(dir_entry.first_cluster())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// no inode found, make a new one
|
||||||
|
let ino = self.next_ino();
|
||||||
|
|
||||||
|
let inode = Inode::new(&self.fat_fs, dir_entry, ino, self.uid, self.gid);
|
||||||
|
|
||||||
|
self.insert_inode(inode)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_inode_by_first_cluster(&self, first_cluster: u32) -> Option<&Inode> {
|
pub fn get_inode_by_first_cluster(&self, first_cluster: u32) -> Option<&Inode> {
|
||||||
|
if first_cluster == 0 {
|
||||||
|
debug!("trying to get inode by first cluster 0");
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let ino = self.ino_by_first_cluster.get(&first_cluster)?;
|
let ino = self.ino_by_first_cluster.get(&first_cluster)?;
|
||||||
|
|
||||||
if let Some(inode) = self.inode_table.get(ino) {
|
if let Some(inode) = self.inode_table.get(ino) {
|
||||||
|
|
@ -158,6 +214,12 @@ impl FatFuse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_inode_by_first_cluster_mut(&mut self, first_cluster: u32) -> Option<&mut Inode> {
|
pub fn get_inode_by_first_cluster_mut(&mut self, first_cluster: u32) -> Option<&mut Inode> {
|
||||||
|
if first_cluster == 0 {
|
||||||
|
debug!("trying to get inode by first cluster 0");
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let ino = self.ino_by_first_cluster.get(&first_cluster)?;
|
let ino = self.ino_by_first_cluster.get(&first_cluster)?;
|
||||||
|
|
||||||
if let Some(inode) = self.inode_table.get_mut(ino) {
|
if let Some(inode) = self.inode_table.get_mut(ino) {
|
||||||
|
|
@ -171,4 +233,28 @@ impl FatFuse {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_inode_by_fh(&self, fh: u64) -> Option<&Inode> {
|
||||||
|
let ino = self.ino_by_fh.get(&fh)?;
|
||||||
|
|
||||||
|
if let Some(inode) = self.inode_table.get(ino) {
|
||||||
|
Some(inode)
|
||||||
|
} else {
|
||||||
|
debug!("fh {} is mapped to ino {}, but inode is not in table", fh, ino);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_inode_by_fh_mut(&mut self, fh: u64) -> Option<&mut Inode> {
|
||||||
|
let ino = self.ino_by_fh.get(&fh)?;
|
||||||
|
|
||||||
|
if let Some(inode) = self.inode_table.get_mut(ino) {
|
||||||
|
Some(inode)
|
||||||
|
} else {
|
||||||
|
debug!("fh {} is mapped to ino {}, but inode is not in table", fh, ino);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let handle = fuser::spawn_mount2(fat_fuse, mountpoint, &options)?;
|
let _handle = fuser::spawn_mount2(fat_fuse, mountpoint, &options)?;
|
||||||
|
|
||||||
rx.recv().unwrap();
|
rx.recv().unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue