diff options
Diffstat (limited to 'src/filesystem')
-rw-r--r-- | src/filesystem/trait_impl.rs | 347 |
1 files changed, 232 insertions, 115 deletions
diff --git a/src/filesystem/trait_impl.rs b/src/filesystem/trait_impl.rs index 73ae878..636bae7 100644 --- a/src/filesystem/trait_impl.rs +++ b/src/filesystem/trait_impl.rs @@ -1,21 +1,22 @@ - use crate::disk::inode::InodeMode; -use crate::utils::{from_systime, time_now, to_fileattr, to_filetype}; use crate::utils::permissions::get_groups; +use crate::utils::permissions::{check_access, clear_suid_sgid}; +use crate::utils::{from_systime, time_now, to_fileattr, to_filetype}; use crate::{AyaFS, TTL}; -use fuser::{Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, - ReplyEntry, ReplyLseek, ReplyOpen, Request, TimeOrNow, +use fuser::TimeOrNow::{Now, SpecificTime}; +use fuser::{ + Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, + ReplyLseek, ReplyOpen, Request, TimeOrNow, +}; +use libc::{ + c_int, EACCES, EEXIST, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR, EPERM, R_OK, + S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK, }; -use libc::{c_int, EACCES, EEXIST, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR, EPERM, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK}; use log::debug; use std::ffi::OsStr; use std::time::SystemTime; -use fuser::TimeOrNow::{Now, SpecificTime}; -use crate::utils::permissions::{check_access, clear_suid_sgid}; -impl AyaFS { - -} +impl AyaFS {} impl Filesystem for AyaFS { fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> { @@ -42,15 +43,15 @@ impl Filesystem for AyaFS { parent_inode.uid, parent_inode.gid, parent_inode.mode, - R_OK + R_OK, ) { let parent_inode = parent_inode.clone(); match self.lookup_name(&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) + } + Err(err_code) => reply.error(err_code), }; } else { reply.error(EACCES); @@ -96,7 +97,10 @@ impl Filesystem for AyaFS { 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) { + 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); @@ -175,14 +179,17 @@ impl Filesystem for AyaFS { 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 对吗 - ) { + 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; } @@ -201,14 +208,17 @@ impl Filesystem for AyaFS { 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 - ) { + 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; } @@ -248,49 +258,54 @@ impl Filesystem for AyaFS { ); if let Some(parent_inode) = self.get_inode(parent as usize) { - if check_access( + if !check_access( req.uid(), req.gid(), parent_inode.uid, parent_inode.gid, parent_inode.mode, - W_OK + W_OK, ) { - if parent_inode.is_dir() { - let parent_inode = parent_inode.clone(); - // 如果已经存在, 返回 already exists - if self.lookup_name(&parent_inode, name).is_ok() { - reply.error(EEXIST); - return; - } - // 文件名长度超过 255, 返回 filename too long - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } + reply.error(EACCES); + return; + } - let mode = mode as u16; - if let Some((inode_index, inode)) = self.create_file( - mode, - req.uid(), - req.gid(), - 0, - ) { - let file_attr = to_fileattr(inode_index, inode); - // TODO 把 inode 挂到 parent 下 - 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 不是 IFDIR -> Not a directory - reply.error(ENOTDIR); + // 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_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 child_inode = child_inode.clone(); + let file_attr = to_fileattr(child_inode_index, &child_inode); + if let Err(err_code) = + self.add_direntry(&mut parent_inode, child_inode_index, name, &child_inode) + { + reply.error(err_code); + return; } + self.update_inode(parent as usize, parent_inode); // 前面 clone 了, 这里写回 + reply.entry(&TTL, &file_attr, 0); } else { - reply.error(EACCES); + // create_inode 失败 -> no enough space + reply.error(ENOSPC); } } else { // parent 不存在 -> No such file or directory @@ -308,49 +323,55 @@ impl Filesystem for AyaFS { reply: ReplyEntry, ) { if let Some(parent_inode) = self.get_inode(parent as usize) { - if check_access( + // 无权限创建 -> EACCES + if !check_access( req.uid(), req.gid(), parent_inode.uid, parent_inode.gid, parent_inode.mode, - W_OK + W_OK, ) { - if parent_inode.is_dir() { - let parent_inode = parent_inode.clone(); - // 如果已经存在, 返回 already exists - if self.lookup_name(&parent_inode, name).is_ok() { - reply.error(EEXIST); - return; - } - // 文件名长度超过 255, 返回 filename too long - if name.len() > 255 { - reply.error(ENAMETOOLONG); - return; - } + reply.error(EACCES); + return; + } - let mode = mode as u16; - if let Some((inode_index, inode)) = self.create_directory( - mode, - req.uid(), - req.gid(), - 0, - ) { - let file_attr = to_fileattr(inode_index, inode); - // TODO 把 inode 挂到 parent 下 - 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 不是 IFDIR -> Not a directory - reply.error(ENOTDIR); + // 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_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 u32)) + { + let child_inode = child_inode.clone(); + let file_attr = to_fileattr(child_inode_index, &child_inode); + if let Err(err_code) = + self.add_direntry(&mut parent_inode, child_inode_index, name, &child_inode) + { + reply.error(err_code); + return; } + self.update_inode(parent as usize, parent_inode); // 前面 clone 了, 这里写回 + reply.entry(&TTL, &file_attr, 0); } else { - reply.error(EACCES); + // create_inode 失败 -> no enough space + reply.error(ENOSPC); } } else { // parent 不存在 -> No such file or directory @@ -358,11 +379,63 @@ impl Filesystem for AyaFS { } } - fn unlink(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { + fn unlink(&mut self, req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { debug!("unlink(parent: {:#x?}, name: {:?})", parent, name,); - if let Some(inode) = self.get_inode_mut(parent as usize) { - if inode.is_file() { - // TODO 找到这个 inode 并且删掉 + 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_inode, name) + { + let inode_index = inode_index as usize; + // 要删除的 entry 是目录, 不能用 unlink + if inode.is_dir() { + reply.error(EISDIR); + return; + } + // 删除 dir entry + if let Err(err_code) = self.remove_direntry(&mut parent_inode, entry_index) { + reply.error(err_code); + return; + } + // inode 的 n_links 减 1 + inode.n_links -= 1; + if inode.n_links == 0 { + // 释放块的操作在 remove file 里实现了 + match self.remove_file(inode_index) { + Ok(flag) => debug!(" unlink {}", flag), + Err(err_code) => { + reply.error(err_code); + return; + } + } + } else { + self.update_inode(inode_index, inode); + } reply.ok(); } else { reply.error(ENOENT); @@ -372,14 +445,65 @@ impl Filesystem for AyaFS { } } - fn rmdir(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { + fn rmdir(&mut self, req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) { debug!("rmdir(parent: {:#x?}, name: {:?}", parent, name,); - if let Some(inode) = self.get_inode_mut(parent as usize) { - if inode.is_file() { - // TODO 找到这个 inode 并且删掉 + 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_inode, name) + { + let inode_index = inode_index as usize; + // 要删除的 entry 是一般文件, 不用 rmdir + if inode.is_file() { + reply.error(ENOTDIR); + return; + } + + // TODO 检查待删除的 dir 是 empty 的 + + // 删除 dir entry + if let Err(err_code) = self.remove_direntry(&mut parent_inode, entry_index) { + reply.error(err_code); + return; + } + + // directory 没有 hard link, 删了就是删了 + match self.remove_dir(inode_index) { + Ok(flag) => debug!(" rmdir {}", flag), + Err(err_code) => { + reply.error(err_code); + return; + } + } + reply.ok(); } else { - reply.error(ENOTDIR); + reply.error(ENOENT); } } else { reply.error(ENOENT); @@ -415,14 +539,7 @@ impl Filesystem for AyaFS { ) { if let Some(inode) = self.get_inode(ino as usize) { if inode.is_dir() { - if check_access( - req.uid(), - req.gid(), - inode.uid, - inode.gid, - inode.mode, - R_OK, - ) { + if check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, R_OK) { let inode = inode.clone(); let mut entry_index = offset as u32; |