xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/partition.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, 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 //! This file implements storage and partition logic for libgbl.
16*5225e6b1SAndroid Build Coastguard Worker 
17*5225e6b1SAndroid Build Coastguard Worker use crate::fastboot::sparse::{is_sparse_image, write_sparse_image, SparseRawWriter};
18*5225e6b1SAndroid Build Coastguard Worker use core::cell::{RefCell, RefMut};
19*5225e6b1SAndroid Build Coastguard Worker use core::{
20*5225e6b1SAndroid Build Coastguard Worker     ffi::CStr,
21*5225e6b1SAndroid Build Coastguard Worker     mem::swap,
22*5225e6b1SAndroid Build Coastguard Worker     ops::{Deref, DerefMut},
23*5225e6b1SAndroid Build Coastguard Worker };
24*5225e6b1SAndroid Build Coastguard Worker use gbl_storage::{
25*5225e6b1SAndroid Build Coastguard Worker     BlockInfo, BlockIo, Disk, Gpt, GptBuilder, GptSyncResult, Partition as GptPartition,
26*5225e6b1SAndroid Build Coastguard Worker     SliceMaybeUninit,
27*5225e6b1SAndroid Build Coastguard Worker };
28*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
29*5225e6b1SAndroid Build Coastguard Worker use safemath::SafeNum;
30*5225e6b1SAndroid Build Coastguard Worker 
31*5225e6b1SAndroid Build Coastguard Worker /// Maximum name length for raw partition.
32*5225e6b1SAndroid Build Coastguard Worker const RAW_PARTITION_NAME_LEN: usize = 72;
33*5225e6b1SAndroid Build Coastguard Worker 
34*5225e6b1SAndroid Build Coastguard Worker /// Wraps a bytes buffer containing a null-terminated C string
35*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, PartialEq, Debug)]
36*5225e6b1SAndroid Build Coastguard Worker pub struct RawName([u8; RAW_PARTITION_NAME_LEN]);
37*5225e6b1SAndroid Build Coastguard Worker 
38*5225e6b1SAndroid Build Coastguard Worker impl RawName {
new(name: &CStr) -> Result<Self, Error>39*5225e6b1SAndroid Build Coastguard Worker     fn new(name: &CStr) -> Result<Self, Error> {
40*5225e6b1SAndroid Build Coastguard Worker         let mut buf = [0u8; RAW_PARTITION_NAME_LEN];
41*5225e6b1SAndroid Build Coastguard Worker         name.to_str().map_err(|_| Error::InvalidInput)?;
42*5225e6b1SAndroid Build Coastguard Worker         let name = name.to_bytes_with_nul();
43*5225e6b1SAndroid Build Coastguard Worker         buf.get_mut(..name.len()).ok_or(Error::InvalidInput)?.clone_from_slice(name);
44*5225e6b1SAndroid Build Coastguard Worker         Ok(Self(buf))
45*5225e6b1SAndroid Build Coastguard Worker     }
46*5225e6b1SAndroid Build Coastguard Worker 
47*5225e6b1SAndroid Build Coastguard Worker     /// Decodes to a string.
to_str(&self) -> &str48*5225e6b1SAndroid Build Coastguard Worker     pub fn to_str(&self) -> &str {
49*5225e6b1SAndroid Build Coastguard Worker         CStr::from_bytes_until_nul(&self.0[..]).unwrap().to_str().unwrap()
50*5225e6b1SAndroid Build Coastguard Worker     }
51*5225e6b1SAndroid Build Coastguard Worker }
52*5225e6b1SAndroid Build Coastguard Worker 
53*5225e6b1SAndroid Build Coastguard Worker /// Represents a GBL partition.
54*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, PartialEq, Debug)]
55*5225e6b1SAndroid Build Coastguard Worker pub enum Partition {
56*5225e6b1SAndroid Build Coastguard Worker     /// Raw storage partition.
57*5225e6b1SAndroid Build Coastguard Worker     Raw(RawName, u64),
58*5225e6b1SAndroid Build Coastguard Worker     /// Gpt Partition.
59*5225e6b1SAndroid Build Coastguard Worker     Gpt(GptPartition),
60*5225e6b1SAndroid Build Coastguard Worker }
61*5225e6b1SAndroid Build Coastguard Worker 
62*5225e6b1SAndroid Build Coastguard Worker impl Partition {
63*5225e6b1SAndroid Build Coastguard Worker     /// Returns the size.
size(&self) -> Result<u64, Error>64*5225e6b1SAndroid Build Coastguard Worker     pub fn size(&self) -> Result<u64, Error> {
65*5225e6b1SAndroid Build Coastguard Worker         let (start, end) = self.absolute_range()?;
66*5225e6b1SAndroid Build Coastguard Worker         Ok((SafeNum::from(end) - start).try_into()?)
67*5225e6b1SAndroid Build Coastguard Worker     }
68*5225e6b1SAndroid Build Coastguard Worker 
69*5225e6b1SAndroid Build Coastguard Worker     /// Returns the name.
name(&self) -> Result<&str, Error>70*5225e6b1SAndroid Build Coastguard Worker     pub fn name(&self) -> Result<&str, Error> {
71*5225e6b1SAndroid Build Coastguard Worker         Ok(match self {
72*5225e6b1SAndroid Build Coastguard Worker             Partition::Gpt(gpt) => gpt.name().ok_or(Error::InvalidInput)?,
73*5225e6b1SAndroid Build Coastguard Worker             Partition::Raw(name, _) => name.to_str(),
74*5225e6b1SAndroid Build Coastguard Worker         })
75*5225e6b1SAndroid Build Coastguard Worker     }
76*5225e6b1SAndroid Build Coastguard Worker 
77*5225e6b1SAndroid Build Coastguard Worker     /// Computes the absolute start and end offset for the partition in the whole block device.
absolute_range(&self) -> Result<(u64, u64), Error>78*5225e6b1SAndroid Build Coastguard Worker     pub fn absolute_range(&self) -> Result<(u64, u64), Error> {
79*5225e6b1SAndroid Build Coastguard Worker         Ok(match self {
80*5225e6b1SAndroid Build Coastguard Worker             Partition::Gpt(gpt) => gpt.absolute_range()?,
81*5225e6b1SAndroid Build Coastguard Worker             Partition::Raw(_, size) => (0, *size),
82*5225e6b1SAndroid Build Coastguard Worker         })
83*5225e6b1SAndroid Build Coastguard Worker     }
84*5225e6b1SAndroid Build Coastguard Worker }
85*5225e6b1SAndroid Build Coastguard Worker 
86*5225e6b1SAndroid Build Coastguard Worker /// Represents the partition table for a block device. It can either be a GPT partition table or a
87*5225e6b1SAndroid Build Coastguard Worker /// single whole device raw partition.
88*5225e6b1SAndroid Build Coastguard Worker enum PartitionTable<G> {
89*5225e6b1SAndroid Build Coastguard Worker     Raw(RawName, u64),
90*5225e6b1SAndroid Build Coastguard Worker     Gpt(G),
91*5225e6b1SAndroid Build Coastguard Worker }
92*5225e6b1SAndroid Build Coastguard Worker 
93*5225e6b1SAndroid Build Coastguard Worker /// The status of block device
94*5225e6b1SAndroid Build Coastguard Worker pub enum BlockStatus {
95*5225e6b1SAndroid Build Coastguard Worker     /// Idle,
96*5225e6b1SAndroid Build Coastguard Worker     Idle,
97*5225e6b1SAndroid Build Coastguard Worker     /// An IO in progress.
98*5225e6b1SAndroid Build Coastguard Worker     Pending,
99*5225e6b1SAndroid Build Coastguard Worker     /// Error.
100*5225e6b1SAndroid Build Coastguard Worker     Error(Error),
101*5225e6b1SAndroid Build Coastguard Worker }
102*5225e6b1SAndroid Build Coastguard Worker 
103*5225e6b1SAndroid Build Coastguard Worker impl BlockStatus {
104*5225e6b1SAndroid Build Coastguard Worker     /// Converts to str.
to_str(&self) -> &'static str105*5225e6b1SAndroid Build Coastguard Worker     pub fn to_str(&self) -> &'static str {
106*5225e6b1SAndroid Build Coastguard Worker         match self {
107*5225e6b1SAndroid Build Coastguard Worker             BlockStatus::Idle => "idle",
108*5225e6b1SAndroid Build Coastguard Worker             BlockStatus::Pending => "IO pending",
109*5225e6b1SAndroid Build Coastguard Worker             BlockStatus::Error(_) => "error",
110*5225e6b1SAndroid Build Coastguard Worker         }
111*5225e6b1SAndroid Build Coastguard Worker     }
112*5225e6b1SAndroid Build Coastguard Worker 
113*5225e6b1SAndroid Build Coastguard Worker     /// Converts to result.
result(&self) -> Result<(), Error>114*5225e6b1SAndroid Build Coastguard Worker     pub fn result(&self) -> Result<(), Error> {
115*5225e6b1SAndroid Build Coastguard Worker         match self {
116*5225e6b1SAndroid Build Coastguard Worker             Self::Error(e) => Err(*e),
117*5225e6b1SAndroid Build Coastguard Worker             _ => Ok(()),
118*5225e6b1SAndroid Build Coastguard Worker         }
119*5225e6b1SAndroid Build Coastguard Worker     }
120*5225e6b1SAndroid Build Coastguard Worker }
121*5225e6b1SAndroid Build Coastguard Worker 
122*5225e6b1SAndroid Build Coastguard Worker /// Represents a disk device that contains either GPT partitions or a single whole raw storage
123*5225e6b1SAndroid Build Coastguard Worker /// partition.
124*5225e6b1SAndroid Build Coastguard Worker pub struct GblDisk<D, G> {
125*5225e6b1SAndroid Build Coastguard Worker     // Contains a `Disk` for block IO and `Result` to track the most recent error.
126*5225e6b1SAndroid Build Coastguard Worker     // Wraps in `Mutex` as it will be used in parallel fastboot task.
127*5225e6b1SAndroid Build Coastguard Worker     //
128*5225e6b1SAndroid Build Coastguard Worker     // `blk` and `partitions` are wrapped in RefCell because they may be shared by multiple async
129*5225e6b1SAndroid Build Coastguard Worker     // blocks for operations such as parallel fastboot download/flashing. They are also wrapped
130*5225e6b1SAndroid Build Coastguard Worker     // separately in order to make operations on each independent and parallel for use cases such
131*5225e6b1SAndroid Build Coastguard Worker     // as getting partition info for `fastboot getvar` when disk IO is busy.
132*5225e6b1SAndroid Build Coastguard Worker     disk: RefCell<(D, Result<(), Error>)>,
133*5225e6b1SAndroid Build Coastguard Worker     partitions: RefCell<PartitionTable<G>>,
134*5225e6b1SAndroid Build Coastguard Worker     info_cache: BlockInfo,
135*5225e6b1SAndroid Build Coastguard Worker }
136*5225e6b1SAndroid Build Coastguard Worker 
137*5225e6b1SAndroid Build Coastguard Worker impl<B, S, T> GblDisk<Disk<B, S>, Gpt<T>>
138*5225e6b1SAndroid Build Coastguard Worker where
139*5225e6b1SAndroid Build Coastguard Worker     B: BlockIo,
140*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]>,
141*5225e6b1SAndroid Build Coastguard Worker     T: DerefMut<Target = [u8]>,
142*5225e6b1SAndroid Build Coastguard Worker {
143*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance as a GPT device.
new_gpt(mut disk: Disk<B, S>, gpt: Gpt<T>) -> Self144*5225e6b1SAndroid Build Coastguard Worker     pub fn new_gpt(mut disk: Disk<B, S>, gpt: Gpt<T>) -> Self {
145*5225e6b1SAndroid Build Coastguard Worker         let info_cache = disk.io().info();
146*5225e6b1SAndroid Build Coastguard Worker         Self {
147*5225e6b1SAndroid Build Coastguard Worker             disk: (disk, Ok(())).into(),
148*5225e6b1SAndroid Build Coastguard Worker             info_cache,
149*5225e6b1SAndroid Build Coastguard Worker             partitions: PartitionTable::Gpt(gpt).into(),
150*5225e6b1SAndroid Build Coastguard Worker         }
151*5225e6b1SAndroid Build Coastguard Worker     }
152*5225e6b1SAndroid Build Coastguard Worker 
153*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance as a raw storage partition.
new_raw(mut disk: Disk<B, S>, name: &CStr) -> Result<Self, Error>154*5225e6b1SAndroid Build Coastguard Worker     pub fn new_raw(mut disk: Disk<B, S>, name: &CStr) -> Result<Self, Error> {
155*5225e6b1SAndroid Build Coastguard Worker         let info_cache = disk.io().info();
156*5225e6b1SAndroid Build Coastguard Worker         Ok(Self {
157*5225e6b1SAndroid Build Coastguard Worker             disk: (disk, Ok(())).into(),
158*5225e6b1SAndroid Build Coastguard Worker             info_cache,
159*5225e6b1SAndroid Build Coastguard Worker             partitions: PartitionTable::Raw(RawName::new(name)?, info_cache.total_size()?).into(),
160*5225e6b1SAndroid Build Coastguard Worker         })
161*5225e6b1SAndroid Build Coastguard Worker     }
162*5225e6b1SAndroid Build Coastguard Worker 
163*5225e6b1SAndroid Build Coastguard Worker     /// Gets the cached `BlockInfo`.
block_info(&self) -> BlockInfo164*5225e6b1SAndroid Build Coastguard Worker     pub fn block_info(&self) -> BlockInfo {
165*5225e6b1SAndroid Build Coastguard Worker         self.info_cache
166*5225e6b1SAndroid Build Coastguard Worker     }
167*5225e6b1SAndroid Build Coastguard Worker 
168*5225e6b1SAndroid Build Coastguard Worker     /// Gets the block status.
status(&self) -> BlockStatus169*5225e6b1SAndroid Build Coastguard Worker     pub fn status(&self) -> BlockStatus {
170*5225e6b1SAndroid Build Coastguard Worker         match self.disk.try_borrow_mut().ok() {
171*5225e6b1SAndroid Build Coastguard Worker             None => BlockStatus::Pending,
172*5225e6b1SAndroid Build Coastguard Worker             Some(v) if v.1.is_err() => BlockStatus::Error(v.1.unwrap_err()),
173*5225e6b1SAndroid Build Coastguard Worker             _ => BlockStatus::Idle,
174*5225e6b1SAndroid Build Coastguard Worker         }
175*5225e6b1SAndroid Build Coastguard Worker     }
176*5225e6b1SAndroid Build Coastguard Worker 
177*5225e6b1SAndroid Build Coastguard Worker     /// Borrows disk and last_err separately
get_disk_and_last_err( &self, ) -> Result<(RefMut<'_, Disk<B, S>>, RefMut<'_, Result<(), Error>>), Error>178*5225e6b1SAndroid Build Coastguard Worker     fn get_disk_and_last_err(
179*5225e6b1SAndroid Build Coastguard Worker         &self,
180*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<(RefMut<'_, Disk<B, S>>, RefMut<'_, Result<(), Error>>), Error> {
181*5225e6b1SAndroid Build Coastguard Worker         let res = self.disk.try_borrow_mut().map_err(|_| Error::NotReady)?;
182*5225e6b1SAndroid Build Coastguard Worker         Ok(RefMut::map_split(res, |v| (&mut v.0, &mut v.1)))
183*5225e6b1SAndroid Build Coastguard Worker     }
184*5225e6b1SAndroid Build Coastguard Worker 
185*5225e6b1SAndroid Build Coastguard Worker     /// Gets an instance of `PartitionIo` for a partition.
186*5225e6b1SAndroid Build Coastguard Worker     ///
187*5225e6b1SAndroid Build Coastguard Worker     /// If `part` is `None`, an IO for the whole block device is returned.
partition_io(&self, part: Option<&str>) -> Result<PartitionIo<'_, B>, Error>188*5225e6b1SAndroid Build Coastguard Worker     pub fn partition_io(&self, part: Option<&str>) -> Result<PartitionIo<'_, B>, Error> {
189*5225e6b1SAndroid Build Coastguard Worker         let (part_start, part_end) = self.find_partition(part)?.absolute_range()?;
190*5225e6b1SAndroid Build Coastguard Worker         let (disk, last_err) = self.get_disk_and_last_err()?;
191*5225e6b1SAndroid Build Coastguard Worker         Ok(PartitionIo { disk: Disk::from_ref_mut(disk), last_err, part_start, part_end })
192*5225e6b1SAndroid Build Coastguard Worker     }
193*5225e6b1SAndroid Build Coastguard Worker 
194*5225e6b1SAndroid Build Coastguard Worker     /// Finds a partition.
195*5225e6b1SAndroid Build Coastguard Worker     ///
196*5225e6b1SAndroid Build Coastguard Worker     /// * If `part` is none, the method returns an unnamed `Partition` that represents the whole
197*5225e6b1SAndroid Build Coastguard Worker     //    raw storage.
find_partition(&self, part: Option<&str>) -> Result<Partition, Error>198*5225e6b1SAndroid Build Coastguard Worker     pub fn find_partition(&self, part: Option<&str>) -> Result<Partition, Error> {
199*5225e6b1SAndroid Build Coastguard Worker         let Some(part) = part else {
200*5225e6b1SAndroid Build Coastguard Worker             return Ok(Partition::Raw(RawName::new(c"").unwrap(), self.info_cache.total_size()?));
201*5225e6b1SAndroid Build Coastguard Worker         };
202*5225e6b1SAndroid Build Coastguard Worker 
203*5225e6b1SAndroid Build Coastguard Worker         match self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?.deref() {
204*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(gpt) => Ok(Partition::Gpt(gpt.find_partition(part)?)),
205*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(name, size) if name.to_str() == part => {
206*5225e6b1SAndroid Build Coastguard Worker                 Ok(Partition::Raw(*name, *size))
207*5225e6b1SAndroid Build Coastguard Worker             }
208*5225e6b1SAndroid Build Coastguard Worker             _ => Err(Error::NotFound),
209*5225e6b1SAndroid Build Coastguard Worker         }
210*5225e6b1SAndroid Build Coastguard Worker     }
211*5225e6b1SAndroid Build Coastguard Worker 
212*5225e6b1SAndroid Build Coastguard Worker     /// Get total number of partitions.
num_partitions(&self) -> Result<usize, Error>213*5225e6b1SAndroid Build Coastguard Worker     pub fn num_partitions(&self) -> Result<usize, Error> {
214*5225e6b1SAndroid Build Coastguard Worker         match self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?.deref() {
215*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(_, _) => Ok(1),
216*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(gpt) => gpt.num_partitions(),
217*5225e6b1SAndroid Build Coastguard Worker         }
218*5225e6b1SAndroid Build Coastguard Worker     }
219*5225e6b1SAndroid Build Coastguard Worker 
220*5225e6b1SAndroid Build Coastguard Worker     /// Gets a partition by index.
get_partition_by_idx(&self, idx: usize) -> Result<Partition, Error>221*5225e6b1SAndroid Build Coastguard Worker     pub fn get_partition_by_idx(&self, idx: usize) -> Result<Partition, Error> {
222*5225e6b1SAndroid Build Coastguard Worker         match self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?.deref() {
223*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(name, v) if idx == 0 => Ok(Partition::Raw(*name, *v)),
224*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(gpt) => Ok(Partition::Gpt(gpt.get_partition(idx)?)),
225*5225e6b1SAndroid Build Coastguard Worker             _ => Err(Error::InvalidInput),
226*5225e6b1SAndroid Build Coastguard Worker         }
227*5225e6b1SAndroid Build Coastguard Worker     }
228*5225e6b1SAndroid Build Coastguard Worker 
229*5225e6b1SAndroid Build Coastguard Worker     /// Syncs GPT if the partition type is GPT.
230*5225e6b1SAndroid Build Coastguard Worker     ///
231*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
232*5225e6b1SAndroid Build Coastguard Worker     ///
233*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Ok(Some(sync_res))` if partition type is GPT and disk access is successful, where
234*5225e6b1SAndroid Build Coastguard Worker     ///  `sync_res` contains the GPT verification and restoration result.
235*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Ok(None)` if partition type is not GPT.
236*5225e6b1SAndroid Build Coastguard Worker     /// * Returns `Err` in other cases.
sync_gpt(&self) -> Result<Option<GptSyncResult>, Error>237*5225e6b1SAndroid Build Coastguard Worker     pub async fn sync_gpt(&self) -> Result<Option<GptSyncResult>, Error> {
238*5225e6b1SAndroid Build Coastguard Worker         match self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?.deref_mut() {
239*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(_, _) => Ok(None),
240*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(ref mut gpt) => {
241*5225e6b1SAndroid Build Coastguard Worker                 let mut blk = self.disk.try_borrow_mut().map_err(|_| Error::NotReady)?;
242*5225e6b1SAndroid Build Coastguard Worker                 Ok(Some(blk.0.sync_gpt(gpt).await?))
243*5225e6b1SAndroid Build Coastguard Worker             }
244*5225e6b1SAndroid Build Coastguard Worker         }
245*5225e6b1SAndroid Build Coastguard Worker     }
246*5225e6b1SAndroid Build Coastguard Worker 
247*5225e6b1SAndroid Build Coastguard Worker     /// Updates GPT to the block device and sync primary and secondary GPT.
248*5225e6b1SAndroid Build Coastguard Worker     ///
249*5225e6b1SAndroid Build Coastguard Worker     /// # Args
250*5225e6b1SAndroid Build Coastguard Worker     ///
251*5225e6b1SAndroid Build Coastguard Worker     /// * `mbr_primary`: A buffer containing the MBR block, primary GPT header and entries.
252*5225e6b1SAndroid Build Coastguard Worker     /// * `resize`: If set to true, the method updates the last partition to cover the rest of the
253*5225e6b1SAndroid Build Coastguard Worker     ///    storage.
254*5225e6b1SAndroid Build Coastguard Worker     ///
255*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
256*5225e6b1SAndroid Build Coastguard Worker     ///
257*5225e6b1SAndroid Build Coastguard Worker     /// * Return `Err(Error::NotReady)` if device is busy.
258*5225e6b1SAndroid Build Coastguard Worker     /// * Return `Err(Error::Unsupported)` if partition type is not GPT.
259*5225e6b1SAndroid Build Coastguard Worker     /// * Return `Ok(())` new GPT is valid and device is updated and synced successfully.
update_gpt(&self, mbr_primary: &mut [u8], resize: bool) -> Result<(), Error>260*5225e6b1SAndroid Build Coastguard Worker     pub async fn update_gpt(&self, mbr_primary: &mut [u8], resize: bool) -> Result<(), Error> {
261*5225e6b1SAndroid Build Coastguard Worker         match self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?.deref_mut() {
262*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(_, _) => Err(Error::Unsupported),
263*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(ref mut gpt) => {
264*5225e6b1SAndroid Build Coastguard Worker                 let mut blk = self.disk.try_borrow_mut().map_err(|_| Error::NotReady)?;
265*5225e6b1SAndroid Build Coastguard Worker                 blk.0.update_gpt(mbr_primary, resize, gpt).await
266*5225e6b1SAndroid Build Coastguard Worker             }
267*5225e6b1SAndroid Build Coastguard Worker         }
268*5225e6b1SAndroid Build Coastguard Worker     }
269*5225e6b1SAndroid Build Coastguard Worker 
270*5225e6b1SAndroid Build Coastguard Worker     /// Erases GPT on the disk.
271*5225e6b1SAndroid Build Coastguard Worker     ///
272*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
273*5225e6b1SAndroid Build Coastguard Worker     ///
274*5225e6b1SAndroid Build Coastguard Worker     /// * Return `Err(Error::NotReady)` if device is busy.
275*5225e6b1SAndroid Build Coastguard Worker     /// * Return `Err(Error::Unsupported)` if partition type is not GPT.
erase_gpt(&self) -> Result<(), Error>276*5225e6b1SAndroid Build Coastguard Worker     pub async fn erase_gpt(&self) -> Result<(), Error> {
277*5225e6b1SAndroid Build Coastguard Worker         match self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?.deref_mut() {
278*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(_, _) => Err(Error::Unsupported),
279*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(ref mut gpt) => {
280*5225e6b1SAndroid Build Coastguard Worker                 let mut disk = self.disk.try_borrow_mut().map_err(|_| Error::NotReady)?;
281*5225e6b1SAndroid Build Coastguard Worker                 disk.0.erase_gpt(gpt).await
282*5225e6b1SAndroid Build Coastguard Worker             }
283*5225e6b1SAndroid Build Coastguard Worker         }
284*5225e6b1SAndroid Build Coastguard Worker     }
285*5225e6b1SAndroid Build Coastguard Worker 
286*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of GptBuilder.
gpt_builder( &self, ) -> Result<GptBuilder<RefMut<'_, Disk<B, S>>, RefMut<'_, Gpt<T>>>, Error>287*5225e6b1SAndroid Build Coastguard Worker     pub fn gpt_builder(
288*5225e6b1SAndroid Build Coastguard Worker         &self,
289*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<GptBuilder<RefMut<'_, Disk<B, S>>, RefMut<'_, Gpt<T>>>, Error> {
290*5225e6b1SAndroid Build Coastguard Worker         let mut parts = self.partitions.try_borrow_mut().map_err(|_| Error::NotReady)?;
291*5225e6b1SAndroid Build Coastguard Worker         match parts.deref_mut() {
292*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Raw(_, _) => Err(Error::Unsupported),
293*5225e6b1SAndroid Build Coastguard Worker             PartitionTable::Gpt(_) => {
294*5225e6b1SAndroid Build Coastguard Worker                 let gpt = RefMut::map(parts, |v| match v {
295*5225e6b1SAndroid Build Coastguard Worker                     PartitionTable::Gpt(v) => v,
296*5225e6b1SAndroid Build Coastguard Worker                     _ => unreachable!(),
297*5225e6b1SAndroid Build Coastguard Worker                 });
298*5225e6b1SAndroid Build Coastguard Worker                 let (disk, err) = self.get_disk_and_last_err()?;
299*5225e6b1SAndroid Build Coastguard Worker                 (*err)?;
300*5225e6b1SAndroid Build Coastguard Worker                 Ok(GptBuilder::new(disk, gpt)?.0)
301*5225e6b1SAndroid Build Coastguard Worker             }
302*5225e6b1SAndroid Build Coastguard Worker         }
303*5225e6b1SAndroid Build Coastguard Worker     }
304*5225e6b1SAndroid Build Coastguard Worker }
305*5225e6b1SAndroid Build Coastguard Worker 
306*5225e6b1SAndroid Build Coastguard Worker /// `PartitionIo` provides read/write APIs to a partition.
307*5225e6b1SAndroid Build Coastguard Worker pub struct PartitionIo<'a, B: BlockIo> {
308*5225e6b1SAndroid Build Coastguard Worker     disk: Disk<RefMut<'a, B>, RefMut<'a, [u8]>>,
309*5225e6b1SAndroid Build Coastguard Worker     last_err: RefMut<'a, Result<(), Error>>,
310*5225e6b1SAndroid Build Coastguard Worker     part_start: u64,
311*5225e6b1SAndroid Build Coastguard Worker     part_end: u64,
312*5225e6b1SAndroid Build Coastguard Worker }
313*5225e6b1SAndroid Build Coastguard Worker 
314*5225e6b1SAndroid Build Coastguard Worker impl<'a, B: BlockIo> PartitionIo<'a, B> {
315*5225e6b1SAndroid Build Coastguard Worker     /// Returns the size of the partition.
size(&self) -> u64316*5225e6b1SAndroid Build Coastguard Worker     pub fn size(&self) -> u64 {
317*5225e6b1SAndroid Build Coastguard Worker         // Corrects by construction. Should not fail.
318*5225e6b1SAndroid Build Coastguard Worker         self.part_end.checked_sub(self.part_start).unwrap()
319*5225e6b1SAndroid Build Coastguard Worker     }
320*5225e6b1SAndroid Build Coastguard Worker 
321*5225e6b1SAndroid Build Coastguard Worker     /// Gets the block device.
dev(&mut self) -> &mut Disk<RefMut<'a, B>, RefMut<'a, [u8]>>322*5225e6b1SAndroid Build Coastguard Worker     pub fn dev(&mut self) -> &mut Disk<RefMut<'a, B>, RefMut<'a, [u8]>> {
323*5225e6b1SAndroid Build Coastguard Worker         &mut self.disk
324*5225e6b1SAndroid Build Coastguard Worker     }
325*5225e6b1SAndroid Build Coastguard Worker 
326*5225e6b1SAndroid Build Coastguard Worker     /// Checks the read/write parameters and returns the absolute offset in the block.
check_rw_range(&self, off: u64, size: impl Into<SafeNum>) -> Result<u64, Error>327*5225e6b1SAndroid Build Coastguard Worker     fn check_rw_range(&self, off: u64, size: impl Into<SafeNum>) -> Result<u64, Error> {
328*5225e6b1SAndroid Build Coastguard Worker         let ab_range_end = SafeNum::from(self.part_start) + off + size.into();
329*5225e6b1SAndroid Build Coastguard Worker         // Checks overflow by computing the difference between range end and partition end and
330*5225e6b1SAndroid Build Coastguard Worker         // making sure it succeeds.
331*5225e6b1SAndroid Build Coastguard Worker         let _end_diff: u64 = (SafeNum::from(self.part_end) - ab_range_end).try_into()?;
332*5225e6b1SAndroid Build Coastguard Worker         Ok((SafeNum::from(self.part_start) + off).try_into()?)
333*5225e6b1SAndroid Build Coastguard Worker     }
334*5225e6b1SAndroid Build Coastguard Worker 
335*5225e6b1SAndroid Build Coastguard Worker     /// Writes to the partition.
write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error>336*5225e6b1SAndroid Build Coastguard Worker     pub async fn write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error> {
337*5225e6b1SAndroid Build Coastguard Worker         let res =
338*5225e6b1SAndroid Build Coastguard Worker             async { self.disk.write(self.check_rw_range(off, data.len())?, data).await }.await;
339*5225e6b1SAndroid Build Coastguard Worker         *self.last_err = res.and(*self.last_err);
340*5225e6b1SAndroid Build Coastguard Worker         res
341*5225e6b1SAndroid Build Coastguard Worker     }
342*5225e6b1SAndroid Build Coastguard Worker 
343*5225e6b1SAndroid Build Coastguard Worker     /// Reads from the partition.
read( &mut self, off: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<(), Error>344*5225e6b1SAndroid Build Coastguard Worker     pub async fn read(
345*5225e6b1SAndroid Build Coastguard Worker         &mut self,
346*5225e6b1SAndroid Build Coastguard Worker         off: u64,
347*5225e6b1SAndroid Build Coastguard Worker         out: &mut (impl SliceMaybeUninit + ?Sized),
348*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<(), Error> {
349*5225e6b1SAndroid Build Coastguard Worker         let res = async { self.disk.read(self.check_rw_range(off, out.len())?, out).await }.await;
350*5225e6b1SAndroid Build Coastguard Worker         *self.last_err = res.and(*self.last_err);
351*5225e6b1SAndroid Build Coastguard Worker         res
352*5225e6b1SAndroid Build Coastguard Worker     }
353*5225e6b1SAndroid Build Coastguard Worker 
354*5225e6b1SAndroid Build Coastguard Worker     /// Writes zeroes to the partition.
zeroize(&mut self, scratch: &mut [u8]) -> Result<(), Error>355*5225e6b1SAndroid Build Coastguard Worker     pub async fn zeroize(&mut self, scratch: &mut [u8]) -> Result<(), Error> {
356*5225e6b1SAndroid Build Coastguard Worker         let res = async { self.disk.fill(self.part_start, self.size(), 0, scratch).await }.await;
357*5225e6b1SAndroid Build Coastguard Worker         *self.last_err = res.and(*self.last_err);
358*5225e6b1SAndroid Build Coastguard Worker         *self.last_err
359*5225e6b1SAndroid Build Coastguard Worker     }
360*5225e6b1SAndroid Build Coastguard Worker 
361*5225e6b1SAndroid Build Coastguard Worker     /// Writes sparse image to the partition.
write_sparse(&mut self, off: u64, img: &mut [u8]) -> Result<(), Error>362*5225e6b1SAndroid Build Coastguard Worker     pub async fn write_sparse(&mut self, off: u64, img: &mut [u8]) -> Result<(), Error> {
363*5225e6b1SAndroid Build Coastguard Worker         let res = async {
364*5225e6b1SAndroid Build Coastguard Worker             let sz = is_sparse_image(img).map_err(|_| Error::InvalidInput)?.data_size();
365*5225e6b1SAndroid Build Coastguard Worker             write_sparse_image(img, &mut (self.check_rw_range(off, sz)?, &mut self.disk)).await
366*5225e6b1SAndroid Build Coastguard Worker         }
367*5225e6b1SAndroid Build Coastguard Worker         .await;
368*5225e6b1SAndroid Build Coastguard Worker         *self.last_err = res.map(|_| ()).and(*self.last_err);
369*5225e6b1SAndroid Build Coastguard Worker         *self.last_err
370*5225e6b1SAndroid Build Coastguard Worker     }
371*5225e6b1SAndroid Build Coastguard Worker 
372*5225e6b1SAndroid Build Coastguard Worker     /// Turns this IO into one for a subrange in the partition.
sub(self, off: u64, sz: u64) -> Result<Self, Error>373*5225e6b1SAndroid Build Coastguard Worker     pub fn sub(self, off: u64, sz: u64) -> Result<Self, Error> {
374*5225e6b1SAndroid Build Coastguard Worker         self.check_rw_range(off, sz)?;
375*5225e6b1SAndroid Build Coastguard Worker         let mut sub = self;
376*5225e6b1SAndroid Build Coastguard Worker         sub.part_start += off;
377*5225e6b1SAndroid Build Coastguard Worker         sub.part_end = sub.part_start + sz;
378*5225e6b1SAndroid Build Coastguard Worker         Ok(sub)
379*5225e6b1SAndroid Build Coastguard Worker     }
380*5225e6b1SAndroid Build Coastguard Worker 
381*5225e6b1SAndroid Build Coastguard Worker     /// Returns the most recent error.
last_err(&self) -> Result<(), Error>382*5225e6b1SAndroid Build Coastguard Worker     pub fn last_err(&self) -> Result<(), Error> {
383*5225e6b1SAndroid Build Coastguard Worker         *self.last_err
384*5225e6b1SAndroid Build Coastguard Worker     }
385*5225e6b1SAndroid Build Coastguard Worker 
386*5225e6b1SAndroid Build Coastguard Worker     /// Takes the error and resets it.
take_err(&mut self) -> Result<(), Error>387*5225e6b1SAndroid Build Coastguard Worker     pub fn take_err(&mut self) -> Result<(), Error> {
388*5225e6b1SAndroid Build Coastguard Worker         let mut err = Ok(());
389*5225e6b1SAndroid Build Coastguard Worker         swap(&mut self.last_err as _, &mut err);
390*5225e6b1SAndroid Build Coastguard Worker         err
391*5225e6b1SAndroid Build Coastguard Worker     }
392*5225e6b1SAndroid Build Coastguard Worker }
393*5225e6b1SAndroid Build Coastguard Worker 
394*5225e6b1SAndroid Build Coastguard Worker // Implements `SparseRawWriter` for tuple (<flash offset>, <block device>)
395*5225e6b1SAndroid Build Coastguard Worker impl<B, S> SparseRawWriter for (u64, &mut Disk<B, S>)
396*5225e6b1SAndroid Build Coastguard Worker where
397*5225e6b1SAndroid Build Coastguard Worker     B: BlockIo,
398*5225e6b1SAndroid Build Coastguard Worker     S: DerefMut<Target = [u8]>,
399*5225e6b1SAndroid Build Coastguard Worker {
write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error>400*5225e6b1SAndroid Build Coastguard Worker     async fn write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error> {
401*5225e6b1SAndroid Build Coastguard Worker         Ok(self.1.write((SafeNum::from(off) + self.0).try_into()?, data).await?)
402*5225e6b1SAndroid Build Coastguard Worker     }
403*5225e6b1SAndroid Build Coastguard Worker }
404*5225e6b1SAndroid Build Coastguard Worker 
405*5225e6b1SAndroid Build Coastguard Worker /// Checks that a partition is unique.
406*5225e6b1SAndroid Build Coastguard Worker ///
407*5225e6b1SAndroid Build Coastguard Worker /// Returns a pair `(<block device index>, `Partition`)` if the partition exists and is unique.
check_part_unique( devs: &'_ [GblDisk< Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, Gpt<impl DerefMut<Target = [u8]>>, >], part: &str, ) -> Result<(usize, Partition), Error>408*5225e6b1SAndroid Build Coastguard Worker pub fn check_part_unique(
409*5225e6b1SAndroid Build Coastguard Worker     devs: &'_ [GblDisk<
410*5225e6b1SAndroid Build Coastguard Worker         Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
411*5225e6b1SAndroid Build Coastguard Worker         Gpt<impl DerefMut<Target = [u8]>>,
412*5225e6b1SAndroid Build Coastguard Worker     >],
413*5225e6b1SAndroid Build Coastguard Worker     part: &str,
414*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(usize, Partition), Error> {
415*5225e6b1SAndroid Build Coastguard Worker     let mut filtered = devs
416*5225e6b1SAndroid Build Coastguard Worker         .iter()
417*5225e6b1SAndroid Build Coastguard Worker         .enumerate()
418*5225e6b1SAndroid Build Coastguard Worker         .filter_map(|(i, v)| v.find_partition(Some(part)).ok().map(|v| (i, v)));
419*5225e6b1SAndroid Build Coastguard Worker     match (filtered.next(), filtered.next()) {
420*5225e6b1SAndroid Build Coastguard Worker         (Some(v), None) => Ok(v),
421*5225e6b1SAndroid Build Coastguard Worker         (Some(_), Some(_)) => Err(Error::NotUnique),
422*5225e6b1SAndroid Build Coastguard Worker         _ => Err(Error::NotFound),
423*5225e6b1SAndroid Build Coastguard Worker     }
424*5225e6b1SAndroid Build Coastguard Worker }
425*5225e6b1SAndroid Build Coastguard Worker 
426*5225e6b1SAndroid Build Coastguard Worker /// Checks that a partition is unique among all block devices and reads from it.
read_unique_partition( devs: &'_ [GblDisk< Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, Gpt<impl DerefMut<Target = [u8]>>, >], part: &str, off: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<(), Error>427*5225e6b1SAndroid Build Coastguard Worker pub async fn read_unique_partition(
428*5225e6b1SAndroid Build Coastguard Worker     devs: &'_ [GblDisk<
429*5225e6b1SAndroid Build Coastguard Worker         Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
430*5225e6b1SAndroid Build Coastguard Worker         Gpt<impl DerefMut<Target = [u8]>>,
431*5225e6b1SAndroid Build Coastguard Worker     >],
432*5225e6b1SAndroid Build Coastguard Worker     part: &str,
433*5225e6b1SAndroid Build Coastguard Worker     off: u64,
434*5225e6b1SAndroid Build Coastguard Worker     out: &mut (impl SliceMaybeUninit + ?Sized),
435*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(), Error> {
436*5225e6b1SAndroid Build Coastguard Worker     devs[check_part_unique(devs, part)?.0].partition_io(Some(part))?.read(off, out).await
437*5225e6b1SAndroid Build Coastguard Worker }
438*5225e6b1SAndroid Build Coastguard Worker 
439*5225e6b1SAndroid Build Coastguard Worker /// Checks that a partition is unique among all block devices and writes to it.
write_unique_partition( devs: &'_ [GblDisk< Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, Gpt<impl DerefMut<Target = [u8]>>, >], part: &str, off: u64, data: &mut [u8], ) -> Result<(), Error>440*5225e6b1SAndroid Build Coastguard Worker pub async fn write_unique_partition(
441*5225e6b1SAndroid Build Coastguard Worker     devs: &'_ [GblDisk<
442*5225e6b1SAndroid Build Coastguard Worker         Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
443*5225e6b1SAndroid Build Coastguard Worker         Gpt<impl DerefMut<Target = [u8]>>,
444*5225e6b1SAndroid Build Coastguard Worker     >],
445*5225e6b1SAndroid Build Coastguard Worker     part: &str,
446*5225e6b1SAndroid Build Coastguard Worker     off: u64,
447*5225e6b1SAndroid Build Coastguard Worker     data: &mut [u8],
448*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(), Error> {
449*5225e6b1SAndroid Build Coastguard Worker     devs[check_part_unique(devs, part)?.0].partition_io(Some(part))?.write(off, data).await
450*5225e6b1SAndroid Build Coastguard Worker }
451*5225e6b1SAndroid Build Coastguard Worker 
452*5225e6b1SAndroid Build Coastguard Worker /// Syncs all GPT type partition devices.
sync_gpt( devs: &'_ [GblDisk< Disk<impl BlockIo, impl DerefMut<Target = [u8]>>, Gpt<impl DerefMut<Target = [u8]>>, >], ) -> Result<(), Error>453*5225e6b1SAndroid Build Coastguard Worker pub async fn sync_gpt(
454*5225e6b1SAndroid Build Coastguard Worker     devs: &'_ [GblDisk<
455*5225e6b1SAndroid Build Coastguard Worker         Disk<impl BlockIo, impl DerefMut<Target = [u8]>>,
456*5225e6b1SAndroid Build Coastguard Worker         Gpt<impl DerefMut<Target = [u8]>>,
457*5225e6b1SAndroid Build Coastguard Worker     >],
458*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(), Error> {
459*5225e6b1SAndroid Build Coastguard Worker     for ele in &devs[..] {
460*5225e6b1SAndroid Build Coastguard Worker         ele.sync_gpt().await?;
461*5225e6b1SAndroid Build Coastguard Worker     }
462*5225e6b1SAndroid Build Coastguard Worker     Ok(())
463*5225e6b1SAndroid Build Coastguard Worker }
464*5225e6b1SAndroid Build Coastguard Worker 
465*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
466*5225e6b1SAndroid Build Coastguard Worker pub(crate) mod test {
467*5225e6b1SAndroid Build Coastguard Worker     use super::*;
468*5225e6b1SAndroid Build Coastguard Worker     use crate::ops::test::{FakeGblOpsStorage, TestGblDisk};
469*5225e6b1SAndroid Build Coastguard Worker     use core::fmt::Debug;
470*5225e6b1SAndroid Build Coastguard Worker     use gbl_async::block_on;
471*5225e6b1SAndroid Build Coastguard Worker 
472*5225e6b1SAndroid Build Coastguard Worker     /// Absolute start/end offset and size of "boot_a/b" partitions in
473*5225e6b1SAndroid Build Coastguard Worker     /// "../../libstorage/test/gpt_test_1.bin"
474*5225e6b1SAndroid Build Coastguard Worker     const BOOT_A_OFF: u64 = 17 * 1024;
475*5225e6b1SAndroid Build Coastguard Worker     const BOOT_A_END: u64 = 25 * 1024;
476*5225e6b1SAndroid Build Coastguard Worker     const BOOT_A_SZ: u64 = BOOT_A_END - BOOT_A_OFF;
477*5225e6b1SAndroid Build Coastguard Worker     const BOOT_B_OFF: u64 = 25 * 1024;
478*5225e6b1SAndroid Build Coastguard Worker     const BOOT_B_END: u64 = 37 * 1024;
479*5225e6b1SAndroid Build Coastguard Worker     const BOOT_B_SZ: u64 = BOOT_B_END - BOOT_B_OFF;
480*5225e6b1SAndroid Build Coastguard Worker     /// Total size of disk "../../libstorage/test/gpt_test_1.bin"
481*5225e6b1SAndroid Build Coastguard Worker     const GPT_DISK_1_SZ: u64 = 64 * 1024;
482*5225e6b1SAndroid Build Coastguard Worker 
483*5225e6b1SAndroid Build Coastguard Worker     /// A helper to convert an integer into usize and panics on error.
to_usize(val: impl TryInto<usize, Error = impl Debug>) -> usize484*5225e6b1SAndroid Build Coastguard Worker     fn to_usize(val: impl TryInto<usize, Error = impl Debug>) -> usize {
485*5225e6b1SAndroid Build Coastguard Worker         val.try_into().unwrap()
486*5225e6b1SAndroid Build Coastguard Worker     }
487*5225e6b1SAndroid Build Coastguard Worker 
488*5225e6b1SAndroid Build Coastguard Worker     /// A helper to create a GPT type TestGblDisk
gpt_disk(data: impl AsRef<[u8]>) -> TestGblDisk489*5225e6b1SAndroid Build Coastguard Worker     fn gpt_disk(data: impl AsRef<[u8]>) -> TestGblDisk {
490*5225e6b1SAndroid Build Coastguard Worker         let mut res = FakeGblOpsStorage::default();
491*5225e6b1SAndroid Build Coastguard Worker         res.add_gpt_device(data);
492*5225e6b1SAndroid Build Coastguard Worker         res.0.pop().unwrap()
493*5225e6b1SAndroid Build Coastguard Worker     }
494*5225e6b1SAndroid Build Coastguard Worker 
495*5225e6b1SAndroid Build Coastguard Worker     /// A helper to create a raw disk partition type TestGblDisk
raw_disk(name: &CStr, data: impl AsRef<[u8]>) -> TestGblDisk496*5225e6b1SAndroid Build Coastguard Worker     fn raw_disk(name: &CStr, data: impl AsRef<[u8]>) -> TestGblDisk {
497*5225e6b1SAndroid Build Coastguard Worker         let mut res = FakeGblOpsStorage::default();
498*5225e6b1SAndroid Build Coastguard Worker         res.add_raw_device(name, data);
499*5225e6b1SAndroid Build Coastguard Worker         res.0.pop().unwrap()
500*5225e6b1SAndroid Build Coastguard Worker     }
501*5225e6b1SAndroid Build Coastguard Worker 
502*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_find_partition_gpt()503*5225e6b1SAndroid Build Coastguard Worker     fn test_find_partition_gpt() {
504*5225e6b1SAndroid Build Coastguard Worker         let gpt = gpt_disk(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
505*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(gpt.sync_gpt()).unwrap(), Some(GptSyncResult::BothValid));
506*5225e6b1SAndroid Build Coastguard Worker 
507*5225e6b1SAndroid Build Coastguard Worker         let boot_a = gpt.find_partition(Some("boot_a")).unwrap();
508*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(boot_a.name().unwrap(), "boot_a");
509*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(boot_a.size().unwrap(), BOOT_A_SZ);
510*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(boot_a.absolute_range().unwrap(), (BOOT_A_OFF, BOOT_A_END));
511*5225e6b1SAndroid Build Coastguard Worker 
512*5225e6b1SAndroid Build Coastguard Worker         let boot_b = gpt.find_partition(Some("boot_b")).unwrap();
513*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(boot_b.name().unwrap(), "boot_b");
514*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(boot_b.size().unwrap(), BOOT_B_SZ);
515*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(boot_b.absolute_range().unwrap(), (BOOT_B_OFF, BOOT_B_END));
516*5225e6b1SAndroid Build Coastguard Worker 
517*5225e6b1SAndroid Build Coastguard Worker         let unnamed_whole = gpt.find_partition(None).unwrap();
518*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(unnamed_whole.name().unwrap(), "");
519*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(unnamed_whole.size().unwrap(), GPT_DISK_1_SZ);
520*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(unnamed_whole.absolute_range().unwrap(), (0, GPT_DISK_1_SZ));
521*5225e6b1SAndroid Build Coastguard Worker 
522*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.find_partition(Some("not-exist")).is_err());
523*5225e6b1SAndroid Build Coastguard Worker     }
524*5225e6b1SAndroid Build Coastguard Worker 
525*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_find_partition_raw()526*5225e6b1SAndroid Build Coastguard Worker     fn test_find_partition_raw() {
527*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../libstorage/test/gpt_test_1.bin");
528*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", &disk);
529*5225e6b1SAndroid Build Coastguard Worker 
530*5225e6b1SAndroid Build Coastguard Worker         let raw_part = raw.find_partition(Some("raw")).unwrap();
531*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(raw_part.name().unwrap(), "raw");
532*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(raw_part.size().unwrap(), GPT_DISK_1_SZ);
533*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(raw_part.absolute_range().unwrap(), (0, GPT_DISK_1_SZ));
534*5225e6b1SAndroid Build Coastguard Worker 
535*5225e6b1SAndroid Build Coastguard Worker         let unnamed_whole = raw.find_partition(None).unwrap();
536*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(unnamed_whole.name().unwrap(), "");
537*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(unnamed_whole.size().unwrap(), GPT_DISK_1_SZ);
538*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(unnamed_whole.absolute_range().unwrap(), (0, GPT_DISK_1_SZ));
539*5225e6b1SAndroid Build Coastguard Worker 
540*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.find_partition(Some("boot_a")).is_err());
541*5225e6b1SAndroid Build Coastguard Worker     }
542*5225e6b1SAndroid Build Coastguard Worker 
543*5225e6b1SAndroid Build Coastguard Worker     /// A helper for testing partition read.
544*5225e6b1SAndroid Build Coastguard Worker     ///
545*5225e6b1SAndroid Build Coastguard Worker     /// Tests that the content read at `off..off+sz` is the same as `part_content[off..off+sz]`.
test_part_read( blk: &TestGblDisk, part: Option<&str>, part_content: &[u8], off: u64, sz: u64, )546*5225e6b1SAndroid Build Coastguard Worker     fn test_part_read(
547*5225e6b1SAndroid Build Coastguard Worker         blk: &TestGblDisk,
548*5225e6b1SAndroid Build Coastguard Worker         part: Option<&str>,
549*5225e6b1SAndroid Build Coastguard Worker         part_content: &[u8],
550*5225e6b1SAndroid Build Coastguard Worker         off: u64,
551*5225e6b1SAndroid Build Coastguard Worker         sz: u64,
552*5225e6b1SAndroid Build Coastguard Worker     ) {
553*5225e6b1SAndroid Build Coastguard Worker         let mut out = vec![0u8; to_usize(sz)];
554*5225e6b1SAndroid Build Coastguard Worker         block_on(blk.partition_io(part).unwrap().read(off, &mut out[..])).unwrap();
555*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(out, part_content[to_usize(off)..][..out.len()].to_vec());
556*5225e6b1SAndroid Build Coastguard Worker 
557*5225e6b1SAndroid Build Coastguard Worker         // Reads using the `sub()` and then read approach.
558*5225e6b1SAndroid Build Coastguard Worker         let mut out = vec![0u8; to_usize(sz)];
559*5225e6b1SAndroid Build Coastguard Worker         let mut io = blk.partition_io(part).unwrap().sub(off, sz).unwrap();
560*5225e6b1SAndroid Build Coastguard Worker         block_on(io.read(0, &mut out[..])).unwrap();
561*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(out, part_content[to_usize(off)..][..out.len()].to_vec());
562*5225e6b1SAndroid Build Coastguard Worker     }
563*5225e6b1SAndroid Build Coastguard Worker 
564*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_read_partition_gpt()565*5225e6b1SAndroid Build Coastguard Worker     fn test_read_partition_gpt() {
566*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../libstorage/test/gpt_test_1.bin");
567*5225e6b1SAndroid Build Coastguard Worker         let gpt = gpt_disk(&disk[..]);
568*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(gpt.sync_gpt()).unwrap(), Some(GptSyncResult::BothValid));
569*5225e6b1SAndroid Build Coastguard Worker 
570*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_a = include_bytes!("../../libstorage/test/boot_a.bin");
571*5225e6b1SAndroid Build Coastguard Worker         test_part_read(&gpt, Some("boot_a"), expect_boot_a, 1, 1024);
572*5225e6b1SAndroid Build Coastguard Worker         let expect_boot_b = include_bytes!("../../libstorage/test/boot_b.bin");
573*5225e6b1SAndroid Build Coastguard Worker         test_part_read(&gpt, Some("boot_b"), expect_boot_b, 1, 1024);
574*5225e6b1SAndroid Build Coastguard Worker         // Whole block read.
575*5225e6b1SAndroid Build Coastguard Worker         test_part_read(&gpt, None, disk, 1, 1024);
576*5225e6b1SAndroid Build Coastguard Worker     }
577*5225e6b1SAndroid Build Coastguard Worker 
578*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_read_partition_raw()579*5225e6b1SAndroid Build Coastguard Worker     fn test_read_partition_raw() {
580*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../libstorage/test/gpt_test_1.bin");
581*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", &disk);
582*5225e6b1SAndroid Build Coastguard Worker         test_part_read(&raw, Some("raw"), disk, 1, 1024);
583*5225e6b1SAndroid Build Coastguard Worker         test_part_read(&raw, None, disk, 1, 1024);
584*5225e6b1SAndroid Build Coastguard Worker     }
585*5225e6b1SAndroid Build Coastguard Worker 
586*5225e6b1SAndroid Build Coastguard Worker     /// A helper for testing partition write.
test_part_write(blk: &TestGblDisk, part: Option<&str>, off: u64, sz: u64)587*5225e6b1SAndroid Build Coastguard Worker     fn test_part_write(blk: &TestGblDisk, part: Option<&str>, off: u64, sz: u64) {
588*5225e6b1SAndroid Build Coastguard Worker         // Reads the current partition content
589*5225e6b1SAndroid Build Coastguard Worker         let mut part_content = vec![0u8; to_usize(blk.partition_io(part).unwrap().size())];
590*5225e6b1SAndroid Build Coastguard Worker         block_on(blk.partition_io(part).unwrap().read(0, &mut part_content[..])).unwrap();
591*5225e6b1SAndroid Build Coastguard Worker 
592*5225e6b1SAndroid Build Coastguard Worker         // Flips all the bits in the target range and writes back.
593*5225e6b1SAndroid Build Coastguard Worker         let seg = &mut part_content[to_usize(off)..][..to_usize(sz)];
594*5225e6b1SAndroid Build Coastguard Worker         seg.iter_mut().for_each(|v| *v = !(*v));
595*5225e6b1SAndroid Build Coastguard Worker         block_on(blk.partition_io(part).unwrap().write(off, seg)).unwrap();
596*5225e6b1SAndroid Build Coastguard Worker         // Checks that data is written.
597*5225e6b1SAndroid Build Coastguard Worker         test_part_read(blk, part, &part_content, off, sz);
598*5225e6b1SAndroid Build Coastguard Worker 
599*5225e6b1SAndroid Build Coastguard Worker         // Writes using the `sub()` and then write approach.
600*5225e6b1SAndroid Build Coastguard Worker         let seg = &mut part_content[to_usize(off)..][..to_usize(sz)];
601*5225e6b1SAndroid Build Coastguard Worker         seg.iter_mut().for_each(|v| *v = !(*v));
602*5225e6b1SAndroid Build Coastguard Worker         block_on(blk.partition_io(part).unwrap().sub(off, sz).unwrap().write(0, seg)).unwrap();
603*5225e6b1SAndroid Build Coastguard Worker         test_part_read(blk, part, &part_content, off, sz);
604*5225e6b1SAndroid Build Coastguard Worker     }
605*5225e6b1SAndroid Build Coastguard Worker 
606*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_partition_gpt()607*5225e6b1SAndroid Build Coastguard Worker     fn test_write_partition_gpt() {
608*5225e6b1SAndroid Build Coastguard Worker         let gpt = gpt_disk(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
609*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(gpt.sync_gpt()).unwrap(), Some(GptSyncResult::BothValid));
610*5225e6b1SAndroid Build Coastguard Worker         test_part_write(&gpt, Some("boot_a"), 1, 1024);
611*5225e6b1SAndroid Build Coastguard Worker         test_part_write(&gpt, Some("boot_b"), 1, 1024);
612*5225e6b1SAndroid Build Coastguard Worker         test_part_write(&gpt, None, 1, 1024);
613*5225e6b1SAndroid Build Coastguard Worker     }
614*5225e6b1SAndroid Build Coastguard Worker 
615*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_partition_raw()616*5225e6b1SAndroid Build Coastguard Worker     fn test_write_partition_raw() {
617*5225e6b1SAndroid Build Coastguard Worker         let mut raw = raw_disk(c"raw", include_bytes!("../../libstorage/test/gpt_test_1.bin"));
618*5225e6b1SAndroid Build Coastguard Worker         test_part_write(&mut raw, Some("raw"), 1, 1024);
619*5225e6b1SAndroid Build Coastguard Worker         test_part_write(&mut raw, None, 1, 1024);
620*5225e6b1SAndroid Build Coastguard Worker     }
621*5225e6b1SAndroid Build Coastguard Worker 
622*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_read_write_partition_overflow()623*5225e6b1SAndroid Build Coastguard Worker     fn test_read_write_partition_overflow() {
624*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../libstorage/test/gpt_test_1.bin");
625*5225e6b1SAndroid Build Coastguard Worker         let gpt = gpt_disk(&disk[..]);
626*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(gpt.sync_gpt()).unwrap(), Some(GptSyncResult::BothValid));
627*5225e6b1SAndroid Build Coastguard Worker 
628*5225e6b1SAndroid Build Coastguard Worker         let mut part_io = gpt.partition_io(Some("boot_a")).unwrap();
629*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.read(BOOT_A_END, &mut vec![0u8; 1][..])).is_err());
630*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.read(BOOT_A_OFF, &mut vec![0u8; to_usize(BOOT_A_SZ) + 1][..]))
631*5225e6b1SAndroid Build Coastguard Worker             .is_err());
632*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.write(BOOT_A_END, &mut vec![0u8; 1][..])).is_err());
633*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.write(BOOT_A_OFF, &mut vec![0u8; to_usize(BOOT_A_SZ) + 1][..]))
634*5225e6b1SAndroid Build Coastguard Worker             .is_err());
635*5225e6b1SAndroid Build Coastguard Worker 
636*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", &disk);
637*5225e6b1SAndroid Build Coastguard Worker         let mut part_io = raw.partition_io(Some("raw")).unwrap();
638*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.read(GPT_DISK_1_SZ, &mut vec![0u8; 1][..])).is_err());
639*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.read(0, &mut vec![0u8; to_usize(GPT_DISK_1_SZ) + 1][..])).is_err());
640*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.write(GPT_DISK_1_SZ, &mut vec![0u8; 1][..])).is_err());
641*5225e6b1SAndroid Build Coastguard Worker         assert!(
642*5225e6b1SAndroid Build Coastguard Worker             block_on(part_io.write(0, &mut vec![0u8; to_usize(GPT_DISK_1_SZ) + 1][..])).is_err()
643*5225e6b1SAndroid Build Coastguard Worker         );
644*5225e6b1SAndroid Build Coastguard Worker     }
645*5225e6b1SAndroid Build Coastguard Worker 
646*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_sub_overflow()647*5225e6b1SAndroid Build Coastguard Worker     fn test_sub_overflow() {
648*5225e6b1SAndroid Build Coastguard Worker         let disk = include_bytes!("../../libstorage/test/gpt_test_1.bin");
649*5225e6b1SAndroid Build Coastguard Worker         let gpt = gpt_disk(&disk[..]);
650*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(block_on(gpt.sync_gpt()).unwrap(), Some(GptSyncResult::BothValid));
651*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.partition_io(Some("boot_a")).unwrap().sub(0, BOOT_A_SZ + 1).is_err());
652*5225e6b1SAndroid Build Coastguard Worker         assert!(gpt.partition_io(Some("boot_a")).unwrap().sub(1, BOOT_A_SZ).is_err());
653*5225e6b1SAndroid Build Coastguard Worker 
654*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", &disk);
655*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().sub(0, GPT_DISK_1_SZ + 1).is_err());
656*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().sub(1, GPT_DISK_1_SZ).is_err());
657*5225e6b1SAndroid Build Coastguard Worker     }
658*5225e6b1SAndroid Build Coastguard Worker 
659*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_sparse()660*5225e6b1SAndroid Build Coastguard Worker     fn test_write_sparse() {
661*5225e6b1SAndroid Build Coastguard Worker         let sparse_raw = include_bytes!("../testdata/sparse_test_raw.bin");
662*5225e6b1SAndroid Build Coastguard Worker         let mut sparse = include_bytes!("../testdata/sparse_test.bin").to_vec();
663*5225e6b1SAndroid Build Coastguard Worker         let raw = &vec![0u8; sparse_raw.len() + 512][..];
664*5225e6b1SAndroid Build Coastguard Worker         let blk = raw_disk(c"raw", raw);
665*5225e6b1SAndroid Build Coastguard Worker         block_on(
666*5225e6b1SAndroid Build Coastguard Worker             blk.partition_io(Some("raw"))
667*5225e6b1SAndroid Build Coastguard Worker                 .unwrap()
668*5225e6b1SAndroid Build Coastguard Worker                 .sub(1, u64::try_from(raw.len() - 1).unwrap())
669*5225e6b1SAndroid Build Coastguard Worker                 .unwrap()
670*5225e6b1SAndroid Build Coastguard Worker                 .write_sparse(1, &mut sparse),
671*5225e6b1SAndroid Build Coastguard Worker         )
672*5225e6b1SAndroid Build Coastguard Worker         .unwrap();
673*5225e6b1SAndroid Build Coastguard Worker         let mut expected = vec![0u8; raw.len()];
674*5225e6b1SAndroid Build Coastguard Worker         expected[1 + 1..][..sparse_raw.len()].clone_from_slice(sparse_raw);
675*5225e6b1SAndroid Build Coastguard Worker         test_part_read(&blk, Some("raw"), &expected, 1, sparse_raw.len().try_into().unwrap());
676*5225e6b1SAndroid Build Coastguard Worker     }
677*5225e6b1SAndroid Build Coastguard Worker 
678*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_sparse_not_sparse_image()679*5225e6b1SAndroid Build Coastguard Worker     fn test_write_sparse_not_sparse_image() {
680*5225e6b1SAndroid Build Coastguard Worker         let sparse_raw = include_bytes!("../testdata/sparse_test_raw.bin");
681*5225e6b1SAndroid Build Coastguard Worker         let mut sparse = include_bytes!("../testdata/sparse_test.bin").to_vec();
682*5225e6b1SAndroid Build Coastguard Worker         sparse[0] = !sparse[0]; // Corrupt image.
683*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", vec![0u8; sparse_raw.len() + 512]);
684*5225e6b1SAndroid Build Coastguard Worker         assert!(
685*5225e6b1SAndroid Build Coastguard Worker             block_on(raw.partition_io(Some("raw")).unwrap().write_sparse(1, &mut sparse)).is_err()
686*5225e6b1SAndroid Build Coastguard Worker         );
687*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().last_err().is_err());
688*5225e6b1SAndroid Build Coastguard Worker     }
689*5225e6b1SAndroid Build Coastguard Worker 
690*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_sparse_overflow_size()691*5225e6b1SAndroid Build Coastguard Worker     fn test_write_sparse_overflow_size() {
692*5225e6b1SAndroid Build Coastguard Worker         let sparse_raw = include_bytes!("../testdata/sparse_test_raw.bin");
693*5225e6b1SAndroid Build Coastguard Worker         let mut sparse = include_bytes!("../testdata/sparse_test.bin").to_vec();
694*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", vec![0u8; sparse_raw.len()]);
695*5225e6b1SAndroid Build Coastguard Worker         assert!(
696*5225e6b1SAndroid Build Coastguard Worker             block_on(raw.partition_io(Some("raw")).unwrap().write_sparse(1, &mut sparse)).is_err()
697*5225e6b1SAndroid Build Coastguard Worker         );
698*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().last_err().is_err());
699*5225e6b1SAndroid Build Coastguard Worker     }
700*5225e6b1SAndroid Build Coastguard Worker 
701*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_partiton_last_err_read()702*5225e6b1SAndroid Build Coastguard Worker     fn test_partiton_last_err_read() {
703*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", vec![0u8; 1024]);
704*5225e6b1SAndroid Build Coastguard Worker         let mut part_io = raw.partition_io(Some("raw")).unwrap();
705*5225e6b1SAndroid Build Coastguard Worker         // Causes some error by read
706*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.read(1024, &mut [0][..])).is_err());
707*5225e6b1SAndroid Build Coastguard Worker         assert!(part_io.last_err().is_err());
708*5225e6b1SAndroid Build Coastguard Worker     }
709*5225e6b1SAndroid Build Coastguard Worker 
710*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_partiton_last_err_write()711*5225e6b1SAndroid Build Coastguard Worker     fn test_partiton_last_err_write() {
712*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", vec![0u8; 1024]);
713*5225e6b1SAndroid Build Coastguard Worker         let mut part_io = raw.partition_io(Some("raw")).unwrap();
714*5225e6b1SAndroid Build Coastguard Worker         // Causes some error by write
715*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(part_io.write(1024, &mut [0])).is_err());
716*5225e6b1SAndroid Build Coastguard Worker         assert!(part_io.last_err().is_err());
717*5225e6b1SAndroid Build Coastguard Worker     }
718*5225e6b1SAndroid Build Coastguard Worker 
719*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_partiton_last_err_persist_through_operation()720*5225e6b1SAndroid Build Coastguard Worker     fn test_partiton_last_err_persist_through_operation() {
721*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", vec![0u8; 1024]);
722*5225e6b1SAndroid Build Coastguard Worker         // Causes some error by read
723*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(raw.partition_io(Some("raw")).unwrap().read(1024, &mut [0][..])).is_err());
724*5225e6b1SAndroid Build Coastguard Worker         // Tracked error should persist regardless of how many times we get partition io.
725*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().last_err().is_err());
726*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(None).unwrap().last_err().is_err());
727*5225e6b1SAndroid Build Coastguard Worker         // Should persist even after successful operations.
728*5225e6b1SAndroid Build Coastguard Worker         block_on(raw.partition_io(Some("raw")).unwrap().read(1023, &mut [0][..])).unwrap();
729*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().last_err().is_err());
730*5225e6b1SAndroid Build Coastguard Worker         block_on(raw.partition_io(Some("raw")).unwrap().write(1023, &mut [0][..])).unwrap();
731*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(Some("raw")).unwrap().last_err().is_err());
732*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(None).unwrap().last_err().is_err());
733*5225e6b1SAndroid Build Coastguard Worker         // Taking error should reset it.
734*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(None).unwrap().take_err().is_err());
735*5225e6b1SAndroid Build Coastguard Worker         assert!(raw.partition_io(None).unwrap().last_err().is_ok());
736*5225e6b1SAndroid Build Coastguard Worker     }
737*5225e6b1SAndroid Build Coastguard Worker 
738*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_partition_iter()739*5225e6b1SAndroid Build Coastguard Worker     fn test_partition_iter() {
740*5225e6b1SAndroid Build Coastguard Worker         let raw = raw_disk(c"raw", vec![0u8; 1024]);
741*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(raw.num_partitions().unwrap(), 1);
742*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(raw.get_partition_by_idx(0).unwrap().name(), Ok("raw"));
743*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(raw.get_partition_by_idx(0).unwrap().size(), Ok(1024));
744*5225e6b1SAndroid Build Coastguard Worker 
745*5225e6b1SAndroid Build Coastguard Worker         let gpt = gpt_disk(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
746*5225e6b1SAndroid Build Coastguard Worker         block_on(gpt.sync_gpt()).unwrap();
747*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.num_partitions().unwrap(), 2);
748*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.get_partition_by_idx(0).unwrap().name().unwrap(), "boot_a");
749*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.get_partition_by_idx(0).unwrap().size().unwrap(), 0x2000);
750*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.get_partition_by_idx(1).unwrap().name().unwrap(), "boot_b");
751*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(gpt.get_partition_by_idx(1).unwrap().size().unwrap(), 0x3000);
752*5225e6b1SAndroid Build Coastguard Worker     }
753*5225e6b1SAndroid Build Coastguard Worker 
754*5225e6b1SAndroid Build Coastguard Worker     /// A test helper for `read_unique_partition`
755*5225e6b1SAndroid Build Coastguard Worker     /// It verifies that data read from partition `part` at offset `off` is the same as
756*5225e6b1SAndroid Build Coastguard Worker     /// `part_content[off..off+sz]`.
check_read_partition( devs: &[TestGblDisk], part: &str, part_content: &[u8], off: u64, sz: u64, )757*5225e6b1SAndroid Build Coastguard Worker     fn check_read_partition(
758*5225e6b1SAndroid Build Coastguard Worker         devs: &[TestGblDisk],
759*5225e6b1SAndroid Build Coastguard Worker         part: &str,
760*5225e6b1SAndroid Build Coastguard Worker         part_content: &[u8],
761*5225e6b1SAndroid Build Coastguard Worker         off: u64,
762*5225e6b1SAndroid Build Coastguard Worker         sz: u64,
763*5225e6b1SAndroid Build Coastguard Worker     ) {
764*5225e6b1SAndroid Build Coastguard Worker         let mut out = vec![0u8; to_usize(sz)];
765*5225e6b1SAndroid Build Coastguard Worker         block_on(read_unique_partition(devs, part, off, &mut out[..])).unwrap();
766*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(out, part_content[to_usize(off)..][..out.len()]);
767*5225e6b1SAndroid Build Coastguard Worker     }
768*5225e6b1SAndroid Build Coastguard Worker 
769*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_read_unique_partition()770*5225e6b1SAndroid Build Coastguard Worker     fn test_read_unique_partition() {
771*5225e6b1SAndroid Build Coastguard Worker         let mut devs = FakeGblOpsStorage::default();
772*5225e6b1SAndroid Build Coastguard Worker         devs.add_gpt_device(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
773*5225e6b1SAndroid Build Coastguard Worker         devs.add_gpt_device(include_bytes!("../../libstorage/test/gpt_test_2.bin"));
774*5225e6b1SAndroid Build Coastguard Worker         devs.add_raw_device(c"raw_0", [0xaau8; 4 * 1024]);
775*5225e6b1SAndroid Build Coastguard Worker         devs.add_raw_device(c"raw_1", [0x55u8; 4 * 1024]);
776*5225e6b1SAndroid Build Coastguard Worker 
777*5225e6b1SAndroid Build Coastguard Worker         let boot_a = include_bytes!("../../libstorage/test/boot_a.bin");
778*5225e6b1SAndroid Build Coastguard Worker         let boot_b = include_bytes!("../../libstorage/test/boot_b.bin");
779*5225e6b1SAndroid Build Coastguard Worker 
780*5225e6b1SAndroid Build Coastguard Worker         let off = 512u64;
781*5225e6b1SAndroid Build Coastguard Worker         let sz = 1024u64;
782*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(&mut devs, "boot_a", boot_a, off, sz);
783*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(&mut devs, "boot_b", boot_b, off, sz);
784*5225e6b1SAndroid Build Coastguard Worker 
785*5225e6b1SAndroid Build Coastguard Worker         let vendor_boot_a = include_bytes!("../../libstorage/test/vendor_boot_a.bin");
786*5225e6b1SAndroid Build Coastguard Worker         let vendor_boot_b = include_bytes!("../../libstorage/test/vendor_boot_b.bin");
787*5225e6b1SAndroid Build Coastguard Worker 
788*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(&mut devs, "vendor_boot_a", vendor_boot_a, off, sz);
789*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(&mut devs, "vendor_boot_b", vendor_boot_b, off, sz);
790*5225e6b1SAndroid Build Coastguard Worker 
791*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(&mut devs, "raw_0", &[0xaau8; 4 * 1024][..], off, sz);
792*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(&mut devs, "raw_1", &[0x55u8; 4 * 1024][..], off, sz);
793*5225e6b1SAndroid Build Coastguard Worker     }
794*5225e6b1SAndroid Build Coastguard Worker 
795*5225e6b1SAndroid Build Coastguard Worker     /// A test helper for `write_unique_partition`
check_write_partition(devs: &[TestGblDisk], part: &str, off: u64, sz: u64)796*5225e6b1SAndroid Build Coastguard Worker     fn check_write_partition(devs: &[TestGblDisk], part: &str, off: u64, sz: u64) {
797*5225e6b1SAndroid Build Coastguard Worker         // Reads the current partition content
798*5225e6b1SAndroid Build Coastguard Worker         let (_, p) = check_part_unique(devs, part).unwrap();
799*5225e6b1SAndroid Build Coastguard Worker         let mut part_content = vec![0u8; to_usize(p.size().unwrap())];
800*5225e6b1SAndroid Build Coastguard Worker         block_on(read_unique_partition(devs, part, 0, &mut part_content[..])).unwrap();
801*5225e6b1SAndroid Build Coastguard Worker 
802*5225e6b1SAndroid Build Coastguard Worker         // Flips all the bits in the target range and writes back.
803*5225e6b1SAndroid Build Coastguard Worker         let seg = &mut part_content[to_usize(off)..][..to_usize(sz)];
804*5225e6b1SAndroid Build Coastguard Worker         seg.iter_mut().for_each(|v| *v = !(*v));
805*5225e6b1SAndroid Build Coastguard Worker         block_on(write_unique_partition(devs, part, off, seg)).unwrap();
806*5225e6b1SAndroid Build Coastguard Worker         // Checks that data is written.
807*5225e6b1SAndroid Build Coastguard Worker         check_read_partition(devs, part, &part_content, off, sz);
808*5225e6b1SAndroid Build Coastguard Worker     }
809*5225e6b1SAndroid Build Coastguard Worker 
810*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_write_unique_partition()811*5225e6b1SAndroid Build Coastguard Worker     fn test_write_unique_partition() {
812*5225e6b1SAndroid Build Coastguard Worker         let mut devs = FakeGblOpsStorage::default();
813*5225e6b1SAndroid Build Coastguard Worker         devs.add_gpt_device(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
814*5225e6b1SAndroid Build Coastguard Worker         devs.add_gpt_device(include_bytes!("../../libstorage/test/gpt_test_2.bin"));
815*5225e6b1SAndroid Build Coastguard Worker         devs.add_raw_device(c"raw_0", [0xaau8; 4 * 1024]);
816*5225e6b1SAndroid Build Coastguard Worker         devs.add_raw_device(c"raw_1", [0x55u8; 4 * 1024]);
817*5225e6b1SAndroid Build Coastguard Worker 
818*5225e6b1SAndroid Build Coastguard Worker         let off = 512u64;
819*5225e6b1SAndroid Build Coastguard Worker         let sz = 1024u64;
820*5225e6b1SAndroid Build Coastguard Worker         check_write_partition(&mut devs, "boot_a", off, sz);
821*5225e6b1SAndroid Build Coastguard Worker         check_write_partition(&mut devs, "boot_b", off, sz);
822*5225e6b1SAndroid Build Coastguard Worker         check_write_partition(&mut devs, "vendor_boot_a", off, sz);
823*5225e6b1SAndroid Build Coastguard Worker         check_write_partition(&mut devs, "vendor_boot_b", off, sz);
824*5225e6b1SAndroid Build Coastguard Worker         check_write_partition(&mut devs, "raw_0", off, sz);
825*5225e6b1SAndroid Build Coastguard Worker         check_write_partition(&mut devs, "raw_1", off, sz);
826*5225e6b1SAndroid Build Coastguard Worker     }
827*5225e6b1SAndroid Build Coastguard Worker 
828*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_rw_fail_with_non_unique_partition()829*5225e6b1SAndroid Build Coastguard Worker     fn test_rw_fail_with_non_unique_partition() {
830*5225e6b1SAndroid Build Coastguard Worker         let mut devs = FakeGblOpsStorage::default();
831*5225e6b1SAndroid Build Coastguard Worker         devs.add_gpt_device(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
832*5225e6b1SAndroid Build Coastguard Worker         devs.add_gpt_device(include_bytes!("../../libstorage/test/gpt_test_1.bin"));
833*5225e6b1SAndroid Build Coastguard Worker         devs.add_raw_device(c"raw", [0xaau8; 4 * 1024]);
834*5225e6b1SAndroid Build Coastguard Worker         devs.add_raw_device(c"raw", [0x55u8; 4 * 1024]);
835*5225e6b1SAndroid Build Coastguard Worker 
836*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(read_unique_partition(&devs, "boot_a", 0, &mut [] as &mut [u8],)).is_err());
837*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(write_unique_partition(&devs, "boot_a", 0, &mut [],)).is_err());
838*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(read_unique_partition(&devs, "raw", 0, &mut [] as &mut [u8],)).is_err());
839*5225e6b1SAndroid Build Coastguard Worker         assert!(block_on(write_unique_partition(&devs, "raw", 0, &mut [],)).is_err());
840*5225e6b1SAndroid Build Coastguard Worker     }
841*5225e6b1SAndroid Build Coastguard Worker }
842