• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fs::File;
6 use std::io::Read;
7 use std::io::Seek;
8 use std::io::SeekFrom;
9 
10 use cros_async::Executor;
11 
12 use crate::Error;
13 use crate::Result;
14 use crate::SingleFileDisk;
15 
apply_raw_disk_file_options(_raw_image: &File, _is_sparse_file: bool) -> Result<()>16 pub fn apply_raw_disk_file_options(_raw_image: &File, _is_sparse_file: bool) -> Result<()> {
17     // No op on unix.
18     Ok(())
19 }
20 
read_from_disk( mut file: &File, offset: u64, buf: &mut [u8], _overlapped_mode: bool, ) -> Result<()>21 pub fn read_from_disk(
22     mut file: &File,
23     offset: u64,
24     buf: &mut [u8],
25     _overlapped_mode: bool,
26 ) -> Result<()> {
27     file.seek(SeekFrom::Start(offset))
28         .map_err(Error::SeekingFile)?;
29     file.read_exact(buf).map_err(Error::ReadingHeader)
30 }
31 
32 impl SingleFileDisk {
new(disk: File, ex: &Executor) -> Result<Self>33     pub fn new(disk: File, ex: &Executor) -> Result<Self> {
34         let is_block_device_file =
35             base::linux::is_block_file(&disk).map_err(Error::BlockDeviceNew)?;
36         ex.async_from(disk)
37             .map_err(Error::CreateSingleFileDisk)
38             .map(|inner| SingleFileDisk {
39                 inner,
40                 is_block_device_file,
41             })
42     }
43 }
44 
45 #[cfg(test)]
46 mod tests {
47     use std::fs::File;
48     use std::fs::OpenOptions;
49     use std::io::Write;
50 
51     use base::pagesize;
52     use cros_async::Executor;
53     use cros_async::MemRegion;
54     use vm_memory::GuestAddress;
55     use vm_memory::GuestMemory;
56 
57     use crate::*;
58 
59     #[test]
read_async()60     fn read_async() {
61         async fn read_zeros_async(ex: &Executor) {
62             let guest_mem =
63                 Arc::new(GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap());
64             let f = File::open("/dev/zero").unwrap();
65             let async_file = SingleFileDisk::new(f, ex).unwrap();
66             let result = async_file
67                 .read_to_mem(
68                     0,
69                     guest_mem,
70                     MemRegionIter::new(&[MemRegion { offset: 0, len: 48 }]),
71                 )
72                 .await;
73             assert_eq!(48, result.unwrap());
74         }
75 
76         let ex = Executor::new().unwrap();
77         ex.run_until(read_zeros_async(&ex)).unwrap();
78     }
79 
80     #[test]
write_async()81     fn write_async() {
82         async fn write_zeros_async(ex: &Executor) {
83             let guest_mem =
84                 Arc::new(GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap());
85             let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
86             let async_file = SingleFileDisk::new(f, ex).unwrap();
87             let result = async_file
88                 .write_from_mem(
89                     0,
90                     guest_mem,
91                     MemRegionIter::new(&[MemRegion { offset: 0, len: 48 }]),
92                 )
93                 .await;
94             assert_eq!(48, result.unwrap());
95         }
96 
97         let ex = Executor::new().unwrap();
98         ex.run_until(write_zeros_async(&ex)).unwrap();
99     }
100 
101     #[test]
detect_image_type_raw()102     fn detect_image_type_raw() {
103         let mut t = tempfile::tempfile().unwrap();
104         // Fill the first block of the file with "random" data.
105         let buf = "ABCD".as_bytes().repeat(1024);
106         t.write_all(&buf).unwrap();
107         let image_type = detect_image_type(&t, false).expect("failed to detect image type");
108         assert_eq!(image_type, ImageType::Raw);
109     }
110 
111     #[test]
112     #[cfg(feature = "qcow")]
detect_image_type_qcow2()113     fn detect_image_type_qcow2() {
114         let mut t = tempfile::tempfile().unwrap();
115         // Write the qcow2 magic signature. The rest of the header is not filled in, so if
116         // detect_image_type is ever updated to validate more of the header, this test would need
117         // to be updated.
118         let buf: &[u8] = &[0x51, 0x46, 0x49, 0xfb];
119         t.write_all(buf).unwrap();
120         let image_type = detect_image_type(&t, false).expect("failed to detect image type");
121         assert_eq!(image_type, ImageType::Qcow2);
122     }
123 
124     #[test]
125     #[cfg(feature = "android-sparse")]
detect_image_type_android_sparse()126     fn detect_image_type_android_sparse() {
127         let mut t = tempfile::tempfile().unwrap();
128         // Write the Android sparse magic signature. The rest of the header is not filled in, so if
129         // detect_image_type is ever updated to validate more of the header, this test would need
130         // to be updated.
131         let buf: &[u8] = &[0x3a, 0xff, 0x26, 0xed];
132         t.write_all(buf).unwrap();
133         let image_type = detect_image_type(&t, false).expect("failed to detect image type");
134         assert_eq!(image_type, ImageType::AndroidSparse);
135     }
136 
137     #[test]
138     #[cfg(feature = "composite-disk")]
detect_image_type_composite()139     fn detect_image_type_composite() {
140         let mut t = tempfile::tempfile().unwrap();
141         // Write the composite disk magic signature. The rest of the header is not filled in, so if
142         // detect_image_type is ever updated to validate more of the header, this test would need
143         // to be updated.
144         let buf = "composite_disk\x1d".as_bytes();
145         t.write_all(buf).unwrap();
146         let image_type = detect_image_type(&t, false).expect("failed to detect image type");
147         assert_eq!(image_type, ImageType::CompositeDisk);
148     }
149 
150     #[test]
detect_image_type_small_file()151     fn detect_image_type_small_file() {
152         let mut t = tempfile::tempfile().unwrap();
153         // Write a file smaller than the four-byte qcow2/sparse magic to ensure the small file logic
154         // works correctly and handles it as a raw file.
155         let buf: &[u8] = &[0xAA, 0xBB];
156         t.write_all(buf).unwrap();
157         let image_type = detect_image_type(&t, false).expect("failed to detect image type");
158         assert_eq!(image_type, ImageType::Raw);
159     }
160 }
161