//! Interface with the Inodes //! //! See the [OSdev wiki](https://wiki.osdev.org/Ext2#Inodes) for more informations use anyhow::Result; use bitflags::bitflags; use super::block::{BlockGroupDescriptor, Superblock}; use super::{read, SUPERBLOCK}; /// Inode index of the root /// /// See the [OSdev wiki](https://wiki.osdev.org/Ext2#How_To_Read_the_Root_Directory) for more informations pub const ROOT_INODE_INDEX: usize = 2; /// General structure of an Ext2 inode #[repr(packed)] #[derive(Debug)] pub struct Inode { /// Type and Permissions pub type_and_permissions: u16, /// User ID pub user_id: u16, /// Lower 32 bits of size in bytes pub lower_truncation_byte_size: u32, /// Last Access Time (in POSIX time) pub last_access_time: u32, /// Creation Time (in POSIX time) pub creation_time: u32, /// Last Modification time (in POSIX time) pub last_modification_time: u32, /// Deletion time (in POSIX time) pub deletion_time: u32, /// Group ID pub group_id: u16, /// Count of hard links (directory entries) to this inode. When this reaches 0, the data blocks are marked as unallocated. pub total_hard_links: u16, /// Count of disk sectors (not Ext2 blocks) in use by this inode, not counting the actual inode structure nor directory entries /// linking to the inode. pub total_disk_sectors: u32, /// Flags pub flags: u32, /// Operating System Specific value #1 pub os_specific_1: u32, /// Direct Block Pointer 0 pub dbp00: u32, /// Direct Block Pointer 1 pub dbp01: u32, /// Direct Block Pointer 2 pub dbp02: u32, /// Direct Block Pointer 3 pub dbp03: u32, /// Direct Block Pointer 4 pub dbp04: u32, /// Direct Block Pointer 5 pub dbp05: u32, /// Direct Block Pointer 6 pub dbp06: u32, /// Direct Block Pointer 7 pub dbp07: u32, /// Direct Block Pointer 8 pub dbp08: u32, /// Direct Block Pointer 9 pub dbp09: u32, /// Direct Block Pointer 10 pub dbp10: u32, /// Direct Block Pointer 11 pub dbp11: u32, /// Singly Indirect Block Pointer (Points to a block that is a list of block pointers to data) pub singly_indirect_block_pointer: u32, /// Doubly Indirect Block Pointer (Points to a block that is a list of block pointers to Singly Indirect Blocks) pub doubly_indirect_block_pointer: u32, /// Triply Indirect Block Pointer (Points to a block that is a list of block pointers to Doubly Indirect Blocks) pub triply_indirect_block_pointer: u32, /// Generation number (Primarily used for NFS) pub generation_number: u32, /// In Ext2 version 0, this field is reserved. In version >= 1, Extended attribute block (File ACL). pub extended_attribute_block: u32, /// In Ext2 version 0, this field is reserved. In version >= 1, Upper 32 bits of file size (if feature bit set) if it's a file, /// Directory ACL if it's a directory pub higher_truncation_byte_size_or_directory_acl: u32, /// Block address of fragment pub fragment_block_address: u32, /// Operating System Specific value #2 pub os_specific_2: [u8; 12], } impl Inode { /// Returns the `n`th inode /// /// Beware that the inode indexing starts at **1** pub fn new(n: usize) -> Result<Self> { let superblock = SUPERBLOCK.get().expect("The superblock has not been initialized yet"); let block_group = Self::block_group(superblock, n); let block_group_descriptor = BlockGroupDescriptor::new(block_group)?; let inode_table_starting_block = block_group_descriptor.inode_table_starting_block_address as usize; let index = Self::group_index(superblock, n); // SAFETY: if the superblock is well formed and the device contains an Ext2 filesystem, then this offset contain an inode unsafe { read::<Self>(inode_table_starting_block * superblock.block_size() + index * superblock.inode_byte_size as usize) } } /// Returns the block group of the inode `n` /// /// See the [OSdev wiki](https://wiki.osdev.org/Ext2#Determining_which_Block_Group_contains_an_Inode) for more informations pub const fn block_group(superblock: &Superblock, n: usize) -> usize { (n - 1) / superblock.inodes_per_group as usize } /// Returns the index of the inode `n` in its block group /// /// See the [OSdev wiki](https://wiki.osdev.org/Ext2#Finding_an_inode_inside_of_a_Block_Group) for more informations pub const fn group_index(superblock: &Superblock, n: usize) -> usize { (n - 1) % superblock.inodes_per_group as usize } /// Returns the index of the block containing the inode `n` /// /// See the [OSdev wiki](https://wiki.osdev.org/Ext2#Finding_an_inode_inside_of_a_Block_Group) for more informations #[allow(unused)] pub const fn containing_block(superblock: &Superblock, n: usize) -> usize { (n * superblock.inode_byte_size as usize) / superblock.block_size() } } bitflags! { /// Indicators of the inode type and permissions /// /// The type indicator occupies the top hex digit (bits 15 to 12). /// /// The permission indicator occupies the bottom 12 bits. #[derive(Debug)] pub struct TypePermissions: u16 { // Types /// FIFO const FIFO = 0x1000; /// Character device const CHARACTER_DEVICE = 0x2000; /// Directory const DIRECTORY = 0x4000; /// Block device const BLOCK_DEVICE = 0x6000; /// Regular file const FILE = 0x8000; /// Symbolic link const SYMBOLIC_LINK = 0xA000; /// Unix socket const SOCKET = 0xC000; // Permissions /// Other - execute permission const OTHER_X = 0x0001; /// Other - write permission const OTHER_W = 0x0002; /// Other - read permission const OTHER_R = 0x0004; /// Group - execute permission const GROUP_X = 0x0008; /// Group - write permission const GROUP_W = 0x0010; /// Group - read permission const GROUP_R = 0x0020; /// User - execute permission const USER_X = 0x0040; /// User - write permission const USER_W = 0x0080; /// User - read permission const USER_R = 0x0100; /// Sticky bit const STICKY = 0x0200; /// Set group ID const SET_GROUP_ID = 0x0400; /// Set user ID const SET_USER_ID = 0x0800; } } bitflags! { /// Inode Flags #[derive(Debug)] pub struct Flags: u32 { /// Secure deletion (not used) const SECURE_DELETION = 0x0000_0001; /// Keep a copy of data when deleted (not used) const DELETION_KEEP_DATA_COPY = 0x0000_0002; /// File compression (not used) const FILE_COMPRESSION = 0x0000_0004; /// Synchronous updates—new data is written immediately to disk const SYNCHRONOUS_UPDATES = 0x0000_0008; /// Immutable file (content cannot be changed) const IMMUTABLE_FILE = 0x0000_0010; /// Append only const APPEND_ONLY = 0x0000_0020; /// File is not included in `dump` command const DUMP_EXCLUDED = 0x0000_0040; /// Last accessed time should not updated const LAST_ACCESSED_TIME_UPDATE_DISABLE = 0x0000_0080; /// Hash indexed directory const HASHED_INDEXED_DIR = 0x0001_0000; /// AFS directory const AFS_DIR = 0x0002_0000; /// Journal file data const JOURNAL_FILE_DATA = 0x0004_0000; } }