1use crate::crc32;
8use crate::guid::Guid;
9use crate::Error;
10
11pub const SIGNATURE: &[u8; 8] = b"EFI PART";
13pub const MIN_HEADER_SIZE: u32 = 92;
15const HEADER_CRC_OFFSET: usize = 16;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21pub struct GptHeader {
22 pub revision: u32,
24 pub header_size: u32,
26 pub header_crc32: u32,
28 pub header_crc_valid: bool,
30 pub my_lba: u64,
32 pub alternate_lba: u64,
34 pub first_usable_lba: u64,
36 pub last_usable_lba: u64,
38 pub disk_guid: Guid,
40 pub partition_entry_lba: u64,
42 pub num_partition_entries: u32,
44 pub partition_entry_size: u32,
46 pub partition_array_crc32: u32,
48}
49
50fn u32_le(b: &[u8], off: usize) -> u32 {
51 u32::from_le_bytes([b[off], b[off + 1], b[off + 2], b[off + 3]])
52}
53fn u64_le(b: &[u8], off: usize) -> u64 {
54 let mut a = [0u8; 8];
55 a.copy_from_slice(&b[off..off + 8]);
56 u64::from_le_bytes(a)
57}
58
59impl GptHeader {
60 pub fn parse(sector: &[u8]) -> Result<GptHeader, Error> {
66 if sector.len() < MIN_HEADER_SIZE as usize {
67 return Err(Error::TooShort {
68 need: MIN_HEADER_SIZE as usize,
69 got: sector.len(),
70 });
71 }
72 if §or[0..8] != SIGNATURE {
73 return Err(Error::BadSignature);
74 }
75
76 let header_size = u32_le(sector, 12);
77 let header_crc32 = u32_le(sector, 16);
78 let header_crc_valid = compute_header_crc(sector, header_size)
79 .is_some_and(|computed| computed == header_crc32);
80
81 let mut disk_guid = [0u8; 16];
82 disk_guid.copy_from_slice(§or[56..72]);
83
84 Ok(GptHeader {
85 revision: u32_le(sector, 8),
86 header_size,
87 header_crc32,
88 header_crc_valid,
89 my_lba: u64_le(sector, 24),
90 alternate_lba: u64_le(sector, 32),
91 first_usable_lba: u64_le(sector, 40),
92 last_usable_lba: u64_le(sector, 48),
93 disk_guid: Guid(disk_guid),
94 partition_entry_lba: u64_le(sector, 72),
95 num_partition_entries: u32_le(sector, 80),
96 partition_entry_size: u32_le(sector, 84),
97 partition_array_crc32: u32_le(sector, 88),
98 })
99 }
100}
101
102fn compute_header_crc(sector: &[u8], header_size: u32) -> Option<u32> {
105 let size = header_size as usize;
106 if header_size < MIN_HEADER_SIZE || size > sector.len() {
107 return None;
108 }
109 let mut buf = sector[..size].to_vec();
110 buf[HEADER_CRC_OFFSET..HEADER_CRC_OFFSET + 4].fill(0);
111 Some(crc32::checksum(&buf))
112}