#include "project.h" #define TABLE_SIZE (((sizeof(GPT_entry)*GPT_PARITION_ENTRIES)/SECTOR_SIZE)+2) void header_calc_crc (GPT_header * h) { h->header_crc = 0; h->header_crc = crc32 (0, h, sizeof (GPT_header)); } GPT_header header_new (GUID disk_guid, uint64_t lbas, int alt) { GPT_header ret = { 0 }; memcpy (ret.signature, GPT_HEADER_SIGNATURE, sizeof (ret.signature)); ret.revision = GPT_HEADER_REVISION_EFI10; ret.header_size = sizeof (GPT_header); ret.first_usable_lba = TABLE_SIZE; ret.last_usable_lba = lbas - TABLE_SIZE; ret.n_partition_entries = GPT_PARITION_ENTRIES; ret.partition_entry_size = sizeof (GPT_entry); ret.disk_guid = disk_guid; if (!alt) { ret.my_lba = 1; ret.alternate_lba = lbas - 1; ret.partition_entry_lba = 2; } else { ret.my_lba = lbas - 1; ret.alternate_lba = 1; ret.partition_entry_lba = lbas - TABLE_SIZE; } header_calc_crc (&ret); return ret; } uint32_t header_calc_ent_crc (DISK * d, GPT_header * h) { int i; GPT_entry e; uint32_t crc = 0; for (i = 0; i < h->n_partition_entries; ++i) { e = entry_read (d, h, i); crc = crc32 (crc, &e, h->partition_entry_size); } return crc; } int header_check_crc (DISK * d, GPT_header * h) { GPT_header c = *h; uint32_t crc; c.header_crc = 0; crc = crc32 (0, &c, sizeof (c)); if (crc != h->header_crc) return 0; crc = header_calc_ent_crc (d, h); return ! !(crc == h->partition_entry_crc); } void header_show (DISK * d, GPT_header * h) { GPT_header c = *h; uint32_t crc; int i; if (h->my_lba < h->alternate_lba) { printf (" GPT:\n"); } else { printf (" ALTERNATE GPT:\n"); } c.header_crc = 0; crc = crc32 (0, &c, sizeof (c)); printf (" Signature %s, CRC %s\n", (memcmp (h->signature, GPT_HEADER_SIGNATURE, sizeof (h->signature))) ? "INVALID" : "valid", (crc == h->header_crc) ? "matches" : "DOES NOT MATCH"); printf (" rev=0x%08x lba=%lld alternate=%lld\n", h->revision, (long long) h->my_lba, (long long) h->alternate_lba); printf (" usable lbas %lld-%lld\n", (long long) h->first_usable_lba, (long long) h->last_usable_lba); printf (" DISK GUID: %s\n", guid_to_a (h->disk_guid)); crc = header_calc_ent_crc (d, h); printf (" patitions (at lba %lld) CRC %s:\n", (long long) h->partition_entry_lba, (crc == h->partition_entry_crc) ? "matches" : "DOES NOT MATCH"); for (i = 0; i < h->n_partition_entries; ++i) { GPT_entry e = entry_read (d, h, i); if (!entry_empty (&e)) { printf (" %d:\n", i); entry_show (&e); } } } int header_validate (DISK * d, GPT_header * h) { GPT_header c = *h; uint32_t crc; c.header_crc = 0; if (memcmp (h->signature, GPT_HEADER_SIGNATURE, sizeof (h->signature))) return 0; crc = crc32 (0, &c, sizeof (c)); if (crc != h->header_crc) return 0; crc = header_calc_ent_crc (d, h); if (crc == h->partition_entry_crc) return 0; return 1; } void header_redo_ent_crc (DISK * d, GPT_header * h) { h->partition_entry_crc = header_calc_ent_crc (d, h); h->header_crc = 0; h->header_crc = crc32 (0, h, sizeof (*h)); } void header_write (DISK * d, GPT_header * h) { uint8_t buf[512]; memcpy (buf, h, sizeof (*h)); printf ("Writing header to lba %lld\n", (long long) h->my_lba); disk_write (d, buf, h->my_lba, 1); } int headers_validate (DISK * d, GPT_headers * h) { if (!header_validate (d, &h->header)) return 0; return header_validate (d, &h->alt_header); } GPT_headers headers_get (DISK * d) { GPT_headers ret; uint8_t buf[512]; uint64_t lbas; lbas = disk_lbas (d); disk_read (d, buf, 1, 1); memcpy (&ret.header, buf, sizeof (ret.header)); lbas--; if (lbas != ret.header.alternate_lba) { fprintf (stderr, "WARNING: alternate lba is not at end of disk\n"); } disk_read (d, buf, ret.header.alternate_lba, 1); memcpy (&ret.alt_header, buf, sizeof (ret.alt_header)); return ret; } GPT_headers headers_get_one (DISK * d) { GPT_headers ret; uint8_t buf[512]; uint64_t lbas; int table_size; lbas = disk_lbas (d); disk_read (d, buf, 1, 1); memcpy (&ret.header, buf, sizeof (ret.header)); table_size = ret.header.first_usable_lba; ret.header.last_usable_lba = lbas - table_size; ret.alt_header = ret.header; ret.header.alternate_lba = lbas - 1; ret.alt_header.alternate_lba = 1; ret.alt_header.my_lba = lbas - 1; ret.alt_header.partition_entry_lba = (lbas - table_size) + 1; return ret; }