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 a struct to represent an ext2 filesystem and implements methods to create 6*bb4ee6a4SAndroid Build Coastguard Worker // a filesystem in memory. 7*bb4ee6a4SAndroid Build Coastguard Worker 8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap; 9*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::OsStr; 10*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::OsString; 11*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::DirEntry; 12*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File; 13*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::ffi::OsStrExt; 14*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path; 15*bb4ee6a4SAndroid Build Coastguard Worker 16*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow; 17*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail; 18*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context; 19*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 20*bb4ee6a4SAndroid Build Coastguard Worker use base::info; 21*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes; 22*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes; 23*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes; 24*bb4ee6a4SAndroid Build Coastguard Worker 25*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::Arena; 26*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::BlockId; 27*bb4ee6a4SAndroid Build Coastguard Worker use crate::blockgroup::BlockGroupDescriptor; 28*bb4ee6a4SAndroid Build Coastguard Worker use crate::blockgroup::GroupMetaData; 29*bb4ee6a4SAndroid Build Coastguard Worker use crate::blockgroup::BLOCK_SIZE; 30*bb4ee6a4SAndroid Build Coastguard Worker use crate::builder::Builder; 31*bb4ee6a4SAndroid Build Coastguard Worker use crate::inode::Inode; 32*bb4ee6a4SAndroid Build Coastguard Worker use crate::inode::InodeBlock; 33*bb4ee6a4SAndroid Build Coastguard Worker use crate::inode::InodeBlocksCount; 34*bb4ee6a4SAndroid Build Coastguard Worker use crate::inode::InodeNum; 35*bb4ee6a4SAndroid Build Coastguard Worker use crate::inode::InodeType; 36*bb4ee6a4SAndroid Build Coastguard Worker use crate::superblock::SuperBlock; 37*bb4ee6a4SAndroid Build Coastguard Worker use crate::xattr::InlineXattrs; 38*bb4ee6a4SAndroid Build Coastguard Worker 39*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 40*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes, AsBytes, Debug)] 41*bb4ee6a4SAndroid Build Coastguard Worker struct DirEntryRaw { 42*bb4ee6a4SAndroid Build Coastguard Worker inode: u32, 43*bb4ee6a4SAndroid Build Coastguard Worker rec_len: u16, 44*bb4ee6a4SAndroid Build Coastguard Worker name_len: u8, 45*bb4ee6a4SAndroid Build Coastguard Worker file_type: u8, 46*bb4ee6a4SAndroid Build Coastguard Worker } 47*bb4ee6a4SAndroid Build Coastguard Worker 48*bb4ee6a4SAndroid Build Coastguard Worker struct DirEntryWithName<'a> { 49*bb4ee6a4SAndroid Build Coastguard Worker de: &'a mut DirEntryRaw, 50*bb4ee6a4SAndroid Build Coastguard Worker name: OsString, 51*bb4ee6a4SAndroid Build Coastguard Worker } 52*bb4ee6a4SAndroid Build Coastguard Worker 53*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> std::fmt::Debug for DirEntryWithName<'a> { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result54*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 55*bb4ee6a4SAndroid Build Coastguard Worker f.debug_struct("DirEntry") 56*bb4ee6a4SAndroid Build Coastguard Worker .field("de", &self.de) 57*bb4ee6a4SAndroid Build Coastguard Worker .field("name", &self.name) 58*bb4ee6a4SAndroid Build Coastguard Worker .finish() 59*bb4ee6a4SAndroid Build Coastguard Worker } 60*bb4ee6a4SAndroid Build Coastguard Worker } 61*bb4ee6a4SAndroid Build Coastguard Worker 62*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> DirEntryWithName<'a> { new( arena: &'a Arena<'a>, inode: InodeNum, typ: InodeType, name_str: &OsStr, dblock: &mut DirEntryBlock, ) -> Result<Self>63*bb4ee6a4SAndroid Build Coastguard Worker fn new( 64*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 65*bb4ee6a4SAndroid Build Coastguard Worker inode: InodeNum, 66*bb4ee6a4SAndroid Build Coastguard Worker typ: InodeType, 67*bb4ee6a4SAndroid Build Coastguard Worker name_str: &OsStr, 68*bb4ee6a4SAndroid Build Coastguard Worker dblock: &mut DirEntryBlock, 69*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Self> { 70*bb4ee6a4SAndroid Build Coastguard Worker let cs = name_str.as_bytes(); 71*bb4ee6a4SAndroid Build Coastguard Worker let name_len = cs.len(); 72*bb4ee6a4SAndroid Build Coastguard Worker let aligned_name_len = name_len 73*bb4ee6a4SAndroid Build Coastguard Worker .checked_next_multiple_of(4) 74*bb4ee6a4SAndroid Build Coastguard Worker .expect("name length must be 4-byte aligned"); 75*bb4ee6a4SAndroid Build Coastguard Worker 76*bb4ee6a4SAndroid Build Coastguard Worker // rec_len = |inode| + |file_type| + |name_len| + |rec_len| + name + padding 77*bb4ee6a4SAndroid Build Coastguard Worker // = 4 + 1 + 1 + 2 + |name| + padding 78*bb4ee6a4SAndroid Build Coastguard Worker // = 8 + |name| + padding 79*bb4ee6a4SAndroid Build Coastguard Worker // The padding is inserted because the name is 4-byte aligned. 80*bb4ee6a4SAndroid Build Coastguard Worker let rec_len = 8 + aligned_name_len as u16; 81*bb4ee6a4SAndroid Build Coastguard Worker 82*bb4ee6a4SAndroid Build Coastguard Worker let de = arena.allocate(dblock.block_id, dblock.offset)?; 83*bb4ee6a4SAndroid Build Coastguard Worker *de = DirEntryRaw { 84*bb4ee6a4SAndroid Build Coastguard Worker inode: inode.into(), 85*bb4ee6a4SAndroid Build Coastguard Worker rec_len, 86*bb4ee6a4SAndroid Build Coastguard Worker name_len: name_len as u8, 87*bb4ee6a4SAndroid Build Coastguard Worker file_type: typ.into_dir_entry_file_type(), 88*bb4ee6a4SAndroid Build Coastguard Worker }; 89*bb4ee6a4SAndroid Build Coastguard Worker dblock.offset += std::mem::size_of::<DirEntryRaw>(); 90*bb4ee6a4SAndroid Build Coastguard Worker 91*bb4ee6a4SAndroid Build Coastguard Worker let name_slice = arena.allocate_slice(dblock.block_id, dblock.offset, aligned_name_len)?; 92*bb4ee6a4SAndroid Build Coastguard Worker dblock.offset += aligned_name_len; 93*bb4ee6a4SAndroid Build Coastguard Worker name_slice[..cs.len()].copy_from_slice(cs); 94*bb4ee6a4SAndroid Build Coastguard Worker 95*bb4ee6a4SAndroid Build Coastguard Worker if dblock.entries.is_empty() { 96*bb4ee6a4SAndroid Build Coastguard Worker de.rec_len = BLOCK_SIZE as u16; 97*bb4ee6a4SAndroid Build Coastguard Worker } else { 98*bb4ee6a4SAndroid Build Coastguard Worker let last = dblock 99*bb4ee6a4SAndroid Build Coastguard Worker .entries 100*bb4ee6a4SAndroid Build Coastguard Worker .last_mut() 101*bb4ee6a4SAndroid Build Coastguard Worker .expect("parent_dir must not be empty"); 102*bb4ee6a4SAndroid Build Coastguard Worker let last_rec_len = last.de.rec_len; 103*bb4ee6a4SAndroid Build Coastguard Worker last.de.rec_len = (8 + last.name.as_os_str().as_bytes().len() as u16) 104*bb4ee6a4SAndroid Build Coastguard Worker .checked_next_multiple_of(4) 105*bb4ee6a4SAndroid Build Coastguard Worker .expect("overflow to calculate rec_len"); 106*bb4ee6a4SAndroid Build Coastguard Worker de.rec_len = last_rec_len - last.de.rec_len; 107*bb4ee6a4SAndroid Build Coastguard Worker } 108*bb4ee6a4SAndroid Build Coastguard Worker 109*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self { 110*bb4ee6a4SAndroid Build Coastguard Worker de, 111*bb4ee6a4SAndroid Build Coastguard Worker name: name_str.into(), 112*bb4ee6a4SAndroid Build Coastguard Worker }) 113*bb4ee6a4SAndroid Build Coastguard Worker } 114*bb4ee6a4SAndroid Build Coastguard Worker } 115*bb4ee6a4SAndroid Build Coastguard Worker 116*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)] 117*bb4ee6a4SAndroid Build Coastguard Worker struct DirEntryBlock<'a> { 118*bb4ee6a4SAndroid Build Coastguard Worker block_id: BlockId, 119*bb4ee6a4SAndroid Build Coastguard Worker offset: usize, 120*bb4ee6a4SAndroid Build Coastguard Worker entries: Vec<DirEntryWithName<'a>>, 121*bb4ee6a4SAndroid Build Coastguard Worker } 122*bb4ee6a4SAndroid Build Coastguard Worker 123*bb4ee6a4SAndroid Build Coastguard Worker impl DirEntryBlock<'_> { has_enough_space(&self, name: &OsStr) -> bool124*bb4ee6a4SAndroid Build Coastguard Worker fn has_enough_space(&self, name: &OsStr) -> bool { 125*bb4ee6a4SAndroid Build Coastguard Worker let dir_entry_size = std::mem::size_of::<DirEntryRaw>(); 126*bb4ee6a4SAndroid Build Coastguard Worker let aligned_name_len = name 127*bb4ee6a4SAndroid Build Coastguard Worker .as_bytes() 128*bb4ee6a4SAndroid Build Coastguard Worker .len() 129*bb4ee6a4SAndroid Build Coastguard Worker .checked_next_multiple_of(4) 130*bb4ee6a4SAndroid Build Coastguard Worker .expect("length must be < 256 bytes so it must not overflow"); 131*bb4ee6a4SAndroid Build Coastguard Worker self.offset + dir_entry_size + aligned_name_len <= BLOCK_SIZE 132*bb4ee6a4SAndroid Build Coastguard Worker } 133*bb4ee6a4SAndroid Build Coastguard Worker } 134*bb4ee6a4SAndroid Build Coastguard Worker 135*bb4ee6a4SAndroid Build Coastguard Worker /// A struct to represent an ext2 filesystem. 136*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) struct Ext2<'a> { 137*bb4ee6a4SAndroid Build Coastguard Worker sb: &'a mut SuperBlock, 138*bb4ee6a4SAndroid Build Coastguard Worker cur_block_group: usize, 139*bb4ee6a4SAndroid Build Coastguard Worker cur_inode_table: usize, 140*bb4ee6a4SAndroid Build Coastguard Worker 141*bb4ee6a4SAndroid Build Coastguard Worker group_metadata: Vec<GroupMetaData<'a>>, 142*bb4ee6a4SAndroid Build Coastguard Worker 143*bb4ee6a4SAndroid Build Coastguard Worker dir_entries: BTreeMap<InodeNum, Vec<DirEntryBlock<'a>>>, 144*bb4ee6a4SAndroid Build Coastguard Worker } 145*bb4ee6a4SAndroid Build Coastguard Worker 146*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> Ext2<'a> { new(builder: &Builder, arena: &'a Arena<'a>) -> Result<Self>147*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn new(builder: &Builder, arena: &'a Arena<'a>) -> Result<Self> { 148*bb4ee6a4SAndroid Build Coastguard Worker let sb = SuperBlock::new(arena, builder)?; 149*bb4ee6a4SAndroid Build Coastguard Worker let mut group_metadata = vec![]; 150*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..sb.num_groups() { 151*bb4ee6a4SAndroid Build Coastguard Worker group_metadata.push(GroupMetaData::new(arena, sb, i)?); 152*bb4ee6a4SAndroid Build Coastguard Worker } 153*bb4ee6a4SAndroid Build Coastguard Worker 154*bb4ee6a4SAndroid Build Coastguard Worker let mut ext2 = Ext2 { 155*bb4ee6a4SAndroid Build Coastguard Worker sb, 156*bb4ee6a4SAndroid Build Coastguard Worker cur_block_group: 0, 157*bb4ee6a4SAndroid Build Coastguard Worker cur_inode_table: 0, 158*bb4ee6a4SAndroid Build Coastguard Worker group_metadata, 159*bb4ee6a4SAndroid Build Coastguard Worker dir_entries: BTreeMap::new(), 160*bb4ee6a4SAndroid Build Coastguard Worker }; 161*bb4ee6a4SAndroid Build Coastguard Worker 162*bb4ee6a4SAndroid Build Coastguard Worker // Add rootdir 163*bb4ee6a4SAndroid Build Coastguard Worker let root_inode = InodeNum::new(2)?; 164*bb4ee6a4SAndroid Build Coastguard Worker let root_xattr = match &builder.root_dir { 165*bb4ee6a4SAndroid Build Coastguard Worker Some(dir) => Some(InlineXattrs::from_path(dir)?), 166*bb4ee6a4SAndroid Build Coastguard Worker None => None, 167*bb4ee6a4SAndroid Build Coastguard Worker }; 168*bb4ee6a4SAndroid Build Coastguard Worker ext2.add_reserved_dir(arena, root_inode, root_inode, OsStr::new("/"), root_xattr)?; 169*bb4ee6a4SAndroid Build Coastguard Worker let lost_found_inode = ext2.allocate_inode()?; 170*bb4ee6a4SAndroid Build Coastguard Worker ext2.add_reserved_dir( 171*bb4ee6a4SAndroid Build Coastguard Worker arena, 172*bb4ee6a4SAndroid Build Coastguard Worker lost_found_inode, 173*bb4ee6a4SAndroid Build Coastguard Worker root_inode, 174*bb4ee6a4SAndroid Build Coastguard Worker OsStr::new("lost+found"), 175*bb4ee6a4SAndroid Build Coastguard Worker None, 176*bb4ee6a4SAndroid Build Coastguard Worker )?; 177*bb4ee6a4SAndroid Build Coastguard Worker 178*bb4ee6a4SAndroid Build Coastguard Worker Ok(ext2) 179*bb4ee6a4SAndroid Build Coastguard Worker } 180*bb4ee6a4SAndroid Build Coastguard Worker allocate_inode(&mut self) -> Result<InodeNum>181*bb4ee6a4SAndroid Build Coastguard Worker fn allocate_inode(&mut self) -> Result<InodeNum> { 182*bb4ee6a4SAndroid Build Coastguard Worker if self.sb.free_inodes_count == 0 { 183*bb4ee6a4SAndroid Build Coastguard Worker bail!( 184*bb4ee6a4SAndroid Build Coastguard Worker "no free inodes: run out of s_inodes_count={}", 185*bb4ee6a4SAndroid Build Coastguard Worker self.sb.inodes_count 186*bb4ee6a4SAndroid Build Coastguard Worker ); 187*bb4ee6a4SAndroid Build Coastguard Worker } 188*bb4ee6a4SAndroid Build Coastguard Worker 189*bb4ee6a4SAndroid Build Coastguard Worker if self.group_metadata[self.cur_inode_table] 190*bb4ee6a4SAndroid Build Coastguard Worker .group_desc 191*bb4ee6a4SAndroid Build Coastguard Worker .free_inodes_count 192*bb4ee6a4SAndroid Build Coastguard Worker == 0 193*bb4ee6a4SAndroid Build Coastguard Worker { 194*bb4ee6a4SAndroid Build Coastguard Worker self.cur_inode_table += 1; 195*bb4ee6a4SAndroid Build Coastguard Worker } 196*bb4ee6a4SAndroid Build Coastguard Worker 197*bb4ee6a4SAndroid Build Coastguard Worker let gm = &mut self.group_metadata[self.cur_inode_table]; 198*bb4ee6a4SAndroid Build Coastguard Worker let alloc_inode = InodeNum::new(gm.first_free_inode)?; 199*bb4ee6a4SAndroid Build Coastguard Worker // (alloc_inode - 1) because inode is 1-indexed. 200*bb4ee6a4SAndroid Build Coastguard Worker gm.inode_bitmap 201*bb4ee6a4SAndroid Build Coastguard Worker .set( 202*bb4ee6a4SAndroid Build Coastguard Worker (usize::from(alloc_inode) - 1) % self.sb.inodes_per_group as usize, 203*bb4ee6a4SAndroid Build Coastguard Worker true, 204*bb4ee6a4SAndroid Build Coastguard Worker ) 205*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to set inode bitmap")?; 206*bb4ee6a4SAndroid Build Coastguard Worker 207*bb4ee6a4SAndroid Build Coastguard Worker gm.first_free_inode += 1; 208*bb4ee6a4SAndroid Build Coastguard Worker gm.group_desc.free_inodes_count -= 1; 209*bb4ee6a4SAndroid Build Coastguard Worker self.sb.free_inodes_count -= 1; 210*bb4ee6a4SAndroid Build Coastguard Worker Ok(alloc_inode) 211*bb4ee6a4SAndroid Build Coastguard Worker } 212*bb4ee6a4SAndroid Build Coastguard Worker allocate_block(&mut self) -> Result<BlockId>213*bb4ee6a4SAndroid Build Coastguard Worker fn allocate_block(&mut self) -> Result<BlockId> { 214*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_contiguous_blocks(1).map(|v| v[0][0]) 215*bb4ee6a4SAndroid Build Coastguard Worker } 216*bb4ee6a4SAndroid Build Coastguard Worker allocate_contiguous_blocks(&mut self, n: u16) -> Result<Vec<Vec<BlockId>>>217*bb4ee6a4SAndroid Build Coastguard Worker fn allocate_contiguous_blocks(&mut self, n: u16) -> Result<Vec<Vec<BlockId>>> { 218*bb4ee6a4SAndroid Build Coastguard Worker if n == 0 { 219*bb4ee6a4SAndroid Build Coastguard Worker bail!("n must be positive"); 220*bb4ee6a4SAndroid Build Coastguard Worker } 221*bb4ee6a4SAndroid Build Coastguard Worker if self.sb.free_blocks_count < n as u32 { 222*bb4ee6a4SAndroid Build Coastguard Worker bail!( 223*bb4ee6a4SAndroid Build Coastguard Worker "no free blocks: run out of free_blocks_count={} < {n}", 224*bb4ee6a4SAndroid Build Coastguard Worker self.sb.free_blocks_count 225*bb4ee6a4SAndroid Build Coastguard Worker ); 226*bb4ee6a4SAndroid Build Coastguard Worker } 227*bb4ee6a4SAndroid Build Coastguard Worker 228*bb4ee6a4SAndroid Build Coastguard Worker let mut contig_blocks = vec![]; 229*bb4ee6a4SAndroid Build Coastguard Worker let mut remaining = n; 230*bb4ee6a4SAndroid Build Coastguard Worker while remaining > 0 { 231*bb4ee6a4SAndroid Build Coastguard Worker let alloc_block_num = std::cmp::min( 232*bb4ee6a4SAndroid Build Coastguard Worker remaining, 233*bb4ee6a4SAndroid Build Coastguard Worker self.group_metadata[self.cur_block_group] 234*bb4ee6a4SAndroid Build Coastguard Worker .group_desc 235*bb4ee6a4SAndroid Build Coastguard Worker .free_blocks_count, 236*bb4ee6a4SAndroid Build Coastguard Worker ) as u32; 237*bb4ee6a4SAndroid Build Coastguard Worker 238*bb4ee6a4SAndroid Build Coastguard Worker let gm = &mut self.group_metadata[self.cur_block_group]; 239*bb4ee6a4SAndroid Build Coastguard Worker let alloc_blocks = (gm.first_free_block..gm.first_free_block + alloc_block_num) 240*bb4ee6a4SAndroid Build Coastguard Worker .map(BlockId::from) 241*bb4ee6a4SAndroid Build Coastguard Worker .collect(); 242*bb4ee6a4SAndroid Build Coastguard Worker gm.first_free_block += alloc_block_num; 243*bb4ee6a4SAndroid Build Coastguard Worker gm.group_desc.free_blocks_count -= alloc_block_num as u16; 244*bb4ee6a4SAndroid Build Coastguard Worker self.sb.free_blocks_count -= alloc_block_num; 245*bb4ee6a4SAndroid Build Coastguard Worker for &b in &alloc_blocks { 246*bb4ee6a4SAndroid Build Coastguard Worker let index = u32::from(b) as usize 247*bb4ee6a4SAndroid Build Coastguard Worker - self.cur_block_group * self.sb.blocks_per_group as usize; 248*bb4ee6a4SAndroid Build Coastguard Worker gm.block_bitmap 249*bb4ee6a4SAndroid Build Coastguard Worker .set(index, true) 250*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| format!("failed to set block_bitmap at {index}"))?; 251*bb4ee6a4SAndroid Build Coastguard Worker } 252*bb4ee6a4SAndroid Build Coastguard Worker remaining -= alloc_block_num as u16; 253*bb4ee6a4SAndroid Build Coastguard Worker if self.group_metadata[self.cur_block_group] 254*bb4ee6a4SAndroid Build Coastguard Worker .group_desc 255*bb4ee6a4SAndroid Build Coastguard Worker .free_blocks_count 256*bb4ee6a4SAndroid Build Coastguard Worker == 0 257*bb4ee6a4SAndroid Build Coastguard Worker { 258*bb4ee6a4SAndroid Build Coastguard Worker self.cur_block_group += 1; 259*bb4ee6a4SAndroid Build Coastguard Worker } 260*bb4ee6a4SAndroid Build Coastguard Worker contig_blocks.push(alloc_blocks); 261*bb4ee6a4SAndroid Build Coastguard Worker } 262*bb4ee6a4SAndroid Build Coastguard Worker 263*bb4ee6a4SAndroid Build Coastguard Worker Ok(contig_blocks) 264*bb4ee6a4SAndroid Build Coastguard Worker } 265*bb4ee6a4SAndroid Build Coastguard Worker group_num_for_inode(&self, inode: InodeNum) -> usize266*bb4ee6a4SAndroid Build Coastguard Worker fn group_num_for_inode(&self, inode: InodeNum) -> usize { 267*bb4ee6a4SAndroid Build Coastguard Worker inode.to_table_index() / self.sb.inodes_per_group as usize 268*bb4ee6a4SAndroid Build Coastguard Worker } 269*bb4ee6a4SAndroid Build Coastguard Worker get_inode_mut(&mut self, num: InodeNum) -> Result<&mut &'a mut Inode>270*bb4ee6a4SAndroid Build Coastguard Worker fn get_inode_mut(&mut self, num: InodeNum) -> Result<&mut &'a mut Inode> { 271*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(num); 272*bb4ee6a4SAndroid Build Coastguard Worker self.group_metadata[group_id] 273*bb4ee6a4SAndroid Build Coastguard Worker .inode_table 274*bb4ee6a4SAndroid Build Coastguard Worker .get_mut(&num) 275*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("{:?} not found", num)) 276*bb4ee6a4SAndroid Build Coastguard Worker } 277*bb4ee6a4SAndroid Build Coastguard Worker allocate_dir_entry( &mut self, arena: &'a Arena<'a>, parent: InodeNum, inode: InodeNum, typ: InodeType, name: &OsStr, ) -> Result<()>278*bb4ee6a4SAndroid Build Coastguard Worker fn allocate_dir_entry( 279*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 280*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 281*bb4ee6a4SAndroid Build Coastguard Worker parent: InodeNum, 282*bb4ee6a4SAndroid Build Coastguard Worker inode: InodeNum, 283*bb4ee6a4SAndroid Build Coastguard Worker typ: InodeType, 284*bb4ee6a4SAndroid Build Coastguard Worker name: &OsStr, 285*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 286*bb4ee6a4SAndroid Build Coastguard Worker if name.is_empty() { 287*bb4ee6a4SAndroid Build Coastguard Worker bail!("directory name must not be empty"); 288*bb4ee6a4SAndroid Build Coastguard Worker } else if name.len() > 255 { 289*bb4ee6a4SAndroid Build Coastguard Worker bail!("name length must not exceed 255: {:?}", name); 290*bb4ee6a4SAndroid Build Coastguard Worker } 291*bb4ee6a4SAndroid Build Coastguard Worker 292*bb4ee6a4SAndroid Build Coastguard Worker // Disable false-positive `clippy::map_entry`. 293*bb4ee6a4SAndroid Build Coastguard Worker // https://github.com/rust-lang/rust-clippy/issues/9470 294*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::map_entry)] 295*bb4ee6a4SAndroid Build Coastguard Worker if !self.dir_entries.contains_key(&parent) { 296*bb4ee6a4SAndroid Build Coastguard Worker let block_id = self.allocate_block()?; 297*bb4ee6a4SAndroid Build Coastguard Worker let inode = self.get_inode_mut(parent)?; 298*bb4ee6a4SAndroid Build Coastguard Worker inode.block.set_direct_blocks(&[block_id])?; 299*bb4ee6a4SAndroid Build Coastguard Worker inode.blocks = InodeBlocksCount::from_bytes_len(BLOCK_SIZE as u32); 300*bb4ee6a4SAndroid Build Coastguard Worker self.dir_entries.insert( 301*bb4ee6a4SAndroid Build Coastguard Worker parent, 302*bb4ee6a4SAndroid Build Coastguard Worker vec![DirEntryBlock { 303*bb4ee6a4SAndroid Build Coastguard Worker block_id, 304*bb4ee6a4SAndroid Build Coastguard Worker offset: 0, 305*bb4ee6a4SAndroid Build Coastguard Worker entries: Vec::new(), 306*bb4ee6a4SAndroid Build Coastguard Worker }], 307*bb4ee6a4SAndroid Build Coastguard Worker ); 308*bb4ee6a4SAndroid Build Coastguard Worker } 309*bb4ee6a4SAndroid Build Coastguard Worker 310*bb4ee6a4SAndroid Build Coastguard Worker // Allocates a new block for dir entries if needed. 311*bb4ee6a4SAndroid Build Coastguard Worker if !self 312*bb4ee6a4SAndroid Build Coastguard Worker .dir_entries 313*bb4ee6a4SAndroid Build Coastguard Worker .get(&parent) 314*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("parent {:?} not found for {:?}", parent, inode))? 315*bb4ee6a4SAndroid Build Coastguard Worker .last() 316*bb4ee6a4SAndroid Build Coastguard Worker .expect("directory entries must not be empty") 317*bb4ee6a4SAndroid Build Coastguard Worker .has_enough_space(name) 318*bb4ee6a4SAndroid Build Coastguard Worker { 319*bb4ee6a4SAndroid Build Coastguard Worker let idx = self.dir_entries.get(&parent).unwrap().len(); 320*bb4ee6a4SAndroid Build Coastguard Worker let block_id = self.allocate_block()?; 321*bb4ee6a4SAndroid Build Coastguard Worker let parent_inode = self.get_inode_mut(parent)?; 322*bb4ee6a4SAndroid Build Coastguard Worker parent_inode.block.set_block_id(idx, &block_id)?; 323*bb4ee6a4SAndroid Build Coastguard Worker parent_inode.blocks.add(BLOCK_SIZE as u32); 324*bb4ee6a4SAndroid Build Coastguard Worker parent_inode.size += BLOCK_SIZE as u32; 325*bb4ee6a4SAndroid Build Coastguard Worker self.dir_entries 326*bb4ee6a4SAndroid Build Coastguard Worker .get_mut(&parent) 327*bb4ee6a4SAndroid Build Coastguard Worker .unwrap() 328*bb4ee6a4SAndroid Build Coastguard Worker .push(DirEntryBlock { 329*bb4ee6a4SAndroid Build Coastguard Worker block_id, 330*bb4ee6a4SAndroid Build Coastguard Worker offset: 0, 331*bb4ee6a4SAndroid Build Coastguard Worker entries: Vec::new(), 332*bb4ee6a4SAndroid Build Coastguard Worker }); 333*bb4ee6a4SAndroid Build Coastguard Worker } 334*bb4ee6a4SAndroid Build Coastguard Worker 335*bb4ee6a4SAndroid Build Coastguard Worker if typ == InodeType::Directory { 336*bb4ee6a4SAndroid Build Coastguard Worker let parent = self.get_inode_mut(parent)?; 337*bb4ee6a4SAndroid Build Coastguard Worker parent.links_count += 1; 338*bb4ee6a4SAndroid Build Coastguard Worker } 339*bb4ee6a4SAndroid Build Coastguard Worker 340*bb4ee6a4SAndroid Build Coastguard Worker let parent_dir = self 341*bb4ee6a4SAndroid Build Coastguard Worker .dir_entries 342*bb4ee6a4SAndroid Build Coastguard Worker .get_mut(&parent) 343*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("parent {:?} not found for {:?}", parent, inode))? 344*bb4ee6a4SAndroid Build Coastguard Worker .last_mut() 345*bb4ee6a4SAndroid Build Coastguard Worker .expect("directory entries must not be empty"); 346*bb4ee6a4SAndroid Build Coastguard Worker 347*bb4ee6a4SAndroid Build Coastguard Worker let dir_entry = DirEntryWithName::new(arena, inode, typ, name, parent_dir)?; 348*bb4ee6a4SAndroid Build Coastguard Worker 349*bb4ee6a4SAndroid Build Coastguard Worker parent_dir.entries.push(dir_entry); 350*bb4ee6a4SAndroid Build Coastguard Worker 351*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 352*bb4ee6a4SAndroid Build Coastguard Worker } 353*bb4ee6a4SAndroid Build Coastguard Worker add_inode(&mut self, num: InodeNum, inode: &'a mut Inode) -> Result<()>354*bb4ee6a4SAndroid Build Coastguard Worker fn add_inode(&mut self, num: InodeNum, inode: &'a mut Inode) -> Result<()> { 355*bb4ee6a4SAndroid Build Coastguard Worker let typ = inode.typ().ok_or_else(|| anyhow!("unknown inode type"))?; 356*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(num); 357*bb4ee6a4SAndroid Build Coastguard Worker let gm = &mut self.group_metadata[group_id]; 358*bb4ee6a4SAndroid Build Coastguard Worker if gm.inode_table.contains_key(&num) { 359*bb4ee6a4SAndroid Build Coastguard Worker bail!("inode {:?} already exists", &num); 360*bb4ee6a4SAndroid Build Coastguard Worker } 361*bb4ee6a4SAndroid Build Coastguard Worker 362*bb4ee6a4SAndroid Build Coastguard Worker if typ == InodeType::Directory { 363*bb4ee6a4SAndroid Build Coastguard Worker gm.group_desc.used_dirs_count += 1; 364*bb4ee6a4SAndroid Build Coastguard Worker } 365*bb4ee6a4SAndroid Build Coastguard Worker 366*bb4ee6a4SAndroid Build Coastguard Worker gm.inode_table.insert(num, inode); 367*bb4ee6a4SAndroid Build Coastguard Worker let inode_index = num.to_table_index() % self.sb.inodes_per_group as usize; 368*bb4ee6a4SAndroid Build Coastguard Worker gm.inode_bitmap 369*bb4ee6a4SAndroid Build Coastguard Worker .set(inode_index, true) 370*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| format!("failed to set inode bitmap at {}", num.to_table_index()))?; 371*bb4ee6a4SAndroid Build Coastguard Worker 372*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 373*bb4ee6a4SAndroid Build Coastguard Worker } 374*bb4ee6a4SAndroid Build Coastguard Worker 375*bb4ee6a4SAndroid Build Coastguard Worker // Creates a reserved directory such as "root" or "lost+found". 376*bb4ee6a4SAndroid Build Coastguard Worker // So, inode is constructed from scratch. add_reserved_dir( &mut self, arena: &'a Arena<'a>, inode_num: InodeNum, parent_inode: InodeNum, name: &OsStr, xattr: Option<InlineXattrs>, ) -> Result<()>377*bb4ee6a4SAndroid Build Coastguard Worker fn add_reserved_dir( 378*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 379*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 380*bb4ee6a4SAndroid Build Coastguard Worker inode_num: InodeNum, 381*bb4ee6a4SAndroid Build Coastguard Worker parent_inode: InodeNum, 382*bb4ee6a4SAndroid Build Coastguard Worker name: &OsStr, 383*bb4ee6a4SAndroid Build Coastguard Worker xattr: Option<InlineXattrs>, 384*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 385*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(inode_num); 386*bb4ee6a4SAndroid Build Coastguard Worker let inode = Inode::new( 387*bb4ee6a4SAndroid Build Coastguard Worker arena, 388*bb4ee6a4SAndroid Build Coastguard Worker &mut self.group_metadata[group_id], 389*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 390*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Directory, 391*bb4ee6a4SAndroid Build Coastguard Worker BLOCK_SIZE as u32, 392*bb4ee6a4SAndroid Build Coastguard Worker xattr, 393*bb4ee6a4SAndroid Build Coastguard Worker )?; 394*bb4ee6a4SAndroid Build Coastguard Worker self.add_inode(inode_num, inode)?; 395*bb4ee6a4SAndroid Build Coastguard Worker 396*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry( 397*bb4ee6a4SAndroid Build Coastguard Worker arena, 398*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 399*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 400*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Directory, 401*bb4ee6a4SAndroid Build Coastguard Worker OsStr::new("."), 402*bb4ee6a4SAndroid Build Coastguard Worker )?; 403*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry( 404*bb4ee6a4SAndroid Build Coastguard Worker arena, 405*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 406*bb4ee6a4SAndroid Build Coastguard Worker parent_inode, 407*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Directory, 408*bb4ee6a4SAndroid Build Coastguard Worker OsStr::new(".."), 409*bb4ee6a4SAndroid Build Coastguard Worker )?; 410*bb4ee6a4SAndroid Build Coastguard Worker 411*bb4ee6a4SAndroid Build Coastguard Worker if inode_num != parent_inode { 412*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry(arena, parent_inode, inode_num, InodeType::Directory, name)?; 413*bb4ee6a4SAndroid Build Coastguard Worker } 414*bb4ee6a4SAndroid Build Coastguard Worker 415*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 416*bb4ee6a4SAndroid Build Coastguard Worker } 417*bb4ee6a4SAndroid Build Coastguard Worker add_dir( &mut self, arena: &'a Arena<'a>, inode_num: InodeNum, parent_inode: InodeNum, path: &Path, ) -> Result<()>418*bb4ee6a4SAndroid Build Coastguard Worker fn add_dir( 419*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 420*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 421*bb4ee6a4SAndroid Build Coastguard Worker inode_num: InodeNum, 422*bb4ee6a4SAndroid Build Coastguard Worker parent_inode: InodeNum, 423*bb4ee6a4SAndroid Build Coastguard Worker path: &Path, 424*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 425*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(inode_num); 426*bb4ee6a4SAndroid Build Coastguard Worker 427*bb4ee6a4SAndroid Build Coastguard Worker let xattr = InlineXattrs::from_path(path)?; 428*bb4ee6a4SAndroid Build Coastguard Worker let inode = Inode::from_metadata( 429*bb4ee6a4SAndroid Build Coastguard Worker arena, 430*bb4ee6a4SAndroid Build Coastguard Worker &mut self.group_metadata[group_id], 431*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 432*bb4ee6a4SAndroid Build Coastguard Worker &std::fs::metadata(path)?, 433*bb4ee6a4SAndroid Build Coastguard Worker BLOCK_SIZE as u32, 434*bb4ee6a4SAndroid Build Coastguard Worker 0, 435*bb4ee6a4SAndroid Build Coastguard Worker InodeBlocksCount::from_bytes_len(0), 436*bb4ee6a4SAndroid Build Coastguard Worker InodeBlock::default(), 437*bb4ee6a4SAndroid Build Coastguard Worker Some(xattr), 438*bb4ee6a4SAndroid Build Coastguard Worker )?; 439*bb4ee6a4SAndroid Build Coastguard Worker 440*bb4ee6a4SAndroid Build Coastguard Worker self.add_inode(inode_num, inode)?; 441*bb4ee6a4SAndroid Build Coastguard Worker 442*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry( 443*bb4ee6a4SAndroid Build Coastguard Worker arena, 444*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 445*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 446*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Directory, 447*bb4ee6a4SAndroid Build Coastguard Worker OsStr::new("."), 448*bb4ee6a4SAndroid Build Coastguard Worker )?; 449*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry( 450*bb4ee6a4SAndroid Build Coastguard Worker arena, 451*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 452*bb4ee6a4SAndroid Build Coastguard Worker parent_inode, 453*bb4ee6a4SAndroid Build Coastguard Worker InodeType::Directory, 454*bb4ee6a4SAndroid Build Coastguard Worker OsStr::new(".."), 455*bb4ee6a4SAndroid Build Coastguard Worker )?; 456*bb4ee6a4SAndroid Build Coastguard Worker 457*bb4ee6a4SAndroid Build Coastguard Worker if inode_num != parent_inode { 458*bb4ee6a4SAndroid Build Coastguard Worker let name = path 459*bb4ee6a4SAndroid Build Coastguard Worker .file_name() 460*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("failed to get directory name"))?; 461*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry(arena, parent_inode, inode_num, InodeType::Directory, name)?; 462*bb4ee6a4SAndroid Build Coastguard Worker } 463*bb4ee6a4SAndroid Build Coastguard Worker 464*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 465*bb4ee6a4SAndroid Build Coastguard Worker } 466*bb4ee6a4SAndroid Build Coastguard Worker 467*bb4ee6a4SAndroid Build Coastguard Worker /// Registers a file to be mmaped to the memory region. 468*bb4ee6a4SAndroid Build Coastguard Worker /// This function just reserves a region for mmap() on `arena` and doesn't call mmap(). 469*bb4ee6a4SAndroid Build Coastguard Worker /// It's `arena`'s owner's responsibility to call mmap() for the registered files at the end. register_mmap_file( &mut self, arena: &'a Arena<'a>, block_num: usize, file: &File, file_size: usize, mut file_offset: usize, ) -> Result<(Vec<BlockId>, usize)>470*bb4ee6a4SAndroid Build Coastguard Worker fn register_mmap_file( 471*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 472*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 473*bb4ee6a4SAndroid Build Coastguard Worker block_num: usize, 474*bb4ee6a4SAndroid Build Coastguard Worker file: &File, 475*bb4ee6a4SAndroid Build Coastguard Worker file_size: usize, 476*bb4ee6a4SAndroid Build Coastguard Worker mut file_offset: usize, 477*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(Vec<BlockId>, usize)> { 478*bb4ee6a4SAndroid Build Coastguard Worker let contig_blocks = self.allocate_contiguous_blocks(block_num as u16)?; 479*bb4ee6a4SAndroid Build Coastguard Worker 480*bb4ee6a4SAndroid Build Coastguard Worker let mut remaining = std::cmp::min(file_size - file_offset, block_num * BLOCK_SIZE); 481*bb4ee6a4SAndroid Build Coastguard Worker let mut written = 0; 482*bb4ee6a4SAndroid Build Coastguard Worker for blocks in &contig_blocks { 483*bb4ee6a4SAndroid Build Coastguard Worker if remaining == 0 { 484*bb4ee6a4SAndroid Build Coastguard Worker panic!("remaining == 0. This is a bug"); 485*bb4ee6a4SAndroid Build Coastguard Worker } 486*bb4ee6a4SAndroid Build Coastguard Worker let length = std::cmp::min(remaining, BLOCK_SIZE * blocks.len()); 487*bb4ee6a4SAndroid Build Coastguard Worker let start_block = blocks[0]; 488*bb4ee6a4SAndroid Build Coastguard Worker let mem_offset = u32::from(start_block) as usize * BLOCK_SIZE; 489*bb4ee6a4SAndroid Build Coastguard Worker // Reserve the region in arena to prevent from overwriting metadata. 490*bb4ee6a4SAndroid Build Coastguard Worker arena 491*bb4ee6a4SAndroid Build Coastguard Worker .reserve_for_mmap( 492*bb4ee6a4SAndroid Build Coastguard Worker mem_offset, 493*bb4ee6a4SAndroid Build Coastguard Worker length, 494*bb4ee6a4SAndroid Build Coastguard Worker file.try_clone().context("failed to clone file")?, 495*bb4ee6a4SAndroid Build Coastguard Worker file_offset, 496*bb4ee6a4SAndroid Build Coastguard Worker ) 497*bb4ee6a4SAndroid Build Coastguard Worker .context("mmap for direct_block is already occupied")?; 498*bb4ee6a4SAndroid Build Coastguard Worker remaining -= length; 499*bb4ee6a4SAndroid Build Coastguard Worker written += length; 500*bb4ee6a4SAndroid Build Coastguard Worker file_offset += length; 501*bb4ee6a4SAndroid Build Coastguard Worker } 502*bb4ee6a4SAndroid Build Coastguard Worker Ok((contig_blocks.concat(), written)) 503*bb4ee6a4SAndroid Build Coastguard Worker } 504*bb4ee6a4SAndroid Build Coastguard Worker fill_indirect_block( &mut self, arena: &'a Arena<'a>, indirect_table: BlockId, file: &File, file_size: usize, file_offset: usize, ) -> Result<usize>505*bb4ee6a4SAndroid Build Coastguard Worker fn fill_indirect_block( 506*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 507*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 508*bb4ee6a4SAndroid Build Coastguard Worker indirect_table: BlockId, 509*bb4ee6a4SAndroid Build Coastguard Worker file: &File, 510*bb4ee6a4SAndroid Build Coastguard Worker file_size: usize, 511*bb4ee6a4SAndroid Build Coastguard Worker file_offset: usize, 512*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<usize> { 513*bb4ee6a4SAndroid Build Coastguard Worker // We use a block as a table of indirect blocks. 514*bb4ee6a4SAndroid Build Coastguard Worker // So, the maximum number of blocks supported by single indirect blocks is limited by the 515*bb4ee6a4SAndroid Build Coastguard Worker // maximum number of entries in one block, which is (BLOCK_SIZE / 4) where 4 is the size of 516*bb4ee6a4SAndroid Build Coastguard Worker // int. 517*bb4ee6a4SAndroid Build Coastguard Worker let max_num_blocks = BLOCK_SIZE / 4; 518*bb4ee6a4SAndroid Build Coastguard Worker let max_data_len = max_num_blocks * BLOCK_SIZE; 519*bb4ee6a4SAndroid Build Coastguard Worker 520*bb4ee6a4SAndroid Build Coastguard Worker let length = std::cmp::min(file_size - file_offset, max_data_len); 521*bb4ee6a4SAndroid Build Coastguard Worker let block_num = length.div_ceil(BLOCK_SIZE); 522*bb4ee6a4SAndroid Build Coastguard Worker 523*bb4ee6a4SAndroid Build Coastguard Worker let (allocated_blocks, length) = self 524*bb4ee6a4SAndroid Build Coastguard Worker .register_mmap_file(arena, block_num, file, file_size, file_offset) 525*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to reserve mmap regions on indirect block")?; 526*bb4ee6a4SAndroid Build Coastguard Worker 527*bb4ee6a4SAndroid Build Coastguard Worker let slice = arena.allocate_slice(indirect_table, 0, 4 * block_num)?; 528*bb4ee6a4SAndroid Build Coastguard Worker slice.copy_from_slice(allocated_blocks.as_bytes()); 529*bb4ee6a4SAndroid Build Coastguard Worker 530*bb4ee6a4SAndroid Build Coastguard Worker Ok(length) 531*bb4ee6a4SAndroid Build Coastguard Worker } 532*bb4ee6a4SAndroid Build Coastguard Worker add_file( &mut self, arena: &'a Arena<'a>, parent_inode: InodeNum, path: &Path, ) -> Result<()>533*bb4ee6a4SAndroid Build Coastguard Worker fn add_file( 534*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 535*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 536*bb4ee6a4SAndroid Build Coastguard Worker parent_inode: InodeNum, 537*bb4ee6a4SAndroid Build Coastguard Worker path: &Path, 538*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 539*bb4ee6a4SAndroid Build Coastguard Worker let inode_num = self.allocate_inode()?; 540*bb4ee6a4SAndroid Build Coastguard Worker 541*bb4ee6a4SAndroid Build Coastguard Worker let name = path 542*bb4ee6a4SAndroid Build Coastguard Worker .file_name() 543*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("failed to get directory name"))?; 544*bb4ee6a4SAndroid Build Coastguard Worker let file = File::open(path)?; 545*bb4ee6a4SAndroid Build Coastguard Worker let file_size = file.metadata()?.len() as usize; 546*bb4ee6a4SAndroid Build Coastguard Worker let mut block = InodeBlock::default(); 547*bb4ee6a4SAndroid Build Coastguard Worker 548*bb4ee6a4SAndroid Build Coastguard Worker let mut written = 0; 549*bb4ee6a4SAndroid Build Coastguard Worker let mut used_blocks = 0; 550*bb4ee6a4SAndroid Build Coastguard Worker 551*bb4ee6a4SAndroid Build Coastguard Worker if file_size > 0 { 552*bb4ee6a4SAndroid Build Coastguard Worker let block_num = std::cmp::min( 553*bb4ee6a4SAndroid Build Coastguard Worker file_size.div_ceil(BLOCK_SIZE), 554*bb4ee6a4SAndroid Build Coastguard Worker InodeBlock::NUM_DIRECT_BLOCKS, 555*bb4ee6a4SAndroid Build Coastguard Worker ); 556*bb4ee6a4SAndroid Build Coastguard Worker let (allocated_blocks, len) = self 557*bb4ee6a4SAndroid Build Coastguard Worker .register_mmap_file(arena, block_num, &file, file_size, 0) 558*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to reserve mmap regions on direct block")?; 559*bb4ee6a4SAndroid Build Coastguard Worker 560*bb4ee6a4SAndroid Build Coastguard Worker block.set_direct_blocks(&allocated_blocks)?; 561*bb4ee6a4SAndroid Build Coastguard Worker written += len; 562*bb4ee6a4SAndroid Build Coastguard Worker used_blocks += block_num; 563*bb4ee6a4SAndroid Build Coastguard Worker } 564*bb4ee6a4SAndroid Build Coastguard Worker 565*bb4ee6a4SAndroid Build Coastguard Worker // Indirect data block 566*bb4ee6a4SAndroid Build Coastguard Worker if written < file_size { 567*bb4ee6a4SAndroid Build Coastguard Worker let indirect_table = self.allocate_block()?; 568*bb4ee6a4SAndroid Build Coastguard Worker block.set_indirect_block_table(&indirect_table)?; 569*bb4ee6a4SAndroid Build Coastguard Worker used_blocks += 1; 570*bb4ee6a4SAndroid Build Coastguard Worker 571*bb4ee6a4SAndroid Build Coastguard Worker let length = 572*bb4ee6a4SAndroid Build Coastguard Worker self.fill_indirect_block(arena, indirect_table, &file, file_size, written)?; 573*bb4ee6a4SAndroid Build Coastguard Worker written += length; 574*bb4ee6a4SAndroid Build Coastguard Worker used_blocks += length.div_ceil(BLOCK_SIZE); 575*bb4ee6a4SAndroid Build Coastguard Worker } 576*bb4ee6a4SAndroid Build Coastguard Worker 577*bb4ee6a4SAndroid Build Coastguard Worker // Double-indirect data block 578*bb4ee6a4SAndroid Build Coastguard Worker // Supporting double-indirect data block allows storing ~4GB files if 4GB block size is 579*bb4ee6a4SAndroid Build Coastguard Worker // used. 580*bb4ee6a4SAndroid Build Coastguard Worker if written < file_size { 581*bb4ee6a4SAndroid Build Coastguard Worker let d_indirect_table = self.allocate_block()?; 582*bb4ee6a4SAndroid Build Coastguard Worker block.set_double_indirect_block_table(&d_indirect_table)?; 583*bb4ee6a4SAndroid Build Coastguard Worker used_blocks += 1; 584*bb4ee6a4SAndroid Build Coastguard Worker 585*bb4ee6a4SAndroid Build Coastguard Worker let mut indirect_blocks: Vec<BlockId> = vec![]; 586*bb4ee6a4SAndroid Build Coastguard Worker // Iterate (BLOCK_SIZE / 4) times, as each block id is 4-byte. 587*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..BLOCK_SIZE / 4 { 588*bb4ee6a4SAndroid Build Coastguard Worker if written >= file_size { 589*bb4ee6a4SAndroid Build Coastguard Worker break; 590*bb4ee6a4SAndroid Build Coastguard Worker } 591*bb4ee6a4SAndroid Build Coastguard Worker let indirect_table = self.allocate_block()?; 592*bb4ee6a4SAndroid Build Coastguard Worker indirect_blocks.push(indirect_table); 593*bb4ee6a4SAndroid Build Coastguard Worker used_blocks += 1; 594*bb4ee6a4SAndroid Build Coastguard Worker 595*bb4ee6a4SAndroid Build Coastguard Worker let length = self 596*bb4ee6a4SAndroid Build Coastguard Worker .fill_indirect_block(arena, indirect_table, &file, file_size, written) 597*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to indirect block for doubly-indirect table")?; 598*bb4ee6a4SAndroid Build Coastguard Worker written += length; 599*bb4ee6a4SAndroid Build Coastguard Worker used_blocks += length.div_ceil(BLOCK_SIZE); 600*bb4ee6a4SAndroid Build Coastguard Worker } 601*bb4ee6a4SAndroid Build Coastguard Worker 602*bb4ee6a4SAndroid Build Coastguard Worker let d_table = arena.allocate_slice(d_indirect_table, 0, indirect_blocks.len() * 4)?; 603*bb4ee6a4SAndroid Build Coastguard Worker d_table.copy_from_slice(indirect_blocks.as_bytes()); 604*bb4ee6a4SAndroid Build Coastguard Worker } 605*bb4ee6a4SAndroid Build Coastguard Worker 606*bb4ee6a4SAndroid Build Coastguard Worker if written != file_size { 607*bb4ee6a4SAndroid Build Coastguard Worker unimplemented!("Triple-indirect block is not supported"); 608*bb4ee6a4SAndroid Build Coastguard Worker } 609*bb4ee6a4SAndroid Build Coastguard Worker 610*bb4ee6a4SAndroid Build Coastguard Worker let blocks = InodeBlocksCount::from_bytes_len((used_blocks * BLOCK_SIZE) as u32); 611*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(inode_num); 612*bb4ee6a4SAndroid Build Coastguard Worker let size = file_size as u32; 613*bb4ee6a4SAndroid Build Coastguard Worker 614*bb4ee6a4SAndroid Build Coastguard Worker let xattr = InlineXattrs::from_path(path)?; 615*bb4ee6a4SAndroid Build Coastguard Worker let inode = Inode::from_metadata( 616*bb4ee6a4SAndroid Build Coastguard Worker arena, 617*bb4ee6a4SAndroid Build Coastguard Worker &mut self.group_metadata[group_id], 618*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 619*bb4ee6a4SAndroid Build Coastguard Worker &std::fs::metadata(path)?, 620*bb4ee6a4SAndroid Build Coastguard Worker size, 621*bb4ee6a4SAndroid Build Coastguard Worker 1, 622*bb4ee6a4SAndroid Build Coastguard Worker blocks, 623*bb4ee6a4SAndroid Build Coastguard Worker block, 624*bb4ee6a4SAndroid Build Coastguard Worker Some(xattr), 625*bb4ee6a4SAndroid Build Coastguard Worker )?; 626*bb4ee6a4SAndroid Build Coastguard Worker 627*bb4ee6a4SAndroid Build Coastguard Worker self.add_inode(inode_num, inode)?; 628*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry(arena, parent_inode, inode_num, InodeType::Regular, name)?; 629*bb4ee6a4SAndroid Build Coastguard Worker 630*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 631*bb4ee6a4SAndroid Build Coastguard Worker } 632*bb4ee6a4SAndroid Build Coastguard Worker add_symlink( &mut self, arena: &'a Arena<'a>, parent: InodeNum, entry: &DirEntry, ) -> Result<()>633*bb4ee6a4SAndroid Build Coastguard Worker fn add_symlink( 634*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 635*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 636*bb4ee6a4SAndroid Build Coastguard Worker parent: InodeNum, 637*bb4ee6a4SAndroid Build Coastguard Worker entry: &DirEntry, 638*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 639*bb4ee6a4SAndroid Build Coastguard Worker let link = entry.path(); 640*bb4ee6a4SAndroid Build Coastguard Worker let dst_path = std::fs::read_link(&link)?; 641*bb4ee6a4SAndroid Build Coastguard Worker let dst = dst_path 642*bb4ee6a4SAndroid Build Coastguard Worker .to_str() 643*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to convert symlink destination to str")?; 644*bb4ee6a4SAndroid Build Coastguard Worker 645*bb4ee6a4SAndroid Build Coastguard Worker if dst.len() >= InodeBlock::max_inline_symlink_len() { 646*bb4ee6a4SAndroid Build Coastguard Worker return self.add_long_symlink(arena, parent, &link, dst); 647*bb4ee6a4SAndroid Build Coastguard Worker } 648*bb4ee6a4SAndroid Build Coastguard Worker 649*bb4ee6a4SAndroid Build Coastguard Worker let inode_num = self.allocate_inode()?; 650*bb4ee6a4SAndroid Build Coastguard Worker let mut block = InodeBlock::default(); 651*bb4ee6a4SAndroid Build Coastguard Worker block.set_inline_symlink(dst)?; 652*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(inode_num); 653*bb4ee6a4SAndroid Build Coastguard Worker let xattr = InlineXattrs::from_path(&link)?; 654*bb4ee6a4SAndroid Build Coastguard Worker let inode = Inode::from_metadata( 655*bb4ee6a4SAndroid Build Coastguard Worker arena, 656*bb4ee6a4SAndroid Build Coastguard Worker &mut self.group_metadata[group_id], 657*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 658*bb4ee6a4SAndroid Build Coastguard Worker &std::fs::symlink_metadata(&link)?, 659*bb4ee6a4SAndroid Build Coastguard Worker dst.len() as u32, 660*bb4ee6a4SAndroid Build Coastguard Worker 1, //links_count, 661*bb4ee6a4SAndroid Build Coastguard Worker InodeBlocksCount::from_bytes_len(0), 662*bb4ee6a4SAndroid Build Coastguard Worker block, 663*bb4ee6a4SAndroid Build Coastguard Worker Some(xattr), 664*bb4ee6a4SAndroid Build Coastguard Worker )?; 665*bb4ee6a4SAndroid Build Coastguard Worker self.add_inode(inode_num, inode)?; 666*bb4ee6a4SAndroid Build Coastguard Worker 667*bb4ee6a4SAndroid Build Coastguard Worker let link_name = link.file_name().context("failed to get symlink name")?; 668*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry(arena, parent, inode_num, InodeType::Symlink, link_name)?; 669*bb4ee6a4SAndroid Build Coastguard Worker 670*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 671*bb4ee6a4SAndroid Build Coastguard Worker } 672*bb4ee6a4SAndroid Build Coastguard Worker add_long_symlink( &mut self, arena: &'a Arena<'a>, parent: InodeNum, link: &Path, dst: &str, ) -> Result<()>673*bb4ee6a4SAndroid Build Coastguard Worker fn add_long_symlink( 674*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 675*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 676*bb4ee6a4SAndroid Build Coastguard Worker parent: InodeNum, 677*bb4ee6a4SAndroid Build Coastguard Worker link: &Path, 678*bb4ee6a4SAndroid Build Coastguard Worker dst: &str, 679*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 680*bb4ee6a4SAndroid Build Coastguard Worker let dst_len = dst.len(); 681*bb4ee6a4SAndroid Build Coastguard Worker if dst_len > BLOCK_SIZE { 682*bb4ee6a4SAndroid Build Coastguard Worker bail!("symlink longer than block size: {:?}", dst); 683*bb4ee6a4SAndroid Build Coastguard Worker } 684*bb4ee6a4SAndroid Build Coastguard Worker 685*bb4ee6a4SAndroid Build Coastguard Worker // Copy symlink's destination to the block. 686*bb4ee6a4SAndroid Build Coastguard Worker let symlink_block = self.allocate_block()?; 687*bb4ee6a4SAndroid Build Coastguard Worker let buf = arena.allocate_slice(symlink_block, 0, dst_len)?; 688*bb4ee6a4SAndroid Build Coastguard Worker buf.copy_from_slice(dst.as_bytes()); 689*bb4ee6a4SAndroid Build Coastguard Worker 690*bb4ee6a4SAndroid Build Coastguard Worker let inode_num = self.allocate_inode()?; 691*bb4ee6a4SAndroid Build Coastguard Worker let mut block = InodeBlock::default(); 692*bb4ee6a4SAndroid Build Coastguard Worker block.set_direct_blocks(&[symlink_block])?; 693*bb4ee6a4SAndroid Build Coastguard Worker 694*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(inode_num); 695*bb4ee6a4SAndroid Build Coastguard Worker let xattr = InlineXattrs::from_path(link)?; 696*bb4ee6a4SAndroid Build Coastguard Worker let inode = Inode::from_metadata( 697*bb4ee6a4SAndroid Build Coastguard Worker arena, 698*bb4ee6a4SAndroid Build Coastguard Worker &mut self.group_metadata[group_id], 699*bb4ee6a4SAndroid Build Coastguard Worker inode_num, 700*bb4ee6a4SAndroid Build Coastguard Worker &std::fs::symlink_metadata(link)?, 701*bb4ee6a4SAndroid Build Coastguard Worker dst_len as u32, 702*bb4ee6a4SAndroid Build Coastguard Worker 1, //links_count, 703*bb4ee6a4SAndroid Build Coastguard Worker InodeBlocksCount::from_bytes_len(BLOCK_SIZE as u32), 704*bb4ee6a4SAndroid Build Coastguard Worker block, 705*bb4ee6a4SAndroid Build Coastguard Worker Some(xattr), 706*bb4ee6a4SAndroid Build Coastguard Worker )?; 707*bb4ee6a4SAndroid Build Coastguard Worker self.add_inode(inode_num, inode)?; 708*bb4ee6a4SAndroid Build Coastguard Worker 709*bb4ee6a4SAndroid Build Coastguard Worker let link_name = link.file_name().context("failed to get symlink name")?; 710*bb4ee6a4SAndroid Build Coastguard Worker self.allocate_dir_entry(arena, parent, inode_num, InodeType::Symlink, link_name)?; 711*bb4ee6a4SAndroid Build Coastguard Worker 712*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 713*bb4ee6a4SAndroid Build Coastguard Worker } 714*bb4ee6a4SAndroid Build Coastguard Worker 715*bb4ee6a4SAndroid Build Coastguard Worker /// Walks through `src_dir` and copies directories and files to the new file system. copy_dirtree<P: AsRef<Path>>( &mut self, arena: &'a Arena<'a>, src_dir: P, ) -> Result<()>716*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn copy_dirtree<P: AsRef<Path>>( 717*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 718*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 719*bb4ee6a4SAndroid Build Coastguard Worker src_dir: P, 720*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 721*bb4ee6a4SAndroid Build Coastguard Worker // Update the root directory's metadata with the metadata of `src_dir`. 722*bb4ee6a4SAndroid Build Coastguard Worker let root_inode_num = InodeNum::new(2).expect("2 is a valid inode number"); 723*bb4ee6a4SAndroid Build Coastguard Worker let group_id = self.group_num_for_inode(root_inode_num); 724*bb4ee6a4SAndroid Build Coastguard Worker let gm = &mut self.group_metadata[group_id]; 725*bb4ee6a4SAndroid Build Coastguard Worker let inode: &mut &mut Inode = gm 726*bb4ee6a4SAndroid Build Coastguard Worker .inode_table 727*bb4ee6a4SAndroid Build Coastguard Worker .get_mut(&root_inode_num) 728*bb4ee6a4SAndroid Build Coastguard Worker .expect("root dir is not stored"); 729*bb4ee6a4SAndroid Build Coastguard Worker let metadata = src_dir 730*bb4ee6a4SAndroid Build Coastguard Worker .as_ref() 731*bb4ee6a4SAndroid Build Coastguard Worker .metadata() 732*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| format!("failed to get metadata of {:?}", src_dir.as_ref()))?; 733*bb4ee6a4SAndroid Build Coastguard Worker inode.update_metadata(&metadata); 734*bb4ee6a4SAndroid Build Coastguard Worker 735*bb4ee6a4SAndroid Build Coastguard Worker self.copy_dirtree_rec(arena, InodeNum(2), src_dir) 736*bb4ee6a4SAndroid Build Coastguard Worker } 737*bb4ee6a4SAndroid Build Coastguard Worker copy_dirtree_rec<P: AsRef<Path>>( &mut self, arena: &'a Arena<'a>, parent_inode: InodeNum, src_dir: P, ) -> Result<()>738*bb4ee6a4SAndroid Build Coastguard Worker fn copy_dirtree_rec<P: AsRef<Path>>( 739*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 740*bb4ee6a4SAndroid Build Coastguard Worker arena: &'a Arena<'a>, 741*bb4ee6a4SAndroid Build Coastguard Worker parent_inode: InodeNum, 742*bb4ee6a4SAndroid Build Coastguard Worker src_dir: P, 743*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 744*bb4ee6a4SAndroid Build Coastguard Worker for entry in std::fs::read_dir(&src_dir)? { 745*bb4ee6a4SAndroid Build Coastguard Worker let entry = entry?; 746*bb4ee6a4SAndroid Build Coastguard Worker let ftype = entry.file_type()?; 747*bb4ee6a4SAndroid Build Coastguard Worker if ftype.is_dir() { 748*bb4ee6a4SAndroid Build Coastguard Worker // Since we creates `/lost+found` on the root directory, ignore the existing one. 749*bb4ee6a4SAndroid Build Coastguard Worker if parent_inode.0 == 2 && entry.path().file_name() == Some(OsStr::new("lost+found")) 750*bb4ee6a4SAndroid Build Coastguard Worker { 751*bb4ee6a4SAndroid Build Coastguard Worker info!("ext2: Ignore the existing /lost+found directory"); 752*bb4ee6a4SAndroid Build Coastguard Worker continue; 753*bb4ee6a4SAndroid Build Coastguard Worker } 754*bb4ee6a4SAndroid Build Coastguard Worker let inode = self.allocate_inode()?; 755*bb4ee6a4SAndroid Build Coastguard Worker self.add_dir(arena, inode, parent_inode, &entry.path()) 756*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| { 757*bb4ee6a4SAndroid Build Coastguard Worker format!( 758*bb4ee6a4SAndroid Build Coastguard Worker "failed to add directory {:?} as inode={:?}", 759*bb4ee6a4SAndroid Build Coastguard Worker entry.path(), 760*bb4ee6a4SAndroid Build Coastguard Worker inode 761*bb4ee6a4SAndroid Build Coastguard Worker ) 762*bb4ee6a4SAndroid Build Coastguard Worker })?; 763*bb4ee6a4SAndroid Build Coastguard Worker self.copy_dirtree_rec(arena, inode, entry.path())?; 764*bb4ee6a4SAndroid Build Coastguard Worker } else if ftype.is_file() { 765*bb4ee6a4SAndroid Build Coastguard Worker self.add_file(arena, parent_inode, &entry.path()) 766*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| { 767*bb4ee6a4SAndroid Build Coastguard Worker format!( 768*bb4ee6a4SAndroid Build Coastguard Worker "failed to add file {:?} in inode={:?}", 769*bb4ee6a4SAndroid Build Coastguard Worker entry.path(), 770*bb4ee6a4SAndroid Build Coastguard Worker parent_inode 771*bb4ee6a4SAndroid Build Coastguard Worker ) 772*bb4ee6a4SAndroid Build Coastguard Worker })?; 773*bb4ee6a4SAndroid Build Coastguard Worker } else if ftype.is_symlink() { 774*bb4ee6a4SAndroid Build Coastguard Worker self.add_symlink(arena, parent_inode, &entry)?; 775*bb4ee6a4SAndroid Build Coastguard Worker } else { 776*bb4ee6a4SAndroid Build Coastguard Worker bail!("unknown file type {:?} for {:?}", ftype, entry.file_name()); 777*bb4ee6a4SAndroid Build Coastguard Worker } 778*bb4ee6a4SAndroid Build Coastguard Worker } 779*bb4ee6a4SAndroid Build Coastguard Worker 780*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 781*bb4ee6a4SAndroid Build Coastguard Worker } 782*bb4ee6a4SAndroid Build Coastguard Worker copy_backup_metadata(self, arena: &'a Arena<'a>) -> Result<()>783*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn copy_backup_metadata(self, arena: &'a Arena<'a>) -> Result<()> { 784*bb4ee6a4SAndroid Build Coastguard Worker // Copy superblock and group_metadata to every block group 785*bb4ee6a4SAndroid Build Coastguard Worker for i in 1..self.sb.num_groups() as usize { 786*bb4ee6a4SAndroid Build Coastguard Worker let super_block_id = BlockId::from(self.sb.blocks_per_group * i as u32); 787*bb4ee6a4SAndroid Build Coastguard Worker let bg_desc_block_id = BlockId::from(u32::from(super_block_id) + 1); 788*bb4ee6a4SAndroid Build Coastguard Worker self.sb.block_group_nr = i as u16; 789*bb4ee6a4SAndroid Build Coastguard Worker arena.write_to_mem(super_block_id, 0, self.sb)?; 790*bb4ee6a4SAndroid Build Coastguard Worker let mut offset = 0; 791*bb4ee6a4SAndroid Build Coastguard Worker for gm in &self.group_metadata { 792*bb4ee6a4SAndroid Build Coastguard Worker arena.write_to_mem(bg_desc_block_id, offset, gm.group_desc)?; 793*bb4ee6a4SAndroid Build Coastguard Worker offset += std::mem::size_of::<BlockGroupDescriptor>(); 794*bb4ee6a4SAndroid Build Coastguard Worker } 795*bb4ee6a4SAndroid Build Coastguard Worker } 796*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 797*bb4ee6a4SAndroid Build Coastguard Worker } 798*bb4ee6a4SAndroid Build Coastguard Worker } 799