1fad064250bf6c49eb4966bf0f617591a0821808esrs/* 2e3ee733ff8690af7568dac665bc20ecf869dea1dRoderick W. Smith Copyright (C) 2010-2013 <Roderick W. Smith> 3fad064250bf6c49eb4966bf0f617591a0821808esrs 4fad064250bf6c49eb4966bf0f617591a0821808esrs This program is free software; you can redistribute it and/or modify 5fad064250bf6c49eb4966bf0f617591a0821808esrs it under the terms of the GNU General Public License as published by 6fad064250bf6c49eb4966bf0f617591a0821808esrs the Free Software Foundation; either version 2 of the License, or 7fad064250bf6c49eb4966bf0f617591a0821808esrs (at your option) any later version. 8fad064250bf6c49eb4966bf0f617591a0821808esrs 9fad064250bf6c49eb4966bf0f617591a0821808esrs This program is distributed in the hope that it will be useful, 10fad064250bf6c49eb4966bf0f617591a0821808esrs but WITHOUT ANY WARRANTY; without even the implied warranty of 11fad064250bf6c49eb4966bf0f617591a0821808esrs MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12fad064250bf6c49eb4966bf0f617591a0821808esrs GNU General Public License for more details. 13fad064250bf6c49eb4966bf0f617591a0821808esrs 14fad064250bf6c49eb4966bf0f617591a0821808esrs You should have received a copy of the GNU General Public License along 15fad064250bf6c49eb4966bf0f617591a0821808esrs with this program; if not, write to the Free Software Foundation, Inc., 16fad064250bf6c49eb4966bf0f617591a0821808esrs 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17fad064250bf6c49eb4966bf0f617591a0821808esrs 18fad064250bf6c49eb4966bf0f617591a0821808esrs*/ 19fad064250bf6c49eb4966bf0f617591a0821808esrs 20fad064250bf6c49eb4966bf0f617591a0821808esrs/* This class implements an interactive text-mode interface atop the 21fad064250bf6c49eb4966bf0f617591a0821808esrs GPTData class */ 22fad064250bf6c49eb4966bf0f617591a0821808esrs 23fad064250bf6c49eb4966bf0f617591a0821808esrs#include <string.h> 24fad064250bf6c49eb4966bf0f617591a0821808esrs#include <errno.h> 2555d926192adc984462509b2966e23bc0d1129bbdsrs#include <stdint.h> 2661768bccdec0016d3d9757d08e63f9a1386c8bc4srs#include <limits.h> 27fad064250bf6c49eb4966bf0f617591a0821808esrs#include <iostream> 28a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs#include <fstream> 29fad064250bf6c49eb4966bf0f617591a0821808esrs#include <sstream> 301c6f8b013e7f5c166abf21c09e319d22b576c41asrs#include <cstdio> 31fad064250bf6c49eb4966bf0f617591a0821808esrs#include "attributes.h" 32fad064250bf6c49eb4966bf0f617591a0821808esrs#include "gpttext.h" 3355d926192adc984462509b2966e23bc0d1129bbdsrs#include "support.h" 34fad064250bf6c49eb4966bf0f617591a0821808esrs 35fad064250bf6c49eb4966bf0f617591a0821808esrsusing namespace std; 36fad064250bf6c49eb4966bf0f617591a0821808esrs 37a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs/******************************************** 38a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * * 39a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * GPTDataText class and related structures * 40a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * * 41a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ********************************************/ 42fad064250bf6c49eb4966bf0f617591a0821808esrs 43fad064250bf6c49eb4966bf0f617591a0821808esrsGPTDataTextUI::GPTDataTextUI(void) : GPTData() { 44fad064250bf6c49eb4966bf0f617591a0821808esrs} // default constructor 45fad064250bf6c49eb4966bf0f617591a0821808esrs 46fad064250bf6c49eb4966bf0f617591a0821808esrsGPTDataTextUI::GPTDataTextUI(string filename) : GPTData(filename) { 47fad064250bf6c49eb4966bf0f617591a0821808esrs} // constructor passing filename 48fad064250bf6c49eb4966bf0f617591a0821808esrs 49fad064250bf6c49eb4966bf0f617591a0821808esrsGPTDataTextUI::~GPTDataTextUI(void) { 50fad064250bf6c49eb4966bf0f617591a0821808esrs} // default destructor 51fad064250bf6c49eb4966bf0f617591a0821808esrs 52fad064250bf6c49eb4966bf0f617591a0821808esrs/********************************************************************* 53fad064250bf6c49eb4966bf0f617591a0821808esrs * * 54fad064250bf6c49eb4966bf0f617591a0821808esrs * The following functions are extended (interactive) versions of * 55fad064250bf6c49eb4966bf0f617591a0821808esrs * simpler functions in the base class.... * 56fad064250bf6c49eb4966bf0f617591a0821808esrs * * 57fad064250bf6c49eb4966bf0f617591a0821808esrs *********************************************************************/ 58fad064250bf6c49eb4966bf0f617591a0821808esrs 59fad064250bf6c49eb4966bf0f617591a0821808esrs// Overridden function; calls base-class function and then makes 60fad064250bf6c49eb4966bf0f617591a0821808esrs// additional queries of the user, if the base-class function can't 61fad064250bf6c49eb4966bf0f617591a0821808esrs// decide what to do. 62fad064250bf6c49eb4966bf0f617591a0821808esrsWhichToUse GPTDataTextUI::UseWhichPartitions(void) { 63fad064250bf6c49eb4966bf0f617591a0821808esrs WhichToUse which; 64fad064250bf6c49eb4966bf0f617591a0821808esrs MBRValidity mbrState; 65fad064250bf6c49eb4966bf0f617591a0821808esrs int answer; 66fad064250bf6c49eb4966bf0f617591a0821808esrs 67fad064250bf6c49eb4966bf0f617591a0821808esrs which = GPTData::UseWhichPartitions(); 68fad064250bf6c49eb4966bf0f617591a0821808esrs if ((which != use_abort) || beQuiet) 69fad064250bf6c49eb4966bf0f617591a0821808esrs return which; 70fad064250bf6c49eb4966bf0f617591a0821808esrs 71fad064250bf6c49eb4966bf0f617591a0821808esrs // If we get past here, it means that the non-interactive tests were 72fad064250bf6c49eb4966bf0f617591a0821808esrs // inconclusive, so we must ask the user which table to use.... 73fad064250bf6c49eb4966bf0f617591a0821808esrs mbrState = protectiveMBR.GetValidity(); 74fad064250bf6c49eb4966bf0f617591a0821808esrs 75fad064250bf6c49eb4966bf0f617591a0821808esrs if ((state == gpt_valid) && (mbrState == mbr)) { 76fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Found valid MBR and GPT. Which do you want to use?\n"; 77fad064250bf6c49eb4966bf0f617591a0821808esrs answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); 78fad064250bf6c49eb4966bf0f617591a0821808esrs if (answer == 1) { 79fad064250bf6c49eb4966bf0f617591a0821808esrs which = use_mbr; 80fad064250bf6c49eb4966bf0f617591a0821808esrs } else if (answer == 2) { 81fad064250bf6c49eb4966bf0f617591a0821808esrs which = use_gpt; 82fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Using GPT and creating fresh protective MBR.\n"; 83fad064250bf6c49eb4966bf0f617591a0821808esrs } else which = use_new; 84fad064250bf6c49eb4966bf0f617591a0821808esrs } // if 85fad064250bf6c49eb4966bf0f617591a0821808esrs 86fad064250bf6c49eb4966bf0f617591a0821808esrs // Nasty decisions here -- GPT is present, but corrupt (bad CRCs or other 87fad064250bf6c49eb4966bf0f617591a0821808esrs // problems) 88fad064250bf6c49eb4966bf0f617591a0821808esrs if (state == gpt_corrupt) { 89fad064250bf6c49eb4966bf0f617591a0821808esrs if ((mbrState == mbr) || (mbrState == hybrid)) { 90fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n" 91fad064250bf6c49eb4966bf0f617591a0821808esrs << "GPT MAY permit recovery of GPT data.)\n"; 92fad064250bf6c49eb4966bf0f617591a0821808esrs answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); 93fad064250bf6c49eb4966bf0f617591a0821808esrs if (answer == 1) { 94fad064250bf6c49eb4966bf0f617591a0821808esrs which = use_mbr; 95fad064250bf6c49eb4966bf0f617591a0821808esrs } else if (answer == 2) { 96fad064250bf6c49eb4966bf0f617591a0821808esrs which = use_gpt; 97fad064250bf6c49eb4966bf0f617591a0821808esrs } else which = use_new; 98fad064250bf6c49eb4966bf0f617591a0821808esrs } else if (mbrState == invalid) { 99fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n" 100fad064250bf6c49eb4966bf0f617591a0821808esrs << "GPT MAY permit recovery of GPT data.)\n"; 1010283dae41a7db4563be0fe62241ed230e4a101c0srs answer = GetNumber(1, 2, 1, " 1 - Use current GPT\n 2 - Create blank GPT\n\nYour answer: "); 102fad064250bf6c49eb4966bf0f617591a0821808esrs if (answer == 1) { 103fad064250bf6c49eb4966bf0f617591a0821808esrs which = use_gpt; 104fad064250bf6c49eb4966bf0f617591a0821808esrs } else which = use_new; 105fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else/else 106fad064250bf6c49eb4966bf0f617591a0821808esrs } // if (corrupt GPT) 107fad064250bf6c49eb4966bf0f617591a0821808esrs 108fad064250bf6c49eb4966bf0f617591a0821808esrs return which; 109fad064250bf6c49eb4966bf0f617591a0821808esrs} // UseWhichPartitions() 110fad064250bf6c49eb4966bf0f617591a0821808esrs 111fad064250bf6c49eb4966bf0f617591a0821808esrs// Ask the user for a partition number; and prompt for verification 112fad064250bf6c49eb4966bf0f617591a0821808esrs// if the requested partition isn't of a known BSD type. 113fad064250bf6c49eb4966bf0f617591a0821808esrs// Lets the base-class function do the work, and returns its value (the 114fad064250bf6c49eb4966bf0f617591a0821808esrs// number of converted partitions). 115fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::XFormDisklabel(void) { 116fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t partNum; 117fad064250bf6c49eb4966bf0f617591a0821808esrs uint16_t hexCode; 118fad064250bf6c49eb4966bf0f617591a0821808esrs int goOn = 1, numDone = 0; 119fad064250bf6c49eb4966bf0f617591a0821808esrs BSDData disklabel; 120fad064250bf6c49eb4966bf0f617591a0821808esrs 121fad064250bf6c49eb4966bf0f617591a0821808esrs partNum = GetPartNum(); 122fad064250bf6c49eb4966bf0f617591a0821808esrs 123fad064250bf6c49eb4966bf0f617591a0821808esrs // Now see if the specified partition has a BSD type code.... 124fad064250bf6c49eb4966bf0f617591a0821808esrs hexCode = partitions[partNum].GetHexType(); 125fad064250bf6c49eb4966bf0f617591a0821808esrs if ((hexCode != 0xa500) && (hexCode != 0xa900)) { 126fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Specified partition doesn't have a disklabel partition type " 127fad064250bf6c49eb4966bf0f617591a0821808esrs << "code.\nContinue anyway? "; 128fad064250bf6c49eb4966bf0f617591a0821808esrs goOn = (GetYN() == 'Y'); 129fad064250bf6c49eb4966bf0f617591a0821808esrs } // if 130fad064250bf6c49eb4966bf0f617591a0821808esrs 131fad064250bf6c49eb4966bf0f617591a0821808esrs if (goOn) 132fad064250bf6c49eb4966bf0f617591a0821808esrs numDone = GPTData::XFormDisklabel(partNum); 133fad064250bf6c49eb4966bf0f617591a0821808esrs 134fad064250bf6c49eb4966bf0f617591a0821808esrs return numDone; 1351eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith} // GPTData::XFormDisklabel(void) 136fad064250bf6c49eb4966bf0f617591a0821808esrs 13755d926192adc984462509b2966e23bc0d1129bbdsrs 138fad064250bf6c49eb4966bf0f617591a0821808esrs/********************************************************************* 139fad064250bf6c49eb4966bf0f617591a0821808esrs * * 140fad064250bf6c49eb4966bf0f617591a0821808esrs * Begin functions that obtain information from the users, and often * 141fad064250bf6c49eb4966bf0f617591a0821808esrs * do something with that information (call other functions) * 142fad064250bf6c49eb4966bf0f617591a0821808esrs * * 143fad064250bf6c49eb4966bf0f617591a0821808esrs *********************************************************************/ 144fad064250bf6c49eb4966bf0f617591a0821808esrs 145a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Prompts user for partition number and returns the result. Returns "0" 146a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// (the first partition) if none are currently defined. 147fad064250bf6c49eb4966bf0f617591a0821808esrsuint32_t GPTDataTextUI::GetPartNum(void) { 148fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t partNum; 149fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t low, high; 150fad064250bf6c49eb4966bf0f617591a0821808esrs ostringstream prompt; 151fad064250bf6c49eb4966bf0f617591a0821808esrs 152fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetPartRange(&low, &high) > 0) { 153fad064250bf6c49eb4966bf0f617591a0821808esrs prompt << "Partition number (" << low + 1 << "-" << high + 1 << "): "; 154fad064250bf6c49eb4966bf0f617591a0821808esrs partNum = GetNumber(low + 1, high + 1, low, prompt.str()); 155fad064250bf6c49eb4966bf0f617591a0821808esrs } else partNum = 1; 156fad064250bf6c49eb4966bf0f617591a0821808esrs return (partNum - 1); 157fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::GetPartNum() 158fad064250bf6c49eb4966bf0f617591a0821808esrs 159fad064250bf6c49eb4966bf0f617591a0821808esrs// What it says: Resize the partition table. (Default is 128 entries.) 160fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::ResizePartitionTable(void) { 161fad064250bf6c49eb4966bf0f617591a0821808esrs int newSize; 162fad064250bf6c49eb4966bf0f617591a0821808esrs ostringstream prompt; 163fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t curLow, curHigh; 164fad064250bf6c49eb4966bf0f617591a0821808esrs 1650283dae41a7db4563be0fe62241ed230e4a101c0srs cout << "Current partition table size is " << numParts << ".\n"; 166fad064250bf6c49eb4966bf0f617591a0821808esrs GetPartRange(&curLow, &curHigh); 167fad064250bf6c49eb4966bf0f617591a0821808esrs curHigh++; // since GetPartRange() returns numbers starting from 0... 168fad064250bf6c49eb4966bf0f617591a0821808esrs // There's no point in having fewer than four partitions.... 169fad064250bf6c49eb4966bf0f617591a0821808esrs if (curHigh < (blockSize / GPT_SIZE)) 170fad064250bf6c49eb4966bf0f617591a0821808esrs curHigh = blockSize / GPT_SIZE; 171fad064250bf6c49eb4966bf0f617591a0821808esrs prompt << "Enter new size (" << curHigh << " up, default " << NUM_GPT_ENTRIES << "): "; 172fad064250bf6c49eb4966bf0f617591a0821808esrs newSize = GetNumber(4, 65535, 128, prompt.str()); 173fad064250bf6c49eb4966bf0f617591a0821808esrs if (newSize < 128) { 174fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Caution: The partition table size should officially be 16KB or larger,\n" 175fad064250bf6c49eb4966bf0f617591a0821808esrs << "which works out to 128 entries. In practice, smaller tables seem to\n" 176fad064250bf6c49eb4966bf0f617591a0821808esrs << "work with most OSes, but this practice is risky. I'm proceeding with\n" 177fad064250bf6c49eb4966bf0f617591a0821808esrs << "the resize, but you may want to reconsider this action and undo it.\n\n"; 178fad064250bf6c49eb4966bf0f617591a0821808esrs } // if 179fad064250bf6c49eb4966bf0f617591a0821808esrs SetGPTSize(newSize); 180fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::ResizePartitionTable() 181fad064250bf6c49eb4966bf0f617591a0821808esrs 182fad064250bf6c49eb4966bf0f617591a0821808esrs// Interactively create a partition 183fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::CreatePartition(void) { 1845a081757ea2e32a491349544fea92826ccf739f6srs uint64_t firstBlock, firstInLargest, lastBlock, sector, origSector; 185fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t firstFreePart = 0; 186fad064250bf6c49eb4966bf0f617591a0821808esrs ostringstream prompt1, prompt2, prompt3; 187fad064250bf6c49eb4966bf0f617591a0821808esrs int partNum; 188fad064250bf6c49eb4966bf0f617591a0821808esrs 189fad064250bf6c49eb4966bf0f617591a0821808esrs // Find first free partition... 190fad064250bf6c49eb4966bf0f617591a0821808esrs while (partitions[firstFreePart].GetFirstLBA() != 0) { 191fad064250bf6c49eb4966bf0f617591a0821808esrs firstFreePart++; 192fad064250bf6c49eb4966bf0f617591a0821808esrs } // while 193fad064250bf6c49eb4966bf0f617591a0821808esrs 194fad064250bf6c49eb4966bf0f617591a0821808esrs if (((firstBlock = FindFirstAvailable()) != 0) && 1950283dae41a7db4563be0fe62241ed230e4a101c0srs (firstFreePart < numParts)) { 196fad064250bf6c49eb4966bf0f617591a0821808esrs lastBlock = FindLastAvailable(); 19755d926192adc984462509b2966e23bc0d1129bbdsrs firstInLargest = FindFirstInLargest(); 1980541b56fee4e92822340a2b2387508dd58d0ca7csrs Align(&firstInLargest); 19955d926192adc984462509b2966e23bc0d1129bbdsrs 20055d926192adc984462509b2966e23bc0d1129bbdsrs // Get partition number.... 201f694803eca2074523b8e502d386ca03b5642a63bRoderick W. Smith prompt1 << "Partition number (" << firstFreePart + 1 << "-" << numParts 202f694803eca2074523b8e502d386ca03b5642a63bRoderick W. Smith << ", default " << firstFreePart + 1 << "): "; 20355d926192adc984462509b2966e23bc0d1129bbdsrs do { 2040283dae41a7db4563be0fe62241ed230e4a101c0srs partNum = GetNumber(firstFreePart + 1, numParts, 20555d926192adc984462509b2966e23bc0d1129bbdsrs firstFreePart + 1, prompt1.str()) - 1; 20655d926192adc984462509b2966e23bc0d1129bbdsrs if (partitions[partNum].GetFirstLBA() != 0) 20755d926192adc984462509b2966e23bc0d1129bbdsrs cout << "partition " << partNum + 1 << " is in use.\n"; 20855d926192adc984462509b2966e23bc0d1129bbdsrs } while (partitions[partNum].GetFirstLBA() != 0); 20955d926192adc984462509b2966e23bc0d1129bbdsrs 21055d926192adc984462509b2966e23bc0d1129bbdsrs // Get first block for new partition... 21155d926192adc984462509b2966e23bc0d1129bbdsrs prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = " 2120873e9d0e9345a2c4418b4718db525c9f1111c83srs << firstInLargest << ") or {+-}size{KMGTP}: "; 21355d926192adc984462509b2966e23bc0d1129bbdsrs do { 2140873e9d0e9345a2c4418b4718db525c9f1111c83srs sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, blockSize, prompt2.str()); 21555d926192adc984462509b2966e23bc0d1129bbdsrs } while (IsFree(sector) == 0); 2165a081757ea2e32a491349544fea92826ccf739f6srs origSector = sector; 2175a081757ea2e32a491349544fea92826ccf739f6srs if (Align(§or)) { 2185a081757ea2e32a491349544fea92826ccf739f6srs cout << "Information: Moved requested sector from " << origSector << " to " 2195a081757ea2e32a491349544fea92826ccf739f6srs << sector << " in\norder to align on " << sectorAlignment 2205a081757ea2e32a491349544fea92826ccf739f6srs << "-sector boundaries.\n"; 2215a081757ea2e32a491349544fea92826ccf739f6srs if (!beQuiet) 2225a081757ea2e32a491349544fea92826ccf739f6srs cout << "Use 'l' on the experts' menu to adjust alignment\n"; 2235a081757ea2e32a491349544fea92826ccf739f6srs } // if 2245a081757ea2e32a491349544fea92826ccf739f6srs // Align(§or); // Align sector to correct multiple 22555d926192adc984462509b2966e23bc0d1129bbdsrs firstBlock = sector; 22655d926192adc984462509b2966e23bc0d1129bbdsrs 22755d926192adc984462509b2966e23bc0d1129bbdsrs // Get last block for new partitions... 22855d926192adc984462509b2966e23bc0d1129bbdsrs lastBlock = FindLastInFree(firstBlock); 22955d926192adc984462509b2966e23bc0d1129bbdsrs prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = " 2300873e9d0e9345a2c4418b4718db525c9f1111c83srs << lastBlock << ") or {+-}size{KMGTP}: "; 23155d926192adc984462509b2966e23bc0d1129bbdsrs do { 2320873e9d0e9345a2c4418b4718db525c9f1111c83srs sector = GetSectorNum(firstBlock, lastBlock, lastBlock, blockSize, prompt3.str()); 23355d926192adc984462509b2966e23bc0d1129bbdsrs } while (IsFree(sector) == 0); 23455d926192adc984462509b2966e23bc0d1129bbdsrs lastBlock = sector; 23555d926192adc984462509b2966e23bc0d1129bbdsrs 23655d926192adc984462509b2966e23bc0d1129bbdsrs firstFreePart = GPTData::CreatePartition(partNum, firstBlock, lastBlock); 23755d926192adc984462509b2966e23bc0d1129bbdsrs partitions[partNum].ChangeType(); 23855d926192adc984462509b2966e23bc0d1129bbdsrs partitions[partNum].SetDefaultDescription(); 239fad064250bf6c49eb4966bf0f617591a0821808esrs } else { 240bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if (firstFreePart >= numParts) 241bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs cout << "No table partition entries left\n"; 242bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs else 243bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs cout << "No free sectors available\n"; 244fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else 245fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::CreatePartition() 246fad064250bf6c49eb4966bf0f617591a0821808esrs 247fad064250bf6c49eb4966bf0f617591a0821808esrs// Interactively delete a partition (duh!) 248fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::DeletePartition(void) { 249fad064250bf6c49eb4966bf0f617591a0821808esrs int partNum; 250fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t low, high; 251fad064250bf6c49eb4966bf0f617591a0821808esrs ostringstream prompt; 252fad064250bf6c49eb4966bf0f617591a0821808esrs 253fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetPartRange(&low, &high) > 0) { 254fad064250bf6c49eb4966bf0f617591a0821808esrs prompt << "Partition number (" << low + 1 << "-" << high + 1 << "): "; 255fad064250bf6c49eb4966bf0f617591a0821808esrs partNum = GetNumber(low + 1, high + 1, low, prompt.str()); 256fad064250bf6c49eb4966bf0f617591a0821808esrs GPTData::DeletePartition(partNum - 1); 257fad064250bf6c49eb4966bf0f617591a0821808esrs } else { 258fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "No partitions\n"; 259fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else 260fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::DeletePartition() 261fad064250bf6c49eb4966bf0f617591a0821808esrs 262fad064250bf6c49eb4966bf0f617591a0821808esrs// Prompt user for a partition number, then change its type code 263fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::ChangePartType(void) { 264fad064250bf6c49eb4966bf0f617591a0821808esrs int partNum; 265fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t low, high; 26655d926192adc984462509b2966e23bc0d1129bbdsrs 267fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetPartRange(&low, &high) > 0) { 268fad064250bf6c49eb4966bf0f617591a0821808esrs partNum = GetPartNum(); 269fad064250bf6c49eb4966bf0f617591a0821808esrs partitions[partNum].ChangeType(); 270fad064250bf6c49eb4966bf0f617591a0821808esrs } else { 271fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "No partitions\n"; 272fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else 273fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::ChangePartType() 274fad064250bf6c49eb4966bf0f617591a0821808esrs 275815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// Prompt user for a partition number, then change its unique 276815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// GUID. 277815fb65195106b8afe1b8dfec5dae605dbd7ccbesrsvoid GPTDataTextUI::ChangeUniqueGuid(void) { 278815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs int partNum; 279815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs uint32_t low, high; 280815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs string guidStr; 281815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs 282815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs if (GetPartRange(&low, &high) > 0) { 283815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs partNum = GetPartNum(); 284815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cout << "Enter the partition's new unique GUID ('R' to randomize): "; 285815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs guidStr = ReadString(); 286815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs if ((guidStr.length() >= 32) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) { 287815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs SetPartitionGUID(partNum, (GUIDData) guidStr); 288815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cout << "New GUID is " << partitions[partNum].GetUniqueGUID() << "\n"; 289815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs } else { 290815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cout << "GUID is too short!\n"; 291815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs } // if/else 292815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs } else 293815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cout << "No partitions\n"; 294815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs} // GPTDataTextUI::ChangeUniqueGuid() 295815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs 296fad064250bf6c49eb4966bf0f617591a0821808esrs// Partition attributes seem to be rarely used, but I want a way to 297fad064250bf6c49eb4966bf0f617591a0821808esrs// adjust them for completeness.... 298fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::SetAttributes(uint32_t partNum) { 2990873e9d0e9345a2c4418b4718db525c9f1111c83srs partitions[partNum].SetAttributes(); 300fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::SetAttributes() 301fad064250bf6c49eb4966bf0f617591a0821808esrs 302699941e25a1fcf0beec124203747c8ed20842989srs// Prompts the user for a partition name and sets the partition's 303699941e25a1fcf0beec124203747c8ed20842989srs// name. Returns 1 on success, 0 on failure (invalid partition 304699941e25a1fcf0beec124203747c8ed20842989srs// number). (Note that the function skips prompting when an 305699941e25a1fcf0beec124203747c8ed20842989srs// invalid partition number is detected.) 306699941e25a1fcf0beec124203747c8ed20842989srsint GPTDataTextUI::SetName(uint32_t partNum) { 307699941e25a1fcf0beec124203747c8ed20842989srs UnicodeString theName = ""; 308699941e25a1fcf0beec124203747c8ed20842989srs int retval = 1; 309699941e25a1fcf0beec124203747c8ed20842989srs 310699941e25a1fcf0beec124203747c8ed20842989srs if (IsUsedPartNum(partNum)) { 311699941e25a1fcf0beec124203747c8ed20842989srs cout << "Enter name: "; 31284aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#ifdef USE_UTF16 313699941e25a1fcf0beec124203747c8ed20842989srs theName = ReadUString(); 31484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#else 31584aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith theName = ReadString(); 31684aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#endif 317699941e25a1fcf0beec124203747c8ed20842989srs partitions[partNum].SetName(theName); 318699941e25a1fcf0beec124203747c8ed20842989srs } else { 319699941e25a1fcf0beec124203747c8ed20842989srs cerr << "Invalid partition number (" << partNum << ")\n"; 320699941e25a1fcf0beec124203747c8ed20842989srs retval = 0; 321699941e25a1fcf0beec124203747c8ed20842989srs } // if/else 322699941e25a1fcf0beec124203747c8ed20842989srs 323699941e25a1fcf0beec124203747c8ed20842989srs return retval; 324699941e25a1fcf0beec124203747c8ed20842989srs} // GPTDataTextUI::SetName() 325699941e25a1fcf0beec124203747c8ed20842989srs 326fad064250bf6c49eb4966bf0f617591a0821808esrs// Ask user for two partition numbers and swap them in the table. Note that 327fad064250bf6c49eb4966bf0f617591a0821808esrs// this just reorders table entries; it doesn't adjust partition layout on 328fad064250bf6c49eb4966bf0f617591a0821808esrs// the disk. 329fad064250bf6c49eb4966bf0f617591a0821808esrs// Returns 1 if successful, 0 if not. (If user enters identical numbers, it 330fad064250bf6c49eb4966bf0f617591a0821808esrs// counts as successful.) 331fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::SwapPartitions(void) { 332fad064250bf6c49eb4966bf0f617591a0821808esrs int partNum1, partNum2, didIt = 0; 333fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t low, high; 334fad064250bf6c49eb4966bf0f617591a0821808esrs ostringstream prompt; 335fad064250bf6c49eb4966bf0f617591a0821808esrs GPTPart temp; 336fad064250bf6c49eb4966bf0f617591a0821808esrs 337fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetPartRange(&low, &high) > 0) { 338fad064250bf6c49eb4966bf0f617591a0821808esrs partNum1 = GetPartNum(); 3390283dae41a7db4563be0fe62241ed230e4a101c0srs if (high >= numParts - 1) 340fad064250bf6c49eb4966bf0f617591a0821808esrs high = 0; 3410283dae41a7db4563be0fe62241ed230e4a101c0srs prompt << "New partition number (1-" << numParts 34255d926192adc984462509b2966e23bc0d1129bbdsrs << ", default " << high + 2 << "): "; 3430283dae41a7db4563be0fe62241ed230e4a101c0srs partNum2 = GetNumber(1, numParts, high + 2, prompt.str()) - 1; 344fad064250bf6c49eb4966bf0f617591a0821808esrs didIt = GPTData::SwapPartitions(partNum1, partNum2); 345fad064250bf6c49eb4966bf0f617591a0821808esrs } else { 346fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "No partitions\n"; 347fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else 348fad064250bf6c49eb4966bf0f617591a0821808esrs return didIt; 349fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::SwapPartitionNumbers() 350fad064250bf6c49eb4966bf0f617591a0821808esrs 351fad064250bf6c49eb4966bf0f617591a0821808esrs// This function destroys the on-disk GPT structures. Returns 1 if the user 352fad064250bf6c49eb4966bf0f617591a0821808esrs// confirms destruction, 0 if the user aborts or if there's a disk error. 353fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::DestroyGPTwPrompt(void) { 354fad064250bf6c49eb4966bf0f617591a0821808esrs int allOK = 1; 355fad064250bf6c49eb4966bf0f617591a0821808esrs 356fad064250bf6c49eb4966bf0f617591a0821808esrs if ((apmFound) || (bsdFound)) { 357fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "WARNING: APM or BSD disklabel structures detected! This operation could\n" 358fad064250bf6c49eb4966bf0f617591a0821808esrs << "damage any APM or BSD partitions on this disk!\n"; 359fad064250bf6c49eb4966bf0f617591a0821808esrs } // if APM or BSD 360fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "\a\aAbout to wipe out GPT on " << device << ". Proceed? "; 361fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetYN() == 'Y') { 362fad064250bf6c49eb4966bf0f617591a0821808esrs if (DestroyGPT()) { 363fad064250bf6c49eb4966bf0f617591a0821808esrs // Note on below: Touch the MBR only if the user wants it completely 364fad064250bf6c49eb4966bf0f617591a0821808esrs // blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote 365fad064250bf6c49eb4966bf0f617591a0821808esrs // the MBR, but this could wipe out a valid MBR that the program 366fad064250bf6c49eb4966bf0f617591a0821808esrs // had subsequently discarded (say, if it conflicted with older GPT 367fad064250bf6c49eb4966bf0f617591a0821808esrs // structures). 368fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Blank out MBR? "; 369fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetYN() == 'Y') { 370fad064250bf6c49eb4966bf0f617591a0821808esrs DestroyMBR(); 371fad064250bf6c49eb4966bf0f617591a0821808esrs } else { 372fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n" 373fad064250bf6c49eb4966bf0f617591a0821808esrs << "with fdisk or another tool.\n"; 374fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else 375fad064250bf6c49eb4966bf0f617591a0821808esrs } else allOK = 0; // if GPT structures destroyed 376fad064250bf6c49eb4966bf0f617591a0821808esrs } else allOK = 0; // if user confirms destruction 377fad064250bf6c49eb4966bf0f617591a0821808esrs return (allOK); 378fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::DestroyGPTwPrompt() 379fad064250bf6c49eb4966bf0f617591a0821808esrs 380fad064250bf6c49eb4966bf0f617591a0821808esrs// Get partition number from user and then call ShowPartDetails(partNum) 381fad064250bf6c49eb4966bf0f617591a0821808esrs// to show its detailed information 382fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::ShowDetails(void) { 383fad064250bf6c49eb4966bf0f617591a0821808esrs int partNum; 384fad064250bf6c49eb4966bf0f617591a0821808esrs uint32_t low, high; 38555d926192adc984462509b2966e23bc0d1129bbdsrs 386fad064250bf6c49eb4966bf0f617591a0821808esrs if (GetPartRange(&low, &high) > 0) { 387fad064250bf6c49eb4966bf0f617591a0821808esrs partNum = GetPartNum(); 388fad064250bf6c49eb4966bf0f617591a0821808esrs ShowPartDetails(partNum); 389fad064250bf6c49eb4966bf0f617591a0821808esrs } else { 390fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "No partitions\n"; 391fad064250bf6c49eb4966bf0f617591a0821808esrs } // if/else 392fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::ShowDetails() 393fad064250bf6c49eb4966bf0f617591a0821808esrs 394fad064250bf6c49eb4966bf0f617591a0821808esrs// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with 395fad064250bf6c49eb4966bf0f617591a0821808esrs// OSes that don't understand GPT. 396fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::MakeHybrid(void) { 397a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith uint32_t partNums[3] = {0, 0, 0}; 3985a6085310b7f8fe1c35e56bcab7de161808b488dsrs string line; 399a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith int numPartsToCvt = 0, numConverted = 0, i, j, mbrNum = 0; 40055d926192adc984462509b2966e23bc0d1129bbdsrs unsigned int hexCode = 0; 401bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs MBRPart hybridPart; 402bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs MBRData hybridMBR; 403fad064250bf6c49eb4966bf0f617591a0821808esrs char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table 404fad064250bf6c49eb4966bf0f617591a0821808esrs 405058d4a58614e07921a306857294ed017991097a9srs cout << "\nWARNING! Hybrid MBRs are flaky and dangerous! If you decide not to use one,\n" 406058d4a58614e07921a306857294ed017991097a9srs << "just hit the Enter key at the below prompt and your MBR partition table will\n" 407058d4a58614e07921a306857294ed017991097a9srs << "be untouched.\n\n\a"; 408fad064250bf6c49eb4966bf0f617591a0821808esrs 4096aae2a9b70e9f88926baad94c1eea40e0b534f01srs // Use a local MBR structure, copying from protectiveMBR to keep its 4106aae2a9b70e9f88926baad94c1eea40e0b534f01srs // boot loader code intact.... 4116aae2a9b70e9f88926baad94c1eea40e0b534f01srs hybridMBR = protectiveMBR; 4126aae2a9b70e9f88926baad94c1eea40e0b534f01srs hybridMBR.EmptyMBR(0); 4136aae2a9b70e9f88926baad94c1eea40e0b534f01srs 414fad064250bf6c49eb4966bf0f617591a0821808esrs // Now get the numbers of up to three partitions to add to the 415fad064250bf6c49eb4966bf0f617591a0821808esrs // hybrid MBR.... 416fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n" 417fad064250bf6c49eb4966bf0f617591a0821808esrs << "added to the hybrid MBR, in sequence: "; 4185a6085310b7f8fe1c35e56bcab7de161808b488dsrs line = ReadString(); 4199b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith istringstream inLine(line); 4209b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith do { 421a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith inLine >> partNums[numPartsToCvt]; 422a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith if (partNums[numPartsToCvt] > 0) 423a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith numPartsToCvt++; 4249b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith } while (!inLine.eof() && (numPartsToCvt < 3)); 425fad064250bf6c49eb4966bf0f617591a0821808esrs 4260283dae41a7db4563be0fe62241ed230e4a101c0srs if (numPartsToCvt > 0) { 427fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? "; 428fad064250bf6c49eb4966bf0f617591a0821808esrs eeFirst = GetYN(); 429fad064250bf6c49eb4966bf0f617591a0821808esrs } // if 430fad064250bf6c49eb4966bf0f617591a0821808esrs 4310283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numPartsToCvt; i++) { 432bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs j = partNums[i] - 1; 433a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith if (partitions[j].IsUsed() && (partitions[j].IsSizedForMBR() != MBR_SIZED_BAD)) { 434058d4a58614e07921a306857294ed017991097a9srs mbrNum = i + (eeFirst == 'Y'); 435058d4a58614e07921a306857294ed017991097a9srs cout << "\nCreating entry for GPT partition #" << j + 1 436058d4a58614e07921a306857294ed017991097a9srs << " (MBR partition #" << mbrNum + 1 << ")\n"; 437bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetType(GetMBRTypeCode(partitions[j].GetHexType() / 256)); 438bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetLocation(partitions[j].GetFirstLBA(), partitions[j].GetLengthLBA()); 439bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetInclusion(PRIMARY); 440058d4a58614e07921a306857294ed017991097a9srs cout << "Set the bootable flag? "; 441058d4a58614e07921a306857294ed017991097a9srs if (GetYN() == 'Y') 4426aae2a9b70e9f88926baad94c1eea40e0b534f01srs hybridPart.SetStatus(0x80); 443058d4a58614e07921a306857294ed017991097a9srs else 4446aae2a9b70e9f88926baad94c1eea40e0b534f01srs hybridPart.SetStatus(0x00); 445bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetInclusion(PRIMARY); 446a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith if (partitions[j].IsSizedForMBR() == MBR_SIZED_IFFY) 447a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith WarnAboutIffyMBRPart(j + 1); 448a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith numConverted++; 449058d4a58614e07921a306857294ed017991097a9srs } else { 4509b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith cerr << "\nGPT partition #" << j + 1 << " does not exist or is too big; skipping.\n"; 451058d4a58614e07921a306857294ed017991097a9srs } // if/else 452bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridMBR.AddPart(mbrNum, hybridPart); 453fad064250bf6c49eb4966bf0f617591a0821808esrs } // for 454fad064250bf6c49eb4966bf0f617591a0821808esrs 455a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith if (numConverted > 0) { // User opted to create a hybrid MBR.... 456fad064250bf6c49eb4966bf0f617591a0821808esrs // Create EFI protective partition that covers the start of the disk. 457fad064250bf6c49eb4966bf0f617591a0821808esrs // If this location (covering the main GPT data structures) is omitted, 458fad064250bf6c49eb4966bf0f617591a0821808esrs // Linux won't find any partitions on the disk. 459bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetLocation(1, hybridMBR.FindLastInFree(1)); 460bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetStatus(0); 461bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetType(0xEE); 462bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridPart.SetInclusion(PRIMARY); 46355d926192adc984462509b2966e23bc0d1129bbdsrs // newNote firstLBA and lastLBA are computed later... 46455d926192adc984462509b2966e23bc0d1129bbdsrs if (eeFirst == 'Y') { 465bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridMBR.AddPart(0, hybridPart); 46655d926192adc984462509b2966e23bc0d1129bbdsrs } else { 467a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith hybridMBR.AddPart(numConverted, hybridPart); 46855d926192adc984462509b2966e23bc0d1129bbdsrs } // else 469bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs hybridMBR.SetHybrid(); 470fad064250bf6c49eb4966bf0f617591a0821808esrs 471fad064250bf6c49eb4966bf0f617591a0821808esrs // ... and for good measure, if there are any partition spaces left, 472fad064250bf6c49eb4966bf0f617591a0821808esrs // optionally create another protective EFI partition to cover as much 473fad064250bf6c49eb4966bf0f617591a0821808esrs // space as possible.... 474bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if (hybridMBR.CountParts() < 4) { // unused entry.... 47555d926192adc984462509b2966e23bc0d1129bbdsrs cout << "\nUnused partition space(s) found. Use one to protect more partitions? "; 47655d926192adc984462509b2966e23bc0d1129bbdsrs if (GetYN() == 'Y') { 4775a6085310b7f8fe1c35e56bcab7de161808b488dsrs cout << "Note: Default is 0xEE, but this may confuse Mac OS X.\n"; 4785a6085310b7f8fe1c35e56bcab7de161808b488dsrs // Comment on above: Mac OS treats disks with more than one 4795a6085310b7f8fe1c35e56bcab7de161808b488dsrs // 0xEE MBR partition as MBR disks, not as GPT disks. 4805a6085310b7f8fe1c35e56bcab7de161808b488dsrs hexCode = GetMBRTypeCode(0xEE); 4815a6085310b7f8fe1c35e56bcab7de161808b488dsrs hybridMBR.MakeBiggestPart(3, hexCode); 48255d926192adc984462509b2966e23bc0d1129bbdsrs } // if (GetYN() == 'Y') 48355d926192adc984462509b2966e23bc0d1129bbdsrs } // if unused entry 484bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs protectiveMBR = hybridMBR; 485a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith } else { 486a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith cout << "\nNo partitions converted; original protective/hybrid MBR is unmodified!\n"; 487a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith } // if/else (numConverted > 0) 488fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::MakeHybrid() 489fad064250bf6c49eb4966bf0f617591a0821808esrs 49055d926192adc984462509b2966e23bc0d1129bbdsrs// Convert the GPT to MBR form, storing partitions in the protectiveMBR 49155d926192adc984462509b2966e23bc0d1129bbdsrs// variable. This function is necessarily limited; it may not be able to 49255d926192adc984462509b2966e23bc0d1129bbdsrs// convert all partitions, depending on the disk size and available space 49355d926192adc984462509b2966e23bc0d1129bbdsrs// before each partition (one free sector is required to create a logical 49455d926192adc984462509b2966e23bc0d1129bbdsrs// partition, which are necessary to convert more than four partitions). 49555d926192adc984462509b2966e23bc0d1129bbdsrs// Returns the number of converted partitions; if this value 496fad064250bf6c49eb4966bf0f617591a0821808esrs// is over 0, the calling function should call DestroyGPT() to destroy 49755d926192adc984462509b2966e23bc0d1129bbdsrs// the GPT data, call SaveMBR() to save the MBR, and then exit. 498fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::XFormToMBR(void) { 49955d926192adc984462509b2966e23bc0d1129bbdsrs uint32_t i; 50055d926192adc984462509b2966e23bc0d1129bbdsrs 5016aae2a9b70e9f88926baad94c1eea40e0b534f01srs protectiveMBR.EmptyMBR(0); 502bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs for (i = 0; i < numParts; i++) { 503bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if (partitions[i].IsUsed()) { 504a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith if (partitions[i].IsSizedForMBR() == MBR_SIZED_IFFY) 505a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith WarnAboutIffyMBRPart(i + 1); 506a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith // Note: MakePart() checks for oversized partitions, so don't 507a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith // bother checking other IsSizedForMBR() return values.... 508bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs protectiveMBR.MakePart(i, partitions[i].GetFirstLBA(), 509bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[i].GetLengthLBA(), 510bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[i].GetHexType() / 0x0100, 0); 511bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs } // if 512bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs } // for 513bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs protectiveMBR.MakeItLegal(); 514bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs return protectiveMBR.DoMenu(); 515fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::XFormToMBR() 516fad064250bf6c49eb4966bf0f617591a0821808esrs 517a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith/****************************************************** 518a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith * * 519a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith * Display informational messages for the user.... * 520a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith * * 521a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith ******************************************************/ 522a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith 523a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// Although an MBR partition that begins below sector 2^32 and is less than 2^32 sectors in 524a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// length is technically legal even if it ends above the 2^32-sector mark, such a partition 525a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// tends to confuse a lot of OSes, so warn the user about such partitions. This function is 526a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// called by XFormToMBR() and MakeHybrid(); it's a separate function just to consolidate the 527a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// lengthy message in one place. 528a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smithvoid GPTDataTextUI::WarnAboutIffyMBRPart(int partNum) { 529a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith cout << "\a\nWarning! GPT partition " << partNum << " ends after the 2^32 sector mark! The partition\n" 530a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith << "begins before this point, and is smaller than 2^32 sectors. This is technically\n" 531a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith << "legal, but will confuse some OSes. The partition IS being added to the MBR, but\n" 532a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith << "if your OS misbehaves or can't see the partition, the partition may simply be\n" 533a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith << "unusable in that OS and may need to be resized or omitted from the MBR.\n\n"; 534a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith} // GPTDataTextUI::WarnAboutIffyMBRPart() 535a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 536a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs/********************************************************************* 537a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * * 538a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * The following functions provide the main menus for the gdisk * 539a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * program.... * 540a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * * 541a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs *********************************************************************/ 542a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 543a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Accept a command and execute it. Returns only when the user 544a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// wants to exit (such as after a 'w' or 'q' command). 545a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::MainMenu(string filename) { 546a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs int goOn = 1; 547a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs PartType typeHelper; 548a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs uint32_t temp1, temp2; 549a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs 550a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs do { 551a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "\nCommand (? for help): "; 552a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs switch (ReadString()[0]) { 553a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case '\0': 554a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs goOn = cin.good(); 555a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 556a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'b': case 'B': 557a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Enter backup filename to save: "; 558a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SaveGPTBackup(ReadString()); 559a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 560a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'c': case 'C': 561a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (GetPartRange(&temp1, &temp2) > 0) 562a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SetName(GetPartNum()); 563a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs else 564a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "No partitions\n"; 565a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 566a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'd': case 'D': 567a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs DeletePartition(); 568a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 569a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'i': case 'I': 570a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ShowDetails(); 571a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 572a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'l': case 'L': 573a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs typeHelper.ShowAllTypes(); 574a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 575a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'n': case 'N': 576a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs CreatePartition(); 577a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 578a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'o': case 'O': 579a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "This option deletes all partitions and creates a new protective MBR.\n" 580a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << "Proceed? "; 581a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (GetYN() == 'Y') { 582a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ClearGPTData(); 583a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MakeProtectiveMBR(); 584a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 585a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 586a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'p': case 'P': 587a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs DisplayGPTData(); 588a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 589a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'q': case 'Q': 590a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 591a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 592a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'r': case 'R': 593a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs RecoveryMenu(filename); 594a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 595a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 596a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 's': case 'S': 597a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SortGPT(); 598a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "You may need to edit /etc/fstab and/or your boot loader configuration!\n"; 599a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 600a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 't': case 'T': 601a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ChangePartType(); 602a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 603a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'v': case 'V': 604a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs Verify(); 605a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 606a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'w': case 'W': 607a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (SaveGPTData() == 1) 608a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 609a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 610a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'x': case 'X': 611a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ExpertsMenu(filename); 612a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 613a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 614a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs default: 615a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ShowCommands(); 616a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 617a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // switch 618a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } while (goOn); 619a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::MainMenu() 620a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 621a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ShowCommands(void) { 622a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "b\tback up GPT data to a file\n"; 623a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "c\tchange a partition's name\n"; 624a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "d\tdelete a partition\n"; 625a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "i\tshow detailed information on a partition\n"; 626a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "l\tlist known partition types\n"; 627a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "n\tadd a new partition\n"; 628a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "o\tcreate a new empty GUID partition table (GPT)\n"; 629a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "p\tprint the partition table\n"; 630a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "q\tquit without saving changes\n"; 631a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "r\trecovery and transformation options (experts only)\n"; 632a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "s\tsort partitions\n"; 633a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "t\tchange a partition's type code\n"; 634a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "v\tverify disk\n"; 635a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "w\twrite table to disk and exit\n"; 636a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "x\textra functionality (experts only)\n"; 637a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "?\tprint this menu\n"; 638a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ShowCommands() 639a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 640a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Accept a recovery & transformation menu command. Returns only when the user 641a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// issues an exit command, such as 'w' or 'q'. 642a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::RecoveryMenu(string filename) { 643a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs uint32_t numParts; 644a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs int goOn = 1, temp1; 645a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 646a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs do { 647a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "\nRecovery/transformation command (? for help): "; 648a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs switch (ReadString()[0]) { 649a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case '\0': 650a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs goOn = cin.good(); 651a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 652a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'b': case 'B': 653a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs RebuildMainHeader(); 654a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 655a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'c': case 'C': 656a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Warning! This will probably do weird things if you've converted an MBR to\n" 657a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << "GPT form and haven't yet saved the GPT! Proceed? "; 658a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (GetYN() == 'Y') 659a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs LoadSecondTableAsMain(); 660a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 661a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'd': case 'D': 662a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs RebuildSecondHeader(); 663a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 664a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'e': case 'E': 665a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Warning! This will probably do weird things if you've converted an MBR to\n" 666a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << "GPT form and haven't yet saved the GPT! Proceed? "; 667a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (GetYN() == 'Y') 668a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs LoadMainTable(); 669a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 670a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'f': case 'F': 671a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Warning! This will destroy the currently defined partitions! Proceed? "; 672a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (GetYN() == 'Y') { 673a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (LoadMBR(filename) == 1) { // successful load 674a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs XFormPartitions(); 675a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } else { 676a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Problem loading MBR! GPT is untouched; regenerating protective MBR!\n"; 677a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MakeProtectiveMBR(); 678a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if/else 679a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 680a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 681a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'g': case 'G': 682a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs numParts = GetNumParts(); 683a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs temp1 = XFormToMBR(); 684a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (temp1 > 0) 685a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "\nConverted " << temp1 << " partitions. Finalize and exit? "; 686a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if ((temp1 > 0) && (GetYN() == 'Y')) { 687a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if ((DestroyGPT() > 0) && (SaveMBR())) { 688a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 689a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 690a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } else { 691a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MakeProtectiveMBR(); 692706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(numParts, 0); 693a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Note: New protective MBR created\n\n"; 694a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if/else 695a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 696a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'h': case 'H': 697a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MakeHybrid(); 698a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 699a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'i': case 'I': 700a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ShowDetails(); 701a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 702a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'l': case 'L': 703a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Enter backup filename to load: "; 704a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs LoadGPTBackup(ReadString()); 705a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 706a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'm': case 'M': 707a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MainMenu(filename); 708a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 709a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 710a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'o': case 'O': 711a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs DisplayMBRData(); 712a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 713a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'p': case 'P': 714a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs DisplayGPTData(); 715a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 716a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'q': case 'Q': 717a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 718a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 719a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 't': case 'T': 720a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs XFormDisklabel(); 721a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 722a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'v': case 'V': 723a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs Verify(); 724a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 725a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'w': case 'W': 726a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (SaveGPTData() == 1) { 727a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 728a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 729a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 730a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'x': case 'X': 731a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ExpertsMenu(filename); 732a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 733a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 734a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs default: 735a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ShowRecoveryCommands(); 736a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 737a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // switch 738a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } while (goOn); 739a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::RecoveryMenu() 740a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 741a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ShowRecoveryCommands(void) { 742a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "b\tuse backup GPT header (rebuilding main)\n"; 743a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "c\tload backup partition table from disk (rebuilding main)\n"; 744a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "d\tuse main GPT header (rebuilding backup)\n"; 745a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "e\tload main partition table from disk (rebuilding backup)\n"; 746a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "f\tload MBR and build fresh GPT from it\n"; 747a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "g\tconvert GPT into MBR and exit\n"; 748a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "h\tmake hybrid MBR\n"; 749a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "i\tshow detailed information on a partition\n"; 750a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "l\tload partition data from a backup file\n"; 751a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "m\treturn to main menu\n"; 752a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "o\tprint protective MBR data\n"; 753a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "p\tprint the partition table\n"; 754a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "q\tquit without saving changes\n"; 755a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "t\ttransform BSD disklabel partition\n"; 756a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "v\tverify disk\n"; 757a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "w\twrite table to disk and exit\n"; 758a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "x\textra functionality (experts only)\n"; 759a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "?\tprint this menu\n"; 760a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ShowRecoveryCommands() 761a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 762a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Accept an experts' menu command. Returns only after the user 763a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// selects an exit command, such as 'w' or 'q'. 764a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ExpertsMenu(string filename) { 765a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs GPTData secondDevice; 766a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs uint32_t temp1, temp2; 767a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs int goOn = 1; 768a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs string guidStr, device; 769a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs GUIDData aGUID; 770a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ostringstream prompt; 771a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 772a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs do { 773a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "\nExpert command (? for help): "; 774a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs switch (ReadString()[0]) { 775a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case '\0': 776a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs goOn = cin.good(); 777a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 778a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'a': case 'A': 779a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (GetPartRange(&temp1, &temp2) > 0) 780a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SetAttributes(GetPartNum()); 781a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs else 782a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "No partitions\n"; 783a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 784a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'c': case 'C': 785a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ChangeUniqueGuid(); 786a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 787a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'd': case 'D': 788a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Partitions will begin on " << GetAlignment() 789a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << "-sector boundaries.\n"; 790a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 791a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'e': case 'E': 792a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Relocating backup data structures to the end of the disk\n"; 793a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MoveSecondHeaderToEnd(); 794a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 795a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'f': case 'F': 796a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs RandomizeGUIDs(); 797a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 798a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'g': case 'G': 799a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Enter the disk's unique GUID ('R' to randomize): "; 800a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs guidStr = ReadString(); 801a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if ((guidStr.length() >= 32) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) { 802a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SetDiskGUID((GUIDData) guidStr); 803a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "The new disk GUID is " << GetDiskGUID() << "\n"; 804a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } else { 805a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "GUID is too short!\n"; 806a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if/else 807a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 808a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'h': case 'H': 809a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs RecomputeCHS(); 810a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 811a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'i': case 'I': 812a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ShowDetails(); 813a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 814a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'l': case 'L': 815a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs prompt.seekp(0); 816a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = " 817a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << DEFAULT_ALIGNMENT << "): "; 818a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs temp1 = GetNumber(1, MAX_ALIGNMENT, DEFAULT_ALIGNMENT, prompt.str()); 819a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SetAlignment(temp1); 820a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 821a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'm': case 'M': 822a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MainMenu(filename); 823a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 824a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 825a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'n': case 'N': 826a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs MakeProtectiveMBR(); 827a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 828a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'o': case 'O': 829a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs DisplayMBRData(); 830a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 831a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'p': case 'P': 832a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs DisplayGPTData(); 833a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 834a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'q': case 'Q': 835a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 836a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 837a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'r': case 'R': 838a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs RecoveryMenu(filename); 839a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 840a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 841a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 's': case 'S': 842a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ResizePartitionTable(); 843a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 844a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 't': case 'T': 845a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs SwapPartitions(); 846a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 847a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'u': case 'U': 848a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "Type device filename, or press <Enter> to exit: "; 849a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs device = ReadString(); 850a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (device.length() > 0) { 851a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs secondDevice = *this; 852a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs secondDevice.SetDisk(device); 853a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs secondDevice.SaveGPTData(0); 854a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 855a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 856a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'v': case 'V': 857a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs Verify(); 858a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 859a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'w': case 'W': 860a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (SaveGPTData() == 1) { 861a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 862a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 863a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 864a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs case 'z': case 'Z': 865a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (DestroyGPTwPrompt() == 1) { 866a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs goOn = 0; 867a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } 868a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 869a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs default: 870a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ShowExpertCommands(); 871a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs break; 872a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // switch 873a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } while (goOn); 874a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ExpertsMenu() 875a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 876a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ShowExpertCommands(void) { 877a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "a\tset attributes\n"; 878a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "c\tchange partition GUID\n"; 879a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "d\tdisplay the sector alignment value\n"; 880a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "e\trelocate backup data structures to the end of the disk\n"; 881a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "g\tchange disk GUID\n"; 882a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "h\trecompute CHS values in protective/hybrid MBR\n"; 883a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "i\tshow detailed information on a partition\n"; 884a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "l\tset the sector alignment value\n"; 885a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "m\treturn to main menu\n"; 886a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "n\tcreate a new protective MBR\n"; 887a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "o\tprint protective MBR data\n"; 888a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "p\tprint the partition table\n"; 889a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "q\tquit without saving changes\n"; 890a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "r\trecovery and transformation options (experts only)\n"; 891a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "s\tresize partition table\n"; 892a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "t\ttranspose two partition table entries\n"; 89384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cout << "u\treplicate partition table on new device\n"; 894a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "v\tverify disk\n"; 895a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "w\twrite table to disk and exit\n"; 896a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "z\tzap (destroy) GPT data structures and exit\n"; 897a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cout << "?\tprint this menu\n"; 898a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ShowExpertCommands() 899a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 900a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 901a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs 902699941e25a1fcf0beec124203747c8ed20842989srs/******************************** 903699941e25a1fcf0beec124203747c8ed20842989srs * * 904699941e25a1fcf0beec124203747c8ed20842989srs * Non-class support functions. * 905699941e25a1fcf0beec124203747c8ed20842989srs * * 906699941e25a1fcf0beec124203747c8ed20842989srs ********************************/ 907699941e25a1fcf0beec124203747c8ed20842989srs 908699941e25a1fcf0beec124203747c8ed20842989srs// GetMBRTypeCode() doesn't really belong in the class, since it's MBR- 909699941e25a1fcf0beec124203747c8ed20842989srs// specific, but it's also user I/O-related, so I want to keep it in 910699941e25a1fcf0beec124203747c8ed20842989srs// this file.... 911fad064250bf6c49eb4966bf0f617591a0821808esrs 912fad064250bf6c49eb4966bf0f617591a0821808esrs// Get an MBR type code from the user and return it 913fad064250bf6c49eb4966bf0f617591a0821808esrsint GetMBRTypeCode(int defType) { 9145a6085310b7f8fe1c35e56bcab7de161808b488dsrs string line; 915fad064250bf6c49eb4966bf0f617591a0821808esrs int typeCode; 916fad064250bf6c49eb4966bf0f617591a0821808esrs 917fad064250bf6c49eb4966bf0f617591a0821808esrs cout.setf(ios::uppercase); 918fad064250bf6c49eb4966bf0f617591a0821808esrs cout.fill('0'); 919fad064250bf6c49eb4966bf0f617591a0821808esrs do { 920fad064250bf6c49eb4966bf0f617591a0821808esrs cout << "Enter an MBR hex code (default " << hex; 921fad064250bf6c49eb4966bf0f617591a0821808esrs cout.width(2); 922fad064250bf6c49eb4966bf0f617591a0821808esrs cout << defType << "): " << dec; 9235a6085310b7f8fe1c35e56bcab7de161808b488dsrs line = ReadString(); 9245a6085310b7f8fe1c35e56bcab7de161808b488dsrs if (line[0] == '\0') 925fad064250bf6c49eb4966bf0f617591a0821808esrs typeCode = defType; 926fad064250bf6c49eb4966bf0f617591a0821808esrs else 9275a6085310b7f8fe1c35e56bcab7de161808b488dsrs typeCode = StrToHex(line, 0); 928fad064250bf6c49eb4966bf0f617591a0821808esrs } while ((typeCode <= 0) || (typeCode > 255)); 929fad064250bf6c49eb4966bf0f617591a0821808esrs cout.fill(' '); 930fad064250bf6c49eb4966bf0f617591a0821808esrs return typeCode; 9311c6f8b013e7f5c166abf21c09e319d22b576c41asrs} // GetMBRTypeCode 932699941e25a1fcf0beec124203747c8ed20842989srs 93384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#ifdef USE_UTF16 934699941e25a1fcf0beec124203747c8ed20842989srs// Note: ReadUString() is here rather than in support.cc so that the ICU 935699941e25a1fcf0beec124203747c8ed20842989srs// libraries need not be linked to fixparts. 936699941e25a1fcf0beec124203747c8ed20842989srs 937699941e25a1fcf0beec124203747c8ed20842989srs// Reads a Unicode string from stdin, returning it as an ICU-style string. 938699941e25a1fcf0beec124203747c8ed20842989srs// Note that the returned string will NOT include the carriage return 939699941e25a1fcf0beec124203747c8ed20842989srs// entered by the user. Relies on the ICU constructor from a string 940699941e25a1fcf0beec124203747c8ed20842989srs// encoded in the current codepage to work. 941699941e25a1fcf0beec124203747c8ed20842989srsUnicodeString ReadUString(void) { 942699941e25a1fcf0beec124203747c8ed20842989srs return ReadString().c_str(); 943699941e25a1fcf0beec124203747c8ed20842989srs} // ReadUString() 94484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#endif 945699941e25a1fcf0beec124203747c8ed20842989srs 946