xref: /aosp_15_r20/external/crosvm/ext2/src/inode.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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