summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/disk/allocation.rs14
-rw-r--r--src/disk/block.rs63
-rw-r--r--src/disk/inode.rs42
-rw-r--r--src/filesystem/trait_impl.rs258
-rw-r--r--src/memory/cached_block.rs13
-rw-r--r--src/memory/cached_inode.rs92
-rw-r--r--src/memory/dir_entry.rs68
-rw-r--r--src/memory/file_handle.rs4
-rw-r--r--src/tests/common/mod.rs1
-rw-r--r--src/utils/mod.rs20
-rw-r--r--src/utils/permissions.rs4
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 之一设置才可以