The Pedigree Project 0.1
Gpt.h
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2#ifndef PEDIGREE_GPT_H
3#define PEDIGREE_GPT_H
4#include <stddef.h>
5#include <stdint.h>
6
7namespace Gpt {
8constexpr size_t MaxEntries = 4096, MaxArrayBytes = 1024 * 1024;
9inline uint64_t little(const uint8_t* data, size_t count) {
10 uint64_t value = 0;
11 for (size_t i = 0; i < count; ++i)
12 value |= static_cast<uint64_t>(data[i]) << (i * 8);
13 return value;
14}
15inline uint32_t crc(const uint8_t* bytes, size_t length, bool header = false) {
16 uint32_t value = 0xffffffffU;
17 for (size_t i = 0; i < length; ++i) {
18 value ^= header && i >= 16 && i < 20 ? 0 : bytes[i];
19 for (size_t bit = 0; bit < 8; ++bit)
20 value = (value >> 1) ^ ((value & 1) ? 0xedb88320U : 0);
21 }
22 return ~value;
23}
24struct Header {
25 uint64_t first, last, table;
26 size_t count, stride, bytes;
27 uint32_t checksum;
28};
29inline bool decode(const uint8_t* data, size_t sectorBytes, uint64_t sectors, bool backup,
30 Header& result) {
31 if (sectorBytes < 512 || sectorBytes > 4096 || (sectorBytes & (sectorBytes - 1)) || sectors < 6 ||
32 little(data, 8) != 0x5452415020494645ULL || little(data + 8, 4) != 0x10000 ||
33 little(data + 20, 4))
34 return false;
35 const size_t length = little(data + 12, 4);
36 if (length < 92 || length > sectorBytes || crc(data, length, true) != little(data + 16, 4) ||
37 little(data + 24, 8) != (backup ? sectors - 1 : 1) ||
38 little(data + 32, 8) != (backup ? 1 : sectors - 1))
39 return false;
40 result.first = little(data + 40, 8);
41 result.last = little(data + 48, 8);
42 result.table = little(data + 72, 8);
43 result.count = little(data + 80, 4);
44 result.stride = little(data + 84, 4);
45 result.checksum = little(data + 88, 4);
46 if (!result.count || result.count > MaxEntries || result.stride < 128 ||
47 (result.stride & (result.stride - 1)) || result.stride > MaxArrayBytes / result.count)
48 return false;
49 result.bytes = result.count * result.stride;
50 const size_t blocks = (result.bytes + sectorBytes - 1) / sectorBytes;
51 const size_t reserved = (result.bytes < 16384 ? 16384 : result.bytes) / sectorBytes +
52 ((result.bytes < 16384 ? 16384 : result.bytes) % sectorBytes != 0);
53 if (result.first < 2 + reserved || result.first > result.last || reserved + 1 >= sectors ||
54 result.last >= sectors - reserved - 1 || result.table >= sectors ||
55 blocks > sectors - result.table)
56 return false;
57 return backup ? result.table > result.last && result.table < sectors - 1 &&
58 blocks <= sectors - 1 - result.table
59 : result.table > 1 && result.table < result.first &&
60 blocks <= result.first - result.table;
61}
62inline bool used(const uint8_t* entry) {
63 return little(entry, 8) || little(entry + 8, 8);
64}
65inline void formatGuid(const uint8_t* value, char (&result)[37]) {
66 static constexpr char digits[] = "0123456789abcdef";
67 static constexpr uint8_t order[] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15};
68 size_t output = 0;
69 for (size_t i = 0; i < sizeof(order); ++i) {
70 if (i == 4 || i == 6 || i == 8 || i == 10)
71 result[output++] = '-';
72 const uint8_t byte = value[order[i]];
73 result[output++] = digits[byte >> 4];
74 result[output++] = digits[byte & 0xf];
75 }
76 result[output] = 0;
77}
78inline bool validEntries(const uint8_t* data, const Header& header) {
79 if (crc(data, header.bytes) != header.checksum)
80 return false;
81 for (size_t i = 0; i < header.count; ++i) {
82 const uint8_t* entry = data + i * header.stride;
83 if (!used(entry))
84 continue;
85 const uint64_t start = little(entry + 32, 8), end = little(entry + 40, 8);
86 if (start < header.first || start > end || end > header.last ||
87 !(little(entry + 16, 8) || little(entry + 24, 8)))
88 return false;
89 for (size_t j = 0; j < i; ++j) {
90 const uint8_t* other = data + j * header.stride;
91 if (used(other) && ((start <= little(other + 40, 8) && little(other + 32, 8) <= end) ||
92 (little(entry + 16, 8) == little(other + 16, 8) &&
93 little(entry + 24, 8) == little(other + 24, 8))))
94 return false;
95 }
96 }
97 return true;
98}
99} // namespace Gpt
100class Disk;
101bool gptProbeDisk(Disk* disk);
102#endif
Definition Disk.h:35