1#![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 #[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 magic: u32,
137
138 version: u32,
140
141 backing_file_offset: u64,
148
149 backing_file_size: u32,
153
154 cluster_bits: u32,
165
166 size: u64,
179
180 crypt_method: u32,
184
185 l1_size: u32,
187
188 l1_table_offset: u64,
191
192 refcount_table_offset: u64,
195
196 refcount_table_clusters: u32,
198
199 nb_snapshots: u32,
201
202 snapshots_offset: u64,
205
206 incompatible_features: u64,
244
245 compatible_features: u64,
255
256 autoclear_features: u64,
288
289 refcount_order: u32,
295
296 header_length: u32,
301
302 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 extension_type: u32,
336
337 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 (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 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 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 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 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 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 ref_b.increment(0)?;
609 assert!(ref_b.get(0).into_plain() == 1);
610
611 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 ref_b.increment((rc_table.1 as usize) + 1)?;
620
621 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 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 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 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, };
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 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#[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 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#[derive(Copy, Clone, Default, Debug)]
1083pub struct L2Entry(pub(crate) u64);
1084
1085#[derive(Debug, Clone)]
1088pub struct Mapping {
1089 pub source: MappingSource,
1091 pub cluster_offset: Option<u64>,
1094 pub compressed_length: Option<usize>,
1096 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 DataFile,
1125 Backing,
1127 Zero,
1129 Compressed,
1131 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 #[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 let length = (sectors + 1) * 512 - (offset & 511) as usize;
1182
1183 Some((offset, length))
1184 } else {
1185 None
1186 }
1187 }
1188
1189 #[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 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 #[inline]
1212 pub fn into_mapping(self, info: &Qcow2Info, guest_addr: &SplitGuestOffset) -> Mapping {
1213 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 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 #[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 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#[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 #[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 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 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 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 0 => ((raw_data[index / 8] >> (index % 8)) & 0b0000_0001) as u64,
1628
1629 1 => ((raw_data[index / 4] >> (index % 4)) & 0b0000_0011) as u64,
1631
1632 2 => ((raw_data[index / 2] >> (index % 2)) & 0b0000_1111) as u64,
1634
1635 3 => raw_data[index] as u64,
1637
1638 4 => u16::from_be_bytes(raw_data[index * 2..index * 2 + 2].try_into().unwrap()) as u64,
1640
1641 5 => u32::from_be_bytes(raw_data[index * 4..index * 4 + 4].try_into().unwrap()) as u64,
1643
1644 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 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 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 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 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 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 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 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 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 #[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 #[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}