1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker //! Defines the inode structure. 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::MaybeUninit; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::fs::MetadataExt; 9*bb4ee6a4SAndroid Build Coastguard Worker 10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail; 11*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 12*bb4ee6a4SAndroid Build Coastguard Worker use enumn::N; 13*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes; 14*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy_derive::FromBytes; 15*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy_derive::FromZeroes; 16*bb4ee6a4SAndroid Build Coastguard Worker 17*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::Arena; 18*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::BlockId; 19*bb4ee6a4SAndroid Build Coastguard Worker use crate::blockgroup::GroupMetaData; 20*bb4ee6a4SAndroid Build Coastguard Worker use crate::xattr::InlineXattrs; 21*bb4ee6a4SAndroid Build Coastguard Worker 22*bb4ee6a4SAndroid Build Coastguard Worker /// Types of inodes. 23*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq, Clone, Copy, N)] 24*bb4ee6a4SAndroid Build Coastguard Worker pub enum InodeType { 25*bb4ee6a4SAndroid Build Coastguard Worker Fifo = 0x1, 26*bb4ee6a4SAndroid Build Coastguard Worker Char = 0x2, 27*bb4ee6a4SAndroid Build Coastguard Worker Directory = 0x4, 28*bb4ee6a4SAndroid Build Coastguard Worker Block = 0x6, 29*bb4ee6a4SAndroid Build Coastguard Worker Regular = 0x8, 30*bb4ee6a4SAndroid Build Coastguard Worker Symlink = 0xa, 31*bb4ee6a4SAndroid Build Coastguard Worker Socket = 0xc, 32*bb4ee6a4SAndroid Build Coastguard Worker } 33*bb4ee6a4SAndroid Build Coastguard Worker 34*bb4ee6a4SAndroid Build Coastguard Worker impl InodeType { 35*bb4ee6a4SAndroid Build Coastguard Worker /// Converts to a file type for directory entry. 36*bb4ee6a4SAndroid Build Coastguard Worker /// The value is defined in "Table 4.2. Defined Inode File Type Values" in the spec. into_dir_entry_file_type(self) -> u837*bb4ee6a4SAndroid Build Coastguard Worker pub fn into_dir_entry_file_type(self) -> u8 { 38*bb4ee6a4SAndroid Build Coastguard Worker match self { 39*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Regular => 1, 40*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Directory => 2, 41*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Char => 3, 42*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Block => 4, 43*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Fifo => 5, 44*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Socket => 6, 45*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Symlink => 7, 46*bb4ee6a4SAndroid Build Coastguard Worker } 47*bb4ee6a4SAndroid Build Coastguard Worker } 48*bb4ee6a4SAndroid Build Coastguard Worker } 49*bb4ee6a4SAndroid Build Coastguard Worker 50*bb4ee6a4SAndroid Build Coastguard Worker // Represents an inode number. 51*bb4ee6a4SAndroid Build Coastguard Worker // This is 1-indexed. 52*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 53*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) struct InodeNum(pub u32); 54*bb4ee6a4SAndroid Build Coastguard Worker 55*bb4ee6a4SAndroid Build Coastguard Worker impl InodeNum { new(inode: u32) -> Result<Self>56*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(inode: u32) -> Result<Self> { 57*bb4ee6a4SAndroid Build Coastguard Worker if inode == 0 { 58*bb4ee6a4SAndroid Build Coastguard Worker bail!("inode number is 1-indexed"); 59*bb4ee6a4SAndroid Build Coastguard Worker } 60*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self(inode)) 61*bb4ee6a4SAndroid Build Coastguard Worker } 62*bb4ee6a4SAndroid Build Coastguard Worker 63*bb4ee6a4SAndroid Build Coastguard Worker // Returns index in the inode table. to_table_index(self) -> usize64*bb4ee6a4SAndroid Build Coastguard Worker pub fn to_table_index(self) -> usize { 65*bb4ee6a4SAndroid Build Coastguard Worker // (num - 1) because inode is 1-indexed. 66*bb4ee6a4SAndroid Build Coastguard Worker self.0 as usize - 1 67*bb4ee6a4SAndroid Build Coastguard Worker } 68*bb4ee6a4SAndroid Build Coastguard Worker } 69*bb4ee6a4SAndroid Build Coastguard Worker 70*bb4ee6a4SAndroid Build Coastguard Worker impl From<InodeNum> for u32 { from(inode: InodeNum) -> Self71*bb4ee6a4SAndroid Build Coastguard Worker fn from(inode: InodeNum) -> Self { 72*bb4ee6a4SAndroid Build Coastguard Worker inode.0 73*bb4ee6a4SAndroid Build Coastguard Worker } 74*bb4ee6a4SAndroid Build Coastguard Worker } 75*bb4ee6a4SAndroid Build Coastguard Worker 76*bb4ee6a4SAndroid Build Coastguard Worker impl From<InodeNum> for usize { from(inode: InodeNum) -> Self77*bb4ee6a4SAndroid Build Coastguard Worker fn from(inode: InodeNum) -> Self { 78*bb4ee6a4SAndroid Build Coastguard Worker inode.0 as usize 79*bb4ee6a4SAndroid Build Coastguard Worker } 80*bb4ee6a4SAndroid Build Coastguard Worker } 81*bb4ee6a4SAndroid Build Coastguard Worker 82*bb4ee6a4SAndroid Build Coastguard Worker /// Size of the `block` field in Inode. 83*bb4ee6a4SAndroid Build Coastguard Worker const INODE_BLOCK_LEN: usize = 60; 84*bb4ee6a4SAndroid Build Coastguard Worker /// Represents 60-byte region for block in Inode. 85*bb4ee6a4SAndroid Build Coastguard Worker /// This region is used for various ways depending on the file type. 86*bb4ee6a4SAndroid Build Coastguard Worker /// For regular files and directories, it's used for storing 32-bit indices of blocks. 87*bb4ee6a4SAndroid Build Coastguard Worker /// 88*bb4ee6a4SAndroid Build Coastguard Worker /// This is a wrapper of `[u8; 60]` to implement `Default` manually. 89*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 90*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, FromZeroes, FromBytes, AsBytes)] 91*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) struct InodeBlock(pub [u8; INODE_BLOCK_LEN]); 92*bb4ee6a4SAndroid Build Coastguard Worker 93*bb4ee6a4SAndroid Build Coastguard Worker impl Default for InodeBlock { default() -> Self94*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self { 95*bb4ee6a4SAndroid Build Coastguard Worker Self([0; INODE_BLOCK_LEN]) 96*bb4ee6a4SAndroid Build Coastguard Worker } 97*bb4ee6a4SAndroid Build Coastguard Worker } 98*bb4ee6a4SAndroid Build Coastguard Worker 99*bb4ee6a4SAndroid Build Coastguard Worker impl InodeBlock { 100*bb4ee6a4SAndroid Build Coastguard Worker // Each inode contains 12 direct pointers (0-11), one singly indirect pointer (12), one 101*bb4ee6a4SAndroid Build Coastguard Worker // doubly indirect block pointer (13), and one triply indirect pointer (14). 102*bb4ee6a4SAndroid Build Coastguard Worker pub const NUM_DIRECT_BLOCKS: usize = 12; 103*bb4ee6a4SAndroid Build Coastguard Worker const INDIRECT_BLOCK_TABLE_ID: usize = Self::NUM_DIRECT_BLOCKS; 104*bb4ee6a4SAndroid Build Coastguard Worker const DOUBLE_INDIRECT_BLOCK_TABLE_ID: usize = 13; 105*bb4ee6a4SAndroid Build Coastguard Worker 106*bb4ee6a4SAndroid Build Coastguard Worker /// Set a block id at the given index. set_block_id(&mut self, index: usize, block_id: &BlockId) -> Result<()>107*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_block_id(&mut self, index: usize, block_id: &BlockId) -> Result<()> { 108*bb4ee6a4SAndroid Build Coastguard Worker let offset = index * std::mem::size_of::<BlockId>(); 109*bb4ee6a4SAndroid Build Coastguard Worker let bytes = block_id.as_bytes(); 110*bb4ee6a4SAndroid Build Coastguard Worker if self.0.len() < offset + bytes.len() { 111*bb4ee6a4SAndroid Build Coastguard Worker bail!("index out of bounds when setting block_id to InodeBlock: index={index}, block_id: {:?}", block_id); 112*bb4ee6a4SAndroid Build Coastguard Worker } 113*bb4ee6a4SAndroid Build Coastguard Worker self.0[offset..offset + bytes.len()].copy_from_slice(bytes); 114*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 115*bb4ee6a4SAndroid Build Coastguard Worker } 116*bb4ee6a4SAndroid Build Coastguard Worker 117*bb4ee6a4SAndroid Build Coastguard Worker /// Set an array of direct block IDs. set_direct_blocks_from( &mut self, start_idx: usize, block_ids: &[BlockId], ) -> Result<()>118*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_direct_blocks_from( 119*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 120*bb4ee6a4SAndroid Build Coastguard Worker start_idx: usize, 121*bb4ee6a4SAndroid Build Coastguard Worker block_ids: &[BlockId], 122*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 123*bb4ee6a4SAndroid Build Coastguard Worker let bytes = block_ids.as_bytes(); 124*bb4ee6a4SAndroid Build Coastguard Worker if bytes.len() + start_idx * 4 > self.0.len() { 125*bb4ee6a4SAndroid Build Coastguard Worker bail!( 126*bb4ee6a4SAndroid Build Coastguard Worker "length of direct blocks is {} bytes, but it must not exceed {}", 127*bb4ee6a4SAndroid Build Coastguard Worker bytes.len(), 128*bb4ee6a4SAndroid Build Coastguard Worker self.0.len() 129*bb4ee6a4SAndroid Build Coastguard Worker ); 130*bb4ee6a4SAndroid Build Coastguard Worker } 131*bb4ee6a4SAndroid Build Coastguard Worker self.0[start_idx * 4..(start_idx * 4 + bytes.len())].copy_from_slice(bytes); 132*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 133*bb4ee6a4SAndroid Build Coastguard Worker } 134*bb4ee6a4SAndroid Build Coastguard Worker 135*bb4ee6a4SAndroid Build Coastguard Worker /// Set an array of direct block IDs. set_direct_blocks(&mut self, block_ids: &[BlockId]) -> Result<()>136*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_direct_blocks(&mut self, block_ids: &[BlockId]) -> Result<()> { 137*bb4ee6a4SAndroid Build Coastguard Worker self.set_direct_blocks_from(0, block_ids) 138*bb4ee6a4SAndroid Build Coastguard Worker } 139*bb4ee6a4SAndroid Build Coastguard Worker 140*bb4ee6a4SAndroid Build Coastguard Worker /// Set a block id to be used as the indirect block table. set_indirect_block_table(&mut self, block_id: &BlockId) -> Result<()>141*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_indirect_block_table(&mut self, block_id: &BlockId) -> Result<()> { 142*bb4ee6a4SAndroid Build Coastguard Worker self.set_block_id(Self::INDIRECT_BLOCK_TABLE_ID, block_id) 143*bb4ee6a4SAndroid Build Coastguard Worker } 144*bb4ee6a4SAndroid Build Coastguard Worker 145*bb4ee6a4SAndroid Build Coastguard Worker /// Set a block id to be used as the double indirect block table. set_double_indirect_block_table(&mut self, block_id: &BlockId) -> Result<()>146*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_double_indirect_block_table(&mut self, block_id: &BlockId) -> Result<()> { 147*bb4ee6a4SAndroid Build Coastguard Worker self.set_block_id(Self::DOUBLE_INDIRECT_BLOCK_TABLE_ID, block_id) 148*bb4ee6a4SAndroid Build Coastguard Worker } 149*bb4ee6a4SAndroid Build Coastguard Worker 150*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the max length of symbolic links that can be stored in the inode data. 151*bb4ee6a4SAndroid Build Coastguard Worker /// This length contains the trailing `\0`. max_inline_symlink_len() -> usize152*bb4ee6a4SAndroid Build Coastguard Worker pub const fn max_inline_symlink_len() -> usize { 153*bb4ee6a4SAndroid Build Coastguard Worker INODE_BLOCK_LEN 154*bb4ee6a4SAndroid Build Coastguard Worker } 155*bb4ee6a4SAndroid Build Coastguard Worker 156*bb4ee6a4SAndroid Build Coastguard Worker /// Stores a given string as an inlined symbolic link data. set_inline_symlink(&mut self, symlink: &str) -> Result<()>157*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_inline_symlink(&mut self, symlink: &str) -> Result<()> { 158*bb4ee6a4SAndroid Build Coastguard Worker let bytes = symlink.as_bytes(); 159*bb4ee6a4SAndroid Build Coastguard Worker if bytes.len() >= Self::max_inline_symlink_len() { 160*bb4ee6a4SAndroid Build Coastguard Worker bail!( 161*bb4ee6a4SAndroid Build Coastguard Worker "symlink '{symlink}' exceeds or equals tomax length: {} >= {}", 162*bb4ee6a4SAndroid Build Coastguard Worker bytes.len(), 163*bb4ee6a4SAndroid Build Coastguard Worker Self::max_inline_symlink_len() 164*bb4ee6a4SAndroid Build Coastguard Worker ); 165*bb4ee6a4SAndroid Build Coastguard Worker } 166*bb4ee6a4SAndroid Build Coastguard Worker self.0[..bytes.len()].copy_from_slice(bytes); 167*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 168*bb4ee6a4SAndroid Build Coastguard Worker } 169*bb4ee6a4SAndroid Build Coastguard Worker } 170*bb4ee6a4SAndroid Build Coastguard Worker 171*bb4ee6a4SAndroid Build Coastguard Worker /// The ext2 inode. 172*bb4ee6a4SAndroid Build Coastguard Worker /// 173*bb4ee6a4SAndroid Build Coastguard Worker /// The field names are based on [the specification](https://www.nongnu.org/ext2-doc/ext2.html#inode-table). 174*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 175*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, FromZeroes, FromBytes, AsBytes)] 176*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) struct Inode { 177*bb4ee6a4SAndroid Build Coastguard Worker mode: u16, 178*bb4ee6a4SAndroid Build Coastguard Worker uid: u16, 179*bb4ee6a4SAndroid Build Coastguard Worker pub size: u32, 180*bb4ee6a4SAndroid Build Coastguard Worker atime: u32, 181*bb4ee6a4SAndroid Build Coastguard Worker ctime: u32, 182*bb4ee6a4SAndroid Build Coastguard Worker mtime: u32, 183*bb4ee6a4SAndroid Build Coastguard Worker _dtime: u32, 184*bb4ee6a4SAndroid Build Coastguard Worker gid: u16, 185*bb4ee6a4SAndroid Build Coastguard Worker pub links_count: u16, 186*bb4ee6a4SAndroid Build Coastguard Worker pub blocks: InodeBlocksCount, 187*bb4ee6a4SAndroid Build Coastguard Worker _flags: u32, 188*bb4ee6a4SAndroid Build Coastguard Worker _osd1: u32, 189*bb4ee6a4SAndroid Build Coastguard Worker pub block: InodeBlock, 190*bb4ee6a4SAndroid Build Coastguard Worker _generation: u32, 191*bb4ee6a4SAndroid Build Coastguard Worker _file_acl: u32, 192*bb4ee6a4SAndroid Build Coastguard Worker _dir_acl: u32, 193*bb4ee6a4SAndroid Build Coastguard Worker _faddr: u32, 194*bb4ee6a4SAndroid Build Coastguard Worker _fragment_num: u8, 195*bb4ee6a4SAndroid Build Coastguard Worker _fragment_size: u8, 196*bb4ee6a4SAndroid Build Coastguard Worker _reserved1: u16, 197*bb4ee6a4SAndroid Build Coastguard Worker uid_high: u16, 198*bb4ee6a4SAndroid Build Coastguard Worker gid_high: u16, 199*bb4ee6a4SAndroid Build Coastguard Worker _reserved2: u32, // 128-th byte 200*bb4ee6a4SAndroid Build Coastguard Worker 201*bb4ee6a4SAndroid Build Coastguard Worker // We don't use any inode metadata region beyond the basic 128 bytes. 202*bb4ee6a4SAndroid Build Coastguard Worker // However set `extra_size` to the minimum value to let Linux kernel know that there are 203*bb4ee6a4SAndroid Build Coastguard Worker // inline extended attribute data. The minimum possible is 4 bytes, so define extra_size 204*bb4ee6a4SAndroid Build Coastguard Worker // and add the next padding. 205*bb4ee6a4SAndroid Build Coastguard Worker pub extra_size: u16, 206*bb4ee6a4SAndroid Build Coastguard Worker _paddings: u16, // padding for 32-bit alignment 207*bb4ee6a4SAndroid Build Coastguard Worker } 208*bb4ee6a4SAndroid Build Coastguard Worker 209*bb4ee6a4SAndroid Build Coastguard Worker impl Default for Inode { default() -> Self210*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self { 211*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: zero-filled value is a valid value. 212*bb4ee6a4SAndroid Build Coastguard Worker let mut r: Self = unsafe { MaybeUninit::zeroed().assume_init() }; 213*bb4ee6a4SAndroid Build Coastguard Worker // Set extra size to 4 for `extra_size` and `paddings` fields. 214*bb4ee6a4SAndroid Build Coastguard Worker r.extra_size = 4; 215*bb4ee6a4SAndroid Build Coastguard Worker r 216*bb4ee6a4SAndroid Build Coastguard Worker } 217*bb4ee6a4SAndroid Build Coastguard Worker } 218*bb4ee6a4SAndroid Build Coastguard Worker 219*bb4ee6a4SAndroid Build Coastguard Worker /// Used in `Inode` to represent how many 512-byte blocks are used by a file. 220*bb4ee6a4SAndroid Build Coastguard Worker /// 221*bb4ee6a4SAndroid Build Coastguard Worker /// The block size '512' byte is fixed and not related to the actual block size of the file system. 222*bb4ee6a4SAndroid Build Coastguard Worker /// For more details, see notes for `i_blocks_lo` in the specification. 223*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 224*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Debug, Copy, Clone, FromZeroes, FromBytes, AsBytes)] 225*bb4ee6a4SAndroid Build Coastguard Worker pub struct InodeBlocksCount(u32); 226*bb4ee6a4SAndroid Build Coastguard Worker 227*bb4ee6a4SAndroid Build Coastguard Worker impl InodeBlocksCount { 228*bb4ee6a4SAndroid Build Coastguard Worker const INODE_BLOCKS_SIZE: u32 = 512; 229*bb4ee6a4SAndroid Build Coastguard Worker from_bytes_len(len: u32) -> Self230*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_bytes_len(len: u32) -> Self { 231*bb4ee6a4SAndroid Build Coastguard Worker Self(len / Self::INODE_BLOCKS_SIZE) 232*bb4ee6a4SAndroid Build Coastguard Worker } 233*bb4ee6a4SAndroid Build Coastguard Worker add(&mut self, v: u32)234*bb4ee6a4SAndroid Build Coastguard Worker pub fn add(&mut self, v: u32) { 235*bb4ee6a4SAndroid Build Coastguard Worker self.0 += v / Self::INODE_BLOCKS_SIZE; 236*bb4ee6a4SAndroid Build Coastguard Worker } 237*bb4ee6a4SAndroid Build Coastguard Worker } 238*bb4ee6a4SAndroid Build Coastguard Worker 239*bb4ee6a4SAndroid Build Coastguard Worker impl Inode { 240*bb4ee6a4SAndroid Build Coastguard Worker /// Size of the inode record in bytes. 241*bb4ee6a4SAndroid Build Coastguard Worker /// 242*bb4ee6a4SAndroid Build Coastguard Worker /// From ext2 revision 1, inode size larger than 128 bytes is supported. 243*bb4ee6a4SAndroid Build Coastguard Worker /// We use 256 byte here, which is the default value for ext4. 244*bb4ee6a4SAndroid Build Coastguard Worker /// 245*bb4ee6a4SAndroid Build Coastguard Worker /// Note that inode "record" size can be larger that inode "structure" size. 246*bb4ee6a4SAndroid Build Coastguard Worker /// The gap between the end of the inode structure and the end of the inode record can be used 247*bb4ee6a4SAndroid Build Coastguard Worker /// to store extended attributes. 248*bb4ee6a4SAndroid Build Coastguard Worker pub const INODE_RECORD_SIZE: usize = 256; 249*bb4ee6a4SAndroid Build Coastguard Worker 250*bb4ee6a4SAndroid Build Coastguard Worker /// Size of the region that inline extended attributes can be written. 251*bb4ee6a4SAndroid Build Coastguard Worker pub const XATTR_AREA_SIZE: usize = Inode::INODE_RECORD_SIZE - std::mem::size_of::<Inode>(); 252*bb4ee6a4SAndroid Build Coastguard Worker new<'a>( arena: &'a Arena<'a>, group: &mut GroupMetaData, inode_num: InodeNum, typ: InodeType, size: u32, xattr: Option<InlineXattrs>, ) -> Result<&'a mut Self>253*bb4ee6a4SAndroid Build Coastguard Worker pub fn new<'a>( 254*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 255*bb4ee6a4SAndroid Build Coastguard Worker group: &mut GroupMetaData, 256*bb4ee6a4SAndroid Build Coastguard Worker inode_num: InodeNum, 257*bb4ee6a4SAndroid Build Coastguard Worker typ: InodeType, 258*bb4ee6a4SAndroid Build Coastguard Worker size: u32, 259*bb4ee6a4SAndroid Build Coastguard Worker xattr: Option<InlineXattrs>, 260*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<&'a mut Self> { 261*bb4ee6a4SAndroid Build Coastguard Worker const EXT2_S_IRUSR: u16 = 0x0100; // user read 262*bb4ee6a4SAndroid Build Coastguard Worker const EXT2_S_IXUSR: u16 = 0x0040; // user execute 263*bb4ee6a4SAndroid Build Coastguard Worker const EXT2_S_IRGRP: u16 = 0x0020; // group read 264*bb4ee6a4SAndroid Build Coastguard Worker const EXT2_S_IXGRP: u16 = 0x0008; // group execute 265*bb4ee6a4SAndroid Build Coastguard Worker const EXT2_S_IROTH: u16 = 0x0004; // others read 266*bb4ee6a4SAndroid Build Coastguard Worker const EXT2_S_IXOTH: u16 = 0x0001; // others execute 267*bb4ee6a4SAndroid Build Coastguard Worker 268*bb4ee6a4SAndroid Build Coastguard Worker let inode_offset = inode_num.to_table_index() * Inode::INODE_RECORD_SIZE; 269*bb4ee6a4SAndroid Build Coastguard Worker let inode = 270*bb4ee6a4SAndroid Build Coastguard Worker arena.allocate::<Inode>(BlockId::from(group.group_desc.inode_table), inode_offset)?; 271*bb4ee6a4SAndroid Build Coastguard Worker 272*bb4ee6a4SAndroid Build Coastguard Worker // Give read and execute permissions 273*bb4ee6a4SAndroid Build Coastguard Worker let mode = ((typ as u16) << 12) 274*bb4ee6a4SAndroid Build Coastguard Worker | EXT2_S_IRUSR 275*bb4ee6a4SAndroid Build Coastguard Worker | EXT2_S_IXUSR 276*bb4ee6a4SAndroid Build Coastguard Worker | EXT2_S_IRGRP 277*bb4ee6a4SAndroid Build Coastguard Worker | EXT2_S_IXGRP 278*bb4ee6a4SAndroid Build Coastguard Worker | EXT2_S_IROTH 279*bb4ee6a4SAndroid Build Coastguard Worker | EXT2_S_IXOTH; 280*bb4ee6a4SAndroid Build Coastguard Worker 281*bb4ee6a4SAndroid Build Coastguard Worker let now = std::time::SystemTime::now() 282*bb4ee6a4SAndroid Build Coastguard Worker .duration_since(std::time::UNIX_EPOCH)? 283*bb4ee6a4SAndroid Build Coastguard Worker .as_secs() as u32; 284*bb4ee6a4SAndroid Build Coastguard Worker 285*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: geteuid never fail. 286*bb4ee6a4SAndroid Build Coastguard Worker let uid = unsafe { libc::geteuid() }; 287*bb4ee6a4SAndroid Build Coastguard Worker let uid_high = (uid >> 16) as u16; 288*bb4ee6a4SAndroid Build Coastguard Worker let uid_low = uid as u16; 289*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: getegid never fail. 290*bb4ee6a4SAndroid Build Coastguard Worker let gid = unsafe { libc::getegid() }; 291*bb4ee6a4SAndroid Build Coastguard Worker let gid_high = (gid >> 16) as u16; 292*bb4ee6a4SAndroid Build Coastguard Worker let gid_low = gid as u16; 293*bb4ee6a4SAndroid Build Coastguard Worker 294*bb4ee6a4SAndroid Build Coastguard Worker *inode = Self { 295*bb4ee6a4SAndroid Build Coastguard Worker mode, 296*bb4ee6a4SAndroid Build Coastguard Worker size, 297*bb4ee6a4SAndroid Build Coastguard Worker atime: now, 298*bb4ee6a4SAndroid Build Coastguard Worker ctime: now, 299*bb4ee6a4SAndroid Build Coastguard Worker mtime: now, 300*bb4ee6a4SAndroid Build Coastguard Worker uid: uid_low, 301*bb4ee6a4SAndroid Build Coastguard Worker gid: gid_low, 302*bb4ee6a4SAndroid Build Coastguard Worker uid_high, 303*bb4ee6a4SAndroid Build Coastguard Worker gid_high, 304*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 305*bb4ee6a4SAndroid Build Coastguard Worker }; 306*bb4ee6a4SAndroid Build Coastguard Worker if let Some(xattr) = xattr { 307*bb4ee6a4SAndroid Build Coastguard Worker Self::add_xattr(arena, group, inode, inode_offset, xattr)?; 308*bb4ee6a4SAndroid Build Coastguard Worker } 309*bb4ee6a4SAndroid Build Coastguard Worker 310*bb4ee6a4SAndroid Build Coastguard Worker Ok(inode) 311*bb4ee6a4SAndroid Build Coastguard Worker } 312*bb4ee6a4SAndroid Build Coastguard Worker from_metadata<'a>( arena: &'a Arena<'a>, group: &mut GroupMetaData, inode_num: InodeNum, m: &std::fs::Metadata, size: u32, links_count: u16, blocks: InodeBlocksCount, block: InodeBlock, xattr: Option<InlineXattrs>, ) -> Result<&'a mut Self>313*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_metadata<'a>( 314*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 315*bb4ee6a4SAndroid Build Coastguard Worker group: &mut GroupMetaData, 316*bb4ee6a4SAndroid Build Coastguard Worker inode_num: InodeNum, 317*bb4ee6a4SAndroid Build Coastguard Worker m: &std::fs::Metadata, 318*bb4ee6a4SAndroid Build Coastguard Worker size: u32, 319*bb4ee6a4SAndroid Build Coastguard Worker links_count: u16, 320*bb4ee6a4SAndroid Build Coastguard Worker blocks: InodeBlocksCount, 321*bb4ee6a4SAndroid Build Coastguard Worker block: InodeBlock, 322*bb4ee6a4SAndroid Build Coastguard Worker xattr: Option<InlineXattrs>, 323*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<&'a mut Self> { 324*bb4ee6a4SAndroid Build Coastguard Worker let inodes_per_group = group.inode_bitmap.len(); 325*bb4ee6a4SAndroid Build Coastguard Worker // (inode_num - 1) because inode is 1-indexed. 326*bb4ee6a4SAndroid Build Coastguard Worker let inode_offset = 327*bb4ee6a4SAndroid Build Coastguard Worker ((usize::from(inode_num) - 1) % inodes_per_group) * Inode::INODE_RECORD_SIZE; 328*bb4ee6a4SAndroid Build Coastguard Worker let inode = 329*bb4ee6a4SAndroid Build Coastguard Worker arena.allocate::<Inode>(BlockId::from(group.group_desc.inode_table), inode_offset)?; 330*bb4ee6a4SAndroid Build Coastguard Worker 331*bb4ee6a4SAndroid Build Coastguard Worker let mode = m.mode() as u16; 332*bb4ee6a4SAndroid Build Coastguard Worker 333*bb4ee6a4SAndroid Build Coastguard Worker let uid = m.uid(); 334*bb4ee6a4SAndroid Build Coastguard Worker let uid_high = (uid >> 16) as u16; 335*bb4ee6a4SAndroid Build Coastguard Worker let uid_low: u16 = uid as u16; 336*bb4ee6a4SAndroid Build Coastguard Worker let gid = m.gid(); 337*bb4ee6a4SAndroid Build Coastguard Worker let gid_high = (gid >> 16) as u16; 338*bb4ee6a4SAndroid Build Coastguard Worker let gid_low: u16 = gid as u16; 339*bb4ee6a4SAndroid Build Coastguard Worker 340*bb4ee6a4SAndroid Build Coastguard Worker let atime = m.atime() as u32; 341*bb4ee6a4SAndroid Build Coastguard Worker let ctime = m.ctime() as u32; 342*bb4ee6a4SAndroid Build Coastguard Worker let mtime = m.mtime() as u32; 343*bb4ee6a4SAndroid Build Coastguard Worker 344*bb4ee6a4SAndroid Build Coastguard Worker *inode = Inode { 345*bb4ee6a4SAndroid Build Coastguard Worker mode, 346*bb4ee6a4SAndroid Build Coastguard Worker uid: uid_low, 347*bb4ee6a4SAndroid Build Coastguard Worker gid: gid_low, 348*bb4ee6a4SAndroid Build Coastguard Worker size, 349*bb4ee6a4SAndroid Build Coastguard Worker atime, 350*bb4ee6a4SAndroid Build Coastguard Worker ctime, 351*bb4ee6a4SAndroid Build Coastguard Worker mtime, 352*bb4ee6a4SAndroid Build Coastguard Worker links_count, 353*bb4ee6a4SAndroid Build Coastguard Worker blocks, 354*bb4ee6a4SAndroid Build Coastguard Worker block, 355*bb4ee6a4SAndroid Build Coastguard Worker uid_high, 356*bb4ee6a4SAndroid Build Coastguard Worker gid_high, 357*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 358*bb4ee6a4SAndroid Build Coastguard Worker }; 359*bb4ee6a4SAndroid Build Coastguard Worker 360*bb4ee6a4SAndroid Build Coastguard Worker if let Some(xattr) = xattr { 361*bb4ee6a4SAndroid Build Coastguard Worker Self::add_xattr(arena, group, inode, inode_offset, xattr)?; 362*bb4ee6a4SAndroid Build Coastguard Worker } 363*bb4ee6a4SAndroid Build Coastguard Worker 364*bb4ee6a4SAndroid Build Coastguard Worker Ok(inode) 365*bb4ee6a4SAndroid Build Coastguard Worker } 366*bb4ee6a4SAndroid Build Coastguard Worker add_xattr<'a>( arena: &'a Arena<'a>, group: &mut GroupMetaData, inode: &mut Inode, inode_offset: usize, xattr: InlineXattrs, ) -> Result<()>367*bb4ee6a4SAndroid Build Coastguard Worker fn add_xattr<'a>( 368*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 369*bb4ee6a4SAndroid Build Coastguard Worker group: &mut GroupMetaData, 370*bb4ee6a4SAndroid Build Coastguard Worker inode: &mut Inode, 371*bb4ee6a4SAndroid Build Coastguard Worker inode_offset: usize, 372*bb4ee6a4SAndroid Build Coastguard Worker xattr: InlineXattrs, 373*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 374*bb4ee6a4SAndroid Build Coastguard Worker let xattr_region = arena.allocate::<[u8; Inode::XATTR_AREA_SIZE]>( 375*bb4ee6a4SAndroid Build Coastguard Worker BlockId::from(group.group_desc.inode_table), 376*bb4ee6a4SAndroid Build Coastguard Worker inode_offset + std::mem::size_of::<Inode>(), 377*bb4ee6a4SAndroid Build Coastguard Worker )?; 378*bb4ee6a4SAndroid Build Coastguard Worker 379*bb4ee6a4SAndroid Build Coastguard Worker if !xattr.entry_table.is_empty() { 380*bb4ee6a4SAndroid Build Coastguard Worker // Linux and debugfs uses extra_size to check if inline xattr is stored so we need to 381*bb4ee6a4SAndroid Build Coastguard Worker // set a positive value here. 4 (= sizeof(extra_size) + sizeof(_paddings)) 382*bb4ee6a4SAndroid Build Coastguard Worker // is the smallest value. 383*bb4ee6a4SAndroid Build Coastguard Worker inode.extra_size = 4; 384*bb4ee6a4SAndroid Build Coastguard Worker let InlineXattrs { 385*bb4ee6a4SAndroid Build Coastguard Worker entry_table, 386*bb4ee6a4SAndroid Build Coastguard Worker values, 387*bb4ee6a4SAndroid Build Coastguard Worker } = xattr; 388*bb4ee6a4SAndroid Build Coastguard Worker 389*bb4ee6a4SAndroid Build Coastguard Worker if entry_table.len() + values.len() > Inode::XATTR_AREA_SIZE { 390*bb4ee6a4SAndroid Build Coastguard Worker bail!("xattr size is too large for inline store: entry_table.len={}, values.len={}, inline region size={}", 391*bb4ee6a4SAndroid Build Coastguard Worker entry_table.len(), values.len(), Inode::XATTR_AREA_SIZE); 392*bb4ee6a4SAndroid Build Coastguard Worker } 393*bb4ee6a4SAndroid Build Coastguard Worker // `entry_table` should be aligned to the beginning of the region. 394*bb4ee6a4SAndroid Build Coastguard Worker xattr_region[..entry_table.len()].copy_from_slice(&entry_table); 395*bb4ee6a4SAndroid Build Coastguard Worker xattr_region[Inode::XATTR_AREA_SIZE - values.len()..].copy_from_slice(&values); 396*bb4ee6a4SAndroid Build Coastguard Worker } 397*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 398*bb4ee6a4SAndroid Build Coastguard Worker } 399*bb4ee6a4SAndroid Build Coastguard Worker update_metadata(&mut self, m: &std::fs::Metadata)400*bb4ee6a4SAndroid Build Coastguard Worker pub fn update_metadata(&mut self, m: &std::fs::Metadata) { 401*bb4ee6a4SAndroid Build Coastguard Worker self.mode = m.mode() as u16; 402*bb4ee6a4SAndroid Build Coastguard Worker 403*bb4ee6a4SAndroid Build Coastguard Worker let uid: u32 = m.uid(); 404*bb4ee6a4SAndroid Build Coastguard Worker self.uid_high = (uid >> 16) as u16; 405*bb4ee6a4SAndroid Build Coastguard Worker self.uid = uid as u16; 406*bb4ee6a4SAndroid Build Coastguard Worker let gid = m.gid(); 407*bb4ee6a4SAndroid Build Coastguard Worker self.gid_high = (gid >> 16) as u16; 408*bb4ee6a4SAndroid Build Coastguard Worker self.gid = gid as u16; 409*bb4ee6a4SAndroid Build Coastguard Worker 410*bb4ee6a4SAndroid Build Coastguard Worker self.atime = m.atime() as u32; 411*bb4ee6a4SAndroid Build Coastguard Worker self.ctime = m.ctime() as u32; 412*bb4ee6a4SAndroid Build Coastguard Worker self.mtime = m.mtime() as u32; 413*bb4ee6a4SAndroid Build Coastguard Worker } 414*bb4ee6a4SAndroid Build Coastguard Worker typ(&self) -> Option<InodeType>415*bb4ee6a4SAndroid Build Coastguard Worker pub fn typ(&self) -> Option<InodeType> { 416*bb4ee6a4SAndroid Build Coastguard Worker InodeType::n((self.mode >> 12) as u8) 417*bb4ee6a4SAndroid Build Coastguard Worker } 418*bb4ee6a4SAndroid Build Coastguard Worker } 419*bb4ee6a4SAndroid Build Coastguard Worker 420*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 421*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 422*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 423*bb4ee6a4SAndroid Build Coastguard Worker 424*bb4ee6a4SAndroid Build Coastguard Worker #[test] test_inode_size()425*bb4ee6a4SAndroid Build Coastguard Worker fn test_inode_size() { 426*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(std::mem::offset_of!(Inode, extra_size), 128); 427*bb4ee6a4SAndroid Build Coastguard Worker // Check that no implicit paddings is inserted after the padding field. 428*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 429*bb4ee6a4SAndroid Build Coastguard Worker std::mem::offset_of!(Inode, _paddings) + std::mem::size_of::<u16>(), 430*bb4ee6a4SAndroid Build Coastguard Worker std::mem::size_of::<Inode>() 431*bb4ee6a4SAndroid Build Coastguard Worker ); 432*bb4ee6a4SAndroid Build Coastguard Worker 433*bb4ee6a4SAndroid Build Coastguard Worker assert!(128 < std::mem::size_of::<Inode>()); 434*bb4ee6a4SAndroid Build Coastguard Worker assert!(std::mem::size_of::<Inode>() <= Inode::INODE_RECORD_SIZE); 435*bb4ee6a4SAndroid Build Coastguard Worker } 436*bb4ee6a4SAndroid Build Coastguard Worker } 437