diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2018-10-08 16:24:59 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-18 19:01:06 -0700 |
commit | 7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8 (patch) | |
tree | 921d3730fc6e576e54bfbb9c7a56f498c5ed9d19 /qcow_utils/src | |
parent | 2167ae953519e5dae023a92431a34a5a7b44546b (diff) | |
download | crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.tar crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.tar.gz crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.tar.bz2 crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.tar.lz crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.tar.xz crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.tar.zst crosvm-7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8.zip |
qcow: add convert API and export it in qcow_utils
This will be used in vm_concierge's ExportDiskImage function in order to allow a minimal qcow2 image to be written on the fly (containing only the required clusters in a tightly-packed image file). It also allows future flexibility to change the underlying disk image file format while still exporting qcow2 images (e.g. via `vmc export`). For testing, add a qcow_img `convert` command, which can convert between raw and qcow2 as both source and destination. BUG=None TEST=Use qcow_img to convert a raw image to qcow2 and back and verify its contents are the same as the original. Change-Id: I74167aca9a9c857d892e24adf5ee17afc0f6e6b5 Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1272060 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'qcow_utils/src')
-rw-r--r-- | qcow_utils/src/qcow_img.rs | 54 | ||||
-rw-r--r-- | qcow_utils/src/qcow_utils.h | 8 | ||||
-rw-r--r-- | qcow_utils/src/qcow_utils.rs | 31 |
3 files changed, 90 insertions, 3 deletions
diff --git a/qcow_utils/src/qcow_img.rs b/qcow_utils/src/qcow_img.rs index 1040de2..4f8be58 100644 --- a/qcow_utils/src/qcow_img.rs +++ b/qcow_utils/src/qcow_img.rs @@ -41,6 +41,10 @@ fn show_usage(program_name: &str) { "{} dd <file_name> <source_file> - Write bytes from the raw source_file to the file.", program_name ); + println!( + "{} convert <src_file> <dst_file> - Convert from src_file to dst_file.", + program_name + ); } fn main() -> std::result::Result<(), ()> { @@ -95,6 +99,14 @@ fn main() -> std::result::Result<(), ()> { }; dd(&matches.free[1], &matches.free[2], count) } + "convert" => { + if matches.free.len() < 2 { + println!("Source and destination files are required."); + show_usage(&args[0]); + return Err(()); + } + convert(&matches.free[1], &matches.free[2]) + } c => { println!("invalid subcommand: {:?}", c); Err(()) @@ -270,3 +282,45 @@ fn dd(file_path: &str, source_path: &str, count: Option<usize>) -> std::result:: Ok(()) } + +// Reads the file at `src_path` and writes it to `dst_path`. +// The output format is detected based on the `dst_path` file extension. +fn convert(src_path: &str, dst_path: &str) -> std::result::Result<(), ()> { + let src_file = match OpenOptions::new().read(true).open(src_path) { + Ok(f) => f, + Err(_) => { + println!("Failed to open source file {}", src_path); + return Err(()); + } + }; + + let dst_file = match OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(dst_path) + { + Ok(f) => f, + Err(_) => { + println!("Failed to open destination file {}", dst_path); + return Err(()); + } + }; + + let dst_type = if dst_path.ends_with("qcow2") { + qcow::ImageType::Qcow2 + } else { + qcow::ImageType::Raw + }; + + match qcow::convert(src_file, dst_file, dst_type) { + Ok(_) => { + println!("Converted {} to {}", src_path, dst_path); + Ok(()) + } + Err(_) => { + println!("Failed to copy from {} to {}", src_path, dst_path); + Err(()) + } + } +} diff --git a/qcow_utils/src/qcow_utils.h b/qcow_utils/src/qcow_utils.h index e7db911..30c9715 100644 --- a/qcow_utils/src/qcow_utils.h +++ b/qcow_utils/src/qcow_utils.h @@ -13,6 +13,14 @@ 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); +// 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); + +// Copy the source disk image from `src_fd` into `dst_fd` as a raw image file. +// Returns 0 on success or a negated errno value on failure. +int convert_to_raw(int src_fd, int dst_fd); + #ifdef __cplusplus }; #endif diff --git a/qcow_utils/src/qcow_utils.rs b/qcow_utils/src/qcow_utils.rs index c96678e..ea84b62 100644 --- a/qcow_utils/src/qcow_utils.rs +++ b/qcow_utils/src/qcow_utils.rs @@ -7,12 +7,13 @@ extern crate libc; extern crate qcow; -use libc::EINVAL; +use libc::{EINVAL, EIO}; use std::ffi::CStr; -use std::fs::OpenOptions; +use std::fs::{File, OpenOptions}; use std::os::raw::{c_char, c_int}; +use std::os::unix::io::FromRawFd; -use qcow::QcowFile; +use qcow::{ImageType, QcowFile}; #[no_mangle] pub unsafe extern "C" fn create_qcow_with_size(path: *const c_char, virtual_size: u64) -> c_int { @@ -42,3 +43,27 @@ pub unsafe extern "C" fn create_qcow_with_size(path: *const c_char, virtual_size Err(_) => -1, } } + +#[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. + let src_file = File::from_raw_fd(src_fd); + let dst_file = File::from_raw_fd(dst_fd); + + match qcow::convert(src_file, dst_file, ImageType::Qcow2) { + Ok(_) => 0, + Err(_) => -EIO, + } +} + +#[no_mangle] +pub unsafe extern "C" fn convert_to_raw(src_fd: c_int, dst_fd: c_int) -> c_int { + // The caller is responsible for passing valid file descriptors. + let src_file = File::from_raw_fd(src_fd); + let dst_file = File::from_raw_fd(dst_fd); + + match qcow::convert(src_file, dst_file, ImageType::Raw) { + Ok(_) => 0, + Err(_) => -EIO, + } +} |