xref: /aosp_15_r20/bootable/libbootloader/gbl/libstorage/src/gpt.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker use crate::{BlockIo, Disk, Result};
16*5225e6b1SAndroid Build Coastguard Worker use core::{
17*5225e6b1SAndroid Build Coastguard Worker     array::from_fn,
18*5225e6b1SAndroid Build Coastguard Worker     cmp::min,
19*5225e6b1SAndroid Build Coastguard Worker     convert::TryFrom,
20*5225e6b1SAndroid Build Coastguard Worker     default::Default,
21*5225e6b1SAndroid Build Coastguard Worker     fmt::{Debug, Formatter},
22*5225e6b1SAndroid Build Coastguard Worker     mem::size_of,
23*5225e6b1SAndroid Build Coastguard Worker     num::NonZeroU64,
24*5225e6b1SAndroid Build Coastguard Worker     ops::{Deref, DerefMut},
25*5225e6b1SAndroid Build Coastguard Worker     str::from_utf8,
26*5225e6b1SAndroid Build Coastguard Worker };
27*5225e6b1SAndroid Build Coastguard Worker use crc32fast::Hasher;
28*5225e6b1SAndroid Build Coastguard Worker use gbl_async::block_on;
29*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, GptError};
30*5225e6b1SAndroid Build Coastguard Worker use safemath::SafeNum;
31*5225e6b1SAndroid Build Coastguard Worker use zerocopy::{AsBytes, ByteSlice, FromBytes, FromZeroes, Ref};
32*5225e6b1SAndroid Build Coastguard Worker 
33*5225e6b1SAndroid Build Coastguard Worker /// Number of bytes in GUID.
34*5225e6b1SAndroid Build Coastguard Worker pub const GPT_GUID_LEN: usize = 16;
35*5225e6b1SAndroid Build Coastguard Worker /// The maximum number of UTF-16 characters in a GPT partition name, including termination.
36*5225e6b1SAndroid Build Coastguard Worker pub const GPT_NAME_LEN_U16: usize = 36;
37*5225e6b1SAndroid Build Coastguard Worker const GPT_NAME_LEN_U8: usize = 2 * GPT_GUID_LEN;
38*5225e6b1SAndroid Build Coastguard Worker 
39*5225e6b1SAndroid Build Coastguard Worker /// The top-level GPT header.
40*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)]
41*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes, PartialEq, Eq)]
42*5225e6b1SAndroid Build Coastguard Worker pub struct GptHeader {
43*5225e6b1SAndroid Build Coastguard Worker     /// Magic bytes; must be [GPT_MAGIC].
44*5225e6b1SAndroid Build Coastguard Worker     pub magic: u64,
45*5225e6b1SAndroid Build Coastguard Worker     /// Header version.
46*5225e6b1SAndroid Build Coastguard Worker     pub revision: u32,
47*5225e6b1SAndroid Build Coastguard Worker     /// Header size in bytes.
48*5225e6b1SAndroid Build Coastguard Worker     pub size: u32,
49*5225e6b1SAndroid Build Coastguard Worker     /// CRC of the first `size` bytes, calculated with this field zeroed.
50*5225e6b1SAndroid Build Coastguard Worker     pub crc32: u32,
51*5225e6b1SAndroid Build Coastguard Worker     /// Reserved; must be set to 0.
52*5225e6b1SAndroid Build Coastguard Worker     pub reserved0: u32,
53*5225e6b1SAndroid Build Coastguard Worker     /// The on-disk block location of this header.
54*5225e6b1SAndroid Build Coastguard Worker     pub current: u64,
55*5225e6b1SAndroid Build Coastguard Worker     /// The on-disk block location of the other header.
56*5225e6b1SAndroid Build Coastguard Worker     pub backup: u64,
57*5225e6b1SAndroid Build Coastguard Worker     /// First usable block for partition contents.
58*5225e6b1SAndroid Build Coastguard Worker     pub first: u64,
59*5225e6b1SAndroid Build Coastguard Worker     /// Last usable block for partition contents (inclusive).
60*5225e6b1SAndroid Build Coastguard Worker     pub last: u64,
61*5225e6b1SAndroid Build Coastguard Worker     /// Disk GUID.
62*5225e6b1SAndroid Build Coastguard Worker     pub guid: [u8; GPT_GUID_LEN],
63*5225e6b1SAndroid Build Coastguard Worker     /// Starting block for the partition entries array.
64*5225e6b1SAndroid Build Coastguard Worker     pub entries: u64,
65*5225e6b1SAndroid Build Coastguard Worker     /// Number of partition entries.
66*5225e6b1SAndroid Build Coastguard Worker     pub entries_count: u32,
67*5225e6b1SAndroid Build Coastguard Worker     /// The size of each partition entry in bytes.
68*5225e6b1SAndroid Build Coastguard Worker     pub entries_size: u32,
69*5225e6b1SAndroid Build Coastguard Worker     /// CRC of the partition entries array.
70*5225e6b1SAndroid Build Coastguard Worker     pub entries_crc: u32,
71*5225e6b1SAndroid Build Coastguard Worker }
72*5225e6b1SAndroid Build Coastguard Worker 
73*5225e6b1SAndroid Build Coastguard Worker impl GptHeader {
74*5225e6b1SAndroid Build Coastguard Worker     /// Casts a bytes slice into a mutable GptHeader structure.
from_bytes_mut(bytes: &mut [u8]) -> &mut GptHeader75*5225e6b1SAndroid Build Coastguard Worker     pub fn from_bytes_mut(bytes: &mut [u8]) -> &mut GptHeader {
76*5225e6b1SAndroid Build Coastguard Worker         Ref::<_, GptHeader>::new_from_prefix(bytes).unwrap().0.into_mut()
77*5225e6b1SAndroid Build Coastguard Worker     }
78*5225e6b1SAndroid Build Coastguard Worker 
79*5225e6b1SAndroid Build Coastguard Worker     /// Computes the actual crc32 value.
calculate_header_crc(&self) -> u3280*5225e6b1SAndroid Build Coastguard Worker     fn calculate_header_crc(&self) -> u32 {
81*5225e6b1SAndroid Build Coastguard Worker         let mut hasher = Hasher::new();
82*5225e6b1SAndroid Build Coastguard Worker         hasher.update(&self.as_bytes()[..GPT_CRC32_OFFSET]);
83*5225e6b1SAndroid Build Coastguard Worker         hasher.update(&[0u8; size_of::<u32>()]);
84*5225e6b1SAndroid Build Coastguard Worker         hasher.update(&self.as_bytes()[GPT_CRC32_OFFSET + size_of::<u32>()..]);
85*5225e6b1SAndroid Build Coastguard Worker         hasher.finalize()
86*5225e6b1SAndroid Build Coastguard Worker     }
87*5225e6b1SAndroid Build Coastguard Worker 
88*5225e6b1SAndroid Build Coastguard Worker     /// Update the header crc32 value.
update_crc(&mut self)89*5225e6b1SAndroid Build Coastguard Worker     pub fn update_crc(&mut self) {
90*5225e6b1SAndroid Build Coastguard Worker         self.crc32 = self.calculate_header_crc();
91*5225e6b1SAndroid Build Coastguard Worker     }
92*5225e6b1SAndroid Build Coastguard Worker 
93*5225e6b1SAndroid Build Coastguard Worker     /// Updates entries and header crc according to the given entries buffer.
update_entries_crc(&mut self, entries: &[u8])94*5225e6b1SAndroid Build Coastguard Worker     fn update_entries_crc(&mut self, entries: &[u8]) {
95*5225e6b1SAndroid Build Coastguard Worker         let size = SafeNum::from(self.entries_count) * self.entries_size;
96*5225e6b1SAndroid Build Coastguard Worker         self.entries_crc = crc32(&entries[..size.try_into().unwrap()]);
97*5225e6b1SAndroid Build Coastguard Worker         self.update_crc();
98*5225e6b1SAndroid Build Coastguard Worker     }
99*5225e6b1SAndroid Build Coastguard Worker }
100*5225e6b1SAndroid Build Coastguard Worker 
101*5225e6b1SAndroid Build Coastguard Worker /// Computes the number of blocks for the 128 partition entries reserved space in GPT.
gpt_entries_blk(block_size: u64) -> Result<u64>102*5225e6b1SAndroid Build Coastguard Worker fn gpt_entries_blk(block_size: u64) -> Result<u64> {
103*5225e6b1SAndroid Build Coastguard Worker     let size = u64::try_from(GPT_MAX_NUM_ENTRIES_SIZE).unwrap();
104*5225e6b1SAndroid Build Coastguard Worker     match size % block_size {
105*5225e6b1SAndroid Build Coastguard Worker         0 => Ok(size / block_size),
106*5225e6b1SAndroid Build Coastguard Worker         _ => Err(Error::InvalidInput),
107*5225e6b1SAndroid Build Coastguard Worker     }
108*5225e6b1SAndroid Build Coastguard Worker }
109*5225e6b1SAndroid Build Coastguard Worker 
110*5225e6b1SAndroid Build Coastguard Worker /// Checks a header against a block device.
111*5225e6b1SAndroid Build Coastguard Worker ///
112*5225e6b1SAndroid Build Coastguard Worker /// # Args
113*5225e6b1SAndroid Build Coastguard Worker ///
114*5225e6b1SAndroid Build Coastguard Worker /// * `io`: An implementation of [BlockIo],
115*5225e6b1SAndroid Build Coastguard Worker /// * `header`: The GPT header to verify.
116*5225e6b1SAndroid Build Coastguard Worker /// * `is_primary`: If the header is a primary header.
check_header(io: &mut impl BlockIo, header: &GptHeader, is_primary: bool) -> Result<()>117*5225e6b1SAndroid Build Coastguard Worker fn check_header(io: &mut impl BlockIo, header: &GptHeader, is_primary: bool) -> Result<()> {
118*5225e6b1SAndroid Build Coastguard Worker     let num_blks = SafeNum::from(io.info().num_blocks);
119*5225e6b1SAndroid Build Coastguard Worker     let blk_sz = io.info().block_size;
120*5225e6b1SAndroid Build Coastguard Worker 
121*5225e6b1SAndroid Build Coastguard Worker     // GPT spec requires that at least 128 entries worth of space be reserved.
122*5225e6b1SAndroid Build Coastguard Worker     let min_reserved_entries_blk = gpt_entries_blk(blk_sz)?;
123*5225e6b1SAndroid Build Coastguard Worker     // Minimum space needed: 2 * (header + entries) + MBR.
124*5225e6b1SAndroid Build Coastguard Worker     let min_disk_blks: u64 = ((min_reserved_entries_blk + 1) * 2 + 1).try_into().unwrap();
125*5225e6b1SAndroid Build Coastguard Worker     if min_disk_blks > u64::try_from(num_blks).unwrap() {
126*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::DiskTooSmall));
127*5225e6b1SAndroid Build Coastguard Worker     }
128*5225e6b1SAndroid Build Coastguard Worker 
129*5225e6b1SAndroid Build Coastguard Worker     if header.magic != GPT_MAGIC {
130*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::IncorrectMagic(header.magic)));
131*5225e6b1SAndroid Build Coastguard Worker     }
132*5225e6b1SAndroid Build Coastguard Worker 
133*5225e6b1SAndroid Build Coastguard Worker     if header.calculate_header_crc() != header.crc32 {
134*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::IncorrectHeaderCrc));
135*5225e6b1SAndroid Build Coastguard Worker     }
136*5225e6b1SAndroid Build Coastguard Worker 
137*5225e6b1SAndroid Build Coastguard Worker     if header.size != size_of::<GptHeader>().try_into().unwrap() {
138*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::UnexpectedHeaderSize {
139*5225e6b1SAndroid Build Coastguard Worker             actual: header.size,
140*5225e6b1SAndroid Build Coastguard Worker             expect: size_of::<GptHeader>(),
141*5225e6b1SAndroid Build Coastguard Worker         }));
142*5225e6b1SAndroid Build Coastguard Worker     }
143*5225e6b1SAndroid Build Coastguard Worker 
144*5225e6b1SAndroid Build Coastguard Worker     if header.entries_size != size_of::<GptEntry>().try_into().unwrap() {
145*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::UnexpectedEntrySize {
146*5225e6b1SAndroid Build Coastguard Worker             actual: header.entries_size,
147*5225e6b1SAndroid Build Coastguard Worker             expect: size_of::<GptEntry>(),
148*5225e6b1SAndroid Build Coastguard Worker         }));
149*5225e6b1SAndroid Build Coastguard Worker     }
150*5225e6b1SAndroid Build Coastguard Worker 
151*5225e6b1SAndroid Build Coastguard Worker     // Checks first/last usable block.
152*5225e6b1SAndroid Build Coastguard Worker     //
153*5225e6b1SAndroid Build Coastguard Worker     // Assuming maximum range where partition entries are adjacent to GPT headers.
154*5225e6b1SAndroid Build Coastguard Worker     //
155*5225e6b1SAndroid Build Coastguard Worker     // Should leave a minimum space for MBR + primary header + primary entries before.
156*5225e6b1SAndroid Build Coastguard Worker     let min_first: u64 = (min_reserved_entries_blk + 2).try_into().unwrap();
157*5225e6b1SAndroid Build Coastguard Worker     // Should leave a minimum space for secondary header + secondary entries space after.
158*5225e6b1SAndroid Build Coastguard Worker     let max_last: u64 = (num_blks - 1 - min_reserved_entries_blk - 1).try_into().unwrap();
159*5225e6b1SAndroid Build Coastguard Worker     if header.first > header.last + 1 || header.first < min_first || header.last > max_last {
160*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::InvalidFirstLastUsableBlock {
161*5225e6b1SAndroid Build Coastguard Worker             first: header.first,
162*5225e6b1SAndroid Build Coastguard Worker             last: header.last,
163*5225e6b1SAndroid Build Coastguard Worker             range: (min_first, max_last),
164*5225e6b1SAndroid Build Coastguard Worker         }));
165*5225e6b1SAndroid Build Coastguard Worker     }
166*5225e6b1SAndroid Build Coastguard Worker 
167*5225e6b1SAndroid Build Coastguard Worker     // Checks entries starting block.
168*5225e6b1SAndroid Build Coastguard Worker     if is_primary {
169*5225e6b1SAndroid Build Coastguard Worker         // For primary header, entries must be before first usable block and can hold up to
170*5225e6b1SAndroid Build Coastguard Worker         // `GPT_MAX_NUM_ENTRIES` entries
171*5225e6b1SAndroid Build Coastguard Worker         let right: u64 =
172*5225e6b1SAndroid Build Coastguard Worker             (SafeNum::from(header.first) - min_reserved_entries_blk).try_into().unwrap();
173*5225e6b1SAndroid Build Coastguard Worker         if !(header.entries >= 2 && header.entries <= right) {
174*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::GptError(GptError::InvalidPrimaryEntriesStart {
175*5225e6b1SAndroid Build Coastguard Worker                 value: header.entries,
176*5225e6b1SAndroid Build Coastguard Worker                 expect_range: (2, right),
177*5225e6b1SAndroid Build Coastguard Worker             }));
178*5225e6b1SAndroid Build Coastguard Worker         }
179*5225e6b1SAndroid Build Coastguard Worker     } else {
180*5225e6b1SAndroid Build Coastguard Worker         // For secondary header, entries must be after last usable block and can hold up to
181*5225e6b1SAndroid Build Coastguard Worker         // `GPT_MAX_NUM_ENTRIES` entries.
182*5225e6b1SAndroid Build Coastguard Worker         if !(header.entries > header.last && header.entries <= max_last + 1) {
183*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::GptError(GptError::InvalidSecondaryEntriesStart {
184*5225e6b1SAndroid Build Coastguard Worker                 value: header.entries,
185*5225e6b1SAndroid Build Coastguard Worker                 expect_range: (header.last + 1, max_last + 1),
186*5225e6b1SAndroid Build Coastguard Worker             }));
187*5225e6b1SAndroid Build Coastguard Worker         }
188*5225e6b1SAndroid Build Coastguard Worker     }
189*5225e6b1SAndroid Build Coastguard Worker 
190*5225e6b1SAndroid Build Coastguard Worker     if header.entries_count > GPT_MAX_NUM_ENTRIES.try_into().unwrap() {
191*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::NumberOfEntriesOverflow {
192*5225e6b1SAndroid Build Coastguard Worker             entries: header.entries_count,
193*5225e6b1SAndroid Build Coastguard Worker             max_allowed: GPT_MAX_NUM_ENTRIES,
194*5225e6b1SAndroid Build Coastguard Worker         }));
195*5225e6b1SAndroid Build Coastguard Worker     }
196*5225e6b1SAndroid Build Coastguard Worker 
197*5225e6b1SAndroid Build Coastguard Worker     Ok(())
198*5225e6b1SAndroid Build Coastguard Worker }
199*5225e6b1SAndroid Build Coastguard Worker 
200*5225e6b1SAndroid Build Coastguard Worker /// Verifies the given entries against a verifed GPT header.
201*5225e6b1SAndroid Build Coastguard Worker ///
202*5225e6b1SAndroid Build Coastguard Worker /// # Args
203*5225e6b1SAndroid Build Coastguard Worker ///
204*5225e6b1SAndroid Build Coastguard Worker /// * `header`: The verified GPT header corresponding to the entries.
205*5225e6b1SAndroid Build Coastguard Worker /// * `entries`: The buffer containing the entries.
check_entries(header: &GptHeader, entries: &[u8]) -> Result<()>206*5225e6b1SAndroid Build Coastguard Worker fn check_entries(header: &GptHeader, entries: &[u8]) -> Result<()> {
207*5225e6b1SAndroid Build Coastguard Worker     // Checks entries CRC.
208*5225e6b1SAndroid Build Coastguard Worker     assert!(header.entries_count <= GPT_MAX_NUM_ENTRIES.try_into().unwrap());
209*5225e6b1SAndroid Build Coastguard Worker     let entries_size: usize =
210*5225e6b1SAndroid Build Coastguard Worker         (SafeNum::from(header.entries_count) * GPT_ENTRY_SIZE).try_into().unwrap();
211*5225e6b1SAndroid Build Coastguard Worker     let entries = entries.get(..entries_size).ok_or(Error::GptError(GptError::EntriesTruncated))?;
212*5225e6b1SAndroid Build Coastguard Worker     if header.entries_crc != crc32(entries) {
213*5225e6b1SAndroid Build Coastguard Worker         return Err(Error::GptError(GptError::IncorrectEntriesCrc));
214*5225e6b1SAndroid Build Coastguard Worker     }
215*5225e6b1SAndroid Build Coastguard Worker 
216*5225e6b1SAndroid Build Coastguard Worker     // Checks each entry.
217*5225e6b1SAndroid Build Coastguard Worker     let entries = Ref::<_, [GptEntry]>::new_slice(entries)
218*5225e6b1SAndroid Build Coastguard Worker         .ok_or(Error::GptError(GptError::EntriesTruncated))?
219*5225e6b1SAndroid Build Coastguard Worker         .into_slice();
220*5225e6b1SAndroid Build Coastguard Worker     let entries = &entries[..header.entries_count.try_into().unwrap()];
221*5225e6b1SAndroid Build Coastguard Worker     for (idx, ele) in entries.iter().take_while(|v| !v.is_null()).enumerate() {
222*5225e6b1SAndroid Build Coastguard Worker         // Error information uses 1-base partition index.
223*5225e6b1SAndroid Build Coastguard Worker         let idx = idx.checked_add(1).unwrap();
224*5225e6b1SAndroid Build Coastguard Worker         let (first, last) = (ele.first, ele.last);
225*5225e6b1SAndroid Build Coastguard Worker         if first > last + 1 || last > header.last || first < header.first {
226*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::GptError(GptError::InvalidPartitionRange {
227*5225e6b1SAndroid Build Coastguard Worker                 idx,
228*5225e6b1SAndroid Build Coastguard Worker                 part_range: (first, last),
229*5225e6b1SAndroid Build Coastguard Worker                 usable_range: (header.first, header.last),
230*5225e6b1SAndroid Build Coastguard Worker             }));
231*5225e6b1SAndroid Build Coastguard Worker         } else if ele.part_type == [0u8; GPT_GUID_LEN] {
232*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::GptError(GptError::ZeroPartitionTypeGUID { idx }));
233*5225e6b1SAndroid Build Coastguard Worker         } else if ele.guid == [0u8; GPT_GUID_LEN] {
234*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::GptError(GptError::ZeroPartitionUniqueGUID { idx }));
235*5225e6b1SAndroid Build Coastguard Worker         }
236*5225e6b1SAndroid Build Coastguard Worker     }
237*5225e6b1SAndroid Build Coastguard Worker 
238*5225e6b1SAndroid Build Coastguard Worker     // Checks overlap between partition ranges.
239*5225e6b1SAndroid Build Coastguard Worker     // Sorts an index array because we don't want to modify input.
240*5225e6b1SAndroid Build Coastguard Worker     let mut sorted_indices: [u8; GPT_MAX_NUM_ENTRIES] = from_fn(|i| i.try_into().unwrap());
241*5225e6b1SAndroid Build Coastguard Worker     sorted_indices.sort_unstable_by_key(|v| match entries.get(usize::try_from(*v).unwrap()) {
242*5225e6b1SAndroid Build Coastguard Worker         Some(v) if !v.is_null() => v.first,
243*5225e6b1SAndroid Build Coastguard Worker         _ => u64::MAX,
244*5225e6b1SAndroid Build Coastguard Worker     });
245*5225e6b1SAndroid Build Coastguard Worker 
246*5225e6b1SAndroid Build Coastguard Worker     let actual = entries.iter().position(|v| v.is_null()).unwrap_or(entries.len());
247*5225e6b1SAndroid Build Coastguard Worker     if actual > 1 {
248*5225e6b1SAndroid Build Coastguard Worker         for i in 0..actual - 1 {
249*5225e6b1SAndroid Build Coastguard Worker             let prev: usize = sorted_indices[i].try_into().unwrap();
250*5225e6b1SAndroid Build Coastguard Worker             let next: usize = sorted_indices[i + 1].try_into().unwrap();
251*5225e6b1SAndroid Build Coastguard Worker             if entries[prev].last >= entries[next].first {
252*5225e6b1SAndroid Build Coastguard Worker                 return Err(Error::GptError(GptError::PartitionRangeOverlap {
253*5225e6b1SAndroid Build Coastguard Worker                     prev: (prev + 1, entries[prev].first, entries[prev].last),
254*5225e6b1SAndroid Build Coastguard Worker                     next: (next + 1, entries[next].first, entries[next].last),
255*5225e6b1SAndroid Build Coastguard Worker                 }));
256*5225e6b1SAndroid Build Coastguard Worker             }
257*5225e6b1SAndroid Build Coastguard Worker         }
258*5225e6b1SAndroid Build Coastguard Worker     }
259*5225e6b1SAndroid Build Coastguard Worker 
260*5225e6b1SAndroid Build Coastguard Worker     Ok(())
261*5225e6b1SAndroid Build Coastguard Worker }
262*5225e6b1SAndroid Build Coastguard Worker 
263*5225e6b1SAndroid Build Coastguard Worker /// GptEntry is the partition entry data structure in the GPT.
264*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)]
265*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes, PartialEq)]
266*5225e6b1SAndroid Build Coastguard Worker pub struct GptEntry {
267*5225e6b1SAndroid Build Coastguard Worker     /// Partition type GUID.
268*5225e6b1SAndroid Build Coastguard Worker     pub part_type: [u8; GPT_GUID_LEN],
269*5225e6b1SAndroid Build Coastguard Worker     /// Unique partition GUID.
270*5225e6b1SAndroid Build Coastguard Worker     pub guid: [u8; GPT_GUID_LEN],
271*5225e6b1SAndroid Build Coastguard Worker     /// First block.
272*5225e6b1SAndroid Build Coastguard Worker     pub first: u64,
273*5225e6b1SAndroid Build Coastguard Worker     /// Last block (inclusive).
274*5225e6b1SAndroid Build Coastguard Worker     pub last: u64,
275*5225e6b1SAndroid Build Coastguard Worker     /// Partition flags.
276*5225e6b1SAndroid Build Coastguard Worker     pub flags: u64,
277*5225e6b1SAndroid Build Coastguard Worker     /// Partition name in UTF-16.
278*5225e6b1SAndroid Build Coastguard Worker     pub name: [u16; GPT_NAME_LEN_U16],
279*5225e6b1SAndroid Build Coastguard Worker }
280*5225e6b1SAndroid Build Coastguard Worker 
281*5225e6b1SAndroid Build Coastguard Worker impl GptEntry {
282*5225e6b1SAndroid Build Coastguard Worker     /// Return the partition entry size in blocks.
blocks(&self) -> Result<u64>283*5225e6b1SAndroid Build Coastguard Worker     pub fn blocks(&self) -> Result<u64> {
284*5225e6b1SAndroid Build Coastguard Worker         // Must perform "+1" first before subtracting `self.first`. Otherwise if partition size is
285*5225e6b1SAndroid Build Coastguard Worker         // zero, where `self.first > self.last`, arithmetic will overflow.
286*5225e6b1SAndroid Build Coastguard Worker         u64::try_from(SafeNum::from(self.last) + 1 - self.first).map_err(Into::into)
287*5225e6b1SAndroid Build Coastguard Worker     }
288*5225e6b1SAndroid Build Coastguard Worker 
289*5225e6b1SAndroid Build Coastguard Worker     /// Return whether this is a `NULL` entry. The first null entry marks the end of the partition
290*5225e6b1SAndroid Build Coastguard Worker     /// entries.
is_null(&self) -> bool291*5225e6b1SAndroid Build Coastguard Worker     fn is_null(&self) -> bool {
292*5225e6b1SAndroid Build Coastguard Worker         self.first == 0 && self.last == 0
293*5225e6b1SAndroid Build Coastguard Worker     }
294*5225e6b1SAndroid Build Coastguard Worker 
295*5225e6b1SAndroid Build Coastguard Worker     /// Decode the partition name into a string. A length N utf16 string can be at most 2N utf8
296*5225e6b1SAndroid Build Coastguard Worker     /// bytes. Therefore, a safe size of `buffer` is 2*GPT_NAME_LEN_U16 = 72.
name_to_str<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a str>297*5225e6b1SAndroid Build Coastguard Worker     pub fn name_to_str<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a str> {
298*5225e6b1SAndroid Build Coastguard Worker         let mut index = 0;
299*5225e6b1SAndroid Build Coastguard Worker         for c in char::decode_utf16(self.name) {
300*5225e6b1SAndroid Build Coastguard Worker             match c.unwrap_or(char::REPLACEMENT_CHARACTER) {
301*5225e6b1SAndroid Build Coastguard Worker                 '\0' => break,
302*5225e6b1SAndroid Build Coastguard Worker                 c if c.len_utf8() <= buffer[index..].len() => {
303*5225e6b1SAndroid Build Coastguard Worker                     index += c.encode_utf8(&mut buffer[index..]).len()
304*5225e6b1SAndroid Build Coastguard Worker                 }
305*5225e6b1SAndroid Build Coastguard Worker                 _ => return Err(Error::InvalidInput), // Not enough space in `buffer`.
306*5225e6b1SAndroid Build Coastguard Worker             }
307*5225e6b1SAndroid Build Coastguard Worker         }
308*5225e6b1SAndroid Build Coastguard Worker         // SAFETY:
309*5225e6b1SAndroid Build Coastguard Worker         // _unchecked should be OK here since we wrote each utf8 byte ourselves,
310*5225e6b1SAndroid Build Coastguard Worker         // but it's just an optimization, checked version would be fine also.
311*5225e6b1SAndroid Build Coastguard Worker         unsafe { Ok(core::str::from_utf8_unchecked(&buffer[..index])) }
312*5225e6b1SAndroid Build Coastguard Worker     }
313*5225e6b1SAndroid Build Coastguard Worker 
314*5225e6b1SAndroid Build Coastguard Worker     /// Checks if the partition name is the same as the given.
match_name(&self, part: &str) -> Result<bool>315*5225e6b1SAndroid Build Coastguard Worker     pub fn match_name(&self, part: &str) -> Result<bool> {
316*5225e6b1SAndroid Build Coastguard Worker         Ok(self.name_to_str(&mut [0u8; GPT_NAME_LEN_U16 * 2][..])? == part)
317*5225e6b1SAndroid Build Coastguard Worker     }
318*5225e6b1SAndroid Build Coastguard Worker }
319*5225e6b1SAndroid Build Coastguard Worker 
320*5225e6b1SAndroid Build Coastguard Worker impl core::fmt::Display for GptEntry {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result321*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322*5225e6b1SAndroid Build Coastguard Worker         // Format: partition name: "abc", [first, last]: [123, 456]
323*5225e6b1SAndroid Build Coastguard Worker         let mut name_conversion_buffer = [0u8; GPT_NAME_LEN_U16 * 2];
324*5225e6b1SAndroid Build Coastguard Worker         let name = self.name_to_str(&mut name_conversion_buffer).map_err(|_| core::fmt::Error)?;
325*5225e6b1SAndroid Build Coastguard Worker         // Note: The bracket around `{ self.first }` is for forcing a copy of the field because
326*5225e6b1SAndroid Build Coastguard Worker         // GptEntry is a packed structure.
327*5225e6b1SAndroid Build Coastguard Worker         write!(f, "partition: \"{}\", first: {}, last: {}", name, { self.first }, { self.last })
328*5225e6b1SAndroid Build Coastguard Worker     }
329*5225e6b1SAndroid Build Coastguard Worker }
330*5225e6b1SAndroid Build Coastguard Worker 
331*5225e6b1SAndroid Build Coastguard Worker // core::mem::offset_of!(GptHeader, crc32) is unsatble feature and rejected by the compiler in our
332*5225e6b1SAndroid Build Coastguard Worker // settings. We pre-compute the value here.
333*5225e6b1SAndroid Build Coastguard Worker const GPT_CRC32_OFFSET: usize = 16;
334*5225e6b1SAndroid Build Coastguard Worker const GPT_ENTRY_SIZE: usize = size_of::<GptEntry>();
335*5225e6b1SAndroid Build Coastguard Worker const GPT_MAX_NUM_ENTRIES: usize = 128;
336*5225e6b1SAndroid Build Coastguard Worker const GPT_MAX_NUM_ENTRIES_SIZE: usize = GPT_MAX_NUM_ENTRIES * GPT_ENTRY_SIZE;
337*5225e6b1SAndroid Build Coastguard Worker /// GPT header magic bytes ("EFI PART" in ASCII).
338*5225e6b1SAndroid Build Coastguard Worker pub const GPT_MAGIC: u64 = 0x5452415020494645;
339*5225e6b1SAndroid Build Coastguard Worker 
340*5225e6b1SAndroid Build Coastguard Worker enum HeaderType {
341*5225e6b1SAndroid Build Coastguard Worker     Primary,
342*5225e6b1SAndroid Build Coastguard Worker     Secondary,
343*5225e6b1SAndroid Build Coastguard Worker }
344*5225e6b1SAndroid Build Coastguard Worker 
345*5225e6b1SAndroid Build Coastguard Worker /// `Partition` contains information about a GPT partition.
346*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, PartialEq)]
347*5225e6b1SAndroid Build Coastguard Worker pub struct Partition {
348*5225e6b1SAndroid Build Coastguard Worker     entry: GptEntry,
349*5225e6b1SAndroid Build Coastguard Worker     block_size: u64,
350*5225e6b1SAndroid Build Coastguard Worker     decoded_name: Option<([u8; GPT_NAME_LEN_U8], usize)>,
351*5225e6b1SAndroid Build Coastguard Worker }
352*5225e6b1SAndroid Build Coastguard Worker 
353*5225e6b1SAndroid Build Coastguard Worker impl Partition {
354*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance.
new(entry: GptEntry, block_size: u64) -> Self355*5225e6b1SAndroid Build Coastguard Worker     fn new(entry: GptEntry, block_size: u64) -> Self {
356*5225e6b1SAndroid Build Coastguard Worker         let mut buf = [0u8; GPT_NAME_LEN_U8];
357*5225e6b1SAndroid Build Coastguard Worker         let decoded_name = match entry.name_to_str(&mut buf[..]).ok().map(|v| v.len()) {
358*5225e6b1SAndroid Build Coastguard Worker             Some(len) => Some((buf, len)),
359*5225e6b1SAndroid Build Coastguard Worker             _ => None,
360*5225e6b1SAndroid Build Coastguard Worker         };
361*5225e6b1SAndroid Build Coastguard Worker         Self { entry, block_size, decoded_name }
362*5225e6b1SAndroid Build Coastguard Worker     }
363*5225e6b1SAndroid Build Coastguard Worker 
364*5225e6b1SAndroid Build Coastguard Worker     /// Gets the decoded partition name.
name(&self) -> Option<&str>365*5225e6b1SAndroid Build Coastguard Worker     pub fn name(&self) -> Option<&str> {
366*5225e6b1SAndroid Build Coastguard Worker         // Correct by construction. `from_utf8` should not fail.
367*5225e6b1SAndroid Build Coastguard Worker         self.decoded_name.as_ref().map(|(buf, sz)| from_utf8(&buf[..*sz]).unwrap())
368*5225e6b1SAndroid Build Coastguard Worker     }
369*5225e6b1SAndroid Build Coastguard Worker 
370*5225e6b1SAndroid Build Coastguard Worker     /// Returns the partition size in bytes.
size(&self) -> Result<u64>371*5225e6b1SAndroid Build Coastguard Worker     pub fn size(&self) -> Result<u64> {
372*5225e6b1SAndroid Build Coastguard Worker         u64::try_from(SafeNum::from(self.entry.blocks()?) * self.block_size).map_err(Error::from)
373*5225e6b1SAndroid Build Coastguard Worker     }
374*5225e6b1SAndroid Build Coastguard Worker 
375*5225e6b1SAndroid Build Coastguard Worker     /// Returns the block size of this partition.
block_size(&self) -> u64376*5225e6b1SAndroid Build Coastguard Worker     pub fn block_size(&self) -> u64 {
377*5225e6b1SAndroid Build Coastguard Worker         self.block_size
378*5225e6b1SAndroid Build Coastguard Worker     }
379*5225e6b1SAndroid Build Coastguard Worker 
380*5225e6b1SAndroid Build Coastguard Worker     /// Returns the partition entry structure in the GPT header.
gpt_entry(&self) -> &GptEntry381*5225e6b1SAndroid Build Coastguard Worker     pub fn gpt_entry(&self) -> &GptEntry {
382*5225e6b1SAndroid Build Coastguard Worker         &self.entry
383*5225e6b1SAndroid Build Coastguard Worker     }
384*5225e6b1SAndroid Build Coastguard Worker 
385*5225e6b1SAndroid Build Coastguard Worker     /// Returns the partition's absolute start/end offset in number of bytes.
absolute_range(&self) -> Result<(u64, u64)>386*5225e6b1SAndroid Build Coastguard Worker     pub fn absolute_range(&self) -> Result<(u64, u64)> {
387*5225e6b1SAndroid Build Coastguard Worker         let start = SafeNum::from(self.entry.first) * self.block_size;
388*5225e6b1SAndroid Build Coastguard Worker         let end = (SafeNum::from(self.entry.last) + 1) * self.block_size;
389*5225e6b1SAndroid Build Coastguard Worker         Ok((start.try_into()?, end.try_into()?))
390*5225e6b1SAndroid Build Coastguard Worker     }
391*5225e6b1SAndroid Build Coastguard Worker 
392*5225e6b1SAndroid Build Coastguard Worker     /// Checks a given sub range and returns its absolute offset.
check_range(&self, off: u64, size: u64) -> Result<u64>393*5225e6b1SAndroid Build Coastguard Worker     pub fn check_range(&self, off: u64, size: u64) -> Result<u64> {
394*5225e6b1SAndroid Build Coastguard Worker         let off = SafeNum::from(off);
395*5225e6b1SAndroid Build Coastguard Worker         let end: u64 = (off + size).try_into()?;
396*5225e6b1SAndroid Build Coastguard Worker         match end > self.size()? {
397*5225e6b1SAndroid Build Coastguard Worker             true => Err(Error::BadIndex(end as usize)),
398*5225e6b1SAndroid Build Coastguard Worker             _ => Ok((off + self.absolute_range()?.0).try_into()?),
399*5225e6b1SAndroid Build Coastguard Worker         }
400*5225e6b1SAndroid Build Coastguard Worker     }
401*5225e6b1SAndroid Build Coastguard Worker }
402*5225e6b1SAndroid Build Coastguard Worker 
403*5225e6b1SAndroid Build Coastguard Worker /// `PartitionIterator` iterates all GPT partition entries.
404*5225e6b1SAndroid Build Coastguard Worker pub struct PartitionIterator<'a> {
405*5225e6b1SAndroid Build Coastguard Worker     entries: &'a [GptEntry],
406*5225e6b1SAndroid Build Coastguard Worker     block_size: u64,
407*5225e6b1SAndroid Build Coastguard Worker     idx: usize,
408*5225e6b1SAndroid Build Coastguard Worker }
409*5225e6b1SAndroid Build Coastguard Worker 
410*5225e6b1SAndroid Build Coastguard Worker impl Iterator for PartitionIterator<'_> {
411*5225e6b1SAndroid Build Coastguard Worker     type Item = Partition;
412*5225e6b1SAndroid Build Coastguard Worker 
next(&mut self) -> Option<Self::Item>413*5225e6b1SAndroid Build Coastguard Worker     fn next(&mut self) -> Option<Self::Item> {
414*5225e6b1SAndroid Build Coastguard Worker         let res = self
415*5225e6b1SAndroid Build Coastguard Worker             .entries
416*5225e6b1SAndroid Build Coastguard Worker             .get(self.idx)
417*5225e6b1SAndroid Build Coastguard Worker             .filter(|v| !v.is_null())
418*5225e6b1SAndroid Build Coastguard Worker             .map(|v| Partition::new(*v, self.block_size))?;
419*5225e6b1SAndroid Build Coastguard Worker         self.idx += 1;
420*5225e6b1SAndroid Build Coastguard Worker         Some(res)
421*5225e6b1SAndroid Build Coastguard Worker     }
422*5225e6b1SAndroid Build Coastguard Worker }
423*5225e6b1SAndroid Build Coastguard Worker 
424*5225e6b1SAndroid Build Coastguard Worker /// Contains result of GPT syncing/restoration.
425*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, PartialEq, Debug, Default)]
426*5225e6b1SAndroid Build Coastguard Worker pub enum GptSyncResult {
427*5225e6b1SAndroid Build Coastguard Worker     /// Both primary and secondary GPT are valid.
428*5225e6b1SAndroid Build Coastguard Worker     #[default]
429*5225e6b1SAndroid Build Coastguard Worker     BothValid,
430*5225e6b1SAndroid Build Coastguard Worker     /// Primary GPT is invalid and restored.
431*5225e6b1SAndroid Build Coastguard Worker     PrimaryRestored(Error),
432*5225e6b1SAndroid Build Coastguard Worker     /// Secondary GPT is invalid and restored.
433*5225e6b1SAndroid Build Coastguard Worker     SecondaryRestored(Error),
434*5225e6b1SAndroid Build Coastguard Worker     /// Neither primary or secondary GPT is valid.
435*5225e6b1SAndroid Build Coastguard Worker     NoValidGpt {
436*5225e6b1SAndroid Build Coastguard Worker         /// Primary GPT verify error.
437*5225e6b1SAndroid Build Coastguard Worker         primary: Error,
438*5225e6b1SAndroid Build Coastguard Worker         /// Secondary GPT verify error.
439*5225e6b1SAndroid Build Coastguard Worker         secondary: Error,
440*5225e6b1SAndroid Build Coastguard Worker     },
441*5225e6b1SAndroid Build Coastguard Worker }
442*5225e6b1SAndroid Build Coastguard Worker 
443*5225e6b1SAndroid Build Coastguard Worker impl GptSyncResult {
444*5225e6b1SAndroid Build Coastguard Worker     /// Combined into a result
res(&self) -> Result<()>445*5225e6b1SAndroid Build Coastguard Worker     pub fn res(&self) -> Result<()> {
446*5225e6b1SAndroid Build Coastguard Worker         match self {
447*5225e6b1SAndroid Build Coastguard Worker             Self::NoValidGpt { primary: e, .. } => Err(*e),
448*5225e6b1SAndroid Build Coastguard Worker             _ => Ok(()),
449*5225e6b1SAndroid Build Coastguard Worker         }
450*5225e6b1SAndroid Build Coastguard Worker     }
451*5225e6b1SAndroid Build Coastguard Worker }
452*5225e6b1SAndroid Build Coastguard Worker 
453*5225e6b1SAndroid Build Coastguard Worker impl core::fmt::Display for GptSyncResult {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result454*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
455*5225e6b1SAndroid Build Coastguard Worker         match self {
456*5225e6b1SAndroid Build Coastguard Worker             Self::BothValid => write!(f, "Found valid GPT."),
457*5225e6b1SAndroid Build Coastguard Worker             Self::PrimaryRestored(e) => write!(f, "Primary GPT restored due to {e:?}."),
458*5225e6b1SAndroid Build Coastguard Worker             Self::SecondaryRestored(e) => write!(f, "Secondary GPT restored due to {e:?}."),
459*5225e6b1SAndroid Build Coastguard Worker             Self::NoValidGpt { primary, secondary } => {
460*5225e6b1SAndroid Build Coastguard Worker                 write!(f, "No valid GPT. primary: {primary:?}, secondary: {secondary:?}.")
461*5225e6b1SAndroid Build Coastguard Worker             }
462*5225e6b1SAndroid Build Coastguard Worker         }
463*5225e6b1SAndroid Build Coastguard Worker     }
464*5225e6b1SAndroid Build Coastguard Worker }
465*5225e6b1SAndroid Build Coastguard Worker 
466*5225e6b1SAndroid Build Coastguard Worker /// A packed wrapper of `Option<NonZeroU64>`
467*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)]
468*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
469*5225e6b1SAndroid Build Coastguard Worker struct BlockSize(Option<NonZeroU64>);
470*5225e6b1SAndroid Build Coastguard Worker 
471*5225e6b1SAndroid Build Coastguard Worker /// Represents the structure of a load buffer for loading/verifying/syncing up to N GPT entries.
472*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)]
473*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
474*5225e6b1SAndroid Build Coastguard Worker pub struct GptLoadBufferN<const N: usize> {
475*5225e6b1SAndroid Build Coastguard Worker     // GPT doesn't care about block size. But it's easier to have it available for computing offset
476*5225e6b1SAndroid Build Coastguard Worker     // and size in bytes for partitions. It's also used as a flag for indicating whether a valid
477*5225e6b1SAndroid Build Coastguard Worker     // GPT is loaded.
478*5225e6b1SAndroid Build Coastguard Worker     block_size: BlockSize,
479*5225e6b1SAndroid Build Coastguard Worker     primary_header: GptHeader,
480*5225e6b1SAndroid Build Coastguard Worker     secondary_header: GptHeader,
481*5225e6b1SAndroid Build Coastguard Worker     primary_entries: [GptEntry; N],
482*5225e6b1SAndroid Build Coastguard Worker     secondary_entries: [GptEntry; N],
483*5225e6b1SAndroid Build Coastguard Worker }
484*5225e6b1SAndroid Build Coastguard Worker 
485*5225e6b1SAndroid Build Coastguard Worker impl<const N: usize> Deref for GptLoadBufferN<N> {
486*5225e6b1SAndroid Build Coastguard Worker     type Target = [u8];
487*5225e6b1SAndroid Build Coastguard Worker 
deref(&self) -> &Self::Target488*5225e6b1SAndroid Build Coastguard Worker     fn deref(&self) -> &Self::Target {
489*5225e6b1SAndroid Build Coastguard Worker         self.as_bytes()
490*5225e6b1SAndroid Build Coastguard Worker     }
491*5225e6b1SAndroid Build Coastguard Worker }
492*5225e6b1SAndroid Build Coastguard Worker 
493*5225e6b1SAndroid Build Coastguard Worker impl<const N: usize> DerefMut for GptLoadBufferN<N> {
deref_mut(&mut self) -> &mut Self::Target494*5225e6b1SAndroid Build Coastguard Worker     fn deref_mut(&mut self) -> &mut Self::Target {
495*5225e6b1SAndroid Build Coastguard Worker         self.as_bytes_mut()
496*5225e6b1SAndroid Build Coastguard Worker     }
497*5225e6b1SAndroid Build Coastguard Worker }
498*5225e6b1SAndroid Build Coastguard Worker 
499*5225e6b1SAndroid Build Coastguard Worker /// Contains references corresponding to different GPT load entities parsed from a load buffer.
500*5225e6b1SAndroid Build Coastguard Worker ///
501*5225e6b1SAndroid Build Coastguard Worker /// The structure is simply for organizing together the individual references of fields in
502*5225e6b1SAndroid Build Coastguard Worker /// `GptLoadBufferN` parsed from a raw buffer. Note that we can't parse a `Ref<B, GptLoadBufferN>`
503*5225e6b1SAndroid Build Coastguard Worker /// directly from a buffer because the number of entries (length of [GptEntry]) in this case needs
504*5225e6b1SAndroid Build Coastguard Worker /// to be computed at run time based on the buffer size.
505*5225e6b1SAndroid Build Coastguard Worker struct LoadBufferRef<B: ByteSlice> {
506*5225e6b1SAndroid Build Coastguard Worker     block_size: Ref<B, BlockSize>,
507*5225e6b1SAndroid Build Coastguard Worker     primary_header: Ref<B, GptHeader>,
508*5225e6b1SAndroid Build Coastguard Worker     secondary_header: Ref<B, GptHeader>,
509*5225e6b1SAndroid Build Coastguard Worker     primary_entries: Ref<B, [GptEntry]>,
510*5225e6b1SAndroid Build Coastguard Worker     secondary_entries: Ref<B, [GptEntry]>,
511*5225e6b1SAndroid Build Coastguard Worker }
512*5225e6b1SAndroid Build Coastguard Worker 
513*5225e6b1SAndroid Build Coastguard Worker impl<B: ByteSlice> LoadBufferRef<B> {
from(buffer: B) -> Self514*5225e6b1SAndroid Build Coastguard Worker     fn from(buffer: B) -> Self {
515*5225e6b1SAndroid Build Coastguard Worker         let n = min(GPT_MAX_NUM_ENTRIES, max_supported_entries(&buffer[..]).unwrap());
516*5225e6b1SAndroid Build Coastguard Worker         let (block_size, rest) = Ref::new_from_prefix(buffer).unwrap();
517*5225e6b1SAndroid Build Coastguard Worker         let (primary_header, rest) = Ref::new_from_prefix(rest).unwrap();
518*5225e6b1SAndroid Build Coastguard Worker         let (secondary_header, rest) = Ref::new_from_prefix(rest).unwrap();
519*5225e6b1SAndroid Build Coastguard Worker         let (primary_entries, rest) = Ref::new_slice_from_prefix(rest, n).unwrap();
520*5225e6b1SAndroid Build Coastguard Worker         let (secondary_entries, _) = Ref::new_slice_from_prefix(rest, n).unwrap();
521*5225e6b1SAndroid Build Coastguard Worker         Self { block_size, primary_header, secondary_header, primary_entries, secondary_entries }
522*5225e6b1SAndroid Build Coastguard Worker     }
523*5225e6b1SAndroid Build Coastguard Worker 
524*5225e6b1SAndroid Build Coastguard Worker     /// Unpacks into the secondary GPT header/entries
secondary(self) -> (Ref<B, GptHeader>, Ref<B, [GptEntry]>)525*5225e6b1SAndroid Build Coastguard Worker     fn secondary(self) -> (Ref<B, GptHeader>, Ref<B, [GptEntry]>) {
526*5225e6b1SAndroid Build Coastguard Worker         (self.secondary_header, self.secondary_entries)
527*5225e6b1SAndroid Build Coastguard Worker     }
528*5225e6b1SAndroid Build Coastguard Worker }
529*5225e6b1SAndroid Build Coastguard Worker 
530*5225e6b1SAndroid Build Coastguard Worker /// The minimum buffer size needed for creating a [Gpt] that can load `entries` number of
531*5225e6b1SAndroid Build Coastguard Worker /// partitions.
532*5225e6b1SAndroid Build Coastguard Worker ///
533*5225e6b1SAndroid Build Coastguard Worker /// # Returns
534*5225e6b1SAndroid Build Coastguard Worker ///
535*5225e6b1SAndroid Build Coastguard Worker /// * Returns Ok(size) on success.
536*5225e6b1SAndroid Build Coastguard Worker /// * Returns Err(Error::InvalidInput) if max_entries is greater than 128.
gpt_buffer_size(entries: usize) -> Result<usize>537*5225e6b1SAndroid Build Coastguard Worker pub fn gpt_buffer_size(entries: usize) -> Result<usize> {
538*5225e6b1SAndroid Build Coastguard Worker     match entries > GPT_MAX_NUM_ENTRIES {
539*5225e6b1SAndroid Build Coastguard Worker         true => Err(Error::InvalidInput),
540*5225e6b1SAndroid Build Coastguard Worker         _ => Ok(size_of::<GptLoadBufferN<0>>() + entries * GPT_ENTRY_SIZE * 2),
541*5225e6b1SAndroid Build Coastguard Worker     }
542*5225e6b1SAndroid Build Coastguard Worker }
543*5225e6b1SAndroid Build Coastguard Worker 
544*5225e6b1SAndroid Build Coastguard Worker /// Computes the maximum number of entries that can be loaded if using the given buffer for [Gpt].
max_supported_entries(buf: &[u8]) -> Result<usize>545*5225e6b1SAndroid Build Coastguard Worker fn max_supported_entries(buf: &[u8]) -> Result<usize> {
546*5225e6b1SAndroid Build Coastguard Worker     match buf.len() < size_of::<GptLoadBufferN<0>>() {
547*5225e6b1SAndroid Build Coastguard Worker         true => Err(Error::BufferTooSmall(Some(size_of::<GptLoadBufferN<0>>()))),
548*5225e6b1SAndroid Build Coastguard Worker         _ => Ok((buf.len() - size_of::<GptLoadBufferN<0>>()) / 2 / GPT_ENTRY_SIZE),
549*5225e6b1SAndroid Build Coastguard Worker     }
550*5225e6b1SAndroid Build Coastguard Worker }
551*5225e6b1SAndroid Build Coastguard Worker 
552*5225e6b1SAndroid Build Coastguard Worker /// [Gpt] manages a buffer for loading, verifying and syncing GPT.
553*5225e6b1SAndroid Build Coastguard Worker pub struct Gpt<B> {
554*5225e6b1SAndroid Build Coastguard Worker     buffer: B,
555*5225e6b1SAndroid Build Coastguard Worker }
556*5225e6b1SAndroid Build Coastguard Worker 
557*5225e6b1SAndroid Build Coastguard Worker impl<B: DerefMut<Target = [u8]>> Gpt<B> {
558*5225e6b1SAndroid Build Coastguard Worker     /// Create an uninitialized Gpt instance from a provided buffer.
559*5225e6b1SAndroid Build Coastguard Worker     ///
560*5225e6b1SAndroid Build Coastguard Worker     /// The created [Gpt] can then be used in `Disk::sync_gpt()` for loading, verifying and syncing
561*5225e6b1SAndroid Build Coastguard Worker     /// GPT on disk.
562*5225e6b1SAndroid Build Coastguard Worker     ///
563*5225e6b1SAndroid Build Coastguard Worker     /// # Args:
564*5225e6b1SAndroid Build Coastguard Worker     ///
565*5225e6b1SAndroid Build Coastguard Worker     /// * `buffer`: A buffer to use for loading, verifying and syncing primary and secondary GPT.
566*5225e6b1SAndroid Build Coastguard Worker     ///   The size of the buffer determines the maximum number of partition entries that can be
567*5225e6b1SAndroid Build Coastguard Worker     ///   loaded. If actual number of partitions, specified by `entries_count` in the GPT header,
568*5225e6b1SAndroid Build Coastguard Worker     ///   exceeds it, verification and sync will eventually fail with `Error::BufferTooSmall`.
569*5225e6b1SAndroid Build Coastguard Worker     ///   `gpt_buffer_size(num_entries)` can be used to compute the required size of buffer for
570*5225e6b1SAndroid Build Coastguard Worker     ///   loading a specific number of entries. Note that most tools and OS fix the `entries_count`
571*5225e6b1SAndroid Build Coastguard Worker     ///   value to the max 128 regardless of the actual number of partition entries used. Thus
572*5225e6b1SAndroid Build Coastguard Worker     ///   unless you have full control of GPT generation in your entire system where you can always
573*5225e6b1SAndroid Build Coastguard Worker     ///   ensure a smaller bound on it, it is recommended to always provide enough buffer for
574*5225e6b1SAndroid Build Coastguard Worker     ///   loading 128 entries.
575*5225e6b1SAndroid Build Coastguard Worker     ///
576*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
577*5225e6b1SAndroid Build Coastguard Worker     ///
578*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok(Self) on success.
579*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Err(Error::BufferTooSmall) if buffer is less than the minimum size.
new(mut buffer: B) -> Result<Self>580*5225e6b1SAndroid Build Coastguard Worker     pub fn new(mut buffer: B) -> Result<Self> {
581*5225e6b1SAndroid Build Coastguard Worker         max_supported_entries(&buffer[..])?;
582*5225e6b1SAndroid Build Coastguard Worker         LoadBufferRef::from(&mut buffer[..]).block_size.0 = None;
583*5225e6b1SAndroid Build Coastguard Worker         Ok(Self { buffer })
584*5225e6b1SAndroid Build Coastguard Worker     }
585*5225e6b1SAndroid Build Coastguard Worker 
586*5225e6b1SAndroid Build Coastguard Worker     /// Returns the maximum allowed entries.
max_entries(&self) -> usize587*5225e6b1SAndroid Build Coastguard Worker     pub fn max_entries(&self) -> usize {
588*5225e6b1SAndroid Build Coastguard Worker         max_supported_entries(&self.buffer[..]).unwrap()
589*5225e6b1SAndroid Build Coastguard Worker     }
590*5225e6b1SAndroid Build Coastguard Worker 
591*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of `Gpt<&mut [u8]>` that borrows the internal GPT buffer.
as_borrowed(&mut self) -> Gpt<&mut [u8]>592*5225e6b1SAndroid Build Coastguard Worker     pub fn as_borrowed(&mut self) -> Gpt<&mut [u8]> {
593*5225e6b1SAndroid Build Coastguard Worker         Gpt { buffer: &mut self.buffer[..] }
594*5225e6b1SAndroid Build Coastguard Worker     }
595*5225e6b1SAndroid Build Coastguard Worker 
596*5225e6b1SAndroid Build Coastguard Worker     /// Returns an iterator to GPT partition entries.
597*5225e6b1SAndroid Build Coastguard Worker     ///
598*5225e6b1SAndroid Build Coastguard Worker     /// If the object does not contain a valid GPT, the method returns Error.
partition_iter(&self) -> Result<PartitionIterator>599*5225e6b1SAndroid Build Coastguard Worker     pub fn partition_iter(&self) -> Result<PartitionIterator> {
600*5225e6b1SAndroid Build Coastguard Worker         let block_size = self.check_valid()?;
601*5225e6b1SAndroid Build Coastguard Worker         let entries = LoadBufferRef::from(&self.buffer[..]).primary_entries.into_slice();
602*5225e6b1SAndroid Build Coastguard Worker         Ok(PartitionIterator { entries, idx: 0, block_size })
603*5225e6b1SAndroid Build Coastguard Worker     }
604*5225e6b1SAndroid Build Coastguard Worker 
605*5225e6b1SAndroid Build Coastguard Worker     /// Checks if a read/write range into a GPT partition overflows and returns the range's absolute
606*5225e6b1SAndroid Build Coastguard Worker     /// offset in number of bytes.
check_range(&self, part_name: &str, offset: u64, size: usize) -> Result<u64>607*5225e6b1SAndroid Build Coastguard Worker     pub fn check_range(&self, part_name: &str, offset: u64, size: usize) -> Result<u64> {
608*5225e6b1SAndroid Build Coastguard Worker         self.find_partition(part_name)?.check_range(offset, u64::try_from(size)?)
609*5225e6b1SAndroid Build Coastguard Worker     }
610*5225e6b1SAndroid Build Coastguard Worker 
611*5225e6b1SAndroid Build Coastguard Worker     /// Return the list of GPT entries.
612*5225e6b1SAndroid Build Coastguard Worker     ///
613*5225e6b1SAndroid Build Coastguard Worker     /// If there is not a valid GPT, the method returns Error.
entries(&self) -> Result<&[GptEntry]>614*5225e6b1SAndroid Build Coastguard Worker     pub fn entries(&self) -> Result<&[GptEntry]> {
615*5225e6b1SAndroid Build Coastguard Worker         self.check_valid()?;
616*5225e6b1SAndroid Build Coastguard Worker         let entries = LoadBufferRef::from(&self.buffer[..]).primary_entries.into_slice();
617*5225e6b1SAndroid Build Coastguard Worker         let n = entries.iter().position(|v| v.is_null()).unwrap_or(entries.len());
618*5225e6b1SAndroid Build Coastguard Worker         Ok(&entries[..n])
619*5225e6b1SAndroid Build Coastguard Worker     }
620*5225e6b1SAndroid Build Coastguard Worker 
621*5225e6b1SAndroid Build Coastguard Worker     /// Returns the total number of partitions.
num_partitions(&self) -> Result<usize>622*5225e6b1SAndroid Build Coastguard Worker     pub fn num_partitions(&self) -> Result<usize> {
623*5225e6b1SAndroid Build Coastguard Worker         Ok(self.entries()?.len())
624*5225e6b1SAndroid Build Coastguard Worker     }
625*5225e6b1SAndroid Build Coastguard Worker 
626*5225e6b1SAndroid Build Coastguard Worker     /// Gets the `idx`th partition.
get_partition(&self, idx: usize) -> Result<Partition>627*5225e6b1SAndroid Build Coastguard Worker     pub fn get_partition(&self, idx: usize) -> Result<Partition> {
628*5225e6b1SAndroid Build Coastguard Worker         let block_size = self.check_valid()?;
629*5225e6b1SAndroid Build Coastguard Worker         let entry = *self.entries()?.get(idx).ok_or(Error::BadIndex(idx))?;
630*5225e6b1SAndroid Build Coastguard Worker         Ok(Partition::new(entry, block_size))
631*5225e6b1SAndroid Build Coastguard Worker     }
632*5225e6b1SAndroid Build Coastguard Worker 
633*5225e6b1SAndroid Build Coastguard Worker     /// Returns the `Partition` for a partition.
634*5225e6b1SAndroid Build Coastguard Worker     ///
635*5225e6b1SAndroid Build Coastguard Worker     /// # Args
636*5225e6b1SAndroid Build Coastguard Worker     ///
637*5225e6b1SAndroid Build Coastguard Worker     /// * `part`: Name of the partition.
find_partition(&self, part: &str) -> Result<Partition>638*5225e6b1SAndroid Build Coastguard Worker     pub fn find_partition(&self, part: &str) -> Result<Partition> {
639*5225e6b1SAndroid Build Coastguard Worker         let block_size = self.check_valid()?;
640*5225e6b1SAndroid Build Coastguard Worker         for entry in self.entries()? {
641*5225e6b1SAndroid Build Coastguard Worker             let mut name_conversion_buffer = [0u8; GPT_NAME_LEN_U16 * 2];
642*5225e6b1SAndroid Build Coastguard Worker             if entry.name_to_str(&mut name_conversion_buffer)? != part {
643*5225e6b1SAndroid Build Coastguard Worker                 continue;
644*5225e6b1SAndroid Build Coastguard Worker             }
645*5225e6b1SAndroid Build Coastguard Worker             return Ok(Partition::new(*entry, block_size));
646*5225e6b1SAndroid Build Coastguard Worker         }
647*5225e6b1SAndroid Build Coastguard Worker         Err(Error::NotFound)
648*5225e6b1SAndroid Build Coastguard Worker     }
649*5225e6b1SAndroid Build Coastguard Worker 
650*5225e6b1SAndroid Build Coastguard Worker     /// Checks whether the Gpt has been initialized and returns the block size.
check_valid(&self) -> Result<u64>651*5225e6b1SAndroid Build Coastguard Worker     fn check_valid(&self) -> Result<u64> {
652*5225e6b1SAndroid Build Coastguard Worker         Ok(LoadBufferRef::from(&self.buffer[..]).block_size.0.ok_or(Error::InvalidState)?.get())
653*5225e6b1SAndroid Build Coastguard Worker     }
654*5225e6b1SAndroid Build Coastguard Worker 
655*5225e6b1SAndroid Build Coastguard Worker     /// Helper function for loading and validating GPT header and entries.
load_and_validate_gpt( &mut self, disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, hdr_type: HeaderType, ) -> Result<()>656*5225e6b1SAndroid Build Coastguard Worker     async fn load_and_validate_gpt(
657*5225e6b1SAndroid Build Coastguard Worker         &mut self,
658*5225e6b1SAndroid Build Coastguard Worker         disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
659*5225e6b1SAndroid Build Coastguard Worker         hdr_type: HeaderType,
660*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
661*5225e6b1SAndroid Build Coastguard Worker         let blk_sz = disk.io().info().block_size;
662*5225e6b1SAndroid Build Coastguard Worker         let load = LoadBufferRef::from(&mut self.buffer[..]);
663*5225e6b1SAndroid Build Coastguard Worker         let (header_start, mut header, mut entries) = match hdr_type {
664*5225e6b1SAndroid Build Coastguard Worker             HeaderType::Primary => (blk_sz, load.primary_header, load.primary_entries),
665*5225e6b1SAndroid Build Coastguard Worker             HeaderType::Secondary => (
666*5225e6b1SAndroid Build Coastguard Worker                 ((SafeNum::from(disk.io().info().num_blocks) - 1) * blk_sz).try_into()?,
667*5225e6b1SAndroid Build Coastguard Worker                 load.secondary_header,
668*5225e6b1SAndroid Build Coastguard Worker                 load.secondary_entries,
669*5225e6b1SAndroid Build Coastguard Worker             ),
670*5225e6b1SAndroid Build Coastguard Worker         };
671*5225e6b1SAndroid Build Coastguard Worker 
672*5225e6b1SAndroid Build Coastguard Worker         // Loads the header
673*5225e6b1SAndroid Build Coastguard Worker         disk.read(header_start, header.as_bytes_mut()).await?;
674*5225e6b1SAndroid Build Coastguard Worker         // Checks header.
675*5225e6b1SAndroid Build Coastguard Worker         check_header(disk.io(), &header, matches!(hdr_type, HeaderType::Primary))?;
676*5225e6b1SAndroid Build Coastguard Worker         // Loads the entries.
677*5225e6b1SAndroid Build Coastguard Worker         let entries_size = SafeNum::from(header.entries_count) * GPT_ENTRY_SIZE;
678*5225e6b1SAndroid Build Coastguard Worker         let entries_offset = SafeNum::from(header.entries) * blk_sz;
679*5225e6b1SAndroid Build Coastguard Worker         let out = entries.as_bytes_mut().get_mut(..entries_size.try_into().unwrap()).ok_or(
680*5225e6b1SAndroid Build Coastguard Worker             Error::BufferTooSmall(Some(
681*5225e6b1SAndroid Build Coastguard Worker                 gpt_buffer_size(header.entries_count.try_into().unwrap()).unwrap(),
682*5225e6b1SAndroid Build Coastguard Worker             )),
683*5225e6b1SAndroid Build Coastguard Worker         )?;
684*5225e6b1SAndroid Build Coastguard Worker         disk.read(entries_offset.try_into().unwrap(), out).await?;
685*5225e6b1SAndroid Build Coastguard Worker         // Checks entries.
686*5225e6b1SAndroid Build Coastguard Worker         check_entries(&header, entries.as_bytes())
687*5225e6b1SAndroid Build Coastguard Worker     }
688*5225e6b1SAndroid Build Coastguard Worker 
689*5225e6b1SAndroid Build Coastguard Worker     /// Loads and syncs GPT from a block device.
690*5225e6b1SAndroid Build Coastguard Worker     ///
691*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok(sync_result) if disk IO is successful, where `sync_result` contains the GPT
692*5225e6b1SAndroid Build Coastguard Worker     ///   verification and restoration result,
693*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Err() if disk IO encounters error.
load_and_sync( &mut self, disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, ) -> Result<GptSyncResult>694*5225e6b1SAndroid Build Coastguard Worker     pub(crate) async fn load_and_sync(
695*5225e6b1SAndroid Build Coastguard Worker         &mut self,
696*5225e6b1SAndroid Build Coastguard Worker         disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
697*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<GptSyncResult> {
698*5225e6b1SAndroid Build Coastguard Worker         let blk_sz = disk.io().info().block_size;
699*5225e6b1SAndroid Build Coastguard Worker         let nonzero_blk_sz = NonZeroU64::new(blk_sz).ok_or(Error::InvalidInput)?;
700*5225e6b1SAndroid Build Coastguard Worker         let total_blocks: SafeNum = disk.io().info().num_blocks.into();
701*5225e6b1SAndroid Build Coastguard Worker 
702*5225e6b1SAndroid Build Coastguard Worker         let primary_header_blk = 1;
703*5225e6b1SAndroid Build Coastguard Worker         let primary_header_pos = blk_sz;
704*5225e6b1SAndroid Build Coastguard Worker         let secondary_header_blk = total_blocks - 1;
705*5225e6b1SAndroid Build Coastguard Worker 
706*5225e6b1SAndroid Build Coastguard Worker         // Entries position for restoring.
707*5225e6b1SAndroid Build Coastguard Worker         let primary_entries_blk = 2;
708*5225e6b1SAndroid Build Coastguard Worker         let primary_entries_pos = SafeNum::from(primary_entries_blk) * blk_sz;
709*5225e6b1SAndroid Build Coastguard Worker         let primary_res = self.load_and_validate_gpt(disk, HeaderType::Primary).await;
710*5225e6b1SAndroid Build Coastguard Worker         let secondary_res = self.load_and_validate_gpt(disk, HeaderType::Secondary).await;
711*5225e6b1SAndroid Build Coastguard Worker 
712*5225e6b1SAndroid Build Coastguard Worker         let LoadBufferRef {
713*5225e6b1SAndroid Build Coastguard Worker             mut block_size,
714*5225e6b1SAndroid Build Coastguard Worker             mut primary_header,
715*5225e6b1SAndroid Build Coastguard Worker             mut secondary_header,
716*5225e6b1SAndroid Build Coastguard Worker             mut primary_entries,
717*5225e6b1SAndroid Build Coastguard Worker             mut secondary_entries,
718*5225e6b1SAndroid Build Coastguard Worker         } = LoadBufferRef::from(&mut self.buffer[..]);
719*5225e6b1SAndroid Build Coastguard Worker         block_size.0 = None;
720*5225e6b1SAndroid Build Coastguard Worker         let primary_entries = primary_entries.as_bytes_mut();
721*5225e6b1SAndroid Build Coastguard Worker         let secondary_entries = secondary_entries.as_bytes_mut();
722*5225e6b1SAndroid Build Coastguard Worker         let sync_res = match (primary_res, secondary_res) {
723*5225e6b1SAndroid Build Coastguard Worker             (Err(primary), Err(secondary)) => GptSyncResult::NoValidGpt { primary, secondary },
724*5225e6b1SAndroid Build Coastguard Worker             (Ok(()), Ok(())) if is_consistent(&primary_header, &secondary_header) => {
725*5225e6b1SAndroid Build Coastguard Worker                 GptSyncResult::BothValid
726*5225e6b1SAndroid Build Coastguard Worker             }
727*5225e6b1SAndroid Build Coastguard Worker             (Err(e), Ok(())) => {
728*5225e6b1SAndroid Build Coastguard Worker                 // Restores to primary
729*5225e6b1SAndroid Build Coastguard Worker                 primary_header.as_bytes_mut().clone_from_slice(secondary_header.as_bytes());
730*5225e6b1SAndroid Build Coastguard Worker                 primary_entries.clone_from_slice(&secondary_entries);
731*5225e6b1SAndroid Build Coastguard Worker                 primary_header.current = primary_header_blk;
732*5225e6b1SAndroid Build Coastguard Worker                 primary_header.backup = secondary_header_blk.try_into()?;
733*5225e6b1SAndroid Build Coastguard Worker                 primary_header.entries = primary_entries_blk;
734*5225e6b1SAndroid Build Coastguard Worker                 primary_header.update_crc();
735*5225e6b1SAndroid Build Coastguard Worker 
736*5225e6b1SAndroid Build Coastguard Worker                 disk.write(primary_header_pos, primary_header.as_bytes_mut()).await?;
737*5225e6b1SAndroid Build Coastguard Worker                 disk.write(primary_entries_pos.try_into()?, primary_entries).await?;
738*5225e6b1SAndroid Build Coastguard Worker                 GptSyncResult::PrimaryRestored(e)
739*5225e6b1SAndroid Build Coastguard Worker             }
740*5225e6b1SAndroid Build Coastguard Worker             (Ok(()), v) => {
741*5225e6b1SAndroid Build Coastguard Worker                 // Restores to secondary
742*5225e6b1SAndroid Build Coastguard Worker                 let pos = secondary_header_blk * blk_sz;
743*5225e6b1SAndroid Build Coastguard Worker                 let secondary_entries_pos = pos - GPT_MAX_NUM_ENTRIES_SIZE;
744*5225e6b1SAndroid Build Coastguard Worker                 let secondary_entries_blk = secondary_entries_pos / blk_sz;
745*5225e6b1SAndroid Build Coastguard Worker 
746*5225e6b1SAndroid Build Coastguard Worker                 secondary_header.as_bytes_mut().clone_from_slice(primary_header.as_bytes());
747*5225e6b1SAndroid Build Coastguard Worker                 secondary_entries.clone_from_slice(primary_entries);
748*5225e6b1SAndroid Build Coastguard Worker                 secondary_header.current = secondary_header_blk.try_into()?;
749*5225e6b1SAndroid Build Coastguard Worker                 secondary_header.backup = primary_header_blk;
750*5225e6b1SAndroid Build Coastguard Worker                 secondary_header.entries = secondary_entries_blk.try_into()?;
751*5225e6b1SAndroid Build Coastguard Worker                 secondary_header.update_crc();
752*5225e6b1SAndroid Build Coastguard Worker 
753*5225e6b1SAndroid Build Coastguard Worker                 disk.write(pos.try_into()?, secondary_header.as_bytes_mut()).await?;
754*5225e6b1SAndroid Build Coastguard Worker                 disk.write(secondary_entries_pos.try_into()?, secondary_entries).await?;
755*5225e6b1SAndroid Build Coastguard Worker 
756*5225e6b1SAndroid Build Coastguard Worker                 GptSyncResult::SecondaryRestored(match v {
757*5225e6b1SAndroid Build Coastguard Worker                     Err(e) => e,
758*5225e6b1SAndroid Build Coastguard Worker                     _ => Error::GptError(GptError::DifferentFromPrimary),
759*5225e6b1SAndroid Build Coastguard Worker                 })
760*5225e6b1SAndroid Build Coastguard Worker             }
761*5225e6b1SAndroid Build Coastguard Worker         };
762*5225e6b1SAndroid Build Coastguard Worker 
763*5225e6b1SAndroid Build Coastguard Worker         block_size.0 = Some(nonzero_blk_sz);
764*5225e6b1SAndroid Build Coastguard Worker         Ok(sync_res)
765*5225e6b1SAndroid Build Coastguard Worker     }
766*5225e6b1SAndroid Build Coastguard Worker }
767*5225e6b1SAndroid Build Coastguard Worker 
768*5225e6b1SAndroid Build Coastguard Worker /// Checks whether primary and secondary header
is_consistent(primary: &GptHeader, secondary: &GptHeader) -> bool769*5225e6b1SAndroid Build Coastguard Worker fn is_consistent(primary: &GptHeader, secondary: &GptHeader) -> bool {
770*5225e6b1SAndroid Build Coastguard Worker     let mut expected_secondary = *primary;
771*5225e6b1SAndroid Build Coastguard Worker     expected_secondary.crc32 = secondary.crc32;
772*5225e6b1SAndroid Build Coastguard Worker     expected_secondary.current = secondary.current;
773*5225e6b1SAndroid Build Coastguard Worker     expected_secondary.backup = 1;
774*5225e6b1SAndroid Build Coastguard Worker     expected_secondary.entries = secondary.entries;
775*5225e6b1SAndroid Build Coastguard Worker     &expected_secondary == secondary
776*5225e6b1SAndroid Build Coastguard Worker }
777*5225e6b1SAndroid Build Coastguard Worker 
778*5225e6b1SAndroid Build Coastguard Worker /// A [Gpt] that owns a `GptLoadBufferN<N>` and can load up to N partition entries.
779*5225e6b1SAndroid Build Coastguard Worker ///
780*5225e6b1SAndroid Build Coastguard Worker /// Note: The size of this type increases with N and can be expensive to store on stack. It is
781*5225e6b1SAndroid Build Coastguard Worker /// typically intended for resource abundant environment such as test.
782*5225e6b1SAndroid Build Coastguard Worker pub type GptN<const N: usize> = Gpt<GptLoadBufferN<N>>;
783*5225e6b1SAndroid Build Coastguard Worker 
784*5225e6b1SAndroid Build Coastguard Worker /// Creates an instance of GptN.
new_gpt_n<const N: usize>() -> GptN<N>785*5225e6b1SAndroid Build Coastguard Worker pub fn new_gpt_n<const N: usize>() -> GptN<N> {
786*5225e6b1SAndroid Build Coastguard Worker     Gpt::new(GptLoadBufferN::<N>::new_zeroed()).unwrap()
787*5225e6b1SAndroid Build Coastguard Worker }
788*5225e6b1SAndroid Build Coastguard Worker 
789*5225e6b1SAndroid Build Coastguard Worker /// A [Gpt] that owns a `GptLoadBufferN<128>` and can load the maximum 128 partition entries.
790*5225e6b1SAndroid Build Coastguard Worker ///
791*5225e6b1SAndroid Build Coastguard Worker /// Note: The size of this type is approximately 34K and can be expensive to store on stack. It
792*5225e6b1SAndroid Build Coastguard Worker /// is typically intended for resource abundant environment such as test.
793*5225e6b1SAndroid Build Coastguard Worker pub type GptMax = GptN<GPT_MAX_NUM_ENTRIES>;
794*5225e6b1SAndroid Build Coastguard Worker 
795*5225e6b1SAndroid Build Coastguard Worker /// Creates an instance of GptMax.
new_gpt_max() -> GptMax796*5225e6b1SAndroid Build Coastguard Worker pub fn new_gpt_max() -> GptMax {
797*5225e6b1SAndroid Build Coastguard Worker     new_gpt_n::<GPT_MAX_NUM_ENTRIES>()
798*5225e6b1SAndroid Build Coastguard Worker }
799*5225e6b1SAndroid Build Coastguard Worker 
800*5225e6b1SAndroid Build Coastguard Worker /// Updates GPT on a block device.
801*5225e6b1SAndroid Build Coastguard Worker ///
802*5225e6b1SAndroid Build Coastguard Worker /// # Args
803*5225e6b1SAndroid Build Coastguard Worker ///
804*5225e6b1SAndroid Build Coastguard Worker /// * `io`: An implementation of [BlockIo]
805*5225e6b1SAndroid Build Coastguard Worker /// * `scratch`: Scratch buffer for unaligned read write.
806*5225e6b1SAndroid Build Coastguard Worker /// * `mbr_primary`: A buffer containing the MBR block, primary GPT header and entries.
807*5225e6b1SAndroid Build Coastguard Worker /// * `resize`: If set to true, the method updates the last partition to cover the rest of the
808*5225e6b1SAndroid Build Coastguard Worker ///    storage.
809*5225e6b1SAndroid Build Coastguard Worker /// * `gpt`: The output [Gpt] to update.
update_gpt( disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, mbr_primary: &mut [u8], resize: bool, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>, ) -> Result<()>810*5225e6b1SAndroid Build Coastguard Worker pub(crate) async fn update_gpt(
811*5225e6b1SAndroid Build Coastguard Worker     disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
812*5225e6b1SAndroid Build Coastguard Worker     mbr_primary: &mut [u8],
813*5225e6b1SAndroid Build Coastguard Worker     resize: bool,
814*5225e6b1SAndroid Build Coastguard Worker     gpt: &mut Gpt<impl DerefMut<Target = [u8]>>,
815*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
816*5225e6b1SAndroid Build Coastguard Worker     let blk_sz: usize = disk.io().info().block_size.try_into()?;
817*5225e6b1SAndroid Build Coastguard Worker     let (header, remain) = mbr_primary
818*5225e6b1SAndroid Build Coastguard Worker         .get_mut(blk_sz..)
819*5225e6b1SAndroid Build Coastguard Worker         .map(|v| v.split_at_mut_checked(blk_sz))
820*5225e6b1SAndroid Build Coastguard Worker         .flatten()
821*5225e6b1SAndroid Build Coastguard Worker         .ok_or(Error::BufferTooSmall(Some(blk_sz * 2)))?;
822*5225e6b1SAndroid Build Coastguard Worker     let header = Ref::<_, GptHeader>::new_from_prefix(&mut header[..]).unwrap().0.into_mut();
823*5225e6b1SAndroid Build Coastguard Worker 
824*5225e6b1SAndroid Build Coastguard Worker     // Adjusts last usable block according to this device in case the GPT was generated for a
825*5225e6b1SAndroid Build Coastguard Worker     // different disk size. If this results in some partition being out of range, it will be
826*5225e6b1SAndroid Build Coastguard Worker     // caught during `check_header()`.
827*5225e6b1SAndroid Build Coastguard Worker     let entries_blk = SafeNum::from(GPT_MAX_NUM_ENTRIES_SIZE) / blk_sz;
828*5225e6b1SAndroid Build Coastguard Worker     // Reserves only secondary GPT header and entries.
829*5225e6b1SAndroid Build Coastguard Worker     let num_blks = SafeNum::from(disk.io().info().num_blocks);
830*5225e6b1SAndroid Build Coastguard Worker     header.last = (num_blks - entries_blk - 2).try_into().unwrap();
831*5225e6b1SAndroid Build Coastguard Worker     header.backup = (num_blks - 1).try_into().unwrap();
832*5225e6b1SAndroid Build Coastguard Worker     header.update_crc();
833*5225e6b1SAndroid Build Coastguard Worker 
834*5225e6b1SAndroid Build Coastguard Worker     check_header(disk.io(), &header, true)?;
835*5225e6b1SAndroid Build Coastguard Worker     // Computes entries offset in bytes relative to `remain`
836*5225e6b1SAndroid Build Coastguard Worker     let entries_off: usize = ((SafeNum::from(header.entries) - 2) * blk_sz).try_into().unwrap();
837*5225e6b1SAndroid Build Coastguard Worker     let entries_size: usize =
838*5225e6b1SAndroid Build Coastguard Worker         (SafeNum::from(header.entries_count) * header.entries_size).try_into().unwrap();
839*5225e6b1SAndroid Build Coastguard Worker     let entries = remain
840*5225e6b1SAndroid Build Coastguard Worker         .get_mut(entries_off..)
841*5225e6b1SAndroid Build Coastguard Worker         .map(|v| v.get_mut(..entries_size))
842*5225e6b1SAndroid Build Coastguard Worker         .flatten()
843*5225e6b1SAndroid Build Coastguard Worker         .ok_or(Error::BufferTooSmall(Some(2 * blk_sz + entries_off + entries_size)))?;
844*5225e6b1SAndroid Build Coastguard Worker     check_entries(&header, entries)?;
845*5225e6b1SAndroid Build Coastguard Worker 
846*5225e6b1SAndroid Build Coastguard Worker     if resize {
847*5225e6b1SAndroid Build Coastguard Worker         // Updates the last entry to cover the rest of the storage.
848*5225e6b1SAndroid Build Coastguard Worker         let gpt_entries =
849*5225e6b1SAndroid Build Coastguard Worker             Ref::<_, [GptEntry]>::new_slice(&mut entries[..]).unwrap().into_mut_slice();
850*5225e6b1SAndroid Build Coastguard Worker         gpt_entries.iter_mut().filter(|e| !e.is_null()).last().map(|v| v.last = header.last);
851*5225e6b1SAndroid Build Coastguard Worker         header.update_entries_crc(entries);
852*5225e6b1SAndroid Build Coastguard Worker         // Re-verifies everything.
853*5225e6b1SAndroid Build Coastguard Worker         check_header(disk.io(), &header, true).unwrap();
854*5225e6b1SAndroid Build Coastguard Worker         check_entries(&header, entries).unwrap();
855*5225e6b1SAndroid Build Coastguard Worker     }
856*5225e6b1SAndroid Build Coastguard Worker 
857*5225e6b1SAndroid Build Coastguard Worker     disk.write(0, mbr_primary).await?;
858*5225e6b1SAndroid Build Coastguard Worker     disk.sync_gpt(gpt).await?.res()
859*5225e6b1SAndroid Build Coastguard Worker }
860*5225e6b1SAndroid Build Coastguard Worker 
861*5225e6b1SAndroid Build Coastguard Worker /// Erases GPT if there is one on the device.
erase_gpt( disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, gpt: &mut Gpt<impl DerefMut<Target = [u8]>>, ) -> Result<()>862*5225e6b1SAndroid Build Coastguard Worker pub(crate) async fn erase_gpt(
863*5225e6b1SAndroid Build Coastguard Worker     disk: &mut Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
864*5225e6b1SAndroid Build Coastguard Worker     gpt: &mut Gpt<impl DerefMut<Target = [u8]>>,
865*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
866*5225e6b1SAndroid Build Coastguard Worker     match disk.sync_gpt(gpt).await?.res() {
867*5225e6b1SAndroid Build Coastguard Worker         Err(_) => Ok(()), // No valid GPT. Nothing to erase.
868*5225e6b1SAndroid Build Coastguard Worker         _ => {
869*5225e6b1SAndroid Build Coastguard Worker             let blk_sz = disk.block_info().block_size;
870*5225e6b1SAndroid Build Coastguard Worker             let mut load = LoadBufferRef::from(&mut gpt.buffer[..]);
871*5225e6b1SAndroid Build Coastguard Worker             let entries_size = SafeNum::from(load.primary_header.entries_count) * GPT_ENTRY_SIZE;
872*5225e6b1SAndroid Build Coastguard Worker             let scratch = load.primary_entries.as_bytes_mut();
873*5225e6b1SAndroid Build Coastguard Worker             // Invalidate GPT first.
874*5225e6b1SAndroid Build Coastguard Worker             load.block_size.0 = None;
875*5225e6b1SAndroid Build Coastguard Worker             // Erases primary header/entries.
876*5225e6b1SAndroid Build Coastguard Worker             let header = load.primary_header.current;
877*5225e6b1SAndroid Build Coastguard Worker             let entries = load.primary_header.entries;
878*5225e6b1SAndroid Build Coastguard Worker             disk.fill(header * blk_sz, blk_sz, 0, scratch).await?;
879*5225e6b1SAndroid Build Coastguard Worker             disk.fill(entries * blk_sz, entries_size.try_into().unwrap(), 0, scratch).await?;
880*5225e6b1SAndroid Build Coastguard Worker             // Erases secondary header/entries.
881*5225e6b1SAndroid Build Coastguard Worker             let header = load.secondary_header.current;
882*5225e6b1SAndroid Build Coastguard Worker             let entries = load.secondary_header.entries;
883*5225e6b1SAndroid Build Coastguard Worker             disk.fill(header * blk_sz, blk_sz, 0, scratch).await?;
884*5225e6b1SAndroid Build Coastguard Worker             disk.fill(entries * blk_sz, entries_size.try_into().unwrap(), 0, scratch).await?;
885*5225e6b1SAndroid Build Coastguard Worker             Ok(())
886*5225e6b1SAndroid Build Coastguard Worker         }
887*5225e6b1SAndroid Build Coastguard Worker     }
888*5225e6b1SAndroid Build Coastguard Worker }
889*5225e6b1SAndroid Build Coastguard Worker 
890*5225e6b1SAndroid Build Coastguard Worker /// Computes the minimum blocks needed for creating a GPT.
min_required_blocks(block_size: u64) -> Result<u64>891*5225e6b1SAndroid Build Coastguard Worker fn min_required_blocks(block_size: u64) -> Result<u64> {
892*5225e6b1SAndroid Build Coastguard Worker     // MBR + primary/secondary GPT header block + primary/secondary entries blocks.
893*5225e6b1SAndroid Build Coastguard Worker     Ok(1 + (1 + gpt_entries_blk(block_size)?) * 2)
894*5225e6b1SAndroid Build Coastguard Worker }
895*5225e6b1SAndroid Build Coastguard Worker 
896*5225e6b1SAndroid Build Coastguard Worker /// `GptBuilder` provides API for modifying/creating GPT partition table on a disk.
897*5225e6b1SAndroid Build Coastguard Worker pub struct GptBuilder<D, G> {
898*5225e6b1SAndroid Build Coastguard Worker     disk: D,
899*5225e6b1SAndroid Build Coastguard Worker     gpt: G,
900*5225e6b1SAndroid Build Coastguard Worker }
901*5225e6b1SAndroid Build Coastguard Worker 
902*5225e6b1SAndroid Build Coastguard Worker impl<D: Debug, G: Debug> Debug for GptBuilder<D, G> {
fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error>903*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
904*5225e6b1SAndroid Build Coastguard Worker         write!(f, "GptBuilder {{ disk: {:?}, gpt: {:?} }}", self.disk, self.gpt)
905*5225e6b1SAndroid Build Coastguard Worker     }
906*5225e6b1SAndroid Build Coastguard Worker }
907*5225e6b1SAndroid Build Coastguard Worker // Generic parameters:
908*5225e6b1SAndroid Build Coastguard Worker //
909*5225e6b1SAndroid Build Coastguard Worker // * T: The type that implement BlockIo.
910*5225e6b1SAndroid Build Coastguard Worker // * S: The type for the scratch buffer in `Self::disk`.
911*5225e6b1SAndroid Build Coastguard Worker // * B: The type for the GPT buffer in `Self::gpt`.
912*5225e6b1SAndroid Build Coastguard Worker // * D: The type for `Self::disk` which can dereference to a Disk<T, S>.
913*5225e6b1SAndroid Build Coastguard Worker // * G: The type for `Self::gpt` which can dereference to a Gpt<B>.
914*5225e6b1SAndroid Build Coastguard Worker impl<'a, T, S, B, D, G> GptBuilder<D, G>
915*5225e6b1SAndroid Build Coastguard Worker where
916*5225e6b1SAndroid Build Coastguard Worker     T: BlockIo,
917*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]>,
918*5225e6b1SAndroid Build Coastguard Worker     B: DerefMut<Target = [u8]>,
919*5225e6b1SAndroid Build Coastguard Worker     D: DerefMut<Target = Disk<T, S>>,
920*5225e6b1SAndroid Build Coastguard Worker     G: DerefMut<Target = Gpt<B>>,
921*5225e6b1SAndroid Build Coastguard Worker {
922*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance.
923*5225e6b1SAndroid Build Coastguard Worker     ///
924*5225e6b1SAndroid Build Coastguard Worker     /// The method always re-syncs the GPT. If `disk` does not contain a valid GPT, a new GPT is
925*5225e6b1SAndroid Build Coastguard Worker     /// started from scratch.
926*5225e6b1SAndroid Build Coastguard Worker     ///
927*5225e6b1SAndroid Build Coastguard Worker     /// The partition entries will always be sorted when writing back to disk by `Self::persist()`.
928*5225e6b1SAndroid Build Coastguard Worker     ///
929*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
930*5225e6b1SAndroid Build Coastguard Worker     ///
931*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok((Self, true)) if an instance is created and the disk has a valid GPT.
932*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok((Self, false)) if an instance is created but disk does not have a valid GPT.
933*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Err() otherwise.
new(mut disk: D, mut gpt: G) -> Result<(Self, bool)>934*5225e6b1SAndroid Build Coastguard Worker     pub fn new(mut disk: D, mut gpt: G) -> Result<(Self, bool)> {
935*5225e6b1SAndroid Build Coastguard Worker         if disk.block_info().num_blocks < min_required_blocks(disk.block_info().block_size)? {
936*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::GptError(GptError::DiskTooSmall));
937*5225e6b1SAndroid Build Coastguard Worker         }
938*5225e6b1SAndroid Build Coastguard Worker         let has_valid_gpt = block_on(disk.sync_gpt(&mut gpt))?.res().is_ok();
939*5225e6b1SAndroid Build Coastguard Worker         // Uses the buffer for secondary GPT header/entries as construction buffer, as it is not
940*5225e6b1SAndroid Build Coastguard Worker         // used by Gpt once loaded and synced.
941*5225e6b1SAndroid Build Coastguard Worker         let (mut header, mut entries) = LoadBufferRef::from(&mut gpt.buffer[..]).secondary();
942*5225e6b1SAndroid Build Coastguard Worker         if !has_valid_gpt {
943*5225e6b1SAndroid Build Coastguard Worker             header.as_bytes_mut().fill(0);
944*5225e6b1SAndroid Build Coastguard Worker             entries.as_bytes_mut().fill(0);
945*5225e6b1SAndroid Build Coastguard Worker             let entries_blk = gpt_entries_blk(disk.block_info().block_size).unwrap();
946*5225e6b1SAndroid Build Coastguard Worker             // Initializes a secondary header.
947*5225e6b1SAndroid Build Coastguard Worker             let num_blks = SafeNum::from(disk.block_info().num_blocks);
948*5225e6b1SAndroid Build Coastguard Worker             header.magic = GPT_MAGIC;
949*5225e6b1SAndroid Build Coastguard Worker             header.current = (num_blks - 1).try_into().unwrap();
950*5225e6b1SAndroid Build Coastguard Worker             header.backup = 1;
951*5225e6b1SAndroid Build Coastguard Worker             header.size = size_of::<GptHeader>().try_into().unwrap();
952*5225e6b1SAndroid Build Coastguard Worker             header.first = 1 + 1 + entries_blk; // MBR + GPT header blocks + entries block
953*5225e6b1SAndroid Build Coastguard Worker             header.last = (num_blks - 1 - entries_blk - 1).try_into().unwrap();
954*5225e6b1SAndroid Build Coastguard Worker             header.entries = (num_blks - 1 - entries_blk).try_into().unwrap();
955*5225e6b1SAndroid Build Coastguard Worker             header.entries_count = 0;
956*5225e6b1SAndroid Build Coastguard Worker             header.entries_size = size_of::<GptEntry>().try_into().unwrap();
957*5225e6b1SAndroid Build Coastguard Worker         }
958*5225e6b1SAndroid Build Coastguard Worker         // Normalizes `entries_count` to actual valid entries. Some GPT disk fixes `entry_count` to
959*5225e6b1SAndroid Build Coastguard Worker         // 128.
960*5225e6b1SAndroid Build Coastguard Worker         header.entries_count =
961*5225e6b1SAndroid Build Coastguard Worker             entries.iter().position(|v| v.is_null()).unwrap_or(entries.len()).try_into().unwrap();
962*5225e6b1SAndroid Build Coastguard Worker         entries.sort_unstable_by_key(|v| match v.is_null() {
963*5225e6b1SAndroid Build Coastguard Worker             true => u64::MAX,
964*5225e6b1SAndroid Build Coastguard Worker             _ => v.first,
965*5225e6b1SAndroid Build Coastguard Worker         });
966*5225e6b1SAndroid Build Coastguard Worker         Ok((Self { disk, gpt }, has_valid_gpt))
967*5225e6b1SAndroid Build Coastguard Worker     }
968*5225e6b1SAndroid Build Coastguard Worker 
969*5225e6b1SAndroid Build Coastguard Worker     /// Removes a partition.
970*5225e6b1SAndroid Build Coastguard Worker     ///
971*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
972*5225e6b1SAndroid Build Coastguard Worker     ///
973*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok(true) if found and removed.
974*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Ok(false) if not found.
975*5225e6b1SAndroid Build Coastguard Worker     /// * Returns Err() otherwise.
remove(&mut self, part: &str) -> Result<bool>976*5225e6b1SAndroid Build Coastguard Worker     pub fn remove(&mut self, part: &str) -> Result<bool> {
977*5225e6b1SAndroid Build Coastguard Worker         let (mut header, mut entries) = LoadBufferRef::from(&mut self.gpt.buffer[..]).secondary();
978*5225e6b1SAndroid Build Coastguard Worker         let entries = &mut entries[..header.entries_count.try_into().unwrap()];
979*5225e6b1SAndroid Build Coastguard Worker         match entries.iter().position(|v| v.match_name(part).unwrap_or(false)) {
980*5225e6b1SAndroid Build Coastguard Worker             Some(n) => {
981*5225e6b1SAndroid Build Coastguard Worker                 // Shift the elements behind forward.
982*5225e6b1SAndroid Build Coastguard Worker                 entries[n..].rotate_left(1);
983*5225e6b1SAndroid Build Coastguard Worker                 // Zeroizes the last element.
984*5225e6b1SAndroid Build Coastguard Worker                 entries.last_mut().unwrap().as_bytes_mut().fill(0);
985*5225e6b1SAndroid Build Coastguard Worker                 header.entries_count -= 1;
986*5225e6b1SAndroid Build Coastguard Worker                 Ok(true)
987*5225e6b1SAndroid Build Coastguard Worker             }
988*5225e6b1SAndroid Build Coastguard Worker             _ => Ok(false),
989*5225e6b1SAndroid Build Coastguard Worker         }
990*5225e6b1SAndroid Build Coastguard Worker     }
991*5225e6b1SAndroid Build Coastguard Worker 
992*5225e6b1SAndroid Build Coastguard Worker     /// Inserts a new partition before a partition.
993*5225e6b1SAndroid Build Coastguard Worker     ///
994*5225e6b1SAndroid Build Coastguard Worker     /// # Args
995*5225e6b1SAndroid Build Coastguard Worker     ///
996*5225e6b1SAndroid Build Coastguard Worker     /// * `idx`: Index of the partition to insert before. If index is out of range of valid entries,
997*5225e6b1SAndroid Build Coastguard Worker     ///   the partition will be inserted at the last.
998*5225e6b1SAndroid Build Coastguard Worker     /// * `name`: Name of the partition.
999*5225e6b1SAndroid Build Coastguard Worker     /// * `part_type`: Type GUID.
1000*5225e6b1SAndroid Build Coastguard Worker     /// * `unique_guid`: Unique GUID.
1001*5225e6b1SAndroid Build Coastguard Worker     /// * `flags`: Partition flag.
1002*5225e6b1SAndroid Build Coastguard Worker     /// * `size`: If Some(_), specifies the size in number of bytes for the partition. The method
1003*5225e6b1SAndroid Build Coastguard Worker     ///   will round it up to multiple of disk block size and check that there is enough space for
1004*5225e6b1SAndroid Build Coastguard Worker     ///   the partition. If None, the method will insert the partition and consumes all the
1005*5225e6b1SAndroid Build Coastguard Worker     ///   available space in between.
insert_before( &mut self, idx: usize, name: &str, part_type: [u8; GPT_GUID_LEN], unique_guid: [u8; GPT_GUID_LEN], flags: u64, size: Option<u64>, ) -> Result<()>1006*5225e6b1SAndroid Build Coastguard Worker     fn insert_before(
1007*5225e6b1SAndroid Build Coastguard Worker         &mut self,
1008*5225e6b1SAndroid Build Coastguard Worker         idx: usize,
1009*5225e6b1SAndroid Build Coastguard Worker         name: &str,
1010*5225e6b1SAndroid Build Coastguard Worker         part_type: [u8; GPT_GUID_LEN],
1011*5225e6b1SAndroid Build Coastguard Worker         unique_guid: [u8; GPT_GUID_LEN],
1012*5225e6b1SAndroid Build Coastguard Worker         flags: u64,
1013*5225e6b1SAndroid Build Coastguard Worker         size: Option<u64>,
1014*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
1015*5225e6b1SAndroid Build Coastguard Worker         let (mut header, mut entries) = LoadBufferRef::from(&mut self.gpt.buffer[..]).secondary();
1016*5225e6b1SAndroid Build Coastguard Worker         // Gets position to the first NULL entry.
1017*5225e6b1SAndroid Build Coastguard Worker         let n = entries.iter().position(|v| v.is_null()).ok_or(Error::OutOfResources)?;
1018*5225e6b1SAndroid Build Coastguard Worker         let entries = &mut entries[..n + 1];
1019*5225e6b1SAndroid Build Coastguard Worker         // Caps `idx` to no more than the first NULL entry.
1020*5225e6b1SAndroid Build Coastguard Worker         let idx = min(n, idx);
1021*5225e6b1SAndroid Build Coastguard Worker         // Comptues the ending block index (non-inclusive) of the previous partition entry.
1022*5225e6b1SAndroid Build Coastguard Worker         // Entries are guaranteed sorted in `Self::new()`.
1023*5225e6b1SAndroid Build Coastguard Worker         let prev_end = match idx {
1024*5225e6b1SAndroid Build Coastguard Worker             0 => header.first,
1025*5225e6b1SAndroid Build Coastguard Worker             _ => entries[idx - 1].last + 1,
1026*5225e6b1SAndroid Build Coastguard Worker         };
1027*5225e6b1SAndroid Build Coastguard Worker         // Comptues the starting block index (inclusive) of the next partition entry.
1028*5225e6b1SAndroid Build Coastguard Worker         let next_start = match idx == n {
1029*5225e6b1SAndroid Build Coastguard Worker             true => header.last + 1,
1030*5225e6b1SAndroid Build Coastguard Worker             _ => entries[idx].first,
1031*5225e6b1SAndroid Build Coastguard Worker         };
1032*5225e6b1SAndroid Build Coastguard Worker         // Computes the size in number of blocks
1033*5225e6b1SAndroid Build Coastguard Worker         let blk_sz = self.disk.block_info().block_size;
1034*5225e6b1SAndroid Build Coastguard Worker         let blocks: u64 = match size {
1035*5225e6b1SAndroid Build Coastguard Worker             Some(v) => (SafeNum::from(v).round_up(blk_sz) / blk_sz).try_into()?,
1036*5225e6b1SAndroid Build Coastguard Worker             _ => next_start - prev_end, // If not given, uses up all the gap space
1037*5225e6b1SAndroid Build Coastguard Worker         };
1038*5225e6b1SAndroid Build Coastguard Worker         // Checks if there is enough space.
1039*5225e6b1SAndroid Build Coastguard Worker         if next_start - prev_end < blocks {
1040*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::OutOfResources);
1041*5225e6b1SAndroid Build Coastguard Worker         }
1042*5225e6b1SAndroid Build Coastguard Worker         // Inserts the new entry.
1043*5225e6b1SAndroid Build Coastguard Worker         entries[idx..].rotate_right(1);
1044*5225e6b1SAndroid Build Coastguard Worker         let entry = &mut entries[idx];
1045*5225e6b1SAndroid Build Coastguard Worker         assert!(entry.is_null());
1046*5225e6b1SAndroid Build Coastguard Worker         entry.part_type = part_type;
1047*5225e6b1SAndroid Build Coastguard Worker         entry.guid = unique_guid;
1048*5225e6b1SAndroid Build Coastguard Worker         entry.flags = flags;
1049*5225e6b1SAndroid Build Coastguard Worker         entry.first = prev_end;
1050*5225e6b1SAndroid Build Coastguard Worker         entry.last = prev_end + blocks - 1;
1051*5225e6b1SAndroid Build Coastguard Worker         for (idx, ele) in name.encode_utf16().enumerate() {
1052*5225e6b1SAndroid Build Coastguard Worker             match idx < GPT_NAME_LEN_U16 {
1053*5225e6b1SAndroid Build Coastguard Worker                 true => entry.name[idx] = ele,
1054*5225e6b1SAndroid Build Coastguard Worker                 _ => break,
1055*5225e6b1SAndroid Build Coastguard Worker             }
1056*5225e6b1SAndroid Build Coastguard Worker         }
1057*5225e6b1SAndroid Build Coastguard Worker         header.entries_count += 1;
1058*5225e6b1SAndroid Build Coastguard Worker         Ok(())
1059*5225e6b1SAndroid Build Coastguard Worker     }
1060*5225e6b1SAndroid Build Coastguard Worker 
1061*5225e6b1SAndroid Build Coastguard Worker     /// Adds a partition.
1062*5225e6b1SAndroid Build Coastguard Worker     ///
1063*5225e6b1SAndroid Build Coastguard Worker     /// # Args
1064*5225e6b1SAndroid Build Coastguard Worker     ///
1065*5225e6b1SAndroid Build Coastguard Worker     /// * `name`: Name of the partition.
1066*5225e6b1SAndroid Build Coastguard Worker     /// * `part_type`: Type GUID.
1067*5225e6b1SAndroid Build Coastguard Worker     /// * `unique_guid`: Unique GUID.
1068*5225e6b1SAndroid Build Coastguard Worker     /// * `flags`: Partition flag.
1069*5225e6b1SAndroid Build Coastguard Worker     /// * `size`: If Some(_), specifies the size in number of bytes for the partition. The method
1070*5225e6b1SAndroid Build Coastguard Worker     ///   will round it up to multiple of disk block size and search for the first large enough
1071*5225e6b1SAndroid Build Coastguard Worker     ///   space in the unused spae for putting the partition. If None, the method will add the
1072*5225e6b1SAndroid Build Coastguard Worker     ///   partition at the last and have it consume all remaining usable disk space.
add( &mut self, name: &str, part_type: [u8; GPT_GUID_LEN], unique_guid: [u8; GPT_GUID_LEN], flags: u64, size: Option<u64>, ) -> Result<()>1073*5225e6b1SAndroid Build Coastguard Worker     pub fn add(
1074*5225e6b1SAndroid Build Coastguard Worker         &mut self,
1075*5225e6b1SAndroid Build Coastguard Worker         name: &str,
1076*5225e6b1SAndroid Build Coastguard Worker         part_type: [u8; GPT_GUID_LEN],
1077*5225e6b1SAndroid Build Coastguard Worker         unique_guid: [u8; GPT_GUID_LEN],
1078*5225e6b1SAndroid Build Coastguard Worker         flags: u64,
1079*5225e6b1SAndroid Build Coastguard Worker         size: Option<u64>,
1080*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
1081*5225e6b1SAndroid Build Coastguard Worker         let (header, _) = LoadBufferRef::from(&mut self.gpt.buffer[..]).secondary();
1082*5225e6b1SAndroid Build Coastguard Worker         let entry_count = usize::try_from(header.entries_count).unwrap();
1083*5225e6b1SAndroid Build Coastguard Worker         let search_start = size.is_some().then_some(0).unwrap_or(entry_count);
1084*5225e6b1SAndroid Build Coastguard Worker         for i in search_start..entry_count + 1 {
1085*5225e6b1SAndroid Build Coastguard Worker             if self.insert_before(i, name, part_type, unique_guid, flags, size).is_ok() {
1086*5225e6b1SAndroid Build Coastguard Worker                 return Ok(());
1087*5225e6b1SAndroid Build Coastguard Worker             }
1088*5225e6b1SAndroid Build Coastguard Worker         }
1089*5225e6b1SAndroid Build Coastguard Worker         Err(Error::OutOfResources)
1090*5225e6b1SAndroid Build Coastguard Worker     }
1091*5225e6b1SAndroid Build Coastguard Worker 
1092*5225e6b1SAndroid Build Coastguard Worker     /// Persists the constructed GPT table to the disk and syncs. The builder is consumed.
persist(mut self) -> Result<()>1093*5225e6b1SAndroid Build Coastguard Worker     pub async fn persist(mut self) -> Result<()> {
1094*5225e6b1SAndroid Build Coastguard Worker         let (mut header, mut entries) = LoadBufferRef::from(&mut self.gpt.buffer[..]).secondary();
1095*5225e6b1SAndroid Build Coastguard Worker         header.update_entries_crc(entries.as_bytes());
1096*5225e6b1SAndroid Build Coastguard Worker         // Check validity. Should not fail if implementation is correct.
1097*5225e6b1SAndroid Build Coastguard Worker         check_header(self.disk.io(), &header, false).unwrap();
1098*5225e6b1SAndroid Build Coastguard Worker         check_entries(&header, entries.as_bytes()).unwrap();
1099*5225e6b1SAndroid Build Coastguard Worker         let blk_sz = self.disk.block_info().block_size;
1100*5225e6b1SAndroid Build Coastguard Worker         // Writes to secondary header/ entries
1101*5225e6b1SAndroid Build Coastguard Worker         self.disk.write(header.current * blk_sz, header.as_bytes_mut()).await?;
1102*5225e6b1SAndroid Build Coastguard Worker         self.disk.write(header.entries * blk_sz, entries.as_bytes_mut()).await?;
1103*5225e6b1SAndroid Build Coastguard Worker         // Clears primary header magic
1104*5225e6b1SAndroid Build Coastguard Worker         self.disk.write(blk_sz, &mut 0u64.to_be_bytes()).await?;
1105*5225e6b1SAndroid Build Coastguard Worker         // Re-syncs GPT
1106*5225e6b1SAndroid Build Coastguard Worker         self.disk.sync_gpt(&mut self.gpt).await?.res()
1107*5225e6b1SAndroid Build Coastguard Worker     }
1108*5225e6b1SAndroid Build Coastguard Worker }
1109*5225e6b1SAndroid Build Coastguard Worker 
1110*5225e6b1SAndroid Build Coastguard Worker /// Helper for calculcating the Crc32.
crc32(data: &[u8]) -> u321111*5225e6b1SAndroid Build Coastguard Worker fn crc32(data: &[u8]) -> u32 {
1112*5225e6b1SAndroid Build Coastguard Worker     let mut hasher = Hasher::new();
1113*5225e6b1SAndroid Build Coastguard Worker     hasher.update(data);
1114*5225e6b1SAndroid Build Coastguard Worker     hasher.finalize()
1115*5225e6b1SAndroid Build Coastguard Worker }
1116*5225e6b1SAndroid Build Coastguard Worker 
1117*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
1118*5225e6b1SAndroid Build Coastguard Worker pub(crate) mod test {
1119*5225e6b1SAndroid Build Coastguard Worker     use super::*;
1120*5225e6b1SAndroid Build Coastguard Worker     use crate::test::TestDisk;
1121*5225e6b1SAndroid Build Coastguard Worker     use gbl_async::block_on;
1122*5225e6b1SAndroid Build Coastguard Worker 
1123*5225e6b1SAndroid Build Coastguard Worker     /// A helper for creating a [TestDisk] from given data.
test_disk(data: impl AsRef<[u8]>) -> TestDisk1124*5225e6b1SAndroid Build Coastguard Worker     fn test_disk(data: impl AsRef<[u8]>) -> TestDisk {
1125*5225e6b1SAndroid Build Coastguard Worker         // All tests cases use pre-generated GPT disk of 512 block size.
1126*5225e6b1SAndroid Build Coastguard Worker         TestDisk::new_ram_alloc(512, 512, data.as_ref().to_vec()).unwrap()
1127*5225e6b1SAndroid Build Coastguard Worker     }
1128*5225e6b1SAndroid Build Coastguard Worker 
1129*5225e6b1SAndroid Build Coastguard Worker     /// A helper for creating a [TestDisk] from given data and a [Gpt] for 128 entries.
test_disk_and_gpt(data: impl AsRef<[u8]>) -> (TestDisk, GptMax)1130*5225e6b1SAndroid Build Coastguard Worker     fn test_disk_and_gpt(data: impl AsRef<[u8]>) -> (TestDisk, GptMax) {
1131*5225e6b1SAndroid Build Coastguard Worker         (test_disk(data), new_gpt_max())
1132*5225e6b1SAndroid Build Coastguard Worker     }
1133*5225e6b1SAndroid Build Coastguard Worker 
1134*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_and_sync()1135*5225e6b1SAndroid Build Coastguard Worker     fn test_load_and_sync() {
1136*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(include_bytes!("../test/gpt_test_1.bin"));
1137*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.sync_gpt(&mut gpt)).unwrap();
1138*5225e6b1SAndroid Build Coastguard Worker 
1139*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.partition_iter().unwrap().count(), 2);
1140*5225e6b1SAndroid Build Coastguard Worker         gpt.find_partition("boot_a").unwrap();
1141*5225e6b1SAndroid Build Coastguard Worker         gpt.find_partition("boot_b").unwrap();
1142*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.find_partition("boot_c").is_err());
1143*5225e6b1SAndroid Build Coastguard Worker 
1144*5225e6b1SAndroid Build Coastguard Worker         // Creating a new [Gpt] using the same buffer should reset the valid state.
1145*5225e6b1SAndroid Build Coastguard Worker         let gpt = Gpt::new(gpt.buffer).unwrap();
1146*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.partition_iter().is_err());
1147*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.find_partition("boot_a").is_err());
1148*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.find_partition("boot_b").is_err());
1149*5225e6b1SAndroid Build Coastguard Worker     }
1150*5225e6b1SAndroid Build Coastguard Worker 
1151*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_with_unaligned_buffer()1152*5225e6b1SAndroid Build Coastguard Worker     fn test_load_with_unaligned_buffer() {
1153*5225e6b1SAndroid Build Coastguard Worker         #[repr(align(8))]
1154*5225e6b1SAndroid Build Coastguard Worker         struct AlignedBuffer([u8; 34 * 1024]);
1155*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = AlignedBuffer([0u8; 34 * 1024]);
1156*5225e6b1SAndroid Build Coastguard Worker         let buffer = &mut buffer.0[1..];
1157*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(buffer.as_ptr() as usize % 2, 0);
1158*5225e6b1SAndroid Build Coastguard Worker         let mut disk = test_disk(include_bytes!("../test/gpt_test_1.bin"));
1159*5225e6b1SAndroid Build Coastguard Worker         let mut gpt = Gpt::new(buffer).unwrap();
1160*5225e6b1SAndroid Build Coastguard Worker         block_on(disk.sync_gpt(&mut gpt)).unwrap();
1161*5225e6b1SAndroid Build Coastguard Worker     }
1162*5225e6b1SAndroid Build Coastguard Worker 
1163*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_buffer_too_small()1164*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_buffer_too_small() {
1165*5225e6b1SAndroid Build Coastguard Worker         assert!(Gpt::new(vec![0u8; size_of::<GptLoadBufferN<0>>() - 1]).is_err());
1166*5225e6b1SAndroid Build Coastguard Worker     }
1167*5225e6b1SAndroid Build Coastguard Worker 
1168*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_buffer_not_enough_for_all_entries()1169*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_buffer_not_enough_for_all_entries() {
1170*5225e6b1SAndroid Build Coastguard Worker         let mut dev = test_disk(include_bytes!("../test/gpt_test_1.bin"));
1171*5225e6b1SAndroid Build Coastguard Worker         let mut gpt = new_gpt_n::<127>();
1172*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.max_entries(), 127);
1173*5225e6b1SAndroid Build Coastguard Worker         // Actual entries_count is 128 in the GPT.
1174*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(dev.sync_gpt(&mut gpt)).unwrap().res().is_err());
1175*5225e6b1SAndroid Build Coastguard Worker     }
1176*5225e6b1SAndroid Build Coastguard Worker 
1177*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_good_gpt_no_repair_write()1178*5225e6b1SAndroid Build Coastguard Worker     fn test_good_gpt_no_repair_write() {
1179*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(include_bytes!("../test/gpt_test_1.bin"));
1180*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(dev.sync_gpt(&mut gpt)).unwrap(), GptSyncResult::BothValid);
1181*5225e6b1SAndroid Build Coastguard Worker     }
1182*5225e6b1SAndroid Build Coastguard Worker 
1183*5225e6b1SAndroid Build Coastguard Worker     /// A helper for testing restoration of invalid primary/secondary header modified by caller.
test_gpt_sync_restore<'a>( modify_primary: impl FnOnce(&mut GptHeader, Ref<&mut [u8], [GptEntry]>), modify_secondary: impl FnOnce(&mut GptHeader, Ref<&mut [u8], [GptEntry]>), expect_primary_err: Error, expect_secondary_err: Error, )1184*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_sync_restore<'a>(
1185*5225e6b1SAndroid Build Coastguard Worker         modify_primary: impl FnOnce(&mut GptHeader, Ref<&mut [u8], [GptEntry]>),
1186*5225e6b1SAndroid Build Coastguard Worker         modify_secondary: impl FnOnce(&mut GptHeader, Ref<&mut [u8], [GptEntry]>),
1187*5225e6b1SAndroid Build Coastguard Worker         expect_primary_err: Error,
1188*5225e6b1SAndroid Build Coastguard Worker         expect_secondary_err: Error,
1189*5225e6b1SAndroid Build Coastguard Worker     ) {
1190*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../test/gpt_test_1.bin");
1191*5225e6b1SAndroid Build Coastguard Worker 
1192*5225e6b1SAndroid Build Coastguard Worker         // Restores from secondary to primary.
1193*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1194*5225e6b1SAndroid Build Coastguard Worker         let (header, entries) = (&mut disk[512..]).split_at_mut(512);
1195*5225e6b1SAndroid Build Coastguard Worker         let mut header = GptHeader::from_bytes_mut(header);
1196*5225e6b1SAndroid Build Coastguard Worker         modify_primary(&mut header, Ref::<_, [GptEntry]>::new_slice(entries).unwrap());
1197*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1198*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(dev.io().storage(), disk_orig);
1199*5225e6b1SAndroid Build Coastguard Worker         let sync_res = block_on(dev.sync_gpt(&mut gpt)).unwrap();
1200*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(sync_res, GptSyncResult::PrimaryRestored(expect_primary_err));
1201*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(dev.io().storage(), disk_orig);
1202*5225e6b1SAndroid Build Coastguard Worker 
1203*5225e6b1SAndroid Build Coastguard Worker         // Restores from primary to secondary.
1204*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1205*5225e6b1SAndroid Build Coastguard Worker         let (entries, header) = (&mut disk[512..]).split_last_chunk_mut::<512>().unwrap();
1206*5225e6b1SAndroid Build Coastguard Worker         let (_, entries) = entries.split_last_chunk_mut::<{ 512 * 32 }>().unwrap();
1207*5225e6b1SAndroid Build Coastguard Worker         let mut header = GptHeader::from_bytes_mut(&mut header[..]);
1208*5225e6b1SAndroid Build Coastguard Worker         modify_secondary(&mut header, Ref::<_, [GptEntry]>::new_slice(&mut entries[..]).unwrap());
1209*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1210*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(dev.io().storage(), disk_orig);
1211*5225e6b1SAndroid Build Coastguard Worker         let sync_res = block_on(dev.sync_gpt(&mut gpt)).unwrap();
1212*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(sync_res, GptSyncResult::SecondaryRestored(expect_secondary_err));
1213*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(dev.io().storage(), disk_orig);
1214*5225e6b1SAndroid Build Coastguard Worker     }
1215*5225e6b1SAndroid Build Coastguard Worker 
1216*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_incorrect_magic()1217*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_incorrect_magic() {
1218*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1219*5225e6b1SAndroid Build Coastguard Worker             hdr.magic = 0x123456;
1220*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1221*5225e6b1SAndroid Build Coastguard Worker         }
1222*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::IncorrectMagic(0x123456));
1223*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1224*5225e6b1SAndroid Build Coastguard Worker     }
1225*5225e6b1SAndroid Build Coastguard Worker 
1226*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_incorrect_crc()1227*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_incorrect_crc() {
1228*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1229*5225e6b1SAndroid Build Coastguard Worker             hdr.crc32 = !hdr.crc32;
1230*5225e6b1SAndroid Build Coastguard Worker         }
1231*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::IncorrectHeaderCrc);
1232*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1233*5225e6b1SAndroid Build Coastguard Worker     }
1234*5225e6b1SAndroid Build Coastguard Worker 
1235*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_unexpected_header_size()1236*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_unexpected_header_size() {
1237*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1238*5225e6b1SAndroid Build Coastguard Worker             hdr.size += 1;
1239*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1240*5225e6b1SAndroid Build Coastguard Worker         }
1241*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::UnexpectedHeaderSize { actual: 93, expect: 92 });
1242*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1243*5225e6b1SAndroid Build Coastguard Worker     }
1244*5225e6b1SAndroid Build Coastguard Worker 
1245*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_unexpected_entry_size()1246*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_unexpected_entry_size() {
1247*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1248*5225e6b1SAndroid Build Coastguard Worker             hdr.entries_size += 1;
1249*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1250*5225e6b1SAndroid Build Coastguard Worker         }
1251*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::UnexpectedEntrySize { actual: 129, expect: 128 });
1252*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1253*5225e6b1SAndroid Build Coastguard Worker     }
1254*5225e6b1SAndroid Build Coastguard Worker 
1255*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_first_usable_gt_last()1256*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_first_usable_gt_last() {
1257*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1258*5225e6b1SAndroid Build Coastguard Worker             hdr.first = hdr.last;
1259*5225e6b1SAndroid Build Coastguard Worker             hdr.last = hdr.first - 2;
1260*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1261*5225e6b1SAndroid Build Coastguard Worker         }
1262*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::InvalidFirstLastUsableBlock {
1263*5225e6b1SAndroid Build Coastguard Worker             first: 94,
1264*5225e6b1SAndroid Build Coastguard Worker             last: 92,
1265*5225e6b1SAndroid Build Coastguard Worker             range: (34, 94),
1266*5225e6b1SAndroid Build Coastguard Worker         });
1267*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1268*5225e6b1SAndroid Build Coastguard Worker     }
1269*5225e6b1SAndroid Build Coastguard Worker 
1270*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_first_usable_out_of_range()1271*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_first_usable_out_of_range() {
1272*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1273*5225e6b1SAndroid Build Coastguard Worker             hdr.first = 33;
1274*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1275*5225e6b1SAndroid Build Coastguard Worker         }
1276*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::InvalidFirstLastUsableBlock {
1277*5225e6b1SAndroid Build Coastguard Worker             first: 33,
1278*5225e6b1SAndroid Build Coastguard Worker             last: 94,
1279*5225e6b1SAndroid Build Coastguard Worker             range: (34, 94),
1280*5225e6b1SAndroid Build Coastguard Worker         });
1281*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1282*5225e6b1SAndroid Build Coastguard Worker     }
1283*5225e6b1SAndroid Build Coastguard Worker 
1284*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_last_usable_out_of_range()1285*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_last_usable_out_of_range() {
1286*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1287*5225e6b1SAndroid Build Coastguard Worker             hdr.last += 1;
1288*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1289*5225e6b1SAndroid Build Coastguard Worker         }
1290*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::InvalidFirstLastUsableBlock {
1291*5225e6b1SAndroid Build Coastguard Worker             first: 34,
1292*5225e6b1SAndroid Build Coastguard Worker             last: 95,
1293*5225e6b1SAndroid Build Coastguard Worker             range: (34, 94),
1294*5225e6b1SAndroid Build Coastguard Worker         });
1295*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1296*5225e6b1SAndroid Build Coastguard Worker     }
1297*5225e6b1SAndroid Build Coastguard Worker 
1298*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_primary_entries_out_of_range()1299*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_primary_entries_out_of_range() {
1300*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(
1301*5225e6b1SAndroid Build Coastguard Worker             |hdr, _| {
1302*5225e6b1SAndroid Build Coastguard Worker                 hdr.entries = 1;
1303*5225e6b1SAndroid Build Coastguard Worker                 hdr.update_crc();
1304*5225e6b1SAndroid Build Coastguard Worker             },
1305*5225e6b1SAndroid Build Coastguard Worker             |hdr, _| {
1306*5225e6b1SAndroid Build Coastguard Worker                 hdr.entries = hdr.last;
1307*5225e6b1SAndroid Build Coastguard Worker                 hdr.update_crc();
1308*5225e6b1SAndroid Build Coastguard Worker             },
1309*5225e6b1SAndroid Build Coastguard Worker             Error::GptError(GptError::InvalidPrimaryEntriesStart {
1310*5225e6b1SAndroid Build Coastguard Worker                 value: 1,
1311*5225e6b1SAndroid Build Coastguard Worker                 expect_range: (2, 2),
1312*5225e6b1SAndroid Build Coastguard Worker             }),
1313*5225e6b1SAndroid Build Coastguard Worker             Error::GptError(GptError::InvalidSecondaryEntriesStart {
1314*5225e6b1SAndroid Build Coastguard Worker                 value: 94,
1315*5225e6b1SAndroid Build Coastguard Worker                 expect_range: (95, 95),
1316*5225e6b1SAndroid Build Coastguard Worker             }),
1317*5225e6b1SAndroid Build Coastguard Worker         );
1318*5225e6b1SAndroid Build Coastguard Worker     }
1319*5225e6b1SAndroid Build Coastguard Worker 
1320*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_incorrect_entry_crc()1321*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_incorrect_entry_crc() {
1322*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, _: Ref<&mut [u8], [GptEntry]>) {
1323*5225e6b1SAndroid Build Coastguard Worker             hdr.entries_crc = !hdr.entries_crc;
1324*5225e6b1SAndroid Build Coastguard Worker             hdr.update_crc();
1325*5225e6b1SAndroid Build Coastguard Worker         }
1326*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::IncorrectEntriesCrc);
1327*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1328*5225e6b1SAndroid Build Coastguard Worker     }
1329*5225e6b1SAndroid Build Coastguard Worker 
1330*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_partition_range_overflow()1331*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_partition_range_overflow() {
1332*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, mut entries: Ref<&mut [u8], [GptEntry]>) {
1333*5225e6b1SAndroid Build Coastguard Worker             entries[1].last = hdr.last + 1;
1334*5225e6b1SAndroid Build Coastguard Worker             hdr.update_entries_crc(entries.as_bytes());
1335*5225e6b1SAndroid Build Coastguard Worker         }
1336*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::InvalidPartitionRange {
1337*5225e6b1SAndroid Build Coastguard Worker             idx: 2,
1338*5225e6b1SAndroid Build Coastguard Worker             part_range: (50, 95),
1339*5225e6b1SAndroid Build Coastguard Worker             usable_range: (34, 94),
1340*5225e6b1SAndroid Build Coastguard Worker         });
1341*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1342*5225e6b1SAndroid Build Coastguard Worker     }
1343*5225e6b1SAndroid Build Coastguard Worker 
1344*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_invalid_partition_range()1345*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_invalid_partition_range() {
1346*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, mut entries: Ref<&mut [u8], [GptEntry]>) {
1347*5225e6b1SAndroid Build Coastguard Worker             entries[1].first = entries[1].last;
1348*5225e6b1SAndroid Build Coastguard Worker             entries[1].last = entries[1].first - 2;
1349*5225e6b1SAndroid Build Coastguard Worker             hdr.update_entries_crc(entries.as_bytes());
1350*5225e6b1SAndroid Build Coastguard Worker         }
1351*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::InvalidPartitionRange {
1352*5225e6b1SAndroid Build Coastguard Worker             idx: 2,
1353*5225e6b1SAndroid Build Coastguard Worker             part_range: (73, 71),
1354*5225e6b1SAndroid Build Coastguard Worker             usable_range: (34, 94),
1355*5225e6b1SAndroid Build Coastguard Worker         });
1356*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1357*5225e6b1SAndroid Build Coastguard Worker     }
1358*5225e6b1SAndroid Build Coastguard Worker 
1359*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_partition_overlap()1360*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_partition_overlap() {
1361*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, mut entries: Ref<&mut [u8], [GptEntry]>) {
1362*5225e6b1SAndroid Build Coastguard Worker             entries[0].last = entries[1].first;
1363*5225e6b1SAndroid Build Coastguard Worker             entries.swap(0, 1);
1364*5225e6b1SAndroid Build Coastguard Worker             hdr.update_entries_crc(entries.as_bytes());
1365*5225e6b1SAndroid Build Coastguard Worker         }
1366*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::PartitionRangeOverlap {
1367*5225e6b1SAndroid Build Coastguard Worker             prev: (2, 34, 50),
1368*5225e6b1SAndroid Build Coastguard Worker             next: (1, 50, 73),
1369*5225e6b1SAndroid Build Coastguard Worker         });
1370*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1371*5225e6b1SAndroid Build Coastguard Worker     }
1372*5225e6b1SAndroid Build Coastguard Worker 
1373*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_zero_partition_type_guid()1374*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_zero_partition_type_guid() {
1375*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, mut entries: Ref<&mut [u8], [GptEntry]>) {
1376*5225e6b1SAndroid Build Coastguard Worker             entries[1].part_type = [0u8; GPT_GUID_LEN];
1377*5225e6b1SAndroid Build Coastguard Worker             hdr.update_entries_crc(entries.as_bytes());
1378*5225e6b1SAndroid Build Coastguard Worker         }
1379*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::ZeroPartitionTypeGUID { idx: 2 });
1380*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1381*5225e6b1SAndroid Build Coastguard Worker     }
1382*5225e6b1SAndroid Build Coastguard Worker 
1383*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_zero_partition_unique_guid()1384*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_zero_partition_unique_guid() {
1385*5225e6b1SAndroid Build Coastguard Worker         fn modify(hdr: &mut GptHeader, mut entries: Ref<&mut [u8], [GptEntry]>) {
1386*5225e6b1SAndroid Build Coastguard Worker             entries[1].guid = [0u8; GPT_GUID_LEN];
1387*5225e6b1SAndroid Build Coastguard Worker             hdr.update_entries_crc(entries.as_bytes());
1388*5225e6b1SAndroid Build Coastguard Worker         }
1389*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::ZeroPartitionUniqueGUID { idx: 2 });
1390*5225e6b1SAndroid Build Coastguard Worker         test_gpt_sync_restore(modify, modify, err, err);
1391*5225e6b1SAndroid Build Coastguard Worker     }
1392*5225e6b1SAndroid Build Coastguard Worker 
1393*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_gpt_disk_primary_override_secondary()1394*5225e6b1SAndroid Build Coastguard Worker     fn test_load_gpt_disk_primary_override_secondary() {
1395*5225e6b1SAndroid Build Coastguard Worker         let mut disk = include_bytes!("../test/gpt_test_1.bin").to_vec();
1396*5225e6b1SAndroid Build Coastguard Worker         // Modifies secondary header.
1397*5225e6b1SAndroid Build Coastguard Worker         let secondary_hdr = GptHeader::from_bytes_mut(disk.last_chunk_mut::<512>().unwrap());
1398*5225e6b1SAndroid Build Coastguard Worker         secondary_hdr.revision = !secondary_hdr.revision;
1399*5225e6b1SAndroid Build Coastguard Worker         secondary_hdr.update_crc();
1400*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1401*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1402*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.sync_gpt(&mut gpt)).unwrap(),
1403*5225e6b1SAndroid Build Coastguard Worker             GptSyncResult::SecondaryRestored(Error::GptError(GptError::DifferentFromPrimary)),
1404*5225e6b1SAndroid Build Coastguard Worker         );
1405*5225e6b1SAndroid Build Coastguard Worker     }
1406*5225e6b1SAndroid Build Coastguard Worker 
1407*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_gpt_disk_too_small()1408*5225e6b1SAndroid Build Coastguard Worker     fn test_load_gpt_disk_too_small() {
1409*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../test/gpt_test_1.bin");
1410*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1411*5225e6b1SAndroid Build Coastguard Worker         // Resizes so that it's not enough to hold a full 128 maximum entries.
1412*5225e6b1SAndroid Build Coastguard Worker         // MBR + (header + entries) * 2 - 1
1413*5225e6b1SAndroid Build Coastguard Worker         disk.resize((1 + (32 + 1) * 2 - 1) * 512, 0);
1414*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1415*5225e6b1SAndroid Build Coastguard Worker         let sync_res = block_on(dev.sync_gpt(&mut gpt)).unwrap();
1416*5225e6b1SAndroid Build Coastguard Worker         let err = Error::GptError(GptError::DiskTooSmall);
1417*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(sync_res, GptSyncResult::NoValidGpt { primary: err, secondary: err });
1418*5225e6b1SAndroid Build Coastguard Worker     }
1419*5225e6b1SAndroid Build Coastguard Worker 
1420*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_uninitialized_gpt()1421*5225e6b1SAndroid Build Coastguard Worker     fn test_uninitialized_gpt() {
1422*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../test/gpt_test_1.bin");
1423*5225e6b1SAndroid Build Coastguard Worker         // Load a good GPT first.
1424*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1425*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(dev.sync_gpt(&mut gpt)).unwrap(), GptSyncResult::BothValid);
1426*5225e6b1SAndroid Build Coastguard Worker         gpt.find_partition("boot_a").unwrap();
1427*5225e6b1SAndroid Build Coastguard Worker         // Corrupt GPT.
1428*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.write(0, &mut vec![0u8; disk.len()])).unwrap();
1429*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(dev.sync_gpt(&mut gpt)).unwrap().res().is_err());
1430*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.find_partition("").is_err());
1431*5225e6b1SAndroid Build Coastguard Worker     }
1432*5225e6b1SAndroid Build Coastguard Worker 
1433*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt()1434*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt() {
1435*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../test/gpt_test_1.bin");
1436*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1437*5225e6b1SAndroid Build Coastguard Worker         // Erases all GPT headers.
1438*5225e6b1SAndroid Build Coastguard Worker         disk[512..][..512].fill(0);
1439*5225e6b1SAndroid Build Coastguard Worker         disk.last_chunk_mut::<512>().unwrap().fill(0);
1440*5225e6b1SAndroid Build Coastguard Worker 
1441*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1442*5225e6b1SAndroid Build Coastguard Worker 
1443*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(dev.io().storage(), disk_orig);
1444*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = disk_orig[..34 * 512].to_vec();
1445*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.update_gpt(&mut mbr_primary, false, &mut gpt)).unwrap();
1446*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(dev.io().storage(), disk_orig);
1447*5225e6b1SAndroid Build Coastguard Worker     }
1448*5225e6b1SAndroid Build Coastguard Worker 
1449*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_has_existing_valid_secondary()1450*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_has_existing_valid_secondary() {
1451*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../test/gpt_test_1.bin");
1452*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1453*5225e6b1SAndroid Build Coastguard Worker         // Erases all GPT headers.
1454*5225e6b1SAndroid Build Coastguard Worker         disk[512..][..512].fill(0);
1455*5225e6b1SAndroid Build Coastguard Worker         // Leaves a valid but different secondary GPT.
1456*5225e6b1SAndroid Build Coastguard Worker         let secondary_hdr = GptHeader::from_bytes_mut(disk.last_chunk_mut::<512>().unwrap());
1457*5225e6b1SAndroid Build Coastguard Worker         secondary_hdr.revision = !secondary_hdr.revision;
1458*5225e6b1SAndroid Build Coastguard Worker         secondary_hdr.update_crc();
1459*5225e6b1SAndroid Build Coastguard Worker 
1460*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1461*5225e6b1SAndroid Build Coastguard Worker 
1462*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(dev.io().storage(), disk_orig);
1463*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = disk_orig[..34 * 512].to_vec();
1464*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.update_gpt(&mut mbr_primary, false, &mut gpt)).unwrap();
1465*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(dev.io().storage(), disk_orig);
1466*5225e6b1SAndroid Build Coastguard Worker     }
1467*5225e6b1SAndroid Build Coastguard Worker 
1468*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_last_usable_adjusted()1469*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_last_usable_adjusted() {
1470*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../test/gpt_test_1.bin");
1471*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1472*5225e6b1SAndroid Build Coastguard Worker         // Erases all GPT headers.
1473*5225e6b1SAndroid Build Coastguard Worker         disk[512..][..512].fill(0);
1474*5225e6b1SAndroid Build Coastguard Worker         disk.last_chunk_mut::<512>().unwrap().fill(0);
1475*5225e6b1SAndroid Build Coastguard Worker         // Doubles the disk size.
1476*5225e6b1SAndroid Build Coastguard Worker         disk.resize(disk_orig.len() * 2, 0);
1477*5225e6b1SAndroid Build Coastguard Worker 
1478*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1479*5225e6b1SAndroid Build Coastguard Worker 
1480*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(dev.io().storage, disk_orig);
1481*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = disk_orig[..34 * 512].to_vec();
1482*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.update_gpt(&mut mbr_primary, true, &mut gpt)).unwrap();
1483*5225e6b1SAndroid Build Coastguard Worker         let expected_last = (disk.len() - GPT_MAX_NUM_ENTRIES_SIZE - 512) / 512 - 1;
1484*5225e6b1SAndroid Build Coastguard Worker 
1485*5225e6b1SAndroid Build Coastguard Worker         let (primary, secondary) = dev.io().storage().split_last_chunk_mut::<512>().unwrap();
1486*5225e6b1SAndroid Build Coastguard Worker         let primary_hdr = GptHeader::from_bytes_mut(&mut primary[512..]);
1487*5225e6b1SAndroid Build Coastguard Worker         let secondary_hdr = GptHeader::from_bytes_mut(secondary);
1488*5225e6b1SAndroid Build Coastguard Worker         // Header's last usable block is updated.
1489*5225e6b1SAndroid Build Coastguard Worker         assert_eq!({ primary_hdr.last }, expected_last.try_into().unwrap());
1490*5225e6b1SAndroid Build Coastguard Worker         assert_eq!({ primary_hdr.backup }, (disk.len() / 512 - 1).try_into().unwrap());
1491*5225e6b1SAndroid Build Coastguard Worker         assert_eq!({ secondary_hdr.last }, expected_last.try_into().unwrap());
1492*5225e6b1SAndroid Build Coastguard Worker     }
1493*5225e6b1SAndroid Build Coastguard Worker 
1494*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_resize()1495*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_resize() {
1496*5225e6b1SAndroid Build Coastguard Worker         let disk_orig = include_bytes!("../test/gpt_test_1.bin");
1497*5225e6b1SAndroid Build Coastguard Worker         let mut disk = disk_orig.to_vec();
1498*5225e6b1SAndroid Build Coastguard Worker         // Erases all GPT headers.
1499*5225e6b1SAndroid Build Coastguard Worker         disk[512..][..512].fill(0);
1500*5225e6b1SAndroid Build Coastguard Worker         disk.last_chunk_mut::<512>().unwrap().fill(0);
1501*5225e6b1SAndroid Build Coastguard Worker         // Doubles the disk size.
1502*5225e6b1SAndroid Build Coastguard Worker         disk.resize(disk_orig.len() * 2, 0);
1503*5225e6b1SAndroid Build Coastguard Worker 
1504*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1505*5225e6b1SAndroid Build Coastguard Worker 
1506*5225e6b1SAndroid Build Coastguard Worker         assert_ne!(dev.io().storage, disk_orig);
1507*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = disk_orig[..34 * 512].to_vec();
1508*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.update_gpt(&mut mbr_primary, true, &mut gpt)).unwrap();
1509*5225e6b1SAndroid Build Coastguard Worker         // Last entry is extended.
1510*5225e6b1SAndroid Build Coastguard Worker         let expected_last = (disk.len() - GPT_MAX_NUM_ENTRIES_SIZE - 512) / 512 - 1;
1511*5225e6b1SAndroid Build Coastguard Worker         assert_eq!({ gpt.entries().unwrap()[1].last }, expected_last.try_into().unwrap());
1512*5225e6b1SAndroid Build Coastguard Worker     }
1513*5225e6b1SAndroid Build Coastguard Worker 
1514*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_new_partition_out_of_range()1515*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_new_partition_out_of_range() {
1516*5225e6b1SAndroid Build Coastguard Worker         // `gpt_test_1.bin` has a 8k "boot_a" and a 12k "boot_b". Thus partitions space is 40
1517*5225e6b1SAndroid Build Coastguard Worker         // blocks (512 bytes block size) and in total the GPT disk needs (40 + 1 + (33) * 2) = 107
1518*5225e6b1SAndroid Build Coastguard Worker         // blocks.
1519*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&vec![0u8; 106 * 512]);
1520*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = include_bytes!("../test/gpt_test_1.bin")[..34 * 512].to_vec();
1521*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(dev.update_gpt(&mut mbr_primary, true, &mut gpt)).is_err());
1522*5225e6b1SAndroid Build Coastguard Worker     }
1523*5225e6b1SAndroid Build Coastguard Worker 
1524*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_buffer_truncated()1525*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_buffer_truncated() {
1526*5225e6b1SAndroid Build Coastguard Worker         let mut disk = include_bytes!("../test/gpt_test_1.bin").to_vec();
1527*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1528*5225e6b1SAndroid Build Coastguard Worker 
1529*5225e6b1SAndroid Build Coastguard Worker         // Less than 1 MBR block.
1530*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1531*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.update_gpt(&mut disk[..511], false, &mut gpt)),
1532*5225e6b1SAndroid Build Coastguard Worker             Err(Error::BufferTooSmall(Some(1024)))
1533*5225e6b1SAndroid Build Coastguard Worker         );
1534*5225e6b1SAndroid Build Coastguard Worker 
1535*5225e6b1SAndroid Build Coastguard Worker         // Less than MBR + GPT header.
1536*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1537*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.update_gpt(&mut disk[..1023], false, &mut gpt)),
1538*5225e6b1SAndroid Build Coastguard Worker             Err(Error::BufferTooSmall(Some(1024)))
1539*5225e6b1SAndroid Build Coastguard Worker         );
1540*5225e6b1SAndroid Build Coastguard Worker 
1541*5225e6b1SAndroid Build Coastguard Worker         // Less than MBR + GPT header + entries.
1542*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1543*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.update_gpt(&mut disk[..34 * 512 - 1], false, &mut gpt)),
1544*5225e6b1SAndroid Build Coastguard Worker             Err(Error::BufferTooSmall(Some(34 * 512)))
1545*5225e6b1SAndroid Build Coastguard Worker         );
1546*5225e6b1SAndroid Build Coastguard Worker     }
1547*5225e6b1SAndroid Build Coastguard Worker 
1548*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_check_header_fail()1549*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_check_header_fail() {
1550*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../test/gpt_test_1.bin");
1551*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1552*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = disk[..34 * 512].to_vec();
1553*5225e6b1SAndroid Build Coastguard Worker         // Corrupts the first byte of the GPT header.
1554*5225e6b1SAndroid Build Coastguard Worker         mbr_primary[512] = !mbr_primary[512];
1555*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1556*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.update_gpt(&mut mbr_primary, false, &mut gpt)),
1557*5225e6b1SAndroid Build Coastguard Worker             Err(Error::GptError(GptError::IncorrectMagic(0x54524150204946BA)))
1558*5225e6b1SAndroid Build Coastguard Worker         );
1559*5225e6b1SAndroid Build Coastguard Worker     }
1560*5225e6b1SAndroid Build Coastguard Worker 
1561*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_update_gpt_check_entries_fail()1562*5225e6b1SAndroid Build Coastguard Worker     fn test_update_gpt_check_entries_fail() {
1563*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../test/gpt_test_1.bin");
1564*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1565*5225e6b1SAndroid Build Coastguard Worker         let mut mbr_primary = disk[..34 * 512].to_vec();
1566*5225e6b1SAndroid Build Coastguard Worker         // Corrupts the first byte of the entries.
1567*5225e6b1SAndroid Build Coastguard Worker         mbr_primary[1024] = !mbr_primary[1024];
1568*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1569*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.update_gpt(&mut mbr_primary, false, &mut gpt)),
1570*5225e6b1SAndroid Build Coastguard Worker             Err(Error::GptError(GptError::IncorrectEntriesCrc))
1571*5225e6b1SAndroid Build Coastguard Worker         );
1572*5225e6b1SAndroid Build Coastguard Worker     }
1573*5225e6b1SAndroid Build Coastguard Worker 
1574*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_erase_gpt_no_gpt()1575*5225e6b1SAndroid Build Coastguard Worker     fn test_erase_gpt_no_gpt() {
1576*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&[0u8; 1024 * 1024]);
1577*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.erase_gpt(&mut gpt)).unwrap();
1578*5225e6b1SAndroid Build Coastguard Worker     }
1579*5225e6b1SAndroid Build Coastguard Worker 
1580*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_erase_gpt()1581*5225e6b1SAndroid Build Coastguard Worker     fn test_erase_gpt() {
1582*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(include_bytes!("../test/gpt_test_1.bin"));
1583*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.erase_gpt(&mut gpt)).unwrap();
1584*5225e6b1SAndroid Build Coastguard Worker         const GPT_SECTOR: usize = 33 * 512;
1585*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(dev.io().storage[512..][..GPT_SECTOR], vec![0u8; GPT_SECTOR]);
1586*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(*dev.io().storage.last_chunk::<GPT_SECTOR>().unwrap(), *vec![0u8; GPT_SECTOR]);
1587*5225e6b1SAndroid Build Coastguard Worker         assert!(matches!(
1588*5225e6b1SAndroid Build Coastguard Worker             block_on(dev.sync_gpt(&mut gpt)).unwrap(),
1589*5225e6b1SAndroid Build Coastguard Worker             GptSyncResult::NoValidGpt { .. }
1590*5225e6b1SAndroid Build Coastguard Worker         ));
1591*5225e6b1SAndroid Build Coastguard Worker     }
1592*5225e6b1SAndroid Build Coastguard Worker 
1593*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_zero_partition_size()1594*5225e6b1SAndroid Build Coastguard Worker     fn test_zero_partition_size() {
1595*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../test/gpt_test_1.bin").to_vec();
1596*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1597*5225e6b1SAndroid Build Coastguard Worker         let (mut builder, _) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1598*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(builder.remove("boot_a"), Ok(true));
1599*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(builder.remove("boot_b"), Ok(true));
1600*5225e6b1SAndroid Build Coastguard Worker         builder.add("boot_b", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, Some(0)).unwrap();
1601*5225e6b1SAndroid Build Coastguard Worker         block_on(builder.persist()).unwrap();
1602*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.partition_iter().unwrap().next().unwrap().size().unwrap(), 0);
1603*5225e6b1SAndroid Build Coastguard Worker     }
1604*5225e6b1SAndroid Build Coastguard Worker 
1605*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sync_gpt_non_sorted_entries()1606*5225e6b1SAndroid Build Coastguard Worker     fn test_sync_gpt_non_sorted_entries() {
1607*5225e6b1SAndroid Build Coastguard Worker         let mut disk = include_bytes!("../test/gpt_test_1.bin").to_vec();
1608*5225e6b1SAndroid Build Coastguard Worker         let (header, entries) = disk[512..].split_at_mut(512);
1609*5225e6b1SAndroid Build Coastguard Worker         let header = GptHeader::from_bytes_mut(header);
1610*5225e6b1SAndroid Build Coastguard Worker         let mut entries = Ref::<_, [GptEntry]>::new_slice(entries).unwrap();
1611*5225e6b1SAndroid Build Coastguard Worker         // Makes partition non-sorted.
1612*5225e6b1SAndroid Build Coastguard Worker         entries.swap(0, 1);
1613*5225e6b1SAndroid Build Coastguard Worker         header.update_entries_crc(entries.as_bytes());
1614*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1615*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.sync_gpt(&mut gpt)).unwrap().res().unwrap();
1616*5225e6b1SAndroid Build Coastguard Worker     }
1617*5225e6b1SAndroid Build Coastguard Worker 
1618*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_builder_initialize_gpt_if_no_valid_gpt()1619*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_builder_initialize_gpt_if_no_valid_gpt() {
1620*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(vec![0u8; 1024 * 1024]);
1621*5225e6b1SAndroid Build Coastguard Worker         let (builder, valid) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1622*5225e6b1SAndroid Build Coastguard Worker         assert!(!valid);
1623*5225e6b1SAndroid Build Coastguard Worker         block_on(builder.persist()).unwrap();
1624*5225e6b1SAndroid Build Coastguard Worker         // A new GPT is created.
1625*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.sync_gpt(&mut gpt)).unwrap().res().unwrap();
1626*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.partition_iter().unwrap().next().is_none());
1627*5225e6b1SAndroid Build Coastguard Worker     }
1628*5225e6b1SAndroid Build Coastguard Worker 
1629*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_builder_remove_partition()1630*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_builder_remove_partition() {
1631*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(include_bytes!("../test/gpt_test_1.bin"));
1632*5225e6b1SAndroid Build Coastguard Worker         let (mut builder, valid) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1633*5225e6b1SAndroid Build Coastguard Worker         assert!(valid);
1634*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(builder.remove("boot_b"), Ok(true));
1635*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(builder.remove("non-existent"), Ok(false));
1636*5225e6b1SAndroid Build Coastguard Worker         block_on(builder.persist()).unwrap();
1637*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.sync_gpt(&mut gpt)).unwrap().res().unwrap();
1638*5225e6b1SAndroid Build Coastguard Worker         let part_iter = gpt.partition_iter().unwrap();
1639*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
1640*5225e6b1SAndroid Build Coastguard Worker             part_iter.map(|v| v.name().unwrap().into()).collect::<Vec<String>>(),
1641*5225e6b1SAndroid Build Coastguard Worker             ["boot_a"]
1642*5225e6b1SAndroid Build Coastguard Worker         );
1643*5225e6b1SAndroid Build Coastguard Worker     }
1644*5225e6b1SAndroid Build Coastguard Worker 
1645*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_builder_add_partition_find_first()1646*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_builder_add_partition_find_first() {
1647*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(include_bytes!("../test/gpt_test_1.bin"));
1648*5225e6b1SAndroid Build Coastguard Worker         let (mut builder, _) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1649*5225e6b1SAndroid Build Coastguard Worker         assert!(builder.remove("boot_a").unwrap());
1650*5225e6b1SAndroid Build Coastguard Worker         // Adds at the beginning.
1651*5225e6b1SAndroid Build Coastguard Worker         builder.add("new_0", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, Some(1024)).unwrap();
1652*5225e6b1SAndroid Build Coastguard Worker         // Adds following "new_0"
1653*5225e6b1SAndroid Build Coastguard Worker         builder.add("new_1", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, Some(1)).unwrap();
1654*5225e6b1SAndroid Build Coastguard Worker         block_on(builder.persist()).unwrap();
1655*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.sync_gpt(&mut gpt)).unwrap().res().unwrap();
1656*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("new_0").unwrap().absolute_range().unwrap(), (17408, 18432));
1657*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("new_1").unwrap().absolute_range().unwrap(), (18432, 18944));
1658*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("boot_b").unwrap().absolute_range().unwrap(), (25600, 37888));
1659*5225e6b1SAndroid Build Coastguard Worker     }
1660*5225e6b1SAndroid Build Coastguard Worker 
1661*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_builder_non_sorted_add_partition()1662*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_builder_non_sorted_add_partition() {
1663*5225e6b1SAndroid Build Coastguard Worker         let mut disk = include_bytes!("../test/gpt_test_1.bin").to_vec();
1664*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(&disk);
1665*5225e6b1SAndroid Build Coastguard Worker         let (header, entries) = disk[512..].split_at_mut(512);
1666*5225e6b1SAndroid Build Coastguard Worker         let header = GptHeader::from_bytes_mut(header);
1667*5225e6b1SAndroid Build Coastguard Worker         let mut entries = Ref::<_, [GptEntry]>::new_slice(entries).unwrap();
1668*5225e6b1SAndroid Build Coastguard Worker         // Makes partition non-sorted.
1669*5225e6b1SAndroid Build Coastguard Worker         entries.swap(0, 1);
1670*5225e6b1SAndroid Build Coastguard Worker         header.update_entries_crc(entries.as_bytes());
1671*5225e6b1SAndroid Build Coastguard Worker 
1672*5225e6b1SAndroid Build Coastguard Worker         let (mut builder, _) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1673*5225e6b1SAndroid Build Coastguard Worker         // Adds following boot_b.
1674*5225e6b1SAndroid Build Coastguard Worker         builder.add("new", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, Some(1024)).unwrap();
1675*5225e6b1SAndroid Build Coastguard Worker         block_on(builder.persist()).unwrap();
1676*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("boot_a").unwrap().absolute_range().unwrap(), (17408, 25600));
1677*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("boot_b").unwrap().absolute_range().unwrap(), (25600, 37888));
1678*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("new").unwrap().absolute_range().unwrap(), (37888, 38912));
1679*5225e6b1SAndroid Build Coastguard Worker     }
1680*5225e6b1SAndroid Build Coastguard Worker 
1681*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_builder_add_partition_append()1682*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_builder_add_partition_append() {
1683*5225e6b1SAndroid Build Coastguard Worker         let (mut dev, mut gpt) = test_disk_and_gpt(include_bytes!("../test/gpt_test_1.bin"));
1684*5225e6b1SAndroid Build Coastguard Worker         let (mut builder, _) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1685*5225e6b1SAndroid Build Coastguard Worker         assert!(builder.remove("boot_b").unwrap());
1686*5225e6b1SAndroid Build Coastguard Worker         // Adds following "boot_a".
1687*5225e6b1SAndroid Build Coastguard Worker         builder.add("new_0", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, Some(1024)).unwrap();
1688*5225e6b1SAndroid Build Coastguard Worker         // Consumes the rest of the space.
1689*5225e6b1SAndroid Build Coastguard Worker         builder.add("new_1", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, None).unwrap();
1690*5225e6b1SAndroid Build Coastguard Worker         block_on(builder.persist()).unwrap();
1691*5225e6b1SAndroid Build Coastguard Worker         block_on(dev.sync_gpt(&mut gpt)).unwrap().res().unwrap();
1692*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("boot_a").unwrap().absolute_range().unwrap(), (17408, 25600));
1693*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("new_0").unwrap().absolute_range().unwrap(), (25600, 26624));
1694*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.find_partition("new_1").unwrap().absolute_range().unwrap(), (26624, 48640));
1695*5225e6b1SAndroid Build Coastguard Worker     }
1696*5225e6b1SAndroid Build Coastguard Worker 
1697*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_gpt_builder_not_enough_resource()1698*5225e6b1SAndroid Build Coastguard Worker     fn test_gpt_builder_not_enough_resource() {
1699*5225e6b1SAndroid Build Coastguard Worker         // Create a Gpt that can only load 1 entry.
1700*5225e6b1SAndroid Build Coastguard Worker         let mut gpt = new_gpt_n::<1>();
1701*5225e6b1SAndroid Build Coastguard Worker         let mut dev = test_disk(vec![0u8; 64 * 1024]);
1702*5225e6b1SAndroid Build Coastguard Worker         let (mut builder, _) = GptBuilder::new(&mut dev, &mut gpt).unwrap();
1703*5225e6b1SAndroid Build Coastguard Worker         builder.add("new_0", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, Some(1024)).unwrap();
1704*5225e6b1SAndroid Build Coastguard Worker         assert!(builder.add("new_1", [1u8; GPT_GUID_LEN], [1u8; GPT_GUID_LEN], 0, None).is_err());
1705*5225e6b1SAndroid Build Coastguard Worker     }
1706*5225e6b1SAndroid Build Coastguard Worker }
1707