FIX: TLS options
This commit is contained in:
@@ -11,20 +11,18 @@ use tokio::runtime::Handle;
|
||||
|
||||
const TTL: Duration = Duration::from_secs(1); // 1 second FUSE kernel TTL
|
||||
|
||||
pub struct FurumiFuse {
|
||||
client: FurumiClient,
|
||||
rt_handle: Handle,
|
||||
// FUSE deals in inodes (u64). We need to map inode -> string path.
|
||||
// In a real VFS, this requires a proper tree or bidirectional map.
|
||||
// For simplicity: inode 1 is always the root "/".
|
||||
// ── InodeMapper ──────────────────────────────────────────────────
|
||||
|
||||
/// Maps FUSE inodes (u64) to remote virtual filesystem paths (String) and vice versa.
|
||||
/// Inode 1 is permanently assigned to the root directory ("/").
|
||||
pub struct InodeMapper {
|
||||
inode_to_path: Arc<Mutex<HashMap<u64, String>>>,
|
||||
// Mapping path back to inode to keep them consistent
|
||||
path_to_inode: Arc<Mutex<HashMap<String, u64>>>,
|
||||
next_inode: Arc<Mutex<u64>>,
|
||||
}
|
||||
|
||||
impl FurumiFuse {
|
||||
pub fn new(client: FurumiClient, rt_handle: Handle) -> Self {
|
||||
impl InodeMapper {
|
||||
pub fn new() -> Self {
|
||||
let mut inode_to_path = HashMap::new();
|
||||
let mut path_to_inode = HashMap::new();
|
||||
|
||||
@@ -33,15 +31,13 @@ impl FurumiFuse {
|
||||
path_to_inode.insert("/".to_string(), 1);
|
||||
|
||||
Self {
|
||||
client,
|
||||
rt_handle,
|
||||
inode_to_path: Arc::new(Mutex::new(inode_to_path)),
|
||||
path_to_inode: Arc::new(Mutex::new(path_to_inode)),
|
||||
next_inode: Arc::new(Mutex::new(2)), // Inodes start from 2
|
||||
}
|
||||
}
|
||||
|
||||
fn get_inode(&self, path: &str) -> u64 {
|
||||
pub fn get_inode(&self, path: &str) -> u64 {
|
||||
let mut p2i = self.path_to_inode.lock().unwrap();
|
||||
if let Some(&inode) = p2i.get(path) {
|
||||
inode
|
||||
@@ -55,9 +51,27 @@ impl FurumiFuse {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_path(&self, inode: u64) -> Option<String> {
|
||||
pub fn get_path(&self, inode: u64) -> Option<String> {
|
||||
self.inode_to_path.lock().unwrap().get(&inode).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
// ── FurumiFuse ──────────────────────────────────────────────────
|
||||
|
||||
pub struct FurumiFuse {
|
||||
client: FurumiClient,
|
||||
rt_handle: Handle,
|
||||
mapper: InodeMapper,
|
||||
}
|
||||
|
||||
impl FurumiFuse {
|
||||
pub fn new(client: FurumiClient, rt_handle: Handle) -> Self {
|
||||
Self {
|
||||
client,
|
||||
rt_handle,
|
||||
mapper: InodeMapper::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_attr(inode: u64, attr: &furumi_common::proto::AttrResponse) -> FileAttr {
|
||||
let kind = if attr.mode & libc::S_IFDIR != 0 {
|
||||
@@ -91,7 +105,7 @@ impl Filesystem for FurumiFuse {
|
||||
let name_str = name.to_string_lossy();
|
||||
debug!("lookup: parent={} name={}", parent, name_str);
|
||||
|
||||
let parent_path = match self.get_path(parent) {
|
||||
let parent_path = match self.mapper.get_path(parent) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
reply.error(libc::ENOENT);
|
||||
@@ -115,7 +129,7 @@ impl Filesystem for FurumiFuse {
|
||||
|
||||
match attr_res {
|
||||
Ok(attr) => {
|
||||
let inode = self.get_inode(&full_path);
|
||||
let inode = self.mapper.get_inode(&full_path);
|
||||
reply.entry(&TTL, &Self::make_attr(inode, &attr), 0);
|
||||
}
|
||||
Err(_) => {
|
||||
@@ -127,7 +141,7 @@ impl Filesystem for FurumiFuse {
|
||||
fn getattr(&mut self, _req: &Request, ino: u64, _fh: Option<u64>, reply: ReplyAttr) {
|
||||
debug!("getattr: ino={}", ino);
|
||||
|
||||
let path = match self.get_path(ino) {
|
||||
let path = match self.mapper.get_path(ino) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
reply.error(libc::ENOENT);
|
||||
@@ -158,7 +172,7 @@ impl Filesystem for FurumiFuse {
|
||||
) {
|
||||
debug!("readdir: ino={} offset={}", ino, offset);
|
||||
|
||||
let path = match self.get_path(ino) {
|
||||
let path = match self.mapper.get_path(ino) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
reply.error(libc::ENOENT);
|
||||
@@ -192,7 +206,7 @@ impl Filesystem for FurumiFuse {
|
||||
format!("{}/{}", path, entry.name)
|
||||
};
|
||||
|
||||
let child_ino = self.get_inode(&full_path);
|
||||
let child_ino = self.mapper.get_inode(&full_path);
|
||||
let kind = if entry.r#type == 4 {
|
||||
FileType::Directory
|
||||
} else {
|
||||
@@ -226,7 +240,7 @@ impl Filesystem for FurumiFuse {
|
||||
) {
|
||||
debug!("read: ino={} offset={} size={}", ino, offset, size);
|
||||
|
||||
let path = match self.get_path(ino) {
|
||||
let path = match self.mapper.get_path(ino) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
reply.error(libc::ENOENT);
|
||||
@@ -263,3 +277,43 @@ impl Filesystem for FurumiFuse {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_inode_mapper_root() {
|
||||
let mapper = InodeMapper::new();
|
||||
// Root is always 1
|
||||
assert_eq!(mapper.get_path(1).unwrap(), "/");
|
||||
assert_eq!(mapper.get_inode("/"), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inode_mapper_assignment() {
|
||||
let mapper = InodeMapper::new();
|
||||
|
||||
// New paths get new inodes starting from 2
|
||||
let path1 = "/hello.txt";
|
||||
let ino1 = mapper.get_inode(path1);
|
||||
assert_eq!(ino1, 2);
|
||||
|
||||
let path2 = "/dir/world.mkv";
|
||||
let ino2 = mapper.get_inode(path2);
|
||||
assert_eq!(ino2, 3);
|
||||
|
||||
// Lookup gives the mapped paths back
|
||||
assert_eq!(mapper.get_path(2).unwrap(), path1);
|
||||
assert_eq!(mapper.get_path(3).unwrap(), path2);
|
||||
|
||||
// Asking for the same path again returns the same inode
|
||||
assert_eq!(mapper.get_inode(path1), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inode_mapper_non_existent() {
|
||||
let mapper = InodeMapper::new();
|
||||
assert!(mapper.get_path(999).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user