From b8afa7cfb02b32278e268924e189170496f81c1b Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Thu, 23 Nov 2023 02:11:16 -0800 Subject: Add some callback (not finished) --- src/disk/allocation.rs | 16 +-- src/disk/inode.rs | 71 ++++++++++-- src/filesystem/trait_impl.rs | 271 +++++++++++++++++++++++++++++++++---------- src/main.rs | 7 -- src/memory/cached_block.rs | 16 +-- src/memory/cached_inode.rs | 10 +- src/tests/block_cache.rs | 117 ++++++++++++++----- src/utils/mod.rs | 49 ++++++-- 8 files changed, 425 insertions(+), 132 deletions(-) (limited to 'src') diff --git a/src/disk/allocation.rs b/src/disk/allocation.rs index bfdba46..5643dd3 100644 --- a/src/disk/allocation.rs +++ b/src/disk/allocation.rs @@ -194,11 +194,8 @@ impl AyaFS { { let mut triple_indirect_block = triple_indirect_block.clone(); let mut block_modified = false; - for double_indirect_entry in triple_indirect_block - .block - .double_indirect - .iter_mut() - .rev() + for double_indirect_entry in + triple_indirect_block.block.double_indirect.iter_mut().rev() { // 如果这个位置的 double indirect 存在 if self.data_bitmap.query(*double_indirect_entry as usize) { @@ -212,8 +209,10 @@ impl AyaFS { return Some(block_index); // 成功则直接返回 } else { // 失败则把这个 double indirect 销毁 - let double_indirect_entry_to_deallocate = std::mem::replace(double_indirect_entry, 0); - self.data_bitmap.deallocate(double_indirect_entry_to_deallocate as usize); + let double_indirect_entry_to_deallocate = + std::mem::replace(double_indirect_entry, 0); + self.data_bitmap + .deallocate(double_indirect_entry_to_deallocate as usize); triple_indirect_block.dirty = true; block_modified = true; } @@ -246,7 +245,8 @@ impl AyaFS { } else { // 失败则把这个 indirect 销毁 let indirect_entry_to_deallocate = std::mem::replace(indirect_entry, 0); - self.data_bitmap.deallocate(indirect_entry_to_deallocate as usize); + self.data_bitmap + .deallocate(indirect_entry_to_deallocate as usize); double_indirect_block.dirty = true; block_modified = true; } diff --git a/src/disk/inode.rs b/src/disk/inode.rs index 48085d8..1095aca 100644 --- a/src/disk/inode.rs +++ b/src/disk/inode.rs @@ -1,4 +1,6 @@ use bitflags::bitflags; +use fuser::{FileAttr, FileType}; +use std::fs::File; const DIRECT_NUMBER: usize = 15; @@ -30,6 +32,43 @@ bitflags! { } } +impl InodeMode { + pub(crate) fn perm(&self) -> u16 { + self.0 & 0x0FFF + } + + pub(crate) fn is_file(&self) -> bool { + (self.0 & 0xF000) == Self::IFREG.0 + } + + pub(crate) fn is_dir(&self) -> bool { + (self.0 & 0xF000) == Self::IFDIR.0 + } + + pub(crate) fn validate(mode_value: u16) -> Option { + let valid_flags: [u16; 7] = [0x1000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000]; + valid_flags + .contains(&(mode_value & 0xF000)) + .then(|| Self(mode_value)) + } +} + +impl From for FileType { + fn from(value: InodeMode) -> Self { + let type_flag = value.0 & 0xF000; + match type_flag { + 0x1000 => FileType::NamedPipe, + 0x2000 => FileType::CharDevice, + 0x4000 => FileType::Directory, + 0x6000 => FileType::BlockDevice, + 0x8000 => FileType::RegularFile, + 0xA000 => FileType::Symlink, + 0xC000 => FileType::Socket, + _ => panic!("Invalid inode mode {:x}", type_flag), + } + } +} + /// Pretty much the same with ext2, with minor changes: /// - removed OS dependent attributes (osd1 & osd2) /// - removed i_faddr since fragmentation is not supported @@ -39,24 +78,24 @@ bitflags! { #[repr(C)] #[derive(Debug, Clone)] pub struct Inode { - mode: InodeMode, - uid: u32, - size: u32, - atime: u32, // access time, in seconds - ctime: u32, // change time, in seconds - mtime: u32, // modify time, in seconds - crtime: u32, // create time, in seconds - gid: u32, + pub mode: InodeMode, + pub uid: u32, + pub size: u32, + pub atime: u32, // access time, in seconds + pub ctime: u32, // change time, in seconds + pub mtime: u32, // modify time, in seconds + pub crtime: u32, // create time, in seconds + pub gid: u32, pub n_links: u16, pub n_blocks: u32, - flags: u32, // TODO: do we actually need this? maybe just return 0 + pub flags: u32, // TODO: do we actually need this? maybe just return 0 pub direct: [u32; DIRECT_NUMBER], pub single_indirect: u32, pub double_indirect: u32, pub triple_indirect: u32, - generation: u32, - file_acl: u32, - dir_acl: u32, // TODO do we have to implement ACL......? + pub generation: u32, + pub file_acl: u32, + pub dir_acl: u32, // TODO do we have to implement ACL......? } impl Inode { @@ -159,6 +198,14 @@ impl Inode { ) } + pub(crate) fn is_file(&self) -> bool { + self.mode.is_file() + } + + pub(crate) fn is_dir(&self) -> bool { + self.mode.is_dir() + } + pub fn empty() -> Self { Self::new(InodeMode(0), 0, 0, 0, 0, 0, 0, 0) } 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, uid: Option, gid: Option, - size: Option, - _atime: Option, - _mtime: Option, - _ctime: Option, + size: Option, // TODO 为什么 setattr 还可以设置 size?? + atime: Option, + mtime: Option, + ctime: Option, fh: Option, - _crtime: Option, + crtime: Option, _chgtime: Option, _bkuptime: Option, flags: Option, 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); } } diff --git a/src/main.rs b/src/main.rs index a5ec616..2df0a10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,6 @@ mod utils; use clap::Parser; use fuser::MountOption; use log::debug; -use lru::LruCache; -use std::num::NonZeroUsize; use std::sync::Arc; use std::time::Duration; @@ -20,7 +18,6 @@ use block_device::{memory_disk::MemoryDisk, BlockDevice, BLOCK_SIZE}; use disk::bitmap::Bitmap; use disk::block::DataBlock; use disk::inode::INODE_SIZE; -use memory::cached_block::CachedBlock; use users::{get_current_gid, get_current_uid}; #[derive(Parser, Debug)] @@ -66,8 +63,6 @@ struct AyaFS { cached_inodes: BlockCache, cached_blocks: BlockCache, - // cached_inodes: LruCache>, - // cached_blocks: LruCache>, } impl AyaFS { @@ -118,8 +113,6 @@ impl AyaFS { + 1, cached_inodes: BlockCache::new(device.clone(), 256), cached_blocks: BlockCache::new(device.clone(), 256), - // cached_inodes: LruCache::new(NonZeroUsize::new(256).unwrap()), - // cached_blocks: LruCache::new(NonZeroUsize::new(256).unwrap()), }; fs.create_inode( diff --git a/src/memory/cached_block.rs b/src/memory/cached_block.rs index 9e266ef..eb59a4b 100644 --- a/src/memory/cached_block.rs +++ b/src/memory/cached_block.rs @@ -2,6 +2,7 @@ use crate::block_device::{BlockDevice, BLOCK_SIZE}; use crate::disk::block::Block; use crate::AyaFS; use and_then_some::BoolExt; +use log::debug; use lru::LruCache; use std::num::NonZeroUsize; use std::sync::Arc; @@ -46,11 +47,9 @@ impl BlockCache { pub(crate) fn load_block(&mut self, index: usize) -> bool { if self.cache.contains(&index) == false { - let block = T::default(); - let buffer = unsafe { - std::slice::from_raw_parts_mut(&block as *const T as *mut u8, BLOCK_SIZE) - }; - self.device.read(index, buffer); + let mut buffer = [0u8; BLOCK_SIZE]; + self.device.read(index, &mut buffer); + let block: T = unsafe { std::mem::transmute_copy(&buffer) }; let cached_block = CachedBlock { block, index, @@ -77,8 +76,11 @@ impl BlockCache { /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载. pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { - self.load_block(index) - .and_then(|| self.cache.get_mut(&index).map(convert_mut::)) + debug!("Blockcache get block mut"); + self.load_block(index).and_then(|| { + debug!("block loaded"); + self.cache.get_mut(&index).map(convert_mut::) + }) } /// 从 LRU cache 中读取一个 block 的引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. diff --git a/src/memory/cached_inode.rs b/src/memory/cached_inode.rs index b81bd2e..dd5e5c3 100644 --- a/src/memory/cached_inode.rs +++ b/src/memory/cached_inode.rs @@ -1,7 +1,8 @@ -use crate::disk::block::{Block, InodeBlock}; +use crate::disk::block::InodeBlock; use crate::disk::inode::{Inode, InodeMode, INODE_SIZE}; -use crate::AyaFS; +use crate::{utils, AyaFS}; use and_then_some::BoolExt; +use log::debug; impl AyaFS { pub(crate) fn create_inode( @@ -12,20 +13,23 @@ impl AyaFS { gid: u32, flags: u32, ) -> Option { + debug!("create inode"); self.inode_bitmap.allocate().map(|inode_index| { + debug!("creating inode"); self.get_inode_mut(inode_index).map(|inode| { *inode = Inode::make_inode( permissions, mode, uid, gid, - Self::time_now(), + utils::time_now(), flags, 0, 0, 0, ); }); + debug!("inode created"); inode_index }) } diff --git a/src/tests/block_cache.rs b/src/tests/block_cache.rs index bbea3a0..90875ae 100644 --- a/src/tests/block_cache.rs +++ b/src/tests/block_cache.rs @@ -62,7 +62,10 @@ fn test_inode_allocation() { } let double_indirect = inode.double_indirect; - println!("double indirect is {} after allocation", inode.double_indirect); + println!( + "double indirect is {} after allocation", + inode.double_indirect + ); fs.update_inode(inode_index, inode); @@ -96,7 +99,10 @@ fn test_inode_deallocation() { assert!(fs.data_bitmap.query(inode.double_indirect as usize)); for i in 0..INDIRECT_NUMBER + 5 { - println!("Deallocated {}", fs.deallocate_block_for(&mut inode).unwrap()); + println!( + "Deallocated {}", + fs.deallocate_block_for(&mut inode).unwrap() + ); } println!("single indirect is {}", inode.single_indirect); @@ -121,57 +127,116 @@ fn test_multiple_inode_allocation() { const DIRECT_NUMBER: u32 = 15; const INDIRECT_NUMBER: u32 = 1024; - for i in 0 .. DIRECT_NUMBER + INDIRECT_NUMBER { - println!("Allcoated {} in inode {}", fs.allocate_block_for(&mut inode_1).unwrap(), inode_index_1); - println!("Allcoated {} in inode {}", fs.allocate_block_for(&mut inode_2).unwrap(), inode_index_2); + for i in 0..DIRECT_NUMBER + INDIRECT_NUMBER { + println!( + "Allocated {} in inode {}", + fs.allocate_block_for(&mut inode_1).unwrap(), + inode_index_1 + ); + println!( + "Allocated {} in inode {}", + fs.allocate_block_for(&mut inode_2).unwrap(), + inode_index_2 + ); } let inode_index_3 = fs.create_inode(0o755, InodeMode::IFDIR, 0, 0, 0).unwrap(); let mut inode_3 = fs.get_inode(inode_index_3).unwrap().clone(); - for _i in 0 .. INDIRECT_NUMBER { - println!("Deallcoated {} in inode {}", fs.deallocate_block_for(&mut inode_1).unwrap(), inode_index_1); - println!("Allcoated {} in inode {}", fs.allocate_block_for(&mut inode_3).unwrap(), inode_index_3); + for _i in 0..INDIRECT_NUMBER { + println!( + "Deallocated {} in inode {}", + fs.deallocate_block_for(&mut inode_1).unwrap(), + inode_index_1 + ); + println!( + "Allocated {} in inode {}", + fs.allocate_block_for(&mut inode_3).unwrap(), + inode_index_3 + ); } - for _i in 0 .. DIRECT_NUMBER { - println!("Deallcoated {} in inode {}", fs.deallocate_block_for(&mut inode_1).unwrap(), inode_index_1); + for _i in 0..DIRECT_NUMBER { + println!( + "Deallocated {} in inode {}", + fs.deallocate_block_for(&mut inode_1).unwrap(), + inode_index_1 + ); } assert!(fs.deallocate_block_for(&mut inode_1).is_none()); - println!("single indirect is {} for {}", inode_1.single_indirect, inode_index_1); - println!("double indirect is {} for {}", inode_1.double_indirect, inode_index_1); - println!("single indirect is {} for {}", inode_2.single_indirect, inode_index_2); - println!("double indirect is {} for {}", inode_2.double_indirect, inode_index_2); - println!("single indirect is {} for {}", inode_3.single_indirect, inode_index_3); - println!("double indirect is {} for {}", inode_3.double_indirect, inode_index_3); - - assert_eq!(fs.data_bitmap.query(inode_1.single_indirect as usize), false); + println!( + "single indirect is {} for {}", + inode_1.single_indirect, inode_index_1 + ); + println!( + "double indirect is {} for {}", + inode_1.double_indirect, inode_index_1 + ); + println!( + "single indirect is {} for {}", + inode_2.single_indirect, inode_index_2 + ); + println!( + "double indirect is {} for {}", + inode_2.double_indirect, inode_index_2 + ); + println!( + "single indirect is {} for {}", + inode_3.single_indirect, inode_index_3 + ); + println!( + "double indirect is {} for {}", + inode_3.double_indirect, inode_index_3 + ); + + assert_eq!( + fs.data_bitmap.query(inode_1.single_indirect as usize), + false + ); assert!(fs.data_bitmap.query(inode_2.single_indirect as usize)); - assert_eq!(fs.data_bitmap.query(inode_2.double_indirect as usize), false); + assert_eq!( + fs.data_bitmap.query(inode_2.double_indirect as usize), + false + ); assert!(fs.data_bitmap.query(inode_3.single_indirect as usize)); - assert_eq!(fs.data_bitmap.query(inode_3.double_indirect as usize), false); + assert_eq!( + fs.data_bitmap.query(inode_3.double_indirect as usize), + false + ); fs.allocate_block_for(&mut inode_2).unwrap(); println!("-----------------"); - println!("double indirect is {} for {}", inode_2.double_indirect, inode_index_2); + println!( + "double indirect is {} for {}", + inode_2.double_indirect, inode_index_2 + ); assert!(fs.data_bitmap.query(inode_2.double_indirect as usize)); - for _i in 0 .. DIRECT_NUMBER { + for _i in 0..DIRECT_NUMBER { fs.allocate_block_for(&mut inode_3).unwrap(); } println!("-----------------"); - println!("double indirect is {} for {}", inode_3.double_indirect, inode_index_3); - assert_eq!(fs.data_bitmap.query(inode_3.double_indirect as usize), false); + println!( + "double indirect is {} for {}", + inode_3.double_indirect, inode_index_3 + ); + assert_eq!( + fs.data_bitmap.query(inode_3.double_indirect as usize), + false + ); fs.allocate_block_for(&mut inode_3).unwrap(); println!("-----------------"); - println!("double indirect is {} for {}", inode_3.double_indirect, inode_index_3); + println!( + "double indirect is {} for {}", + inode_3.double_indirect, inode_index_3 + ); assert!(fs.data_bitmap.query(inode_3.double_indirect as usize)); fs.update_inode(inode_index_1, inode_1); fs.update_inode(inode_index_2, inode_2); fs.update_inode(inode_index_3, inode_3); -} \ No newline at end of file +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2ea25e7..60b09f2 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,15 +1,48 @@ -use crate::disk::inode::INODE_SIZE; +use crate::block_device::BLOCK_SIZE; +use crate::disk::inode::{Inode, INODE_SIZE}; use crate::{AyaFS, INODE_PER_BLOCK}; -use std::time::{SystemTime, UNIX_EPOCH}; +use fuser::FileAttr; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; -impl AyaFS { - pub(crate) fn time_now() -> u32 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("How can current time be earlier than UNIX_EPOCH?") - .as_secs() as u32 +pub(crate) fn time_now() -> u32 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("How can current time be earlier than UNIX_EPOCH?") + .as_secs() as u32 +} + +pub(crate) fn from_systime(system_time: SystemTime) -> u32 { + system_time + .duration_since(UNIX_EPOCH) + .expect("How can current time be earlier than UNIX_EPOCH?") + .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) +} +impl AyaFS { /// 输入 inode 编号, 返回它对应的 block number 和 block 内 offset pub(crate) fn locate_inode(&self, inode_index: usize) -> (usize, usize) { let block_number = -- cgit v1.2.3-70-g09d2