summaryrefslogtreecommitdiff
path: root/src/filesystem
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-11-23 02:11:16 -0800
committerChuyan Zhang <me@zcy.moe>2023-11-23 02:11:16 -0800
commitb8afa7cfb02b32278e268924e189170496f81c1b (patch)
tree449d5ae3342e259d66fcb338217e29479f906046 /src/filesystem
parent3f2151c043177501b0c7beb580d9737e3d824ad0 (diff)
downloadmyfs-b8afa7cfb02b32278e268924e189170496f81c1b.tar.gz
myfs-b8afa7cfb02b32278e268924e189170496f81c1b.zip
Add some callback (not finished)
Diffstat (limited to 'src/filesystem')
-rw-r--r--src/filesystem/trait_impl.rs271
1 files changed, 210 insertions, 61 deletions
diff --git a/src/filesystem/trait_impl.rs b/src/filesystem/trait_impl.rs
index 3a60578..a25a383 100644
--- a/src/filesystem/trait_impl.rs
+++ b/src/filesystem/trait_impl.rs
@@ -1,12 +1,17 @@
-use crate::AyaFS;
+use crate::block_device::BLOCK_SIZE;
+use crate::disk::inode::InodeMode;
+use crate::utils::make_fileattr;
+use crate::{utils, AyaFS, TTL};
use fuser::{
- Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry,
- ReplyLseek, ReplyWrite, Request, TimeOrNow,
+ FileAttr, FileType, Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty,
+ ReplyEntry, ReplyLseek, ReplyWrite, Request, TimeOrNow,
};
-use libc::{c_int, ENOENT, ENOSPC, ENOSYS};
+use libc::{c_int, ENAMETOOLONG, ENOENT, ENOSPC, ENOSYS, ENOTDIR};
use log::debug;
use std::ffi::OsStr;
+use std::os::unix::ffi::OsStrExt;
use std::time::SystemTime;
+use users::{get_current_gid, get_current_uid};
impl Filesystem for AyaFS {
fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> {
@@ -19,11 +24,6 @@ impl Filesystem for AyaFS {
}
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
- debug!(
- "Filesystem::lookup called with parent {} name {}",
- parent,
- name.to_str().unwrap()
- );
let parent = parent as usize;
if let Some(inode) = self.get_inode(parent) {
// debug!("{:?}", inode);
@@ -43,11 +43,28 @@ impl Filesystem for AyaFS {
fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) {
debug!("Filesystem::getattr(ino: {})", ino);
- let ino = ino as usize;
- if let Some(inode) = self.get_inode(ino) {
- // debug!("{:?}", inode);
+ if let Some(inode) = self.get_inode(ino as usize) {
+ let attr = FileAttr {
+ ino,
+ size: inode.size as u64,
+ blocks: inode.n_blocks as u64,
+ atime: utils::to_systime(inode.atime),
+ mtime: utils::to_systime(inode.mtime),
+ ctime: utils::to_systime(inode.ctime),
+ crtime: utils::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,
+ };
+ reply.attr(&TTL, &attr);
+ } else {
+ reply.error(ENOENT);
}
- reply.error(ENOENT);
}
fn setattr(
@@ -57,23 +74,92 @@ impl Filesystem for AyaFS {
mode: Option<u32>,
uid: Option<u32>,
gid: Option<u32>,
- size: Option<u64>,
- _atime: Option<TimeOrNow>,
- _mtime: Option<TimeOrNow>,
- _ctime: Option<SystemTime>,
+ size: Option<u64>, // TODO 为什么 setattr 还可以设置 size??
+ atime: Option<TimeOrNow>,
+ mtime: Option<TimeOrNow>,
+ ctime: Option<SystemTime>,
fh: Option<u64>,
- _crtime: Option<SystemTime>,
+ crtime: Option<SystemTime>,
_chgtime: Option<SystemTime>,
_bkuptime: Option<SystemTime>,
flags: Option<u32>,
reply: ReplyAttr,
) {
- debug!(
- "Filesystem::setattr(ino: {:#x?}, mode: {:?}, uid: {:?}, \
- gid: {:?}, size: {:?}, fh: {:?}, flags: {:?})",
- ino, mode, uid, gid, size, fh, flags
- );
- reply.error(ENOSYS);
+ if let Some(inode) = self.get_inode_mut(ino as usize) {
+ let mode = mode
+ .and_then(|mode_value| {
+ InodeMode::validate(mode_value as u16) // high 16 bit truncated
+ })
+ .unwrap_or(inode.mode);
+ inode.mode = mode;
+ // 如果传入的 InodeMode 是合法结果, 那么得到 Some(mode), 否则 None
+ // 需要检查权限吗? 如果需要, 如何知道 invoke 这个 callback 的 UID/GID?
+
+ let size = size.unwrap_or(inode.size as u64);
+ inode.size = size as u32;
+ // TODO 为什么可以设置 size 呢……
+
+ let uid = uid.unwrap_or(inode.uid);
+ let gid = gid.unwrap_or(inode.gid);
+ inode.uid = uid;
+ inode.gid = gid;
+
+ let (atime, atime_inner) = atime
+ .map(|atime| {
+ let system_time = match atime {
+ TimeOrNow::SpecificTime(system_time) => system_time,
+ TimeOrNow::Now => SystemTime::now(),
+ };
+ (system_time, utils::from_systime(system_time))
+ })
+ .unwrap_or((utils::to_systime(inode.atime), inode.atime));
+ inode.atime = atime_inner;
+
+ let (mtime, mtime_inner) = mtime
+ .map(|mtime| {
+ let system_time = match mtime {
+ TimeOrNow::SpecificTime(system_time) => system_time,
+ TimeOrNow::Now => SystemTime::now(),
+ };
+ (system_time, utils::from_systime(system_time))
+ })
+ .unwrap_or((utils::to_systime(inode.mtime), inode.mtime));
+ inode.mtime = mtime_inner;
+
+ let (ctime, ctime_inner) = ctime
+ .map(|ctime| (ctime, utils::from_systime(ctime)))
+ .unwrap_or((utils::to_systime(inode.ctime), inode.ctime));
+ inode.ctime = ctime_inner;
+
+ let (crtime, crtime_inner) = crtime
+ .map(|crtime| (crtime, utils::from_systime(crtime)))
+ .unwrap_or((utils::to_systime(inode.crtime), inode.crtime));
+ inode.crtime = crtime_inner;
+
+ let flags = flags.unwrap_or(inode.flags);
+ inode.flags = flags;
+
+ let attr = FileAttr {
+ ino,
+ size,
+ blocks: inode.n_blocks as u64,
+ atime,
+ mtime,
+ ctime,
+ crtime,
+ kind: mode.into(),
+ perm: mode.perm(),
+ nlink: inode.n_links as u32,
+ uid,
+ gid,
+ rdev: 0,
+ blksize: BLOCK_SIZE as u32,
+ flags,
+ };
+ reply.attr(&TTL, &attr);
+ } else {
+ reply.error(ENOSYS);
+ }
}
fn readlink(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyData) {
@@ -87,15 +173,46 @@ impl Filesystem for AyaFS {
parent: u64,
name: &OsStr,
mode: u32,
- umask: u32,
- rdev: u32,
+ _umask: u32, // umask 是用不到的
+ _rdev: u32, // the device number (only valid if created file is a device)
reply: ReplyEntry,
) {
debug!(
- "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {}, rdev: {})",
- parent, name, mode, umask, rdev
+ "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {})",
+ parent, name, mode, _umask
);
- reply.error(ENOSPC);
+ if let Some(inode) = self.get_inode(parent as usize) {
+ if inode.is_dir() {
+ let name = name.as_bytes();
+ if name.len() <= 255 {
+ let permissions = (mode & 0o777) as u16;
+ if let Some(inode_index) = self.create_inode(
+ permissions,
+ InodeMode::IFREG,
+ get_current_uid(),
+ get_current_gid(),
+ 0,
+ ) {
+ let inode = self.get_inode(inode_index).unwrap();
+ let file_attr = make_fileattr(inode_index, inode);
+ // TODO 把 inode 挂到 parent 下
+ reply.entry(&TTL, &file_attr, 0);
+ } else {
+ // create_inode 失败 -> no enough space
+ reply.error(ENOSPC);
+ }
+ } else {
+ // name 长度超过 255 -> File name too long
+ reply.error(ENAMETOOLONG);
+ }
+ } else {
+ // parent 不是 IFDIR -> Not a directory
+ reply.error(ENOTDIR);
+ }
+ } else {
+ // parent 不存在 -> No such file or directory
+ reply.error(ENOENT);
+ }
}
fn mkdir(
@@ -104,18 +221,54 @@ impl Filesystem for AyaFS {
parent: u64,
name: &OsStr,
mode: u32,
- umask: u32,
+ _umask: u32, // umask 应该也是用不到的
reply: ReplyEntry,
) {
+ if let Some(inode) = self.get_inode(parent as usize) {
+ if inode.is_dir() {
+ let name = name.as_bytes();
+ if name.len() <= 255 {
+ let permissions = (mode & 0o777) as u16;
+ if let Some(inode_index) = self.create_inode(
+ permissions,
+ InodeMode::IFDIR,
+ get_current_uid(),
+ get_current_gid(),
+ 0,
+ ) {
+ let inode = self.get_inode(inode_index).unwrap();
+ let file_attr = make_fileattr(inode_index, inode);
+ // TODO 把 inode 挂到 parent 下
+ reply.entry(&TTL, &file_attr, 0);
+ } else {
+ // create_inode 失败 -> no enough space
+ reply.error(ENOSPC);
+ }
+ } else {
+ // name 长度超过 255 -> File name too long
+ reply.error(ENAMETOOLONG);
+ }
+ } else {
+ // parent 不是 IFDIR -> Not a directory
+ reply.error(ENOTDIR);
+ }
+ } else {
+ // parent 不存在 -> No such file or directory
+ reply.error(ENOENT);
+ }
+ }
+
+ fn unlink(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) {
debug!(
- "Filesystem::mkdir(parent: {}, name: {:?}, mode: {}, umask: {})",
- parent, name, mode, umask
+ "unlink(parent: {:#x?}, name: {:?})",
+ parent, name,
);
- if let Some(inode) = self.get_inode(parent as usize) {
+ if let Some(inode) = self.get_inode_mut(parent as usize) {
+ // TODO 找到这个 inode 并且删掉
+ reply.ok();
} else {
reply.error(ENOENT);
}
- // reply.error(ENOSPC);
}
fn read(
@@ -140,7 +293,29 @@ impl Filesystem for AyaFS {
offset: i64,
mut reply: ReplyDirectory,
) {
- todo!()
+ if let Some(inode) = self.get_inode(ino as usize) {
+ } else {
+ reply.error(ENOENT);
+ }
+
+ // if ino != 1 {
+ // reply.error(ENOENT);
+ // return;
+ // }
+ //
+ // let entries = vec![
+ // (1, FileType::Directory, "."),
+ // (1, FileType::Directory, ".."),
+ // (2, FileType::RegularFile, "hello.txt"),
+ // ];
+ //
+ // for (i, entry) in entries.into_iter().enumerate().skip(offset as usize) {
+ // // i + 1 means the index of the next entry
+ // if reply.add(entry.0, (i + 1) as i64, entry.1, entry.2) {
+ // break;
+ // }
+ // }
+ // reply.ok();
}
fn access(&mut self, _req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) {
@@ -161,32 +336,6 @@ impl Filesystem for AyaFS {
whence: i32,
reply: ReplyLseek,
) {
- debug!(
- "lseek(ino: {:#x?}, fh: {}, offset: {}, whence: {})",
- ino, fh, offset, whence
- );
- reply.error(ENOSYS);
- }
-
- fn copy_file_range(
- &mut self,
- _req: &Request<'_>,
- ino_in: u64,
- fh_in: u64,
- offset_in: i64,
- ino_out: u64,
- fh_out: u64,
- offset_out: i64,
- len: u64,
- flags: u32,
- reply: ReplyWrite,
- ) {
- debug!(
- "copy_file_range(ino_in: {:#x?}, fh_in: {}, \
- offset_in: {}, ino_out: {:#x?}, fh_out: {}, offset_out: {}, \
- len: {}, flags: {})",
- ino_in, fh_in, offset_in, ino_out, fh_out, offset_out, len, flags
- );
reply.error(ENOSYS);
}
}