首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言解析 GPT 分區表與保護性 MBR (GCC/Linux)

     編輯:關於C語言

GPT 結構概覽

GUID Partition Table (GPT) 取代傳統 MBR,支援 2TB 以上磁碟、128 個分區、CRC32 校驗、備份表頭。關鍵結構:

  • LBA 0:保護性 MBR (防舊工具誤操作)
  • LBA 1:Primary GPT Header
  • LBA 2~33:Partition Entry Array (128 entries × 128 bytes)
  • LBA -1:Backup GPT Header
  • LBA -33~-2:Backup Partition Entry Array

核心資料結構


#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;

關鍵演算法:CRC32 校驗


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;
}

完整解析流程

  1. 開啟裝置 open("/dev/sdX", O_RDONLY)
  2. 讀取 LBA 0 驗證保護性 MBR (分區類型 0xEE)
  3. 讀取 LBA 1 解析 Primary GPT Header,驗證簽名、CRC32
  4. 根據 Header 中 partition_entry_lba 讀取分區陣列
  5. 遍歷分區項目:解析 GUID、LBA 範圍、屬性、UTF-16 名稱
  6. 驗證分區陣列 CRC32
  7. (可選)讀取備份 Header 與陣列交叉驗證

關鍵代碼片段


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;
}

UTF-16LE 名稱轉換


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

實務注意事項

  • 需 root 權限讀取區塊裝置
  • 支援 512e/4Kn 磁區大小(邏輯區塊大小可能非 512)
  • 處理大端/小端架構差異(GPT 為小端)
  • 備份表頭位於磁碟末尾,需用 lseek(fd, -LOGICAL_BLOCK_SIZE, SEEK_END)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved