GPT fdisk 0.5.0
Added several features, including a restructuring of the menu system,
GPT-to-MBR conversion, and the ability to re-read the MBR to generate
a fresh GPT from the current on-disk MBR.
diff --git a/mbr.cc b/mbr.cc
index 4e789e1..2be731b 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -1,7 +1,7 @@
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
data. */
-/* By Rod Smith, January to February, 2009 */
+/* Initial coding by Rod Smith, January to February, 2009 */
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
@@ -35,6 +35,8 @@
strcpy(device, "");
state = invalid;
srand((unsigned int) time(NULL));
+ numHeads = MAX_HEADS;
+ numSecspTrack = MAX_SECSPERTRACK;
EmptyMBR();
} // MBRData default constructor
@@ -43,6 +45,8 @@
diskSize = 0;
strcpy(device, filename);
state = invalid;
+ numHeads = MAX_HEADS;
+ numSecspTrack = MAX_SECSPERTRACK;
srand((unsigned int) time(NULL));
// Try to read the specified partition table, but if it fails....
@@ -55,51 +59,11 @@
MBRData::~MBRData(void) {
} // MBRData destructor
-// Empty all data. Meant mainly for calling by constructors, but it's also
-// used by the hybrid MBR functions in the GPTData class.
-void MBRData::EmptyMBR(int clearBootloader) {
- int i;
-
- // Zero out the boot loader section, the disk signature, and the
- // 2-byte nulls area only if requested to do so. (This is the
- // default.)
- if (clearBootloader == 1) {
- for (i = 0; i < 440; i++)
- code[i] = 0;
- diskSignature = (uint32_t) rand();
- nulls = 0;
- } // if
-
- // Blank out the partitions
- for (i = 0; i < 4; i++) {
- partitions[i].status = UINT8_C(0);
- partitions[i].firstSector[0] = UINT8_C(0);
- partitions[i].firstSector[1] = UINT8_C(0);
- partitions[i].firstSector[2] = UINT8_C(0);
- partitions[i].partitionType = UINT8_C(0);
- partitions[i].lastSector[0] = UINT8_C(0);
- partitions[i].lastSector[1] = UINT8_C(0);
- partitions[i].lastSector[2] = UINT8_C(0);
- partitions[i].firstLBA = UINT32_C(0);
- partitions[i].lengthLBA = UINT32_C(0);
- } // for
- MBRSignature = MBR_SIGNATURE;
-
- blockSize = SECTOR_SIZE;
- diskSize = 0;
- for (i = 0; i < NUM_LOGICALS; i++) {
- logicals[i].status = UINT8_C(0);
- logicals[i].firstSector[0] = UINT8_C(0);
- logicals[i].firstSector[1] = UINT8_C(0);
- logicals[i].firstSector[2] = UINT8_C(0);
- logicals[i].partitionType = UINT8_C(0);
- logicals[i].lastSector[0] = UINT8_C(0);
- logicals[i].lastSector[1] = UINT8_C(0);
- logicals[i].lastSector[2] = UINT8_C(0);
- logicals[i].firstLBA = UINT32_C(0);
- logicals[i].lengthLBA = UINT32_C(0);
- } // for
-} // MBRData::EmptyMBR()
+/**********************
+ * *
+ * Disk I/O functions *
+ * *
+ **********************/
// Read data from MBR. Returns 1 if read was successful (even if the
// data isn't a valid MBR), 0 if the read failed.
@@ -120,25 +84,18 @@
return allOK;
} // MBRData::ReadMBRData(char* deviceFilename)
-// Read data from MBR.
+// Read data from MBR. If checkBlockSize == 1 (the default), the block
+// size is checked; otherwise it's set to the default (512 bytes).
+// Note that any extended partition(s) present will be explicitly stored
+// in the partitions[] array, along with their contained partitions; the
+// extended container partition(s) should be ignored by other functions.
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
- int allOK = 1, i, j, maxLogicals = 0;
+ int allOK = 1, i, j, logicalNum;
int err;
TempMBR tempMBR;
- // Clear logical partition array
- for (i = 0; i < NUM_LOGICALS; i++) {
- logicals[i].status = UINT8_C(0);
- logicals[i].firstSector[0] = UINT8_C(0);
- logicals[i].firstSector[1] = UINT8_C(0);
- logicals[i].firstSector[2] = UINT8_C(0);
- logicals[i].partitionType = UINT8_C(0);
- logicals[i].lastSector[0] = UINT8_C(0);
- logicals[i].lastSector[1] = UINT8_C(0);
- logicals[i].lastSector[2] = UINT8_C(0);
- logicals[i].firstLBA = UINT32_C(0);
- logicals[i].lengthLBA = UINT32_C(0);
- } // for
+ // Empty existing MBR data, including the logical partitions...
+ EmptyMBR(0);
err = lseek64(fd, 0, SEEK_SET);
err = read(fd, &tempMBR, 512);
@@ -154,8 +111,8 @@
for (j = 0; j < 3; j++) {
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
- } // for j...
- } // for i...
+ } // for j... (reading parts of CHS geometry)
+ } // for i... (reading all four partitions)
MBRSignature = tempMBR.MBRSignature;
// Reverse the byte order, if necessary
@@ -180,21 +137,16 @@
// Find block size
if (checkBlockSize) {
blockSize = GetBlockSize(fd);
-// if ((blockSize = GetBlockSize(fd)) == -1) {
-// blockSize = SECTOR_SIZE;
-// printf("Unable to determine sector size; assuming %lu bytes!\n",
-// (unsigned long) SECTOR_SIZE);
-// } // if
} // if (checkBlockSize)
// Load logical partition data, if any is found....
if (allOK) {
for (i = 0; i < 4; i++) {
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
- || (partitions[i].partitionType == 0x85)) {
+ || (partitions[i].partitionType == 0x85)) {
// Found it, so call a recursive algorithm to load everything from them....
- maxLogicals = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), maxLogicals);
- if ((maxLogicals < 0) || (maxLogicals > NUM_LOGICALS)) {
+ logicalNum = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), 4);
+ if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
allOK = 0;
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
} // if maxLogicals valid
@@ -224,26 +176,70 @@
(partitions[i].partitionType != UINT8_C(0x00)))
state = hybrid;
} // for
- } // if hybrid
-
-/* // Tell the user what the MBR state is...
- switch (state) {
- case invalid:
- printf("Information: MBR appears to be empty or invalid.\n");
- break;
- case gpt:
- printf("Information: MBR holds GPT placeholder partitions.\n");
- break;
- case hybrid:
- printf("Information: MBR holds hybrid GPT/MBR data.\n");
- break;
- case mbr:
- printf("Information: MBR data appears to be valid.\n");
- break;
- } // switch */
+ } // if (hybrid detection code)
} // MBRData::ReadMBRData(int fd)
-// Write the MBR data to the default defined device.
+// This is a recursive function to read all the logical partitions, following the
+// logical partition linked list from the disk and storing the basic data in the
+// partitions[] array. Returns last index to partitions[] used, or -1 if there was
+// a problem.
+// Parameters:
+// fd = file descriptor
+// extendedStart = LBA of the start of the extended partition
+// diskOffset = LBA offset WITHIN the extended partition of the one to be read
+// partNum = location in partitions[] array to store retrieved data
+int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
+ uint32_t diskOffset, int partNum) {
+ struct TempMBR ebr;
+ off_t offset;
+
+ // Check for a valid partition number. Note that partitions MAY be read into
+ // the area normally used by primary partitions, although the only calling
+ // function as of GPT fdisk version 0.5.0 doesn't do so.
+ if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
+ offset = (off_t) (extendedStart + diskOffset) * blockSize;
+ if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
+ fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
+ partNum = -1;
+ }
+ if (read(fd, &ebr, 512) != 512) { // Load the data....
+ fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
+ (unsigned long) offset);
+ partNum = -1;
+ } else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
+ ReverseBytes(&ebr.MBRSignature, 2);
+ ReverseBytes(&ebr.partitions[0].firstLBA, 4);
+ ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
+ ReverseBytes(&ebr.partitions[1].firstLBA, 4);
+ ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
+ } // if/else/if
+
+ if (ebr.MBRSignature != MBR_SIGNATURE) {
+ partNum = -1;
+ fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
+ (unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
+ } // if
+
+ // Copy over the basic data....
+ partitions[partNum].status = ebr.partitions[0].status;
+ partitions[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
+ partitions[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
+ partitions[partNum].partitionType = ebr.partitions[0].partitionType;
+
+ // Find the next partition (if there is one) and recurse....
+ if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
+ (partNum < (MAX_MBR_PARTS - 1))) {
+ partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
+ partNum + 1);
+ } else {
+ partNum++;
+ } // if another partition
+ } // Not enough space for all the logicals (or previous error encountered)
+ return (partNum);
+} // MBRData::ReadLogicalPart()
+
+// Write the MBR data to the default defined device. Note that this writes
+// ONLY the MBR itself, not the logical partition data.
int MBRData::WriteMBRData(void) {
int allOK = 1, fd;
@@ -295,12 +291,6 @@
lseek64(fd, 0, SEEK_SET);
write(fd, &tempMBR, 512);
-/* write(fd, code, 440);
- write(fd, &diskSignature, 4);
- write(fd, &nulls, 2);
- write(fd, partitions, 64);
- write(fd, &MBRSignature, 2); */
-
// Reverse the byte order back, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes(&diskSignature, 4);
@@ -313,56 +303,11 @@
}// if
} // MBRData::WriteMBRData(int fd)
-// This is a recursive function to read all the logical partitions, following the
-// logical partition linked list from the disk and storing the basic data in the
-// logicals[] array. Returns last index to logicals[] uses, or -1 if there was a
-// problem
-int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
- uint32_t diskOffset, int partNum) {
- struct EBRRecord ebr;
- off_t offset;
-
- if ((partNum < NUM_LOGICALS) && (partNum >= 0)) {
- offset = (off_t) (extendedStart + diskOffset) * blockSize;
- if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
- fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
- partNum = -1;
- }
- if (read(fd, &ebr, 512) != 512) { // Load the data....
- fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
- (unsigned long) offset);
- partNum = -1;
- } else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
- ReverseBytes(&ebr.MBRSignature, 2);
- ReverseBytes(&ebr.partitions[0].firstLBA, 4);
- ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
- ReverseBytes(&ebr.partitions[1].firstLBA, 4);
- ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
- } // if/else/if
-
- if (ebr.MBRSignature != MBR_SIGNATURE) {
- partNum = -1;
- fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
- (unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
- } // if
-
- // Copy over the basic data....
- logicals[partNum].status = ebr.partitions[0].status;
- logicals[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
- logicals[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
- logicals[partNum].partitionType = ebr.partitions[0].partitionType;
-
- // Find the next partition (if there is one) and recurse....
- if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 0) &&
- (partNum < (NUM_LOGICALS - 1))) {
- partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
- partNum + 1);
- } else {
- partNum++;
- } // if another partition
- } // Not enough space for all the logicals (or previous error encountered)
- return (partNum);
-} // MBRData::ReadLogicalPart()
+/********************************************
+ * *
+ * Functions that display data for the user *
+ * *
+ ********************************************/
// Show the MBR data to the user....
void MBRData::DisplayMBRData(void) {
@@ -373,10 +318,10 @@
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
printf("MBR partitions:\n");
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\n");
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
if (partitions[i].lengthLBA != 0) {
if (partitions[i].status && 0x80) // it's bootable
- bootCode = '*';
+ bootCode = '*';
else
bootCode = ' ';
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
@@ -384,31 +329,144 @@
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
} // if
} // for
-
- // Now display logical partition data....
- for (i = 0; i < NUM_LOGICALS; i++) {
- if (logicals[i].lengthLBA != 0) {
- printf("%4d\t%13lu\t%15lu \t0x%02X\n", i + 5, (unsigned long) logicals[i].firstLBA,
- (unsigned long) logicals[i].lengthLBA, logicals[i].partitionType);
- } // if
- } // for
- printf("\nDisk size is %lu sectors (%s)\n", (unsigned long) diskSize,
+ printf("\nDisk size is %llu sectors (%s)\n", (unsigned long long) diskSize,
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
} // MBRData::DisplayMBRData()
+// Displays the state, as a word, on stdout. Used for debugging & to
+// tell the user about the MBR state when the program launches....
+void MBRData::ShowState(void) {
+ switch (state) {
+ case invalid:
+ printf(" MBR: not present\n");
+ break;
+ case gpt:
+ printf(" MBR: protective\n");
+ break;
+ case hybrid:
+ printf(" MBR: hybrid\n");
+ break;
+ case mbr:
+ printf(" MBR: MBR only\n");
+ break;
+ default:
+ printf("\a MBR: unknown -- bug!\n");
+ break;
+ } // switch
+} // MBRData::ShowState()
+
+/*********************************************************************
+ * *
+ * Functions that set or get disk metadata (CHS geometry, disk size, *
+ * etc.) *
+ * *
+ *********************************************************************/
+
+// Sets the CHS geometry. CHS geometry is used by LBAtoCHS() function.
+// Note that this only sets the heads and sectors; the number of
+// cylinders is determined by these values and the disk size.
+void MBRData::SetCHSGeom(uint32_t h, uint32_t s) {
+ if ((h <= MAX_HEADS) && (s <= MAX_SECSPERTRACK)) {
+ numHeads = h;
+ numSecspTrack = s;
+ } else {
+ printf("Warning! Attempt to set invalid CHS geometry!\n");
+ } // if/else
+} // MBRData::SetCHSGeom()
+
+// Converts 64-bit LBA value to MBR-style CHS value. Returns 1 if conversion
+// was within the range that can be expressed by CHS (including 0, for an
+// empty partition), 0 if the value is outside that range, and -1 if chs is
+// invalid.
+int MBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
+ uint64_t cylinder, head, sector; // all numbered from 0
+ uint64_t remainder;
+ int retval = 1;
+ int done = 0;
+
+ if (chs != NULL) {
+ // Special case: In case of 0 LBA value, zero out CHS values....
+ if (lba == 0) {
+ chs[0] = chs[1] = chs[2] = UINT8_C(0);
+ done = 1;
+ } // if
+ // If LBA value is too large for CHS, max out CHS values....
+ if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
+ chs[0] = 254;
+ chs[1] = chs[2] = 255;
+ done = 1;
+ retval = 0;
+ } // if
+ // If neither of the above applies, compute CHS values....
+ if (!done) {
+ cylinder = lba / (uint64_t) (numHeads * numSecspTrack);
+ remainder = lba - (cylinder * numHeads * numSecspTrack);
+ head = remainder / numSecspTrack;
+ remainder -= head * numSecspTrack;
+ sector = remainder;
+ if (head < numHeads)
+ chs[0] = head;
+ else
+ retval = 0;
+ if (sector < numSecspTrack) {
+ chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
+ chs[2] = (uint8_t) (cylinder & UINT64_C(0xFF));
+ } else {
+ retval = 0;
+ } // if/else
+ } // if value is expressible and non-0
+ } else { // Invalid (NULL) chs pointer
+ retval = -1;
+ } // if CHS pointer valid
+ return (retval);
+} // MBRData::LBAtoCHS()
+
+/*****************************************************
+ * *
+ * Functions to create, delete, or change partitions *
+ * *
+ *****************************************************/
+
+// Empty all data. Meant mainly for calling by constructors, but it's also
+// used by the hybrid MBR functions in the GPTData class.
+void MBRData::EmptyMBR(int clearBootloader) {
+ int i;
+
+ // Zero out the boot loader section, the disk signature, and the
+ // 2-byte nulls area only if requested to do so. (This is the
+ // default.)
+ if (clearBootloader == 1) {
+ for (i = 0; i < 440; i++)
+ code[i] = 0;
+ diskSignature = (uint32_t) rand();
+ nulls = 0;
+ } // if
+
+ // Blank out the partitions
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ partitions[i].status = UINT8_C(0);
+ partitions[i].firstSector[0] = UINT8_C(0);
+ partitions[i].firstSector[1] = UINT8_C(0);
+ partitions[i].firstSector[2] = UINT8_C(0);
+ partitions[i].partitionType = UINT8_C(0);
+ partitions[i].lastSector[0] = UINT8_C(0);
+ partitions[i].lastSector[1] = UINT8_C(0);
+ partitions[i].lastSector[2] = UINT8_C(0);
+ partitions[i].firstLBA = UINT32_C(0);
+ partitions[i].lengthLBA = UINT32_C(0);
+ } // for
+ MBRSignature = MBR_SIGNATURE;
+} // MBRData::EmptyMBR()
+
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
void MBRData::MakeProtectiveMBR(int clearBoot) {
- int i;
+
+ EmptyMBR(clearBoot);
// Initialize variables
nulls = 0;
MBRSignature = MBR_SIGNATURE;
- if (clearBoot > 0) {
- for (i = 0; i < 440; i++)
- code[i] = (uint8_t) 0;
- } // if
-
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
// Write CHS data. This maxes out the use of the disk, as much as
@@ -427,44 +485,43 @@
partitions[0].partitionType = UINT8_C(0xEE);
partitions[0].firstLBA = UINT32_C(1);
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
- partitions[0].lengthLBA = diskSize - 1;
+ partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
} else { // disk is too big to represent, so fake it...
partitions[0].lengthLBA = UINT32_MAX;
} // if/else
- // Zero out three unused primary partitions...
- for (i = 1; i < 4; i++) {
- partitions[i].status = UINT8_C(0);
- partitions[i].firstSector[0] = UINT8_C(0);
- partitions[i].firstSector[1] = UINT8_C(0);
- partitions[i].firstSector[2] = UINT8_C(0);
- partitions[i].partitionType = UINT8_C(0);
- partitions[i].lastSector[0] = UINT8_C(0);
- partitions[i].lastSector[1] = UINT8_C(0);
- partitions[i].lastSector[2] = UINT8_C(0);
- partitions[i].firstLBA = UINT32_C(0);
- partitions[i].lengthLBA = UINT32_C(0);
- } // for
-
- // Zero out all the logical partitions. Not necessary for data
- // integrity on write, but eliminates stray entries if user wants
- // to view the MBR after converting the disk
- for (i = 0; i < NUM_LOGICALS; i++) {
- logicals[i].status = UINT8_C(0);
- logicals[i].firstSector[0] = UINT8_C(0);
- logicals[i].firstSector[1] = UINT8_C(0);
- logicals[i].firstSector[2] = UINT8_C(0);
- logicals[i].partitionType = UINT8_C(0);
- logicals[i].lastSector[0] = UINT8_C(0);
- logicals[i].lastSector[1] = UINT8_C(0);
- logicals[i].lastSector[2] = UINT8_C(0);
- logicals[i].firstLBA = UINT32_C(0);
- logicals[i].lengthLBA = UINT32_C(0);
- } // for
-
state = gpt;
} // MBRData::MakeProtectiveMBR()
+// Create a partition of the specified number, starting LBA, and
+// length. This function does *NO* error checking, so it's possible
+// to seriously screw up a partition table using this function!
+// Note: This function should NOT be used to create the 0xEE partition
+// in a conventional GPT configuration, since that partition has
+// specific size requirements that this function won't handle. It may
+// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
+// since those toss the rulebook away anyhow....
+void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
+ int bootable) {
+ if ((num >= 0) && (num < MAX_MBR_PARTS)) {
+ partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
+ partitions[num].firstSector[0] = UINT8_C(0);
+ partitions[num].firstSector[1] = UINT8_C(0);
+ partitions[num].firstSector[2] = UINT8_C(0);
+ partitions[num].partitionType = (uint8_t) type;
+ partitions[num].lastSector[0] = UINT8_C(0);
+ partitions[num].lastSector[1] = UINT8_C(0);
+ partitions[num].lastSector[2] = UINT8_C(0);
+ partitions[num].firstLBA = start;
+ partitions[num].lengthLBA = length;
+ // If this is a "real" partition, set its CHS geometry
+ if (length > 0) {
+ LBAtoCHS((uint64_t) start, partitions[num].firstSector);
+ LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
+ } // if (length > 0)
+ } // if valid partition number
+} // MBRData::MakePart()
+
// Create a partition that fills the most available space. Returns
// 1 if partition was created, 0 otherwise. Intended for use in
// creating hybrid MBRs.
@@ -482,11 +539,11 @@
if (firstBlock != UINT32_C(0)) { // something's free...
lastBlock = FindLastInFree(firstBlock);
segmentSize = lastBlock - firstBlock + UINT32_C(1);
- if (segmentSize > selectedSize) {
+ if (segmentSize > selectedSize) {
selectedSize = segmentSize;
- selectedSegment = firstBlock;
- } // if
- start = lastBlock + 1;
+ selectedSegment = firstBlock;
+ } // if
+ start = lastBlock + 1;
} // if
} while (firstBlock != 0);
if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
@@ -517,18 +574,19 @@
// Used to help keep GPT & hybrid MBR partitions in sync....
int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
uint32_t start32, length32;
- int i, j, deleted = 0;
+ int i, deleted = 0;
- if ((state == hybrid) && (start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
+ if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
start32 = (uint32_t) start64;
length32 = (uint32_t) length64;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
- (partitions[i].partitionType != 0xEE)) {
+ (partitions[i].partitionType != 0xEE)) {
DeletePartition(i);
- OptimizeEESize();
+ if (state == hybrid)
+ OptimizeEESize();
deleted = 1;
- } // if (match found)
+ } // if (match found)
} // for i (partition scan)
} // if (hybrid & GPT partition < 2TiB)
return deleted;
@@ -554,74 +612,24 @@
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
} // if free space after
} // if partition is 0xEE
- if (typeFlag == 0) { // No non-hybrid partitions found
- MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
- } // if
} // for partition loop
+ if (typeFlag == 0) { // No non-hybrid partitions found
+ MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
+ } // if
} // MBRData::OptimizeEESize()
-// Return a pointer to a primary or logical partition, or NULL if
-// the partition is out of range....
-struct MBRRecord* MBRData::GetPartition(int i) {
- MBRRecord* thePart = NULL;
-
- if ((i >= 0) && (i < 4)) { // primary partition
- thePart = &partitions[i];
- } // if
- if ((i >= 4) && (i < (NUM_LOGICALS + 4))) {
- thePart = &logicals[i - 4];
- } // if
- return thePart;
-} // GetPartition()
-
-// Displays the state, as a word, on stdout. Used for debugging & to
-// tell the user about the MBR state when the program launches....
-void MBRData::ShowState(void) {
- switch (state) {
- case invalid:
- printf(" MBR: not present\n");
- break;
- case gpt:
- printf(" MBR: protective\n");
- break;
- case hybrid:
- printf(" MBR: hybrid\n");
- break;
- case mbr:
- printf(" MBR: MBR only\n");
- break;
- default:
- printf("\a MBR: unknown -- bug!\n");
- break;
- } // switch
-} // MBRData::ShowState()
-
-// Create a primary partition of the specified number, starting LBA,
-// and length. This function does *NO* error checking, so it's possible
-// to seriously screw up a partition table using this function! It's
-// intended as a way to create a hybrid MBR, which is a pretty funky
-// setup to begin with....
-void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
- int bootable) {
-
- partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
- partitions[num].firstSector[0] = UINT8_C(0);
- partitions[num].firstSector[1] = UINT8_C(0);
- partitions[num].firstSector[2] = UINT8_C(0);
- partitions[num].partitionType = (uint8_t) type;
- partitions[num].lastSector[0] = UINT8_C(0);
- partitions[num].lastSector[1] = UINT8_C(0);
- partitions[num].lastSector[2] = UINT8_C(0);
- partitions[num].firstLBA = start;
- partitions[num].lengthLBA = length;
-} // MakePart()
+/****************************************
+ * *
+ * Functions to find data on free space *
+ * *
+ ****************************************/
// Finds the first free space on the disk from start onward; returns 0
// if none available....
uint32_t MBRData::FindFirstAvailable(uint32_t start) {
uint32_t first;
uint32_t i;
- int firstMoved = 0;
+ int firstMoved;
first = start;
@@ -638,7 +646,7 @@
(first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
first = partitions[i].firstLBA + partitions[i].lengthLBA;
firstMoved = 1;
- } // if
+ } // if
} // for
} while (firstMoved == 1);
if (first >= diskSize)
@@ -651,7 +659,7 @@
uint32_t nearestStart;
uint32_t i;
- if (diskSize <= UINT32_MAX)
+ if ((diskSize <= UINT32_MAX) && (diskSize > 0))
nearestStart = diskSize - 1;
else
nearestStart = UINT32_MAX - 1;
@@ -688,6 +696,8 @@
for (i = 0; i < 4; i++) {
first = partitions[i].firstLBA;
+ // Note: Weird two-line thing to avoid subtracting 1 from a 0 value
+ // for an unsigned int....
last = first + partitions[i].lengthLBA;
if (last > 0) last--;
if ((first <= sector) && (last >= sector))
@@ -696,6 +706,12 @@
return isFree;
} // MBRData::IsFree()
+/******************************************************
+ * *
+ * Functions that extract data on specific partitions *
+ * *
+ ******************************************************/
+
uint8_t MBRData::GetStatus(int i) {
MBRRecord* thePart;
uint8_t retval;
@@ -729,7 +745,7 @@
retval = thePart->firstLBA;
} else
retval = UINT32_C(0);
- return retval;
+ return retval;
} // MBRData::GetFirstSector()
uint32_t MBRData::GetLength(int i) {
@@ -741,7 +757,7 @@
retval = thePart->lengthLBA;
} else
retval = UINT32_C(0);
- return retval;
+ return retval;
} // MBRData::GetLength()
// Return the MBR data as a GPT partition....
@@ -772,7 +788,23 @@
newPart.SetUniqueGUID(1);
newPart.SetAttributes(0);
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
- } // if
- } // if
+ } // if not extended, protective, or non-existent
+ } // if (origPart != NULL)
return newPart;
} // MBRData::AsGPT()
+
+/***********************
+ * *
+ * Protected functions *
+ * *
+ ***********************/
+
+// Return a pointer to a primary or logical partition, or NULL if
+// the partition is out of range....
+struct MBRRecord* MBRData::GetPartition(int i) {
+ MBRRecord* thePart = NULL;
+
+ if ((i >= 0) && (i < MAX_MBR_PARTS))
+ thePart = &partitions[i];
+ return thePart;
+} // GetPartition()