// Copyright 2024 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Defines the superblock structure. use anyhow::Result; use zerocopy::AsBytes; use zerocopy_derive::FromBytes; use zerocopy_derive::FromZeroes; use crate::arena::Arena; use crate::arena::BlockId; use crate::blockgroup::BLOCK_SIZE; use crate::builder::Builder; use crate::inode::Inode; /// A struct to represent the configuration of an ext2 filesystem. /// The ext2 superblock. /// /// The field names are based on [the specification](https://www.nongnu.org/ext2-doc/ext2.html#superblock). /// Note that this struct only holds the fields at the beginning of the superblock. All fields after /// the fields supported by this structure are filled with zeros. #[repr(C)] #[derive(Default, Debug, Copy, Clone, FromZeroes, FromBytes, AsBytes)] pub(crate) struct SuperBlock { pub inodes_count: u32, pub blocks_count: u32, _r_blocks_count: u32, pub free_blocks_count: u32, pub free_inodes_count: u32, _first_data_block: u32, _log_block_size: u32, log_frag_size: u32, pub blocks_per_group: u32, frags_per_group: u32, pub inodes_per_group: u32, mtime: u32, wtime: u32, _mnt_count: u16, _max_mnt_count: u16, magic: u16, state: u16, errors: u16, _minor_rev_level: u16, _lastcheck: u32, _checkinterval: u32, _creator_os: u32, rev_level: u32, _def_resuid: u16, _def_resgid: u16, first_ino: u32, pub inode_size: u16, pub block_group_nr: u16, feature_compat: u32, feature_incompat: u32, _feature_ro_compat: u32, uuid: [u8; 16], // Add more fields if needed. } impl SuperBlock { pub fn new<'a>(arena: &'a Arena<'a>, cfg: &Builder) -> Result<&'a mut SuperBlock> { const EXT2_MAGIC_NUMBER: u16 = 0xEF53; const COMPAT_EXT_ATTR: u32 = 0x8; let num_groups = cfg.size / (cfg.blocks_per_group * BLOCK_SIZE as u32); let blocks_per_group = cfg.blocks_per_group; let inodes_per_group = cfg.inodes_per_group; let log_block_size = 2; // (1024 << log_block_size) = 4K bytes let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH)? .as_secs() as u32; let uuid = uuid::Uuid::new_v4().into_bytes(); let inodes_count = inodes_per_group * num_groups; let blocks_count = blocks_per_group * num_groups; // Reserve 10 inodes. Usually inode 11 is used for the lost+found directory. // . let first_ino = 11; // Superblock is located at 1024 bytes in the first block. let sb = arena.allocate::(BlockId::from(0), 1024)?; *sb = Self { inodes_count, blocks_count, free_blocks_count: 0, //blocks_count, // All blocks are free free_inodes_count: inodes_count, // All inodes are free _log_block_size: log_block_size, log_frag_size: log_block_size, blocks_per_group, frags_per_group: blocks_per_group, inodes_per_group, mtime: now, wtime: now, magic: EXT2_MAGIC_NUMBER, state: 1, // clean errors: 1, // continue on errors rev_level: 1, // Rev 1 for variable inode sizes first_ino, inode_size: Inode::INODE_RECORD_SIZE as u16, block_group_nr: 1, // super block is in block group 1 feature_compat: COMPAT_EXT_ATTR, feature_incompat: 0x2, // Directory entries contain a type field uuid, ..Default::default() }; Ok(sb) } #[inline] pub fn num_groups(&self) -> u16 { (self.inodes_count / self.inodes_per_group) as u16 } }