Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/disk/src/sys/linux.rs
5394 views
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
use std::os::fd::AsRawFd;
10
11
use cros_async::Executor;
12
13
use crate::DiskFileParams;
14
use crate::Error;
15
use crate::Result;
16
use crate::SingleFileDisk;
17
18
pub 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(&params.path, &options)
23
.map_err(|e| Error::OpenFile(params.path.display().to_string(), e))?;
24
25
if params.lock {
26
// Lock the disk image to prevent other crosvm instances from using it.
27
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 O_DIRECT is requested, set the flag via fcntl. It is not done at
36
// open_file_or_reuse time because it will reuse existing fd and will
37
// not actually use the given OpenOptions.
38
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
45
pub fn apply_raw_disk_file_options(_raw_image: &File, _is_sparse_file: bool) -> Result<()> {
46
// No op on unix.
47
Ok(())
48
}
49
50
pub 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
61
impl 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)]
75
mod 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
)
101
.await;
102
assert_eq!(48, result.unwrap());
103
}
104
105
let ex = Executor::new().unwrap();
106
ex.run_until(read_zeros_async(&ex)).unwrap();
107
}
108
109
#[test]
110
fn write_async() {
111
async fn write_zeros_async(ex: &Executor) {
112
let guest_mem =
113
Arc::new(GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap());
114
let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
115
let async_file = SingleFileDisk::new(f, ex).unwrap();
116
let result = async_file
117
.write_from_mem(
118
0,
119
guest_mem,
120
MemRegionIter::new(&[MemRegion { offset: 0, len: 48 }]),
121
)
122
.await;
123
assert_eq!(48, result.unwrap());
124
}
125
126
let ex = Executor::new().unwrap();
127
ex.run_until(write_zeros_async(&ex)).unwrap();
128
}
129
130
#[test]
131
fn detect_image_type_raw() {
132
let mut t = tempfile::tempfile().unwrap();
133
// Fill the first block of the file with "random" data.
134
let buf = "ABCD".as_bytes().repeat(1024);
135
t.write_all(&buf).unwrap();
136
let image_type = detect_image_type(&t, false).expect("failed to detect image type");
137
assert_eq!(image_type, ImageType::Raw);
138
}
139
140
#[test]
141
#[cfg(feature = "qcow")]
142
fn detect_image_type_qcow2() {
143
let mut t = tempfile::tempfile().unwrap();
144
// Write the qcow2 magic signature. The rest of the header is not filled in, so if
145
// detect_image_type is ever updated to validate more of the header, this test would need
146
// to be updated.
147
let buf: &[u8] = &[0x51, 0x46, 0x49, 0xfb];
148
t.write_all(buf).unwrap();
149
let image_type = detect_image_type(&t, false).expect("failed to detect image type");
150
assert_eq!(image_type, ImageType::Qcow2);
151
}
152
153
#[test]
154
#[cfg(feature = "android-sparse")]
155
fn detect_image_type_android_sparse() {
156
let mut t = tempfile::tempfile().unwrap();
157
// Write the Android sparse magic signature. The rest of the header is not filled in, so if
158
// detect_image_type is ever updated to validate more of the header, this test would need
159
// to be updated.
160
let buf: &[u8] = &[0x3a, 0xff, 0x26, 0xed];
161
t.write_all(buf).unwrap();
162
let image_type = detect_image_type(&t, false).expect("failed to detect image type");
163
assert_eq!(image_type, ImageType::AndroidSparse);
164
}
165
166
#[test]
167
#[cfg(feature = "composite-disk")]
168
fn detect_image_type_composite() {
169
let mut t = tempfile::tempfile().unwrap();
170
// Write the composite disk magic signature. The rest of the header is not filled in, so if
171
// detect_image_type is ever updated to validate more of the header, this test would need
172
// to be updated.
173
let buf = "composite_disk\x1d".as_bytes();
174
t.write_all(buf).unwrap();
175
let image_type = detect_image_type(&t, false).expect("failed to detect image type");
176
assert_eq!(image_type, ImageType::CompositeDisk);
177
}
178
179
#[test]
180
fn detect_image_type_small_file() {
181
let mut t = tempfile::tempfile().unwrap();
182
// Write a file smaller than the four-byte qcow2/sparse magic to ensure the small file logic
183
// works correctly and handles it as a raw file.
184
let buf: &[u8] = &[0xAA, 0xBB];
185
t.write_all(buf).unwrap();
186
let image_type = detect_image_type(&t, false).expect("failed to detect image type");
187
assert_eq!(image_type, ImageType::Raw);
188
}
189
}
190
191