diff options
author | srs5694 <srs5694@users.sourceforge.net> | 2010-03-07 22:16:07 -0500 |
---|---|---|
committer | srs5694 <srs5694@users.sourceforge.net> | 2010-03-07 22:16:07 -0500 |
commit | 55d926192adc984462509b2966e23bc0d1129bbd (patch) | |
tree | bff8bea805e3fb0e15f7f3a0cd26a20fa12c5f29 /gpttext.cc | |
parent | ea17cffd083c839b7af3560d55ba697667277901 (diff) | |
download | sgdisk-55d926192adc984462509b2966e23bc0d1129bbd.tar.gz |
Updated project files for 0.6.5 release version.
Diffstat (limited to 'gpttext.cc')
-rw-r--r-- | gpttext.cc | 326 |
1 files changed, 200 insertions, 126 deletions
@@ -22,11 +22,14 @@ #include <string.h> #include <errno.h> +#include <stdint.h> #include <iostream> #include <sstream> #include <cstdio> #include "attributes.h" #include "gpttext.h" +#include "partnotes.h" +#include "support.h" using namespace std; @@ -130,6 +133,7 @@ int GPTDataTextUI::XFormDisklabel(void) { return numDone; } // GPTData::XFormDisklabel(int i) + /********************************************************************* * * * Begin functions that obtain information from the users, and often * @@ -186,41 +190,41 @@ void GPTDataTextUI::CreatePartition(void) { } // while if (((firstBlock = FindFirstAvailable()) != 0) && - (firstFreePart < mainHeader.numParts)) { + (firstFreePart < mainHeader.numParts)) { lastBlock = FindLastAvailable(); - firstInLargest = FindFirstInLargest(); - - // Get partition number.... - do { - prompt1 << "Partition number (" << firstFreePart + 1 << "-" << mainHeader.numParts - << ", default " << firstFreePart + 1 << "): "; - partNum = GetNumber(firstFreePart + 1, mainHeader.numParts, - firstFreePart + 1, prompt1.str()) - 1; - if (partitions[partNum].GetFirstLBA() != 0) - cout << "partition " << partNum + 1 << " is in use.\n"; - } while (partitions[partNum].GetFirstLBA() != 0); - - // Get first block for new partition... - prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = " - << firstInLargest << ") or {+-}size{KMGT}: "; - do { - sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt2.str()); - } while (IsFree(sector) == 0); - Align(§or); // Align sector to correct multiple - firstBlock = sector; - - // Get last block for new partitions... - lastBlock = FindLastInFree(firstBlock); - prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = " - << lastBlock << ") or {+-}size{KMGT}: "; - do { - sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt3.str()); - } while (IsFree(sector) == 0); - lastBlock = sector; - - firstFreePart = GPTData::CreatePartition(partNum, firstBlock, lastBlock); - partitions[partNum].ChangeType(); - partitions[partNum].SetDefaultDescription(); + firstInLargest = FindFirstInLargest(); + + // Get partition number.... + do { + prompt1 << "Partition number (" << firstFreePart + 1 << "-" << mainHeader.numParts + << ", default " << firstFreePart + 1 << "): "; + partNum = GetNumber(firstFreePart + 1, mainHeader.numParts, + firstFreePart + 1, prompt1.str()) - 1; + if (partitions[partNum].GetFirstLBA() != 0) + cout << "partition " << partNum + 1 << " is in use.\n"; + } while (partitions[partNum].GetFirstLBA() != 0); + + // Get first block for new partition... + prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = " + << firstInLargest << ") or {+-}size{KMGT}: "; + do { + sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt2.str()); + } while (IsFree(sector) == 0); + Align(§or); // Align sector to correct multiple + firstBlock = sector; + + // Get last block for new partitions... + lastBlock = FindLastInFree(firstBlock); + prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = " + << lastBlock << ") or {+-}size{KMGT}: "; + do { + sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt3.str()); + } while (IsFree(sector) == 0); + lastBlock = sector; + + firstFreePart = GPTData::CreatePartition(partNum, firstBlock, lastBlock); + partitions[partNum].ChangeType(); + partitions[partNum].SetDefaultDescription(); } else { cout << "No free sectors available\n"; } // if/else @@ -246,7 +250,7 @@ void GPTDataTextUI::DeletePartition(void) { void GPTDataTextUI::ChangePartType(void) { int partNum; uint32_t low, high; - + if (GetPartRange(&low, &high) > 0) { partNum = GetPartNum(); partitions[partNum].ChangeType(); @@ -259,7 +263,7 @@ void GPTDataTextUI::ChangePartType(void) { // adjust them for completeness.... void GPTDataTextUI::SetAttributes(uint32_t partNum) { Attributes theAttr; - + theAttr.SetAttributes(partitions[partNum].GetAttributes()); theAttr.DisplayAttributes(); theAttr.ChangeAttributes(); @@ -282,7 +286,7 @@ int GPTDataTextUI::SwapPartitions(void) { if (high >= mainHeader.numParts - 1) high = 0; prompt << "New partition number (1-" << mainHeader.numParts - << ", default " << high + 2 << "): "; + << ", default " << high + 2 << "): "; partNum2 = GetNumber(1, mainHeader.numParts, high + 2, prompt.str()) - 1; didIt = GPTData::SwapPartitions(partNum1, partNum2); } else { @@ -325,7 +329,7 @@ int GPTDataTextUI::DestroyGPTwPrompt(void) { void GPTDataTextUI::ShowDetails(void) { int partNum; uint32_t low, high; - + if (GetPartRange(&low, &high) > 0) { partNum = GetPartNum(); ShowPartDetails(partNum); @@ -340,9 +344,10 @@ void GPTDataTextUI::MakeHybrid(void) { uint32_t partNums[3]; char line[255]; char* junk; - int numParts, i, j, mbrNum, bootable = -1; - int gptParts[4], mbrTypes[4]; - char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe) + int numParts, i, j, mbrNum, bootable = 0; + unsigned int hexCode = 0; + struct PartInfo *newNote; + PartNotes notes; char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table cout << "\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n" @@ -361,120 +366,189 @@ void GPTDataTextUI::MakeHybrid(void) { eeFirst = GetYN(); } // if - for (i = 0; i < 4; i++) - gptParts[i] = MBR_EMPTY; - for (i = 0; i < numParts; i++) { - j = partNums[i] - 1; + newNote = new struct PartInfo; + j = newNote->gptPartNum = partNums[i] - 1; mbrNum = i + (eeFirst == 'Y'); cout << "\nCreating entry for GPT partition #" << j + 1 << " (MBR partition #" << mbrNum + 1 << ")\n"; - gptParts[mbrNum] = j; - mbrTypes[mbrNum] = GetMBRTypeCode(partitions[j].GetHexType() / 256); + newNote->hexCode = GetMBRTypeCode(partitions[j].GetHexType() / 256); + newNote->firstLBA = partitions[j].GetFirstLBA(); + newNote->lastLBA = partitions[j].GetLastLBA(); + newNote->type = PRIMARY; cout << "Set the bootable flag? "; if (GetYN() == 'Y') - bootable = mbrNum; + newNote->active = 1; + else + newNote->active = 0; + notes.AddToEnd(newNote); } // for if (numParts > 0) { // User opted to create a hybrid MBR.... // Create EFI protective partition that covers the start of the disk. // If this location (covering the main GPT data structures) is omitted, // Linux won't find any partitions on the disk. - if (eeFirst == 'Y') - mbrNum = 0; - else - mbrNum = numParts; - gptParts[mbrNum] = MBR_EFI_GPT; - mbrTypes[mbrNum] = 0xEE; + newNote = new struct PartInfo; + newNote->gptPartNum = MBR_EFI_GPT; + newNote->active = 0; + newNote->hexCode = 0xEE; + newNote->type = PRIMARY; + // newNote firstLBA and lastLBA are computed later... + if (eeFirst == 'Y') { + notes.AddToStart(newNote); + } else { + notes.AddToEnd(newNote); + } // else protectiveMBR.SetHybrid(); // ... and for good measure, if there are any partition spaces left, // optionally create another protective EFI partition to cover as much // space as possible.... - for (i = 0; i < 4; i++) { - if (gptParts[i] == MBR_EMPTY) { // unused entry.... - if (fillItUp == 'M') { - cout << "\nUnused partition space(s) found. Use one to protect more partitions? "; - fillItUp = GetYN(); - mbrTypes[i] = 0x00; // use this to flag a need to get type code - } // if - if (fillItUp == 'Y') { - while ((mbrTypes[i] <= 0) || (mbrTypes[i] > 255)) { - cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): "; - // Comment on above: Mac OS treats disks with more than one - // 0xEE MBR partition as MBR disks, not as GPT disks. - junk = fgets(line, 255, stdin); - sscanf(line, "%x", &mbrTypes[i]); - if (line[0] == '\n') - mbrTypes[i] = 0; - } // while - gptParts[i] = MBR_EFI_GPT; - } // if (fillItUp == 'Y') - } // if unused entry - } // for (i = 0; i < 4; i++) - PartsToMBR(gptParts, mbrTypes); + if (notes.GetNumPrimary() < 4) { // unused entry.... + cout << "\nUnused partition space(s) found. Use one to protect more partitions? "; + if (GetYN() == 'Y') { + while ((hexCode <= 0) || (hexCode > 255)) { + cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): "; + // Comment on above: Mac OS treats disks with more than one + // 0xEE MBR partition as MBR disks, not as GPT disks. + junk = fgets(line, 255, stdin); + sscanf(line, "%x", &hexCode); + if (line[0] == '\n') + hexCode = 0x00; + } // while + newNote = new struct PartInfo; + newNote->gptPartNum = MBR_EFI_GPT; + newNote->active = 0; + newNote->hexCode = hexCode; + newNote->type = PRIMARY; + // newNote firstLBA and lastLBA are computed later... + notes.AddToEnd(newNote); + } // if (GetYN() == 'Y') + } // if unused entry + PartsToMBR(notes); if (bootable > 0) protectiveMBR.SetPartBootable(bootable); } // if (numParts > 0) } // GPTDataTextUI::MakeHybrid() -// Convert the GPT to MBR form. This function is necessarily limited; it -// handles at most four partitions and creates layouts that ignore CHS -// geometries. Returns the number of converted partitions; if this value +// Assign GPT partitions to primary or logical status for conversion. The +// function first presents a suggested layout with as many logicals as +// possible, but gives the user the option to override this suggestion. +// Returns the number of partitions assigned (0 if problems or if the +// user aborts) +int GPTDataTextUI::AssignPrimaryOrLogical(PartNotes & notes) { + int i, partNum, allOK = 1, changesWanted = 1, countedParts, numPrimary = 0, numLogical = 0; + int newNumParts; // size of GPT table + + // Sort and resize the GPT table. Resized to clear the sector before the + // first available sector, if possible, so as to enable turning the + // first partition into a logical, should that be desirable/necessary. + SortGPT(); + countedParts = newNumParts = CountParts(); + i = blockSize / GPT_SIZE; + if ((newNumParts % i) != 0) { + newNumParts = ((newNumParts / i) + 1) * i; + } // if + SetGPTSize(newNumParts); + + // Takes notes on existing partitions: Create an initial assignment as + // primary or logical, set default MBR types, and then make it legal + // (drop partitions as required to fit in the MBR and as logicals). + allOK = (notes.PassPartitions(partitions, this, mainHeader.numParts, blockSize) == + (int) mainHeader.numParts); + for (i = 0; i < countedParts; i++) + notes.SetMbrHexType(i, partitions[i].GetHexType() / 255); + notes.MakeItLegal(); + + while (allOK && changesWanted) { + notes.ShowSummary(); + cout << "\n"; + partNum = GetNumber(-1, countedParts, -2, + "Type partition to change, 0 to accept, -1 to abort: "); + switch (partNum) { + case -1: + allOK = 0; + break; + case 0: + changesWanted = 0; + break; + default: + allOK = notes.MakeChange(partNum - 1); + break; + } // switch + } // while + + i = 0; + if (allOK) + for (i = 0; i < countedParts; i++) { + switch (notes.GetType(i)) { + case PRIMARY: + numPrimary++; + break; + case LOGICAL: + numLogical++; + break; + } // switch + if (notes.GetActiveStatus(i)) + protectiveMBR.SetPartBootable(i); + } // for + + if (numPrimary > 4) { + cerr << "Warning! More than four primary partitions in " + << "GPTDataTextUI::AssignPrimaryOrLogical()!\n"; + allOK = 0; + } // if + return (allOK * (numPrimary + numLogical)); +} // GPTDataTextUI::AssignPrimaryOrLogical() + +// Convert the GPT to MBR form, storing partitions in the protectiveMBR +// variable. This function is necessarily limited; it may not be able to +// convert all partitions, depending on the disk size and available space +// before each partition (one free sector is required to create a logical +// partition, which are necessary to convert more than four partitions). +// Returns the number of converted partitions; if this value // is over 0, the calling function should call DestroyGPT() to destroy -// the GPT data, and then exit. +// the GPT data, call SaveMBR() to save the MBR, and then exit. int GPTDataTextUI::XFormToMBR(void) { - char line[255]; - char* junk; - int j, numParts, bootable = -1, numConverted = 0, numReallyConverted; - int gptParts[4], mbrTypes[4]; - uint32_t i, partNums[4]; + int numParts, numToConvert, numReallyConverted = 0; + int origNumParts; + PartNotes notes; + GPTPart *tempGptParts; + uint32_t i; + + // Back up partition array, since we'll be sorting it and we want to + // be able to restore it in case the user aborts.... + origNumParts = mainHeader.numParts; + tempGptParts = new GPTPart[mainHeader.numParts]; + for (i = 0; i < mainHeader.numParts; i++) + tempGptParts[i] = partitions[i]; - // Get the numbers of up to four partitions to add to the - // hybrid MBR.... numParts = CountParts(); - cout << "Counted " << numParts << " partitions.\n"; - - if (numParts > 4) { // Over four partitions; engage in triage - cout << "Type from one to four GPT partition numbers, separated by spaces, to be\n" - << "used in the MBR, in sequence: "; - junk = fgets(line, 255, stdin); - numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1], - &partNums[2], &partNums[3]); - } else { // Four or fewer partitions; convert them all - i = j = 0; - while ((j < numParts) && (i < mainHeader.numParts)) { - if (partitions[i].GetFirstLBA() > 0) { // if GPT part. is defined - partNums[j++] = ++i; // flag it for conversion - } else i++; - } // while - } // if/else - for (i = 0; i < 4; i++) - gptParts[i] = MBR_EMPTY; + numToConvert = AssignPrimaryOrLogical(notes); + + if (numToConvert > 0) { + numReallyConverted = PartsToMBR(notes); + if (numReallyConverted != numToConvert) { + cerr << "Error converting partitions to MBR; tried to convert " + << numToConvert << " partitions,\nbut converted " << numReallyConverted + << ". Aborting operation!\n"; + numReallyConverted = 0; + protectiveMBR.MakeProtectiveMBR(); + } // if/else + } // if - for (i = 0; i < (uint32_t) numParts; i++) { - j = partNums[i] - 1; - cout << "\nCreating entry for GPT partition #" << j + 1 - << " (MBR partition #" << i + 1 << ")\n"; - gptParts[i] = j; - mbrTypes[i] = GetMBRTypeCode(partitions[j].GetHexType() / 256); - cout << "Set the bootable flag? "; - if (GetYN() == 'Y') - bootable = i; - numConverted++; - } // for - numReallyConverted = PartsToMBR(gptParts, mbrTypes); - if (bootable > 0) - protectiveMBR.SetPartBootable(bootable); - if (numReallyConverted == numConverted) { - protectiveMBR.WriteMBRData(&myDisk); + // A problem or the user aborted; restore backup of unsorted and + // original-sized partition table and delete the sorted and + // resized one; otherwise free the backup table's memory.... + if (numReallyConverted == 0) { + delete[] partitions; + partitions = tempGptParts; + SetGPTSize(origNumParts); } else { - cerr << "Error converting partitions to MBR; aborting operation!\n"; - numConverted = 0; - protectiveMBR.MakeProtectiveMBR(); - } // if/else - return numConverted; + delete[] tempGptParts; + } // if + return numReallyConverted; } // GPTDataTextUI::XFormToMBR() /********************************************************************* |