vsc/block.rs
1//! Typed diff-area records: the block descriptor and store block range.
2//!
3//! Phase 1 parses these two records so a consumer sees the copy-on-write mapping
4//! structurally. The full snapshot-reconstruction engine (overlaying diff-area
5//! blocks to materialize a snapshot's view of the volume) is Phase 2 and is
6//! deliberately **not** implemented here.
7
8use crate::bytes::{le_u32, le_u64};
9
10/// Length of a block descriptor record, in bytes.
11pub const BLOCK_DESCRIPTOR_LEN: usize = 32;
12
13/// Length of a store block range record, in bytes.
14pub const STORE_BLOCK_RANGE_LEN: usize = 24;
15
16/// Flags on a block descriptor.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct BlockDescriptorFlags(pub u32);
19
20impl BlockDescriptorFlags {
21 /// Forwarder — maps to the next block's original offset.
22 pub const FORWARDER: u32 = 0x01;
23 /// Overlay — the allocation bitmap defines how the block is filled.
24 pub const OVERLAY: u32 = 0x02;
25 /// Not used — the block is ignored.
26 pub const NOT_USED: u32 = 0x04;
27
28 /// The raw flag bits.
29 #[must_use]
30 pub fn bits(self) -> u32 {
31 self.0
32 }
33
34 /// Whether any of the given flag bits are set.
35 #[must_use]
36 pub fn contains(self, flag: u32) -> bool {
37 self.0 & flag != 0
38 }
39
40 /// Whether the forwarder flag is set.
41 #[must_use]
42 pub fn is_forwarder(self) -> bool {
43 self.contains(Self::FORWARDER)
44 }
45
46 /// Whether the overlay flag is set.
47 #[must_use]
48 pub fn is_overlay(self) -> bool {
49 self.contains(Self::OVERLAY)
50 }
51
52 /// Whether the not-used flag is set.
53 #[must_use]
54 pub fn is_not_used(self) -> bool {
55 self.contains(Self::NOT_USED)
56 }
57}
58
59/// A 32-byte diff-area block descriptor: it maps an original volume block to the
60/// copy-on-write block saved in the store.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct BlockDescriptor {
63 /// Original data block offset (volume-relative).
64 pub original_offset: u64,
65 /// Relative store data block offset (store-relative).
66 pub relative_store_offset: u64,
67 /// Store data block offset (volume-relative).
68 pub store_offset: u64,
69 /// Flags.
70 pub flags: BlockDescriptorFlags,
71 /// Allocation bitmap (used when the overlay flag is set).
72 pub allocation_bitmap: u32,
73}
74
75impl BlockDescriptor {
76 /// Parse a 32-byte block descriptor.
77 #[must_use]
78 pub fn parse(buf: &[u8]) -> Self {
79 BlockDescriptor {
80 original_offset: le_u64(buf, 0),
81 relative_store_offset: le_u64(buf, 8),
82 store_offset: le_u64(buf, 16),
83 flags: BlockDescriptorFlags(le_u32(buf, 24)),
84 allocation_bitmap: le_u32(buf, 28),
85 }
86 }
87}
88
89/// A 24-byte store block range record.
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub struct StoreBlockRange {
92 /// Store block range start offset (volume-relative).
93 pub store_offset: u64,
94 /// Relative block range start offset (store-relative).
95 pub relative_offset: u64,
96 /// Block range size, in bytes.
97 pub range_size: u64,
98}
99
100impl StoreBlockRange {
101 /// Parse a 24-byte store block range record.
102 #[must_use]
103 pub fn parse(buf: &[u8]) -> Self {
104 StoreBlockRange {
105 store_offset: le_u64(buf, 0),
106 relative_offset: le_u64(buf, 8),
107 range_size: le_u64(buf, 16),
108 }
109 }
110}