1use crate::bytes::{le_arr16, le_u32, le_u64};
2use crate::error::{Result, VhdxError};
3
4pub const HEADER1_OFFSET: u64 = 0x0001_0000; pub const HEADER2_OFFSET: u64 = 0x0002_0000; pub const REGION_TABLE1_OFFSET: u64 = 0x0003_0000; pub const REGION_TABLE2_OFFSET: u64 = 0x0004_0000; pub const HEADER_SIGNATURE: &[u8; 4] = b"head";
12pub const HEADER_SIZE: usize = 4096;
13
14#[derive(Debug, Clone)]
16pub struct VhdxHeader {
17 pub sequence_number: u64,
18 pub log_guid: [u8; 16],
19 pub log_offset: u64,
20 pub log_length: u32,
21}
22
23pub fn parse_active_header(data: &[u8]) -> Result<VhdxHeader> {
26 let h1 = parse_one_header(data, HEADER1_OFFSET as usize);
27 let h2 = parse_one_header(data, HEADER2_OFFSET as usize);
28 match (h1, h2) {
29 (Ok(a), Ok(b)) => {
30 if a.sequence_number >= b.sequence_number {
31 Ok(a)
32 } else {
33 Ok(b)
34 }
35 }
36 (Ok(a), Err(_)) => Ok(a),
37 (Err(_), Ok(b)) => Ok(b),
38 (Err(_), Err(_)) => Err(VhdxError::NoValidHeader),
39 }
40}
41
42fn parse_one_header(data: &[u8], offset: usize) -> Result<VhdxHeader> {
43 let end = offset
44 .checked_add(HEADER_SIZE)
45 .ok_or(VhdxError::NoValidHeader)?;
46 if data.len() < end {
47 return Err(VhdxError::NoValidHeader);
48 }
49 let slice = &data[offset..end];
50 if &slice[0..4] != HEADER_SIGNATURE {
51 return Err(VhdxError::NoValidHeader);
52 }
53 if !verify_crc32c(slice) {
54 return Err(VhdxError::NoValidHeader);
55 }
56 let sequence_number = le_u64(slice, 8);
57 let log_guid: [u8; 16] = le_arr16(slice, 48);
58 let log_length = le_u32(slice, 68);
59 let log_offset = le_u64(slice, 72);
60 Ok(VhdxHeader {
61 sequence_number,
62 log_guid,
63 log_offset,
64 log_length,
65 })
66}
67
68fn verify_crc32c(block: &[u8]) -> bool {
69 let stored = le_u32(block, 4);
70 let mut buf = block.to_vec();
71 buf[4..8].fill(0);
72 crc32c(&buf) == stored
73}
74
75pub fn crc32c(data: &[u8]) -> u32 {
76 const POLY: u32 = 0x82F6_3B78;
77 let mut crc: u32 = 0xFFFF_FFFF;
78 for &byte in data {
79 crc ^= u32::from(byte);
80 for _ in 0..8 {
81 if crc & 1 != 0 {
82 crc = (crc >> 1) ^ POLY;
83 } else {
84 crc >>= 1;
85 }
86 }
87 }
88 crc ^ 0xFFFF_FFFF
89}