qcow2_rs/
meta.rs

1// borrowed from rsd project
2
3#![allow(dead_code)]
4
5use crate::dev::Qcow2Info;
6use crate::error::Qcow2Result;
7use crate::helpers::IntAlignment;
8use crate::helpers::Qcow2IoBuf;
9use crate::numerical_enum;
10use bincode::Options;
11use serde::{Deserialize, Serialize};
12use std::cell::RefCell;
13use std::collections::HashMap;
14use std::collections::VecDeque;
15use std::mem::size_of;
16
17macro_rules! impl_table_gen_funcs {
18    ($field:ident) => {
19        #[inline(always)]
20        fn as_ptr(&self) -> *const u8 {
21            self.$field.as_ptr() as *const u8
22        }
23
24        #[inline(always)]
25        fn as_mut_ptr(&mut self) -> *mut u8 {
26            self.$field.as_mut_ptr() as *mut u8
27        }
28
29        #[inline(always)]
30        fn get_offset(&self) -> Option<u64> {
31            self.offset
32        }
33
34        #[inline(always)]
35        fn set_offset(&mut self, offset: Option<u64>) {
36            self.offset = offset;
37        }
38    };
39}
40
41macro_rules! impl_table_gen_setter {
42    ($entry:ident, $field:ident) => {
43        #[inline(always)]
44        fn entries(&self) -> usize {
45            self.$field.len()
46        }
47
48        #[inline(always)]
49        fn get(&self, index: usize) -> $entry {
50            match self.$field.get(index) {
51                Some(entry) => $entry(u64::from_be(entry.0)),
52                None => $entry(0),
53            }
54        }
55
56        #[inline(always)]
57        fn set(&mut self, index: usize, entry: $entry) {
58            self.$field[index] = $entry(entry.0.to_be());
59        }
60    };
61}
62
63macro_rules! impl_top_table_gen_funcs {
64    () => {
65        #[inline(always)]
66        fn set_dirty(&self, idx: usize) {
67            let bs_idx = ((idx as u32) << 3) >> self.bs_bits;
68            let mut blkq = self.dirty_blocks.borrow_mut();
69
70            if !blkq.contains(&bs_idx) {
71                blkq.push_back(bs_idx);
72            }
73        }
74
75        /// Remove specified data iff val isn't None
76        #[inline(always)]
77        fn pop_dirty_blk_idx(&self, val: Option<u32>) -> Option<u32> {
78            let mut blkq = self.dirty_blocks.borrow_mut();
79
80            match val {
81                Some(data) => match blkq.iter().position(|x| *x == data) {
82                    Some(pos) => {
83                        blkq.remove(pos);
84                        Some(data)
85                    }
86                    None => None,
87                },
88                None => blkq.pop_front(),
89            }
90        }
91    };
92}
93
94macro_rules! impl_table_traits {
95    ($table:ident, $entry:ident, $field:ident) => {
96        impl Table for $table {
97            type Entry = $entry;
98
99            impl_table_gen_funcs!($field);
100            impl_table_gen_setter!($entry, $field);
101        }
102    };
103}
104
105macro_rules! impl_top_table_traits {
106    ($table:ident, $entry:ident, $field:ident) => {
107        impl Table for $table {
108            type Entry = $entry;
109
110            impl_table_gen_funcs!($field);
111            impl_table_gen_setter!($entry, $field);
112            impl_top_table_gen_funcs!();
113        }
114    };
115}
116
117macro_rules! impl_entry_display_trait {
118    ($entry:ident) => {
119        impl std::fmt::Display for $entry {
120            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121                write!(f, "{:<16x}", self.into_plain())
122            }
123        }
124    };
125}
126
127impl_entry_display_trait!(L1Entry);
128impl_entry_display_trait!(L2Entry);
129impl_entry_display_trait!(RefTableEntry);
130impl_entry_display_trait!(RefBlockEntry);
131
132#[derive(Debug, Default, Deserialize, Serialize)]
133#[repr(packed)]
134pub(crate) struct Qcow2RawHeader {
135    /// QCOW magic string ("QFI\xfb")
136    magic: u32,
137
138    /// Version number (valid values are 2 and 3)
139    version: u32,
140
141    /// Offset into the image file at which the backing file name
142    /// is stored (NB: The string is not null terminated). 0 if the
143    /// image doesn't have a backing file.
144    ///
145    /// Note: backing files are incompatible with raw external data
146    /// files (auto-clear feature bit 1).
147    backing_file_offset: u64,
148
149    /// Length of the backing file name in bytes. Must not be
150    /// longer than 1023 bytes. Undefined if the image doesn't have
151    /// a backing file.
152    backing_file_size: u32,
153
154    /// Number of bits that are used for addressing an offset
155    /// within a cluster (1 << cluster_bits is the cluster size).
156    /// Must not be less than 9 (i.e. 512 byte clusters).
157    ///
158    /// Note: qemu as of today has an implementation limit of 2 MB
159    /// as the maximum cluster size and won't be able to open images
160    /// with larger cluster sizes.
161    ///
162    /// Note: if the image has Extended L2 Entries then cluster_bits
163    /// must be at least 14 (i.e. 16384 byte clusters).
164    cluster_bits: u32,
165
166    /// Virtual disk size in bytes.
167    ///
168    /// Note: qemu has an implementation limit of 32 MB as
169    /// the maximum L1 table size.  With a 2 MB cluster
170    /// size, it is unable to populate a virtual cluster
171    /// beyond 2 EB (61 bits); with a 512 byte cluster
172    /// size, it is unable to populate a virtual size
173    /// larger than 128 GB (37 bits).  Meanwhile, L1/L2
174    /// table layouts limit an image to no more than 64 PB
175    /// (56 bits) of populated clusters, and an image may
176    /// hit other limits first (such as a file system's
177    /// maximum size).
178    size: u64,
179
180    /// 0 for no encryption
181    /// 1 for AES encryption
182    /// 2 for LUKS encryption
183    crypt_method: u32,
184
185    /// Number of entries in the active L1 table
186    l1_size: u32,
187
188    /// Offset into the image file at which the active L1 table
189    /// starts. Must be aligned to a cluster boundary.
190    l1_table_offset: u64,
191
192    /// Offset into the image file at which the refcount table
193    /// starts. Must be aligned to a cluster boundary.
194    refcount_table_offset: u64,
195
196    /// Number of clusters that the refcount table occupies
197    refcount_table_clusters: u32,
198
199    /// Number of snapshots contained in the image
200    nb_snapshots: u32,
201
202    /// Offset into the image file at which the snapshot table
203    /// starts. Must be aligned to a cluster boundary.
204    snapshots_offset: u64,
205
206    // The following fields are only valid for version >= 3
207    /// Bitmask of incompatible features. An implementation must
208    /// fail to open an image if an unknown bit is set.
209    ///
210    /// Bit 0:      Dirty bit.  If this bit is set then refcounts
211    /// may be inconsistent, make sure to scan L1/L2
212    /// tables to repair refcounts before accessing the
213    /// image.
214    ///
215    /// Bit 1:      Corrupt bit.  If this bit is set then any data
216    /// structure may be corrupt and the image must not
217    /// be written to (unless for regaining
218    /// consistency).
219    ///
220    /// Bit 2:      External data file bit.  If this bit is set, an
221    /// external data file is used. Guest clusters are
222    /// then stored in the external data file. For such
223    /// images, clusters in the external data file are
224    /// not refcounted. The offset field in the
225    /// Standard Cluster Descriptor must match the
226    /// guest offset and neither compressed clusters
227    /// nor internal snapshots are supported.
228    ///
229    /// An External Data File Name header extension may
230    /// be present if this bit is set.
231    ///
232    /// Bit 3:      Compression type bit.  If this bit is set,
233    /// a non-default compression is used for compressed
234    /// clusters. The compression_type field must be
235    /// present and not zero.
236    ///
237    /// Bit 4:      Extended L2 Entries.  If this bit is set then
238    /// L2 table entries use an extended format that
239    /// allows subcluster-based allocation. See the
240    /// Extended L2 Entries section for more details.
241    ///
242    /// Bits 5-63:  Reserved (set to 0)
243    incompatible_features: u64,
244
245    /// Bitmask of compatible features. An implementation can
246    /// safely ignore any unknown bits that are set.
247    ///
248    /// Bit 0:      Lazy refcounts bit.  If this bit is set then
249    /// lazy refcount updates can be used.  This means
250    /// marking the image file dirty and postponing
251    /// refcount metadata updates.
252    ///
253    /// Bits 1-63:  Reserved (set to 0)
254    compatible_features: u64,
255
256    /// Bitmask of auto-clear features. An implementation may only
257    /// write to an image with unknown auto-clear features if it
258    /// clears the respective bits from this field first.
259    ///
260    /// Bit 0:      Bitmaps extension bit
261    /// This bit indicates consistency for the bitmaps
262    /// extension data.
263    ///
264    /// It is an error if this bit is set without the
265    /// bitmaps extension present.
266    ///
267    /// If the bitmaps extension is present but this
268    /// bit is unset, the bitmaps extension data must be
269    /// considered inconsistent.
270    ///
271    /// Bit 1:      Raw external data bit
272    /// If this bit is set, the external data file can
273    /// be read as a consistent standalone raw image
274    /// without looking at the qcow2 metadata.
275    ///
276    /// Setting this bit has a performance impact for
277    /// some operations on the image (e.g. writing
278    /// zeros requires writing to the data file instead
279    /// of only setting the zero flag in the L2 table
280    /// entry) and conflicts with backing files.
281    ///
282    /// This bit may only be set if the External Data
283    /// File bit (incompatible feature bit 1) is also
284    /// set.
285    ///
286    /// Bits 2-63:  Reserved (set to 0)
287    autoclear_features: u64,
288
289    /// Describes the width of a reference count block entry (width
290    /// in bits: refcount_bits = 1 << refcount_order). For version 2
291    /// images, the order is always assumed to be 4
292    /// (i.e. refcount_bits = 16).
293    /// This value may not exceed 6 (i.e. refcount_bits = 64).
294    refcount_order: u32,
295
296    /// Length of the header structure in bytes. For version 2
297    /// images, the length is always assumed to be 72 bytes.
298    /// For version 3 it's at least 104 bytes and must be a multiple
299    /// of 8.
300    header_length: u32,
301
302    /// Additional fields
303    compression_type: u8,
304}
305
306numerical_enum! {
307    pub enum Qcow2HeaderExtensionType as u32 {
308        End = 0,
309        BackingFileFormat = 0xe2792aca,
310        FeatureNameTable = 0x6803f857,
311    }
312}
313
314impl Qcow2RawHeader {
315    pub fn serialize_vec(&mut self) -> Qcow2Result<Vec<u8>> {
316        self.header_length = size_of::<Self>().align_up(8usize).unwrap().try_into()?;
317
318        let bincode = bincode::DefaultOptions::new()
319            .with_fixint_encoding()
320            .with_big_endian();
321
322        let mut header_buf = bincode.serialize(self)?;
323        header_buf.resize(header_buf.len().align_up(8usize).unwrap(), 0);
324
325        assert!(header_buf.len() == self.header_length as usize);
326
327        Ok(header_buf)
328    }
329}
330
331#[derive(Default, Deserialize, Serialize)]
332#[repr(packed)]
333struct Qcow2HeaderExtensionHeader {
334    /// Type code of the header extension
335    extension_type: u32,
336
337    /// Data length
338    length: u32,
339}
340
341numerical_enum! {
342    #[derive(Hash)]
343    pub enum Qcow2FeatureType as u8 {
344        Incompatible = 0,
345        Compatible = 1,
346        Autoclear = 2,
347    }
348}
349
350#[derive(Debug, Clone)]
351pub enum Qcow2HeaderExtension {
352    BackingFileFormat(String),
353    FeatureNameTable(HashMap<(Qcow2FeatureType, u8), String>),
354    Unknown { extension_type: u32, data: Vec<u8> },
355}
356
357#[derive(Debug, Clone)]
358pub struct SplitGuestOffset(pub u64);
359
360impl SplitGuestOffset {
361    #[inline(always)]
362    pub fn guest_addr(&self) -> u64 {
363        self.0
364    }
365
366    #[inline(always)]
367    pub fn cluster_offset(&self, info: &Qcow2Info) -> u64 {
368        let cluster_bits = info.cluster_bits();
369        (((self.l1_index(info) as u64) << (cluster_bits - 3)) + self.l2_index(info) as u64)
370            << cluster_bits
371    }
372
373    #[inline(always)]
374    pub fn l1_index(&self, info: &Qcow2Info) -> usize {
375        let guest_offset = self.0 >> (info.cluster_shift + info.l2_index_shift);
376        guest_offset.try_into().unwrap()
377    }
378
379    #[inline(always)]
380    pub fn l2_index(&self, info: &Qcow2Info) -> usize {
381        let guest_offset = self.0 >> info.cluster_bits();
382        guest_offset as usize & info.l2_index_mask
383    }
384
385    #[inline(always)]
386    pub fn l2_slice_index(&self, info: &Qcow2Info) -> usize {
387        let guest_offset = self.0 >> info.cluster_bits();
388        guest_offset as usize & (info.l2_slice_entries as usize - 1)
389    }
390
391    #[inline(always)]
392    pub fn l2_slice_key(&self, info: &Qcow2Info) -> usize {
393        (self.0 >> (info.cluster_shift + info.l2_slice_index_shift)) as usize
394    }
395
396    #[inline(always)]
397    pub fn l2_slice_off_in_table(&self, info: &Qcow2Info) -> usize {
398        let l2_idx = self.l2_index(info);
399
400        //todo: support extended l2 descriptor
401        (l2_idx >> info.l2_slice_index_shift) << info.l2_slice_bits
402    }
403
404    #[inline(always)]
405    pub fn in_cluster_offset(&self, info: &Qcow2Info) -> usize {
406        self.0 as usize & info.in_cluster_offset_mask
407    }
408}
409
410#[derive(Debug)]
411pub struct Qcow2Header {
412    raw: Qcow2RawHeader,
413    backing_filename: Option<String>,
414    extensions: Vec<Qcow2HeaderExtension>,
415}
416
417impl Qcow2Header {
418    pub const QCOW2_MAGIC: u32 = 0x51_46_49_fb;
419    pub const MAX_CLUSTER_SIZE: u32 = 2_u32 << 20;
420    pub const MAX_L1_SIZE: u32 = 32_u32 << 20;
421    pub const MAX_REFCOUNT_TABLE_SIZE: u32 = 8_u32 << 20;
422
423    pub fn from_buf(header_buf: &[u8]) -> Qcow2Result<Self> {
424        let bincode = bincode::DefaultOptions::new()
425            .with_fixint_encoding()
426            .with_big_endian();
427
428        let mut header: Qcow2RawHeader =
429            bincode.deserialize(&header_buf[0..size_of::<Qcow2RawHeader>()])?;
430        if header.magic != Self::QCOW2_MAGIC {
431            return Err("Not a qcow2 file".into());
432        }
433
434        if header.version < 2 {
435            let v = header.version;
436            return Err(format!("qcow2 v{} is not supported", v).into());
437        }
438
439        // refcount_order is always 4 for version 2
440        if header.version == 2 {
441            header.refcount_order = 4;
442        }
443
444        let cluster_size = 1u64 << header.cluster_bits;
445        if cluster_size > Self::MAX_CLUSTER_SIZE as u64 {
446            return Err(format!("qcow2 cluster size {} is too big", cluster_size).into());
447        }
448
449        let backing_filename = if header.backing_file_offset != 0 {
450            let (offset, length) = (header.backing_file_offset, header.backing_file_size);
451            if length > 1023 {
452                return Err(format!(
453                    "Backing file name is too long ({}, must not exceed 1023)",
454                    length
455                )
456                .into());
457            }
458
459            let end = offset
460                .checked_add(length as u64)
461                .ok_or("Backing file name offset is invalid (too high)")?;
462            if end >= cluster_size {
463                return Err("Backing file name offset is invalid (too high)".into());
464            }
465
466            if end > header_buf.len() as u64 {
467                return Err("header buffer is too small".into());
468            }
469
470            let backing_buf = header_buf[(end - (length as u64)) as usize..(end as usize)].to_vec();
471            Some(
472                String::from_utf8(backing_buf)
473                    .map_err(|err| format!("Backing file name is invalid: {}", err))?,
474            )
475        } else {
476            None
477        };
478
479        let mut ext_offset: u64 = header.header_length as u64;
480        let mut extensions = Vec::<Qcow2HeaderExtension>::new();
481        loop {
482            let max_len = ext_offset + size_of::<Qcow2HeaderExtensionHeader>() as u64;
483            if max_len > cluster_size || max_len > header_buf.len() as u64 {
484                return Err(
485                    "Header extensions exceed the first cluster or header buffer is too small"
486                        .into(),
487                );
488            }
489
490            let ext_hdr_buf = &header_buf[ext_offset as usize
491                ..ext_offset as usize + size_of::<Qcow2HeaderExtensionHeader>()];
492
493            ext_offset += size_of::<Qcow2HeaderExtensionHeader>() as u64;
494
495            let ext_hdr: Qcow2HeaderExtensionHeader = bincode.deserialize(ext_hdr_buf)?;
496            let max_len = ext_offset + ext_hdr.length as u64;
497            if max_len > cluster_size || max_len > header_buf.len() as u64 {
498                return Err("Header extensions exceed the first cluster or buffer length".into());
499            }
500
501            let ext_data = header_buf
502                [ext_offset as usize..ext_offset as usize + ext_hdr.length as usize]
503                .to_vec();
504            ext_offset += (ext_hdr.length as u64).align_up(8u64).unwrap();
505
506            let extension = match Qcow2HeaderExtension::from(ext_hdr.extension_type, ext_data)? {
507                Some(ext) => ext,
508                None => break,
509            };
510
511            extensions.push(extension);
512        }
513
514        let header = Qcow2Header {
515            raw: header,
516            backing_filename,
517            extensions,
518        };
519
520        // No need to clear autoclear features for read-only images, and it is caller's
521        // responsibility to clear the feature bit
522        /*
523        if header.raw.autoclear_features != 0 && !read_only {
524            header.raw.autoclear_features = 0;
525            header.write(queue).await?;
526        }*/
527
528        if header.raw.incompatible_features != 0 {
529            let feats = (0..64)
530                .filter(|bit| header.raw.incompatible_features & (1u64 << bit) != 0)
531                .map(|bit| {
532                    if let Some(name) = header.feature_name(Qcow2FeatureType::Incompatible, bit) {
533                        format!("{} ({})", bit, name)
534                    } else {
535                        format!("{}", bit)
536                    }
537                })
538                .collect::<Vec<String>>();
539
540            return Err(
541                format!("Unrecognized incompatible feature(s) {}", feats.join(", ")).into(),
542            );
543        }
544
545        Ok(header)
546    }
547
548    pub fn calculate_meta_params(
549        size: u64,
550        cluster_bits: usize,
551        refcount_order: u8,
552        block_size: usize,
553    ) -> ((u64, u32), (u64, u32), (u64, u32)) {
554        let cluster_size = 1usize << cluster_bits;
555
556        // cluster 0 is for header, refcount_table starts from 1st cluster
557        let rc_table_offset = cluster_size as u64;
558        let rc_table_size =
559            Qcow2Info::__max_refcount_table_size(size, cluster_size, refcount_order, block_size);
560        let rc_table_clusters = (rc_table_size + cluster_size - 1) / cluster_size;
561
562        let rc_block_offset = rc_table_offset + ((rc_table_clusters as u64) << cluster_bits);
563        let rc_block_clusters = 1;
564
565        let l1_table_offset = rc_block_offset + cluster_size as u64;
566        let l1_table_entries = Qcow2Info::get_max_l1_entries(size, cluster_bits);
567        let l1_table_size = Qcow2Info::__max_l1_size(l1_table_entries, block_size);
568        let l1_table_clusters = (l1_table_size + cluster_size - 1) / cluster_size;
569
570        let rc_table = (rc_table_offset, rc_table_clusters as u32);
571        let rc_block = (rc_block_offset, rc_block_clusters);
572        let l1_table = (l1_table_offset, l1_table_clusters as u32);
573
574        (rc_table, rc_block, l1_table)
575    }
576    /// Format in-ram qcow2 image, for test purpose
577    pub fn format_qcow2(
578        buf: &mut [u8],
579        size: u64,
580        cluster_bits: usize,
581        refcount_order: u8,
582        block_size: usize,
583    ) -> Qcow2Result<()> {
584        let cluster_size = 1usize << cluster_bits;
585
586        if buf.len() & (block_size - 1) != 0 {
587            return Err("buffer isn't cluster aligned".into());
588        }
589
590        let (rc_table, rc_blk, l1_table) =
591            Self::calculate_meta_params(size, cluster_bits, refcount_order, block_size);
592
593        // don't take l1 table into account
594        let clusters = 1 + rc_table.1 + rc_blk.1;
595        if (buf.len() / cluster_size) < clusters as usize {
596            return Err("buffer is too small".into());
597        }
598
599        let start = rc_table.0 as usize;
600        let end = start + ((rc_table.1 as usize) << cluster_bits);
601        let mut rc_t = RefTable::new_empty(Some(rc_table.0), end - start);
602
603        let start = rc_blk.0 as usize;
604        let end = start + ((rc_blk.1 as usize) << cluster_bits);
605        let mut ref_b = RefBlock::new(refcount_order, end - start, Some(rc_blk.0));
606
607        //header
608        ref_b.increment(0)?;
609        assert!(ref_b.get(0).into_plain() == 1);
610
611        //refcount table
612        let start = rc_table.0;
613        let end = start + ((rc_table.1 as u64) << cluster_bits);
614        for i in (start..end).step_by(cluster_size) {
615            ref_b.increment((i >> cluster_bits) as usize)?;
616        }
617
618        //me
619        ref_b.increment((rc_table.1 as usize) + 1)?;
620
621        //l1 table
622        let start = l1_table.0;
623        let end = start + ((l1_table.1 as u64) << cluster_bits);
624        for i in (start..end).step_by(cluster_size) {
625            ref_b.increment((i >> cluster_bits) as usize)?;
626        }
627
628        rc_t.set(0, RefTableEntry(rc_blk.0));
629
630        // commit meta into external buffer
631        let buf_start = buf.as_mut_ptr() as u64;
632        unsafe {
633            libc::memcpy(
634                (buf_start + rc_table.0) as *mut libc::c_void,
635                rc_t.as_ptr() as *const libc::c_void,
636                (rc_table.1 as usize) << cluster_bits,
637            );
638        }
639        unsafe {
640            libc::memcpy(
641                (buf_start + rc_blk.0) as *mut libc::c_void,
642                ref_b.as_ptr() as *const libc::c_void,
643                (rc_blk.1 as usize) << cluster_bits,
644            );
645        }
646
647        // We are empty image, so nothing is in l1 table, just zero the
648        // 1st sector
649        unsafe {
650            libc::memset((buf_start + l1_table.0) as *mut libc::c_void, 0, block_size);
651        }
652
653        let l2_entries = (cluster_size as u64) / 8;
654        let size_per_l1_entry = l2_entries << cluster_bits;
655        let l1_entries = (size + size_per_l1_entry - 1) / size_per_l1_entry;
656
657        let mut h = Qcow2RawHeader {
658            magic: Self::QCOW2_MAGIC,
659            version: 3,
660            cluster_bits: cluster_bits as u32,
661            size,
662            refcount_order: refcount_order as u32,
663            header_length: 112,
664            l1_table_offset: l1_table.0,
665            l1_size: l1_entries.try_into().unwrap(),
666            refcount_table_offset: rc_table.0,
667            refcount_table_clusters: rc_table.1,
668            ..Default::default()
669        };
670
671        let vec = h.serialize_vec()?;
672        buf[..vec.len()].copy_from_slice(vec.as_slice());
673
674        Ok(())
675    }
676
677    pub fn serialize_to_buf(&mut self) -> Qcow2Result<Vec<u8>> {
678        let header_len = size_of::<Qcow2RawHeader>().align_up(8usize).unwrap();
679        let mut header_exts = self.serialize_extensions()?;
680
681        if let Some(backing) = self.backing_filename.as_ref() {
682            self.raw.backing_file_offset = (header_len + header_exts.len()).try_into()?;
683            self.raw.backing_file_size = backing.as_bytes().len().try_into()?;
684        } else {
685            self.raw.backing_file_offset = 0;
686            self.raw.backing_file_size = 0;
687        }
688
689        let mut full_buf = self.raw.serialize_vec()?;
690        full_buf.append(&mut header_exts);
691        if let Some(backing) = self.backing_filename.as_ref() {
692            full_buf.extend_from_slice(backing.as_bytes());
693        }
694
695        if full_buf.len() > 1 << self.raw.cluster_bits {
696            return Err(format!(
697                "Header is too big to write ({}, larger than a cluster ({}))",
698                full_buf.len(),
699                1 << self.raw.cluster_bits
700            )
701            .into());
702        }
703
704        Ok(full_buf)
705    }
706
707    pub fn version(&self) -> u32 {
708        self.raw.version
709    }
710
711    pub fn crypt_method(&self) -> u32 {
712        self.raw.crypt_method
713    }
714
715    pub fn compression_type(&self) -> u8 {
716        self.raw.compression_type
717    }
718
719    pub fn header_length(&self) -> u32 {
720        self.raw.header_length
721    }
722
723    pub fn size(&self) -> u64 {
724        self.raw.size
725    }
726
727    pub fn cluster_bits(&self) -> u32 {
728        self.raw.cluster_bits
729    }
730
731    pub fn refcount_order(&self) -> u32 {
732        self.raw.refcount_order
733    }
734
735    pub fn l1_table_offset(&self) -> u64 {
736        self.raw.l1_table_offset
737    }
738
739    pub fn l1_table_entries(&self) -> usize {
740        self.raw.l1_size as usize
741    }
742
743    pub fn set_l1_table(&mut self, offset: u64, entries: usize) -> Qcow2Result<()> {
744        self.raw.l1_size = entries.try_into()?;
745        self.raw.l1_table_offset = offset;
746        Ok(())
747    }
748
749    pub fn nb_snapshots(&self) -> u32 {
750        self.raw.nb_snapshots
751    }
752
753    pub fn snapshots_offset(&self) -> u64 {
754        self.raw.snapshots_offset
755    }
756
757    pub fn reftable_offset(&self) -> u64 {
758        self.raw.refcount_table_offset
759    }
760
761    pub fn reftable_clusters(&self) -> usize {
762        self.raw.refcount_table_clusters as usize
763    }
764
765    pub fn set_reftable(&mut self, offset: u64, clusters: usize) -> Qcow2Result<()> {
766        self.raw.refcount_table_clusters = clusters.try_into()?;
767        self.raw.refcount_table_offset = offset;
768        Ok(())
769    }
770
771    pub fn backing_filename(&self) -> Option<&String> {
772        self.backing_filename.as_ref()
773    }
774
775    pub fn backing_format(&self) -> Option<&String> {
776        for e in &self.extensions {
777            if let Qcow2HeaderExtension::BackingFileFormat(fmt) = e {
778                return Some(fmt);
779            }
780        }
781
782        None
783    }
784
785    pub fn feature_name(&self, feat_type: Qcow2FeatureType, bit: u32) -> Option<&String> {
786        for e in &self.extensions {
787            if let Qcow2HeaderExtension::FeatureNameTable(names) = e {
788                if let Some(name) = names.get(&(feat_type, bit as u8)) {
789                    return Some(name);
790                }
791            }
792        }
793
794        None
795    }
796
797    fn serialize_extensions(&self) -> Qcow2Result<Vec<u8>> {
798        let bincode = bincode::DefaultOptions::new()
799            .with_fixint_encoding()
800            .with_big_endian();
801
802        let mut result = Vec::new();
803        for e in &self.extensions {
804            let mut data = e.serialize_data()?;
805            let ext_hdr = Qcow2HeaderExtensionHeader {
806                extension_type: e.extension_type(),
807                length: data.len().try_into()?,
808            };
809            result.append(&mut bincode.serialize(&ext_hdr)?);
810            result.append(&mut data);
811            result.resize(result.len().align_up(8usize).unwrap(), 0);
812        }
813
814        let end_ext = Qcow2HeaderExtensionHeader {
815            extension_type: Qcow2HeaderExtensionType::End as u32,
816            length: 0,
817        };
818        result.append(&mut bincode.serialize(&end_ext)?);
819        result.resize(result.len().align_up(8usize).unwrap(), 0);
820
821        Ok(result)
822    }
823}
824
825impl Qcow2HeaderExtension {
826    /// Parse an extension from its type and data.  Unrecognized types are stored as `Unknown`
827    /// extensions, encountering the end of extensions returns `Ok(None)`.
828    fn from(ext_type: u32, data: Vec<u8>) -> Qcow2Result<Option<Self>> {
829        let ext = if let Ok(ext_type) = Qcow2HeaderExtensionType::try_from(ext_type) {
830            match ext_type {
831                Qcow2HeaderExtensionType::End => return Ok(None),
832                Qcow2HeaderExtensionType::BackingFileFormat => {
833                    let fmt = String::from_utf8(data)
834                        .map_err(|err| format!("Invalid backing file format: {}", err))?;
835                    Qcow2HeaderExtension::BackingFileFormat(fmt)
836                }
837                Qcow2HeaderExtensionType::FeatureNameTable => {
838                    let mut feats = HashMap::new();
839                    for feat in data.chunks(48) {
840                        let feat_type: Qcow2FeatureType = match feat[0].try_into() {
841                            Ok(ft) => ft,
842                            Err(_) => continue, // skip unrecognized entries
843                        };
844                        let feat_name = String::from(
845                            String::from_utf8_lossy(&feat[2..]).trim_end_matches('\0'),
846                        );
847
848                        feats.insert((feat_type, feat[1]), feat_name);
849                    }
850                    Qcow2HeaderExtension::FeatureNameTable(feats)
851                }
852            }
853        } else {
854            Qcow2HeaderExtension::Unknown {
855                extension_type: ext_type,
856                data,
857            }
858        };
859
860        Ok(Some(ext))
861    }
862
863    fn extension_type(&self) -> u32 {
864        match self {
865            Qcow2HeaderExtension::BackingFileFormat(_) => {
866                Qcow2HeaderExtensionType::BackingFileFormat as u32
867            }
868            Qcow2HeaderExtension::FeatureNameTable(_) => {
869                Qcow2HeaderExtensionType::FeatureNameTable as u32
870            }
871            Qcow2HeaderExtension::Unknown {
872                extension_type,
873                data: _,
874            } => *extension_type,
875        }
876    }
877
878    fn serialize_data(&self) -> Qcow2Result<Vec<u8>> {
879        match self {
880            Qcow2HeaderExtension::BackingFileFormat(fmt) => Ok(fmt.as_bytes().into()),
881            Qcow2HeaderExtension::FeatureNameTable(map) => {
882                let mut result = Vec::new();
883                for (bit, name) in map {
884                    result.push(bit.0 as u8);
885                    result.push(bit.1);
886
887                    let mut padded_name = vec![0; 46];
888                    let name_bytes = name.as_bytes();
889                    // Might truncate in the middle of a multibyte character, but getting that
890                    // right is complicated and probably not worth it
891                    let truncated_len = std::cmp::min(name_bytes.len(), 46);
892                    padded_name[..truncated_len].copy_from_slice(&name_bytes[..truncated_len]);
893                    result.extend_from_slice(&padded_name);
894                }
895                Ok(result)
896            }
897            Qcow2HeaderExtension::Unknown {
898                extension_type: _,
899                data,
900            } => Ok(data.clone()),
901        }
902    }
903}
904
905// L1 table entry:
906//
907// Bit  0 -  8:     Reserved (set to 0)
908//
909//      9 - 55:     Bits 9-55 of the offset into the image file at which the L2
910//                  table starts. Must be aligned to a cluster boundary. If the
911//                  offset is 0, the L2 table and all clusters described by this
912//                  L2 table are unallocated.
913//
914//      56 - 62:    Reserved (set to 0)
915//
916//      63:         0 for an L2 table that is unused or requires COW, 1 if its
917//                  refcount is exactly one. This information is only accurate
918//                  in the active L1 table.
919#[derive(Copy, Clone, Default, Debug)]
920pub struct L1Entry(u64);
921
922impl L1Entry {
923    const DIRTY: u64 = 0x1;
924    const NEW: u64 = 0x2;
925
926    pub fn l2_offset(&self) -> u64 {
927        self.0 & 0x00ff_ffff_ffff_fe00u64
928    }
929
930    pub fn is_copied(&self) -> bool {
931        self.0 & (1u64 << 63) != 0
932    }
933
934    pub fn is_zero(&self) -> bool {
935        self.l2_offset() == 0
936    }
937
938    pub fn reserved_bits(&self) -> u64 {
939        self.0 & 0x7f00_0000_0000_01feu64
940    }
941}
942
943impl TableEntry for L1Entry {
944    fn try_from_plain(value: u64, qcow2_info: &Qcow2Info) -> Qcow2Result<Self> {
945        let entry = L1Entry(value);
946
947        if entry.reserved_bits() != 0 {
948            return Err(format!(
949                "Invalid L1 entry 0x{:x}, reserved bits set (0x{:x})",
950                value,
951                entry.reserved_bits()
952            )
953            .into());
954        }
955
956        if qcow2_info.in_cluster_offset(entry.l2_offset()) != 0 {
957            return Err(format!(
958                "Invalid L1 entry 0x{:x}, offset (0x{:x}) is not aligned to cluster size (0x{:x})",
959                value,
960                entry.l2_offset(),
961                qcow2_info.cluster_size()
962            )
963            .into());
964        }
965
966        Ok(entry)
967    }
968
969    #[inline(always)]
970    fn into_plain(self) -> u64 {
971        self.0
972    }
973
974    #[inline(always)]
975    fn get_value(&self) -> u64 {
976        self.l2_offset()
977    }
978}
979
980#[derive(Debug)]
981pub struct L1Table {
982    header_entries: u32,
983    dirty_blocks: RefCell<VecDeque<u32>>,
984    bs_bits: u8,
985    offset: Option<u64>,
986    data: Qcow2IoBuf<L1Entry>,
987}
988
989impl L1Table {
990    pub fn new(offset: Option<u64>, data_size: usize, header_entries: u32, bs_bits: u8) -> Self {
991        let mut l1 = L1Table::new_empty(offset, data_size);
992        l1.header_entries = header_entries;
993        l1.dirty_blocks = RefCell::new(VecDeque::new());
994        l1.bs_bits = bs_bits;
995        l1
996    }
997
998    pub fn update_header_entries(&mut self, entries: u32) {
999        assert!((entries as usize) <= self.data.len());
1000        self.header_entries = entries;
1001    }
1002
1003    /// Create a clone that covers at least `at_least_index`
1004    pub fn clone_and_grow(&self, at_least_index: usize, cluster_size: usize) -> Self {
1005        let new_size = std::cmp::max(at_least_index + 1, self.data.len());
1006        let new_size = new_size.align_up(cluster_size).unwrap();
1007        let mut new_data = Qcow2IoBuf::<L1Entry>::new(new_size);
1008        new_data[..self.data.len()].copy_from_slice(&self.data);
1009
1010        Self {
1011            offset: None,
1012            data: new_data,
1013            bs_bits: self.bs_bits,
1014            header_entries: self.data.len() as u32,
1015            dirty_blocks: RefCell::new(self.dirty_blocks.borrow().clone()),
1016        }
1017    }
1018
1019    pub fn in_bounds(&self, index: usize) -> bool {
1020        index < self.header_entries as usize
1021    }
1022
1023    pub fn map_l2_offset(&mut self, index: usize, l2_offset: u64) {
1024        let l1entry = L1Entry((1 << 63) | l2_offset);
1025        debug_assert!(l1entry.reserved_bits() == 0);
1026        self.set(index, l1entry);
1027        self.set_dirty(index);
1028    }
1029}
1030
1031impl_top_table_traits!(L1Table, L1Entry, data);
1032
1033impl From<Qcow2IoBuf<L1Entry>> for L1Table {
1034    fn from(data: Qcow2IoBuf<L1Entry>) -> Self {
1035        Self {
1036            bs_bits: 0,
1037            header_entries: 0,
1038            offset: None,
1039            data,
1040            dirty_blocks: RefCell::new(VecDeque::new()),
1041        }
1042    }
1043}
1044
1045// L2 table entry:
1046//
1047// Bit  0 -  61:    Cluster descriptor
1048//
1049//      62:         0 for standard clusters
1050//                  1 for compressed clusters
1051//
1052//      63:         0 for clusters that are unused, compressed or require COW.
1053//                  1 for standard clusters whose refcount is exactly one.
1054//                  This information is only accurate in L2 tables
1055//                  that are reachable from the active L1 table.
1056//
1057//                  With external data files, all guest clusters have an
1058//                  implicit refcount of 1 (because of the fixed host = guest
1059//                  mapping for guest cluster offsets), so this bit should be 1
1060//                  for all allocated clusters.
1061//
1062// Standard Cluster Descriptor:
1063//
1064//     Bit       0:    If set to 1, the cluster reads as all zeros. The host
1065//                     cluster offset can be used to describe a preallocation,
1066//                     but it won't be used for reading data from this cluster,
1067//                     nor is data read from the backing file if the cluster is
1068//                     unallocated.
1069//
1070//                     With version 2 or with extended L2 entries (see the next
1071//                     section), this is always 0.
1072//
1073//          1 -  8:    Reserved (set to 0)
1074//
1075//          9 - 55:    Bits 9-55 of host cluster offset. Must be aligned to a
1076//                     cluster boundary. If the offset is 0 and bit 63 is clear,
1077//                     the cluster is unallocated. The offset may only be 0 with
1078//                     bit 63 set (indicating a host cluster offset of 0) when an
1079//                     external data file is used.
1080//
1081//         56 - 61:    Reserved (set to 0)
1082#[derive(Copy, Clone, Default, Debug)]
1083pub struct L2Entry(pub(crate) u64);
1084
1085/// Mapping represents the mapping of a cluster to a source of data
1086/// Mapping and L2Entry can be converted to each other.
1087#[derive(Debug, Clone)]
1088pub struct Mapping {
1089    /// Where/how to get the mapped data from
1090    pub source: MappingSource,
1091    /// Offset in `source` from which to read the whole cluster data; for compressed clusters, this
1092    /// is generally not aligned to a cluster boundary
1093    pub cluster_offset: Option<u64>,
1094    /// For compressed data: Upper limit on the number of bytes that comprise the compressed data
1095    pub compressed_length: Option<usize>,
1096    /// If this is true, `cluster_offset` may be written to, and doing so will only change this
1097    /// cluster's data (note that for zero clusters, writing to a COPIED cluster will not change
1098    /// the visible data: first, the mapping must be changed to be a data cluster)
1099    pub copied: bool,
1100}
1101
1102impl std::fmt::Display for Mapping {
1103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1104        write!(
1105            f,
1106            "Source: {:?} offset 0x{:<x} compressed_len {} copied {}",
1107            self.source,
1108            match self.cluster_offset {
1109                None => u64::MAX,
1110                Some(o) => o,
1111            },
1112            match self.compressed_length {
1113                None => usize::MIN,
1114                Some(o) => o,
1115            },
1116            self.copied,
1117        )
1118    }
1119}
1120
1121#[derive(Debug, Clone, Eq, PartialEq)]
1122pub enum MappingSource {
1123    /// Read the mapped data from the data file
1124    DataFile,
1125    /// Read the mapped data from the backing file
1126    Backing,
1127    /// This is zero data; use memset(0) instead of reading it
1128    Zero,
1129    /// Read compressed data from the data file
1130    Compressed,
1131    /// Unallocated
1132    Unallocated,
1133}
1134
1135impl L2Entry {
1136    #[inline(always)]
1137    pub fn cluster_offset(&self) -> u64 {
1138        self.0 & 0x00ff_ffff_ffff_fe00u64
1139    }
1140
1141    #[inline(always)]
1142    pub fn is_compressed(&self) -> bool {
1143        self.0 & (1u64 << 62) != 0
1144    }
1145
1146    #[inline(always)]
1147    pub fn is_copied(&self) -> bool {
1148        self.0 & (1u64 << 63) != 0
1149    }
1150
1151    #[inline(always)]
1152    pub fn is_zero(&self) -> bool {
1153        self.0 & (1u64 << 0) != 0
1154    }
1155
1156    #[inline(always)]
1157    pub fn reserved_bits(&self) -> u64 {
1158        if self.is_compressed() {
1159            self.0 & 0x8000_0000_0000_0000u64
1160        } else {
1161            self.0 & 0x3f00_0000_0000_01feu64
1162        }
1163    }
1164
1165    #[inline(always)]
1166    pub fn compressed_descriptor(&self) -> u64 {
1167        self.0 & 0x3fff_ffff_ffff_ffffu64
1168    }
1169
1170    /// If this entry is compressed, return the start host offset and upper
1171    /// limit on the compressed number of bytes
1172    #[inline(always)]
1173    pub fn compressed_range(&self, cluster_bits: u32) -> Option<(u64, usize)> {
1174        if self.is_compressed() {
1175            let desc = self.compressed_descriptor();
1176            let compressed_offset_bits = 62 - (cluster_bits - 8);
1177            let offset = desc & ((1 << compressed_offset_bits) - 1) & 0x00ff_ffff_ffff_ffffu64;
1178            let sectors = (desc >> compressed_offset_bits) as usize;
1179            // The first sector is not considered in `sectors`, so we add it and subtract the
1180            // number of bytes there that do not belong to this compressed cluster
1181            let length = (sectors + 1) * 512 - (offset & 511) as usize;
1182
1183            Some((offset, length))
1184        } else {
1185            None
1186        }
1187    }
1188
1189    /// If this entry is allocated, return the host cluster offset and the number of clusters it
1190    /// references; otherwise return None.
1191    #[inline(always)]
1192    pub fn allocation(&self, cluster_bits: u32) -> Option<(u64, usize)> {
1193        if let Some((offset, length)) = self.compressed_range(cluster_bits) {
1194            // Compressed clusters can cross host cluster boundaries, and thus occupy two clusters
1195            let cluster_size = 1u64 << cluster_bits;
1196            let cluster_base = offset & !(cluster_size - 1);
1197            let clusters =
1198                ((offset + length as u64 + cluster_size - 1) - cluster_base) >> cluster_bits;
1199            Some((cluster_base, clusters as usize))
1200        } else {
1201            match self.cluster_offset() {
1202                0 => None,
1203                ofs => Some((ofs, 1)),
1204            }
1205        }
1206    }
1207
1208    /// Convert to mapping
1209    ///
1210    /// `guest_addr` is only used for backing offset
1211    #[inline]
1212    pub fn into_mapping(self, info: &Qcow2Info, guest_addr: &SplitGuestOffset) -> Mapping {
1213        //println!("into_mapping guest {:x} l2_entry {}", guest_addr.0, self);
1214        let cluster_bits: u32 = info.cluster_bits() as u32;
1215        if let Some((offset, length)) = self.compressed_range(cluster_bits) {
1216            Mapping {
1217                source: MappingSource::Compressed,
1218                cluster_offset: Some(offset),
1219                compressed_length: Some(length),
1220                copied: false,
1221            }
1222        } else if self.is_zero() {
1223            let offset = match self.cluster_offset() {
1224                0 => None,
1225                ofs => Some(ofs),
1226            };
1227
1228            Mapping {
1229                source: MappingSource::Zero,
1230                cluster_offset: offset,
1231                compressed_length: None,
1232                copied: offset.is_some() && self.is_copied(),
1233            }
1234        } else {
1235            match self.cluster_offset() {
1236                0 => {
1237                    // in case of backing file, return backing mapping
1238                    if self.is_copied() || info.has_back_file() {
1239                        Mapping {
1240                            source: MappingSource::Backing,
1241                            cluster_offset: Some(guest_addr.cluster_offset(info)),
1242                            compressed_length: None,
1243                            copied: false,
1244                        }
1245                    } else {
1246                        Mapping {
1247                            source: MappingSource::Unallocated,
1248                            cluster_offset: Some(0),
1249                            compressed_length: None,
1250                            copied: false,
1251                        }
1252                    }
1253                }
1254                ofs => Mapping {
1255                    source: MappingSource::DataFile,
1256                    cluster_offset: Some(ofs),
1257                    compressed_length: None,
1258                    copied: self.is_copied(),
1259                },
1260            }
1261        }
1262    }
1263
1264    // Convert mapping into L2Entry
1265    #[inline]
1266    pub fn from_mapping(value: Mapping, cluster_bits: u32) -> Self {
1267        debug_assert!(value.cluster_offset.unwrap_or(0) <= 0x00ff_ffff_ffff_ffffu64);
1268
1269        let num_val: u64 = match value.source {
1270            MappingSource::DataFile => {
1271                debug_assert!(value.compressed_length.is_none());
1272                if value.copied {
1273                    (1 << 63) | value.cluster_offset.unwrap()
1274                } else {
1275                    value.cluster_offset.unwrap()
1276                }
1277            }
1278
1279            MappingSource::Backing => {
1280                debug_assert!(value.compressed_length.is_none() && !value.copied);
1281                0
1282            }
1283
1284            MappingSource::Zero => {
1285                debug_assert!(value.compressed_length.is_none());
1286                if value.copied {
1287                    (1 << 63) | value.cluster_offset.unwrap() | 0x1
1288                } else {
1289                    value.cluster_offset.unwrap_or(0) | 0x1
1290                }
1291            }
1292
1293            MappingSource::Compressed => {
1294                debug_assert!(!value.copied);
1295                let compressed_offset_bits = 62 - (cluster_bits - 8);
1296                let offset = value.cluster_offset.unwrap();
1297                let length = value.compressed_length.unwrap();
1298                assert!(length < 1 << cluster_bits);
1299
1300                // The first sector is not considered, so we subtract the number of bytes in it
1301                // that belong to this compressed cluster from `length`:
1302                // ceil((length - (512 - (offset & 511))) / 512)
1303                // = (length + 511 - 512 + (offset & 511)) / 512
1304                let sectors = (length - 1 + (offset & 511) as usize) / 512;
1305
1306                (1 << 62) | ((sectors as u64) << compressed_offset_bits) | offset
1307            }
1308            MappingSource::Unallocated => 0,
1309        };
1310
1311        let entry = L2Entry(num_val);
1312        debug_assert!(entry.reserved_bits() == 0);
1313        entry
1314    }
1315}
1316
1317impl Mapping {
1318    #[inline]
1319    pub fn plain_offset(&self, in_cluster_offset: usize) -> Option<u64> {
1320        (self.source == MappingSource::DataFile && self.copied)
1321            .then(|| self.cluster_offset.unwrap() + in_cluster_offset as u64)
1322    }
1323
1324    #[inline]
1325    pub fn allocated(&self) -> bool {
1326        self.source != MappingSource::Unallocated
1327    }
1328}
1329
1330impl TableEntry for L2Entry {
1331    fn try_from_plain(value: u64, qcow2_info: &Qcow2Info) -> Qcow2Result<Self> {
1332        let entry = L2Entry(value);
1333
1334        if entry.reserved_bits() != 0 {
1335            return Err(format!(
1336                "Invalid L2 entry 0x{:x}, reserved bits set (0x{:x})",
1337                value,
1338                entry.reserved_bits()
1339            )
1340            .into());
1341        }
1342
1343        if !entry.is_compressed() && qcow2_info.in_cluster_offset(entry.cluster_offset()) != 0 {
1344            return Err(format!(
1345                "Invalid L2 entry 0x{:x}, offset (0x{:x}) is not aligned to cluster size (0x{:x})",
1346                value,
1347                entry.cluster_offset(),
1348                qcow2_info.cluster_size()
1349            )
1350            .into());
1351        }
1352
1353        Ok(entry)
1354    }
1355
1356    fn into_plain(self) -> u64 {
1357        self.0
1358    }
1359}
1360
1361// Given an offset into the virtual disk, the offset into the image file can be
1362// obtained as follows:
1363//
1364// l2_entries = (cluster_size / sizeof(uint64_t))        [*]
1365//
1366// l2_index = (offset / cluster_size) % l2_entries
1367// l1_index = (offset / cluster_size) / l2_entries
1368//
1369// l2_table = load_cluster(l1_table[l1_index]);
1370// cluster_offset = l2_table[l2_index];
1371//
1372// return cluster_offset + (offset % cluster_size)
1373//
1374// [*] this changes if Extended L2 Entries are enabled, see next section
1375#[derive(Debug)]
1376pub struct L2Table {
1377    offset: Option<u64>,
1378    cluster_bits: u32,
1379    data: Qcow2IoBuf<L2Entry>,
1380}
1381
1382impl L2Table {
1383    #[inline]
1384    pub fn get_entry(&self, info: &Qcow2Info, lookup_addr: &SplitGuestOffset) -> L2Entry {
1385        let l2_slice_index = lookup_addr.l2_slice_index(info);
1386        self.get(l2_slice_index)
1387    }
1388
1389    #[inline]
1390    pub fn get_mapping(&self, info: &Qcow2Info, lookup_addr: &SplitGuestOffset) -> Mapping {
1391        let l2_slice_index = lookup_addr.l2_slice_index(info);
1392        let entry = self.get(l2_slice_index);
1393
1394        entry.into_mapping(info, lookup_addr)
1395    }
1396
1397    /// If the previous entry pointed to an allocated cluster, return
1398    /// the old allocation so its refcount can be decreased (offset of
1399    /// the first cluster and number of clusters -- compressed clusters
1400    /// can span across host cluster boundaries).
1401    ///
1402    /// If the allocation is reused, `None` is returned, so this function
1403    /// only returns `Some(_)` if some cluster is indeed leaked.
1404    #[must_use]
1405    pub fn map_cluster(&mut self, index: usize, host_cluster: u64) -> Option<(u64, usize)> {
1406        let allocation = self.data[index].allocation(self.cluster_bits);
1407
1408        self.set(
1409            index,
1410            L2Entry::from_mapping(
1411                Mapping {
1412                    source: MappingSource::DataFile,
1413                    cluster_offset: Some(host_cluster),
1414                    compressed_length: None,
1415                    copied: true,
1416                },
1417                self.cluster_bits,
1418            ),
1419        );
1420
1421        if let Some((a_offset, a_count)) = allocation {
1422            if a_offset == host_cluster && a_count == 1 {
1423                None
1424            } else {
1425                allocation
1426            }
1427        } else {
1428            None
1429        }
1430    }
1431
1432    /// Following L2Table creating, and we are supporting
1433    /// l2 table slice
1434    pub fn set_cluster_bits(&mut self, cluster_bits: usize) {
1435        self.cluster_bits = cluster_bits as u32;
1436    }
1437
1438    pub fn new(offset: Option<u64>, size: usize, cluster_bits: usize) -> L2Table {
1439        let mut t = L2Table::new_empty(offset, size);
1440
1441        t.set_cluster_bits(cluster_bits);
1442
1443        t
1444    }
1445}
1446
1447impl From<Qcow2IoBuf<L2Entry>> for L2Table {
1448    fn from(data: Qcow2IoBuf<L2Entry>) -> Self {
1449        Self {
1450            offset: None,
1451            cluster_bits: 0,
1452            data,
1453        }
1454    }
1455}
1456
1457impl_table_traits!(L2Table, L2Entry, data);
1458
1459#[derive(Copy, Clone, Default, Debug)]
1460pub struct RefTableEntry(pub u64);
1461
1462impl RefTableEntry {
1463    const DIRTY: u64 = 0x1;
1464    const NEW: u64 = 0x2;
1465    pub fn refblock_offset(&self) -> u64 {
1466        self.0 & 0xffff_ffff_ffff_fe00u64
1467    }
1468
1469    pub fn is_zero(&self) -> bool {
1470        self.refblock_offset() == 0
1471    }
1472
1473    pub fn reserved_bits(&self) -> u64 {
1474        self.0 & 0x0000_0000_0000_01ffu64
1475    }
1476}
1477
1478impl TableEntry for RefTableEntry {
1479    fn try_from_plain(value: u64, qcow2_info: &Qcow2Info) -> Qcow2Result<Self> {
1480        let entry = RefTableEntry(value);
1481
1482        if entry.reserved_bits() != 0 {
1483            return Err(format!(
1484                "Invalid reftable entry 0x{:x}, reserved bits set (0x{:x})",
1485                value,
1486                entry.reserved_bits()
1487            )
1488            .into());
1489        }
1490
1491        if qcow2_info.in_cluster_offset(entry.refblock_offset()) != 0 {
1492            return Err(format!(
1493                "Invalid reftable entry 0x{:x}, offset (0x{:x}) is not aligned to cluster size (0x{:x})",
1494                value,
1495                entry.refblock_offset(),
1496                qcow2_info.cluster_size()
1497            )
1498            .into());
1499        }
1500
1501        Ok(entry)
1502    }
1503
1504    #[inline(always)]
1505    fn into_plain(self) -> u64 {
1506        self.0
1507    }
1508
1509    #[inline(always)]
1510    fn get_value(&self) -> u64 {
1511        self.refblock_offset()
1512    }
1513}
1514
1515#[derive(Debug)]
1516pub struct RefTable {
1517    dirty_blocks: RefCell<VecDeque<u32>>,
1518    bs_bits: u8,
1519    offset: Option<u64>,
1520    data: Qcow2IoBuf<RefTableEntry>,
1521}
1522
1523impl RefTable {
1524    pub fn new(offset: Option<u64>, size: usize, bs_bits: u8) -> Self {
1525        let mut rt = RefTable::new_empty(offset, size);
1526
1527        rt.dirty_blocks = RefCell::new(VecDeque::new());
1528        rt.bs_bits = bs_bits;
1529        rt
1530    }
1531
1532    /// Create a clone that covers at least `at_least_index`
1533    pub fn clone_and_grow(&self, clusters: usize, cluster_size: usize, bs: usize) -> Self {
1534        let entry_size = core::mem::size_of::<RefTableEntry>();
1535        let ram_size = self.data.len() * entry_size;
1536
1537        //table in ram may not reach end of reftable in disk
1538        let (new_size, new_off) = if ram_size + entry_size < clusters * cluster_size {
1539            (ram_size + entry_size, self.offset)
1540        } else {
1541            (clusters * cluster_size + bs, None)
1542        };
1543
1544        let mut new_data = Qcow2IoBuf::<RefTableEntry>::new(new_size);
1545        new_data.zero_buf();
1546        new_data[..self.data.len()].copy_from_slice(&self.data);
1547
1548        Self {
1549            offset: new_off,
1550            data: new_data,
1551            dirty_blocks: RefCell::new(self.dirty_blocks.borrow().clone()),
1552            bs_bits: self.bs_bits,
1553        }
1554    }
1555
1556    pub fn in_bounds(&self, index: usize) -> bool {
1557        index < self.data.len()
1558    }
1559
1560    pub fn set_refblock_offset(&mut self, index: usize, rb_offset: u64) {
1561        let rt_entry = RefTableEntry(rb_offset);
1562        debug_assert!(rt_entry.reserved_bits() == 0);
1563
1564        self.set(index, rt_entry);
1565        self.set_dirty(index);
1566    }
1567}
1568
1569impl From<Qcow2IoBuf<RefTableEntry>> for RefTable {
1570    fn from(data: Qcow2IoBuf<RefTableEntry>) -> Self {
1571        Self {
1572            data,
1573            dirty_blocks: RefCell::new(VecDeque::new()),
1574            bs_bits: 0,
1575            offset: None,
1576        }
1577    }
1578}
1579
1580impl_top_table_traits!(RefTable, RefTableEntry, data);
1581
1582#[derive(Copy, Clone, Default, Debug)]
1583pub struct RefBlockEntry(u64);
1584
1585impl RefBlockEntry {
1586    #[inline(always)]
1587    pub fn is_zero(&self) -> bool {
1588        self.0 == 0
1589    }
1590}
1591impl TableEntry for RefBlockEntry {
1592    #[inline(always)]
1593    fn try_from_plain(value: u64, _qcow2_info: &Qcow2Info) -> Qcow2Result<Self> {
1594        Ok(RefBlockEntry(value))
1595    }
1596
1597    #[inline(always)]
1598    fn into_plain(self) -> u64 {
1599        self.0
1600    }
1601}
1602
1603#[derive(Debug)]
1604pub struct RefBlock {
1605    offset: Option<u64>,
1606    raw_data: Qcow2IoBuf<RefBlockEntry>,
1607    refcount_order: u8,
1608}
1609
1610impl RefBlock {
1611    pub fn new(refcount_order: u8, size: usize, offset: Option<u64>) -> Self {
1612        let mut rb = RefBlock::new_empty(offset, size);
1613
1614        rb.set_refcount_order(refcount_order);
1615        rb
1616    }
1617
1618    pub fn set_refcount_order(&mut self, refcount_order: u8) {
1619        self.refcount_order = refcount_order;
1620    }
1621
1622    #[inline(always)]
1623    fn __get(&self, index: usize) -> u64 {
1624        let raw_data = &self.raw_data.as_u8_slice();
1625        match self.refcount_order {
1626            // refcount_bits == 1
1627            0 => ((raw_data[index / 8] >> (index % 8)) & 0b0000_0001) as u64,
1628
1629            // refcount_bits == 2
1630            1 => ((raw_data[index / 4] >> (index % 4)) & 0b0000_0011) as u64,
1631
1632            // refcount_bits == 4
1633            2 => ((raw_data[index / 2] >> (index % 2)) & 0b0000_1111) as u64,
1634
1635            // refcount_bits == 8
1636            3 => raw_data[index] as u64,
1637
1638            // refcount_bits == 16
1639            4 => u16::from_be_bytes(raw_data[index * 2..index * 2 + 2].try_into().unwrap()) as u64,
1640
1641            // refcount_bits == 32
1642            5 => u32::from_be_bytes(raw_data[index * 4..index * 4 + 4].try_into().unwrap()) as u64,
1643
1644            // refcount_bits == 64
1645            6 => u64::from_be_bytes(raw_data[index * 8..index * 8 + 8].try_into().unwrap()),
1646
1647            _ => unreachable!(),
1648        }
1649    }
1650
1651    fn __set(&mut self, index: usize, value: u64) -> Qcow2Result<()> {
1652        let raw_data = &mut self.raw_data.as_u8_slice_mut();
1653        match self.refcount_order {
1654            // refcount_bits == 1
1655            0 => {
1656                if value > 0b0000_0001 {
1657                    return Err(format!(
1658                        "Cannot increase refcount beyond {} with refcount_bits=1",
1659                        0b0000_0001
1660                    )
1661                    .into());
1662                }
1663                raw_data[index / 8] = (raw_data[index / 8] & !(0b0000_0001 << (index % 8)))
1664                    | ((value as u8) << (index % 8));
1665            }
1666
1667            // refcount_bits == 2
1668            1 => {
1669                if value > 0b0000_0011 {
1670                    return Err(format!(
1671                        "Cannot increase refcount beyond {} with refcount_bits=2",
1672                        0b0000_0011
1673                    )
1674                    .into());
1675                }
1676                raw_data[index / 4] = (raw_data[index / 4] & !(0b0000_0011 << (index % 4)))
1677                    | ((value as u8) << (index % 4));
1678            }
1679
1680            // refcount_bits == 4
1681            2 => {
1682                if value > 0b0000_1111 {
1683                    return Err(format!(
1684                        "Cannot increase refcount beyond {} with refcount_bits=4",
1685                        0b0000_1111
1686                    )
1687                    .into());
1688                }
1689                raw_data[index / 2] = (raw_data[index / 2] & !(0b0000_1111 << (index % 2)))
1690                    | ((value as u8) << (index % 2));
1691            }
1692
1693            // refcount_bits == 8
1694            3 => {
1695                if value > u8::MAX as u64 {
1696                    return Err(format!(
1697                        "Cannot increase refcount beyond {} with refcount_bits=8",
1698                        u8::MAX
1699                    )
1700                    .into());
1701                }
1702                raw_data[index] = value as u8;
1703            }
1704
1705            // refcount_bits == 16
1706            4 => {
1707                if value > u16::MAX as u64 {
1708                    return Err(format!(
1709                        "Cannot increase refcount beyond {} with refcount_bits=16",
1710                        u16::MAX
1711                    )
1712                    .into());
1713                }
1714                raw_data[index * 2] = (value >> 8) as u8;
1715                raw_data[index * 2 + 1] = value as u8;
1716            }
1717
1718            // refcount_bits == 32
1719            5 => {
1720                if value > u32::MAX as u64 {
1721                    return Err(format!(
1722                        "Cannot increase refcount beyond {} with refcount_bits=32",
1723                        u32::MAX
1724                    )
1725                    .into());
1726                }
1727                raw_data[index * 4] = (value >> 24) as u8;
1728                raw_data[index * 4 + 1] = (value >> 16) as u8;
1729                raw_data[index * 4 + 2] = (value >> 8) as u8;
1730                raw_data[index * 4 + 3] = value as u8;
1731            }
1732
1733            // refcount_bits == 64
1734            6 => {
1735                let array: &mut [u8; 8] = (&mut raw_data[index * 8..index * 8 + 8])
1736                    .try_into()
1737                    .unwrap();
1738                *array = value.to_be_bytes();
1739            }
1740
1741            _ => unreachable!(),
1742        }
1743
1744        Ok(())
1745    }
1746
1747    pub fn increment(&mut self, index: usize) -> Qcow2Result<()> {
1748        let val = self
1749            .get(index)
1750            .into_plain()
1751            .checked_add(1)
1752            .ok_or_else(|| format!("Cannot increase refcount beyond {}", u64::MAX))?;
1753        self.__set(index, val)
1754    }
1755
1756    pub fn decrement(&mut self, index: usize) -> Qcow2Result<()> {
1757        let val = self
1758            .get(index)
1759            .into_plain()
1760            .checked_sub(1)
1761            .ok_or("Cannot decrease refcount below 0")?;
1762        self.__set(index, val)
1763    }
1764
1765    fn byte_indices(&self, index: usize) -> std::ops::RangeInclusive<usize> {
1766        match self.refcount_order {
1767            0 => index / 8..=index / 8,
1768            1 => index / 4..=index / 4,
1769            2 => index / 2..=index / 2,
1770            3 => index..=index,
1771            4 => index * 2..=index * 2 + 1,
1772            5 => index * 4..=index * 4 + 3,
1773            6 => index * 8..=index * 8 + 7,
1774            _ => unreachable!(),
1775        }
1776    }
1777
1778    fn check_if_free(&self, r: std::ops::Range<usize>) -> bool {
1779        for i in r {
1780            if !self.get(i).is_zero() {
1781                return false;
1782            }
1783        }
1784        true
1785    }
1786
1787    pub fn get_free_range(&self, start: usize, count: usize) -> Option<std::ops::Range<usize>> {
1788        assert!(start + count <= self.entries());
1789        let max_start = self.entries() - count;
1790
1791        for i in start..=max_start {
1792            if self.check_if_free(i..i + count) {
1793                return Some(i..i + count);
1794            }
1795        }
1796
1797        None
1798    }
1799
1800    pub fn get_tail_free_range(&self) -> Option<std::ops::Range<usize>> {
1801        let r = 0..self.entries();
1802
1803        for i in r.rev() {
1804            if !self.get(i).is_zero() {
1805                if i == self.entries() - 1 {
1806                    break;
1807                }
1808                return Some(i + 1..self.entries());
1809            }
1810        }
1811        None
1812    }
1813
1814    pub fn alloc_range(&mut self, s: usize, e: usize) -> Qcow2Result<()> {
1815        for i in s..e {
1816            self.increment(i)?;
1817        }
1818        Ok(())
1819    }
1820}
1821
1822impl Table for RefBlock {
1823    type Entry = RefBlockEntry;
1824
1825    impl_table_gen_funcs!(raw_data);
1826
1827    fn entries(&self) -> usize {
1828        self.byte_size() * 8 / (1 << self.refcount_order)
1829    }
1830
1831    fn get(&self, index: usize) -> Self::Entry {
1832        RefBlockEntry(self.__get(index))
1833    }
1834
1835    fn set(&mut self, index: usize, value: Self::Entry) {
1836        self.__set(index, value.into_plain()).unwrap();
1837    }
1838
1839    fn set_with_return(&mut self, index: usize, value: Self::Entry) -> Qcow2Result<()> {
1840        self.__set(index, value.into_plain())
1841    }
1842
1843    /// RefBlock is special, since RefBlockEntry is defined as u64
1844    fn byte_size(&self) -> usize {
1845        self.raw_data.len() * 8
1846    }
1847}
1848
1849impl From<Qcow2IoBuf<RefBlockEntry>> for RefBlock {
1850    fn from(data: Qcow2IoBuf<RefBlockEntry>) -> Self {
1851        Self {
1852            offset: None,
1853            refcount_order: 0,
1854            raw_data: data,
1855        }
1856    }
1857}
1858
1859pub trait TableEntry
1860where
1861    Self: Copy + Sized + std::fmt::Debug,
1862{
1863    fn try_from_plain(value: u64, qcow2_info: &Qcow2Info) -> Qcow2Result<Self>;
1864    fn into_plain(self) -> u64;
1865
1866    /// Only for top table to return offset stored
1867    #[inline(always)]
1868    fn get_value(&self) -> u64 {
1869        panic!();
1870    }
1871}
1872
1873pub trait Table: From<Qcow2IoBuf<Self::Entry>> {
1874    type Entry: TableEntry;
1875
1876    fn entries(&self) -> usize;
1877    fn get(&self, index: usize) -> Self::Entry;
1878    fn set(&mut self, index: usize, value: Self::Entry);
1879    fn get_offset(&self) -> Option<u64>;
1880    fn set_offset(&mut self, offset: Option<u64>);
1881
1882    fn as_ptr(&self) -> *const u8;
1883    fn as_mut_ptr(&mut self) -> *mut u8;
1884
1885    fn set_with_return(&mut self, index: usize, value: Self::Entry) -> Qcow2Result<()> {
1886        self.set(index, value);
1887        Ok(())
1888    }
1889
1890    fn byte_size(&self) -> usize {
1891        self.entries() * size_of::<u64>()
1892    }
1893
1894    fn cluster_count(&self, qcow2_info: &Qcow2Info) -> usize {
1895        (self.byte_size() + qcow2_info.cluster_size() - 1) / qcow2_info.cluster_size()
1896    }
1897
1898    fn is_update(&self) -> bool {
1899        self.get_offset().is_some()
1900    }
1901
1902    fn new_empty(offset: Option<u64>, size: usize) -> Self {
1903        let table = Qcow2IoBuf::<Self::Entry>::new(size);
1904        unsafe {
1905            std::ptr::write_bytes(table.as_mut_ptr(), 0, table.len());
1906        }
1907        let mut table: Self = table.into();
1908        table.set_offset(offset);
1909
1910        table
1911    }
1912
1913    #[inline(always)]
1914    fn set_dirty(&self, _idx: usize) {}
1915
1916    #[inline(always)]
1917    fn pop_dirty_blk_idx(&self, _val: Option<u32>) -> Option<u32> {
1918        None
1919    }
1920}
1921
1922#[cfg(test)]
1923mod tests {
1924    use crate::dev::*;
1925    use crate::meta::*;
1926
1927    #[test]
1928    fn test_l1_table() {
1929        let cluster_size = 1 << 16;
1930        let size = 4096;
1931
1932        let mut l1 = L1Table::new_empty(Some(cluster_size), 4096);
1933        assert!(l1.entries() == (size / core::mem::size_of::<u64>()));
1934        assert!(l1.as_ptr() != std::ptr::null());
1935
1936        let entry = l1.get(0);
1937        assert!(entry.is_zero() == true);
1938
1939        let l2_offset = cluster_size * 3;
1940        l1.set(0, L1Entry(l2_offset));
1941        let entry = l1.get(0);
1942        assert!(entry.l2_offset() == l2_offset);
1943
1944        let raw_addr = l1.as_ptr() as *const u64;
1945        unsafe {
1946            assert!(u64::from_be(*raw_addr) == l2_offset);
1947        };
1948    }
1949
1950    #[test]
1951    fn test_refcount_table() {
1952        let cluster_size = 1 << 16;
1953        let size = 4096;
1954
1955        let mut rc = RefTable::new_empty(Some(cluster_size), 4096);
1956        assert!(rc.entries() == (size / core::mem::size_of::<u64>()));
1957        assert!(rc.as_ptr() != std::ptr::null());
1958
1959        let entry = rc.get(0);
1960        assert!(entry.is_zero() == true);
1961
1962        let rcb_offset = cluster_size * 3;
1963        rc.set(0, RefTableEntry(rcb_offset));
1964        let entry = rc.get(0);
1965        assert!(entry.refblock_offset() == rcb_offset);
1966
1967        let raw_addr = rc.as_ptr() as *const u64;
1968        unsafe {
1969            assert!(u64::from_be(*raw_addr) == rcb_offset);
1970        };
1971    }
1972
1973    #[test]
1974    fn test_refcount_block() {
1975        let cluster_size = 1 << 16;
1976        let size = 4096;
1977        let refcount_order = 4;
1978        let entries = size * 8 / (1 << refcount_order);
1979
1980        let mut rc_b = RefBlock::new(refcount_order, size, Some(2 * cluster_size));
1981        assert!(rc_b.entries() == entries);
1982        assert!(rc_b.as_ptr() != std::ptr::null());
1983
1984        for i in 0..entries {
1985            let entry = rc_b.get(i).into_plain();
1986            assert!(entry == 0);
1987            rc_b.increment(i).unwrap();
1988            let entry = rc_b.get(i).into_plain();
1989            assert!(entry == 1);
1990        }
1991    }
1992
1993    #[test]
1994    fn test_l2_table() {
1995        let cluster_bits = 16;
1996        let cluster_size = 1 << cluster_bits;
1997        let size = 4096;
1998
1999        let l2 = L2Table::new(Some(cluster_size * 4), size, cluster_bits);
2000        assert!(l2.cluster_bits == cluster_bits as u32);
2001    }
2002
2003    /// more detailed unit test generated by AI with small fixes
2004    #[test]
2005    fn test_refcount_block2() {
2006        let mut refblock = RefBlock::new(3, 4096, Some(0));
2007        assert_eq!(refblock.entries(), 4096);
2008        assert_eq!(refblock.byte_size(), 4096);
2009        assert_eq!(refblock.get_offset(), Some(0));
2010
2011        assert!(refblock.get(0).is_zero());
2012
2013        assert!(refblock.increment(0).is_ok());
2014        assert_eq!(refblock.get(0).into_plain(), 1);
2015
2016        assert!(refblock.decrement(0).is_ok());
2017        assert_eq!(refblock.get(0).into_plain(), 0);
2018
2019        assert!(refblock.set_with_return(0, RefBlockEntry(255)).is_ok());
2020        assert!(refblock.set_with_return(0, RefBlockEntry(1)).is_ok());
2021        assert_eq!(refblock.get(0).into_plain(), 1);
2022
2023        assert!(refblock.set_with_return(0, RefBlockEntry(256)).is_err());
2024        assert!(refblock.set_with_return(0, RefBlockEntry(255)).is_ok());
2025        assert_eq!(refblock.get(0).into_plain(), 255);
2026
2027        assert!(refblock
2028            .set_with_return(0, RefBlockEntry(u16::MAX as u64 + 1))
2029            .is_err());
2030        assert!(refblock
2031            .set_with_return(0, RefBlockEntry(u16::MAX as u64))
2032            .is_err());
2033
2034        assert!(refblock
2035            .set_with_return(0, RefBlockEntry(u32::MAX as u64 + 1))
2036            .is_err());
2037        assert!(refblock
2038            .set_with_return(0, RefBlockEntry(u32::MAX as u64))
2039            .is_err());
2040
2041        assert!(refblock
2042            .set_with_return(0, RefBlockEntry(u64::MAX))
2043            .is_err());
2044    }
2045
2046    #[test]
2047    fn test_format() {
2048        fn __test_format(cluster_bits: usize, refcount_order: u8, size: u64) {
2049            let p = crate::qcow2_default_params!(true, true);
2050            let bs = 1 << p.get_bs_bits();
2051            let (rc_t, rc_b, _) =
2052                Qcow2Header::calculate_meta_params(size, cluster_bits, refcount_order, bs);
2053            let clusters = 1 + rc_t.1 + rc_b.1;
2054            let img_size = ((clusters as usize) << cluster_bits) + 512;
2055            let mut buf = vec![0u8; img_size];
2056
2057            Qcow2Header::format_qcow2(&mut buf, size, cluster_bits, refcount_order, bs).unwrap();
2058
2059            let header = Qcow2Header::from_buf(&buf).unwrap();
2060            let info = Qcow2Info::new(&header, &p).unwrap();
2061
2062            assert!(info.cluster_bits() == cluster_bits);
2063            assert!(info.virtual_size() == size);
2064            assert!(info.refcount_order() == refcount_order);
2065        }
2066
2067        let sizes = [64 << 20, 64 << 30, 2 << 40];
2068
2069        for c in 13..21 {
2070            for r in 1..7 {
2071                for s in sizes {
2072                    __test_format(c, r, s);
2073                }
2074            }
2075        }
2076    }
2077}