diff options
author | Chuyan Zhang <me@zcy.moe> | 2023-11-29 03:29:34 -0800 |
---|---|---|
committer | Chuyan Zhang <me@zcy.moe> | 2023-11-29 03:29:34 -0800 |
commit | 7af0771f9a3031acc36a6990d07bdb92a61c0c75 (patch) | |
tree | 3db3c79b8d385bc949c8486d97def8dadd4323e6 | |
parent | ceb83a7214000ccd048857b40cc0ebfc54290731 (diff) | |
download | myfs-7af0771f9a3031acc36a6990d07bdb92a61c0c75.tar.gz myfs-7af0771f9a3031acc36a6990d07bdb92a61c0c75.zip |
symlink, probably not working
-rw-r--r-- | src/disk/allocation.rs | 14 | ||||
-rw-r--r-- | src/disk/block.rs | 63 | ||||
-rw-r--r-- | src/disk/inode.rs | 42 | ||||
-rw-r--r-- | src/filesystem/trait_impl.rs | 258 | ||||
-rw-r--r-- | src/memory/cached_block.rs | 13 | ||||
-rw-r--r-- | src/memory/cached_inode.rs | 92 | ||||
-rw-r--r-- | src/memory/dir_entry.rs | 68 | ||||
-rw-r--r-- | src/memory/file_handle.rs | 4 | ||||
-rw-r--r-- | src/tests/common/mod.rs | 1 | ||||
-rw-r--r-- | src/utils/mod.rs | 20 | ||||
-rw-r--r-- | src/utils/permissions.rs | 4 |
11 files changed, 371 insertions, 208 deletions
diff --git a/src/disk/allocation.rs b/src/disk/allocation.rs index a4bb3f7..d4ad397 100644 --- a/src/disk/allocation.rs +++ b/src/disk/allocation.rs @@ -5,6 +5,7 @@ use crate::disk::inode::{Inode, DIRECT_NUMBER}; use crate::memory::cached_block::{convert, CachedBlock}; use crate::{AyaFS, INODE_PER_BLOCK}; use libc::c_int; +use log::debug; impl AyaFS { /// 为 Inode 分配新 block, 返回 block 的编号和它在 inode 内的编号 @@ -403,12 +404,16 @@ impl AyaFS { inode: &Inode, mut block_index_within_inode: usize, ) -> Option<usize> { + debug!("get_block_index(block_index_within_inode: {})", block_index_within_inode); // direct block if block_index_within_inode < DIRECT_NUMBER { let block_index = inode.direct[block_index_within_inode] as usize; + debug!(" get_block_index -> direct"); return if self.data_bitmap.query(block_index) { + debug!(" get_block_index -> direct -> ✓"); Some(block_index) } else { + debug!(" get_block_index -> direct -> ×"); None }; } else { @@ -416,18 +421,22 @@ impl AyaFS { } // indirect block - let indirect_number = INODE_PER_BLOCK; + let indirect_number = 1024; if block_index_within_inode < indirect_number { return if let Some(indirect_block) = self.get_block::<IndirectBlock>(inode.single_indirect as usize) { + debug!(" get_block_index -> indirect"); let block_index = indirect_block.block.entries[block_index_within_inode] as usize; if self.data_bitmap.query(block_index) { + debug!(" get_block_index -> indirect -> direct -> ✓"); Some(block_index) } else { + debug!(" get_block_index -> indirect -> direct -> ×"); None } } else { + debug!(" get_block_index -> indirect -> ×"); None }; } else { @@ -435,7 +444,7 @@ impl AyaFS { } // double indirect block - let double_indirect_number = INODE_PER_BLOCK * INODE_PER_BLOCK; + let double_indirect_number = 1024 * 1024; if block_index_within_inode < double_indirect_number { if let Some(double_indirect_block) = self.get_block::<DoubleIndirectBlock>(inode.double_indirect as usize) @@ -516,6 +525,7 @@ impl AyaFS { ) -> Option<&mut CachedBlock<T>> { self.get_block_index(inode, block_index_within_inode) .map(|block_index| { + debug!("access_block_mut(index: {}) found", block_index_within_inode); self.get_block_mut::<T>(block_index).unwrap() // 可以 unwrap 吧这里 ?? }) } diff --git a/src/disk/block.rs b/src/disk/block.rs index 26a7ec5..73819e2 100644 --- a/src/disk/block.rs +++ b/src/disk/block.rs @@ -19,7 +19,7 @@ impl Block for DataBlock {} #[repr(C)] #[derive(Clone)] pub struct InodeBlock { - pub(crate) inodes: [Inode; 16], + pub(crate) inodes: [Inode; 32], } impl Default for InodeBlock { @@ -42,6 +42,22 @@ impl Default for InodeBlock { Inode::empty(), Inode::empty(), Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), ], } } @@ -49,8 +65,6 @@ impl Default for InodeBlock { impl Block for InodeBlock {} -const FULL_MAP: u16 = 0b111_111_111_111_111; - #[repr(C)] #[derive(Clone)] pub struct DirectoryEntry { @@ -115,6 +129,7 @@ impl Default for DirectoryBlock { } impl DirectoryBlock { + #[allow(unused)] pub(crate) fn is_full(&self) -> bool { self.occupancy[0] == 0xFF && self.occupancy[1] == 0xFF } @@ -133,20 +148,42 @@ impl DirectoryBlock { } } - pub(crate) fn allocate(&mut self) -> Option<usize> { - if self.occupancy[0] != 0xFF { - let leading_ones = self.occupancy[0].leading_ones(); - self.occupancy[0] |= (1 << (7 - leading_ones)) as u8; - Some(leading_ones as usize) - } else if self.occupancy[1] != 0xFF { - let leading_ones = self.occupancy[1].leading_ones(); - self.occupancy[1] |= (1 << (7 - leading_ones)) as u8; - Some(7 + leading_ones as usize) + pub(crate) fn allocate(&mut self, mut index: usize) -> bool { + if index < 7 { + index = index + 1; + let mask = (1 << (7 - index)) as u8; + if self.occupancy[0] & mask != 0 { + false + } else { + self.occupancy[0] |= mask; + true + } } else { - None + index = index - 7; + let mask = (1 << (7 - index)) as u8; + if self.occupancy[1] & mask != 0 { + false + } else { + self.occupancy[1] |= mask; + true + } } } + // pub(crate) fn allocate(&mut self) -> Option<usize> { + // if self.occupancy[0] != 0xFF { + // let leading_ones = self.occupancy[0].leading_ones(); + // self.occupancy[0] |= (1 << (7 - leading_ones)) as u8; + // Some(leading_ones as usize) + // } else if self.occupancy[1] != 0xFF { + // let leading_ones = self.occupancy[1].leading_ones(); + // self.occupancy[1] |= (1 << (7 - leading_ones)) as u8; + // Some(7 + leading_ones as usize) + // } else { + // None + // } + // } + pub(crate) fn deallocate(&mut self, mut index: usize) { if index < 7 { index = index + 1; diff --git a/src/disk/inode.rs b/src/disk/inode.rs index 6f9d338..1f5e54e 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 fuser::FileType; pub const DIRECT_NUMBER: usize = 15; @@ -33,30 +33,39 @@ bitflags! { } impl InodeMode { + #[allow(unused)] pub(crate) fn exec_other(&self) -> bool { self.0 & Self::IXOTH.0 != 0 } + #[allow(unused)] pub(crate) fn write_other(&self) -> bool { self.0 & Self::IWOTH.0 != 0 } + #[allow(unused)] pub(crate) fn read_other(&self) -> bool { self.0 & Self::IROTH.0 != 0 } + #[allow(unused)] pub(crate) fn exec_group(&self) -> bool { self.0 & Self::IXGRP.0 != 0 } + #[allow(unused)] pub(crate) fn write_group(&self) -> bool { self.0 & Self::IWGRP.0 != 0 } + #[allow(unused)] pub(crate) fn read_group(&self) -> bool { self.0 & Self::IRGRP.0 != 0 } + #[allow(unused)] pub(crate) fn exec_user(&self) -> bool { self.0 & Self::IXUSR.0 != 0 } + #[allow(unused)] pub(crate) fn write_user(&self) -> bool { self.0 & Self::IWUSR.0 != 0 } + #[allow(unused)] pub(crate) fn read_user(&self) -> bool { self.0 & Self::IRUSR.0 != 0 } @@ -73,6 +82,8 @@ impl InodeMode { (self.0 & 0xF000) == Self::IFDIR.0 } + pub(crate) fn is_symlink(&self) -> bool { self.0 & 0xF000 == Self::IFLNK.0 } + pub(crate) fn validate(mode_value: u16) -> Option<Self> { let valid_flags: [u16; 7] = [0x1000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000]; valid_flags @@ -165,6 +176,7 @@ impl Inode { } } + #[allow(unused)] pub fn make_inode( permissions: u16, mode: InodeMode, @@ -232,6 +244,28 @@ impl Inode { ) } + pub fn symlink( + permissions: u16, + uid: u32, + gid: u32, + time: u32, + flags: u32, + generation: u32, + file_acl: u32, + dir_acl: u32, + ) -> Self { + Self::new( + InodeMode(permissions) | InodeMode::IFLNK, + uid, + gid, + time, + flags, + generation, + file_acl, + dir_acl, + ) + } + pub(crate) fn is_file(&self) -> bool { self.mode.is_file() } @@ -240,6 +274,12 @@ impl Inode { self.mode.is_dir() } + pub(crate) fn is_symlink(&self) -> bool { self.mode.is_symlink() } + + pub(crate) fn file_type(&self) -> FileType { + self.mode.into() + } + pub fn empty() -> Self { Self { mode: InodeMode(0), diff --git a/src/filesystem/trait_impl.rs b/src/filesystem/trait_impl.rs index 78916ed..5523c8c 100644 --- a/src/filesystem/trait_impl.rs +++ b/src/filesystem/trait_impl.rs @@ -1,15 +1,16 @@ use crate::disk::inode::InodeMode; 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::utils::{from_filetype, from_systime, time_now, to_fileattr, to_filetype}; use crate::{AyaFS, TTL}; use fuser::TimeOrNow::{Now, SpecificTime}; -use fuser::{ - Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyWrite, Request, TimeOrNow, -}; -use libc::{c_int, EACCES, EBADF, EEXIST, EINVAL, EIO, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR, ENOTEMPTY, EPERM, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK}; +use fuser::{Filesystem, FileType, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyWrite, Request, TimeOrNow}; +use libc::{c_int, EACCES, EBADF, EEXIST, EFAULT, EINVAL, EIO, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR, ENOTEMPTY, EPERM, IPOPT_OFFSET, link, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK, write}; use log::debug; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; +use std::os::unix::ffi::OsStrExt; +use std::path::Path; +use std::slice; use std::time::SystemTime; use crate::block_device::BLOCK_SIZE; use crate::disk::block::DataBlock; @@ -155,6 +156,7 @@ impl Filesystem for AyaFS { // 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(); @@ -254,9 +256,184 @@ impl Filesystem for AyaFS { } } - fn readlink(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyData) { - debug!("[Not Implemented] readlink(ino: {})", ino); - reply.error(ENOSYS); + 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 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( @@ -270,11 +447,12 @@ impl Filesystem for AyaFS { reply: ReplyEntry, ) { debug!( - "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {})", + "mknod(parent: {}, name: {:?}, mode: {}, umask: {})", parent, name, mode, _umask ); - if let Some(parent_inode) = self.get_inode(parent as usize) { + let parent = parent as usize; + if let Some(parent_inode) = self.get_inode(parent) { if !check_access( req.uid(), req.gid(), @@ -302,7 +480,7 @@ impl Filesystem for AyaFS { let mut parent_inode = parent_inode.clone(); // 如果已经存在, 返回 already exists if self - .lookup_name(parent as usize, &parent_inode, name) + .lookup_name(parent, &parent_inode, name) .is_ok() { reply.error(EEXIST); @@ -313,19 +491,19 @@ impl Filesystem for AyaFS { 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); + let mode = child_inode.mode; + let file_attr = to_fileattr(child_inode_index, child_inode); if let Err(err_code) = self.add_direntry( - parent as usize, + parent, &mut parent_inode, child_inode_index, name, - child_inode.mode.into(), + mode.into(), ) { reply.error(err_code); return; } - self.update_inode(parent as usize, parent_inode); // 前面 clone 了, 这里写回 + self.update_inode(parent, parent_inode); // 前面 clone 了, 这里写回 reply.entry(&TTL, &file_attr, 0); } else { // create_inode 失败 -> no enough space @@ -444,27 +622,37 @@ impl Filesystem for AyaFS { self.lookup_name(parent as usize, &parent_inode, name) { let inode_index = inode_index as usize; - // 要删除的 entry 是目录, 不能用 unlink - if inode.is_dir() { - reply.error(EISDIR); - return; - } - - 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; + + 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; } - } else { - // n_links > 0 -> 只是移除了一个 hard link, 将改动写回 - self.update_inode(inode_index, inode); } - + // 删除 dir entry if let Err(err_code) = self.remove_direntry(parent as usize, &mut parent_inode, name, entry_index) diff --git a/src/memory/cached_block.rs b/src/memory/cached_block.rs index 002a75b..c3d0338 100644 --- a/src/memory/cached_block.rs +++ b/src/memory/cached_block.rs @@ -1,9 +1,6 @@ use crate::block_device::{BlockDevice, BLOCK_SIZE}; use crate::disk::block::Block; -use crate::disk::inode::Inode; use crate::AyaFS; -use and_then_some::BoolExt; -use log::debug; use lru::LruCache; use std::num::NonZeroUsize; use std::sync::Arc; @@ -15,12 +12,6 @@ pub struct CachedBlock<T: Block> { pub dirty: bool, } -impl<T: Block> CachedBlock<T> { - fn cast<U: Block>(&self) -> CachedBlock<U> { - unsafe { std::mem::transmute_copy(&self) } - } -} - pub fn convert_mut<U: Block, T: Block>(input_block: &mut CachedBlock<U>) -> &mut CachedBlock<T> { let ptr = input_block as *const CachedBlock<U> as *mut u8; let block = ptr.cast::<CachedBlock<T>>(); @@ -108,11 +99,13 @@ impl<T: Block> BlockCache<T> { } } + #[allow(unused)] /// 从 LRU cache 中读取一个 block 的引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. pub(crate) fn peek_block<U: Block>(&self, index: usize) -> Option<&CachedBlock<U>> { self.cache.peek(&index).map(convert::<T, U>) } + #[allow(unused)] /// 从 LRU cache 中读取一个 block 的可变引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. pub(crate) fn peek_block_mut<U: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<U>> { self.cache.peek_mut(&index).map(convert_mut::<T, U>) @@ -165,6 +158,7 @@ impl AyaFS { // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid } + #[allow(unused)] pub(crate) fn peek_block<T: Block>(&self, index: usize) -> Option<&CachedBlock<T>> { self.data_bitmap .query(index) @@ -172,6 +166,7 @@ impl AyaFS { // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid } + #[allow(unused)] pub(crate) fn peek_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> { self.data_bitmap .query(index) diff --git a/src/memory/cached_inode.rs b/src/memory/cached_inode.rs index a9c92f5..441d0fb 100644 --- a/src/memory/cached_inode.rs +++ b/src/memory/cached_inode.rs @@ -1,8 +1,14 @@ -use crate::disk::block::{DirectoryBlock, DirectoryEntry, InodeBlock}; +use std::ffi::OsStr; +use std::os::unix::ffi::OsStrExt; +use std::path::Path; +use std::slice; +use crate::disk::block::InodeBlock; use crate::disk::inode::{Inode, INODE_SIZE}; use crate::{utils, AyaFS}; use and_then_some::BoolExt; -use libc::{c_int, EISDIR, ENOENT, ENOTDIR, ENOTEMPTY}; +use fuser::FileType; +use libc::{c_int, EIO, EISDIR, ENOENT, ENOTDIR, ENOTEMPTY}; +use log::{debug, error}; impl AyaFS { pub(crate) fn create_file( @@ -20,6 +26,21 @@ impl AyaFS { }) } + pub(crate) fn create_symlink( + &mut self, + permissions: u16, + uid: u32, + gid: u32, + flags: u32, + ) -> Option<(usize, &Inode)> { + self.inode_bitmap.allocate().map(|inode_index| { + self.get_inode_mut(inode_index).map(|inode| { + *inode = Inode::symlink(permissions, uid, gid, utils::time_now(), flags, 0, 0, 0); + }); + (inode_index, self.get_inode(inode_index).unwrap()) + }) + } + /// 根目录的 parent_inode_number 传入 None, 会直接以自己作为 .. 的 inode number pub(crate) fn create_directory( &mut self, @@ -44,36 +65,6 @@ impl AyaFS { 0x2, ) .unwrap(); - - // // 分配第一个 direct block - // (new_inode.direct[0], _) = self.allocate_block_for(&mut new_inode).unwrap(); - // new_inode.size = 2; - // // 在 direct block 里分配 . 和 .. - // if let Some(directory_block) = - // self.get_block_mut::<DirectoryBlock>(new_inode.direct[0] as usize) - // { - // let dot = '.'.to_ascii_lowercase() as u8; - // // add dot entry - // directory_block.block.entries[0] = DirectoryEntry { - // inode: inode_index as u32, - // record_len: 264, - // name_len: 1, - // file_type: 0x2, - // name: [0; 256], - // }; - // directory_block.block.entries[0].name[0] = dot; - // - // // add dot dot entry - // directory_block.block.entries[1] = DirectoryEntry { - // inode: parent_inode_number.unwrap_or(inode_index as u32), - // record_len: 264, - // name_len: 2, - // file_type: 0x2, - // name: [0; 256], - // }; - // directory_block.block.entries[1].name[0] = dot; - // directory_block.block.entries[1].name[1] = dot; - // } // 把 inode 放到指定位置 self.get_inode_mut(inode_index).map(|inode| { *inode = new_inode; @@ -88,10 +79,16 @@ impl AyaFS { let (block_index, offset) = self.locate_inode(inode_index); if let Some(cached_block) = self.cached_inodes.get_block::<InodeBlock>(block_index) { let inode = cached_block.block.inodes[offset / INODE_SIZE].clone(); - if !inode.is_file() { - return Err(EISDIR); + match inode.file_type() { + FileType::RegularFile => self.deallocate_all_blocks_for(&inode).unwrap(), + FileType::Symlink => { + if inode.size >= 60 { + self.deallocate_all_blocks_for(&inode).unwrap(); + } + }, + FileType::Directory => return Err(EISDIR), + _ => return Err(EIO), } - self.deallocate_all_blocks_for(&inode).unwrap(); } self.inode_bitmap.deallocate(inode_index); Ok(true) @@ -125,27 +122,6 @@ impl AyaFS { } } - 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::<InodeBlock>(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 { if self.inode_bitmap.query(inode_index) { let (block_index, offset) = self.locate_inode(inode_index); @@ -162,6 +138,7 @@ impl AyaFS { pub(crate) fn get_inode(&mut self, inode_index: usize) -> Option<&Inode> { self.inode_bitmap.query(inode_index).and_then(|| { let (block_index, offset) = self.locate_inode(inode_index); + // debug!("get_inode(inode_index: {}) -> block_index: {}, offset: {}", inode_index, block_index, offset); self.cached_inodes .get_block::<InodeBlock>(block_index) .map(|cached_block| &cached_block.block.inodes[offset / INODE_SIZE]) @@ -171,6 +148,7 @@ impl AyaFS { pub(crate) fn get_inode_mut(&mut self, inode_index: usize) -> Option<&mut Inode> { self.inode_bitmap.query(inode_index).and_then(|| { let (block_index, offset) = self.locate_inode(inode_index); + // debug!("get_inode_mut(inode_index: {}) -> block_index: {}, offset: {}", inode_index, block_index, offset); self.cached_inodes .get_block_mut::<InodeBlock>(block_index) .map(|cached_block| { @@ -180,6 +158,7 @@ impl AyaFS { }) } + #[allow(unused)] pub(crate) fn peek_inode(&self, inode_index: usize) -> Option<&Inode> { self.inode_bitmap.query(inode_index).and_then(|| { let (block_index, offset) = self.locate_inode(inode_index); @@ -189,6 +168,7 @@ impl AyaFS { }) } + #[allow(unused)] pub(crate) fn peek_inode_mut(&mut self, inode_index: usize) -> Option<&mut Inode> { self.inode_bitmap.query(inode_index).and_then(|| { let (block_index, offset) = self.locate_inode(inode_index); diff --git a/src/memory/dir_entry.rs b/src/memory/dir_entry.rs index 08a82c5..5e030d3 100644 --- a/src/memory/dir_entry.rs +++ b/src/memory/dir_entry.rs @@ -88,6 +88,7 @@ impl AyaFS { } match self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode) { Some(directory_block) => { + directory_block.block.allocate(entry_index_within_block); directory_block.block.entries[entry_index_within_block] = dir_entry; } None => { @@ -104,7 +105,7 @@ impl AyaFS { parent_index: usize, parent_inode: &mut Inode, name: &OsStr, - entry_index: u32, + _entry_index: u32, ) -> Result<(), c_int> { self.load_direntry_map(parent_index, parent_inode)?; if let Some(dir_entry_map) = self.dir_entry_map.get_mut(&parent_index) { @@ -116,22 +117,6 @@ impl AyaFS { } } else { Err(ENOENT) - // let block_index_within_inode = (entry_index / 15) as usize; - // let entry_index_within_block = (entry_index % 15) as usize; - // - // match self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode) { - // 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(); - // Ok(()) - // } else { - // Err(ENOENT) - // } - // } - // None => Err(ENOENT), - // } } } @@ -169,41 +154,6 @@ impl AyaFS { } else { Err(ENOENT) } - // // 找到第一个有空闲 DirEntry 的块, 从中分配一个 entry - // let mut block_index_within_inode: usize = 0; - // loop { - // // 所有已经分配的块都用完, 需要额外分配一个块了 - // if block_index_within_inode as u32 == parent_inode.n_blocks { - // if self.allocate_block_for(parent_inode).is_none() { - // return Err(ENOSPC); - // } - // } - // // 寻找当前块里有没有空闲空间 - // if let Some(directory_block) = - // self.access_block_mut::<DirectoryBlock>(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; - // let mut name = [0u8; 256]; - // (&mut name[0..name_len as usize]) - // .copy_from_slice(child_inode_name.as_bytes()); - // - // let dir_entry = DirectoryEntry { - // inode: child_inode_index as u32, - // record_len: 264, - // name_len, - // file_type, - // name, - // }; - // directory_block.block.entries[entry_index_within_block] = dir_entry; - // let entry_index = block_index_within_inode * 15 + entry_index_within_block; - // parent_inode.size += 1; - // return Ok(entry_index as u32); - // } - // } - // block_index_within_inode += 1; - // } } pub(crate) fn get_direntry( &mut self, @@ -225,23 +175,9 @@ impl AyaFS { .ok_or(ENOENT) } else { Err(ENOENT) - // let block_index_within_inode = (entry_index / 15) as usize; - // let entry_index_within_block = (entry_index % 15) as usize; - // - // match self.access_block::<DirectoryBlock>(parent_inode, block_index_within_inode) { - // Some(directory_block) => { - // if directory_block.block.query(entry_index_within_block) { - // Ok(directory_block.block.entries[entry_index_within_block].clone()) - // } else { - // Err(ENOENT) - // } - // } - // None => Err(ENOENT), - // } } } - // TODO 实现一个带 cache 的版本 /// 返回 inode_index, inode 在 parent 里的 index, inode 本身 pub fn lookup_name( &mut self, diff --git a/src/memory/file_handle.rs b/src/memory/file_handle.rs index 0da2ed2..c821619 100644 --- a/src/memory/file_handle.rs +++ b/src/memory/file_handle.rs @@ -12,8 +12,4 @@ impl AyaFS { self.file_handle_map.insert(fd, (inode_index, read, write)); fd } - - pub(crate) fn get_inode_from_fd(&self, file_descriptor: u64) -> Option<(usize, bool, bool)> { - self.file_handle_map.get(&file_descriptor).copied() - } } diff --git a/src/tests/common/mod.rs b/src/tests/common/mod.rs index 9314fd9..3abfcb4 100644 --- a/src/tests/common/mod.rs +++ b/src/tests/common/mod.rs @@ -2,6 +2,7 @@ use crate::block_device::memory_disk::MemoryDisk; use crate::AyaFS; use std::sync::Arc; +#[allow(unused)] pub(crate) fn setup() -> AyaFS { let mem_disk = Arc::new(MemoryDisk::new(1059715)); AyaFS::new(mem_disk, 1059715) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 0a9b825..468ebdb 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -21,26 +21,6 @@ pub(crate) fn from_systime(system_time: SystemTime) -> u32 { .as_secs() as u32 } -pub(crate) fn make_fileattr(inode_index: usize, inode: &Inode) -> FileAttr { - FileAttr { - ino: inode_index as u64, - size: inode.size as u64, - blocks: inode.n_blocks as u64, - atime: to_systime(inode.atime), - mtime: to_systime(inode.atime), - ctime: to_systime(inode.ctime), - crtime: 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, - } -} - pub(crate) fn to_systime(time: u32) -> SystemTime { UNIX_EPOCH + Duration::from_secs(time as u64) } diff --git a/src/utils/permissions.rs b/src/utils/permissions.rs index b1ec999..6773511 100644 --- a/src/utils/permissions.rs +++ b/src/utils/permissions.rs @@ -33,14 +33,14 @@ pub(crate) fn check_access( incoming_gid: u32, uid: u32, gid: u32, - perm: InodeMode, + mode: InodeMode, mut mask: i32, ) -> bool { if mask == F_OK { return true; } - let perm = i32::from(perm.0); + let perm = i32::from(mode.0); // root if incoming_uid == 0 { // 读写任何东西都是可以的, 执行只有 IXOTH/IXGRP/IXUSR 之一设置才可以 |