forked from AbleOS/ableos
189 lines
6 KiB
Rust
189 lines
6 KiB
Rust
//!
|
|
use {
|
|
core::{fmt::Debug, mem},
|
|
error::Error,
|
|
sector::{Address, SectorSize},
|
|
volume::Volume,
|
|
};
|
|
|
|
/// An inode is a structure on the disk that represents a file, directory,
|
|
/// symbolic link, etc. Inodes do not contain the data of the file / directory /
|
|
/// etc. that they represent. Instead, they link to the blocks that actually
|
|
/// contain the data. This lets the inodes themselves have a well-defined size
|
|
/// which lets them be placed in easily indexed arrays. Each block group has an
|
|
/// array of inodes it is responsible for, and conversely every inode within a
|
|
/// file system belongs to one of such tables (and one of such block groups).
|
|
#[repr(C, packed)]
|
|
#[derive(Clone, Debug, Copy)]
|
|
pub struct Inode {
|
|
/// Type and Permissions (see below)
|
|
pub type_perm: TypePerm,
|
|
/// User ID
|
|
pub uid: u16,
|
|
/// Lower 32 bits of size in bytes
|
|
pub size_low: u32,
|
|
/// Last Access Time (in POSIX time)
|
|
pub atime: u32,
|
|
/// Creation Time (in POSIX time)
|
|
pub ctime: u32,
|
|
/// Last Modification time (in POSIX time)
|
|
pub mtime: u32,
|
|
/// Deletion time (in POSIX time)
|
|
pub dtime: u32,
|
|
/// Group ID
|
|
pub gid: u16,
|
|
/// Count of hard links (directory entries) to this inode. When this
|
|
/// reaches 0, the data blocks are marked as unallocated.
|
|
pub 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 sectors_count: u32,
|
|
/// Flags
|
|
pub flags: Flags,
|
|
/// Operating System Specific value #1
|
|
pub _os_specific_1: [u8; 4],
|
|
/// Direct block pointers
|
|
pub direct_pointer: [u32; 12],
|
|
/// Singly Indirect Block Pointer (Points to a block that is a list of
|
|
/// block pointers to data)
|
|
pub indirect_pointer: u32,
|
|
/// Doubly Indirect Block Pointer (Points to a block that is a list of
|
|
/// block pointers to Singly Indirect Blocks)
|
|
pub doubly_indirect: u32,
|
|
/// Triply Indirect Block Pointer (Points to a block that is a list of
|
|
/// block pointers to Doubly Indirect Blocks)
|
|
pub triply_indirect: u32,
|
|
/// Generation number (Primarily used for NFS)
|
|
pub gen_number: u32,
|
|
/// In Ext2 version 0, this field is reserved. In version >= 1,
|
|
/// Extended attribute block (File ACL).
|
|
pub ext_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 size_high: u32,
|
|
/// Block address of fragment
|
|
pub frag_block_addr: u32,
|
|
/// Operating System Specific Value #2
|
|
pub _os_specific_2: [u8; 12],
|
|
}
|
|
|
|
impl Inode {
|
|
/// Discover the inode location on the disk.
|
|
pub unsafe fn find_inode<S: SectorSize, V: Volume<u8, S>>(
|
|
haystack: &V,
|
|
offset: Address<S>,
|
|
size: usize,
|
|
) -> Result<(Inode, Address<S>), Error> {
|
|
if size != mem::size_of::<Inode>() {
|
|
unimplemented!("inodes with a size != 128");
|
|
}
|
|
|
|
let end = offset + Address::from(size);
|
|
if haystack.size() < end {
|
|
return Err(Error::AddressOutOfBounds {
|
|
sector: end.sector(),
|
|
offset: end.offset(),
|
|
size: end.sector_size(),
|
|
});
|
|
}
|
|
|
|
let inode = haystack
|
|
.slice_unchecked(offset..end)
|
|
.dynamic_cast::<Inode>();
|
|
|
|
Ok(inode)
|
|
}
|
|
}
|
|
|
|
bitflags! {
|
|
///
|
|
// #[derive(Copy)]
|
|
pub struct TypePerm: u16 {
|
|
/// FIFO
|
|
const FIFO = 0x1000;
|
|
/// Character device
|
|
const CHAR_DEVICE = 0x2000;
|
|
/// Directory
|
|
const DIRECTORY = 0x4000;
|
|
/// Block device
|
|
const BLOCK_DEVICE = 0x6000;
|
|
/// Regular file
|
|
const FILE = 0x8000;
|
|
/// Symbolic link
|
|
const SYMLINK = 0xA000;
|
|
/// Unix socket
|
|
const SOCKET = 0xC000;
|
|
/// Other—execute permission
|
|
const O_EXEC = 0x001;
|
|
/// Other—write permission
|
|
const O_WRITE = 0x002;
|
|
/// Other—read permission
|
|
const O_READ = 0x004;
|
|
/// Group—execute permission
|
|
const G_EXEC = 0x008;
|
|
/// Group—write permission
|
|
const G_WRITE = 0x010;
|
|
/// Group—read permission
|
|
const G_READ = 0x020;
|
|
/// User—execute permission
|
|
const U_EXEC = 0x040;
|
|
/// User—write permission
|
|
const U_WRITE = 0x080;
|
|
/// User—read permission
|
|
const U_READ = 0x100;
|
|
/// Sticky Bit
|
|
const STICKY = 0x200;
|
|
/// Set group ID
|
|
const SET_GID = 0x400;
|
|
/// Set user ID
|
|
const SET_UID = 0x800;
|
|
}
|
|
}
|
|
|
|
bitflags! {
|
|
/// Flags
|
|
pub struct Flags: u32 {
|
|
/// Secure deletion (not used)
|
|
const SECURE_DEL = 0x00000001;
|
|
/// Keep a copy of data when deleted (not used)
|
|
const KEEP_COPY = 0x00000002;
|
|
/// File compression (not used)
|
|
const COMPRESSION = 0x00000004;
|
|
/// Synchronous updates—new data is written immediately to disk
|
|
const SYNC_UPDATE = 0x00000008;
|
|
/// Immutable file (content cannot be changed)
|
|
const IMMUTABLE = 0x00000010;
|
|
/// Append only
|
|
const APPEND_ONLY = 0x00000020;
|
|
/// File is not included in 'dump' command
|
|
const NODUMP = 0x00000040;
|
|
/// Last accessed time should not updated
|
|
const DONT_ATIME = 0x00000080;
|
|
/// Hash indexed directory
|
|
const HASH_DIR = 0x00010000;
|
|
/// AFS directory
|
|
const AFS_DIR = 0x00020000;
|
|
/// Journal file data
|
|
const JOURNAL_DATA = 0x00040000;
|
|
}
|
|
}
|
|
|
|
/// Unknown entry type
|
|
pub const UNKNOWN: u8 = 0;
|
|
/// FIFO entry type
|
|
pub const FIFO: u8 = 1;
|
|
/// Character device entry type
|
|
pub const CHAR_DEVICE: u8 = 2;
|
|
/// Directory entry type
|
|
pub const DIRECTORY: u8 = 3;
|
|
/// Block device entry type
|
|
pub const BLOCK_DEVICE: u8 = 4;
|
|
/// Regular file entry type
|
|
pub const FILE: u8 = 5;
|
|
/// Symbolic link entry type
|
|
pub const SYMLINK: u8 = 6;
|
|
/// Unix socket entry type
|
|
pub const SOCKET: u8 = 7;
|