From 9d1368b0ea380a9446b4697af668d1685464b6c7 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Sun, 26 Nov 2023 02:33:01 -0800 Subject: more code idk what they are im so tired ohno --- src/disk/allocation.rs | 164 +++++++++++++++++--- src/disk/block.rs | 9 +- src/disk/inode.rs | 26 +++- src/filesystem/trait_impl.rs | 347 +++++++++++++++++++++++++++++-------------- src/main.rs | 2 +- src/memory/cached_block.rs | 53 +++++-- src/memory/cached_inode.rs | 87 +++++++---- src/memory/dir_entry.rs | 40 +++-- src/utils/permissions.rs | 6 +- 9 files changed, 528 insertions(+), 206 deletions(-) (limited to 'src') diff --git a/src/disk/allocation.rs b/src/disk/allocation.rs index 57cca0e..b88e7d5 100644 --- a/src/disk/allocation.rs +++ b/src/disk/allocation.rs @@ -1,7 +1,10 @@ -use crate::disk::block::{Block, DataBlock, DoubleIndirectBlock, IndirectBlock, TripleIndirectBlock}; -use crate::disk::inode::{DIRECT_NUMBER, Inode}; -use crate::memory::cached_block::{CachedBlock, convert}; +use crate::disk::block::{ + Block, DataBlock, DoubleIndirectBlock, IndirectBlock, TripleIndirectBlock, +}; +use crate::disk::inode::{Inode, DIRECT_NUMBER}; +use crate::memory::cached_block::{convert, CachedBlock}; use crate::{AyaFS, INODE_PER_BLOCK}; +use libc::c_int; impl AyaFS { /// 为 Inode 分配新 block, 返回 block 的编号和它在 inode 内的编号 @@ -13,6 +16,8 @@ impl AyaFS { // println!("allocating {} for direct", block_index); *index = block_index; inode.n_blocks += 1; + // 初始化这个 block + self.init_block(block_index as usize); // 当调用 get_inode_mut 拿出 &mut Inode 的时候对应的 block 在 cache 里已经脏了 return Some((block_index, index_within_direct)); } @@ -24,12 +29,16 @@ impl AyaFS { .data_bitmap .allocate() .expect("No free space for new block") as u32; + self.init_block(inode.single_indirect as usize); // println!("allocating {} for indirect", inode.single_indirect); } // 在 indirect block 里尝试分配 - if let Some((block_index, index_within_indirect)) = self.allocate_in_indirect(inode.single_indirect) { + if let Some((block_index, index_within_indirect)) = + self.allocate_in_indirect(inode.single_indirect) + { // println!("allocating {} in indirect", block_index); inode.n_blocks += 1; + let index_within_block = DIRECT_NUMBER + index_within_indirect; return Some((block_index, index_within_block)); } @@ -40,10 +49,13 @@ impl AyaFS { .data_bitmap .allocate() .expect("No free space for new block") as u32; + self.init_block(inode.double_indirect as usize); // println!("allocating {} for double indirect", inode.double_indirect); } // 在 double indirect block 里尝试分配 - if let Some((block_index, index_within_double)) = self.alloc_in_double_indirect(inode.double_indirect) { + if let Some((block_index, index_within_double)) = + self.alloc_in_double_indirect(inode.double_indirect) + { // println!("allocating {} in double indirect", block_index); inode.n_blocks += 1; let index_within_block = DIRECT_NUMBER + INODE_PER_BLOCK + index_within_double; @@ -56,13 +68,19 @@ impl AyaFS { .data_bitmap .allocate() .expect("No free space for new block") as u32; + self.init_block(inode.triple_indirect as usize); // println!("allocating {} for triple indirect", inode.triple_indirect); } // 在 double indirect block 里尝试分配 - if let Some((block_index, index_within_triple)) = self.alloc_in_triple_indirect(inode.triple_indirect) { + if let Some((block_index, index_within_triple)) = + self.alloc_in_triple_indirect(inode.triple_indirect) + { // println!("allocating {} in triple indirect", block_index); inode.n_blocks += 1; - let index_within_block = DIRECT_NUMBER + INODE_PER_BLOCK + INODE_PER_BLOCK * INODE_PER_BLOCK + index_within_triple; + let index_within_block = DIRECT_NUMBER + + INODE_PER_BLOCK + + INODE_PER_BLOCK * INODE_PER_BLOCK + + index_within_triple; return Some((block_index, index_within_block)); } None @@ -79,10 +97,13 @@ impl AyaFS { { // println!("found indirect block with number {}", indirect_entry); let mut indirect_block = block.clone(); - for (index_within_indirect, entry) in indirect_block.block.entries.iter_mut().enumerate() { + for (index_within_indirect, entry) in + indirect_block.block.entries.iter_mut().enumerate() + { if self.data_bitmap.query(*entry as usize) == false { indirect_block.dirty = true; // 把这个块标记为 dirty let block_index = self.data_bitmap.allocate().expect("No free space") as u32; + self.init_block(block_index as usize); *entry = block_index; self.update_block(indirect_block); return Some((block_index, index_within_indirect)); @@ -101,18 +122,26 @@ impl AyaFS { { let mut double_indirect_block = block.clone(); let mut double_indirect_modified = false; - for (index_within_double_indirect, indirect_entry) in double_indirect_block.block.indirect.iter_mut().enumerate() { + for (index_within_double_indirect, indirect_entry) in + double_indirect_block.block.indirect.iter_mut().enumerate() + { if self.data_bitmap.query(*indirect_entry as usize) == false { double_indirect_block.dirty = true; double_indirect_modified = true; - *indirect_entry = self.data_bitmap.allocate().expect("No free space") as u32; + + let indirect_index = self.data_bitmap.allocate().expect("No free space"); + *indirect_entry = indirect_index as u32; + self.init_block(indirect_index); } - if let Some((block_index, index_within_indirect)) = self.allocate_in_indirect(*indirect_entry) { + if let Some((block_index, index_within_indirect)) = + self.allocate_in_indirect(*indirect_entry) + { if double_indirect_modified { self.update_block(double_indirect_block); } - let index_within_double = index_within_double_indirect * INODE_PER_BLOCK + index_within_indirect; + let index_within_double = + index_within_double_indirect * INODE_PER_BLOCK + index_within_indirect; return Some((block_index, index_within_double)); } } @@ -129,18 +158,29 @@ impl AyaFS { { let mut triple_indirect_block = block.clone(); let mut triple_indirect_modified = false; - for (index_within_triple_indirect, double_indirect_entry) in triple_indirect_block.block.double_indirect.iter_mut().enumerate() { + for (index_within_triple_indirect, double_indirect_entry) in triple_indirect_block + .block + .double_indirect + .iter_mut() + .enumerate() + { if self.data_bitmap.query(*double_indirect_entry as usize) == false { triple_indirect_block.dirty = true; triple_indirect_modified = true; - *double_indirect_entry = - self.data_bitmap.allocate().expect("No free space") as u32; + + let double_indirect_index = self.data_bitmap.allocate().expect("No free space"); + *double_indirect_entry = double_indirect_index as u32; + self.init_block(double_indirect_index) } - if let Some((block_index, index_within_double_indirect)) = self.alloc_in_double_indirect(*double_indirect_entry) { + if let Some((block_index, index_within_double_indirect)) = + self.alloc_in_double_indirect(*double_indirect_entry) + { if triple_indirect_modified { self.update_block(triple_indirect_block); } - let index_within_triple = index_within_triple_indirect * INODE_PER_BLOCK * INODE_PER_BLOCK + index_within_double_indirect; + let index_within_triple = + index_within_triple_indirect * INODE_PER_BLOCK * INODE_PER_BLOCK + + index_within_double_indirect; return Some((block_index, index_within_triple)); } } @@ -150,6 +190,70 @@ impl AyaFS { } impl AyaFS { + pub(crate) fn deallocate_all_blocks_for(&mut self, inode: &Inode) -> Result<(), c_int> { + // 遍历 direct block 并删除 + for block_index in inode.direct { + self.data_bitmap.deallocate(block_index as usize); + } + + // 遍历 indirect block 并删除 + if self.data_bitmap.query(inode.single_indirect as usize) { + let indirect = self + .get_block::(inode.single_indirect as usize) + .unwrap(); + for block_index in indirect.block.entries { + self.data_bitmap.deallocate(block_index as usize); + } + self.data_bitmap.deallocate(inode.single_indirect as usize); + } + + // 遍历 double indirect block 并删除 + if self.data_bitmap.query(inode.double_indirect as usize) { + let double_indirect = self + .get_block::(inode.double_indirect as usize) + .unwrap(); + for indirect_block_index in double_indirect.block.indirect { + if let Some(indirect) = + self.get_block::(indirect_block_index as usize) + { + for block_index in indirect.block.entries { + self.data_bitmap.deallocate(block_index as usize); + } + self.data_bitmap.deallocate(indirect_block_index as usize); + } + } + self.data_bitmap.deallocate(inode.double_indirect as usize); + } + + // 遍历 triple indirect block 并删除 + if self.data_bitmap.query(inode.triple_indirect as usize) { + let triple_indirect = self + .get_block::(inode.triple_indirect as usize) + .unwrap(); + for double_indirect_block_index in triple_indirect.block.double_indirect { + if let Some(double_indirect) = + self.get_block::(double_indirect_block_index as usize) + { + for indirect_block_index in double_indirect.block.indirect { + if let Some(indirect) = + self.get_block::(indirect_block_index as usize) + { + for block_index in indirect.block.entries { + self.data_bitmap.deallocate(block_index as usize); + } + self.data_bitmap.deallocate(indirect_block_index as usize); + } + } + self.data_bitmap + .deallocate(double_indirect_block_index as usize); + } + } + self.data_bitmap.deallocate(inode.triple_indirect as usize); + } + + Ok(()) + } + /// 从 inode 中删去最后一个 block pub(crate) fn deallocate_block_for(&mut self, inode: &mut Inode) -> Option { // 如果 triple indirect 块存在, 则尝试从中销毁一个块 @@ -294,7 +398,11 @@ impl AyaFS { } impl AyaFS { - fn get_block_index(&mut self, inode: &Inode, mut block_index_within_inode: usize) -> Option { + fn get_block_index( + &mut self, + inode: &Inode, + mut block_index_within_inode: usize, + ) -> Option { // direct block if block_index_within_inode < DIRECT_NUMBER { let block_index = inode.direct[block_index_within_inode] as usize; @@ -335,7 +443,7 @@ impl AyaFS { [block_index_within_inode % INODE_PER_BLOCK] as usize; // 拿到 DirectoryBlock 的 index - return Some(block_index) + return Some(block_index); } } return None; @@ -358,7 +466,7 @@ impl AyaFS { // 取出 double indirect block let indirect_block_index = double_indirect_block.block.indirect [block_index_within_inode % (INODE_PER_BLOCK * INODE_PER_BLOCK) - / INODE_PER_BLOCK] as usize; + / INODE_PER_BLOCK] as usize; // 要找的 entry 在 double indirect block 中的第几个 indirect block if let Some(indirect_block) = self.get_block::(indirect_block_index) { @@ -366,7 +474,7 @@ impl AyaFS { [block_index_within_inode % INODE_PER_BLOCK] as usize; // DirectoryBlock 的 index - return Some(block_index) + return Some(block_index); } } } @@ -374,17 +482,25 @@ impl AyaFS { None } - pub(crate) fn access_block(&mut self, inode: &Inode, block_index_within_inode: usize) -> Option<&CachedBlock> { + pub(crate) fn access_block( + &mut self, + inode: &Inode, + block_index_within_inode: usize, + ) -> Option<&CachedBlock> { self.get_block_index(inode, block_index_within_inode) .map(|block_index| { self.get_block::(block_index).unwrap() // 可以 unwrap 吧这里 ?? }) } - pub(crate) fn access_block_mut(&mut self, inode: &Inode, block_index_within_inode: usize) -> Option<&mut CachedBlock> { + pub(crate) fn access_block_mut( + &mut self, + inode: &Inode, + block_index_within_inode: usize, + ) -> Option<&mut CachedBlock> { self.get_block_index(inode, block_index_within_inode) .map(|block_index| { self.get_block_mut::(block_index).unwrap() // 可以 unwrap 吧这里 ?? }) } -} \ No newline at end of file +} diff --git a/src/disk/block.rs b/src/disk/block.rs index be3d85a..26a7ec5 100644 --- a/src/disk/block.rs +++ b/src/disk/block.rs @@ -120,10 +120,12 @@ impl DirectoryBlock { } pub(crate) fn query(&self, mut index: usize) -> bool { - if index < 7 { // 0-6, first u8 + if index < 7 { + // 0-6, first u8 index = index + 1; self.occupancy[0] & (1 << (7 - index)) as u8 != 0 - } else if index < 15 { // 7-14, second u8 + } else if index < 15 { + // 7-14, second u8 index = index - 7; self.occupancy[1] & (1 << (7 - index)) as u8 != 0 } else { @@ -149,7 +151,8 @@ impl DirectoryBlock { if index < 7 { index = index + 1; self.occupancy[0] &= !((1 << (7 - index)) as u8); - } else if index < 15 { // 7-14, second u8 + } else if index < 15 { + // 7-14, second u8 index = index - 7; self.occupancy[1] &= !((1 << (7 - index)) as u8); } diff --git a/src/disk/inode.rs b/src/disk/inode.rs index 256d2f5..6f9d338 100644 --- a/src/disk/inode.rs +++ b/src/disk/inode.rs @@ -1,6 +1,6 @@ +use crate::utils; use bitflags::bitflags; use fuser::{FileAttr, FileType}; -use crate::utils; pub const DIRECT_NUMBER: usize = 15; @@ -103,7 +103,6 @@ impl From for u8 { } } - /// Pretty much the same with ext2, with minor changes: /// - removed OS dependent attributes (osd1 & osd2) /// - removed i_faddr since fragmentation is not supported @@ -153,7 +152,7 @@ impl Inode { mtime: time, crtime: time, gid, - n_links: 0, + n_links: 1, n_blocks: 0, flags, direct: [0; DIRECT_NUMBER], @@ -242,7 +241,26 @@ impl Inode { } pub fn empty() -> Self { - Self::new(InodeMode(0), 0, 0, 0, 0, 0, 0, 0) + Self { + mode: InodeMode(0), + uid: 0, + size: 0, + atime: 0, + ctime: 0, + mtime: 0, + crtime: 0, + gid: 0, + n_links: 0, + n_blocks: 0, + flags: 0, + direct: [0; 15], + single_indirect: 0, + double_indirect: 0, + triple_indirect: 0, + generation: 0, + file_acl: 0, + dir_acl: 0, + } } } pub const INODE_SIZE: usize = std::mem::size_of::(); 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; diff --git a/src/main.rs b/src/main.rs index e0bfa2e..5d460fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,7 @@ impl AyaFS { cached_blocks: BlockCache::new(device.clone(), 8192), }; - fs.create_directory(0o755, get_current_uid(), get_current_gid(), 0); + fs.create_directory(0o755, get_current_uid(), get_current_gid(), 0, None); fs } diff --git a/src/memory/cached_block.rs b/src/memory/cached_block.rs index 783e987..002a75b 100644 --- a/src/memory/cached_block.rs +++ b/src/memory/cached_block.rs @@ -75,7 +75,7 @@ impl BlockCache { if !self.cache.contains(&index) { self.load_block(index); } - self.cache.get(&index).map(convert::) + self.cache.get(&index).map(convert::) } /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载. @@ -90,6 +90,24 @@ impl BlockCache { }) } + /// 向 LRU cache 中插入一个全新初始化的 block + /// 这个 block 全 0, 而且是 dirty 的, 即使被挤出去也会触发一次落盘 + pub(crate) fn init_block(&mut self, index: usize) { + let allocated_block = CachedBlock { + block: T::default(), + index, + dirty: true, + }; + if let Some((old_index, old_block)) = self.cache.push(index, allocated_block) { + if old_block.dirty { + let old_block_ptr = &old_block.block as *const T as *mut u8; + let old_block_buffer = + unsafe { std::slice::from_raw_parts(old_block_ptr, BLOCK_SIZE) }; + self.device.write(old_index, old_block_buffer); + } + } + } + /// 从 LRU cache 中读取一个 block 的引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. pub(crate) fn peek_block(&self, index: usize) -> Option<&CachedBlock> { self.cache.peek(&index).map(convert::) @@ -117,26 +135,33 @@ impl BlockCache { } impl AyaFS { - pub(crate) fn load_block(&mut self, index: usize) -> bool { - if !self.data_bitmap.query(index) { - self.cached_blocks.pop(&index); - // deallocate 时只更新 bitmap 没有动 cache, lazy 地驱逐 cache 中的无效 entry. - return false; - } - self.cached_blocks.load_block(index) + pub(crate) fn init_block(&mut self, index: usize) { + self.cached_blocks.init_block(index); } pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { - self.data_bitmap - .query(index) - .then(|| self.cached_blocks.get_block::(index).unwrap()) + if self.data_bitmap.query(index) { + Some(self.cached_blocks.get_block::(index).unwrap()) + } else { + self.cached_blocks.pop(&index); + None + } + // self.data_bitmap + // .query(index) + // .then(|| self.cached_blocks.get_block::(index).unwrap()) // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid } pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { - self.data_bitmap - .query(index) - .then(|| self.cached_blocks.get_block_mut::(index).unwrap()) + if self.data_bitmap.query(index) { + Some(self.cached_blocks.get_block_mut::(index).unwrap()) + } else { + self.cached_blocks.pop(&index); + None + } + // self.data_bitmap + // .query(index) + // .then(|| self.cached_blocks.get_block_mut::(index).unwrap()) // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid } diff --git a/src/memory/cached_inode.rs b/src/memory/cached_inode.rs index b1be2de..aa4f5e3 100644 --- a/src/memory/cached_inode.rs +++ b/src/memory/cached_inode.rs @@ -1,10 +1,8 @@ use crate::disk::block::{DirectoryBlock, DirectoryEntry, InodeBlock}; -use crate::disk::inode::{Inode, InodeMode, INODE_SIZE}; -use crate::utils::from_filetype; +use crate::disk::inode::{Inode, INODE_SIZE}; use crate::{utils, AyaFS}; use and_then_some::BoolExt; -use fuser::FileType; -use log::debug; +use libc::{c_int, EISDIR, ENOENT, ENOTDIR}; impl AyaFS { pub(crate) fn create_file( @@ -22,12 +20,14 @@ impl AyaFS { }) } + /// 根目录的 parent_inode_number 传入 None, 会直接以自己作为 .. 的 inode number pub(crate) fn create_directory( &mut self, permissions: u16, uid: u32, gid: u32, flags: u32, + parent_inode_number: Option, ) -> Option<(usize, &Inode)> { self.inode_bitmap.allocate().map(|inode_index| { // 创建 Inode @@ -53,7 +53,7 @@ impl AyaFS { // add dot dot entry directory_block.block.entries[1] = DirectoryEntry { - inode: 0, // TODO set this as parent inode number + inode: parent_inode_number.unwrap_or(inode_index as u32), record_len: 264, name_len: 2, file_type: 0x2, @@ -70,31 +70,60 @@ impl AyaFS { (inode_index, self.get_inode(inode_index).unwrap()) }) } + + pub(crate) fn remove_file(&mut self, inode_index: usize) -> Result { + if self.inode_bitmap.query(inode_index) { + self.inode_bitmap.deallocate(inode_index); + let (block_index, offset) = self.locate_inode(inode_index); + if let Some(cached_block) = self.cached_inodes.get_block::(block_index) { + let inode = cached_block.block.inodes[offset / INODE_SIZE].clone(); + if !inode.is_file() { + return Err(EISDIR); + } + self.deallocate_all_blocks_for(&inode).unwrap(); + } + Ok(true) + } else { + Err(ENOENT) + } + } + + pub(crate) fn remove_dir(&mut self, inode_index: usize) -> Result { + if self.inode_bitmap.query(inode_index) { + self.inode_bitmap.deallocate(inode_index); + let (block_index, offset) = self.locate_inode(inode_index); + if let Some(cached_block) = self.cached_inodes.get_block::(block_index) { + let inode = cached_block.block.inodes[offset / INODE_SIZE].clone(); + if !inode.is_dir() { + return Err(ENOTDIR); + } + // TODO 递归删除所有下面的 direntry 里的 inode, 注意排除 . 和 .. + } + Ok(true) + } else { + Err(ENOENT) + } + } - pub(crate) fn create_inode( - &mut self, - permissions: u16, - mode: InodeMode, - uid: u32, - gid: u32, - flags: u32, - ) -> Option { - self.inode_bitmap.allocate().map(|inode_index| { - self.get_inode_mut(inode_index).map(|inode| { - *inode = Inode::make_inode( - permissions, - mode, - uid, - gid, - utils::time_now(), - flags, - 0, - 0, - 0, - ); - }); - inode_index - }) + pub(crate) fn remove_inode(&mut self, inode_index: usize) -> bool { + if self.inode_bitmap.query(inode_index) { + self.inode_bitmap.deallocate(inode_index); + let (block_index, offset) = self.locate_inode(inode_index); + if let Some(cached_block) = self.cached_inodes.get_block::(block_index) { + let inode = &cached_block.block.inodes[offset / INODE_SIZE].clone(); + + if inode.is_file() { + self.deallocate_all_blocks_for(inode).unwrap(); + } else if inode.is_dir() { + // TODO 把 dir 下所有子目录 remove 掉 + } else { + unimplemented!("only file and dir are implemented!"); + } + } + true + } else { + false + } } pub(crate) fn update_inode(&mut self, inode_index: usize, inode: Inode) -> bool { diff --git a/src/memory/dir_entry.rs b/src/memory/dir_entry.rs index 0ade23f..2d961db 100644 --- a/src/memory/dir_entry.rs +++ b/src/memory/dir_entry.rs @@ -1,15 +1,21 @@ -use std::ffi::OsStr; -use std::os::unix::ffi::OsStrExt; -use libc::{c_int, ENOENT, ENOSPC}; use crate::disk::block::{DirectoryBlock, DirectoryEntry}; -use crate::disk::inode::{Inode}; +use crate::disk::inode::Inode; use crate::AyaFS; +use libc::{c_int, ENOENT, ENOSPC}; +use std::ffi::OsStr; +use std::os::unix::ffi::OsStrExt; impl AyaFS { + /// 删除所有的 dir entry, 递归 + pub(crate) fn clear_direntry(&mut self, parent_inode: &mut Inode) -> Result<(), c_int> { + todo!() + } + + /// 删除第 entry_index 个 dir entry pub(crate) fn remove_direntry( &mut self, parent_inode: &mut Inode, - entry_index: u32 + entry_index: u32, ) -> Result<(), c_int> { let block_index_within_inode = (entry_index / 15) as usize; let entry_index_within_block = (entry_index % 15) as usize; @@ -18,7 +24,8 @@ impl AyaFS { Some(directory_block) => { if directory_block.block.query(entry_index_within_block) { directory_block.block.deallocate(entry_index_within_block); - directory_block.block.entries[entry_index_within_block] = DirectoryEntry::default(); + directory_block.block.entries[entry_index_within_block] = + DirectoryEntry::default(); Ok(()) } else { Err(ENOENT) @@ -31,7 +38,7 @@ impl AyaFS { pub(crate) fn add_direntry( &mut self, parent_inode: &mut Inode, - child_inode_index: u32, + child_inode_index: usize, child_inode_name: &OsStr, child_inode: &Inode, ) -> Result { @@ -45,7 +52,9 @@ impl AyaFS { } } // 寻找当前块里有没有空闲空间 - if let Some(directory_block) = self.access_block_mut::(parent_inode, block_index_within_inode) { + if let Some(directory_block) = + self.access_block_mut::(parent_inode, block_index_within_inode) + { if let Some(entry_index_within_block) = directory_block.block.allocate() { // 如果有空闲空间, 可以分配一个块 let name_len = child_inode_name.len() as u8; @@ -54,7 +63,7 @@ impl AyaFS { name.copy_from_slice(child_inode_name.as_bytes()); let dir_entry = DirectoryEntry { - inode: child_inode_index, + inode: child_inode_index as u32, record_len: 264, name_len, file_type, @@ -66,12 +75,12 @@ impl AyaFS { } } block_index_within_inode += 1; - }; + } } pub(crate) fn get_direntry( &mut self, parent_inode: &Inode, - entry_index: u32 + entry_index: u32, ) -> Option { let block_index_within_inode = (entry_index / 15) as usize; let entry_index_within_block = (entry_index % 15) as usize; @@ -87,13 +96,18 @@ impl AyaFS { } // TODO 实现一个带 cache 的版本 - pub fn lookup_name(&mut self, parent_inode: &Inode, name: &OsStr) -> Result<(u32, u32, Inode), c_int> { + /// 返回 inode_index, inode 在 parent 里的 index, inode 本身 + pub fn lookup_name( + &mut self, + parent_inode: &Inode, + name: &OsStr, + ) -> Result<(u32, u32, Inode), c_int> { let mut entry_index = 0; while entry_index < parent_inode.size { if let Some(entry) = self.get_direntry(parent_inode, entry_index) { if entry.name() == name { let inode = self.get_inode(entry.inode as usize).unwrap().clone(); - return Ok((entry.inode, entry_index, inode)) + return Ok((entry.inode, entry_index, inode)); } } entry_index += 1; diff --git a/src/utils/permissions.rs b/src/utils/permissions.rs index a3afe77..b1ec999 100644 --- a/src/utils/permissions.rs +++ b/src/utils/permissions.rs @@ -1,7 +1,7 @@ +use crate::disk::inode::InodeMode; +use libc::{F_OK, S_ISGID, S_ISUID, S_IXGRP, X_OK}; use std::fs::File; use std::io::BufRead; -use libc::{F_OK, S_ISGID, S_ISUID, S_IXGRP, X_OK}; -use crate::disk::inode::InodeMode; pub(crate) fn get_groups(pid: u32) -> Vec { let file = File::open(format!("/proc/{pid}/task/{pid}/status")) @@ -59,4 +59,4 @@ pub(crate) fn check_access( mask -= mask & perm; } mask == 0 -} \ No newline at end of file +} -- cgit v1.2.3-70-g09d2