From b8afa7cfb02b32278e268924e189170496f81c1b Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Thu, 23 Nov 2023 02:11:16 -0800 Subject: Add some callback (not finished) --- src/filesystem/trait_impl.rs | 271 +++++++++++++++++++++++++++++++++---------- 1 file changed, 210 insertions(+), 61 deletions(-) (limited to 'src/filesystem') diff --git a/src/filesystem/trait_impl.rs b/src/filesystem/trait_impl.rs index 3a60578..a25a383 100644 --- a/src/filesystem/trait_impl.rs +++ b/src/filesystem/trait_impl.rs @@ -1,12 +1,17 @@ -use crate::AyaFS; +use crate::block_device::BLOCK_SIZE; +use crate::disk::inode::InodeMode; +use crate::utils::make_fileattr; +use crate::{utils, AyaFS, TTL}; use fuser::{ - Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, - ReplyLseek, ReplyWrite, Request, TimeOrNow, + FileAttr, FileType, Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, + ReplyEntry, ReplyLseek, ReplyWrite, Request, TimeOrNow, }; -use libc::{c_int, ENOENT, ENOSPC, ENOSYS}; +use libc::{c_int, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR}; use log::debug; use std::ffi::OsStr; +use std::os::unix::ffi::OsStrExt; use std::time::SystemTime; +use users::{get_current_gid, get_current_uid}; impl Filesystem for AyaFS { fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> { @@ -19,11 +24,6 @@ impl Filesystem for AyaFS { } fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) { - debug!( - "Filesystem::lookup called with parent {} name {}", - parent, - name.to_str().unwrap() - ); let parent = parent as usize; if let Some(inode) = self.get_inode(parent) { // debug!("{:?}", inode); @@ -43,11 +43,28 @@ impl Filesystem for AyaFS { fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) { debug!("Filesystem::getattr(ino: {})", ino); - let ino = ino as usize; - if let Some(inode) = self.get_inode(ino) { - // debug!("{:?}", inode); + if let Some(inode) = self.get_inode(ino as usize) { + let attr = FileAttr { + ino, + size: inode.size as u64, + blocks: inode.n_blocks as u64, + atime: utils::to_systime(inode.atime), + mtime: utils::to_systime(inode.mtime), + ctime: utils::to_systime(inode.ctime), + crtime: utils::to_systime(inode.crtime), + kind: inode.mode.into(), + perm: inode.mode.perm(), + nlink: inode.n_links as u32, + uid: inode.uid, + gid: inode.gid, + rdev: 0, + blksize: BLOCK_SIZE as u32, + flags: inode.flags, + }; + reply.attr(&TTL, &attr); + } else { + reply.error(ENOENT); } - reply.error(ENOENT); } fn setattr( @@ -57,23 +74,92 @@ impl Filesystem for AyaFS { mode: Option, uid: Option, gid: Option, - size: Option, - _atime: Option, - _mtime: Option, - _ctime: Option, + size: Option, // TODO 为什么 setattr 还可以设置 size?? + atime: Option, + mtime: Option, + ctime: Option, fh: Option, - _crtime: Option, + crtime: Option, _chgtime: Option, _bkuptime: Option, flags: Option, reply: ReplyAttr, ) { - debug!( - "Filesystem::setattr(ino: {:#x?}, mode: {:?}, uid: {:?}, \ - gid: {:?}, size: {:?}, fh: {:?}, flags: {:?})", - ino, mode, uid, gid, size, fh, flags - ); - reply.error(ENOSYS); + if let Some(inode) = self.get_inode_mut(ino as usize) { + let mode = mode + .and_then(|mode_value| { + InodeMode::validate(mode_value as u16) // high 16 bit truncated + }) + .unwrap_or(inode.mode); + inode.mode = mode; + // 如果传入的 InodeMode 是合法结果, 那么得到 Some(mode), 否则 None + // 需要检查权限吗? 如果需要, 如何知道 invoke 这个 callback 的 UID/GID? + + let size = size.unwrap_or(inode.size as u64); + inode.size = size as u32; + // TODO 为什么可以设置 size 呢…… + + let uid = uid.unwrap_or(inode.uid); + let gid = gid.unwrap_or(inode.gid); + inode.uid = uid; + inode.gid = gid; + + let (atime, atime_inner) = atime + .map(|atime| { + let system_time = match atime { + TimeOrNow::SpecificTime(system_time) => system_time, + TimeOrNow::Now => SystemTime::now(), + }; + (system_time, utils::from_systime(system_time)) + }) + .unwrap_or((utils::to_systime(inode.atime), inode.atime)); + inode.atime = atime_inner; + + let (mtime, mtime_inner) = mtime + .map(|mtime| { + let system_time = match mtime { + TimeOrNow::SpecificTime(system_time) => system_time, + TimeOrNow::Now => SystemTime::now(), + }; + (system_time, utils::from_systime(system_time)) + }) + .unwrap_or((utils::to_systime(inode.mtime), inode.mtime)); + inode.mtime = mtime_inner; + + let (ctime, ctime_inner) = ctime + .map(|ctime| (ctime, utils::from_systime(ctime))) + .unwrap_or((utils::to_systime(inode.ctime), inode.ctime)); + inode.ctime = ctime_inner; + + let (crtime, crtime_inner) = crtime + .map(|crtime| (crtime, utils::from_systime(crtime))) + .unwrap_or((utils::to_systime(inode.crtime), inode.crtime)); + inode.crtime = crtime_inner; + + let flags = flags.unwrap_or(inode.flags); + inode.flags = flags; + + let attr = FileAttr { + ino, + size, + blocks: inode.n_blocks as u64, + atime, + mtime, + ctime, + crtime, + kind: mode.into(), + perm: mode.perm(), + nlink: inode.n_links as u32, + uid, + gid, + rdev: 0, + blksize: BLOCK_SIZE as u32, + flags, + }; + reply.attr(&TTL, &attr); + } else { + reply.error(ENOSYS); + } } fn readlink(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyData) { @@ -87,15 +173,46 @@ impl Filesystem for AyaFS { parent: u64, name: &OsStr, mode: u32, - umask: u32, - rdev: u32, + _umask: u32, // umask 是用不到的 + _rdev: u32, // the device number (only valid if created file is a device) reply: ReplyEntry, ) { debug!( - "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {}, rdev: {})", - parent, name, mode, umask, rdev + "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {})", + parent, name, mode, _umask ); - reply.error(ENOSPC); + if let Some(inode) = self.get_inode(parent as usize) { + if inode.is_dir() { + let name = name.as_bytes(); + if name.len() <= 255 { + let permissions = (mode & 0o777) as u16; + if let Some(inode_index) = self.create_inode( + permissions, + InodeMode::IFREG, + get_current_uid(), + get_current_gid(), + 0, + ) { + let inode = self.get_inode(inode_index).unwrap(); + let file_attr = make_fileattr(inode_index, inode); + // TODO 把 inode 挂到 parent 下 + reply.entry(&TTL, &file_attr, 0); + } else { + // create_inode 失败 -> no enough space + reply.error(ENOSPC); + } + } else { + // name 长度超过 255 -> File name too long + reply.error(ENAMETOOLONG); + } + } else { + // parent 不是 IFDIR -> Not a directory + reply.error(ENOTDIR); + } + } else { + // parent 不存在 -> No such file or directory + reply.error(ENOENT); + } } fn mkdir( @@ -104,18 +221,54 @@ impl Filesystem for AyaFS { parent: u64, name: &OsStr, mode: u32, - umask: u32, + _umask: u32, // umask 应该也是用不到的 reply: ReplyEntry, ) { + if let Some(inode) = self.get_inode(parent as usize) { + if inode.is_dir() { + let name = name.as_bytes(); + if name.len() <= 255 { + let permissions = (mode & 0o777) as u16; + if let Some(inode_index) = self.create_inode( + permissions, + InodeMode::IFDIR, + get_current_uid(), + get_current_gid(), + 0, + ) { + let inode = self.get_inode(inode_index).unwrap(); + let file_attr = make_fileattr(inode_index, inode); + // TODO 把 inode 挂到 parent 下 + reply.entry(&TTL, &file_attr, 0); + } else { + // create_inode 失败 -> no enough space + reply.error(ENOSPC); + } + } else { + // name 长度超过 255 -> File name too long + reply.error(ENAMETOOLONG); + } + } else { + // parent 不是 IFDIR -> Not a directory + reply.error(ENOTDIR); + } + } else { + // parent 不存在 -> No such file or directory + reply.error(ENOENT); + } + } + + fn unlink(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { debug!( - "Filesystem::mkdir(parent: {}, name: {:?}, mode: {}, umask: {})", - parent, name, mode, umask + "unlink(parent: {:#x?}, name: {:?})", + parent, name, ); - if let Some(inode) = self.get_inode(parent as usize) { + if let Some(inode) = self.get_inode_mut(parent as usize) { + // TODO 找到这个 inode 并且删掉 + reply.ok(); } else { reply.error(ENOENT); } - // reply.error(ENOSPC); } fn read( @@ -140,7 +293,29 @@ impl Filesystem for AyaFS { offset: i64, mut reply: ReplyDirectory, ) { - todo!() + if let Some(inode) = self.get_inode(ino as usize) { + } else { + reply.error(ENOENT); + } + + // if ino != 1 { + // reply.error(ENOENT); + // return; + // } + // + // let entries = vec![ + // (1, FileType::Directory, "."), + // (1, FileType::Directory, ".."), + // (2, FileType::RegularFile, "hello.txt"), + // ]; + // + // for (i, entry) in entries.into_iter().enumerate().skip(offset as usize) { + // // i + 1 means the index of the next entry + // if reply.add(entry.0, (i + 1) as i64, entry.1, entry.2) { + // break; + // } + // } + // reply.ok(); } fn access(&mut self, _req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) { @@ -161,32 +336,6 @@ impl Filesystem for AyaFS { whence: i32, reply: ReplyLseek, ) { - debug!( - "lseek(ino: {:#x?}, fh: {}, offset: {}, whence: {})", - ino, fh, offset, whence - ); - reply.error(ENOSYS); - } - - fn copy_file_range( - &mut self, - _req: &Request<'_>, - ino_in: u64, - fh_in: u64, - offset_in: i64, - ino_out: u64, - fh_out: u64, - offset_out: i64, - len: u64, - flags: u32, - reply: ReplyWrite, - ) { - debug!( - "copy_file_range(ino_in: {:#x?}, fh_in: {}, \ - offset_in: {}, ino_out: {:#x?}, fh_out: {}, offset_out: {}, \ - len: {}, flags: {})", - ino_in, fh_in, offset_in, ino_out, fh_out, offset_out, len, flags - ); reply.error(ENOSYS); } } -- cgit v1.2.3-70-g09d2