Initial commit of support for moving main partition table to arbitrary

location on disk (within limits based on existing partitions).
This commit is contained in:
Rod Smith
2017-07-21 21:48:13 -04:00
parent e7452642ac
commit 503e9ada12
10 changed files with 123 additions and 10 deletions

56
gpt.cc
View File

@@ -276,6 +276,23 @@ int GPTData::Verify(void) {
<< "The 'e' option on the experts' menu may fix this problem.\n";
} // if
// Check the main and backup partition tables for overlap with things
if (mainHeader.partitionEntriesLBA + GetTableSizeInSectors() > mainHeader.firstUsableLBA) {
problems++;
cout << "\nProblem: Main partition table extends past the first usable LBA.\n"
<< "Using 'j' on the experts' menu may enable fixing this problem.\n";
} // if
if (mainHeader.partitionEntriesLBA < 2) {
problems++;
cout << "\nProblem: Main partition table appears impossibly early on the disk.\n"
<< "Using 'j' on the experts' menu may enable fixing this problem.\n";
} // if
if (secondHeader.partitionEntriesLBA + GetTableSizeInSectors() > secondHeader.currentLBA) {
problems++;
cout << "\nProblem: The backup partition table overlaps the backup header.\n"
<< "Using 'e' on the experts' menu may fix this problem.\n";
} // if
if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) {
problems++;
cout << "\nProblem: GPT claims the disk is larger than it is! (Claimed last usable\n"
@@ -552,8 +569,8 @@ void GPTData::RebuildMainHeader(void) {
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
mainHeader.diskGUID = secondHeader.diskGUID;
mainHeader.partitionEntriesLBA = UINT64_C(2);
mainHeader.numParts = secondHeader.numParts;
mainHeader.partitionEntriesLBA = secondHeader.firstUsableLBA - GetTableSizeInSectors();
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC;
memcpy(mainHeader.reserved2, secondHeader.reserved2, sizeof(mainHeader.reserved2));
@@ -658,7 +675,7 @@ int GPTData::FindInsanePartitions(void) {
} // if
if (partitions[i].GetLastLBA() >= diskSize) {
problems++;
cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n";
cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n";
} // if
} // if
} // for
@@ -1441,6 +1458,8 @@ void GPTData::DisplayGPTData(void) {
cout << "Logical sector size: " << blockSize << " bytes\n";
cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n";
cout << "Partition table holds up to " << numParts << " entries\n";
cout << "Main partition table begins at sector " << mainHeader.partitionEntriesLBA
<< " and ends at sector " << mainHeader.partitionEntriesLBA + GetTableSizeInSectors() - 1 << "\n";
cout << "First usable sector is " << mainHeader.firstUsableLBA
<< ", last usable sector is " << mainHeader.lastUsableLBA << "\n";
totalFree = FindFreeBlocks(&i, &temp);
@@ -1732,7 +1751,7 @@ int GPTData::SetGPTSize(uint32_t numEntries, int fillGPTSectors) {
partitions = newParts;
} // if/else existing partitions
numParts = numEntries;
mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + (((numEntries * GPT_SIZE) % blockSize) != 0) + 2 ;
mainHeader.firstUsableLBA = GetTableSizeInSectors() + mainHeader.partitionEntriesLBA;
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
MoveSecondHeaderToEnd();
if (diskSize > 0)
@@ -1747,6 +1766,23 @@ int GPTData::SetGPTSize(uint32_t numEntries, int fillGPTSectors) {
return (allOK);
} // GPTData::SetGPTSize()
// Change the start sector for the main partition table.
// Returns 1 on success, 0 on failure
int GPTData::MoveMainTable(uint64_t pteSector) {
uint64_t pteSize = GetTableSizeInSectors();
int retval = 1;
if ((pteSector >= 2) && ((pteSector + pteSize) <= FindFirstUsedLBA())) {
mainHeader.partitionEntriesLBA = pteSector;
mainHeader.firstUsableLBA = pteSector + pteSize;
RebuildSecondHeader();
} else {
cerr << "Unable to set the main partition table's location to " << pteSector << "!\n";
retval = 0;
} // if/else
return retval;
} // GPTData::MoveMainTable()
// Blank the partition array
void GPTData::BlankPartitions(void) {
uint32_t i;
@@ -2121,6 +2157,20 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
return (first);
} // GPTData::FindFirstAvailable()
// Returns the LBA of the start of the first partition on the disk (by
// sector number), or 0 if there are no partitions defined.
uint64_t GPTData::FindFirstUsedLBA(void) {
uint32_t i;
uint64_t firstFound = UINT64_MAX;
for (i = 0; i < numParts; i++) {
if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() < firstFound)) {
firstFound = partitions[i].GetFirstLBA();
} // if
} // for
return firstFound;
} // GPTData::FindFirstUsedLBA()
// Finds the first available sector in the largest block of unallocated
// space on the disk. Returns 0 if there are no available blocks left
uint64_t GPTData::FindFirstInLargest(void) {