Generalize disk file creation logic
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-05-29 08:03:42 +02:00
parent 7451f1b7b4
commit 20de618568
6 changed files with 103 additions and 58 deletions

View File

@ -1,4 +1,5 @@
use crate::constants;
use crate::utils::file_size_utils::FileSize;
use std::os::linux::fs::MetadataExt;
use std::path::Path;
use std::process::Command;
@ -8,13 +9,15 @@ use std::time::UNIX_EPOCH;
enum DisksError {
#[error("DiskParseError: {0}")]
Parse(&'static str),
#[error("DiskCreateError")]
Create,
}
#[derive(Debug, serde::Serialize)]
#[serde(tag = "format")]
pub enum DiskFileFormat {
Raw { is_sparse: bool },
QCow2 { virtual_size: usize },
QCow2 { virtual_size: FileSize },
CompressedRaw,
CompressedQCow2,
}
@ -22,7 +25,7 @@ pub enum DiskFileFormat {
/// Disk file information
#[derive(serde::Serialize)]
pub struct DiskFileInfo {
pub file_size: usize,
pub file_size: FileSize,
#[serde(flatten)]
pub format: DiskFileFormat,
pub file_name: String,
@ -64,7 +67,7 @@ impl DiskFileInfo {
Ok(Self {
name,
file_size: metadata.len() as usize,
file_size: FileSize::from_bytes(metadata.len() as usize),
format,
file_name: file
.file_name()
@ -78,6 +81,50 @@ impl DiskFileInfo {
.as_secs(),
})
}
/// Create a new empty disk
pub fn create(file: &Path, format: DiskFileFormat, size: FileSize) -> anyhow::Result<()> {
// Prepare command to create file
let res = match format {
DiskFileFormat::Raw { is_sparse } => {
let mut cmd = Command::new("/usr/bin/dd");
cmd.arg("if=/dev/zero")
.arg(format!("of={}", file.to_string_lossy()))
.arg("bs=1M");
match is_sparse {
false => cmd.arg(format!("count={}", size.as_mb())),
true => cmd.arg(format!("seek={}", size.as_mb())).arg("count=0"),
};
cmd.output()?
}
DiskFileFormat::QCow2 { virtual_size } => {
let mut cmd = Command::new(constants::QEMU_IMAGE_PROGRAM);
cmd.arg("create")
.arg("-f")
.arg("qcow2")
.arg(file)
.arg(format!("{}M", virtual_size.as_mb()));
cmd.output()?
}
_ => anyhow::bail!("Cannot create disk file image of this format: {format:?}!"),
};
// Execute Linux command
if !res.status.success() {
log::error!(
"Failed to create disk! stderr={} stdout={}",
String::from_utf8_lossy(&res.stderr),
String::from_utf8_lossy(&res.stdout)
);
return Err(DisksError::Create.into());
}
Ok(())
}
}
#[derive(serde::Deserialize)]
@ -87,7 +134,7 @@ struct QCowInfoOutput {
}
/// Get QCow2 virtual size
fn qcow_virt_size(path: &Path) -> anyhow::Result<usize> {
fn qcow_virt_size(path: &Path) -> anyhow::Result<FileSize> {
// Run qemu-img
let mut cmd = Command::new(constants::QEMU_IMAGE_PROGRAM);
cmd.args([
@ -110,5 +157,5 @@ fn qcow_virt_size(path: &Path) -> anyhow::Result<usize> {
// Decode JSON
let decoded: QCowInfoOutput = serde_json::from_str(&res_json)?;
Ok(decoded.virtual_size)
Ok(FileSize::from_bytes(decoded.virtual_size))
}