xref: /aosp_15_r20/external/crosvm/ext2/src/fs.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 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