///|
/// All byte offsets/counts are strings so JSON consumers preserve 64-bit values.
pub fn Header::json(self : Header) -> Json {
{
"version": self.version,
"virtual_size": self.virtual_size.to_string(),
"cluster_bits": self.cluster_bits,
"cluster_size": self.cluster_size(),
"l1_offset": self.l1_offset.to_string(),
"l1_entries": self.l1_entries.to_string(),
"refcount_offset": self.refcount_offset.to_string(),
"refcount_clusters": self.refcount_clusters.to_string(),
"refcount_order": self.refcount_order,
"snapshot_count": self.snapshot_count,
"snapshot_offset": self.snapshot_offset.to_string(),
"backing_offset": self.backing_offset.to_string(),
"backing_name_length": self.backing_name_length,
"header_length": self.header_length,
"incompatible_features": self.incompatible.to_string(),
"compatible_features": self.compatible.to_string(),
"autoclear_features": self.autoclear.to_string(),
"extended_l2": self.extended_l2(),
}
}
///|
pub fn ExtentKind::name(self : ExtentKind) -> String {
match self {
Data => "data"
Zero => "zero"
Unallocated => "unallocated"
Compressed => "compressed"
}
}
///|
fn optional_offset(offset : UInt64?) -> Json {
match offset {
Some(value) => Json::string(value.to_string())
None => Json::null()
}
}
///|
pub fn Extent::json(self : Extent) -> Json {
{
"offset": self.offset.to_string(),
"length": self.length.to_string(),
"kind": self.kind.name(),
"physical": optional_offset(self.physical),
"stored_length": self.stored_length,
}
}
///|
pub fn ResolvedExtent::json(self : ResolvedExtent) -> Json {
{
"offset": self.offset.to_string(),
"length": self.length.to_string(),
"kind": self.kind.name(),
"physical": optional_offset(self.physical),
"stored_length": self.stored_length,
"depth": self.depth,
}
}
///|
pub fn Snapshot::json(self : Snapshot) -> Json {
{
"index": self.index,
"id": self.id,
"name": self.name,
"l1_offset": self.l1_offset.to_string(),
"l1_entries": self.l1_entries.to_string(),
"virtual_size": self.virtual_size.to_string(),
"date_seconds": self.date_seconds.to_string(),
"date_nanoseconds": self.date_nanoseconds.to_string(),
"vm_clock_nanoseconds": self.vm_clock_nanoseconds.to_string(),
"vm_state_size": self.vm_state_size.to_string(),
}
}
///|
pub fn AllocationStats::json(self : AllocationStats) -> Json {
{
"virtual_bytes": self.virtual_bytes.to_string(),
"physical_bytes": self.physical_bytes.to_string(),
"local_data_bytes": self.local_data_bytes.to_string(),
"explicit_zero_bytes": self.explicit_zero_bytes.to_string(),
"backing_or_hole_bytes": self.backing_or_hole_bytes.to_string(),
"compressed_guest_bytes": self.compressed_guest_bytes.to_string(),
"compressed_storage_bytes": self.compressed_storage_bytes.to_string(),
"mapped_records": self.mapped_records,
}
}
///|
pub fn CacheStats::json(self : CacheStats) -> Json {
{
"bytes": self.bytes,
"blocks": self.blocks,
"hits": self.hits.to_string(),
"misses": self.misses.to_string(),
}
}
///|
pub fn RefcountStats::json(self : RefcountStats) -> Json {
{
"host_clusters": self.host_clusters.to_string(),
"unreferenced_clusters": self.unreferenced_clusters.to_string(),
"exclusive_clusters": self.exclusive_clusters.to_string(),
"shared_clusters": self.shared_clusters.to_string(),
"max_refcount": self.max_refcount.to_string(),
}
}
///|
pub fn RefcountRun::json(self : RefcountRun) -> Json {
{
"offset": self.offset.to_string(),
"length": self.length.to_string(),
"count": self.count.to_string(),
}
}
///|
pub fn HostRegion::json(self : HostRegion) -> Json {
{
"offset": self.offset.to_string(),
"length": self.length.to_string(),
"role": self.role,
}
}
///|
pub fn CopyProgress::json(self : CopyProgress) -> Json {
{
"start": self.start.to_string(),
"next_offset": self.next_offset.to_string(),
"end": self.end.to_string(),
"written_bytes": self.written_bytes.to_string(),
"skipped_zero_bytes": self.skipped_zero_bytes.to_string(),
"complete": self.complete,
}
}
///|
pub fn Difference::json(self : Difference) -> Json {
{ "offset": self.offset.to_string(), "length": self.length.to_string() }
}
///|
pub fn CompareReport::json(self : CompareReport) -> Json {
let ranges = self.ranges.map(fn(range) { range.json() })
{
"compared_bytes": self.compared_bytes.to_string(),
"different_bytes": self.different_bytes.to_string(),
"ranges": ranges,
"complete": self.complete,
}
}
///|
pub fn AuditIssue::json(self : AuditIssue) -> Json {
{
"severity": self.severity,
"code": self.code,
"offset": self.offset.to_string(),
"message": self.message,
}
}
///|
pub fn AuditReport::json(self : AuditReport) -> Json {
let issues = self.issues.map(fn(issue) { issue.json() })
{
"ok": self.ok(),
"complete": self.complete,
"scanned_bytes": self.scanned_bytes.to_string(),
"mappings": self.mappings,
"issues": issues,
"scope": "active mappings, metadata overlap, nonzero referenced refcounts; not full repair/check",
}
}
///|
pub fn Reference::json(self : Reference) -> Json {
{
"guest_offset": self.guest_offset.to_string(),
"guest_length": self.guest_length.to_string(),
"physical_offset": self.physical_offset.to_string(),
"physical_length": self.physical_length.to_string(),
"compressed": self.compressed,
}
}
///|
pub fn FeatureName::json(self : FeatureName) -> Json {
{ "feature_type": self.feature_type, "bit": self.bit, "name": self.name }
}
///|
pub fn HeaderExtension::json(self : HeaderExtension) -> Json {
{
"kind": self.kind.to_string(),
"offset": self.offset.to_string(),
"length": self.data.length(),
}
}
///|
pub fn QcowError::message(self : QcowError) -> String {
match self {
Invalid(message) => "invalid image: " + message
Unsupported(message) => "unsupported feature: " + message
OutOfBounds => "logical range exceeds virtual disk"
MissingBacking =>
"backing source required; following embedded paths requires explicit authorization"
LimitExceeded => "configured resource limit exceeded"
Io(message) => "I/O failure: " + message
}
}