goldboot_image/qcow/header.rs
1use binrw::BinRead;
2
3/// Qcow header version 3.
4#[derive(BinRead, Debug)]
5#[br(magic = b"QFI\xfb")]
6pub struct QcowHeader {
7 /// Version of the QCOW format.
8 #[br(assert(version == 3))]
9 pub version: u32,
10
11 /// Offset into the image file at which the backing file name
12 /// is stored (NB: The string is not null terminated). 0 if the
13 /// image doesn't have a backing file.
14 _backing_file_offset: u64,
15
16 /// Length of the backing file name in bytes. Must not be
17 /// longer than 1023 bytes. Undefined if the image doesn't have
18 /// a backing file.
19 _backing_file_size: u32,
20
21 /// Number of bits that are used for addressing an offset
22 /// within a cluster (1 << cluster_bits is the cluster size).
23 /// Must not be less than 9 (i.e. 512 byte clusters).
24 pub cluster_bits: u32,
25
26 /// Virtual disk size in bytes.
27 pub size: u64,
28
29 /// Encryption method to use for contents
30 _crypt_method: u32,
31
32 /// Number of entries in the active L1 table
33 pub l1_size: u32,
34
35 /// Offset into the image file at which the active L1 table
36 /// starts. Must be aligned to a cluster boundary.
37 pub l1_table_offset: u64,
38
39 /// Offset into the image file at which the refcount table
40 /// starts. Must be aligned to a cluster boundary.
41 _refcount_table_offset: u64,
42
43 /// Number of clusters that the refcount table occupies
44 _refcount_table_clusters: u32,
45
46 /// Number of snapshots contained in the image
47 _nb_snapshots: u32,
48
49 /// Offset into the image file at which the snapshot table
50 /// starts. Must be aligned to a cluster boundary.
51 _snapshots_offset: u64,
52
53 /// Bitmask of incompatible features. An implementation must fail to open an
54 /// image if an unknown bit is set.
55 #[br(align_after = 8)]
56 _incompatible_features: u64,
57
58 /// Bitmask of compatible features. An implementation can safely ignore any
59 /// unknown bits that are set.
60 _compatible_features: u64,
61
62 /// Bitmask of auto-clear features. An implementation may only write to an
63 /// image with unknown auto-clear features if it clears the respective bits
64 /// from this field first.
65 _autoclear_features: u64,
66
67 /// Describes the width of a reference count block entry (width
68 /// in bits: refcount_bits = 1 << refcount_order). For version 2
69 /// images, the order is always assumed to be 4
70 /// (i.e. refcount_bits = 16).
71 /// This value may not exceed 6 (i.e. refcount_bits = 64).
72 _refcount_order: u32,
73
74 /// Total length of the header.
75 pub header_len: u32,
76
77 /// Defines the compression method used for compressed clusters.
78 ///
79 /// All compressed clusters in an image use the same compression
80 /// type.
81 ///
82 /// If the incompatible bit "Compression type" is set: the field
83 /// must be present and non-zero (which means non-zlib
84 /// compression type). Otherwise, this field must not be present
85 /// or must be zero (which means zlib).
86 #[br(if(header_len > 104))]
87 pub compression_type: CompressionType,
88
89 /// Marks the end of the extensions
90 _end: u32,
91}
92
93/// Compression type used for compressed clusters.
94#[derive(BinRead, Debug, Clone, Copy, PartialEq, Eq, Default)]
95#[br(repr(u8))]
96pub enum CompressionType {
97 /// Uses flate/zlib compression for any clusters which are compressed
98 #[default]
99 Zlib = 0,
100
101 /// Uses zstandard compression for any clusters which are compressed
102 Zstd = 1,
103}
104
105impl QcowHeader {
106 /// Get the size of a cluster in bytes from the qcow
107 pub fn cluster_size(&self) -> u64 {
108 1 << self.cluster_bits
109 }
110
111 /// Get the number of entries in an L2 table.
112 pub fn l2_entries_per_cluster(&self) -> u64 {
113 self.cluster_size() / 8
114 }
115}