summary refs log tree commit diff
path: root/qcow_utils/src/qcow_img.rs
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2018-10-08 16:24:59 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-10-18 19:01:06 -0700
commit7f9b9ea344b5f9db68310d1d73e579b4e9bf59a8 (patch)
tree921d3730fc6e576e54bfbb9c7a56f498c5ed9d19 /qcow_utils/src/qcow_img.rs
parent2167ae953519e5dae023a92431a34a5a7b44546b (diff)
downloadcrosvm-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/qcow_img.rs')
-rw-r--r--qcow_utils/src/qcow_img.rs54
1 files changed, 54 insertions, 0 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(())
+        }
+    }
+}