1use crate::xml::HashType;
2
3use thiserror::Error;
4
5#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6#[non_exhaustive]
7pub enum HashValue {
8 Sha256([u8; 32]),
9}
10
11impl HashValue {
12 pub fn to_type(&self) -> HashType {
13 match self {
14 HashValue::Sha256(_) => HashType::Sha256,
15 }
16 }
17
18 pub fn as_slice(&self) -> &[u8] {
19 match self {
20 HashValue::Sha256(v) => v,
21 }
22 }
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct BlockRange {
27 offset: u64,
28 length: u64,
29 checksum: HashValue,
30}
31
32impl BlockRange {
33 pub fn checksum(&self) -> HashValue {
34 self.checksum
35 }
36
37 pub fn offset(&self) -> u64 {
38 self.offset
39 }
40
41 pub fn length(&self) -> u64 {
42 self.length
43 }
44}
45
46#[derive(Clone, Debug)]
47pub struct Bmap {
48 image_size: u64,
49 block_size: u64,
50 blocks: u64,
51 mapped_blocks: u64,
52 checksum_type: HashType,
53 blockmap: Vec<BlockRange>,
54}
55
56impl Bmap {
57 pub fn builder() -> BmapBuilder {
58 BmapBuilder::default()
59 }
60
61 pub fn from_xml(xml: &str) -> Result<Self, crate::xml::XmlError> {
63 crate::xml::from_xml(xml)
64 }
65
66 pub fn image_size(&self) -> u64 {
68 self.image_size
69 }
70
71 pub const fn block_size(&self) -> u64 {
73 self.block_size
74 }
75
76 pub fn blocks(&self) -> u64 {
78 self.blocks
79 }
80
81 pub fn mapped_blocks(&self) -> u64 {
83 self.mapped_blocks
84 }
85
86 pub fn checksum_type(&self) -> HashType {
88 self.checksum_type
89 }
90
91 pub fn block_map(&self) -> impl ExactSizeIterator<Item = &BlockRange> {
93 self.blockmap.iter()
94 }
95
96 pub fn total_mapped_size(&self) -> u64 {
98 self.block_size * self.mapped_blocks
99 }
100}
101
102#[derive(Clone, Debug, Error)]
103pub enum BmapBuilderError {
104 #[error("Image size missing")]
105 MissingImageSize,
106 #[error("Block size missing")]
107 MissingBlockSize,
108 #[error("Blocks missing")]
109 MissingBlocks,
110 #[error("Mapped blocks missing")]
111 MissingMappedBlocks,
112 #[error("Checksum type missing")]
113 MissingChecksumType,
114 #[error("No block ranges")]
115 NoBlockRanges,
116}
117
118#[derive(Clone, Debug, Default)]
119pub struct BmapBuilder {
120 image_size: Option<u64>,
121 block_size: Option<u64>,
122 blocks: Option<u64>,
123 checksum_type: Option<HashType>,
124 mapped_blocks: Option<u64>,
125 blockmap: Vec<BlockRange>,
126}
127
128impl BmapBuilder {
129 pub fn image_size(&mut self, size: u64) -> &mut Self {
130 self.image_size = Some(size);
131 self
132 }
133
134 pub fn block_size(&mut self, block_size: u64) -> &mut Self {
135 self.block_size = Some(block_size);
136 self
137 }
138
139 pub fn blocks(&mut self, blocks: u64) -> &mut Self {
140 self.blocks = Some(blocks);
141 self
142 }
143
144 pub fn mapped_blocks(&mut self, blocks: u64) -> &mut Self {
145 self.mapped_blocks = Some(blocks);
146 self
147 }
148
149 pub fn checksum_type(&mut self, checksum_type: HashType) -> &mut Self {
150 self.checksum_type = Some(checksum_type);
151 self
152 }
153
154 pub fn add_block_range(&mut self, start: u64, end: u64, checksum: HashValue) -> &mut Self {
155 let bs = self.block_size.expect("Blocksize needs to be set first");
156 let total = self.image_size.expect("Image size needs to be set first");
157 let offset = start * bs;
158 let length = (total - offset).min((end - start + 1) * bs);
159 self.add_byte_range(offset, length, checksum)
160 }
161
162 pub fn add_byte_range(&mut self, offset: u64, length: u64, checksum: HashValue) -> &mut Self {
163 let range = BlockRange {
164 offset,
165 length,
166 checksum,
167 };
168 self.blockmap.push(range);
169 self
170 }
171
172 pub fn build(self) -> Result<Bmap, BmapBuilderError> {
173 let image_size = self.image_size.ok_or(BmapBuilderError::MissingImageSize)?;
174 let block_size = self.block_size.ok_or(BmapBuilderError::MissingBlockSize)?;
175 let blocks = self.blocks.ok_or(BmapBuilderError::MissingBlocks)?;
176 let mapped_blocks = self
177 .mapped_blocks
178 .ok_or(BmapBuilderError::MissingMappedBlocks)?;
179 let checksum_type = self
180 .checksum_type
181 .ok_or(BmapBuilderError::MissingChecksumType)?;
182 let blockmap = self.blockmap;
183
184 Ok(Bmap {
185 image_size,
186 block_size,
187 blocks,
188 mapped_blocks,
189 checksum_type,
190 blockmap,
191 })
192 }
193}
194
195#[cfg(test)]
196mod test {
197 use super::*;
198
199 #[test]
200 fn hashes() {
201 let h = HashValue::Sha256([0; 32]);
202 assert_eq!(HashType::Sha256, h.to_type());
203 }
204}