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}