GUID Partition Table (GPT) 取代傳統 MBR,支援 2TB 以上磁碟、128 個分區、CRC32 校驗、備份表頭。關鍵結構:
#define LOGICAL_BLOCK_SIZE 512
typedef struct {
uint8_t signature[8]; // "EFI PART"
uint8_t revision[4]; // 0x00010000
uint32_t header_size; // 92 bytes
uint32_t crc32_header; // Header CRC32
uint32_t reserved1;
uint64_t current_lba; // 1
uint64_t backup_lba; // Last LBA
uint64_t first_usable_lba; // 34
uint64_t last_usable_lba; // Last - 33
uint8_t disk_guid[16]; // Disk UUID
uint64_t partition_entry_lba; // 2
uint32_t num_partition_entries; // 128
uint32_t partition_entry_size; // 128
uint32_t crc32_partitions; // Partition Array CRC32
} __attribute__((packed)) gpt_header;
typedef struct {
uint8_t type_guid[16]; // Partition Type GUID
uint8_t unique_guid[16]; // Partition Unique GUID
uint64_t first_lba;
uint64_t last_lba;
uint64_t attributes;
uint16_t name[36]; // UTF-16LE
} __attribute__((packed)) gpt_partition_entry;
uint32_t crc32_tab[256] = { /* 標準多項式 0xEDB88320 查表 */ };
uint32_t efi_crc32(const void *buf, size_t len) {
uint32_t crc = ~0U;
const uint8_t *p = buf;
for (size_t i = 0; i < len; ++i)
crc = crc32_tab[(crc ^ p[i]) & 0xFF] ^ (crc >> 8);
return ~crc;
}
open("/dev/sdX", O_RDONLY)partition_entry_lba 讀取分區陣列
int parse_gpt(int fd) {
gpt_header hdr;
lseek(fd, LOGICAL_BLOCK_SIZE, SEEK_SET); // LBA 1
read(fd, &hdr, sizeof(hdr));
if (memcmp(hdr.signature, "EFI PART", 8) != 0) return -1;
if (efi_crc32(&hdr, hdr.header_size) != hdr.crc32_header) return -2;
size_t entries_size = hdr.num_partition_entries * hdr.partition_entry_size;
void *entries = malloc(entries_size);
lseek(fd, hdr.partition_entry_lba * LOGICAL_BLOCK_SIZE, SEEK_SET);
read(fd, entries, entries_size);
if (efi_crc32(entries, entries_size) != hdr.crc32_partitions) { free(entries); return -3; }
gpt_partition_entry *pe = entries;
for (uint32_t i = 0; i < hdr.num_partition_entries; ++i, ++pe) {
if (pe->type_guid[0] == 0 && ... ) continue; // 空項目
// 解析 pe->first_lba, pe->last_lba, pe->name (UTF-16 轉 UTF-8)
print_partition(pe);
}
free(entries);
return 0;
}
char *utf16_to_utf8(const uint16_t *src, int len) {
char *dst = malloc(len * 3 + 1);
int j = 0;
for (int i = 0; i < len; ++i) {
uint16_t c = src[i];
if (c < 0x80) dst[j++] = c;
else if (c < 0x800) { dst[j++] = 0xC0 | (c >> 6); dst[j++] = 0x80 | (c & 0x3F); }
else { dst[j++] = 0xE0 | (c >> 12); dst[j++] = 0x80 | ((c >> 6) & 0x3F); dst[j++] = 0x80 | (c & 0x3F); }
}
dst[j] = 0;
return dst;
}
gcc -std=c99 -Wall -o gpt_parser gpt_parser.c
sudo ./gpt_parser /dev/sda
lseek(fd, -LOGICAL_BLOCK_SIZE, SEEK_END)