8constexpr size_t MaxEntries = 4096, MaxArrayBytes = 1024 * 1024;
9inline uint64_t little(
const uint8_t* data,
size_t count) {
11 for (
size_t i = 0; i < count; ++i)
12 value |=
static_cast<uint64_t
>(data[i]) << (i * 8);
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);
25 uint64_t first, last, table;
26 size_t count, stride, bytes;
29inline bool decode(
const uint8_t* data,
size_t sectorBytes, uint64_t sectors,
bool backup,
31 if (sectorBytes < 512 || sectorBytes > 4096 || (sectorBytes & (sectorBytes - 1)) || sectors < 6 ||
32 little(data, 8) != 0x5452415020494645ULL || little(data + 8, 4) != 0x10000 ||
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))
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)
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)
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;
62inline bool used(
const uint8_t* entry) {
63 return little(entry, 8) || little(entry + 8, 8);
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};
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];
78inline bool validEntries(
const uint8_t* data,
const Header& header) {
79 if (crc(data, header.bytes) != header.checksum)
81 for (
size_t i = 0; i < header.count; ++i) {
82 const uint8_t* entry = data + i * header.stride;
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)))
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))))
101bool gptProbeDisk(
Disk* disk);