1use std::fs::File;
6use std::io::Read;
7use std::io::Seek;
8use std::io::SeekFrom;
9use std::os::fd::AsRawFd;
10
11use cros_async::Executor;
12
13use crate::DiskFileParams;
14use crate::Error;
15use crate::Result;
16use crate::SingleFileDisk;
17
18pub fn open_raw_disk_image(params: &DiskFileParams) -> Result<File> {
19 let mut options = File::options();
20 options.read(true).write(!params.is_read_only);
21
22 let raw_image = base::open_file_or_duplicate(¶ms.path, &options)
23 .map_err(|e| Error::OpenFile(params.path.display().to_string(), e))?;
24
25 if params.lock {
26 let lock_op = if params.is_read_only {
28 base::FlockOperation::LockShared
29 } else {
30 base::FlockOperation::LockExclusive
31 };
32 base::flock(&raw_image, lock_op, true).map_err(Error::LockFileFailure)?;
33 }
34
35 if params.is_direct {
39 base::add_fd_flags(raw_image.as_raw_fd(), libc::O_DIRECT).map_err(Error::DirectFailed)?;
40 }
41
42 Ok(raw_image)
43}
44
45pub fn apply_raw_disk_file_options(_raw_image: &File, _is_sparse_file: bool) -> Result<()> {
46 Ok(())
48}
49
50pub fn read_from_disk(
51 mut file: &File,
52 offset: u64,
53 buf: &mut [u8],
54 _overlapped_mode: bool,
55) -> Result<()> {
56 file.seek(SeekFrom::Start(offset))
57 .map_err(Error::SeekingFile)?;
58 file.read_exact(buf).map_err(Error::ReadingHeader)
59}
60
61impl SingleFileDisk {
62 pub fn new(disk: File, ex: &Executor) -> Result<Self> {
63 let is_block_device_file =
64 base::linux::is_block_file(&disk).map_err(Error::BlockDeviceNew)?;
65 ex.async_from(disk)
66 .map_err(Error::CreateSingleFileDisk)
67 .map(|inner| SingleFileDisk {
68 inner,
69 is_block_device_file,
70 })
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use std::fs::File;
77 use std::fs::OpenOptions;
78 use std::io::Write;
79
80 use base::pagesize;
81 use cros_async::Executor;
82 use cros_async::MemRegion;
83 use vm_memory::GuestAddress;
84 use vm_memory::GuestMemory;
85
86 use crate::*;
87
88 #[test]
89 fn read_async() {
90 async fn read_zeros_async(ex: &Executor) {
91 let guest_mem =
92 Arc::new(GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap());
93 let f = File::open("/dev/zero").unwrap();
94 let async_file = SingleFileDisk::new(f, ex).unwrap();
95 let result = async_file
96 .read_to_mem(
97 0,
98 guest_mem,
99 MemRegionIter::new(&[MemRegion { offset: 0, len: 48 }]),
100 Default::default(),
101 )
102 .await;
103 assert_eq!(48, result.unwrap());
104 }
105
106 let ex = Executor::new().unwrap();
107 ex.run_until(read_zeros_async(&ex)).unwrap();
108 }
109
110 #[test]
111 fn write_async() {
112 async fn write_zeros_async(ex: &Executor) {
113 let guest_mem =
114 Arc::new(GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap());
115 let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
116 let async_file = SingleFileDisk::new(f, ex).unwrap();
117 let result = async_file
118 .write_from_mem(
119 0,
120 guest_mem,
121 MemRegionIter::new(&[MemRegion { offset: 0, len: 48 }]),
122 Default::default(),
123 )
124 .await;
125 assert_eq!(48, result.unwrap());
126 }
127
128 let ex = Executor::new().unwrap();
129 ex.run_until(write_zeros_async(&ex)).unwrap();
130 }
131
132 #[test]
133 fn detect_image_type_raw() {
134 let mut t = tempfile::tempfile().unwrap();
135 let buf = "ABCD".as_bytes().repeat(1024);
137 t.write_all(&buf).unwrap();
138 let image_type = detect_image_type(&t, false).expect("failed to detect image type");
139 assert_eq!(image_type, ImageType::Raw);
140 }
141
142 #[test]
143 #[cfg(feature = "qcow")]
144 fn detect_image_type_qcow2() {
145 let mut t = tempfile::tempfile().unwrap();
146 let buf: &[u8] = &[0x51, 0x46, 0x49, 0xfb];
150 t.write_all(buf).unwrap();
151 let image_type = detect_image_type(&t, false).expect("failed to detect image type");
152 assert_eq!(image_type, ImageType::Qcow2);
153 }
154
155 #[test]
156 #[cfg(feature = "android-sparse")]
157 fn detect_image_type_android_sparse() {
158 let mut t = tempfile::tempfile().unwrap();
159 let buf: &[u8] = &[0x3a, 0xff, 0x26, 0xed];
163 t.write_all(buf).unwrap();
164 let image_type = detect_image_type(&t, false).expect("failed to detect image type");
165 assert_eq!(image_type, ImageType::AndroidSparse);
166 }
167
168 #[test]
169 #[cfg(feature = "composite-disk")]
170 fn detect_image_type_composite() {
171 let mut t = tempfile::tempfile().unwrap();
172 let buf = "composite_disk\x1d".as_bytes();
176 t.write_all(buf).unwrap();
177 let image_type = detect_image_type(&t, false).expect("failed to detect image type");
178 assert_eq!(image_type, ImageType::CompositeDisk);
179 }
180
181 #[test]
182 fn detect_image_type_small_file() {
183 let mut t = tempfile::tempfile().unwrap();
184 let buf: &[u8] = &[0xAA, 0xBB];
187 t.write_all(buf).unwrap();
188 let image_type = detect_image_type(&t, false).expect("failed to detect image type");
189 assert_eq!(image_type, ImageType::Raw);
190 }
191}