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 use core::{
16*5225e6b1SAndroid Build Coastguard Worker cmp::{max, min},
17*5225e6b1SAndroid Build Coastguard Worker mem::size_of,
18*5225e6b1SAndroid Build Coastguard Worker };
19*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
20*5225e6b1SAndroid Build Coastguard Worker use static_assertions::const_assert;
21*5225e6b1SAndroid Build Coastguard Worker use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};
22*5225e6b1SAndroid Build Coastguard Worker
23*5225e6b1SAndroid Build Coastguard Worker // TODO(b/331854173): Switch to use bindgen for the following type definitions once
24*5225e6b1SAndroid Build Coastguard Worker // system/core/libsparse is added to repo checkout.
25*5225e6b1SAndroid Build Coastguard Worker
26*5225e6b1SAndroid Build Coastguard Worker const HEADER_MAGIC: u32 = 0xED26FF3A;
27*5225e6b1SAndroid Build Coastguard Worker const CHUNK_TYPE_RAW: u16 = 0xCAC1;
28*5225e6b1SAndroid Build Coastguard Worker const CHUNK_TYPE_FILL: u16 = 0xCAC2;
29*5225e6b1SAndroid Build Coastguard Worker const CHUNK_TYPE_DONT_CARE: u16 = 0xCAC3;
30*5225e6b1SAndroid Build Coastguard Worker const CHUNK_TYPE_CRC32: u16 = 0xCAC4;
31*5225e6b1SAndroid Build Coastguard Worker
32*5225e6b1SAndroid Build Coastguard Worker const SPARSE_HEADER_MAJOR_VER: u16 = 1;
33*5225e6b1SAndroid Build Coastguard Worker const SPARSE_HEADER_MINOR_VER: u16 = 0;
34*5225e6b1SAndroid Build Coastguard Worker
35*5225e6b1SAndroid Build Coastguard Worker #[repr(C)]
36*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
37*5225e6b1SAndroid Build Coastguard Worker pub struct SparseHeader {
38*5225e6b1SAndroid Build Coastguard Worker pub magic: u32,
39*5225e6b1SAndroid Build Coastguard Worker pub major_version: u16,
40*5225e6b1SAndroid Build Coastguard Worker pub minor_version: u16,
41*5225e6b1SAndroid Build Coastguard Worker pub file_hdr_sz: u16,
42*5225e6b1SAndroid Build Coastguard Worker pub chunk_hdr_sz: u16,
43*5225e6b1SAndroid Build Coastguard Worker pub blk_sz: u32,
44*5225e6b1SAndroid Build Coastguard Worker pub total_blks: u32,
45*5225e6b1SAndroid Build Coastguard Worker pub total_chunks: u32,
46*5225e6b1SAndroid Build Coastguard Worker pub image_checksum: u32,
47*5225e6b1SAndroid Build Coastguard Worker }
48*5225e6b1SAndroid Build Coastguard Worker
49*5225e6b1SAndroid Build Coastguard Worker impl SparseHeader {
50*5225e6b1SAndroid Build Coastguard Worker /// Returns the total size in bytes for the data after unsparsified.
data_size(&self) -> u6451*5225e6b1SAndroid Build Coastguard Worker pub fn data_size(&self) -> u64 {
52*5225e6b1SAndroid Build Coastguard Worker (self.total_blks as u64) * (self.blk_sz as u64)
53*5225e6b1SAndroid Build Coastguard Worker }
54*5225e6b1SAndroid Build Coastguard Worker }
55*5225e6b1SAndroid Build Coastguard Worker
56*5225e6b1SAndroid Build Coastguard Worker #[repr(C)]
57*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
58*5225e6b1SAndroid Build Coastguard Worker pub struct ChunkHeader {
59*5225e6b1SAndroid Build Coastguard Worker pub chunk_type: u16,
60*5225e6b1SAndroid Build Coastguard Worker pub reserved1: u16,
61*5225e6b1SAndroid Build Coastguard Worker pub chunk_sz: u32,
62*5225e6b1SAndroid Build Coastguard Worker pub total_sz: u32,
63*5225e6b1SAndroid Build Coastguard Worker }
64*5225e6b1SAndroid Build Coastguard Worker
65*5225e6b1SAndroid Build Coastguard Worker const ERR_ARITHMETIC_OVERFLOW: &str = "Arithmetic Overflow";
66*5225e6b1SAndroid Build Coastguard Worker const ERR_IMAGE_SIZE: &str = "Bad image. Invalid image size";
67*5225e6b1SAndroid Build Coastguard Worker
68*5225e6b1SAndroid Build Coastguard Worker /// Checks if a sparse image is valid and returns the sparse header.
is_sparse_image(sparse_img: &[u8]) -> Result<SparseHeader, Error>69*5225e6b1SAndroid Build Coastguard Worker pub fn is_sparse_image(sparse_img: &[u8]) -> Result<SparseHeader, Error> {
70*5225e6b1SAndroid Build Coastguard Worker let sparse_header: SparseHeader = copy_from(sparse_img)?;
71*5225e6b1SAndroid Build Coastguard Worker if sparse_header.magic != HEADER_MAGIC {
72*5225e6b1SAndroid Build Coastguard Worker return Err("Sparse magic mismatch".into());
73*5225e6b1SAndroid Build Coastguard Worker } else if sparse_header.major_version != SPARSE_HEADER_MAJOR_VER {
74*5225e6b1SAndroid Build Coastguard Worker return Err("Sparse major version mismatch".into());
75*5225e6b1SAndroid Build Coastguard Worker } else if sparse_header.minor_version != SPARSE_HEADER_MINOR_VER {
76*5225e6b1SAndroid Build Coastguard Worker return Err("Sparse minor version mismatch".into());
77*5225e6b1SAndroid Build Coastguard Worker }
78*5225e6b1SAndroid Build Coastguard Worker Ok(sparse_header)
79*5225e6b1SAndroid Build Coastguard Worker }
80*5225e6b1SAndroid Build Coastguard Worker
81*5225e6b1SAndroid Build Coastguard Worker /// `FillInfo` is derived from a sparse chunk and contains information whether to fill a value or
82*5225e6b1SAndroid Build Coastguard Worker /// skip for a number of blocks.
83*5225e6b1SAndroid Build Coastguard Worker ///
84*5225e6b1SAndroid Build Coastguard Worker /// Context and uses:
85*5225e6b1SAndroid Build Coastguard Worker ///
86*5225e6b1SAndroid Build Coastguard Worker /// When writing fill chunks from a sparse image, it is usually better to write a larger buffer
87*5225e6b1SAndroid Build Coastguard Worker /// with the filled value instead of a single u32 at a time. However, separately maintaining a fill
88*5225e6b1SAndroid Build Coastguard Worker /// buffer can be inconvenient for the caller. Therefore, we use a strategy that re-uses the input
89*5225e6b1SAndroid Build Coastguard Worker /// buffer for fill buffer.
90*5225e6b1SAndroid Build Coastguard Worker ///
91*5225e6b1SAndroid Build Coastguard Worker /// The idea is to write the sparse image in two passes. In the first pass, we only write non-fill
92*5225e6b1SAndroid Build Coastguard Worker /// chunks. For each sparse chunk, we create a `FillInfo` and append it from the beginning of the
93*5225e6b1SAndroid Build Coastguard Worker /// input buffer. For fill chunks, `FillInfo::fill_blocks` and
94*5225e6b1SAndroid Build Coastguard Worker /// `FillInfo::fill_value_or_skip_blocks` are set to the chunk size and fill value. For others,
95*5225e6b1SAndroid Build Coastguard Worker /// `FillInfo::fill_blocks` will be set to 0 and `FillInfo::fill_value_or_skip_blocks` will be set
96*5225e6b1SAndroid Build Coastguard Worker /// to the chunk size instead to represent number of blocks to skip. The second pass writes the
97*5225e6b1SAndroid Build Coastguard Worker /// fill chunk according to `FillInfo`.
98*5225e6b1SAndroid Build Coastguard Worker ///
99*5225e6b1SAndroid Build Coastguard Worker /// Because a sparse chunk is at least 12 bytes, whereas `FillInfo` is 8 bytes, at the end of the
100*5225e6b1SAndroid Build Coastguard Worker /// first pass, we are guaranteed to have at least 1/3 of the input buffer free to use as fill
101*5225e6b1SAndroid Build Coastguard Worker /// buffer.
102*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)]
103*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
104*5225e6b1SAndroid Build Coastguard Worker struct FillInfo {
105*5225e6b1SAndroid Build Coastguard Worker // Number of blocks to fill.
106*5225e6b1SAndroid Build Coastguard Worker pub fill_blocks: u32,
107*5225e6b1SAndroid Build Coastguard Worker // If `fill_blocks` is None, this field represents the number of blocks to skip.
108*5225e6b1SAndroid Build Coastguard Worker // Otherwise, it represents the fill value.
109*5225e6b1SAndroid Build Coastguard Worker pub fill_value_or_skip_blocks: u32,
110*5225e6b1SAndroid Build Coastguard Worker }
111*5225e6b1SAndroid Build Coastguard Worker
112*5225e6b1SAndroid Build Coastguard Worker impl FillInfo {
113*5225e6b1SAndroid Build Coastguard Worker /// Creates an instance that represents filling a number of blocks.
new_fill(blocks: u32, value: u32) -> Self114*5225e6b1SAndroid Build Coastguard Worker fn new_fill(blocks: u32, value: u32) -> Self {
115*5225e6b1SAndroid Build Coastguard Worker assert_ne!(blocks, 0);
116*5225e6b1SAndroid Build Coastguard Worker Self { fill_blocks: blocks, fill_value_or_skip_blocks: value }
117*5225e6b1SAndroid Build Coastguard Worker }
118*5225e6b1SAndroid Build Coastguard Worker
119*5225e6b1SAndroid Build Coastguard Worker /// Creates an instance that represents skipping a number of blocks.
new_skip(blocks: u32) -> Self120*5225e6b1SAndroid Build Coastguard Worker fn new_skip(blocks: u32) -> Self {
121*5225e6b1SAndroid Build Coastguard Worker Self { fill_blocks: 0, fill_value_or_skip_blocks: blocks }
122*5225e6b1SAndroid Build Coastguard Worker }
123*5225e6b1SAndroid Build Coastguard Worker
124*5225e6b1SAndroid Build Coastguard Worker // Returns (blocks, None) for the skip case or (blocks, Some(value)) for the fill case.
get_blocks_and_value(&self) -> (u32, Option<u32>)125*5225e6b1SAndroid Build Coastguard Worker fn get_blocks_and_value(&self) -> (u32, Option<u32>) {
126*5225e6b1SAndroid Build Coastguard Worker match self.fill_blocks {
127*5225e6b1SAndroid Build Coastguard Worker 0 => (self.fill_value_or_skip_blocks, None),
128*5225e6b1SAndroid Build Coastguard Worker v => (v, Some(self.fill_value_or_skip_blocks)),
129*5225e6b1SAndroid Build Coastguard Worker }
130*5225e6b1SAndroid Build Coastguard Worker }
131*5225e6b1SAndroid Build Coastguard Worker }
132*5225e6b1SAndroid Build Coastguard Worker
133*5225e6b1SAndroid Build Coastguard Worker const_assert!(size_of::<FillInfo>() < size_of::<ChunkHeader>());
134*5225e6b1SAndroid Build Coastguard Worker
135*5225e6b1SAndroid Build Coastguard Worker /// `SparseRawWriter` defines an interface for writing to raw storage used by `write_sparse_image`.
136*5225e6b1SAndroid Build Coastguard Worker pub(crate) trait SparseRawWriter {
137*5225e6b1SAndroid Build Coastguard Worker /// Writes bytes from `data` to the destination storage at offset `off`
write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error>138*5225e6b1SAndroid Build Coastguard Worker async fn write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error>;
139*5225e6b1SAndroid Build Coastguard Worker }
140*5225e6b1SAndroid Build Coastguard Worker
141*5225e6b1SAndroid Build Coastguard Worker /// Write a sparse image in `sparse_img`.
142*5225e6b1SAndroid Build Coastguard Worker ///
143*5225e6b1SAndroid Build Coastguard Worker /// # Args
144*5225e6b1SAndroid Build Coastguard Worker //
145*5225e6b1SAndroid Build Coastguard Worker /// * `sparse_img`: The input buffer containing the sparse image. The API modifes input buffer for
146*5225e6b1SAndroid Build Coastguard Worker /// internal optimization.
147*5225e6b1SAndroid Build Coastguard Worker /// * `writer`: An implementation of `SparseRawWriter`.
148*5225e6b1SAndroid Build Coastguard Worker ///
149*5225e6b1SAndroid Build Coastguard Worker /// # Returns
150*5225e6b1SAndroid Build Coastguard Worker ///
151*5225e6b1SAndroid Build Coastguard Worker /// Returns the total number of bytes written, including don't care chunks.
write_sparse_image( sparse_img: &mut [u8], writer: &mut impl SparseRawWriter, ) -> Result<u64, Error>152*5225e6b1SAndroid Build Coastguard Worker pub async fn write_sparse_image(
153*5225e6b1SAndroid Build Coastguard Worker sparse_img: &mut [u8],
154*5225e6b1SAndroid Build Coastguard Worker writer: &mut impl SparseRawWriter,
155*5225e6b1SAndroid Build Coastguard Worker ) -> Result<u64, Error> {
156*5225e6b1SAndroid Build Coastguard Worker let sparse_header: SparseHeader = is_sparse_image(sparse_img)?;
157*5225e6b1SAndroid Build Coastguard Worker let mut curr: usize = size_of::<SparseHeader>();
158*5225e6b1SAndroid Build Coastguard Worker let mut write_offset = 0u64;
159*5225e6b1SAndroid Build Coastguard Worker
160*5225e6b1SAndroid Build Coastguard Worker // First pass. Writes non-fill chunk and constructs `FillInfo`.
161*5225e6b1SAndroid Build Coastguard Worker let mut fill_off = 0usize;
162*5225e6b1SAndroid Build Coastguard Worker for _ in 0..sparse_header.total_chunks {
163*5225e6b1SAndroid Build Coastguard Worker let header: ChunkHeader = copy_from(&mut sparse_img[curr..])?;
164*5225e6b1SAndroid Build Coastguard Worker let payload = &mut sparse_img[curr + size_of::<ChunkHeader>()..];
165*5225e6b1SAndroid Build Coastguard Worker let payload_sz = u64_mul(header.chunk_sz, sparse_header.blk_sz)?;
166*5225e6b1SAndroid Build Coastguard Worker let mut fill = FillInfo::new_skip(header.chunk_sz);
167*5225e6b1SAndroid Build Coastguard Worker match header.chunk_type {
168*5225e6b1SAndroid Build Coastguard Worker CHUNK_TYPE_RAW => {
169*5225e6b1SAndroid Build Coastguard Worker writer.write(write_offset, get_mut(payload, 0, to_usize(payload_sz)?)?).await?;
170*5225e6b1SAndroid Build Coastguard Worker }
171*5225e6b1SAndroid Build Coastguard Worker CHUNK_TYPE_FILL if header.chunk_sz != 0 => {
172*5225e6b1SAndroid Build Coastguard Worker let fill_val = u32::from_le_bytes(get_mut(payload, 0, 4)?.try_into().unwrap());
173*5225e6b1SAndroid Build Coastguard Worker fill = FillInfo::new_fill(header.chunk_sz, fill_val);
174*5225e6b1SAndroid Build Coastguard Worker }
175*5225e6b1SAndroid Build Coastguard Worker CHUNK_TYPE_DONT_CARE | CHUNK_TYPE_CRC32 => {}
176*5225e6b1SAndroid Build Coastguard Worker _ => return Err("Invalid Chunk Type".into()),
177*5225e6b1SAndroid Build Coastguard Worker };
178*5225e6b1SAndroid Build Coastguard Worker write_offset = u64_add(write_offset, payload_sz)?;
179*5225e6b1SAndroid Build Coastguard Worker sparse_img[fill_off..][..size_of::<FillInfo>()].clone_from_slice(fill.as_bytes());
180*5225e6b1SAndroid Build Coastguard Worker fill_off = usize_add(fill_off, size_of::<FillInfo>())?;
181*5225e6b1SAndroid Build Coastguard Worker curr = usize_add(curr, header.total_sz)?;
182*5225e6b1SAndroid Build Coastguard Worker }
183*5225e6b1SAndroid Build Coastguard Worker let total = write_offset;
184*5225e6b1SAndroid Build Coastguard Worker
185*5225e6b1SAndroid Build Coastguard Worker // Second pass. Writes fill chunks.
186*5225e6b1SAndroid Build Coastguard Worker // Use all reamining buffer as fill buffer.
187*5225e6b1SAndroid Build Coastguard Worker let (fill_infos, fill_buffer) = sparse_img.split_at_mut(fill_off);
188*5225e6b1SAndroid Build Coastguard Worker let mut fill_buffer = FillBuffer { curr_val: None, curr_size: 0, buffer: fill_buffer };
189*5225e6b1SAndroid Build Coastguard Worker let fill_infos = Ref::<_, [FillInfo]>::new_slice(fill_infos).unwrap().into_slice();
190*5225e6b1SAndroid Build Coastguard Worker write_offset = 0;
191*5225e6b1SAndroid Build Coastguard Worker for ele in fill_infos {
192*5225e6b1SAndroid Build Coastguard Worker match ele.get_blocks_and_value() {
193*5225e6b1SAndroid Build Coastguard Worker (blks, None) => {
194*5225e6b1SAndroid Build Coastguard Worker write_offset = u64_add(write_offset, u64_mul(blks, sparse_header.blk_sz)?)?;
195*5225e6b1SAndroid Build Coastguard Worker }
196*5225e6b1SAndroid Build Coastguard Worker (blks, Some(v)) => {
197*5225e6b1SAndroid Build Coastguard Worker let sz = u64_mul(blks, sparse_header.blk_sz)?;
198*5225e6b1SAndroid Build Coastguard Worker let buffer = fill_buffer.get(v, sz)?;
199*5225e6b1SAndroid Build Coastguard Worker let buffer_len = to_u64(buffer.len())?;
200*5225e6b1SAndroid Build Coastguard Worker let end = u64_add(write_offset, sz)?;
201*5225e6b1SAndroid Build Coastguard Worker while write_offset < end {
202*5225e6b1SAndroid Build Coastguard Worker let to_write = min(buffer_len, end - write_offset);
203*5225e6b1SAndroid Build Coastguard Worker writer.write(write_offset, &mut buffer[..to_usize(to_write).unwrap()]).await?;
204*5225e6b1SAndroid Build Coastguard Worker write_offset += to_write;
205*5225e6b1SAndroid Build Coastguard Worker }
206*5225e6b1SAndroid Build Coastguard Worker }
207*5225e6b1SAndroid Build Coastguard Worker }
208*5225e6b1SAndroid Build Coastguard Worker }
209*5225e6b1SAndroid Build Coastguard Worker Ok(total)
210*5225e6b1SAndroid Build Coastguard Worker }
211*5225e6b1SAndroid Build Coastguard Worker
212*5225e6b1SAndroid Build Coastguard Worker /// `FillUnit` is a packed C struct wrapping a u32. It is mainly used for filling a buffer of
213*5225e6b1SAndroid Build Coastguard Worker /// arbitrary alignment with a u32 value.
214*5225e6b1SAndroid Build Coastguard Worker #[repr(C, packed)]
215*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
216*5225e6b1SAndroid Build Coastguard Worker struct FillUnit(u32);
217*5225e6b1SAndroid Build Coastguard Worker
218*5225e6b1SAndroid Build Coastguard Worker /// `FillBuffer` manages a buffer and provides API for making a fill buffer with the given value.
219*5225e6b1SAndroid Build Coastguard Worker struct FillBuffer<'a> {
220*5225e6b1SAndroid Build Coastguard Worker curr_val: Option<u32>,
221*5225e6b1SAndroid Build Coastguard Worker curr_size: usize,
222*5225e6b1SAndroid Build Coastguard Worker buffer: &'a mut [u8],
223*5225e6b1SAndroid Build Coastguard Worker }
224*5225e6b1SAndroid Build Coastguard Worker
225*5225e6b1SAndroid Build Coastguard Worker impl FillBuffer<'_> {
226*5225e6b1SAndroid Build Coastguard Worker /// Get a buffer up to `size` number of bytes filled with `val`.
get(&mut self, val: u32, size: u64) -> Result<&mut [u8], Error>227*5225e6b1SAndroid Build Coastguard Worker fn get(&mut self, val: u32, size: u64) -> Result<&mut [u8], Error> {
228*5225e6b1SAndroid Build Coastguard Worker let aligned_len = self.buffer.len() - (self.buffer.len() % size_of::<u32>());
229*5225e6b1SAndroid Build Coastguard Worker let size: usize = min(to_u64(aligned_len)?, size).try_into().unwrap();
230*5225e6b1SAndroid Build Coastguard Worker if Some(val) != self.curr_val {
231*5225e6b1SAndroid Build Coastguard Worker self.curr_size = 0;
232*5225e6b1SAndroid Build Coastguard Worker self.curr_val = Some(val);
233*5225e6b1SAndroid Build Coastguard Worker }
234*5225e6b1SAndroid Build Coastguard Worker let gap = max(self.curr_size, size) - self.curr_size;
235*5225e6b1SAndroid Build Coastguard Worker let to_fill = &mut self.buffer[self.curr_size..][..gap];
236*5225e6b1SAndroid Build Coastguard Worker Ref::<_, [FillUnit]>::new_slice(to_fill).unwrap().into_mut_slice().fill(FillUnit(val));
237*5225e6b1SAndroid Build Coastguard Worker self.curr_size += gap;
238*5225e6b1SAndroid Build Coastguard Worker Ok(&mut self.buffer[..size])
239*5225e6b1SAndroid Build Coastguard Worker }
240*5225e6b1SAndroid Build Coastguard Worker }
241*5225e6b1SAndroid Build Coastguard Worker
242*5225e6b1SAndroid Build Coastguard Worker /// A helper to check and get a mutable sub slice.
get_mut<L: TryInto<usize>, R: TryInto<usize>>( bytes: &mut [u8], start: L, end: R, ) -> Result<&mut [u8], Error>243*5225e6b1SAndroid Build Coastguard Worker fn get_mut<L: TryInto<usize>, R: TryInto<usize>>(
244*5225e6b1SAndroid Build Coastguard Worker bytes: &mut [u8],
245*5225e6b1SAndroid Build Coastguard Worker start: L,
246*5225e6b1SAndroid Build Coastguard Worker end: R,
247*5225e6b1SAndroid Build Coastguard Worker ) -> Result<&mut [u8], Error> {
248*5225e6b1SAndroid Build Coastguard Worker bytes.get_mut(to_usize(start)?..to_usize(end)?).ok_or(ERR_IMAGE_SIZE.into())
249*5225e6b1SAndroid Build Coastguard Worker }
250*5225e6b1SAndroid Build Coastguard Worker
251*5225e6b1SAndroid Build Coastguard Worker /// A helper to check and get a sub slice.
get<L: TryInto<usize>, R: TryInto<usize>>( bytes: &[u8], start: L, end: R, ) -> Result<&[u8], Error>252*5225e6b1SAndroid Build Coastguard Worker fn get<L: TryInto<usize>, R: TryInto<usize>>(
253*5225e6b1SAndroid Build Coastguard Worker bytes: &[u8],
254*5225e6b1SAndroid Build Coastguard Worker start: L,
255*5225e6b1SAndroid Build Coastguard Worker end: R,
256*5225e6b1SAndroid Build Coastguard Worker ) -> Result<&[u8], Error> {
257*5225e6b1SAndroid Build Coastguard Worker bytes.get(to_usize(start)?..to_usize(end)?).ok_or(ERR_IMAGE_SIZE.into())
258*5225e6b1SAndroid Build Coastguard Worker }
259*5225e6b1SAndroid Build Coastguard Worker
260*5225e6b1SAndroid Build Coastguard Worker /// A helper to return a copy of a zerocopy object from bytes.
copy_from<T: AsBytes + FromBytes + Default>(bytes: &[u8]) -> Result<T, Error>261*5225e6b1SAndroid Build Coastguard Worker fn copy_from<T: AsBytes + FromBytes + Default>(bytes: &[u8]) -> Result<T, Error> {
262*5225e6b1SAndroid Build Coastguard Worker let mut res: T = Default::default();
263*5225e6b1SAndroid Build Coastguard Worker res.as_bytes_mut().clone_from_slice(get(bytes, 0, size_of::<T>())?);
264*5225e6b1SAndroid Build Coastguard Worker Ok(res)
265*5225e6b1SAndroid Build Coastguard Worker }
266*5225e6b1SAndroid Build Coastguard Worker
267*5225e6b1SAndroid Build Coastguard Worker // Investigate switching the following to use SafeNum. A naive replacement results in too many
268*5225e6b1SAndroid Build Coastguard Worker // `try_into()?` callsites which looks chaotics. Some proper wrapper might still be needed.
269*5225e6b1SAndroid Build Coastguard Worker
270*5225e6b1SAndroid Build Coastguard Worker /// Checks and converts an integer into usize.
to_usize<T: TryInto<usize>>(val: T) -> Result<usize, Error>271*5225e6b1SAndroid Build Coastguard Worker fn to_usize<T: TryInto<usize>>(val: T) -> Result<usize, Error> {
272*5225e6b1SAndroid Build Coastguard Worker Ok(val.try_into().map_err(|_| ERR_ARITHMETIC_OVERFLOW)?)
273*5225e6b1SAndroid Build Coastguard Worker }
274*5225e6b1SAndroid Build Coastguard Worker
275*5225e6b1SAndroid Build Coastguard Worker /// Adds two usize convertible numbers and checks overflow.
usize_add<L: TryInto<usize>, R: TryInto<usize>>(lhs: L, rhs: R) -> Result<usize, Error>276*5225e6b1SAndroid Build Coastguard Worker fn usize_add<L: TryInto<usize>, R: TryInto<usize>>(lhs: L, rhs: R) -> Result<usize, Error> {
277*5225e6b1SAndroid Build Coastguard Worker Ok(to_usize(lhs)?.checked_add(to_usize(rhs)?).ok_or(ERR_ARITHMETIC_OVERFLOW)?)
278*5225e6b1SAndroid Build Coastguard Worker }
279*5225e6b1SAndroid Build Coastguard Worker
280*5225e6b1SAndroid Build Coastguard Worker /// Checks and converts an integer into u64
to_u64<T: TryInto<u64>>(val: T) -> Result<u64, Error>281*5225e6b1SAndroid Build Coastguard Worker fn to_u64<T: TryInto<u64>>(val: T) -> Result<u64, Error> {
282*5225e6b1SAndroid Build Coastguard Worker Ok(val.try_into().map_err(|_| ERR_ARITHMETIC_OVERFLOW)?)
283*5225e6b1SAndroid Build Coastguard Worker }
284*5225e6b1SAndroid Build Coastguard Worker
285*5225e6b1SAndroid Build Coastguard Worker /// Adds two u64 convertible numbers and checks overflow.
u64_add<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, Error>286*5225e6b1SAndroid Build Coastguard Worker fn u64_add<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, Error> {
287*5225e6b1SAndroid Build Coastguard Worker Ok(to_u64(lhs)?.checked_add(to_u64(rhs)?).ok_or(ERR_ARITHMETIC_OVERFLOW)?)
288*5225e6b1SAndroid Build Coastguard Worker }
289*5225e6b1SAndroid Build Coastguard Worker
290*5225e6b1SAndroid Build Coastguard Worker /// Multiplies two u64 convertible numbers and checks overflow.
u64_mul<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, Error>291*5225e6b1SAndroid Build Coastguard Worker fn u64_mul<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, Error> {
292*5225e6b1SAndroid Build Coastguard Worker Ok(to_u64(lhs)?.checked_mul(to_u64(rhs)?).ok_or(ERR_ARITHMETIC_OVERFLOW)?)
293*5225e6b1SAndroid Build Coastguard Worker }
294*5225e6b1SAndroid Build Coastguard Worker
295*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
296*5225e6b1SAndroid Build Coastguard Worker mod test {
297*5225e6b1SAndroid Build Coastguard Worker use super::*;
298*5225e6b1SAndroid Build Coastguard Worker use gbl_async::block_on;
299*5225e6b1SAndroid Build Coastguard Worker
300*5225e6b1SAndroid Build Coastguard Worker impl SparseRawWriter for Vec<u8> {
write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error>301*5225e6b1SAndroid Build Coastguard Worker async fn write(&mut self, off: u64, data: &mut [u8]) -> Result<(), Error> {
302*5225e6b1SAndroid Build Coastguard Worker self[off.try_into().unwrap()..][..data.len()].clone_from_slice(data);
303*5225e6b1SAndroid Build Coastguard Worker Ok(())
304*5225e6b1SAndroid Build Coastguard Worker }
305*5225e6b1SAndroid Build Coastguard Worker }
306*5225e6b1SAndroid Build Coastguard Worker
307*5225e6b1SAndroid Build Coastguard Worker #[test]
test_sparse_write()308*5225e6b1SAndroid Build Coastguard Worker fn test_sparse_write() {
309*5225e6b1SAndroid Build Coastguard Worker let raw = include_bytes!("../../testdata/sparse_test_raw.bin");
310*5225e6b1SAndroid Build Coastguard Worker let sparse = include_bytes!("../../testdata/sparse_test.bin");
311*5225e6b1SAndroid Build Coastguard Worker // Gives a larger output buffer.
312*5225e6b1SAndroid Build Coastguard Worker let mut out = vec![0u8; 2 * raw.len()];
313*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
314*5225e6b1SAndroid Build Coastguard Worker block_on(write_sparse_image(&mut sparse.to_vec()[..], &mut out)).unwrap(),
315*5225e6b1SAndroid Build Coastguard Worker raw.len().try_into().unwrap()
316*5225e6b1SAndroid Build Coastguard Worker );
317*5225e6b1SAndroid Build Coastguard Worker assert_eq!(out[..raw.len()].to_vec(), raw);
318*5225e6b1SAndroid Build Coastguard Worker }
319*5225e6b1SAndroid Build Coastguard Worker
320*5225e6b1SAndroid Build Coastguard Worker #[test]
test_sparse_write_non_default_block_size()321*5225e6b1SAndroid Build Coastguard Worker fn test_sparse_write_non_default_block_size() {
322*5225e6b1SAndroid Build Coastguard Worker let raw = include_bytes!("../../testdata/sparse_test_raw.bin");
323*5225e6b1SAndroid Build Coastguard Worker let sparse = include_bytes!("../../testdata/sparse_test_blk1024.bin");
324*5225e6b1SAndroid Build Coastguard Worker // Gives a larger output buffer.
325*5225e6b1SAndroid Build Coastguard Worker let mut out = vec![0u8; 2 * raw.len()];
326*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
327*5225e6b1SAndroid Build Coastguard Worker block_on(write_sparse_image(&mut sparse.to_vec()[..], &mut out)).unwrap(),
328*5225e6b1SAndroid Build Coastguard Worker raw.len().try_into().unwrap()
329*5225e6b1SAndroid Build Coastguard Worker );
330*5225e6b1SAndroid Build Coastguard Worker assert_eq!(out[..raw.len()].to_vec(), raw);
331*5225e6b1SAndroid Build Coastguard Worker }
332*5225e6b1SAndroid Build Coastguard Worker
333*5225e6b1SAndroid Build Coastguard Worker /// A helper to copy a zerocopy object into a buffer
copy_to<T: AsBytes + FromBytes>(val: &T, bytes: &mut [u8])334*5225e6b1SAndroid Build Coastguard Worker fn copy_to<T: AsBytes + FromBytes>(val: &T, bytes: &mut [u8]) {
335*5225e6b1SAndroid Build Coastguard Worker bytes[..size_of::<T>()].clone_from_slice(val.as_bytes());
336*5225e6b1SAndroid Build Coastguard Worker }
337*5225e6b1SAndroid Build Coastguard Worker
338*5225e6b1SAndroid Build Coastguard Worker #[test]
test_sparse_invalid_magic()339*5225e6b1SAndroid Build Coastguard Worker fn test_sparse_invalid_magic() {
340*5225e6b1SAndroid Build Coastguard Worker let mut sparse = include_bytes!("../../testdata/sparse_test.bin").to_vec();
341*5225e6b1SAndroid Build Coastguard Worker let mut sparse_header: SparseHeader = copy_from(&sparse[..]).unwrap();
342*5225e6b1SAndroid Build Coastguard Worker sparse_header.magic = 0;
343*5225e6b1SAndroid Build Coastguard Worker copy_to(&sparse_header, &mut sparse[..]);
344*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(write_sparse_image(&mut sparse[..], &mut vec![])).is_err());
345*5225e6b1SAndroid Build Coastguard Worker }
346*5225e6b1SAndroid Build Coastguard Worker
347*5225e6b1SAndroid Build Coastguard Worker #[test]
test_sparse_invalid_major_version()348*5225e6b1SAndroid Build Coastguard Worker fn test_sparse_invalid_major_version() {
349*5225e6b1SAndroid Build Coastguard Worker let mut sparse = include_bytes!("../../testdata/sparse_test.bin").to_vec();
350*5225e6b1SAndroid Build Coastguard Worker let mut sparse_header: SparseHeader = copy_from(&sparse[..]).unwrap();
351*5225e6b1SAndroid Build Coastguard Worker sparse_header.major_version = SPARSE_HEADER_MAJOR_VER + 1;
352*5225e6b1SAndroid Build Coastguard Worker copy_to(&sparse_header, &mut sparse[..]);
353*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(write_sparse_image(&mut sparse[..], &mut vec![])).is_err());
354*5225e6b1SAndroid Build Coastguard Worker }
355*5225e6b1SAndroid Build Coastguard Worker
356*5225e6b1SAndroid Build Coastguard Worker #[test]
test_sparse_invalid_minor_version()357*5225e6b1SAndroid Build Coastguard Worker fn test_sparse_invalid_minor_version() {
358*5225e6b1SAndroid Build Coastguard Worker let mut sparse = include_bytes!("../../testdata/sparse_test.bin").to_vec();
359*5225e6b1SAndroid Build Coastguard Worker let mut sparse_header: SparseHeader = copy_from(&sparse[..]).unwrap();
360*5225e6b1SAndroid Build Coastguard Worker sparse_header.minor_version = SPARSE_HEADER_MINOR_VER + 1;
361*5225e6b1SAndroid Build Coastguard Worker copy_to(&sparse_header, &mut sparse[..]);
362*5225e6b1SAndroid Build Coastguard Worker assert!(block_on(write_sparse_image(&mut sparse[..], &mut vec![])).is_err());
363*5225e6b1SAndroid Build Coastguard Worker }
364*5225e6b1SAndroid Build Coastguard Worker }
365