Skip to content
Snippets Groups Projects
inode.rs 8.03 KiB
Newer Older
//! 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;
        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;
        const AFS_DIR                               =   0x0002_0000;
        const JOURNAL_FILE_DATA                     =   0x0004_0000;