use crate::error::{Error, Result, SignaturePosition};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct ValidationIssue {
section: &'static str,
code: &'static str,
message: String,
spec_ref: &'static str,
}
impl ValidationIssue {
pub(crate) fn new(
section: &'static str, code: &'static str, message: impl Into<String>,
spec_ref: &'static str,
) -> Self {
Self {
section,
code,
message: message.into(),
spec_ref,
}
}
#[must_use]
pub fn section(&self) -> &'static str {
self.section
}
#[must_use]
pub fn code(&self) -> &'static str {
self.code
}
#[must_use]
pub fn message(&self) -> String {
self.message.clone()
}
#[must_use]
pub fn spec_ref(&self) -> &'static str {
self.spec_ref
}
}
pub struct SpecValidator {
pub(super) data: Arc<[u8]>,
pub(super) strict: bool,
}
impl SpecValidator {
#[cfg(test)]
pub(crate) fn new(data: &[u8], strict: bool) -> Self {
Self {
data: Arc::from(data),
strict,
}
}
pub(crate) fn from_file<T>(file: &mut crate::medium::Medium<T>) -> Result<Self>
where
T: std::io::Read + std::io::Seek,
{
let strict = file.is_strict();
let data = file.validator_buf()?;
Ok(Self { data, strict })
}
pub(super) fn push_issue(issues: &mut Vec<ValidationIssue>, issue: ValidationIssue) {
issues.push(issue);
}
pub(super) fn push_header_issue(
issues: &mut Vec<ValidationIssue>, header_idx: u32, err: &Error,
) {
let issue = match err {
Error::InvalidSignature {
position: SignaturePosition::Header,
..
} => ValidationIssue::new(
"header",
"HEADER_SIGNATURE_INVALID",
format!("header {header_idx} signature error: {err}"),
"MS-VHDX/2.2.2",
),
Error::InvalidChecksum { .. } => ValidationIssue::new(
"header",
"HEADER_CHECKSUM_MISMATCH",
format!("header {header_idx} checksum error: {err}"),
"MS-VHDX/2.2.2",
),
Error::UnsupportedVersion { version } => ValidationIssue::new(
"header",
"HEADER_VERSION_UNSUPPORTED",
format!("header {header_idx} version {version} is not supported (expected 1)"),
"MS-VHDX/2.2.2",
),
Error::UnsupportedLogVersion { version } => ValidationIssue::new(
"header",
"HEADER_LOG_VERSION_UNSUPPORTED",
format!("header {header_idx} log version {version} is not supported (expected 0)"),
"MS-VHDX/2.2.2",
),
_ => ValidationIssue::new(
"header",
"HEADER_CORRUPTED",
format!("header {header_idx} error: {err}"),
"MS-VHDX/2.2.2",
),
};
issues.push(issue);
}
pub fn validate_file(&self) -> Result<Vec<ValidationIssue>> {
let mut issues = Vec::new();
issues.extend(self.validate_header()?);
issues.extend(self.validate_region_table()?);
issues.extend(self.validate_log()?);
issues.extend(self.validate_bat()?);
issues.extend(self.validate_metadata()?);
issues.extend(self.validate_required_metadata_items()?);
if self.has_parent() {
issues.extend(self.validate_parent_locator()?);
}
Ok(issues)
}
}