From 1eac97eea4ec0bcef0be061a2cba93a584355283 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Thu, 30 Nov 2023 02:15:06 -0800 Subject: Add real disk i/o, add mkfs.aya (not yet implemented) --- ayafs/src/disk/inode.rs | 312 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 ayafs/src/disk/inode.rs (limited to 'ayafs/src/disk/inode.rs') diff --git a/ayafs/src/disk/inode.rs b/ayafs/src/disk/inode.rs new file mode 100644 index 0000000..0c801ad --- /dev/null +++ b/ayafs/src/disk/inode.rs @@ -0,0 +1,312 @@ +use crate::utils; +use bitflags::bitflags; +use fuser::FileType; +use crate::block_device::BLOCK_SIZE; + +pub const DIRECT_NUMBER: usize = 15; + +#[derive(Debug, Clone, Copy)] +pub struct InodeMode(pub u16); + +bitflags! { + impl InodeMode: u16 { + const IXOTH = 0x0001; + const IWOTH = 0x0002; + const IROTH = 0x0004; + const IXGRP = 0x0008; + const IWGRP = 0x0010; + const IRGRP = 0x0020; + const IXUSR = 0x0040; + const IWUSR = 0x0080; + const IRUSR = 0x0100; + const ISVTX = 0x0200; + const ISGID = 0x0400; + const ISUID = 0x0800; + // These are mutually-exclusive: + const IFIFO = 0x1000; + const IFCHR = 0x2000; + const IFDIR = 0x4000; + const IFBLK = 0x6000; + const IFREG = 0x8000; + const IFLNK = 0xA000; + const IFSOCK = 0xC000; + } +} + +impl InodeMode { + #[allow(unused)] + pub(crate) fn exec_other(&self) -> bool { + self.0 & Self::IXOTH.0 != 0 + } + #[allow(unused)] + pub(crate) fn write_other(&self) -> bool { + self.0 & Self::IWOTH.0 != 0 + } + #[allow(unused)] + pub(crate) fn read_other(&self) -> bool { + self.0 & Self::IROTH.0 != 0 + } + #[allow(unused)] + pub(crate) fn exec_group(&self) -> bool { + self.0 & Self::IXGRP.0 != 0 + } + #[allow(unused)] + pub(crate) fn write_group(&self) -> bool { + self.0 & Self::IWGRP.0 != 0 + } + #[allow(unused)] + pub(crate) fn read_group(&self) -> bool { + self.0 & Self::IRGRP.0 != 0 + } + #[allow(unused)] + pub(crate) fn exec_user(&self) -> bool { + self.0 & Self::IXUSR.0 != 0 + } + #[allow(unused)] + pub(crate) fn write_user(&self) -> bool { + self.0 & Self::IWUSR.0 != 0 + } + #[allow(unused)] + pub(crate) fn read_user(&self) -> bool { + self.0 & Self::IRUSR.0 != 0 + } + + 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 is_symlink(&self) -> bool { + self.0 & 0xF000 == Self::IFLNK.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), + } + } +} + +impl From for u8 { + fn from(value: InodeMode) -> Self { + utils::from_filetype(value.into()) + } +} + +/// Pretty much the same with ext2, with minor changes: +/// - removed OS dependent attributes (osd1 & osd2) +/// - removed i_faddr since fragmentation is not supported +/// - changed uid and gid from u16 to u32 +/// - added more direct blocks for a total size of 128 bytes +/// TODO: do we need to extend time precision? +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Inode { + 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, + 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, + pub generation: u32, + pub file_acl: u32, + pub dir_acl: u32, // TODO do we have to implement ACL......? +} + +impl Inode { + fn new( + mode: InodeMode, + uid: u32, + gid: u32, + time: u32, + flags: u32, + generation: u32, + file_acl: u32, + dir_acl: u32, + ) -> Self { + Self { + mode, + uid, + size: 0, + atime: time, + ctime: time, + mtime: time, + crtime: time, + gid, + n_links: 1, + n_blocks: 0, + flags, + direct: [0; DIRECT_NUMBER], + single_indirect: 0, + double_indirect: 0, + triple_indirect: 0, + generation, + file_acl, + dir_acl, + } + } + + #[allow(unused)] + pub fn make_inode( + permissions: u16, + mode: InodeMode, + uid: u32, + gid: u32, + time: u32, + flags: u32, + generation: u32, + file_acl: u32, + dir_acl: u32, + ) -> Self { + Self::new( + InodeMode(permissions) | mode, + uid, + gid, + time, + flags, + generation, + file_acl, + dir_acl, + ) + } + + pub fn directory( + permissions: u16, + uid: u32, + gid: u32, + time: u32, + flags: u32, + generation: u32, + file_acl: u32, + dir_acl: u32, + ) -> Self { + Self::new( + InodeMode(permissions) | InodeMode::IFDIR, + uid, + gid, + time, + flags, + generation, + file_acl, + dir_acl, + ) + } + + pub fn file( + permissions: u16, + uid: u32, + gid: u32, + time: u32, + flags: u32, + generation: u32, + file_acl: u32, + dir_acl: u32, + ) -> Self { + Self::new( + InodeMode(permissions) | InodeMode::IFREG, + uid, + gid, + time, + flags, + generation, + file_acl, + dir_acl, + ) + } + + pub fn symlink( + permissions: u16, + uid: u32, + gid: u32, + time: u32, + flags: u32, + generation: u32, + file_acl: u32, + dir_acl: u32, + ) -> Self { + Self::new( + InodeMode(permissions) | InodeMode::IFLNK, + uid, + gid, + time, + flags, + generation, + file_acl, + dir_acl, + ) + } + + pub(crate) fn is_file(&self) -> bool { + self.mode.is_file() + } + + pub(crate) fn is_dir(&self) -> bool { + self.mode.is_dir() + } + + pub(crate) fn is_symlink(&self) -> bool { + self.mode.is_symlink() + } + + pub(crate) fn file_type(&self) -> FileType { + self.mode.into() + } + + pub fn empty() -> Self { + 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::(); +pub const ENTRY_PER_BLOCK: usize = BLOCK_SIZE / 4; \ No newline at end of file -- cgit v1.2.3-70-g09d2