diff options
Diffstat (limited to 'ayafs/src/filesystem')
-rw-r--r-- | ayafs/src/filesystem/mod.rs | 2 | ||||
-rw-r--r-- | ayafs/src/filesystem/trait_impl.rs | 1247 |
2 files changed, 0 insertions, 1249 deletions
diff --git a/ayafs/src/filesystem/mod.rs b/ayafs/src/filesystem/mod.rs deleted file mode 100644 index 1eaa8e8..0000000 --- a/ayafs/src/filesystem/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// Where upper filesystem calls are implemented. -pub mod trait_impl; diff --git a/ayafs/src/filesystem/trait_impl.rs b/ayafs/src/filesystem/trait_impl.rs deleted file mode 100644 index 1c40b92..0000000 --- a/ayafs/src/filesystem/trait_impl.rs +++ /dev/null @@ -1,1247 +0,0 @@ -use crate::block_device::BLOCK_SIZE; -use crate::disk::block::DataBlock; -use crate::disk::inode::InodeMode; -use crate::utils::permissions::{check_access, clear_suid_sgid, get_groups}; -use crate::utils::{from_filetype, from_systime, time_now, to_fileattr, to_filetype}; -use crate::{AyaFS, TTL}; -use fuser::TimeOrNow::{Now, SpecificTime}; -use fuser::{ - FileType, Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, - ReplyEntry, ReplyOpen, ReplyWrite, Request, TimeOrNow, -}; -use libc::{c_int, EACCES, EBADF, EEXIST, EINVAL, EIO, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY, EPERM, IPOPT_OFFSET, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK, RENAME_NOREPLACE, RENAME_EXCHANGE}; -use log::debug; -use std::ffi::OsStr; -use std::os::unix::ffi::OsStrExt; -use std::path::Path; -use std::slice; -use std::time::SystemTime; - -impl AyaFS {} - -impl Filesystem for AyaFS { - fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> { - debug!("`init()"); - Ok(()) - } - - fn destroy(&mut self) { - debug!("destroy()"); - // TODO 写回 - } - - fn lookup(&mut self, req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) { - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let parent = parent as usize; - if let Some(parent_inode) = self.get_inode(parent) { - if check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - R_OK, - ) { - let parent_inode = parent_inode.clone(); - match self.lookup_name(parent, &parent_inode, name) { - Ok((inode_index, _, inode)) => { - let attr = to_fileattr(inode_index as usize, &inode); - reply.entry(&TTL, &attr, 0); - } - Err(err_code) => reply.error(err_code), - }; - } else { - reply.error(EACCES); - } - } else { - reply.error(ENOENT); - } - } - - fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) { - if let Some(inode) = self.get_inode(ino as usize) { - reply.attr(&TTL, &to_fileattr(ino as usize, inode)); - } else { - reply.error(ENOENT); - } - } - - fn setattr( - &mut self, - req: &Request<'_>, - ino: u64, - mode: Option<u32>, - uid: Option<u32>, - gid: Option<u32>, - size: Option<u64>, // 当 setattr 被 ftruncate invoke 时会设置 size - atime: Option<TimeOrNow>, - mtime: Option<TimeOrNow>, - _ctime: Option<SystemTime>, - fh: Option<u64>, // 当 setattr 被 ftruncate invoke 时会提供 fh - _crtime: Option<SystemTime>, // 忽略 - _chgtime: Option<SystemTime>, // 忽略 - _bkuptime: Option<SystemTime>, // 忽略 - _flags: Option<u32>, // 忽略 - reply: ReplyAttr, - ) { - if let Some(inode) = self.get_inode_mut(ino as usize) { - // chmod - if let Some(mode) = mode { - debug!("chmod on inode {:#x?} mode {:o}", ino, mode); - if req.uid() != 0 && req.uid() != inode.uid { - reply.error(EPERM); - return; - } // uid == 0 (root) or uid == inode.uid (user itself) - - if req.uid() != 0 - && req.gid() != inode.gid - && !get_groups(req.pid()).contains(&inode.gid) - { - inode.mode = InodeMode((mode & !S_ISGID) as u16); - } else { - inode.mode = InodeMode(mode as u16); - } - - inode.ctime = time_now(); - reply.attr(&TTL, &to_fileattr(ino as usize, inode)); - return; - } - - // chown - if uid.is_some() || gid.is_some() { - debug!("chown on inode {:#x?} uid {:?} gid {:?}", ino, uid, gid); - if let Some(uid) = uid { - // 虽然只有 root 可以 chown 但是 user chown 自己也是不报错的 - if req.uid() != 0 && !(uid == inode.uid && uid == req.uid()) { - reply.error(EPERM); - return; - } - } - if let Some(gid) = gid { - // 只有 root 和 file owner 才可以 chgrp - if req.uid() != 0 && req.uid() != inode.uid { - reply.error(EPERM); - return; - } - // root 可以任意 chgrp, 非 root 只能修改到用户自己所在的组里 - if req.gid() != 0 && !get_groups(req.pid()).contains(&gid) { - reply.error(EPERM); - return; - } - } - - // 可执行文件要清除 suid & sgid - if inode.mode.0 & (S_IXUSR | S_IXGRP | S_IXOTH) as u16 != 0 { - inode.mode = clear_suid_sgid(inode.mode); - } - - // chown 要清除 suid - if let Some(uid) = uid { - inode.uid = uid; - inode.mode.0 &= !S_ISUID as u16; - } - - if let Some(gid) = gid { - inode.gid = gid; - if req.uid() != 0 { - inode.mode.0 &= !S_ISGID as u16; - } - } - inode.ctime = time_now(); - reply.attr(&TTL, &to_fileattr(ino as usize, inode)); - return; - } - - // ftruncate - if let Some(size) = size { - // TODO 当大小减小的时候对应 deallocate 块 - debug!("ftruncate on inode {:#x?} size {:?}", ino, size); - if let Some(file_handle) = fh { - let mut inode = inode.clone(); - let (inode_index, _read, write) = - self.file_handle_map.get(&file_handle).unwrap(); - assert_eq!(ino as usize, *inode_index); - if !write { - reply.error(EACCES); - } else { - inode.size = size as u32; - reply.attr(&TTL, &to_fileattr(*inode_index, &inode)); - self.update_inode(*inode_index, inode); - } - } else { - if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, W_OK) { - reply.error(EACCES); - } else { - inode.size = size as u32; - reply.attr(&TTL, &to_fileattr(ino as usize, &inode)); - } - } - return; - } - - // time 相关 - if atime.is_some() || mtime.is_some() { - let current_time = time_now(); - if let Some(atime) = atime { - debug!("utimensat on inode {:#x?}, atime {:?}", ino, atime); - // root 和 user 可以随意修改 atime, 其他用户只能 touch (即 atime == Now) - if req.uid() != 0 && req.uid() != inode.uid && atime != Now { - reply.error(EPERM); - return; - } - - if req.uid() != 0 - && req.uid() != inode.uid - && check_access( - req.uid(), - req.gid(), - inode.uid, - inode.gid, - inode.mode, - R_OK, // atime 来说是 read TODO 对吗 - ) - { - reply.error(EACCES); - return; - } - - inode.atime = match atime { - SpecificTime(time) => from_systime(time), - Now => current_time, - }; - inode.ctime = current_time; - } - if let Some(mtime) = mtime { - debug!("utimensat on inode {:#x?}, mtime {:?}", ino, mtime); - // root 和 user 可以随意修改 mtime, 其他用户只能 mtime == Now - if req.uid() != 0 && req.uid() != inode.uid && mtime != Now { - reply.error(EPERM); - return; - } - - if req.uid() != 0 - && req.uid() != inode.uid - && check_access( - req.uid(), - req.gid(), - inode.uid, - inode.gid, - inode.mode, - W_OK, // mtime 来说是 write - ) - { - reply.error(EACCES); - return; - } - - inode.mtime = match mtime { - SpecificTime(time) => from_systime(time), - Now => current_time, - }; - inode.ctime = current_time; - } - } - reply.attr(&TTL, &to_fileattr(ino as usize, inode)); - return; - } else { - reply.error(ENOENT); - } - } - - // 这啥语义啊?? - fn readlink(&mut self, req: &Request<'_>, ino: u64, reply: ReplyData) { - debug!("readlink(ino: {})", ino); - if let Some(inode) = self.get_inode(ino as usize) { - if !inode.is_symlink() { - reply.error(ENOENT); - return; - } - if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, R_OK) { - reply.error(EACCES); - return; - } - let path_length = inode.size as usize; - let mut path = vec![0u8; path_length]; - if path_length < 60 { - debug!( - "symlink path length is {}, reading directly from inode.direct", - path_length - ); - let copy_src = unsafe { - let src = (&inode.direct) as *const u32 as *const u8; - slice::from_raw_parts(src, path_length) - }; - path.as_mut_slice().copy_from_slice(copy_src); - } else { - debug!( - "symlink path length is {}, using original read", - path_length - ); - let inode = inode.clone(); - let mut read_ptr = 0usize; - while read_ptr < path_length { - let block_index = read_ptr / BLOCK_SIZE; - let offset = read_ptr % BLOCK_SIZE; - - let read_length_within_block = if BLOCK_SIZE - offset < path_length - read_ptr { - BLOCK_SIZE - offset - } else { - path_length - read_ptr - }; - - if let Some(block) = self.access_block::<DataBlock>(&inode, block_index) { - (&mut path[read_ptr..read_ptr + read_length_within_block]).copy_from_slice( - &block.block.0[offset..offset + read_length_within_block], - ); - read_ptr += read_length_within_block; - } else { - reply.error(EIO); - return; - } - } - } - debug!( - "readlink path read is {:?}", - OsStr::from_bytes(path.as_slice()) - ); - reply.data(path.as_slice()); - } else { - reply.error(ENOENT); - } - } - - fn mknod( - &mut self, - req: &Request<'_>, - parent: u64, - name: &OsStr, - mode: u32, - _umask: u32, // umask 是用不到的 - _rdev: u32, // the device number (only valid if created file is a device) - reply: ReplyEntry, - ) { - debug!( - "mknod(parent: {}, name: {:?}, mode: {}, umask: {})", - parent, name, mode, _umask - ); - - let parent = parent as usize; - if let Some(parent_inode) = self.get_inode(parent) { - if !check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - W_OK, - ) { - reply.error(EACCES); - return; - } - - // parent 不是 IFDIR -> Not a directory - if !parent_inode.is_dir() { - reply.error(ENOTDIR); - return; - } - - // 文件名长度超过 255, 返回 filename too long - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let mut parent_inode = parent_inode.clone(); - // 如果已经存在, 返回 already exists - if self.lookup_name(parent, &parent_inode, name).is_ok() { - reply.error(EEXIST); - return; - } - - let mode = mode as u16; - if let Some((child_inode_index, child_inode)) = - self.create_file(mode, req.uid(), req.gid(), 0) - { - let mode = child_inode.mode; - let file_attr = to_fileattr(child_inode_index, child_inode); - if let Err(err_code) = self.add_direntry( - parent, - &mut parent_inode, - child_inode_index, - name, - mode.into(), - ) { - reply.error(err_code); - return; - } - self.update_inode(parent, parent_inode); // 前面 clone 了, 这里写回 - reply.entry(&TTL, &file_attr, 0); - } else { - // create_inode 失败 -> no enough space - reply.error(ENOSPC); - } - } else { - // parent 不存在 -> No such file or directory - reply.error(ENOENT); - } - } - - fn mkdir( - &mut self, - req: &Request<'_>, - parent: u64, - name: &OsStr, - mode: u32, - _umask: u32, // umask 应该也是用不到的 - reply: ReplyEntry, - ) { - if let Some(parent_inode) = self.get_inode(parent as usize) { - // 无权限创建 -> EACCES - if !check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - W_OK, - ) { - reply.error(EACCES); - return; - } - - // parent 不是 IFDIR -> Not a directory - if !parent_inode.is_dir() { - reply.error(ENOTDIR); - return; - } - - // 文件名长度超过 255 -> filename too long - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let mut parent_inode = parent_inode.clone(); - // 已经存在 -> File exists - if self - .lookup_name(parent as usize, &parent_inode, name) - .is_ok() - { - reply.error(EEXIST); - return; - } - - let mode = mode as u16; - if let Some((child_inode_index, child_inode)) = - self.create_directory(mode, req.uid(), req.gid(), 0, Some(parent as usize)) - { - let child_inode = child_inode.clone(); - let file_attr = to_fileattr(child_inode_index, &child_inode); - if let Err(err_code) = self.add_direntry( - parent as usize, - &mut parent_inode, - child_inode_index, - name, - child_inode.mode.into(), - ) { - reply.error(err_code); - return; - } - self.update_inode(parent as usize, parent_inode); // 前面 clone 了, 这里写回 - reply.entry(&TTL, &file_attr, 0); - } else { - // create_inode 失败 -> no enough space - reply.error(ENOSPC); - } - } else { - // parent 不存在 -> No such file or directory - reply.error(ENOENT); - } - } - - fn unlink(&mut self, req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { - debug!("unlink(parent: {:#x?}, name: {:?})", parent, name,); - if let Some(parent_inode) = self.get_inode(parent as usize) { - // 无权限删除 -> EACCES - if !check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - W_OK, - ) { - reply.error(EACCES); - return; - } - - // parent 不是 dir -> ENOTDIR - if !parent_inode.is_dir() { - reply.error(ENOTDIR); - return; - } - - // 文件名长度超过 255 -> filename too long - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let mut parent_inode = parent_inode.clone(); - // 不存在 -> No such file or directory - if let Ok((inode_index, entry_index, mut inode)) = - self.lookup_name(parent as usize, &parent_inode, name) - { - let inode_index = inode_index as usize; - - match inode.file_type() { - FileType::RegularFile => { - inode.n_links -= 1; - if inode.n_links == 0 { - // n_links == 0 -> 整个 inode 都要删除掉 - match self.remove_file(inode_index) { - Ok(flag) => debug!(" unlink {}", flag), - Err(err_code) => { - reply.error(err_code); - return; - } - } - } else { - // n_links > 0 -> 只是移除了一个 hard link, 将改动写回 - self.update_inode(inode_index, inode); - } - } - FileType::Symlink => {} - FileType::Directory => { - reply.error(EISDIR); - return; - } - _ => { - // Not implemented! - reply.error(EIO); - return; - } - } - - // 删除 dir entry - if let Err(err_code) = - self.remove_direntry(parent as usize, &mut parent_inode, name, entry_index) - { - reply.error(err_code); - return; - } - reply.ok(); - } else { - reply.error(ENOENT); - } - } else { - reply.error(ENOENT); - } - } - - fn rmdir(&mut self, req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { - debug!("rmdir(parent: {:#x?}, name: {:?}", parent, name,); - if let Some(parent_inode) = self.get_inode(parent as usize) { - // 无权限删除 -> EACCES - if !check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - W_OK, - ) { - reply.error(EACCES); - return; - } - - // parent 不是 dir -> ENOTDIR - if !parent_inode.is_dir() { - reply.error(ENOTDIR); - return; - } - - // 文件名长度超过 255 -> filename too long - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let mut parent_inode = parent_inode.clone(); - // 不存在 -> No such file or directory - if let Ok((inode_index, entry_index, inode)) = - self.lookup_name(parent as usize, &parent_inode, name) - { - let inode_index = inode_index as usize; - // 要删除的 entry 是一般文件, 不用 rmdir - if inode.is_file() { - reply.error(ENOTDIR); - return; - } - - // 一定有 . 和 .. 所以 size == 2 就是空目录 - // 目录非空 -> ENOTEMPTY - if inode.size > 2 { - reply.error(ENOTEMPTY); - return; - } - - // directory 没有 hard link, 删了就是删了 - match self.remove_dir(inode_index) { - Ok(flag) => debug!(" rmdir {}", flag), - Err(err_code) => { - reply.error(err_code); - return; - } - } - - // 删除 dir entry - if let Err(err_code) = - self.remove_direntry(parent as usize, &mut parent_inode, name, entry_index) - { - reply.error(err_code); - return; - } - - reply.ok(); - } else { - reply.error(ENOENT); - } - } else { - reply.error(ENOENT); - } - } - - fn symlink( - &mut self, - req: &Request<'_>, - parent: u64, - link_name: &OsStr, - target: &Path, - reply: ReplyEntry, - ) { - debug!( - "symlink(parent: {}, name: {:?}, target: {:?})", - parent, link_name, target - ); - let parent = parent as usize; - - // let root_inode_index = 1usize; - // if let Some(root_inode) = self.get_inode(root_inode_index) { - // let mut curr_inode_index = root_inode_index; - // let mut curr_inode = root_inode.clone(); - // for segment in target.iter() { - // match self.lookup_name(curr_inode_index, &curr_inode, segment) { - // Ok((next_inode_index, _, next_inode)) => { - // curr_inode_index = next_inode_index as usize; - // curr_inode = next_inode; - // } - // Err(err_code) => { - // reply.error(err_code); - // return; - // } - // } - // } - // } else { - // reply.error(EIO); - // return; - // } - - if let Some(parent_inode) = self.get_inode(parent) { - if !check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - W_OK, - ) { - reply.error(EACCES); - return; - } - - if !parent_inode.is_dir() { - reply.error(ENOTDIR); - return; - } - - if link_name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let target = target.as_os_str(); - let mut parent_inode = parent_inode.clone(); - if self.lookup_name(parent, &parent_inode, link_name).is_ok() { - reply.error(EEXIST); - return; - } - - if let Some((child_inode_index, child_inode)) = - self.create_symlink(0o777, req.uid(), req.gid(), 0) - { - let mut child_inode = child_inode.clone(); - child_inode.size = target.len() as u32; - if target.len() < 60 { - debug!("create_symlink: target length < 60, allocating in 'direct' section."); - let target_path = target.as_bytes(); - let copy_dst = unsafe { - let dst = (&mut child_inode.direct) as *mut u32 as *mut u8; - slice::from_raw_parts_mut(dst, target_path.len()) - }; - copy_dst.copy_from_slice(target_path); - } else { - debug!("create_symlink: target length >= 60, using original layout."); - let mut write_ptr = 0usize; - while write_ptr < target.len() { - let block_index = write_ptr / BLOCK_SIZE; - let offset = write_ptr % BLOCK_SIZE; - - let write_length_within_block = - if BLOCK_SIZE - offset < target.len() - write_ptr { - BLOCK_SIZE - offset - } else { - target.len() - write_ptr - }; - - if let Some(block) = - self.access_block_mut::<DataBlock>(&child_inode, block_index) - { - block.block.0[offset..offset + write_length_within_block] - .copy_from_slice( - &target.as_bytes() - [write_ptr..write_ptr + write_length_within_block], - ); - write_ptr += write_length_within_block; - } else { - if let Some((_block_index, block_index_within_inode)) = - self.allocate_block_for(&mut child_inode) - { - let block = self - .access_block_mut::<DataBlock>( - &child_inode, - block_index_within_inode, - ) - .unwrap(); - block.block.0[offset..offset + write_length_within_block] - .copy_from_slice( - &target.as_bytes() - [write_ptr..write_ptr + write_length_within_block], - ); - write_ptr += write_length_within_block; - } else { - reply.error(ENOSPC); - return; - } - } - } - } - - let file_attr = to_fileattr(child_inode_index, &child_inode); - self.update_inode(child_inode_index, child_inode); - - if let Err(err_code) = self.add_direntry( - parent, - &mut parent_inode, - child_inode_index, - link_name, - from_filetype(FileType::Symlink), - ) { - reply.error(err_code); - return; - } - self.update_inode(parent, parent_inode); - reply.entry(&TTL, &file_attr, 0); - } else { - reply.error(ENOSPC); - } - } else { - reply.error(ENOENT); - } - } - - fn rename( - &mut self, - req: &Request<'_>, - parent: u64, - name: &OsStr, - new_parent: u64, - new_name: &OsStr, - flags: u32, - reply: ReplyEmpty, - ) { - debug!( - "rename(parent: {}, name: {:?}, new_parent: {}, new_name: {:?})", - parent, name, new_parent, new_name - ); - - let parent = parent as usize; - let new_parent = new_parent as usize; - if let Some(parent_inode) = self.get_inode(parent) { - if !check_access( - req.uid(), - req.gid(), - parent_inode.uid, - parent_inode.gid, - parent_inode.mode, - R_OK, - ) { - reply.error(EACCES); - return; - } - - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let mut parent_inode = parent_inode.clone(); - match self.lookup_name(parent, &parent_inode, name) { - Ok((inode_index, entry_index, inode)) => { - if let Some(new_parent_inode) = self.get_inode(new_parent) { - if !check_access( - req.uid(), - req.gid(), - new_parent_inode.uid, - new_parent_inode.gid, - new_parent_inode.mode, - W_OK, - ) { - reply.error(EACCES); - return; - } - if new_name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } - - let mut new_parent_inode = new_parent_inode.clone(); - match self.lookup_name(new_parent, &new_parent_inode, new_name) { - Ok((new_inode_index, new_entry_index, new_inode)) => { - // 新文件存在 - if flags & RENAME_NOREPLACE != 0 { // 指定 noreplace 之后不允许覆盖文件 - reply.error(EEXIST); - return; - } - if flags & RENAME_EXCHANGE != 0 { // 交换两个文件 - if let Err(err_code) = self.exchange_direntry( - parent, - &mut parent_inode, - name, - new_parent, - &mut new_parent_inode, - new_name - ) { - reply.error(err_code); - return; - } - } else { // 用新文件替换旧文件 - let dir_entry = self.get_direntry_by_name(parent, &parent_inode, name) - .unwrap(); - if let Err(err_code) = self.remove_direntry(parent, &mut parent_inode, name, entry_index) { - reply.error(err_code); - return; - } - if let Err(err_code) = self.remove_direntry(new_parent, &mut new_parent_inode, new_name, new_entry_index) { - reply.error(err_code); - return; - } - if let Err(err_code) = self.add_direntry_2(new_parent, &mut new_parent_inode, new_name, dir_entry) { - reply.error(err_code); - return; - } - } - reply.ok(); - }, - Err(ENOENT) => { // 新文件不存在, 删除旧的创建新的 - let dir_entry = self.get_direntry_by_name(parent, &parent_inode, name) - .unwrap(); - if let Err(err_code) = self.remove_direntry(parent, &mut parent_inode, name, entry_index) { - reply.error(err_code); - return; - } - if let Err(err_code) = self.add_direntry_2(new_parent, &mut new_parent_inode, new_name, dir_entry) { - reply.error(err_code); - return; - } - reply.ok(); - }, - Err(err_code) => { - // 其他 Err code - reply.error(err_code); - return; - } - } - } else { - reply.error(ENOENT); - } - }, - Err(err_code) => { - reply.error(err_code); - return; - } - } - } else { - reply.error(ENOENT); - } - } - - fn open(&mut self, req: &Request<'_>, ino: u64, flags: i32, reply: ReplyOpen) { - debug!("open(ino: {:#x?}, flags: {:#x?})", ino, flags); - let (access_mask, read, write) = match flags & O_ACCMODE { - O_RDONLY => { - // Behavior is undefined, but most filesystems return EACCES - if flags & libc::O_TRUNC != 0 { - reply.error(EACCES); - return; - } - (R_OK, true, false) - } - O_WRONLY => (W_OK, false, true), - O_RDWR => (R_OK | W_OK, true, true), - _ => { - // flag 非法 - reply.error(EINVAL); - return; - } - }; - - match self.get_inode(ino as usize) { - Some(inode) => { - if !check_access( - req.uid(), - req.gid(), - inode.uid, - inode.gid, - inode.mode, - access_mask, - ) { - reply.error(EACCES); - return; - } - let fd = self.allocate_file_descriptor(ino as usize, read, write); - reply.opened(fd, 0); - } - None => { - reply.error(ENOENT); - } - } - } - - // read [offset, offset + size) - // - EOF < offset + size -> return EOF - offset - // - EOF > offset + size -> return size - fn read( - &mut self, - req: &Request<'_>, - ino: u64, - fh: u64, - offset: i64, - size: u32, - _flags: i32, - _lock_owner: Option<u64>, // 用不到! - reply: ReplyData, - ) { - assert_eq!(self.file_handle_map.get(&fh).unwrap().0, ino as usize); - if let Some(inode) = self.get_inode(ino as usize) { - if inode.is_dir() { - reply.error(EISDIR); - return; - } - if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, R_OK) { - reply.error(EACCES); - return; - } - debug!("reading inode {:#x} (offset {} size {})", ino, offset, size); - - if offset as u32 >= inode.size { - // offset 在 EOF 后面, 直接返回一个 0 长度的空 buffer - reply.data(&Vec::new()); - return; - } - - // let read_length = size.min(inode.size.saturating_sub(offset as u32)) as usize; - // 这和下面那个是等同的但是不利于让人看懂…… - let read_length = if offset as u32 + size <= inode.size { - size // 没有越过 EOF, 读取 size 个 byte - } else { - inode.size - offset as u32 // 越过了 EOF, 读取 inode.size - offset 个 byte - } as usize; - - let mut read_buffer = vec![0u8; read_length]; - let mut read_ptr = 0usize; - - let inode = inode.clone(); - - while read_ptr < read_length { - let current_point = offset as usize + read_ptr; - let current_block_index = current_point / BLOCK_SIZE; - let current_offset = current_point % BLOCK_SIZE; - - let read_length_within_block = - if BLOCK_SIZE - current_offset < read_length - read_ptr { - BLOCK_SIZE - current_offset // 可以读到 block 最后 - } else { - read_length - read_ptr // 读到中途会停下来 - }; - - if let Some(block) = self.access_block::<DataBlock>(&inode, current_block_index) { - (&mut read_buffer[read_ptr..read_ptr + read_length_within_block]) - .copy_from_slice( - &block.block.0 - [current_offset..current_offset + read_length_within_block], - ); - read_ptr += read_length_within_block; - } else { - reply.error(EIO); - return; - } - } - - reply.data(&read_buffer); - } - } - - // 写了多少就返回多少 - fn write( - &mut self, - req: &Request<'_>, - ino: u64, - fh: u64, - offset: i64, - data: &[u8], - _write_flags: u32, - _flags: i32, - _lock_owner: Option<u64>, - reply: ReplyWrite, - ) { - assert_eq!(self.file_handle_map.get(&fh).unwrap().0, ino as usize); - if let Some(inode) = self.get_inode(ino as usize) { - if inode.is_dir() { - reply.error(EISDIR); - return; - } - if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, W_OK) { - reply.error(EACCES); - return; - } - debug!( - "writing inode {:#x} (offset {} size {})", - ino, - offset, - data.len() - ); - let write_length = data.len(); - let mut write_ptr = 0usize; - - let mut inode = inode.clone(); - - while write_ptr < write_length { - let current_point = offset as usize + write_ptr; - let current_block_index = current_point / BLOCK_SIZE; - let current_offset = current_point % BLOCK_SIZE; - - let write_length_within_block = - if BLOCK_SIZE - current_offset < write_length - write_ptr { - BLOCK_SIZE - current_offset // 可以写满 block - } else { - write_length - write_ptr // 写完 buffer 就停下来 - }; - - // 当前块已分配, 直接往里写 - if let Some(block) = self.access_block_mut::<DataBlock>(&inode, current_block_index) - { - debug!( - "writing {} bytes in block {} within inode", - write_length_within_block, current_block_index - ); - (block.block.0[current_offset..current_offset + write_length_within_block]) - .copy_from_slice(&data[write_ptr..write_ptr + write_length_within_block]); - write_ptr += write_length_within_block; - } else { - // 当前块未分配,尝试分配 - if let Some((block_index, block_index_within_inode)) = - self.allocate_block_for(&mut inode) - { - debug!("writing {} bytes in allocated block {} within inode, block index is {}", write_length_within_block, block_index_within_inode, block_index); - // 能分配, 往里写 - let block = self - .access_block_mut::<DataBlock>(&inode, block_index_within_inode) - .unwrap(); - (block.block.0[current_offset..current_offset + write_length_within_block]) - .copy_from_slice( - &data[write_ptr..write_ptr + write_length_within_block], - ); - write_ptr += write_length_within_block; - } else { - // 分配不了, 没空间了 - break; - } - } - } - - inode.size = inode.size.max(offset as u32 + write_length as u32); - self.update_inode(ino as usize, inode); - reply.written(write_length as u32); - } else { - reply.error(ENOENT); - } - } - - fn release( - &mut self, - _req: &Request<'_>, - ino: u64, - fh: u64, - _flags: i32, - _lock_owner: Option<u64>, - _flush: bool, - reply: ReplyEmpty, - ) { - debug!("release(ino: {:#x?}, fh: {}", ino, fh); - if self.file_handle_map.contains_key(&fh) { - self.file_handle_map.remove(&fh); - reply.ok(); - } else { - reply.error(EBADF); - } - } - - fn opendir(&mut self, req: &Request<'_>, ino: u64, flags: i32, reply: ReplyOpen) { - debug!("opendir(ino: {:#x?}, flags: {:#x?})", ino, flags); - let (access_mask, read, write) = match flags & O_ACCMODE { - O_RDONLY => { - // Behavior is undefined, but most filesystems return EACCES - if flags & libc::O_TRUNC != 0 { - reply.error(EACCES); - return; - } - (R_OK, true, false) - } - O_WRONLY => (W_OK, false, true), - O_RDWR => (R_OK | W_OK, true, true), - _ => { - // flag 非法 - reply.error(EINVAL); - return; - } - }; - - match self.get_inode(ino as usize) { - Some(inode) => { - if !check_access( - req.uid(), - req.gid(), - inode.uid, - inode.gid, - inode.mode, - access_mask, - ) { - reply.error(EACCES); - return; - } - let fd = self.allocate_file_descriptor(ino as usize, read, write); - reply.opened(fd, 0); - } - None => { - reply.error(ENOENT); - } - } - } - - fn readdir( - &mut self, - req: &Request<'_>, - ino: u64, - fh: u64, // 如果 invoke 它的 opendir 里有指定 fh, 那么这里会收到 fh 参数 - offset: i64, - mut reply: ReplyDirectory, - ) { - assert_eq!(self.file_handle_map.get(&fh).unwrap().0, ino as usize); - if let Some(inode) = self.get_inode(ino as usize) { - if !inode.is_dir() { - reply.error(ENOTDIR); - return; - } - - if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, R_OK) { - reply.error(EACCES); - return; - } - - debug!( - "reading dir entries from inode {:#x} with offset {}", - ino, offset - ); - let inode = inode.clone(); - - self.load_direntry_map(ino as usize, &inode).unwrap(); - for (entry_index, (name, dir_entry)) in self - .dir_entry_map - .get(&(ino as usize)) - .unwrap() - .iter() - .enumerate() - .skip(offset as usize) - { - debug!( - " entry {} from inode {:#x} with name {:?}", - entry_index, dir_entry.inode, name - ); - if reply.add( - dir_entry.inode as u64, - entry_index as i64 + 1, - to_filetype(dir_entry.file_type).expect("not 0x0!"), - name, - ) { - break; - } - } - - reply.ok(); - } else { - reply.error(ENOENT); - } - } - - fn releasedir( - &mut self, - _req: &Request<'_>, - ino: u64, - fh: u64, - _flags: i32, - reply: ReplyEmpty, - ) { - debug!("releasedir(ino: {:#x?}, fh: {}", ino, fh); - if self.file_handle_map.contains_key(&fh) { - self.file_handle_map.remove(&fh); - reply.ok(); - } else { - reply.error(EBADF); - } - } - - fn access(&mut self, req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) { - // mask: - // - 要么是 libc::F_OK (aka 0), 检查文件是否存在 - // - 要么是 libc::R_OK,libc::W_OK,libc::X_OK (aka 4/2/1) 构成的 bitmask, 检查是否有对应权限 - debug!("Filesystem::access(ino: {}, mask: {})", ino, mask); - - if let Some(inode) = self.get_inode(ino as usize) { - if mask == libc::F_OK // 只要检查是否存在 - || check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, mask) - // 需要检查 rwx 权限 - { - reply.ok(); - } else { - reply.error(EACCES); - } - } else { - reply.error(ENOENT); - } - } -} |