|
| 1 | +use crate::utils::CeilDiv; |
| 2 | + |
| 3 | +use super::FileType; |
| 4 | + |
| 5 | +#[derive(Debug, Copy, Clone)] |
| 6 | +#[repr(C, packed)] |
| 7 | +pub struct SuperBlock { |
| 8 | + pub inodes_count: u32, |
| 9 | + pub blocks_count: u32, |
| 10 | + pub r_blocks_count: u32, |
| 11 | + pub free_blocks_count: u32, |
| 12 | + pub free_inodes_count: u32, |
| 13 | + pub first_data_block: u32, |
| 14 | + pub log_block_size: u32, |
| 15 | + pub log_frag_size: u32, |
| 16 | + pub blocks_per_group: u32, |
| 17 | + pub frags_per_group: u32, |
| 18 | + pub inodes_per_group: u32, |
| 19 | + pub mtime: u32, |
| 20 | + pub wtime: u32, |
| 21 | + pub mnt_count: u16, |
| 22 | + pub max_mnt_count: u16, |
| 23 | + pub magic: u16, |
| 24 | + pub state: u16, |
| 25 | + pub errors: u16, |
| 26 | + pub minor_rev_level: u16, |
| 27 | + pub lastcheck: u32, |
| 28 | + pub checkinterval: u32, |
| 29 | + pub creator_os: u32, |
| 30 | + pub rev_level: u32, |
| 31 | + pub def_resuid: u16, |
| 32 | + pub def_gid: u16, |
| 33 | + |
| 34 | + // Extended Superblock fields |
| 35 | + // |
| 36 | + // XXX: If version number >= 1, we have to use the ext2 extended superblock as well :) |
| 37 | + pub first_ino: u32, |
| 38 | + pub inode_size: u16, |
| 39 | + pub block_group_nr: u16, |
| 40 | + pub feature_compat: u32, |
| 41 | + pub feature_incompat: u32, |
| 42 | + pub feature_ro_compat: u32, |
| 43 | + pub uuid: [u64; 2usize], |
| 44 | + pub volume_name: [u8; 16usize], |
| 45 | + pub last_mounted: [u64; 8usize], |
| 46 | + pub compression_info: u32, |
| 47 | + pub prealloc_blocks: u8, |
| 48 | + pub prealloc_dir_blocks: u8, |
| 49 | + pub reserved_gdt_blocks: u16, |
| 50 | + pub journal_uuid: [u8; 16usize], |
| 51 | + pub journal_inum: u32, |
| 52 | + pub journal_dev: u32, |
| 53 | + pub last_orphan: u32, |
| 54 | + pub hash_seed: [u32; 4usize], |
| 55 | + pub def_hash_version: u8, |
| 56 | + pub jnl_backup_type: u8, |
| 57 | + pub group_desc_size: u16, |
| 58 | + pub default_mount_opts: u32, |
| 59 | + pub first_meta_bg: u32, |
| 60 | + pub mkfs_time: u32, |
| 61 | + pub jnl_blocks: [u32; 17usize], |
| 62 | +} |
| 63 | + |
| 64 | +impl SuperBlock { |
| 65 | + pub const MAGIC: u16 = 0xef53; |
| 66 | + |
| 67 | + /// Returns the number of entries per block. |
| 68 | + pub fn entries_per_block(&self) -> usize { |
| 69 | + self.block_size() / core::mem::size_of::<u32>() |
| 70 | + } |
| 71 | + |
| 72 | + /// Returns the size of a block in bytes. |
| 73 | + pub fn block_size(&self) -> usize { |
| 74 | + 1024usize << self.log_block_size |
| 75 | + } |
| 76 | + |
| 77 | + /// Returns the length of the BGDT. |
| 78 | + pub fn bgdt_len(&self) -> usize { |
| 79 | + self.blocks_count.ceil_div(self.blocks_per_group) as usize |
| 80 | + } |
| 81 | + |
| 82 | + pub fn bgdt_block(&self) -> usize { |
| 83 | + // XXX: The block group descriptors are always located in the block immediately |
| 84 | + // following the superblock. |
| 85 | + let block_size = self.block_size(); |
| 86 | + |
| 87 | + if block_size >= 2048 { |
| 88 | + block_size |
| 89 | + } else { |
| 90 | + block_size * 2 |
| 91 | + } |
| 92 | + } |
| 93 | +} |
| 94 | + |
| 95 | +#[repr(C)] |
| 96 | +#[derive(Debug, Copy, Clone)] |
| 97 | +pub struct GroupDescriptor { |
| 98 | + pub block_bitmap: u32, |
| 99 | + pub inode_bitmap: u32, |
| 100 | + pub inode_table: u32, |
| 101 | + pub free_blocks_count: u16, |
| 102 | + pub free_inodes_count: u16, |
| 103 | + pub used_dirs_count: u16, |
| 104 | + pub pad: u16, |
| 105 | + pub reserved: [u8; 12usize], |
| 106 | +} |
| 107 | + |
| 108 | +const_assert_eq!(core::mem::size_of::<GroupDescriptor>(), 32); |
| 109 | + |
| 110 | +#[derive(Debug, Copy, Clone)] |
| 111 | +#[repr(C, packed)] |
| 112 | +pub struct DirEntry { |
| 113 | + pub inode: u32, |
| 114 | + pub entry_size: u16, |
| 115 | + pub name_size: u8, |
| 116 | + pub file_type: u8, |
| 117 | +} |
| 118 | + |
| 119 | +impl DirEntry { |
| 120 | + pub fn set_name(&mut self, name: &str) { |
| 121 | + assert!(name.len() < u8::MAX as usize); |
| 122 | + |
| 123 | + self.name_size = name.len() as u8; |
| 124 | + |
| 125 | + // SAFETY: Above we have verified that the name will fit in the entry. |
| 126 | + let name_ptr = unsafe { (self as *mut _ as *mut u8).add(core::mem::size_of::<Self>()) }; |
| 127 | + let name_bytes = unsafe { core::slice::from_raw_parts_mut(name_ptr, name.len()) }; |
| 128 | + |
| 129 | + name_bytes.copy_from_slice(name.as_bytes()); |
| 130 | + } |
| 131 | + |
| 132 | + pub fn avaliable_size(&self) -> usize { |
| 133 | + if self.inode == 0 { |
| 134 | + self.entry_size as usize |
| 135 | + } else { |
| 136 | + 0 |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + pub fn as_bytes(&self) -> &[u8] { |
| 141 | + unsafe { |
| 142 | + core::slice::from_raw_parts(self as *const Self as *const u8, self.entry_size as usize) |
| 143 | + } |
| 144 | + } |
| 145 | +} |
| 146 | + |
| 147 | +#[repr(C)] |
| 148 | +#[derive(Debug, Default, Copy, Clone)] |
| 149 | +pub struct INode { |
| 150 | + type_and_perm: u16, |
| 151 | + pub user_id: u16, |
| 152 | + pub size_lower: u32, |
| 153 | + pub last_access: u32, |
| 154 | + pub creation_time: u32, |
| 155 | + pub last_modification: u32, |
| 156 | + pub deletion_time: u32, |
| 157 | + pub group_id: u16, |
| 158 | + pub hl_count: u16, |
| 159 | + pub block_count: u32, |
| 160 | + pub flags: u32, |
| 161 | + pub os_specific: u32, |
| 162 | + pub data_ptr: [u32; 15], |
| 163 | + pub gen_number: u32, |
| 164 | + pub ext_attr_block: u32, |
| 165 | + pub size_or_acl: u32, |
| 166 | + pub fragment_address: u32, |
| 167 | + pub os_specific2: [u8; 12], |
| 168 | +} |
| 169 | + |
| 170 | +impl INode { |
| 171 | + pub fn file_type(&self) -> FileType { |
| 172 | + let ty = self.type_and_perm >> 12; |
| 173 | + |
| 174 | + match ty { |
| 175 | + 0x1 => FileType::Fifo, |
| 176 | + 0x2 => FileType::CharDev, |
| 177 | + 0x4 => FileType::Directory, |
| 178 | + 0x6 => FileType::BlockDev, |
| 179 | + 0x8 => FileType::File, |
| 180 | + 0xa => FileType::Symlink, |
| 181 | + 0xc => FileType::Socket, |
| 182 | + _ => FileType::Unknown, |
| 183 | + } |
| 184 | + } |
| 185 | +} |
| 186 | + |
| 187 | +const_assert_eq!(core::mem::size_of::<INode>(), 128); |
0 commit comments