diff --git a/Cargo.toml b/Cargo.toml index 9cd3fdc053..403f544866 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,7 +125,7 @@ balloon = ["devices/balloon", "vm_control/balloon"] chromeos = ["base/chromeos", "audio_cras", "devices/chromeos"] composite-disk = ["protos/composite-disk", "protobuf", "disk/composite-disk"] crash-report = [] -default = ["audio", "balloon", "gpu", "usb"] +default = ["audio", "balloon", "gpu", "qcow", "usb"] default-no-sandbox = [] direct = ["balloon", "devices/direct", "arch/direct", "x86_64/direct"] ffmpeg = ["devices/ffmpeg"] @@ -147,6 +147,7 @@ linux-aarch64 = ["all-linux"] plugin = ["protos/plugin", "crosvm_plugin", "kvm", "kvm_sys", "protobuf"] plugin-render-server = [] power-monitor-powerd = ["arch/power-monitor-powerd"] +qcow = ["disk/qcow"] slirp = ["devices/slirp"] tpm = ["devices/tpm"] usb = ["devices/usb"] diff --git a/disk/Cargo.toml b/disk/Cargo.toml index 7be3424fb6..0b4e28ae73 100644 --- a/disk/Cargo.toml +++ b/disk/Cargo.toml @@ -9,6 +9,7 @@ path = "src/disk.rs" [features] composite-disk = ["crc32fast", "protos", "protobuf", "uuid"] +qcow = [] [dependencies] async-trait = "*" diff --git a/disk/src/disk.rs b/disk/src/disk.rs index d5cb4a9af8..3b95e81ed7 100644 --- a/disk/src/disk.rs +++ b/disk/src/disk.rs @@ -32,8 +32,11 @@ use thiserror::Error as ThisError; mod asynchronous; pub(crate) use asynchronous::AsyncDiskFileWrapper; +#[cfg(feature = "qcow")] mod qcow; +#[cfg(feature = "qcow")] pub use qcow::QcowFile; +#[cfg(feature = "qcow")] pub use qcow::QCOW_MAGIC; mod sys; @@ -92,6 +95,7 @@ pub enum Error { MaxNestingDepthExceeded, #[error("failure to punch hole: {0}")] PunchHole(io::Error), + #[cfg(feature = "qcow")] #[error("failure in qcow: {0}")] QcowError(qcow::Error), #[error("failed to read data: {0}")] @@ -237,9 +241,11 @@ pub fn detect_image_type(file: &File) -> Result { } if let Some(magic4) = magic.data.get(0..4) { + #[cfg(feature = "qcow")] if magic4 == QCOW_MAGIC.to_be_bytes() { return Ok(ImageType::Qcow2); - } else if magic4 == SPARSE_HEADER_MAGIC.to_le_bytes() { + } + if magic4 == SPARSE_HEADER_MAGIC.to_le_bytes() { return Ok(ImageType::AndroidSparse); } } @@ -271,14 +277,18 @@ pub fn create_async_disk_file(raw_image: File) -> Result> { pub fn create_disk_file( raw_image: File, is_sparse_file: bool, - mut max_nesting_depth: u32, + // max_nesting_depth is only used if the composite-disk or qcow features are enabled. + #[allow(unused_variables)] mut max_nesting_depth: u32, // image_path is only used if the composite-disk feature is enabled. #[allow(unused_variables)] image_path: &Path, ) -> Result> { if max_nesting_depth == 0 { return Err(Error::MaxNestingDepthExceeded); } - max_nesting_depth -= 1; + #[allow(unused_assignments)] + { + max_nesting_depth -= 1; + } let image_type = detect_image_type(&raw_image)?; Ok(match image_type { @@ -286,6 +296,7 @@ pub fn create_disk_file( sys::apply_raw_disk_file_options(&raw_image, is_sparse_file)?; Box::new(raw_image) as Box } + #[cfg(feature = "qcow")] ImageType::Qcow2 => { Box::new(QcowFile::from(raw_image, max_nesting_depth).map_err(Error::QcowError)?) as Box @@ -303,12 +314,12 @@ pub fn create_disk_file( .map_err(Error::CreateCompositeDisk)?, ) as Box } - #[cfg(not(feature = "composite-disk"))] - ImageType::CompositeDisk => return Err(Error::UnknownType), ImageType::AndroidSparse => { Box::new(AndroidSparse::from_file(raw_image).map_err(Error::CreateAndroidSparseDisk)?) as Box } + #[allow(unreachable_patterns)] + _ => return Err(Error::UnknownType), }) } diff --git a/disk/src/sys/unix.rs b/disk/src/sys/unix.rs index ec75eb723f..60d16262de 100644 --- a/disk/src/sys/unix.rs +++ b/disk/src/sys/unix.rs @@ -67,6 +67,7 @@ mod tests { } #[test] + #[cfg(feature = "qcow")] fn detect_image_type_qcow2() { let mut t = tempfile::tempfile().unwrap(); // Write the qcow2 magic signature. The rest of the header is not filled in, so if diff --git a/qcow_utils/src/qcow_utils.rs b/qcow_utils/src/qcow_utils.rs index 7cf52c980c..0e99769add 100644 --- a/qcow_utils/src/qcow_utils.rs +++ b/qcow_utils/src/qcow_utils.rs @@ -13,38 +13,45 @@ use base::flock; use base::FlockOperation; use disk::DiskFile; use disk::ImageType; +#[cfg(feature = "qcow")] use disk::QcowFile; use libc::EINVAL; use libc::EIO; use libc::ENOSYS; #[no_mangle] +#[allow(unused_variables)] // If the qcow feature is disabled, this function becomes an empty stub. pub unsafe extern "C" fn create_qcow_with_size(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 file = match OpenOptions::new() - .create(true) - .read(true) - .write(true) - .open(file_path) + #[cfg(feature = "qcow")] { - Ok(f) => f, - Err(_) => return -1, - }; + // 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, + }; - match QcowFile::new(file, virtual_size) { - Ok(_) => 0, - Err(_) => -1, + let file = match OpenOptions::new() + .create(true) + .read(true) + .write(true) + .open(file_path) + { + Ok(f) => f, + Err(_) => return -1, + }; + + match QcowFile::new(file, virtual_size) { + Ok(_) => 0, + Err(_) => -1, + } } + #[cfg(not(feature = "qcow"))] + -ENOSYS // Not implemented } #[no_mangle] @@ -77,6 +84,7 @@ pub unsafe extern "C" fn expand_disk_image(path: *const c_char, virtual_size: u6 let disk_image: Box = match image_type { ImageType::Raw => Box::new(raw_image), + #[cfg(feature = "qcow")] ImageType::Qcow2 => match QcowFile::from(raw_image, disk::MAX_NESTING_DEPTH) { Ok(f) => Box::new(f), Err(_) => return -EINVAL, diff --git a/src/crosvm/cmdline.rs b/src/crosvm/cmdline.rs index ae8b0d59fa..5fefe6b986 100644 --- a/src/crosvm/cmdline.rs +++ b/src/crosvm/cmdline.rs @@ -121,6 +121,7 @@ pub enum CrossPlatformCommands { Battery(BatteryCommand), #[cfg(feature = "composite-disk")] CreateComposite(CreateCompositeCommand), + #[cfg(feature = "qcow")] CreateQcow2(CreateQcow2Command), Device(DeviceCommand), Disk(DiskCommand), @@ -198,6 +199,7 @@ pub struct CreateCompositeCommand { pub partitions: Vec, } +#[cfg(feature = "qcow")] #[derive(FromArgs)] #[argh(subcommand, name = "create_qcow2")] /// Create Qcow2 image given path and size diff --git a/src/main.rs b/src/main.rs index 1c49659aa3..bc55dbe9ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ //! Runs a virtual machine +#[cfg(any(feature = "composite-disk", feature = "qcow"))] use std::fs::OpenOptions; use std::path::Path; @@ -34,6 +35,7 @@ use disk::create_zero_filler; use disk::ImagePartitionType; #[cfg(feature = "composite-disk")] use disk::PartitionInfo; +#[cfg(feature = "qcow")] use disk::QcowFile; mod sys; use crosvm::cmdline::Command; @@ -338,6 +340,7 @@ fn create_composite(cmd: cmdline::CreateCompositeCommand) -> std::result::Result Ok(()) } +#[cfg(feature = "qcow")] fn create_qcow2(cmd: cmdline::CreateQcow2Command) -> std::result::Result<(), ()> { if !(cmd.size.is_some() ^ cmd.backing_file.is_some()) { println!( @@ -563,6 +566,7 @@ fn crosvm_main() -> Result { #[cfg(feature = "composite-disk")] CrossPlatformCommands::CreateComposite(cmd) => create_composite(cmd) .map_err(|_| anyhow!("create_composite subcommand failed")), + #[cfg(feature = "qcow")] CrossPlatformCommands::CreateQcow2(cmd) => { create_qcow2(cmd).map_err(|_| anyhow!("create_qcow2 subcommand failed")) }