mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 12:34:31 +00:00
qcow_utils: add disk image expand function
This exports a new C API to resize a disk image. The new function is intended to only expand (increase in size) to avoid accidentally truncating user data due to bugs elsewhere. BUG=chromium:858815 TEST=build_test.py Change-Id: I6f834209aba693618e0f51d920e7b73d4f2a9dfc Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1464384 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Zach Reizner <zachr@chromium.org>
This commit is contained in:
parent
d39dd9af71
commit
348ccf1102
2 changed files with 68 additions and 1 deletions
|
@ -13,6 +13,10 @@ extern "C" {
|
|||
// Create a basic, empty qcow2 file that can grow to `virtual_size` at `path`.
|
||||
int create_qcow_with_size(const char *path, uint64_t virtual_size);
|
||||
|
||||
// Attempt to resize the disk image at `path` to `virtual_size` bytes if
|
||||
// the disk image is currently smaller than the requested size.
|
||||
int expand_disk_image(const char *path, uint64_t virtual_size);
|
||||
|
||||
// Copy the source disk image from `src_fd` into `dst_fd` as a qcow2 image file.
|
||||
// Returns 0 on success or a negated errno value on failure.
|
||||
int convert_to_qcow2(int src_fd, int dst_fd);
|
||||
|
|
|
@ -6,16 +6,22 @@
|
|||
|
||||
extern crate libc;
|
||||
extern crate qcow;
|
||||
extern crate sys_util;
|
||||
|
||||
use libc::{EBADFD, EINVAL, EIO};
|
||||
use libc::{EBADFD, EINVAL, EIO, ENOSYS};
|
||||
use std::ffi::CStr;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::mem::forget;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::panic::catch_unwind;
|
||||
|
||||
use qcow::{ImageType, QcowFile};
|
||||
use sys_util::{flock, FileSetLen, FlockOperation};
|
||||
|
||||
trait DiskFile: FileSetLen + Seek {}
|
||||
impl<D: FileSetLen + Seek> DiskFile for D {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn create_qcow_with_size(path: *const c_char, virtual_size: u64) -> c_int {
|
||||
|
@ -46,6 +52,63 @@ pub unsafe extern "C" fn create_qcow_with_size(path: *const c_char, virtual_size
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn expand_disk_image(path: *const c_char, virtual_size: u64) -> c_int {
|
||||
// NULL pointers are checked, but this will access any other invalid pointer passed from C
|
||||
// code. It's the caller's responsibility to pass a valid pointer.
|
||||
if path.is_null() {
|
||||
return -EINVAL;
|
||||
}
|
||||
let c_str = CStr::from_ptr(path);
|
||||
let file_path = match c_str.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return -EINVAL,
|
||||
};
|
||||
|
||||
let raw_image = match OpenOptions::new().read(true).write(true).open(file_path) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return -EIO,
|
||||
};
|
||||
|
||||
// Lock the disk image to prevent other processes from using it.
|
||||
if let Err(_) = flock(&raw_image, FlockOperation::LockExclusive, true) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
let image_type = match qcow::detect_image_type(&raw_image) {
|
||||
Ok(t) => t,
|
||||
Err(_) => return -EINVAL,
|
||||
};
|
||||
|
||||
let mut disk_image: Box<DiskFile> = match image_type {
|
||||
ImageType::Raw => Box::new(raw_image),
|
||||
ImageType::Qcow2 => match QcowFile::from(raw_image) {
|
||||
Ok(f) => Box::new(f),
|
||||
Err(_) => return -EINVAL,
|
||||
},
|
||||
};
|
||||
|
||||
// For safety against accidentally shrinking the disk image due to a
|
||||
// programming error elsewhere, verify that the new size is larger than
|
||||
// the current size. This is safe against races due to the exclusive
|
||||
// flock() taken above - this is only an advisory lock, but it is also
|
||||
// acquired by other instances of this function as well as crosvm
|
||||
// itself when running a VM, so this should be safe in all cases that
|
||||
// can access a disk image in normal operation.
|
||||
let current_size = match disk_image.seek(SeekFrom::End(0)) {
|
||||
Ok(len) => len,
|
||||
Err(_) => return -EIO,
|
||||
};
|
||||
if current_size >= virtual_size {
|
||||
return 0;
|
||||
}
|
||||
|
||||
match disk_image.set_len(virtual_size) {
|
||||
Ok(_) => 0,
|
||||
Err(_) => -ENOSYS,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn convert_to_qcow2(src_fd: c_int, dst_fd: c_int) -> c_int {
|
||||
// The caller is responsible for passing valid file descriptors.
|
||||
|
|
Loading…
Reference in a new issue