summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-11-27 02:24:52 -0800
committerChuyan Zhang <me@zcy.moe>2023-11-27 02:24:52 -0800
commit51118228f978f8dde956016f4cf3f169d9e21f20 (patch)
tree404027869d0373c34c8a3f9f8c7326df2e9a0c2d
parentec2f349a648e4d87fba12d20e338b1cd6d8ef29a (diff)
downloadmyfs-51118228f978f8dde956016f4cf3f169d9e21f20.tar.gz
myfs-51118228f978f8dde956016f4cf3f169d9e21f20.zip
Implemented read
-rw-r--r--src/filesystem/trait_impl.rs176
1 files changed, 135 insertions, 41 deletions
diff --git a/src/filesystem/trait_impl.rs b/src/filesystem/trait_impl.rs
index 5353f6e..2a49eeb 100644
--- a/src/filesystem/trait_impl.rs
+++ b/src/filesystem/trait_impl.rs
@@ -8,14 +8,12 @@ use fuser::{
Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry,
ReplyLseek, ReplyOpen, ReplyWrite, Request, TimeOrNow,
};
-use libc::{
- c_int, EACCES, EBADF, EEXIST, EINVAL, 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 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 log::debug;
use std::ffi::OsStr;
use std::time::SystemTime;
+use crate::block_device::BLOCK_SIZE;
+use crate::disk::block::DataBlock;
impl AyaFS {}
@@ -537,22 +535,116 @@ impl Filesystem for AyaFS {
}
}
- fn open(&mut self, _req: &Request<'_>, _ino: u64, _flags: i32, reply: ReplyOpen) {
- todo!()
+ fn open(&mut self, req: &Request<'_>, ino: u64, flags: i32, reply: ReplyOpen) {
+ debug!("open(ino: {:#x?}, flags: {:#x?})", ino, flags);
+ let (access_mask, read, write) = match flags & O_ACCMODE {
+ O_RDONLY => {
+ // Behavior is undefined, but most filesystems return EACCES
+ if flags & libc::O_TRUNC != 0 {
+ reply.error(libc::EACCES);
+ return;
+ }
+ (R_OK, true, false)
+ }
+ O_WRONLY => (W_OK, false, true),
+ O_RDWR => (R_OK | W_OK, true, true),
+ _ => {
+ // flag 非法
+ reply.error(EINVAL);
+ return;
+ }
+ };
+
+ match self.get_inode(ino as usize) {
+ Some(inode) => {
+ if !check_access(
+ req.uid(),
+ req.gid(),
+ inode.uid,
+ inode.gid,
+ inode.mode,
+ access_mask,
+ ) {
+ reply.error(EACCES);
+ return;
+ }
+ let fd = self.allocate_file_descriptor(ino as usize, read, write);
+ reply.opened(fd, 0);
+ }
+ None => {
+ reply.error(ENOENT);
+ }
+ }
}
+ // read [offset, offset + size)
+ // - EOF < offset + size -> return EOF - offset
+ // - EOF > offset + size -> return size
fn read(
&mut self,
- _req: &Request<'_>,
+ req: &Request<'_>,
ino: u64,
- _fh: u64,
+ fh: u64,
offset: i64,
- _size: u32,
+ size: u32,
_flags: i32,
- _lock_owner: Option<u64>,
+ _lock_owner: Option<u64>, // 用不到!
reply: ReplyData,
) {
- todo!()
+ assert_eq!(self.file_handle_map.get(&fh).unwrap().0, ino as usize);
+ if let Some(inode) = self.get_inode(ino as usize) {
+ if inode.is_dir() {
+ reply.error(EISDIR);
+ return;
+ }
+ if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, R_OK) {
+ reply.error(EACCES);
+ return;
+ }
+ debug!("reading inode {:#x} (offset {} size {})", ino, offset, size);
+
+ if offset as u32 >= inode.size {
+ // offset 在 EOF 后面, 直接返回一个 0 长度的空 buffer
+ reply.data(&Vec::new());
+ return;
+ }
+
+ // let read_length = size.min(inode.size.saturating_sub(offset as u32)) as usize;
+ // 这和下面那个是等同的但是不利于让人看懂……
+ let read_length = if offset as u32 + size <= inode.size {
+ size // 没有越过 EOF, 读取 size 个 byte
+ } else {
+ inode.size - offset as u32 // 越过了 EOF, 读取 inode.size - offset 个 byte
+ } as usize;
+
+ let mut read_buffer = vec![0u8; read_length];
+ let mut read_ptr = 0usize;
+
+ let inode = inode.clone();
+
+ while read_ptr < read_length {
+ let current_point = offset as usize + read_ptr;
+ let current_block_index = current_point / BLOCK_SIZE;
+ let current_offset = current_point % BLOCK_SIZE;
+
+ let read_length_within_block = if BLOCK_SIZE - current_offset < read_length - read_ptr {
+ BLOCK_SIZE - current_offset // 可以读到 block 最后
+ } else {
+ read_length - read_ptr // 读到中途会停下来
+ };
+
+ if let Some(block) = self.access_block::<DataBlock>(&inode, current_block_index) {
+ (&mut read_buffer[read_ptr .. read_ptr + read_length_within_block])
+ .copy_from_slice(&block.block.0[current_offset .. current_offset + read_length_within_block]);
+ read_ptr += read_length_within_block;
+ } else {
+ reply.error(EIO);
+ return;
+ }
+ }
+
+ reply.data(&read_buffer);
+ }
}
fn write(
@@ -635,38 +727,40 @@ impl Filesystem for AyaFS {
) {
assert_eq!(self.file_handle_map.get(&fh).unwrap().0, ino as usize);
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) {
- debug!("reading dir entries from inode {:#x} with offset {}", ino, offset);
- let inode = inode.clone();
-
- self.load_direntry_map(ino as usize, &inode).unwrap();
- for (entry_index, (name, dir_entry)) in self
- .dir_entry_map
- .get(&(ino as usize))
- .unwrap()
- .iter()
- .enumerate()
- .skip(offset as usize)
- {
- debug!(" entry {} from inode {:#x} with name {:?}", entry_index, dir_entry.inode, name);
- if reply.add(
- dir_entry.inode as u64,
- entry_index as i64 + 1,
- to_filetype(dir_entry.file_type).expect("not 0x0!"),
- name
- ) {
- break;
- }
- }
+ if !inode.is_dir() {
+ reply.error(ENOTDIR);
+ return;
+ }
- reply.ok();
- } else {
- reply.error(EACCES);
+ if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, R_OK) {
+ reply.error(EACCES);
+ return;
+ }
+
+ debug!("reading dir entries from inode {:#x} with offset {}", ino, offset);
+ let inode = inode.clone();
+
+ self.load_direntry_map(ino as usize, &inode).unwrap();
+ for (entry_index, (name, dir_entry)) in self
+ .dir_entry_map
+ .get(&(ino as usize))
+ .unwrap()
+ .iter()
+ .enumerate()
+ .skip(offset as usize)
+ {
+ debug!(" entry {} from inode {:#x} with name {:?}", entry_index, dir_entry.inode, name);
+ if reply.add(
+ dir_entry.inode as u64,
+ entry_index as i64 + 1,
+ to_filetype(dir_entry.file_type).expect("not 0x0!"),
+ name
+ ) {
+ break;
}
- } else {
- reply.error(ENOTDIR);
}
+
+ reply.ok();
} else {
reply.error(ENOENT);
}