Version 0.6.3 release. Big-endian bug fix, new GUID generation method,
architectural changes.
diff --git a/gpt.cc b/gpt.cc
index 9bb6763..562a085 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -173,12 +173,11 @@
<< secondHeader.lastUsableLBA << ")\n"
<< "The 'e' option on the experts' menu can probably fix this problem.\n";
} // if
- if ((mainHeader.diskGUID.data1 != secondHeader.diskGUID.data1) ||
- (mainHeader.diskGUID.data2 != secondHeader.diskGUID.data2)) {
+ if ((mainHeader.diskGUID != secondHeader.diskGUID)) {
problems++;
- cout << "\nProblem: main header's disk GUID (" << GUIDToStr(mainHeader.diskGUID)
+ cout << "\nProblem: main header's disk GUID (" << mainHeader.diskGUID.AsString()
<< ") doesn't\nmatch the backup GPT header's disk GUID ("
- << GUIDToStr(secondHeader.diskGUID) << ")\n"
+ << secondHeader.diskGUID.AsString() << ")\n"
<< "You should use the 'b' or 'd' option on the recovery & transformation menu to\n"
<< "select one or the other header.\n";
} // if
@@ -368,8 +367,9 @@
return (oldCRC == newCRC);
} // GPTData::CheckHeaderCRC()
-// Recompute all the CRCs. Must be called before saving (but after reversing
-// byte order on big-endian systems) if any changes have been made.
+// Recompute all the CRCs. Must be called before saving if any changes have
+// been made. Must be called on platform-ordered data (this function reverses
+// byte order and then undoes that reversal.)
void GPTData::RecomputeCRCs(void) {
uint32_t crc, hSize, trueNumParts;
int littleEndian = 1;
@@ -377,13 +377,21 @@
// Initialize CRC functions...
chksum_crc32gentab();
+ // Save some key data from header before reversing byte order....
+ trueNumParts = mainHeader.numParts;
hSize = mainHeader.headerSize;
- littleEndian = IsLittleEndian();
+
+ if ((littleEndian = IsLittleEndian()) == 0) {
+ ReversePartitionBytes();
+ ReverseHeaderBytes(&mainHeader);
+ ReverseHeaderBytes(&secondHeader);
+ } // if
+/* if ((littleEndian = IsLittleEndian()) == 0) {
+ ReverseBytes(&trueNumParts, 4);
+ ReverseBytes(&hSize, 4);
+ } // if */
// Compute CRC of partition tables & store in main and secondary headers
- trueNumParts = mainHeader.numParts;
- if (littleEndian == 0)
- ReverseBytes(&trueNumParts, 4); // unreverse this key piece of data....
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
mainHeader.partitionEntriesCRC = crc;
secondHeader.partitionEntriesCRC = crc;
@@ -405,6 +413,12 @@
if (littleEndian == 0)
ReverseBytes(&crc, 4);
secondHeader.headerCRC = crc;
+
+ if ((littleEndian = IsLittleEndian()) == 0) {
+ ReverseHeaderBytes(&mainHeader);
+ ReverseHeaderBytes(&secondHeader);
+ ReversePartitionBytes();
+ } // if
} // GPTData::RecomputeCRCs()
// Rebuild the main GPT header, using the secondary header as a model.
@@ -421,8 +435,7 @@
mainHeader.backupLBA = secondHeader.currentLBA;
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
- mainHeader.diskGUID.data1 = secondHeader.diskGUID.data1;
- mainHeader.diskGUID.data2 = secondHeader.diskGUID.data2;
+ mainHeader.diskGUID = secondHeader.diskGUID;
mainHeader.partitionEntriesLBA = UINT64_C(2);
mainHeader.numParts = secondHeader.numParts;
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
@@ -445,8 +458,7 @@
secondHeader.backupLBA = mainHeader.currentLBA;
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
secondHeader.lastUsableLBA = mainHeader.lastUsableLBA;
- secondHeader.diskGUID.data1 = mainHeader.diskGUID.data1;
- secondHeader.diskGUID.data2 = mainHeader.diskGUID.data2;
+ secondHeader.diskGUID = mainHeader.diskGUID;
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
secondHeader.numParts = mainHeader.numParts;
secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries;
@@ -836,12 +848,14 @@
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
// write, 0 if there was a problem.
int GPTData::SaveGPTData(int quiet) {
- int allOK = 1;
+ int allOK = 1, littleEndian;
char answer;
uint64_t secondTable;
uint32_t numParts;
uint64_t offset;
+ littleEndian = IsLittleEndian();
+
if (device == "") {
cerr << "Device not defined.\n";
} // if
@@ -894,14 +908,17 @@
// big-endian systems....
numParts = mainHeader.numParts;
secondTable = secondHeader.partitionEntriesLBA;
- if (IsLittleEndian() == 0) {
+/* if (IsLittleEndian() == 0) {
// Reverse partition bytes first, since that function requires non-reversed
// data from the main header....
ReversePartitionBytes();
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
- } // if
+ } // if */
RecomputeCRCs();
+/* ReverseHeaderBytes(&mainHeader);
+ ReverseHeaderBytes(&secondHeader);
+ ReversePartitionBytes(); */
if ((allOK) && (!quiet)) {
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
@@ -922,16 +939,24 @@
if (allOK && myDisk.OpenForWrite(device)) {
// Now write the main GPT header...
if (myDisk.Seek(1) == 1) {
+ if (!littleEndian)
+ ReverseHeaderBytes(&mainHeader);
if (myDisk.Write(&mainHeader, 512) != 512)
allOK = 0;
+ if (!littleEndian)
+ ReverseHeaderBytes(&mainHeader);
} else allOK = 0; // if (myDisk.Seek()...)
// Now write the main partition tables...
if (allOK) {
offset = mainHeader.partitionEntriesLBA;
if (myDisk.Seek(offset)) {
+ if (!littleEndian)
+ ReversePartitionBytes();
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0;
+ if (!littleEndian)
+ ReversePartitionBytes();
} else allOK = 0; // if (myDisk.Seek()...)
} // if (allOK)
@@ -947,18 +972,26 @@
// Now write the secondary partition tables....
if (allOK) {
+ if (!littleEndian)
+ ReversePartitionBytes();
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0;
- } // if (allOK)
+ if (!littleEndian)
+ ReversePartitionBytes();
+ } // if (allOK)
// Now write the secondary GPT header...
if (allOK) {
offset = mainHeader.backupLBA;
- if (myDisk.Seek(offset)) {
+ if (!littleEndian)
+ ReverseHeaderBytes(&secondHeader);
+ if (myDisk.Seek(offset)) {
if (myDisk.Write(&secondHeader, 512) == -1)
allOK = 0;
} else allOK = 0; // if (myDisk.Seek()...)
- } // if (allOK)
+ if (!littleEndian)
+ ReverseHeaderBytes(&secondHeader);
+ } // if (allOK)
// re-read the partition table
if (allOK) {
@@ -982,13 +1015,13 @@
cout << "Aborting write of new partition table.\n";
} // if
- if (IsLittleEndian() == 0) {
+/* if (IsLittleEndian() == 0) {
// Reverse (normalize) header bytes first, since ReversePartitionBytes()
// requires non-reversed data in mainHeader...
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes();
- } // if
+ } // if */
return (allOK);
} // GPTData::SaveGPTData()
@@ -1005,6 +1038,12 @@
DiskIO backupFile;
if (backupFile.OpenForWrite(filename)) {
+ // Recomputing the CRCs is likely to alter them, which could be bad
+ // if the intent is to save a potentially bad GPT for later analysis;
+ // but if we don't do this, we get bogus errors when we load the
+ // backup. I'm favoring misses over false alarms....
+ RecomputeCRCs();
+
// Reverse the byte order, if necessary....
numParts = mainHeader.numParts;
if (IsLittleEndian() == 0) {
@@ -1013,12 +1052,6 @@
ReverseHeaderBytes(&secondHeader);
} // if
- // Recomputing the CRCs is likely to alter them, which could be bad
- // if the intent is to save a potentially bad GPT for later analysis;
- // but if we don't do this, we get bogus errors when we load the
- // backup. I'm favoring misses over false alarms....
- RecomputeCRCs();
-
// Now write the protective MBR...
protectiveMBR.WriteMBRData(&backupFile);
@@ -1191,7 +1224,7 @@
cout << "Disk " << device << ": " << diskSize << " sectors, "
<< BytesToSI(diskSize * blockSize) << "\n";
cout << "Logical sector size: " << blockSize << " bytes\n";
- cout << "Disk identifier (GUID): " << GUIDToStr(mainHeader.diskGUID) << "\n";
+ cout << "Disk identifier (GUID): " << mainHeader.diskGUID.AsString() << "\n";
cout << "Partition table holds up to " << mainHeader.numParts << " entries\n";
cout << "First usable sector is " << mainHeader.firstUsableLBA
<< ", last usable sector is " << mainHeader.lastUsableLBA << "\n";
@@ -1320,7 +1353,7 @@
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
partitions[partNum].ChangeType();
- partitions[partNum].SetName(partitions[partNum].GetNameType());
+ partitions[partNum].SetDefaultDescription();
} else {
cout << "No free sectors available\n";
} // if/else
@@ -1551,7 +1584,6 @@
int GPTData::XFormPartitions(void) {
int i, numToConvert;
uint8_t origType;
- struct newGUID;
// Clear out old data & prepare basics....
ClearGPTData();
@@ -1567,7 +1599,7 @@
// don't waste CPU time trying to convert extended, hybrid protective, or
// null (non-existent) partitions
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
- (origType != 0x00) && (origType != 0xEE))
+ (origType != 0x00) && (origType != 0xEE))
partitions[i] = protectiveMBR.AsGPT(i);
} // for
@@ -1583,6 +1615,7 @@
// Transforms BSD disklabel on the specified partition (numbered from 0).
// If an invalid partition number is given, the program prompts for one.
+// (Default for i is -1; called without an option, it therefore prompts.)
// Returns the number of new partitions created.
int GPTData::XFormDisklabel(int i) {
uint32_t low, high, partNum, startPart;
@@ -1635,7 +1668,7 @@
int i, numDone = 0;
if ((disklabel->IsDisklabel()) && (startPart >= 0) &&
- (startPart < mainHeader.numParts)) {
+ (startPart < mainHeader.numParts)) {
for (i = 0; i < disklabel->GetNumParts(); i++) {
partitions[i + startPart] = disklabel->AsGPT(i);
if (partitions[i + startPart].GetFirstLBA() != UINT64_C(0))
@@ -1682,7 +1715,7 @@
do {
cout << "Enter an MBR hex code (default " << hex;
cout.width(2);
- cout << typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256 << "): ";
+ cout << partitions[gptPart].GetHexType() / 0x0100 << "): ";
junk = fgets(line, 255, stdin);
if (line[0] == '\n')
typeCode = partitions[gptPart].GetHexType() / 256;
@@ -1948,7 +1981,7 @@
partitions[partNum].SetFirstLBA(startSector);
partitions[partNum].SetLastLBA(endSector);
partitions[partNum].SetType(0x0700);
- partitions[partNum].SetUniqueGUID(1);
+ partitions[partNum].RandomizeUniqueGUID();
} else retval = 0; // if free space until endSector
} else retval = 0; // if startSector is free
} else retval = 0; // if legal partition number
@@ -2021,9 +2054,7 @@
mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
// Set a unique GUID for the disk, based on random numbers
- // rand() is only 32 bits, so multiply together to fill a 64-bit value
- mainHeader.diskGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
- mainHeader.diskGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
+ mainHeader.diskGUID.Randomize();
// Copy main header to backup header
RebuildSecondHeader();
@@ -2392,8 +2423,7 @@
ReverseBytes(&header->sizeOfPartitionEntries, 4);
ReverseBytes(&header->partitionEntriesCRC, 4);
ReverseBytes(&header->reserved2, GPT_RESERVED);
- ReverseBytes(&header->diskGUID.data1, 8);
- ReverseBytes(&header->diskGUID.data2, 8);
+// header->diskGUID.ReverseGUIDBytes();
} // GPTData::ReverseHeaderBytes()
// IMPORTANT NOTE: This function requires non-reversed mainHeader
@@ -2458,6 +2488,14 @@
cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n";
allOK = 0;
} // if
+ if (sizeof(GUIDData) != 16) {
+ cerr << "GUIDData is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n";
+ allOK = 0;
+ } // if
+ if (sizeof(PartType) != 16) {
+ cerr << "PartType is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n";
+ allOK = 0;
+ } // if
// Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
if (IsLittleEndian() == 0) {
cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"