Updated project files for 0.6.5 release version.
diff --git a/gpt.cc b/gpt.cc
index e213205..ac42995 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -25,6 +25,7 @@
#include "parttypes.h"
#include "attributes.h"
#include "diskio.h"
+#include "partnotes.h"
using namespace std;
@@ -209,6 +210,9 @@
// Check for overlapping partitions....
problems += FindOverlaps();
+ // Check for insane partitions (start after end, hugely big, etc.)
+ problems += FindInsanePartitions();
+
// Check for mismatched MBR and GPT partitions...
problems += FindHybridMismatches();
@@ -278,7 +282,7 @@
} // Problem at start of disk
if (mainHeader.lastUsableLBA < lastUsedBlock) {
overlap = lastUsedBlock - mainHeader.lastUsableLBA;
- cout << "Warning! Secondary partition table overlaps the last partition by "
+ cout << "\nWarning! Secondary partition table overlaps the last partition by\n"
<< overlap << " blocks!\n";
if (lastUsedBlock > (diskSize - 2)) {
cout << "You will need to delete this partition or resize it in another utility.\n";
@@ -517,6 +521,28 @@
return problems;
} // GPTData::FindOverlaps()
+// Find partitions that are insane -- they start after they end or are too
+// big for the disk. (The latter should duplicate detection of overlaps
+// with GPT backup data structures, but better to err on the side of
+// redundant tests than to miss something....)
+int GPTData::FindInsanePartitions(void) {
+ uint32_t i;
+ int problems = 0;
+
+ for (i = 0; i < mainHeader.numParts; i++) {
+ if (partitions[i].GetFirstLBA() > partitions[i].GetLastLBA()) {
+ problems++;
+ cout << "\nProblem: partition " << i << " ends before it begins.\n";
+ } // if
+ if (partitions[i].GetLastLBA() >= diskSize) {
+ problems++;
+ cout << "\nProblem: partition " << i << " is too big for the disk.\n";
+ } // if
+ } // for
+ return problems;
+} // GPTData::FindInsanePartitions(void)
+
+
/******************************************************************
* *
* Begin functions that load data from disk or save data to disk. *
@@ -560,25 +586,24 @@
int GPTData::LoadPartitions(const string & deviceFilename) {
BSDData bsdDisklabel;
int err, allOK = 1;
- uint32_t i;
- uint64_t firstBlock, lastBlock;
MBRValidity mbrState;
- // First, do a test to see if writing will be possible later....
- err = myDisk.OpenForWrite(deviceFilename);
- if ((err == 0) && (!justLooking)) {
- cout << "\aNOTE: Write test failed with error number " << errno
- << ". It will be impossible to save\nchanges to this disk's partition table!\n";
-#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
- cout << "You may be able to enable writes by exiting this program, typing\n"
- << "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n"
- << "program.\n";
-#endif
- cout << "\n";
- } // if
- myDisk.Close();
-
if (myDisk.OpenForRead(deviceFilename)) {
+ err = myDisk.OpenForWrite(deviceFilename);
+ if ((err == 0) && (!justLooking)) {
+ cout << "\aNOTE: Write test failed with error number " << errno
+ << ". It will be impossible to save\nchanges to this disk's partition table!\n";
+#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+ cout << "You may be able to enable writes by exiting this program, typing\n"
+ << "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n"
+ << "program.\n";
+#endif
+ cout << "\n";
+ } // if
+ myDisk.Close(); // Close and re-open read-only in case of bugs
+ } else allOK = 0; // if
+
+ if (allOK && myDisk.OpenForRead(deviceFilename)) {
// store disk information....
diskSize = myDisk.DiskSize(&err);
blockSize = (uint32_t) myDisk.GetBlockSize();
@@ -613,26 +638,11 @@
break;
} // switch
- // Now find the first and last sectors used by partitions...
- if (allOK) {
- firstBlock = mainHeader.backupLBA; // start high
- lastBlock = 0; // start low
- for (i = 0; i < mainHeader.numParts; i++) {
- if ((partitions[i].GetFirstLBA() < firstBlock) &&
- (partitions[i].GetFirstLBA() > 0))
- firstBlock = partitions[i].GetFirstLBA();
- if (partitions[i].GetLastLBA() > lastBlock)
- lastBlock = partitions[i].GetLastLBA();
- } // for
+ if (allOK)
CheckGPTSize();
- } // if
+ myDisk.Close();
} else {
allOK = 0;
- cerr << "Problem opening " << deviceFilename << " for reading! Error is "
- << errno << "\n";
- if (errno == EACCES) { // User is probably not running as root
- cerr << "You must run this program as root or use sudo!\n";
- } // if
} // if/else
return (allOK);
} // GPTData::LoadPartitions()
@@ -768,11 +778,12 @@
// Reverse byte order, if necessary
if (IsLittleEndian() == 0) {
- ReverseHeaderBytes(header);
+ ReverseHeaderBytes(&tempHeader);
} // if
- if (allOK && mainHeader.numParts != tempHeader.numParts)
+ if (allOK && (mainHeader.numParts != tempHeader.numParts) && *crcOk) {
allOK = SetGPTSize(tempHeader.numParts);
+ }
*header = tempHeader;
return allOK;
@@ -793,8 +804,9 @@
} else {
retval = disk.Seek(sector);
} // if/else
+ if (retval == 1)
+ retval = SetGPTSize(header.numParts);
if (retval == 1) {
- SetGPTSize(header.numParts);
sizeOfParts = header.numParts * header.sizeOfPartitionEntries;
if (disk.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n";
@@ -848,7 +860,6 @@
int GPTData::SaveGPTData(int quiet) {
int allOK = 1, littleEndian;
char answer;
- uint32_t numParts;
littleEndian = IsLittleEndian();
@@ -890,8 +901,8 @@
} // if correction requested
} // if
- // Check for overlapping partitions....
- if (FindOverlaps() > 0) {
+ // Check for overlapping or insane partitions....
+ if ((FindOverlaps() > 0) || (FindInsanePartitions() > 0)) {
allOK = 0;
cerr << "Aborting write operation!\n";
} // if
@@ -900,10 +911,6 @@
// (function displays warning message)
FindHybridMismatches();
- // Pull out some data that's needed before doing byte-order reversal on
- // big-endian systems....
- numParts = mainHeader.numParts;
-
RecomputeCRCs();
if ((allOK) && (!quiet)) {
@@ -1127,7 +1134,7 @@
} // GPTData::LoadGPTBackup()
int GPTData::SaveMBR(void) {
- return protectiveMBR.WriteMBRData();
+ return protectiveMBR.WriteMBRData(&myDisk);
} // GPTData::SaveMBR()
// This function destroys the on-disk GPT structures, but NOT the on-disk
@@ -1413,7 +1420,7 @@
partitions[partNum].BlankPartition();
} // if
return numDone;
-} // GPTData::XFormDisklable(int i)
+} // GPTData::XFormDisklabel(uint32_t i)
// Transform the partitions on an already-loaded BSD disklabel...
int GPTData::XFormDisklabel(BSDData* disklabel) {
@@ -1477,44 +1484,45 @@
return allOK;
} // GPTData::OnePartToMBR()
-// Convert up to four partitions to MBR form and return the number done.
-// Partitions are specified in an array of GPT partition numbers,
-// with an associated array of partition type codes. Both must be
-// at least four elements in size (longer is OK, but will be ignored).
-// A partition number of MBR_EFI_GPT means to place an EFI GPT
-// protective partition in that location in the table (the associated
-// mbrType[] should be 0xEE), and MBR_EMPTY means not to create a
-// partition in that table position. If the mbrType[] entry for a
-// partition is 0, a default entry is used, based on the GPT
-// partition type code.
+// Convert partitions to MBR form (primary and logical) and return
+// the number done. Partitions are specified in a PartNotes variable,
+// which includes pointers to GPT partition numbers. A partition number
+// of MBR_EFI_GPT means to place an EFI GPT protective partition in that
+// location in the table, and MBR_EMPTY means not to create a partition
+// in that table position. If the partition type entry for a partition
+// is 0, a default entry is used, based on the GPT partition type code.
// Returns the number of partitions converted, NOT counting EFI GPT
-// protective partitions.
-int GPTData::PartsToMBR(const int *gptParts, const int *mbrTypes) {
- int i, numConverted = 0;
+// protective partitions or extended partitions.
+int GPTData::PartsToMBR(PartNotes & notes) {
+ int mbrNum = 0, numConverted = 0;
+ struct PartInfo convInfo;
- if ((gptParts != NULL) && (mbrTypes != NULL)) {
- protectiveMBR.EmptyMBR();
- protectiveMBR.SetDiskSize(diskSize);
- // Do two passes, one to get "real" partitions and
- // the next to create EFI GPT protective partition(s)
- for (i = 0; i < 4; i++) {
- if (gptParts[i] >= 0) {
- numConverted += OnePartToMBR((uint32_t) gptParts[i], i);
- if (mbrTypes[i] != 0)
- protectiveMBR.SetPartType(i, mbrTypes[i]);
- } // if
- } // for (regular partition pass)
- for (i = 0; i < 4; i++) {
- if (gptParts[i] == MBR_EFI_GPT) {
- if (protectiveMBR.FindFirstAvailable() == UINT32_C(1)) {
- protectiveMBR.MakePart(i, 1, protectiveMBR.FindLastInFree(1), mbrTypes[i]);
- protectiveMBR.SetHybrid();
- } else {
- protectiveMBR.MakeBiggestPart(i, mbrTypes[i]);
- } // if/else
- } // if EFI GPT partition specified
- } // for (0xEE pass)
- } // if arrays were passed
+ protectiveMBR.EmptyMBR();
+ protectiveMBR.SetDiskSize(diskSize);
+ notes.Rewind();
+ while (notes.GetNextInfo(&convInfo) >= 0) {
+ if ((convInfo.gptPartNum >= 0) && (convInfo.type == PRIMARY)) {
+ numConverted += OnePartToMBR((uint32_t) convInfo.gptPartNum, mbrNum);
+ if (convInfo.hexCode != 0)
+ protectiveMBR.SetPartType(mbrNum, convInfo.hexCode);
+ if (convInfo.active)
+ protectiveMBR.SetPartBootable(mbrNum);
+ mbrNum++;
+ } // if
+ if (convInfo.gptPartNum == MBR_EFI_GPT) {
+ if (protectiveMBR.FindFirstAvailable() == UINT32_C(1)) {
+ protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), convInfo.hexCode);
+ protectiveMBR.SetHybrid();
+ } else {
+ protectiveMBR.MakeBiggestPart(mbrNum, convInfo.hexCode);
+ } // if/else
+ mbrNum++;
+ } // if EFI GPT partition specified
+ } // for
+ // Now do logical partition(s)...
+ protectiveMBR.SetDisk(&myDisk);
+ numConverted += protectiveMBR.CreateLogicals(notes);
+// numConverted += PartsToLogical(notes);
return numConverted;
} // GPTData::PartsToMBR()
@@ -1545,12 +1553,12 @@
} // if
// Do the work only if the # of partitions is changing. Along with being
- // efficient, this prevents mucking the with location of the secondary
+ // efficient, this prevents mucking with the location of the secondary
// partition table, which causes problems when loading data from a RAID
// array that's been expanded because this function is called when loading
// data.
- if ((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts)
- || (partitions == NULL)) {
+ if (((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts)
+ || (partitions == NULL)) && (numEntries > 0)) {
newParts = new GPTPart [numEntries * sizeof (GPTPart)];
if (newParts != NULL) {
if (partitions != NULL) { // existing partitions; copy them over
@@ -1973,10 +1981,10 @@
firstMoved = 0;
for (i = 0; i < mainHeader.numParts; i++) {
if ((first >= partitions[i].GetFirstLBA()) &&
- (first <= partitions[i].GetLastLBA())) { // in existing part.
+ (first <= partitions[i].GetLastLBA())) { // in existing part.
first = partitions[i].GetLastLBA() + 1;
firstMoved = 1;
- } // if
+ } // if
} // for
} while (firstMoved == 1);
if (first > mainHeader.lastUsableLBA)
@@ -2023,10 +2031,10 @@
lastMoved = 0;
for (i = 0; i < mainHeader.numParts; i++) {
if ((last >= partitions[i].GetFirstLBA()) &&
- (last <= partitions[i].GetLastLBA())) { // in existing part.
+ (last <= partitions[i].GetLastLBA())) { // in existing part.
last = partitions[i].GetFirstLBA() - 1;
lastMoved = 1;
- } // if
+ } // if
} // for
} while (lastMoved == 1);
if (last < mainHeader.firstUsableLBA)
@@ -2042,9 +2050,9 @@
nearestStart = mainHeader.lastUsableLBA;
for (i = 0; i < mainHeader.numParts; i++) {
if ((nearestStart > partitions[i].GetFirstLBA()) &&
- (partitions[i].GetFirstLBA() > start)) {
+ (partitions[i].GetFirstLBA() > start)) {
nearestStart = partitions[i].GetFirstLBA() - 1;
- } // if
+ } // if
} // for
return (nearestStart);
} // GPTData::FindLastInFree()
@@ -2077,8 +2085,11 @@
return totalFound;
} // GPTData::FindFreeBlocks()
-// Returns 1 if sector is unallocated, 0 if it's allocated to a partition
-int GPTData::IsFree(uint64_t sector) {
+// Returns 1 if sector is unallocated, 0 if it's allocated to a partition.
+// If it's allocated, return the partition number to which it's allocated
+// in partNum, if that variable is non-NULL. (A value of UINT32_MAX is
+// returned in partNum if the sector is in use by basic GPT data structures.)
+int GPTData::IsFree(uint64_t sector, uint32_t *partNum) {
int isFree = 1;
uint32_t i;
@@ -2086,11 +2097,15 @@
if ((sector >= partitions[i].GetFirstLBA()) &&
(sector <= partitions[i].GetLastLBA())) {
isFree = 0;
+ if (partNum != NULL)
+ *partNum = i;
} // if
} // for
if ((sector < mainHeader.firstUsableLBA) ||
(sector > mainHeader.lastUsableLBA)) {
isFree = 0;
+ if (partNum != NULL)
+ *partNum = UINT32_MAX;
} // if
return (isFree);
} // GPTData::IsFree()