summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-11-26 02:33:01 -0800
committerChuyan Zhang <me@zcy.moe>2023-11-26 02:33:01 -0800
commit9d1368b0ea380a9446b4697af668d1685464b6c7 (patch)
tree2103af418264cc70addc9cfc6ed7acac640f5151 /src
parent777d5e01a34b8ebe6f1a5751b593266f93e88499 (diff)
downloadmyfs-9d1368b0ea380a9446b4697af668d1685464b6c7.tar.gz
myfs-9d1368b0ea380a9446b4697af668d1685464b6c7.zip
more code idk what they are im so tired ohno
Diffstat (limited to 'src')
-rw-r--r--src/disk/allocation.rs164
-rw-r--r--src/disk/block.rs9
-rw-r--r--src/disk/inode.rs26
-rw-r--r--src/filesystem/trait_impl.rs347
-rw-r--r--src/main.rs2
-rw-r--r--src/memory/cached_block.rs53
-rw-r--r--src/memory/cached_inode.rs87
-rw-r--r--src/memory/dir_entry.rs40
-rw-r--r--src/utils/permissions.rs6
9 files changed, 528 insertions, 206 deletions
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::<IndirectBlock>(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::<DoubleIndirectBlock>(inode.double_indirect as usize)
+ .unwrap();
+ for indirect_block_index in double_indirect.block.indirect {
+ if let Some(indirect) =
+ self.get_block::<IndirectBlock>(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::<TripleIndirectBlock>(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::<DoubleIndirectBlock>(double_indirect_block_index as usize)
+ {
+ for indirect_block_index in double_indirect.block.indirect {
+ if let Some(indirect) =
+ self.get_block::<IndirectBlock>(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<u32> {
// 如果 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<usize> {
+ fn get_block_index(
+ &mut self,
+ inode: &Inode,
+ mut block_index_within_inode: usize,
+ ) -> Option<usize> {
// 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::<IndirectBlock>(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<T: Block>(&mut self, inode: &Inode, block_index_within_inode: usize) -> Option<&CachedBlock<T>> {
+ pub(crate) fn access_block<T: Block>(
+ &mut self,
+ inode: &Inode,
+ block_index_within_inode: usize,
+ ) -> Option<&CachedBlock<T>> {
self.get_block_index(inode, block_index_within_inode)
.map(|block_index| {
self.get_block::<T>(block_index).unwrap() // 可以 unwrap 吧这里 ??
})
}
- pub(crate) fn access_block_mut<T: Block>(&mut self, inode: &Inode, block_index_within_inode: usize) -> Option<&mut CachedBlock<T>> {
+ pub(crate) fn access_block_mut<T: Block>(
+ &mut self,
+ inode: &Inode,
+ block_index_within_inode: usize,
+ ) -> Option<&mut CachedBlock<T>> {
self.get_block_index(inode, block_index_within_inode)
.map(|block_index| {
self.get_block_mut::<T>(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<InodeMode> 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::<Inode>();
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<T: Block> BlockCache<T> {
if !self.cache.contains(&index) {
self.load_block(index);
}
- self.cache.get(&index).map(convert::<T,U>)
+ self.cache.get(&index).map(convert::<T, U>)
}
/// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载.
@@ -90,6 +90,24 @@ impl<T: Block> BlockCache<T> {
})
}
+ /// 向 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<U: Block>(&self, index: usize) -> Option<&CachedBlock<U>> {
self.cache.peek(&index).map(convert::<T, U>)
@@ -117,26 +135,33 @@ impl<T: Block> BlockCache<T> {
}
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<T: Block>(&mut self, index: usize) -> Option<&CachedBlock<T>> {
- self.data_bitmap
- .query(index)
- .then(|| self.cached_blocks.get_block::<T>(index).unwrap())
+ if self.data_bitmap.query(index) {
+ Some(self.cached_blocks.get_block::<T>(index).unwrap())
+ } else {
+ self.cached_blocks.pop(&index);
+ None
+ }
+ // self.data_bitmap
+ // .query(index)
+ // .then(|| self.cached_blocks.get_block::<T>(index).unwrap())
// 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid
}
pub(crate) fn get_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> {
- self.data_bitmap
- .query(index)
- .then(|| self.cached_blocks.get_block_mut::<T>(index).unwrap())
+ if self.data_bitmap.query(index) {
+ Some(self.cached_blocks.get_block_mut::<T>(index).unwrap())
+ } else {
+ self.cached_blocks.pop(&index);
+ None
+ }
+ // self.data_bitmap
+ // .query(index)
+ // .then(|| self.cached_blocks.get_block_mut::<T>(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<u32>,
) -> 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<bool, c_int> {
+ 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() {
+ 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<bool, c_int> {
+ 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_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<usize> {
- 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::<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 {
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<u32, c_int> {
@@ -45,7 +52,9 @@ impl AyaFS {
}
}
// 寻找当前块里有没有空闲空间
- if let Some(directory_block) = self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode) {
+ 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;
@@ -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<DirectoryEntry> {
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<u32> {
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
+}