xref: /aosp_15_r20/external/crosvm/disk/src/android_sparse.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker // https://android.googlesource.com/platform/system/core/+/7b444f0/libsparse/sparse_format.h
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::io::ErrorKind;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Seek;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::io::SeekFrom;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
16*bb4ee6a4SAndroid Build Coastguard Worker 
17*bb4ee6a4SAndroid Build Coastguard Worker use async_trait::async_trait;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::FileAllocate;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::FileReadWriteAtVolatile;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::FileSetLen;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::VolatileSlice;
24*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::BackingMemory;
25*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::Executor;
26*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::IoSource;
27*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le16;
28*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le32;
29*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
30*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
31*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
32*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
33*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
34*bb4ee6a4SAndroid Build Coastguard Worker 
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::AsyncDisk;
36*bb4ee6a4SAndroid Build Coastguard Worker use crate::DiskFile;
37*bb4ee6a4SAndroid Build Coastguard Worker use crate::DiskGetLen;
38*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error as DiskError;
39*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result as DiskResult;
40*bb4ee6a4SAndroid Build Coastguard Worker use crate::ToAsyncDisk;
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
43*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
44*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
45*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid magic header for android sparse format")]
46*bb4ee6a4SAndroid Build Coastguard Worker     InvalidMagicHeader,
47*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid specification: \"{0}\"")]
48*bb4ee6a4SAndroid Build Coastguard Worker     InvalidSpecification(String),
49*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to read specification: \"{0}\"")]
50*bb4ee6a4SAndroid Build Coastguard Worker     ReadSpecificationError(io::Error),
51*bb4ee6a4SAndroid Build Coastguard Worker }
52*bb4ee6a4SAndroid Build Coastguard Worker 
53*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>;
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker pub const SPARSE_HEADER_MAGIC: u32 = 0xed26ff3a;
56*bb4ee6a4SAndroid Build Coastguard Worker const MAJOR_VERSION: u16 = 1;
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
59*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, AsBytes, FromZeroes, FromBytes)]
60*bb4ee6a4SAndroid Build Coastguard Worker struct SparseHeader {
61*bb4ee6a4SAndroid Build Coastguard Worker     magic: Le32,          // SPARSE_HEADER_MAGIC
62*bb4ee6a4SAndroid Build Coastguard Worker     major_version: Le16,  // (0x1) - reject images with higher major versions
63*bb4ee6a4SAndroid Build Coastguard Worker     minor_version: Le16,  // (0x0) - allow images with higer minor versions
64*bb4ee6a4SAndroid Build Coastguard Worker     file_hdr_sz: Le16,    // 28 bytes for first revision of the file format
65*bb4ee6a4SAndroid Build Coastguard Worker     chunk_hdr_size: Le16, // 12 bytes for first revision of the file format
66*bb4ee6a4SAndroid Build Coastguard Worker     blk_sz: Le32,         // block size in bytes, must be a multiple of 4 (4096)
67*bb4ee6a4SAndroid Build Coastguard Worker     total_blks: Le32,     // total blocks in the non-sparse output image
68*bb4ee6a4SAndroid Build Coastguard Worker     total_chunks: Le32,   // total chunks in the sparse input image
69*bb4ee6a4SAndroid Build Coastguard Worker     // CRC32 checksum of the original data, counting "don't care" as 0. Standard 802.3 polynomial,
70*bb4ee6a4SAndroid Build Coastguard Worker     // use a Public Domain table implementation
71*bb4ee6a4SAndroid Build Coastguard Worker     image_checksum: Le32,
72*bb4ee6a4SAndroid Build Coastguard Worker }
73*bb4ee6a4SAndroid Build Coastguard Worker 
74*bb4ee6a4SAndroid Build Coastguard Worker const CHUNK_TYPE_RAW: u16 = 0xCAC1;
75*bb4ee6a4SAndroid Build Coastguard Worker const CHUNK_TYPE_FILL: u16 = 0xCAC2;
76*bb4ee6a4SAndroid Build Coastguard Worker const CHUNK_TYPE_DONT_CARE: u16 = 0xCAC3;
77*bb4ee6a4SAndroid Build Coastguard Worker const CHUNK_TYPE_CRC32: u16 = 0xCAC4;
78*bb4ee6a4SAndroid Build Coastguard Worker 
79*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
80*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, AsBytes, FromZeroes, FromBytes)]
81*bb4ee6a4SAndroid Build Coastguard Worker struct ChunkHeader {
82*bb4ee6a4SAndroid Build Coastguard Worker     chunk_type: Le16, /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
83*bb4ee6a4SAndroid Build Coastguard Worker     reserved1: u16,
84*bb4ee6a4SAndroid Build Coastguard Worker     chunk_sz: Le32, /* in blocks in output image */
85*bb4ee6a4SAndroid Build Coastguard Worker     total_sz: Le32, /* in bytes of chunk input file including chunk header and data */
86*bb4ee6a4SAndroid Build Coastguard Worker }
87*bb4ee6a4SAndroid Build Coastguard Worker 
88*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Debug, PartialEq, Eq)]
89*bb4ee6a4SAndroid Build Coastguard Worker enum Chunk {
90*bb4ee6a4SAndroid Build Coastguard Worker     Raw(u64), // Offset into the file
91*bb4ee6a4SAndroid Build Coastguard Worker     Fill([u8; 4]),
92*bb4ee6a4SAndroid Build Coastguard Worker     DontCare,
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Debug, PartialEq, Eq)]
96*bb4ee6a4SAndroid Build Coastguard Worker struct ChunkWithSize {
97*bb4ee6a4SAndroid Build Coastguard Worker     chunk: Chunk,
98*bb4ee6a4SAndroid Build Coastguard Worker     expanded_size: u64,
99*bb4ee6a4SAndroid Build Coastguard Worker }
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker /* Following a Raw or Fill or CRC32 chunk is data.
102*bb4ee6a4SAndroid Build Coastguard Worker  *  For a Raw chunk, it's the data in chunk_sz * blk_sz.
103*bb4ee6a4SAndroid Build Coastguard Worker  *  For a Fill chunk, it's 4 bytes of the fill data.
104*bb4ee6a4SAndroid Build Coastguard Worker  *  For a CRC32 chunk, it's 4 bytes of CRC32
105*bb4ee6a4SAndroid Build Coastguard Worker  */
106*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
107*bb4ee6a4SAndroid Build Coastguard Worker pub struct AndroidSparse {
108*bb4ee6a4SAndroid Build Coastguard Worker     file: File,
109*bb4ee6a4SAndroid Build Coastguard Worker     total_size: u64,
110*bb4ee6a4SAndroid Build Coastguard Worker     chunks: BTreeMap<u64, ChunkWithSize>,
111*bb4ee6a4SAndroid Build Coastguard Worker }
112*bb4ee6a4SAndroid Build Coastguard Worker 
parse_chunk<T: Read + Seek>(input: &mut T, blk_sz: u64) -> Result<Option<ChunkWithSize>>113*bb4ee6a4SAndroid Build Coastguard Worker fn parse_chunk<T: Read + Seek>(input: &mut T, blk_sz: u64) -> Result<Option<ChunkWithSize>> {
114*bb4ee6a4SAndroid Build Coastguard Worker     const HEADER_SIZE: usize = mem::size_of::<ChunkHeader>();
115*bb4ee6a4SAndroid Build Coastguard Worker     let current_offset = input
116*bb4ee6a4SAndroid Build Coastguard Worker         .stream_position()
117*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(Error::ReadSpecificationError)?;
118*bb4ee6a4SAndroid Build Coastguard Worker     let mut chunk_header = ChunkHeader::new_zeroed();
119*bb4ee6a4SAndroid Build Coastguard Worker     input
120*bb4ee6a4SAndroid Build Coastguard Worker         .read_exact(chunk_header.as_bytes_mut())
121*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(Error::ReadSpecificationError)?;
122*bb4ee6a4SAndroid Build Coastguard Worker     let chunk_body_size = (chunk_header.total_sz.to_native() as usize)
123*bb4ee6a4SAndroid Build Coastguard Worker         .checked_sub(HEADER_SIZE)
124*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or(Error::InvalidSpecification(format!(
125*bb4ee6a4SAndroid Build Coastguard Worker             "chunk total_sz {} smaller than header size {}",
126*bb4ee6a4SAndroid Build Coastguard Worker             chunk_header.total_sz.to_native(),
127*bb4ee6a4SAndroid Build Coastguard Worker             HEADER_SIZE
128*bb4ee6a4SAndroid Build Coastguard Worker         )))?;
129*bb4ee6a4SAndroid Build Coastguard Worker     let chunk = match chunk_header.chunk_type.to_native() {
130*bb4ee6a4SAndroid Build Coastguard Worker         CHUNK_TYPE_RAW => {
131*bb4ee6a4SAndroid Build Coastguard Worker             input
132*bb4ee6a4SAndroid Build Coastguard Worker                 .seek(SeekFrom::Current(chunk_body_size as i64))
133*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(Error::ReadSpecificationError)?;
134*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::Raw(current_offset + HEADER_SIZE as u64)
135*bb4ee6a4SAndroid Build Coastguard Worker         }
136*bb4ee6a4SAndroid Build Coastguard Worker         CHUNK_TYPE_FILL => {
137*bb4ee6a4SAndroid Build Coastguard Worker             let mut fill_bytes = [0u8; 4];
138*bb4ee6a4SAndroid Build Coastguard Worker             if chunk_body_size != fill_bytes.len() {
139*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::InvalidSpecification(format!(
140*bb4ee6a4SAndroid Build Coastguard Worker                     "Fill chunk had bad size. Expected {}, was {}",
141*bb4ee6a4SAndroid Build Coastguard Worker                     fill_bytes.len(),
142*bb4ee6a4SAndroid Build Coastguard Worker                     chunk_body_size
143*bb4ee6a4SAndroid Build Coastguard Worker                 )));
144*bb4ee6a4SAndroid Build Coastguard Worker             }
145*bb4ee6a4SAndroid Build Coastguard Worker             input
146*bb4ee6a4SAndroid Build Coastguard Worker                 .read_exact(&mut fill_bytes)
147*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(Error::ReadSpecificationError)?;
148*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::Fill(fill_bytes)
149*bb4ee6a4SAndroid Build Coastguard Worker         }
150*bb4ee6a4SAndroid Build Coastguard Worker         CHUNK_TYPE_DONT_CARE => Chunk::DontCare,
151*bb4ee6a4SAndroid Build Coastguard Worker         CHUNK_TYPE_CRC32 => return Ok(None), // TODO(schuffelen): Validate crc32s in input
152*bb4ee6a4SAndroid Build Coastguard Worker         unknown_type => {
153*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidSpecification(format!(
154*bb4ee6a4SAndroid Build Coastguard Worker                 "Chunk had invalid type, was {:x}",
155*bb4ee6a4SAndroid Build Coastguard Worker                 unknown_type
156*bb4ee6a4SAndroid Build Coastguard Worker             )))
157*bb4ee6a4SAndroid Build Coastguard Worker         }
158*bb4ee6a4SAndroid Build Coastguard Worker     };
159*bb4ee6a4SAndroid Build Coastguard Worker     let expanded_size = chunk_header.chunk_sz.to_native() as u64 * blk_sz;
160*bb4ee6a4SAndroid Build Coastguard Worker     Ok(Some(ChunkWithSize {
161*bb4ee6a4SAndroid Build Coastguard Worker         chunk,
162*bb4ee6a4SAndroid Build Coastguard Worker         expanded_size,
163*bb4ee6a4SAndroid Build Coastguard Worker     }))
164*bb4ee6a4SAndroid Build Coastguard Worker }
165*bb4ee6a4SAndroid Build Coastguard Worker 
166*bb4ee6a4SAndroid Build Coastguard Worker impl AndroidSparse {
from_file(mut file: File) -> Result<AndroidSparse>167*bb4ee6a4SAndroid Build Coastguard Worker     pub fn from_file(mut file: File) -> Result<AndroidSparse> {
168*bb4ee6a4SAndroid Build Coastguard Worker         file.seek(SeekFrom::Start(0))
169*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::ReadSpecificationError)?;
170*bb4ee6a4SAndroid Build Coastguard Worker         let mut sparse_header = SparseHeader::new_zeroed();
171*bb4ee6a4SAndroid Build Coastguard Worker         file.read_exact(sparse_header.as_bytes_mut())
172*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::ReadSpecificationError)?;
173*bb4ee6a4SAndroid Build Coastguard Worker         if sparse_header.magic != SPARSE_HEADER_MAGIC {
174*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidSpecification(format!(
175*bb4ee6a4SAndroid Build Coastguard Worker                 "Header did not match magic constant. Expected {:x}, was {:x}",
176*bb4ee6a4SAndroid Build Coastguard Worker                 SPARSE_HEADER_MAGIC,
177*bb4ee6a4SAndroid Build Coastguard Worker                 sparse_header.magic.to_native()
178*bb4ee6a4SAndroid Build Coastguard Worker             )));
179*bb4ee6a4SAndroid Build Coastguard Worker         } else if sparse_header.major_version != MAJOR_VERSION {
180*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidSpecification(format!(
181*bb4ee6a4SAndroid Build Coastguard Worker                 "Header major version did not match. Expected {}, was {}",
182*bb4ee6a4SAndroid Build Coastguard Worker                 MAJOR_VERSION,
183*bb4ee6a4SAndroid Build Coastguard Worker                 sparse_header.major_version.to_native(),
184*bb4ee6a4SAndroid Build Coastguard Worker             )));
185*bb4ee6a4SAndroid Build Coastguard Worker         } else if sparse_header.chunk_hdr_size.to_native() as usize != mem::size_of::<ChunkHeader>()
186*bb4ee6a4SAndroid Build Coastguard Worker         {
187*bb4ee6a4SAndroid Build Coastguard Worker             // The canonical parser for this format allows `chunk_hdr_size >= sizeof(ChunkHeader)`,
188*bb4ee6a4SAndroid Build Coastguard Worker             // but we've chosen to be stricter for simplicity.
189*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidSpecification(format!(
190*bb4ee6a4SAndroid Build Coastguard Worker                 "Chunk header size does not match chunk header struct, expected {}, was {}",
191*bb4ee6a4SAndroid Build Coastguard Worker                 sparse_header.chunk_hdr_size.to_native(),
192*bb4ee6a4SAndroid Build Coastguard Worker                 mem::size_of::<ChunkHeader>()
193*bb4ee6a4SAndroid Build Coastguard Worker             )));
194*bb4ee6a4SAndroid Build Coastguard Worker         }
195*bb4ee6a4SAndroid Build Coastguard Worker         let block_size = sparse_header.blk_sz.to_native() as u64;
196*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = (0..sparse_header.total_chunks.to_native())
197*bb4ee6a4SAndroid Build Coastguard Worker             .filter_map(|_| parse_chunk(&mut file, block_size).transpose())
198*bb4ee6a4SAndroid Build Coastguard Worker             .collect::<Result<Vec<ChunkWithSize>>>()?;
199*bb4ee6a4SAndroid Build Coastguard Worker         let total_size =
200*bb4ee6a4SAndroid Build Coastguard Worker             sparse_header.total_blks.to_native() as u64 * sparse_header.blk_sz.to_native() as u64;
201*bb4ee6a4SAndroid Build Coastguard Worker         AndroidSparse::from_parts(file, total_size, chunks)
202*bb4ee6a4SAndroid Build Coastguard Worker     }
203*bb4ee6a4SAndroid Build Coastguard Worker 
from_parts(file: File, size: u64, chunks: Vec<ChunkWithSize>) -> Result<AndroidSparse>204*bb4ee6a4SAndroid Build Coastguard Worker     fn from_parts(file: File, size: u64, chunks: Vec<ChunkWithSize>) -> Result<AndroidSparse> {
205*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunks_map: BTreeMap<u64, ChunkWithSize> = BTreeMap::new();
206*bb4ee6a4SAndroid Build Coastguard Worker         let mut expanded_location: u64 = 0;
207*bb4ee6a4SAndroid Build Coastguard Worker         for chunk_with_size in chunks {
208*bb4ee6a4SAndroid Build Coastguard Worker             let size = chunk_with_size.expanded_size;
209*bb4ee6a4SAndroid Build Coastguard Worker             if chunks_map
210*bb4ee6a4SAndroid Build Coastguard Worker                 .insert(expanded_location, chunk_with_size)
211*bb4ee6a4SAndroid Build Coastguard Worker                 .is_some()
212*bb4ee6a4SAndroid Build Coastguard Worker             {
213*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::InvalidSpecification(format!(
214*bb4ee6a4SAndroid Build Coastguard Worker                     "Two chunks were at {}",
215*bb4ee6a4SAndroid Build Coastguard Worker                     expanded_location
216*bb4ee6a4SAndroid Build Coastguard Worker                 )));
217*bb4ee6a4SAndroid Build Coastguard Worker             }
218*bb4ee6a4SAndroid Build Coastguard Worker             expanded_location += size;
219*bb4ee6a4SAndroid Build Coastguard Worker         }
220*bb4ee6a4SAndroid Build Coastguard Worker         let image = AndroidSparse {
221*bb4ee6a4SAndroid Build Coastguard Worker             file,
222*bb4ee6a4SAndroid Build Coastguard Worker             total_size: size,
223*bb4ee6a4SAndroid Build Coastguard Worker             chunks: chunks_map,
224*bb4ee6a4SAndroid Build Coastguard Worker         };
225*bb4ee6a4SAndroid Build Coastguard Worker         let calculated_len: u64 = image.chunks.iter().map(|x| x.1.expanded_size).sum();
226*bb4ee6a4SAndroid Build Coastguard Worker         if calculated_len != size {
227*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidSpecification(format!(
228*bb4ee6a4SAndroid Build Coastguard Worker                 "Header promised size {}, chunks added up to {}",
229*bb4ee6a4SAndroid Build Coastguard Worker                 size, calculated_len
230*bb4ee6a4SAndroid Build Coastguard Worker             )));
231*bb4ee6a4SAndroid Build Coastguard Worker         }
232*bb4ee6a4SAndroid Build Coastguard Worker         Ok(image)
233*bb4ee6a4SAndroid Build Coastguard Worker     }
234*bb4ee6a4SAndroid Build Coastguard Worker }
235*bb4ee6a4SAndroid Build Coastguard Worker 
236*bb4ee6a4SAndroid Build Coastguard Worker impl DiskGetLen for AndroidSparse {
get_len(&self) -> io::Result<u64>237*bb4ee6a4SAndroid Build Coastguard Worker     fn get_len(&self) -> io::Result<u64> {
238*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.total_size)
239*bb4ee6a4SAndroid Build Coastguard Worker     }
240*bb4ee6a4SAndroid Build Coastguard Worker }
241*bb4ee6a4SAndroid Build Coastguard Worker 
242*bb4ee6a4SAndroid Build Coastguard Worker impl FileSetLen for AndroidSparse {
set_len(&self, _len: u64) -> io::Result<()>243*bb4ee6a4SAndroid Build Coastguard Worker     fn set_len(&self, _len: u64) -> io::Result<()> {
244*bb4ee6a4SAndroid Build Coastguard Worker         Err(io::Error::new(
245*bb4ee6a4SAndroid Build Coastguard Worker             ErrorKind::PermissionDenied,
246*bb4ee6a4SAndroid Build Coastguard Worker             "unsupported operation",
247*bb4ee6a4SAndroid Build Coastguard Worker         ))
248*bb4ee6a4SAndroid Build Coastguard Worker     }
249*bb4ee6a4SAndroid Build Coastguard Worker }
250*bb4ee6a4SAndroid Build Coastguard Worker 
251*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for AndroidSparse {
as_raw_descriptor(&self) -> RawDescriptor252*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
253*bb4ee6a4SAndroid Build Coastguard Worker         self.file.as_raw_descriptor()
254*bb4ee6a4SAndroid Build Coastguard Worker     }
255*bb4ee6a4SAndroid Build Coastguard Worker }
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker // Performs reads up to the chunk boundary.
258*bb4ee6a4SAndroid Build Coastguard Worker impl FileReadWriteAtVolatile for AndroidSparse {
read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> io::Result<usize>259*bb4ee6a4SAndroid Build Coastguard Worker     fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> io::Result<usize> {
260*bb4ee6a4SAndroid Build Coastguard Worker         let found_chunk = self.chunks.range(..=offset).next_back();
261*bb4ee6a4SAndroid Build Coastguard Worker         let (
262*bb4ee6a4SAndroid Build Coastguard Worker             chunk_start,
263*bb4ee6a4SAndroid Build Coastguard Worker             ChunkWithSize {
264*bb4ee6a4SAndroid Build Coastguard Worker                 chunk,
265*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size,
266*bb4ee6a4SAndroid Build Coastguard Worker             },
267*bb4ee6a4SAndroid Build Coastguard Worker         ) = found_chunk.ok_or_else(|| {
268*bb4ee6a4SAndroid Build Coastguard Worker             io::Error::new(
269*bb4ee6a4SAndroid Build Coastguard Worker                 ErrorKind::UnexpectedEof,
270*bb4ee6a4SAndroid Build Coastguard Worker                 format!("no chunk for offset {}", offset),
271*bb4ee6a4SAndroid Build Coastguard Worker             )
272*bb4ee6a4SAndroid Build Coastguard Worker         })?;
273*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_offset = offset - chunk_start;
274*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_size = *expanded_size;
275*bb4ee6a4SAndroid Build Coastguard Worker         let subslice = if chunk_offset + (slice.size() as u64) > chunk_size {
276*bb4ee6a4SAndroid Build Coastguard Worker             slice
277*bb4ee6a4SAndroid Build Coastguard Worker                 .sub_slice(0, (chunk_size - chunk_offset) as usize)
278*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(|e| io::Error::new(ErrorKind::InvalidData, format!("{:?}", e)))?
279*bb4ee6a4SAndroid Build Coastguard Worker         } else {
280*bb4ee6a4SAndroid Build Coastguard Worker             slice
281*bb4ee6a4SAndroid Build Coastguard Worker         };
282*bb4ee6a4SAndroid Build Coastguard Worker         match chunk {
283*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::DontCare => {
284*bb4ee6a4SAndroid Build Coastguard Worker                 subslice.write_bytes(0);
285*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(subslice.size())
286*bb4ee6a4SAndroid Build Coastguard Worker             }
287*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::Raw(file_offset) => self
288*bb4ee6a4SAndroid Build Coastguard Worker                 .file
289*bb4ee6a4SAndroid Build Coastguard Worker                 .read_at_volatile(subslice, *file_offset + chunk_offset),
290*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::Fill(fill_bytes) => {
291*bb4ee6a4SAndroid Build Coastguard Worker                 let chunk_offset_mod = chunk_offset % fill_bytes.len() as u64;
292*bb4ee6a4SAndroid Build Coastguard Worker                 let filled_memory: Vec<u8> = fill_bytes
293*bb4ee6a4SAndroid Build Coastguard Worker                     .iter()
294*bb4ee6a4SAndroid Build Coastguard Worker                     .cloned()
295*bb4ee6a4SAndroid Build Coastguard Worker                     .cycle()
296*bb4ee6a4SAndroid Build Coastguard Worker                     .skip(chunk_offset_mod as usize)
297*bb4ee6a4SAndroid Build Coastguard Worker                     .take(subslice.size())
298*bb4ee6a4SAndroid Build Coastguard Worker                     .collect();
299*bb4ee6a4SAndroid Build Coastguard Worker                 subslice.copy_from(&filled_memory);
300*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(subslice.size())
301*bb4ee6a4SAndroid Build Coastguard Worker             }
302*bb4ee6a4SAndroid Build Coastguard Worker         }
303*bb4ee6a4SAndroid Build Coastguard Worker     }
write_at_volatile(&self, _slice: VolatileSlice, _offset: u64) -> io::Result<usize>304*bb4ee6a4SAndroid Build Coastguard Worker     fn write_at_volatile(&self, _slice: VolatileSlice, _offset: u64) -> io::Result<usize> {
305*bb4ee6a4SAndroid Build Coastguard Worker         Err(io::Error::new(
306*bb4ee6a4SAndroid Build Coastguard Worker             ErrorKind::PermissionDenied,
307*bb4ee6a4SAndroid Build Coastguard Worker             "unsupported operation",
308*bb4ee6a4SAndroid Build Coastguard Worker         ))
309*bb4ee6a4SAndroid Build Coastguard Worker     }
310*bb4ee6a4SAndroid Build Coastguard Worker }
311*bb4ee6a4SAndroid Build Coastguard Worker 
312*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/271381851): implement `try_clone`. It allows virtio-blk to run multiple workers.
313*bb4ee6a4SAndroid Build Coastguard Worker impl DiskFile for AndroidSparse {}
314*bb4ee6a4SAndroid Build Coastguard Worker 
315*bb4ee6a4SAndroid Build Coastguard Worker /// An Android Sparse disk that implements `AsyncDisk` for access.
316*bb4ee6a4SAndroid Build Coastguard Worker pub struct AsyncAndroidSparse {
317*bb4ee6a4SAndroid Build Coastguard Worker     inner: IoSource<File>,
318*bb4ee6a4SAndroid Build Coastguard Worker     total_size: u64,
319*bb4ee6a4SAndroid Build Coastguard Worker     chunks: BTreeMap<u64, ChunkWithSize>,
320*bb4ee6a4SAndroid Build Coastguard Worker }
321*bb4ee6a4SAndroid Build Coastguard Worker 
322*bb4ee6a4SAndroid Build Coastguard Worker impl ToAsyncDisk for AndroidSparse {
to_async_disk(self: Box<Self>, ex: &Executor) -> DiskResult<Box<dyn AsyncDisk>>323*bb4ee6a4SAndroid Build Coastguard Worker     fn to_async_disk(self: Box<Self>, ex: &Executor) -> DiskResult<Box<dyn AsyncDisk>> {
324*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(AsyncAndroidSparse {
325*bb4ee6a4SAndroid Build Coastguard Worker             inner: ex.async_from(self.file).map_err(DiskError::ToAsync)?,
326*bb4ee6a4SAndroid Build Coastguard Worker             total_size: self.total_size,
327*bb4ee6a4SAndroid Build Coastguard Worker             chunks: self.chunks,
328*bb4ee6a4SAndroid Build Coastguard Worker         }))
329*bb4ee6a4SAndroid Build Coastguard Worker     }
330*bb4ee6a4SAndroid Build Coastguard Worker }
331*bb4ee6a4SAndroid Build Coastguard Worker 
332*bb4ee6a4SAndroid Build Coastguard Worker impl DiskGetLen for AsyncAndroidSparse {
get_len(&self) -> io::Result<u64>333*bb4ee6a4SAndroid Build Coastguard Worker     fn get_len(&self) -> io::Result<u64> {
334*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.total_size)
335*bb4ee6a4SAndroid Build Coastguard Worker     }
336*bb4ee6a4SAndroid Build Coastguard Worker }
337*bb4ee6a4SAndroid Build Coastguard Worker 
338*bb4ee6a4SAndroid Build Coastguard Worker impl FileSetLen for AsyncAndroidSparse {
set_len(&self, _len: u64) -> io::Result<()>339*bb4ee6a4SAndroid Build Coastguard Worker     fn set_len(&self, _len: u64) -> io::Result<()> {
340*bb4ee6a4SAndroid Build Coastguard Worker         Err(io::Error::new(
341*bb4ee6a4SAndroid Build Coastguard Worker             ErrorKind::PermissionDenied,
342*bb4ee6a4SAndroid Build Coastguard Worker             "unsupported operation",
343*bb4ee6a4SAndroid Build Coastguard Worker         ))
344*bb4ee6a4SAndroid Build Coastguard Worker     }
345*bb4ee6a4SAndroid Build Coastguard Worker }
346*bb4ee6a4SAndroid Build Coastguard Worker 
347*bb4ee6a4SAndroid Build Coastguard Worker impl FileAllocate for AsyncAndroidSparse {
allocate(&self, _offset: u64, _length: u64) -> io::Result<()>348*bb4ee6a4SAndroid Build Coastguard Worker     fn allocate(&self, _offset: u64, _length: u64) -> io::Result<()> {
349*bb4ee6a4SAndroid Build Coastguard Worker         Err(io::Error::new(
350*bb4ee6a4SAndroid Build Coastguard Worker             ErrorKind::PermissionDenied,
351*bb4ee6a4SAndroid Build Coastguard Worker             "unsupported operation",
352*bb4ee6a4SAndroid Build Coastguard Worker         ))
353*bb4ee6a4SAndroid Build Coastguard Worker     }
354*bb4ee6a4SAndroid Build Coastguard Worker }
355*bb4ee6a4SAndroid Build Coastguard Worker 
356*bb4ee6a4SAndroid Build Coastguard Worker #[async_trait(?Send)]
357*bb4ee6a4SAndroid Build Coastguard Worker impl AsyncDisk for AsyncAndroidSparse {
flush(&self) -> crate::Result<()>358*bb4ee6a4SAndroid Build Coastguard Worker     async fn flush(&self) -> crate::Result<()> {
359*bb4ee6a4SAndroid Build Coastguard Worker         // android sparse is read-only, nothing to flush.
360*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
361*bb4ee6a4SAndroid Build Coastguard Worker     }
362*bb4ee6a4SAndroid Build Coastguard Worker 
fsync(&self) -> DiskResult<()>363*bb4ee6a4SAndroid Build Coastguard Worker     async fn fsync(&self) -> DiskResult<()> {
364*bb4ee6a4SAndroid Build Coastguard Worker         // Do nothing because it's read-only.
365*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
366*bb4ee6a4SAndroid Build Coastguard Worker     }
367*bb4ee6a4SAndroid Build Coastguard Worker 
fdatasync(&self) -> DiskResult<()>368*bb4ee6a4SAndroid Build Coastguard Worker     async fn fdatasync(&self) -> DiskResult<()> {
369*bb4ee6a4SAndroid Build Coastguard Worker         // Do nothing because it's read-only.
370*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
371*bb4ee6a4SAndroid Build Coastguard Worker     }
372*bb4ee6a4SAndroid Build Coastguard Worker 
373*bb4ee6a4SAndroid Build Coastguard Worker     /// Reads data from `file_offset` to the end of the current chunk and write them into memory
374*bb4ee6a4SAndroid Build Coastguard Worker     /// `mem` at `mem_offsets`.
read_to_mem<'a>( &'a self, file_offset: u64, mem: Arc<dyn BackingMemory + Send + Sync>, mem_offsets: cros_async::MemRegionIter<'a>, ) -> DiskResult<usize>375*bb4ee6a4SAndroid Build Coastguard Worker     async fn read_to_mem<'a>(
376*bb4ee6a4SAndroid Build Coastguard Worker         &'a self,
377*bb4ee6a4SAndroid Build Coastguard Worker         file_offset: u64,
378*bb4ee6a4SAndroid Build Coastguard Worker         mem: Arc<dyn BackingMemory + Send + Sync>,
379*bb4ee6a4SAndroid Build Coastguard Worker         mem_offsets: cros_async::MemRegionIter<'a>,
380*bb4ee6a4SAndroid Build Coastguard Worker     ) -> DiskResult<usize> {
381*bb4ee6a4SAndroid Build Coastguard Worker         let found_chunk = self.chunks.range(..=file_offset).next_back();
382*bb4ee6a4SAndroid Build Coastguard Worker         let (
383*bb4ee6a4SAndroid Build Coastguard Worker             chunk_start,
384*bb4ee6a4SAndroid Build Coastguard Worker             ChunkWithSize {
385*bb4ee6a4SAndroid Build Coastguard Worker                 chunk,
386*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size,
387*bb4ee6a4SAndroid Build Coastguard Worker             },
388*bb4ee6a4SAndroid Build Coastguard Worker         ) = found_chunk.ok_or(DiskError::ReadingData(io::Error::new(
389*bb4ee6a4SAndroid Build Coastguard Worker             ErrorKind::UnexpectedEof,
390*bb4ee6a4SAndroid Build Coastguard Worker             format!("no chunk for offset {}", file_offset),
391*bb4ee6a4SAndroid Build Coastguard Worker         )))?;
392*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_offset = file_offset - chunk_start;
393*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_size = *expanded_size;
394*bb4ee6a4SAndroid Build Coastguard Worker 
395*bb4ee6a4SAndroid Build Coastguard Worker         // Truncate `mem_offsets` to the remaining size of the current chunk.
396*bb4ee6a4SAndroid Build Coastguard Worker         let mem_offsets = mem_offsets.take_bytes((chunk_size - chunk_offset) as usize);
397*bb4ee6a4SAndroid Build Coastguard Worker         let mem_size = mem_offsets.clone().map(|x| x.len).sum();
398*bb4ee6a4SAndroid Build Coastguard Worker         match chunk {
399*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::DontCare => {
400*bb4ee6a4SAndroid Build Coastguard Worker                 for region in mem_offsets {
401*bb4ee6a4SAndroid Build Coastguard Worker                     mem.get_volatile_slice(region)
402*bb4ee6a4SAndroid Build Coastguard Worker                         .map_err(DiskError::GuestMemory)?
403*bb4ee6a4SAndroid Build Coastguard Worker                         .write_bytes(0);
404*bb4ee6a4SAndroid Build Coastguard Worker                 }
405*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(mem_size)
406*bb4ee6a4SAndroid Build Coastguard Worker             }
407*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::Raw(offset) => self
408*bb4ee6a4SAndroid Build Coastguard Worker                 .inner
409*bb4ee6a4SAndroid Build Coastguard Worker                 .read_to_mem(Some(offset + chunk_offset), mem, mem_offsets)
410*bb4ee6a4SAndroid Build Coastguard Worker                 .await
411*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(DiskError::ReadToMem),
412*bb4ee6a4SAndroid Build Coastguard Worker             Chunk::Fill(fill_bytes) => {
413*bb4ee6a4SAndroid Build Coastguard Worker                 let chunk_offset_mod = chunk_offset % fill_bytes.len() as u64;
414*bb4ee6a4SAndroid Build Coastguard Worker                 let filled_memory: Vec<u8> = fill_bytes
415*bb4ee6a4SAndroid Build Coastguard Worker                     .iter()
416*bb4ee6a4SAndroid Build Coastguard Worker                     .cloned()
417*bb4ee6a4SAndroid Build Coastguard Worker                     .cycle()
418*bb4ee6a4SAndroid Build Coastguard Worker                     .skip(chunk_offset_mod as usize)
419*bb4ee6a4SAndroid Build Coastguard Worker                     .take(mem_size)
420*bb4ee6a4SAndroid Build Coastguard Worker                     .collect();
421*bb4ee6a4SAndroid Build Coastguard Worker 
422*bb4ee6a4SAndroid Build Coastguard Worker                 let mut filled_count = 0;
423*bb4ee6a4SAndroid Build Coastguard Worker                 for region in mem_offsets {
424*bb4ee6a4SAndroid Build Coastguard Worker                     let buf = &filled_memory[filled_count..filled_count + region.len];
425*bb4ee6a4SAndroid Build Coastguard Worker                     mem.get_volatile_slice(region)
426*bb4ee6a4SAndroid Build Coastguard Worker                         .map_err(DiskError::GuestMemory)?
427*bb4ee6a4SAndroid Build Coastguard Worker                         .copy_from(buf);
428*bb4ee6a4SAndroid Build Coastguard Worker                     filled_count += region.len;
429*bb4ee6a4SAndroid Build Coastguard Worker                 }
430*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(mem_size)
431*bb4ee6a4SAndroid Build Coastguard Worker             }
432*bb4ee6a4SAndroid Build Coastguard Worker         }
433*bb4ee6a4SAndroid Build Coastguard Worker     }
434*bb4ee6a4SAndroid Build Coastguard Worker 
write_from_mem<'a>( &'a self, _file_offset: u64, _mem: Arc<dyn BackingMemory + Send + Sync>, _mem_offsets: cros_async::MemRegionIter<'a>, ) -> DiskResult<usize>435*bb4ee6a4SAndroid Build Coastguard Worker     async fn write_from_mem<'a>(
436*bb4ee6a4SAndroid Build Coastguard Worker         &'a self,
437*bb4ee6a4SAndroid Build Coastguard Worker         _file_offset: u64,
438*bb4ee6a4SAndroid Build Coastguard Worker         _mem: Arc<dyn BackingMemory + Send + Sync>,
439*bb4ee6a4SAndroid Build Coastguard Worker         _mem_offsets: cros_async::MemRegionIter<'a>,
440*bb4ee6a4SAndroid Build Coastguard Worker     ) -> DiskResult<usize> {
441*bb4ee6a4SAndroid Build Coastguard Worker         Err(DiskError::UnsupportedOperation)
442*bb4ee6a4SAndroid Build Coastguard Worker     }
443*bb4ee6a4SAndroid Build Coastguard Worker 
punch_hole(&self, _file_offset: u64, _length: u64) -> DiskResult<()>444*bb4ee6a4SAndroid Build Coastguard Worker     async fn punch_hole(&self, _file_offset: u64, _length: u64) -> DiskResult<()> {
445*bb4ee6a4SAndroid Build Coastguard Worker         Err(DiskError::UnsupportedOperation)
446*bb4ee6a4SAndroid Build Coastguard Worker     }
447*bb4ee6a4SAndroid Build Coastguard Worker 
write_zeroes_at(&self, _file_offset: u64, _length: u64) -> DiskResult<()>448*bb4ee6a4SAndroid Build Coastguard Worker     async fn write_zeroes_at(&self, _file_offset: u64, _length: u64) -> DiskResult<()> {
449*bb4ee6a4SAndroid Build Coastguard Worker         Err(DiskError::UnsupportedOperation)
450*bb4ee6a4SAndroid Build Coastguard Worker     }
451*bb4ee6a4SAndroid Build Coastguard Worker }
452*bb4ee6a4SAndroid Build Coastguard Worker 
453*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
454*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
455*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::Cursor;
456*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::Write;
457*bb4ee6a4SAndroid Build Coastguard Worker 
458*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
459*bb4ee6a4SAndroid Build Coastguard Worker 
460*bb4ee6a4SAndroid Build Coastguard Worker     const CHUNK_SIZE: usize = mem::size_of::<ChunkHeader>();
461*bb4ee6a4SAndroid Build Coastguard Worker 
462*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
parse_raw()463*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_raw() {
464*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_raw = ChunkHeader {
465*bb4ee6a4SAndroid Build Coastguard Worker             chunk_type: CHUNK_TYPE_RAW.into(),
466*bb4ee6a4SAndroid Build Coastguard Worker             reserved1: 0,
467*bb4ee6a4SAndroid Build Coastguard Worker             chunk_sz: 1.into(),
468*bb4ee6a4SAndroid Build Coastguard Worker             total_sz: (CHUNK_SIZE as u32 + 123).into(),
469*bb4ee6a4SAndroid Build Coastguard Worker         };
470*bb4ee6a4SAndroid Build Coastguard Worker         let header_bytes = chunk_raw.as_bytes();
471*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_bytes: Vec<u8> = Vec::new();
472*bb4ee6a4SAndroid Build Coastguard Worker         chunk_bytes.extend_from_slice(header_bytes);
473*bb4ee6a4SAndroid Build Coastguard Worker         chunk_bytes.extend_from_slice(&[0u8; 123]);
474*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_cursor = Cursor::new(chunk_bytes);
475*bb4ee6a4SAndroid Build Coastguard Worker         let chunk = parse_chunk(&mut chunk_cursor, 123)
476*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Failed to parse")
477*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Failed to determine chunk type");
478*bb4ee6a4SAndroid Build Coastguard Worker         let expected_chunk = ChunkWithSize {
479*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::Raw(CHUNK_SIZE as u64),
480*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 123,
481*bb4ee6a4SAndroid Build Coastguard Worker         };
482*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(expected_chunk, chunk);
483*bb4ee6a4SAndroid Build Coastguard Worker     }
484*bb4ee6a4SAndroid Build Coastguard Worker 
485*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
parse_dont_care()486*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_dont_care() {
487*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_raw = ChunkHeader {
488*bb4ee6a4SAndroid Build Coastguard Worker             chunk_type: CHUNK_TYPE_DONT_CARE.into(),
489*bb4ee6a4SAndroid Build Coastguard Worker             reserved1: 0,
490*bb4ee6a4SAndroid Build Coastguard Worker             chunk_sz: 100.into(),
491*bb4ee6a4SAndroid Build Coastguard Worker             total_sz: (CHUNK_SIZE as u32).into(),
492*bb4ee6a4SAndroid Build Coastguard Worker         };
493*bb4ee6a4SAndroid Build Coastguard Worker         let header_bytes = chunk_raw.as_bytes();
494*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_cursor = Cursor::new(header_bytes);
495*bb4ee6a4SAndroid Build Coastguard Worker         let chunk = parse_chunk(&mut chunk_cursor, 123)
496*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Failed to parse")
497*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Failed to determine chunk type");
498*bb4ee6a4SAndroid Build Coastguard Worker         let expected_chunk = ChunkWithSize {
499*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::DontCare,
500*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 12300,
501*bb4ee6a4SAndroid Build Coastguard Worker         };
502*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(expected_chunk, chunk);
503*bb4ee6a4SAndroid Build Coastguard Worker     }
504*bb4ee6a4SAndroid Build Coastguard Worker 
505*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
parse_fill()506*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_fill() {
507*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_raw = ChunkHeader {
508*bb4ee6a4SAndroid Build Coastguard Worker             chunk_type: CHUNK_TYPE_FILL.into(),
509*bb4ee6a4SAndroid Build Coastguard Worker             reserved1: 0,
510*bb4ee6a4SAndroid Build Coastguard Worker             chunk_sz: 100.into(),
511*bb4ee6a4SAndroid Build Coastguard Worker             total_sz: (CHUNK_SIZE as u32 + 4).into(),
512*bb4ee6a4SAndroid Build Coastguard Worker         };
513*bb4ee6a4SAndroid Build Coastguard Worker         let header_bytes = chunk_raw.as_bytes();
514*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_bytes: Vec<u8> = Vec::new();
515*bb4ee6a4SAndroid Build Coastguard Worker         chunk_bytes.extend_from_slice(header_bytes);
516*bb4ee6a4SAndroid Build Coastguard Worker         chunk_bytes.extend_from_slice(&[123u8; 4]);
517*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_cursor = Cursor::new(chunk_bytes);
518*bb4ee6a4SAndroid Build Coastguard Worker         let chunk = parse_chunk(&mut chunk_cursor, 123)
519*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Failed to parse")
520*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Failed to determine chunk type");
521*bb4ee6a4SAndroid Build Coastguard Worker         let expected_chunk = ChunkWithSize {
522*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::Fill([123, 123, 123, 123]),
523*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 12300,
524*bb4ee6a4SAndroid Build Coastguard Worker         };
525*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(expected_chunk, chunk);
526*bb4ee6a4SAndroid Build Coastguard Worker     }
527*bb4ee6a4SAndroid Build Coastguard Worker 
528*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
parse_crc32()529*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_crc32() {
530*bb4ee6a4SAndroid Build Coastguard Worker         let chunk_raw = ChunkHeader {
531*bb4ee6a4SAndroid Build Coastguard Worker             chunk_type: CHUNK_TYPE_CRC32.into(),
532*bb4ee6a4SAndroid Build Coastguard Worker             reserved1: 0,
533*bb4ee6a4SAndroid Build Coastguard Worker             chunk_sz: 0.into(),
534*bb4ee6a4SAndroid Build Coastguard Worker             total_sz: (CHUNK_SIZE as u32 + 4).into(),
535*bb4ee6a4SAndroid Build Coastguard Worker         };
536*bb4ee6a4SAndroid Build Coastguard Worker         let header_bytes = chunk_raw.as_bytes();
537*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_bytes: Vec<u8> = Vec::new();
538*bb4ee6a4SAndroid Build Coastguard Worker         chunk_bytes.extend_from_slice(header_bytes);
539*bb4ee6a4SAndroid Build Coastguard Worker         chunk_bytes.extend_from_slice(&[123u8; 4]);
540*bb4ee6a4SAndroid Build Coastguard Worker         let mut chunk_cursor = Cursor::new(chunk_bytes);
541*bb4ee6a4SAndroid Build Coastguard Worker         let chunk = parse_chunk(&mut chunk_cursor, 123).expect("Failed to parse");
542*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(None, chunk);
543*bb4ee6a4SAndroid Build Coastguard Worker     }
544*bb4ee6a4SAndroid Build Coastguard Worker 
test_image(chunks: Vec<ChunkWithSize>) -> AndroidSparse545*bb4ee6a4SAndroid Build Coastguard Worker     fn test_image(chunks: Vec<ChunkWithSize>) -> AndroidSparse {
546*bb4ee6a4SAndroid Build Coastguard Worker         let file = tempfile::tempfile().expect("failed to create tempfile");
547*bb4ee6a4SAndroid Build Coastguard Worker         let size = chunks.iter().map(|x| x.expanded_size).sum();
548*bb4ee6a4SAndroid Build Coastguard Worker         AndroidSparse::from_parts(file, size, chunks).expect("Could not create image")
549*bb4ee6a4SAndroid Build Coastguard Worker     }
550*bb4ee6a4SAndroid Build Coastguard Worker 
551*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read_dontcare()552*bb4ee6a4SAndroid Build Coastguard Worker     fn read_dontcare() {
553*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = vec![ChunkWithSize {
554*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::DontCare,
555*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 100,
556*bb4ee6a4SAndroid Build Coastguard Worker         }];
557*bb4ee6a4SAndroid Build Coastguard Worker         let image = test_image(chunks);
558*bb4ee6a4SAndroid Build Coastguard Worker         let mut input_memory = [55u8; 100];
559*bb4ee6a4SAndroid Build Coastguard Worker         image
560*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(VolatileSlice::new(&mut input_memory[..]), 0)
561*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not read");
562*bb4ee6a4SAndroid Build Coastguard Worker         let expected = [0u8; 100];
563*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(&expected[..], &input_memory[..]);
564*bb4ee6a4SAndroid Build Coastguard Worker     }
565*bb4ee6a4SAndroid Build Coastguard Worker 
566*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read_fill_simple()567*bb4ee6a4SAndroid Build Coastguard Worker     fn read_fill_simple() {
568*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = vec![ChunkWithSize {
569*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::Fill([10, 20, 10, 20]),
570*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 8,
571*bb4ee6a4SAndroid Build Coastguard Worker         }];
572*bb4ee6a4SAndroid Build Coastguard Worker         let image = test_image(chunks);
573*bb4ee6a4SAndroid Build Coastguard Worker         let mut input_memory = [55u8; 8];
574*bb4ee6a4SAndroid Build Coastguard Worker         image
575*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(VolatileSlice::new(&mut input_memory[..]), 0)
576*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not read");
577*bb4ee6a4SAndroid Build Coastguard Worker         let expected = [10, 20, 10, 20, 10, 20, 10, 20];
578*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(&expected[..], &input_memory[..]);
579*bb4ee6a4SAndroid Build Coastguard Worker     }
580*bb4ee6a4SAndroid Build Coastguard Worker 
581*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read_fill_edges()582*bb4ee6a4SAndroid Build Coastguard Worker     fn read_fill_edges() {
583*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = vec![ChunkWithSize {
584*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::Fill([10, 20, 30, 40]),
585*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 8,
586*bb4ee6a4SAndroid Build Coastguard Worker         }];
587*bb4ee6a4SAndroid Build Coastguard Worker         let image = test_image(chunks);
588*bb4ee6a4SAndroid Build Coastguard Worker         let mut input_memory = [55u8; 6];
589*bb4ee6a4SAndroid Build Coastguard Worker         image
590*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(VolatileSlice::new(&mut input_memory[..]), 1)
591*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not read");
592*bb4ee6a4SAndroid Build Coastguard Worker         let expected = [20, 30, 40, 10, 20, 30];
593*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(&expected[..], &input_memory[..]);
594*bb4ee6a4SAndroid Build Coastguard Worker     }
595*bb4ee6a4SAndroid Build Coastguard Worker 
596*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read_fill_offset_edges()597*bb4ee6a4SAndroid Build Coastguard Worker     fn read_fill_offset_edges() {
598*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = vec![
599*bb4ee6a4SAndroid Build Coastguard Worker             ChunkWithSize {
600*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::DontCare,
601*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 20,
602*bb4ee6a4SAndroid Build Coastguard Worker             },
603*bb4ee6a4SAndroid Build Coastguard Worker             ChunkWithSize {
604*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Fill([10, 20, 30, 40]),
605*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 100,
606*bb4ee6a4SAndroid Build Coastguard Worker             },
607*bb4ee6a4SAndroid Build Coastguard Worker         ];
608*bb4ee6a4SAndroid Build Coastguard Worker         let image = test_image(chunks);
609*bb4ee6a4SAndroid Build Coastguard Worker         let mut input_memory = [55u8; 7];
610*bb4ee6a4SAndroid Build Coastguard Worker         image
611*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(VolatileSlice::new(&mut input_memory[..]), 39)
612*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not read");
613*bb4ee6a4SAndroid Build Coastguard Worker         let expected = [40, 10, 20, 30, 40, 10, 20];
614*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(&expected[..], &input_memory[..]);
615*bb4ee6a4SAndroid Build Coastguard Worker     }
616*bb4ee6a4SAndroid Build Coastguard Worker 
617*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read_raw()618*bb4ee6a4SAndroid Build Coastguard Worker     fn read_raw() {
619*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = vec![ChunkWithSize {
620*bb4ee6a4SAndroid Build Coastguard Worker             chunk: Chunk::Raw(0),
621*bb4ee6a4SAndroid Build Coastguard Worker             expanded_size: 100,
622*bb4ee6a4SAndroid Build Coastguard Worker         }];
623*bb4ee6a4SAndroid Build Coastguard Worker         let mut image = test_image(chunks);
624*bb4ee6a4SAndroid Build Coastguard Worker         write!(image.file, "hello").expect("Failed to write into internal file");
625*bb4ee6a4SAndroid Build Coastguard Worker         let mut input_memory = [55u8; 5];
626*bb4ee6a4SAndroid Build Coastguard Worker         image
627*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(VolatileSlice::new(&mut input_memory[..]), 0)
628*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not read");
629*bb4ee6a4SAndroid Build Coastguard Worker         let expected = [104, 101, 108, 108, 111];
630*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(&expected[..], &input_memory[..]);
631*bb4ee6a4SAndroid Build Coastguard Worker     }
632*bb4ee6a4SAndroid Build Coastguard Worker 
633*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read_two_fills()634*bb4ee6a4SAndroid Build Coastguard Worker     fn read_two_fills() {
635*bb4ee6a4SAndroid Build Coastguard Worker         let chunks = vec![
636*bb4ee6a4SAndroid Build Coastguard Worker             ChunkWithSize {
637*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Fill([10, 20, 10, 20]),
638*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 4,
639*bb4ee6a4SAndroid Build Coastguard Worker             },
640*bb4ee6a4SAndroid Build Coastguard Worker             ChunkWithSize {
641*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Fill([30, 40, 30, 40]),
642*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 4,
643*bb4ee6a4SAndroid Build Coastguard Worker             },
644*bb4ee6a4SAndroid Build Coastguard Worker         ];
645*bb4ee6a4SAndroid Build Coastguard Worker         let image = test_image(chunks);
646*bb4ee6a4SAndroid Build Coastguard Worker         let mut input_memory = [55u8; 8];
647*bb4ee6a4SAndroid Build Coastguard Worker         image
648*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(VolatileSlice::new(&mut input_memory[..]), 0)
649*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not read");
650*bb4ee6a4SAndroid Build Coastguard Worker         let expected = [10, 20, 10, 20, 30, 40, 30, 40];
651*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(&expected[..], &input_memory[..]);
652*bb4ee6a4SAndroid Build Coastguard Worker     }
653*bb4ee6a4SAndroid Build Coastguard Worker 
654*bb4ee6a4SAndroid Build Coastguard Worker     /**
655*bb4ee6a4SAndroid Build Coastguard Worker      * Tests for Async.
656*bb4ee6a4SAndroid Build Coastguard Worker      */
657*bb4ee6a4SAndroid Build Coastguard Worker     use cros_async::MemRegion;
658*bb4ee6a4SAndroid Build Coastguard Worker     use cros_async::MemRegionIter;
659*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestAddress;
660*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestMemory;
661*bb4ee6a4SAndroid Build Coastguard Worker 
test_async_image( chunks: Vec<ChunkWithSize>, ex: &Executor, ) -> DiskResult<Box<dyn AsyncDisk>>662*bb4ee6a4SAndroid Build Coastguard Worker     fn test_async_image(
663*bb4ee6a4SAndroid Build Coastguard Worker         chunks: Vec<ChunkWithSize>,
664*bb4ee6a4SAndroid Build Coastguard Worker         ex: &Executor,
665*bb4ee6a4SAndroid Build Coastguard Worker     ) -> DiskResult<Box<dyn AsyncDisk>> {
666*bb4ee6a4SAndroid Build Coastguard Worker         Box::new(test_image(chunks)).to_async_disk(ex)
667*bb4ee6a4SAndroid Build Coastguard Worker     }
668*bb4ee6a4SAndroid Build Coastguard Worker 
669*bb4ee6a4SAndroid Build Coastguard Worker     /// Reads `len` bytes of data from `image` at 'offset'.
read_exact_at(image: &dyn AsyncDisk, offset: usize, len: usize) -> Vec<u8>670*bb4ee6a4SAndroid Build Coastguard Worker     async fn read_exact_at(image: &dyn AsyncDisk, offset: usize, len: usize) -> Vec<u8> {
671*bb4ee6a4SAndroid Build Coastguard Worker         let guest_mem = Arc::new(GuestMemory::new(&[(GuestAddress(0), 4096)]).unwrap());
672*bb4ee6a4SAndroid Build Coastguard Worker         // Fill in guest_mem with dirty data.
673*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem
674*bb4ee6a4SAndroid Build Coastguard Worker             .write_all_at_addr(&vec![55u8; len], GuestAddress(0))
675*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
676*bb4ee6a4SAndroid Build Coastguard Worker 
677*bb4ee6a4SAndroid Build Coastguard Worker         let mut count = 0usize;
678*bb4ee6a4SAndroid Build Coastguard Worker         while count < len {
679*bb4ee6a4SAndroid Build Coastguard Worker             let result = image
680*bb4ee6a4SAndroid Build Coastguard Worker                 .read_to_mem(
681*bb4ee6a4SAndroid Build Coastguard Worker                     (offset + count) as u64,
682*bb4ee6a4SAndroid Build Coastguard Worker                     guest_mem.clone(),
683*bb4ee6a4SAndroid Build Coastguard Worker                     MemRegionIter::new(&[MemRegion {
684*bb4ee6a4SAndroid Build Coastguard Worker                         offset: count as u64,
685*bb4ee6a4SAndroid Build Coastguard Worker                         len: len - count,
686*bb4ee6a4SAndroid Build Coastguard Worker                     }]),
687*bb4ee6a4SAndroid Build Coastguard Worker                 )
688*bb4ee6a4SAndroid Build Coastguard Worker                 .await;
689*bb4ee6a4SAndroid Build Coastguard Worker             count += result.unwrap();
690*bb4ee6a4SAndroid Build Coastguard Worker         }
691*bb4ee6a4SAndroid Build Coastguard Worker 
692*bb4ee6a4SAndroid Build Coastguard Worker         let mut buf = vec![0; len];
693*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem.read_at_addr(&mut buf, GuestAddress(0)).unwrap();
694*bb4ee6a4SAndroid Build Coastguard Worker         buf
695*bb4ee6a4SAndroid Build Coastguard Worker     }
696*bb4ee6a4SAndroid Build Coastguard Worker 
697*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_dontcare()698*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_dontcare() {
699*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
700*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
701*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
702*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::DontCare,
703*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 100,
704*bb4ee6a4SAndroid Build Coastguard Worker             }];
705*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
706*bb4ee6a4SAndroid Build Coastguard Worker             let buf = read_exact_at(&*image, 0, 100).await;
707*bb4ee6a4SAndroid Build Coastguard Worker             assert!(buf.iter().all(|x| *x == 0));
708*bb4ee6a4SAndroid Build Coastguard Worker         })
709*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
710*bb4ee6a4SAndroid Build Coastguard Worker     }
711*bb4ee6a4SAndroid Build Coastguard Worker 
712*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_dontcare_with_offsets()713*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_dontcare_with_offsets() {
714*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
715*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
716*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
717*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::DontCare,
718*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 10,
719*bb4ee6a4SAndroid Build Coastguard Worker             }];
720*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
721*bb4ee6a4SAndroid Build Coastguard Worker             // Prepare guest_mem with dirty data.
722*bb4ee6a4SAndroid Build Coastguard Worker             let guest_mem = Arc::new(GuestMemory::new(&[(GuestAddress(0), 4096)]).unwrap());
723*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem
724*bb4ee6a4SAndroid Build Coastguard Worker                 .write_all_at_addr(&[55u8; 20], GuestAddress(0))
725*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
726*bb4ee6a4SAndroid Build Coastguard Worker 
727*bb4ee6a4SAndroid Build Coastguard Worker             // Pass multiple `MemRegion` to `read_to_mem`.
728*bb4ee6a4SAndroid Build Coastguard Worker             image
729*bb4ee6a4SAndroid Build Coastguard Worker                 .read_to_mem(
730*bb4ee6a4SAndroid Build Coastguard Worker                     0,
731*bb4ee6a4SAndroid Build Coastguard Worker                     guest_mem.clone(),
732*bb4ee6a4SAndroid Build Coastguard Worker                     MemRegionIter::new(&[
733*bb4ee6a4SAndroid Build Coastguard Worker                         MemRegion { offset: 1, len: 3 },
734*bb4ee6a4SAndroid Build Coastguard Worker                         MemRegion { offset: 6, len: 2 },
735*bb4ee6a4SAndroid Build Coastguard Worker                     ]),
736*bb4ee6a4SAndroid Build Coastguard Worker                 )
737*bb4ee6a4SAndroid Build Coastguard Worker                 .await
738*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
739*bb4ee6a4SAndroid Build Coastguard Worker             let mut buf = vec![0; 10];
740*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem.read_at_addr(&mut buf, GuestAddress(0)).unwrap();
741*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [55, 0, 0, 0, 55, 55, 0, 0, 55, 55];
742*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(expected[..], buf[..]);
743*bb4ee6a4SAndroid Build Coastguard Worker         })
744*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
745*bb4ee6a4SAndroid Build Coastguard Worker     }
746*bb4ee6a4SAndroid Build Coastguard Worker 
747*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_fill_simple()748*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_fill_simple() {
749*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
750*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
751*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
752*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Fill([10, 20, 10, 20]),
753*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 8,
754*bb4ee6a4SAndroid Build Coastguard Worker             }];
755*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
756*bb4ee6a4SAndroid Build Coastguard Worker             let buf = read_exact_at(&*image, 0, 8).await;
757*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [10, 20, 10, 20, 10, 20, 10, 20];
758*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(expected[..], buf[..]);
759*bb4ee6a4SAndroid Build Coastguard Worker         })
760*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
761*bb4ee6a4SAndroid Build Coastguard Worker     }
762*bb4ee6a4SAndroid Build Coastguard Worker 
763*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_fill_simple_with_offset()764*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_fill_simple_with_offset() {
765*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
766*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
767*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
768*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Fill([10, 20, 10, 20]),
769*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 8,
770*bb4ee6a4SAndroid Build Coastguard Worker             }];
771*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
772*bb4ee6a4SAndroid Build Coastguard Worker             // Prepare guest_mem with dirty data.
773*bb4ee6a4SAndroid Build Coastguard Worker             let guest_mem = Arc::new(GuestMemory::new(&[(GuestAddress(0), 4096)]).unwrap());
774*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem
775*bb4ee6a4SAndroid Build Coastguard Worker                 .write_all_at_addr(&[55u8; 20], GuestAddress(0))
776*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
777*bb4ee6a4SAndroid Build Coastguard Worker 
778*bb4ee6a4SAndroid Build Coastguard Worker             // Pass multiple `MemRegion` to `read_to_mem`.
779*bb4ee6a4SAndroid Build Coastguard Worker             image
780*bb4ee6a4SAndroid Build Coastguard Worker                 .read_to_mem(
781*bb4ee6a4SAndroid Build Coastguard Worker                     0,
782*bb4ee6a4SAndroid Build Coastguard Worker                     guest_mem.clone(),
783*bb4ee6a4SAndroid Build Coastguard Worker                     MemRegionIter::new(&[
784*bb4ee6a4SAndroid Build Coastguard Worker                         MemRegion { offset: 1, len: 3 },
785*bb4ee6a4SAndroid Build Coastguard Worker                         MemRegion { offset: 6, len: 2 },
786*bb4ee6a4SAndroid Build Coastguard Worker                     ]),
787*bb4ee6a4SAndroid Build Coastguard Worker                 )
788*bb4ee6a4SAndroid Build Coastguard Worker                 .await
789*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
790*bb4ee6a4SAndroid Build Coastguard Worker             let mut buf = vec![0; 10];
791*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem.read_at_addr(&mut buf, GuestAddress(0)).unwrap();
792*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [55, 10, 20, 10, 55, 55, 20, 10, 55, 55];
793*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(expected[..], buf[..]);
794*bb4ee6a4SAndroid Build Coastguard Worker         })
795*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
796*bb4ee6a4SAndroid Build Coastguard Worker     }
797*bb4ee6a4SAndroid Build Coastguard Worker 
798*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_fill_edges()799*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_fill_edges() {
800*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
801*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
802*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
803*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Fill([10, 20, 30, 40]),
804*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 8,
805*bb4ee6a4SAndroid Build Coastguard Worker             }];
806*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
807*bb4ee6a4SAndroid Build Coastguard Worker             let buf = read_exact_at(&*image, 1, 6).await;
808*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [20, 30, 40, 10, 20, 30];
809*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(expected[..], buf[..]);
810*bb4ee6a4SAndroid Build Coastguard Worker         })
811*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
812*bb4ee6a4SAndroid Build Coastguard Worker     }
813*bb4ee6a4SAndroid Build Coastguard Worker 
814*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_fill_offset_edges()815*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_fill_offset_edges() {
816*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
817*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
818*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![
819*bb4ee6a4SAndroid Build Coastguard Worker                 ChunkWithSize {
820*bb4ee6a4SAndroid Build Coastguard Worker                     chunk: Chunk::DontCare,
821*bb4ee6a4SAndroid Build Coastguard Worker                     expanded_size: 20,
822*bb4ee6a4SAndroid Build Coastguard Worker                 },
823*bb4ee6a4SAndroid Build Coastguard Worker                 ChunkWithSize {
824*bb4ee6a4SAndroid Build Coastguard Worker                     chunk: Chunk::Fill([10, 20, 30, 40]),
825*bb4ee6a4SAndroid Build Coastguard Worker                     expanded_size: 100,
826*bb4ee6a4SAndroid Build Coastguard Worker                 },
827*bb4ee6a4SAndroid Build Coastguard Worker             ];
828*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
829*bb4ee6a4SAndroid Build Coastguard Worker             let buf = read_exact_at(&*image, 39, 7).await;
830*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [40, 10, 20, 30, 40, 10, 20];
831*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(expected[..], buf[..]);
832*bb4ee6a4SAndroid Build Coastguard Worker         })
833*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
834*bb4ee6a4SAndroid Build Coastguard Worker     }
835*bb4ee6a4SAndroid Build Coastguard Worker 
836*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_raw()837*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_raw() {
838*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
839*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
840*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
841*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Raw(0),
842*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 100,
843*bb4ee6a4SAndroid Build Coastguard Worker             }];
844*bb4ee6a4SAndroid Build Coastguard Worker             let mut image = Box::new(test_image(chunks));
845*bb4ee6a4SAndroid Build Coastguard Worker             write!(image.file, "hello").unwrap();
846*bb4ee6a4SAndroid Build Coastguard Worker             let async_image = image.to_async_disk(&ex).unwrap();
847*bb4ee6a4SAndroid Build Coastguard Worker             let buf = read_exact_at(&*async_image, 0, 5).await;
848*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [104, 101, 108, 108, 111];
849*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(&expected[..], &buf[..]);
850*bb4ee6a4SAndroid Build Coastguard Worker         })
851*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
852*bb4ee6a4SAndroid Build Coastguard Worker     }
853*bb4ee6a4SAndroid Build Coastguard Worker 
854*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_fill_raw_with_offset()855*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_fill_raw_with_offset() {
856*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
857*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
858*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![ChunkWithSize {
859*bb4ee6a4SAndroid Build Coastguard Worker                 chunk: Chunk::Raw(0),
860*bb4ee6a4SAndroid Build Coastguard Worker                 expanded_size: 100,
861*bb4ee6a4SAndroid Build Coastguard Worker             }];
862*bb4ee6a4SAndroid Build Coastguard Worker             let mut image = Box::new(test_image(chunks));
863*bb4ee6a4SAndroid Build Coastguard Worker             write!(image.file, "hello").unwrap();
864*bb4ee6a4SAndroid Build Coastguard Worker             let async_image = image.to_async_disk(&ex).unwrap();
865*bb4ee6a4SAndroid Build Coastguard Worker             // Prepare guest_mem with dirty data.
866*bb4ee6a4SAndroid Build Coastguard Worker             let guest_mem = Arc::new(GuestMemory::new(&[(GuestAddress(0), 4096)]).unwrap());
867*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem
868*bb4ee6a4SAndroid Build Coastguard Worker                 .write_all_at_addr(&[55u8; 20], GuestAddress(0))
869*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
870*bb4ee6a4SAndroid Build Coastguard Worker 
871*bb4ee6a4SAndroid Build Coastguard Worker             // Pass multiple `MemRegion` to `read_to_mem`.
872*bb4ee6a4SAndroid Build Coastguard Worker             async_image
873*bb4ee6a4SAndroid Build Coastguard Worker                 .read_to_mem(
874*bb4ee6a4SAndroid Build Coastguard Worker                     0,
875*bb4ee6a4SAndroid Build Coastguard Worker                     guest_mem.clone(),
876*bb4ee6a4SAndroid Build Coastguard Worker                     MemRegionIter::new(&[
877*bb4ee6a4SAndroid Build Coastguard Worker                         MemRegion { offset: 1, len: 3 },
878*bb4ee6a4SAndroid Build Coastguard Worker                         MemRegion { offset: 6, len: 2 },
879*bb4ee6a4SAndroid Build Coastguard Worker                     ]),
880*bb4ee6a4SAndroid Build Coastguard Worker                 )
881*bb4ee6a4SAndroid Build Coastguard Worker                 .await
882*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap();
883*bb4ee6a4SAndroid Build Coastguard Worker             let mut buf = vec![0; 10];
884*bb4ee6a4SAndroid Build Coastguard Worker             guest_mem.read_at_addr(&mut buf, GuestAddress(0)).unwrap();
885*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [55, 104, 101, 108, 55, 55, 108, 111, 55, 55];
886*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(expected[..], buf[..]);
887*bb4ee6a4SAndroid Build Coastguard Worker         })
888*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
889*bb4ee6a4SAndroid Build Coastguard Worker     }
890*bb4ee6a4SAndroid Build Coastguard Worker 
891*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
async_read_two_fills()892*bb4ee6a4SAndroid Build Coastguard Worker     fn async_read_two_fills() {
893*bb4ee6a4SAndroid Build Coastguard Worker         let ex = Executor::new().unwrap();
894*bb4ee6a4SAndroid Build Coastguard Worker         ex.run_until(async {
895*bb4ee6a4SAndroid Build Coastguard Worker             let chunks = vec![
896*bb4ee6a4SAndroid Build Coastguard Worker                 ChunkWithSize {
897*bb4ee6a4SAndroid Build Coastguard Worker                     chunk: Chunk::Fill([10, 20, 10, 20]),
898*bb4ee6a4SAndroid Build Coastguard Worker                     expanded_size: 4,
899*bb4ee6a4SAndroid Build Coastguard Worker                 },
900*bb4ee6a4SAndroid Build Coastguard Worker                 ChunkWithSize {
901*bb4ee6a4SAndroid Build Coastguard Worker                     chunk: Chunk::Fill([30, 40, 30, 40]),
902*bb4ee6a4SAndroid Build Coastguard Worker                     expanded_size: 4,
903*bb4ee6a4SAndroid Build Coastguard Worker                 },
904*bb4ee6a4SAndroid Build Coastguard Worker             ];
905*bb4ee6a4SAndroid Build Coastguard Worker             let image = test_async_image(chunks, &ex).unwrap();
906*bb4ee6a4SAndroid Build Coastguard Worker             let buf = read_exact_at(&*image, 0, 8).await;
907*bb4ee6a4SAndroid Build Coastguard Worker             let expected = [10, 20, 10, 20, 30, 40, 30, 40];
908*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(&expected[..], &buf[..]);
909*bb4ee6a4SAndroid Build Coastguard Worker         })
910*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
911*bb4ee6a4SAndroid Build Coastguard Worker     }
912*bb4ee6a4SAndroid Build Coastguard Worker }
913