From 51118228f978f8dde956016f4cf3f169d9e21f20 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Mon, 27 Nov 2023 02:24:52 -0800 Subject: Implemented read --- src/filesystem/trait_impl.rs | 176 +++++++++++++++++++++++++++++++++---------- 1 file changed, 135 insertions(+), 41 deletions(-) (limited to 'src') 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, + _lock_owner: Option, // 用不到! 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::(&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); } -- cgit v1.2.3-70-g09d2