Skip to content

Commit 9b5a62a

Browse files
committed
Write invalid GPT header before writing entries
Once the entries are safely on disk, overwrite the invalid header (all zeros) with a valid one. This ensures that there is never a valid header with the new sector size and incompletely written entries, even in the case of a CRC32 collision. However, it provides no guarantees about the old header. A future commit will clobber that, too, either by replacing it and the protective MBR with a correct protective MBR followed by zeroes or by replacing the backup GPT header with zeroes.
1 parent a2f5128 commit 9b5a62a

File tree

1 file changed

+32
-16
lines changed

1 file changed

+32
-16
lines changed

gptfixer/gpt.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,27 @@ static void print_gpts(struct GPT *gpt) {
734734
}
735735
}
736736

737+
static void sync_pwrite(int fd, const void *data, uint64_t length,
738+
uint64_t offset) {
739+
CHECK(fd >= 0);
740+
CHECK(data != NULL);
741+
CHECK(length <= SSIZE_MAX);
742+
CHECK((off_t)offset >= 0);
743+
CHECK((uint64_t)(off_t)offset == offset);
744+
745+
ssize_t res = pwrite64(fd, data, (size_t)length, (off_t)offset);
746+
CHECK(res >= -1);
747+
if (res == -1)
748+
err(1, "write error");
749+
CHECK((size_t)res <= length);
750+
if ((size_t)res != length)
751+
err(1,
752+
"short write: expected to write %" PRIu64 " bytes, but only wrote %zd",
753+
length, res);
754+
if (fsync(fd))
755+
err(1, "fsync() failed");
756+
}
757+
737758
static void create_new_gpt(int fd, bool used_primary, uint64_t sectors,
738759
uint32_t sector_size, uint32_t new_sector_size,
739760
struct GPT *gpt) {
@@ -753,22 +774,17 @@ static void create_new_gpt(int fd, bool used_primary, uint64_t sectors,
753774
abort();
754775
void *entries = new_gpt->entries;
755776
CHECK(entries != NULL);
756-
new_gpt->used_entries = 0;
757-
new_gpt->entries = NULL;
758-
ssize_t res = pwrite64(fd, new_gpt, sector_size,
759-
(off_t)(new_gpt->header.MyLBA * sector_size));
760-
if (res != sector_size)
761-
err(1, "short write or write error");
762-
if (fsync(fd))
763-
err(1, "fsync() failed");
764-
res = pwrite64(fd, entries, to_write,
765-
(off_t)(new_gpt->header.PartitionEntryLBA * sector_size));
766-
if (res < 0)
767-
err(1, "write error");
768-
if ((size_t)res != to_write)
769-
err(1, "short write or write error");
770-
if (fsync(fd))
771-
err(1, "fsync() failed");
777+
memset((char *)new_gpt + offsetof(struct GPT, used_entries), 0,
778+
sector_size - offsetof(struct GPT, used_entries));
779+
char *buf = aligned_alloc(sector_size, sector_size);
780+
if (buf == NULL)
781+
err(1, "aligned_alloc(%" PRIu32 ", %" PRIu32 ")", sector_size, sector_size);
782+
memset(buf, 0, sector_size);
783+
sync_pwrite(fd, buf, sector_size, new_gpt->header.MyLBA * sector_size);
784+
sync_pwrite(fd, entries, to_write,
785+
new_gpt->header.PartitionEntryLBA * sector_size);
786+
sync_pwrite(fd, new_gpt, sector_size, new_gpt->header.MyLBA * sector_size);
787+
free(buf);
772788
free(new_gpt);
773789
free(entries);
774790
}

0 commit comments

Comments
 (0)