Skip to main content

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}