Skip to content

Commit

Permalink
More partition fixer work
Browse files Browse the repository at this point in the history
Check CRC32 checksums, use for_each_gpt_entry() instead of open-coding
loops incorrectly, remove some code under if (0), and factor GPT
creation and writing into a function.
  • Loading branch information
DemiMarie committed Nov 17, 2024
1 parent 1f0e2b9 commit b2587f4
Showing 1 changed file with 57 additions and 86 deletions.
143 changes: 57 additions & 86 deletions gptfixer/gpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,19 @@ static uint64_t check_gpt_header(const struct GPTHeader *header,
}
fprintf(stdout, "Partition table is %" PRIu64 " bytes long\n",
partition_table_bytes);
struct GPTHeader h = *header;
h.HeaderCRC32 = 0;
if (header->HeaderCRC32 != crc32(0UL, (const unsigned char *)&h, sizeof(h))) {
warnx("Partition table at sector offset 0x%" PRIX64 " has bad CRC",
header->MyLBA);
return 0;
}
return partition_table_bytes;
}

static struct GPT *read_and_check_gpt(int fd, uint64_t sector_offset,
uint32_t sector_size, uint64_t sectors) {
static struct GPT *
read_and_check_gpt(int fd, uint64_t sector_offset, uint32_t sector_size,
uint64_t sectors) {
char *header_buffer = NULL, *entries_buffer = NULL;

if (sector_offset >= sectors) {
Expand Down Expand Up @@ -613,7 +621,8 @@ static struct GPT *read_and_check_gpt(int fd, uint64_t sector_offset,
printf("Partition table entries consume %" PRIu64 " bytes\n",
partition_table_bytes);

static_assert(offsetof(struct GPT, used_entries) == sizeof(struct GPTHeader), "struct def bug");
static_assert(offsetof(struct GPT, used_entries) == sizeof(struct GPTHeader),
"struct def bug");
memset((char *)header + offsetof(struct GPT, used_entries), 0,
sector_size - offsetof(struct GPT, used_entries));

Expand All @@ -639,58 +648,25 @@ static struct GPT *read_and_check_gpt(int fd, uint64_t sector_offset,
partition_table_bytes, read);
}

if (header->PartitionEntryArrayCRC32 !=
crc32(0UL, (const unsigned char *)entries_buffer,
(uint32_t)partition_table_bytes)) {
warnx("Partition table array at sector offset 0x%" PRIX64 " has bad CRC",
header->PartitionEntryLBA);
goto fail;
}
struct GPT *gpt = (struct GPT *)header;

gpt->entries = (struct GPTPartitionEntry *)entries_buffer;
uint32_t partition_entry_count = header->NumberOfPartitionEntries;
uint32_t used_entries = 0, i;
for (i = 0; i < partition_entry_count; ++i) {
const struct GPTPartitionEntry *entry = gpt->entries + i;
uint32_t used_entries = 0;
gpt->used_entries = partition_entry_count;
for_each_gpt_entry(i, size, count, gpt, entry) {
const char zero[sizeof(entry->PartitionTypeGUID)] = {0};
if (memcmp(zero, &entry->PartitionTypeGUID, sizeof(zero)) == 0) {
// Unused entry
continue;
}
if (0)
fprintf(
stdout,
"GPT Partition Table Entry:\n"
"PartitionTypeGUID: "
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%"
"02x%02x%02x%"
"02x\n"
"UniquePartitionGUID: "
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%"
"02x%02x%02x%"
"02x\n"
"StartingLBA: 0x%" PRIx64 "\n"
"EndingLBA: 0x%" PRIx64 "\n"
"Attributes: 0x%016" PRIx64 "\n",
entry->PartitionTypeGUID.guid[0], entry->PartitionTypeGUID.guid[1],
entry->PartitionTypeGUID.guid[2], entry->PartitionTypeGUID.guid[3],
entry->PartitionTypeGUID.guid[4], entry->PartitionTypeGUID.guid[5],
entry->PartitionTypeGUID.guid[6], entry->PartitionTypeGUID.guid[7],
entry->PartitionTypeGUID.guid[8], entry->PartitionTypeGUID.guid[9],
entry->PartitionTypeGUID.guid[10], entry->PartitionTypeGUID.guid[11],
entry->PartitionTypeGUID.guid[12], entry->PartitionTypeGUID.guid[13],
entry->PartitionTypeGUID.guid[14], entry->PartitionTypeGUID.guid[15],
entry->UniquePartitionGUID.guid[0],
entry->UniquePartitionGUID.guid[1],
entry->UniquePartitionGUID.guid[2],
entry->UniquePartitionGUID.guid[3],
entry->UniquePartitionGUID.guid[4],
entry->UniquePartitionGUID.guid[5],
entry->UniquePartitionGUID.guid[6],
entry->UniquePartitionGUID.guid[7],
entry->UniquePartitionGUID.guid[8],
entry->UniquePartitionGUID.guid[9],
entry->UniquePartitionGUID.guid[10],
entry->UniquePartitionGUID.guid[11],
entry->UniquePartitionGUID.guid[12],
entry->UniquePartitionGUID.guid[13],
entry->UniquePartitionGUID.guid[14],
entry->UniquePartitionGUID.guid[15], entry->StartingLBA,
entry->EndingLBA, entry->Attributes);
if (entry->StartingLBA < header->FirstUsableLBA) {
warnx("Starting LBA %" PRIu64 " less than first usable LBA %" PRIu64,
entry->StartingLBA, header->FirstUsableLBA);
Expand All @@ -701,12 +677,13 @@ static struct GPT *read_and_check_gpt(int fd, uint64_t sector_offset,
entry->EndingLBA, header->LastUsableLBA);
goto fail;
}
// Move used entries to the front of the table.
gpt->entries[used_entries++] = *entry;
used_entries = i + 1;
}
if (used_entries == 0) {
// This corresponds to a disk with no partitions at all, which
// makes no real sense.
errx(1, "No used partitions");
}
// Zero all unused entries
memset(gpt->entries + used_entries, 0,
sizeof(*gpt->entries) * (partition_entry_count - used_entries));
gpt->used_entries = used_entries;
return gpt;
fail:
Expand All @@ -715,7 +692,7 @@ static struct GPT *read_and_check_gpt(int fd, uint64_t sector_offset,
return NULL;
}

void print_gpts(struct GPT *gpt) {
static void print_gpts(struct GPT *gpt) {
struct GPTHeader *header = &gpt->header;
fprintf(stdout,
"GPT Partition Table Header:\n"
Expand Down Expand Up @@ -747,8 +724,7 @@ void print_gpts(struct GPT *gpt) {
header->DiskGUID.guid[14], header->DiskGUID.guid[15],
header->PartitionEntryLBA, header->NumberOfPartitionEntries,
header->SizeOfPartitionEntry, header->PartitionEntryArrayCRC32);
for (uint32_t i = 0; i < gpt->used_entries; ++i) {
const struct GPTPartitionEntry *entry = gpt->entries + i;
for_each_gpt_entry(i, size, count, gpt, entry) {
fprintf(
stdout,
"GPT Partition Table Entry:\n"
Expand Down Expand Up @@ -786,6 +762,29 @@ void print_gpts(struct GPT *gpt) {
}
}

static void create_new_gpt(int fd, bool used_primary, uint64_t sectors,
uint32_t sector_size, uint32_t new_sector_size,
struct GPT *gpt) {

struct GPT *new_gpt;
uint64_t to_write = 0;
if (new_sector_size < sector_size) {
new_gpt = gpt_grow_sectors(!used_primary ? sectors - 1 : 1, sector_size,
new_sector_size, sectors, gpt, &to_write);
} else {
new_gpt = gpt_shrink_sectors(!used_primary ? sectors - 1 : 1, sector_size,
new_sector_size, sectors, gpt, &to_write);
}
assert(new_gpt->entries);
if (check_gpt_header(&new_gpt->header, !used_primary ? sectors - 1 : 1,
sector_size, sectors) == 0)
abort();
assert(new_gpt->entries);
print_gpts(new_gpt);
assert(new_gpt->entries);
write_and_free_gpt(fd, new_gpt, sector_size, to_write);
}

int main(int argc, char **argv) {
if (argc != 2)
errx(1, "Usage: fixgpt BLOCK_DEVICE");
Expand Down Expand Up @@ -870,38 +869,10 @@ int main(int argc, char **argv) {
warnx("Found GPT with different sector size, altering");
// "First, do no harm": always start by overwriting the GPT we
// did *not* use, so there is always at least one good GPT!
struct GPT *new_gpt;
uint64_t to_write = 0;
if (new_sector_size < sector_size) {
new_gpt = gpt_grow_sectors(used_primary ? sectors - 1 : 1, sector_size,
new_sector_size, sectors, gpt, &to_write);
} else {
new_gpt = gpt_shrink_sectors(used_primary ? sectors - 1 : 1, sector_size,
new_sector_size, sectors, gpt, &to_write);
}
assert(new_gpt->entries);
if (check_gpt_header(&new_gpt->header, used_primary ? sectors - 1 : 1,
sector_size, sectors) == 0)
abort();
assert(new_gpt->entries);
print_gpts(new_gpt);
assert(new_gpt->entries);
write_and_free_gpt(fd, new_gpt, sector_size, to_write);
if (new_sector_size < sector_size) {
new_gpt = gpt_grow_sectors(!used_primary ? sectors - 1 : 1, sector_size,
new_sector_size, sectors, gpt, &to_write);
} else {
new_gpt = gpt_shrink_sectors(!used_primary ? sectors - 1 : 1, sector_size,
new_sector_size, sectors, gpt, &to_write);
}
assert(new_gpt->entries);
if (check_gpt_header(&new_gpt->header, !used_primary ? sectors - 1 : 1,
sector_size, sectors) == 0)
abort();
assert(new_gpt->entries);
print_gpts(new_gpt);
assert(new_gpt->entries);
write_and_free_gpt(fd, new_gpt, sector_size, to_write);
create_new_gpt(fd, used_primary, sectors, sector_size, new_sector_size,
gpt);
create_new_gpt(fd, !used_primary, sectors, sector_size, new_sector_size,
gpt);
} else {
print_gpts(gpt);
}
Expand Down

0 comments on commit b2587f4

Please sign in to comment.