blob: 46e6eea13c1b1343b7c2d8dea7ac167a01717b03 [file] [log] [blame]
srs5694fad06422010-02-19 17:19:17 -05001/*
2 Copyright (C) <2010> <Roderick W. Smith>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18*/
19
20/* This class implements an interactive text-mode interface atop the
21 GPTData class */
22
23#include <string.h>
24#include <errno.h>
srs569455d92612010-03-07 22:16:07 -050025#include <stdint.h>
srs5694fad06422010-02-19 17:19:17 -050026#include <iostream>
27#include <sstream>
srs56941c6f8b02010-02-21 11:09:20 -050028#include <cstdio>
srs5694fad06422010-02-19 17:19:17 -050029#include "attributes.h"
30#include "gpttext.h"
srs569455d92612010-03-07 22:16:07 -050031#include "partnotes.h"
32#include "support.h"
srs5694fad06422010-02-19 17:19:17 -050033
34using namespace std;
35
36/*******************************************
37* *
38* GPTDataText class and related structures *
39* *
40********************************************/
41
42GPTDataTextUI::GPTDataTextUI(void) : GPTData() {
43} // default constructor
44
45GPTDataTextUI::GPTDataTextUI(string filename) : GPTData(filename) {
46} // constructor passing filename
47
48GPTDataTextUI::~GPTDataTextUI(void) {
49} // default destructor
50
51/*********************************************************************
52 * *
53 * The following functions are extended (interactive) versions of *
54 * simpler functions in the base class.... *
55 * *
56 *********************************************************************/
57
58// Overridden function; calls base-class function and then makes
59// additional queries of the user, if the base-class function can't
60// decide what to do.
61WhichToUse GPTDataTextUI::UseWhichPartitions(void) {
62 WhichToUse which;
63 MBRValidity mbrState;
64 int answer;
65
66 which = GPTData::UseWhichPartitions();
67 if ((which != use_abort) || beQuiet)
68 return which;
69
70 // If we get past here, it means that the non-interactive tests were
71 // inconclusive, so we must ask the user which table to use....
72 mbrState = protectiveMBR.GetValidity();
73
74 if ((state == gpt_valid) && (mbrState == mbr)) {
75 cout << "Found valid MBR and GPT. Which do you want to use?\n";
76 answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
77 if (answer == 1) {
78 which = use_mbr;
79 } else if (answer == 2) {
80 which = use_gpt;
81 cout << "Using GPT and creating fresh protective MBR.\n";
82 } else which = use_new;
83 } // if
84
85 // Nasty decisions here -- GPT is present, but corrupt (bad CRCs or other
86 // problems)
87 if (state == gpt_corrupt) {
88 if ((mbrState == mbr) || (mbrState == hybrid)) {
89 cout << "Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n"
90 << "GPT MAY permit recovery of GPT data.)\n";
91 answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
92 if (answer == 1) {
93 which = use_mbr;
94 } else if (answer == 2) {
95 which = use_gpt;
96 } else which = use_new;
97 } else if (mbrState == invalid) {
98 cout << "Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n"
99 << "GPT MAY permit recovery of GPT data.)\n";
100 answer = GetNumber(1, 2, 1, " 1 - GPT\n 2 - Create blank GPT\n\nYour answer: ");
101 if (answer == 1) {
102 which = use_gpt;
103 } else which = use_new;
104 } // if/else/else
105 } // if (corrupt GPT)
106
107 return which;
108} // UseWhichPartitions()
109
110// Ask the user for a partition number; and prompt for verification
111// if the requested partition isn't of a known BSD type.
112// Lets the base-class function do the work, and returns its value (the
113// number of converted partitions).
114int GPTDataTextUI::XFormDisklabel(void) {
115 uint32_t partNum;
116 uint16_t hexCode;
117 int goOn = 1, numDone = 0;
118 BSDData disklabel;
119
120 partNum = GetPartNum();
121
122 // Now see if the specified partition has a BSD type code....
123 hexCode = partitions[partNum].GetHexType();
124 if ((hexCode != 0xa500) && (hexCode != 0xa900)) {
125 cout << "Specified partition doesn't have a disklabel partition type "
126 << "code.\nContinue anyway? ";
127 goOn = (GetYN() == 'Y');
128 } // if
129
130 if (goOn)
131 numDone = GPTData::XFormDisklabel(partNum);
132
133 return numDone;
134} // GPTData::XFormDisklabel(int i)
135
srs569455d92612010-03-07 22:16:07 -0500136
srs5694fad06422010-02-19 17:19:17 -0500137/*********************************************************************
138 * *
139 * Begin functions that obtain information from the users, and often *
140 * do something with that information (call other functions) *
141 * *
142 *********************************************************************/
143
144// Prompts user for partition number and returns the result.
145uint32_t GPTDataTextUI::GetPartNum(void) {
146 uint32_t partNum;
147 uint32_t low, high;
148 ostringstream prompt;
149
150 if (GetPartRange(&low, &high) > 0) {
151 prompt << "Partition number (" << low + 1 << "-" << high + 1 << "): ";
152 partNum = GetNumber(low + 1, high + 1, low, prompt.str());
153 } else partNum = 1;
154 return (partNum - 1);
155} // GPTDataTextUI::GetPartNum()
156
157// What it says: Resize the partition table. (Default is 128 entries.)
158void GPTDataTextUI::ResizePartitionTable(void) {
159 int newSize;
160 ostringstream prompt;
161 uint32_t curLow, curHigh;
162
163 cout << "Current partition table size is " << mainHeader.numParts << ".\n";
164 GetPartRange(&curLow, &curHigh);
165 curHigh++; // since GetPartRange() returns numbers starting from 0...
166 // There's no point in having fewer than four partitions....
167 if (curHigh < (blockSize / GPT_SIZE))
168 curHigh = blockSize / GPT_SIZE;
169 prompt << "Enter new size (" << curHigh << " up, default " << NUM_GPT_ENTRIES << "): ";
170 newSize = GetNumber(4, 65535, 128, prompt.str());
171 if (newSize < 128) {
172 cout << "Caution: The partition table size should officially be 16KB or larger,\n"
173 << "which works out to 128 entries. In practice, smaller tables seem to\n"
174 << "work with most OSes, but this practice is risky. I'm proceeding with\n"
175 << "the resize, but you may want to reconsider this action and undo it.\n\n";
176 } // if
177 SetGPTSize(newSize);
178} // GPTDataTextUI::ResizePartitionTable()
179
180// Interactively create a partition
181void GPTDataTextUI::CreatePartition(void) {
182 uint64_t firstBlock, firstInLargest, lastBlock, sector;
183 uint32_t firstFreePart = 0;
184 ostringstream prompt1, prompt2, prompt3;
185 int partNum;
186
187 // Find first free partition...
188 while (partitions[firstFreePart].GetFirstLBA() != 0) {
189 firstFreePart++;
190 } // while
191
192 if (((firstBlock = FindFirstAvailable()) != 0) &&
srs569455d92612010-03-07 22:16:07 -0500193 (firstFreePart < mainHeader.numParts)) {
srs5694fad06422010-02-19 17:19:17 -0500194 lastBlock = FindLastAvailable();
srs569455d92612010-03-07 22:16:07 -0500195 firstInLargest = FindFirstInLargest();
196
197 // Get partition number....
198 do {
199 prompt1 << "Partition number (" << firstFreePart + 1 << "-" << mainHeader.numParts
200 << ", default " << firstFreePart + 1 << "): ";
201 partNum = GetNumber(firstFreePart + 1, mainHeader.numParts,
202 firstFreePart + 1, prompt1.str()) - 1;
203 if (partitions[partNum].GetFirstLBA() != 0)
204 cout << "partition " << partNum + 1 << " is in use.\n";
205 } while (partitions[partNum].GetFirstLBA() != 0);
206
207 // Get first block for new partition...
208 prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = "
209 << firstInLargest << ") or {+-}size{KMGT}: ";
210 do {
211 sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt2.str());
212 } while (IsFree(sector) == 0);
213 Align(&sector); // Align sector to correct multiple
214 firstBlock = sector;
215
216 // Get last block for new partitions...
217 lastBlock = FindLastInFree(firstBlock);
218 prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = "
219 << lastBlock << ") or {+-}size{KMGT}: ";
220 do {
221 sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt3.str());
222 } while (IsFree(sector) == 0);
223 lastBlock = sector;
224
225 firstFreePart = GPTData::CreatePartition(partNum, firstBlock, lastBlock);
226 partitions[partNum].ChangeType();
227 partitions[partNum].SetDefaultDescription();
srs5694fad06422010-02-19 17:19:17 -0500228 } else {
229 cout << "No free sectors available\n";
230 } // if/else
231} // GPTDataTextUI::CreatePartition()
232
233// Interactively delete a partition (duh!)
234void GPTDataTextUI::DeletePartition(void) {
235 int partNum;
236 uint32_t low, high;
237 ostringstream prompt;
238
239 if (GetPartRange(&low, &high) > 0) {
240 prompt << "Partition number (" << low + 1 << "-" << high + 1 << "): ";
241 partNum = GetNumber(low + 1, high + 1, low, prompt.str());
242 GPTData::DeletePartition(partNum - 1);
243 } else {
244 cout << "No partitions\n";
245 } // if/else
246} // GPTDataTextUI::DeletePartition()
247
248// Prompt user for a partition number, then change its type code
249// using ChangeGPTType(struct GPTPartition*) function.
250void GPTDataTextUI::ChangePartType(void) {
251 int partNum;
252 uint32_t low, high;
srs569455d92612010-03-07 22:16:07 -0500253
srs5694fad06422010-02-19 17:19:17 -0500254 if (GetPartRange(&low, &high) > 0) {
255 partNum = GetPartNum();
256 partitions[partNum].ChangeType();
257 } else {
258 cout << "No partitions\n";
259 } // if/else
260} // GPTDataTextUI::ChangePartType()
261
262// Partition attributes seem to be rarely used, but I want a way to
263// adjust them for completeness....
264void GPTDataTextUI::SetAttributes(uint32_t partNum) {
265 Attributes theAttr;
srs569455d92612010-03-07 22:16:07 -0500266
srs5694fad06422010-02-19 17:19:17 -0500267 theAttr.SetAttributes(partitions[partNum].GetAttributes());
268 theAttr.DisplayAttributes();
269 theAttr.ChangeAttributes();
270 partitions[partNum].SetAttributes(theAttr.GetAttributes());
271} // GPTDataTextUI::SetAttributes()
272
273// Ask user for two partition numbers and swap them in the table. Note that
274// this just reorders table entries; it doesn't adjust partition layout on
275// the disk.
276// Returns 1 if successful, 0 if not. (If user enters identical numbers, it
277// counts as successful.)
278int GPTDataTextUI::SwapPartitions(void) {
279 int partNum1, partNum2, didIt = 0;
280 uint32_t low, high;
281 ostringstream prompt;
282 GPTPart temp;
283
284 if (GetPartRange(&low, &high) > 0) {
285 partNum1 = GetPartNum();
286 if (high >= mainHeader.numParts - 1)
287 high = 0;
288 prompt << "New partition number (1-" << mainHeader.numParts
srs569455d92612010-03-07 22:16:07 -0500289 << ", default " << high + 2 << "): ";
srs5694fad06422010-02-19 17:19:17 -0500290 partNum2 = GetNumber(1, mainHeader.numParts, high + 2, prompt.str()) - 1;
291 didIt = GPTData::SwapPartitions(partNum1, partNum2);
292 } else {
293 cout << "No partitions\n";
294 } // if/else
295 return didIt;
296} // GPTDataTextUI::SwapPartitionNumbers()
297
298// This function destroys the on-disk GPT structures. Returns 1 if the user
299// confirms destruction, 0 if the user aborts or if there's a disk error.
300int GPTDataTextUI::DestroyGPTwPrompt(void) {
301 int allOK = 1;
302
303 if ((apmFound) || (bsdFound)) {
304 cout << "WARNING: APM or BSD disklabel structures detected! This operation could\n"
305 << "damage any APM or BSD partitions on this disk!\n";
306 } // if APM or BSD
307 cout << "\a\aAbout to wipe out GPT on " << device << ". Proceed? ";
308 if (GetYN() == 'Y') {
309 if (DestroyGPT()) {
310 // Note on below: Touch the MBR only if the user wants it completely
311 // blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
312 // the MBR, but this could wipe out a valid MBR that the program
313 // had subsequently discarded (say, if it conflicted with older GPT
314 // structures).
315 cout << "Blank out MBR? ";
316 if (GetYN() == 'Y') {
317 DestroyMBR();
318 } else {
319 cout << "MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
320 << "with fdisk or another tool.\n";
321 } // if/else
322 } else allOK = 0; // if GPT structures destroyed
323 } else allOK = 0; // if user confirms destruction
324 return (allOK);
325} // GPTDataTextUI::DestroyGPTwPrompt()
326
327// Get partition number from user and then call ShowPartDetails(partNum)
328// to show its detailed information
329void GPTDataTextUI::ShowDetails(void) {
330 int partNum;
331 uint32_t low, high;
srs569455d92612010-03-07 22:16:07 -0500332
srs5694fad06422010-02-19 17:19:17 -0500333 if (GetPartRange(&low, &high) > 0) {
334 partNum = GetPartNum();
335 ShowPartDetails(partNum);
336 } else {
337 cout << "No partitions\n";
338 } // if/else
339} // GPTDataTextUI::ShowDetails()
340
341// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
342// OSes that don't understand GPT.
343void GPTDataTextUI::MakeHybrid(void) {
344 uint32_t partNums[3];
345 char line[255];
346 char* junk;
srs569455d92612010-03-07 22:16:07 -0500347 int numParts, i, j, mbrNum, bootable = 0;
348 unsigned int hexCode = 0;
349 struct PartInfo *newNote;
350 PartNotes notes;
srs5694fad06422010-02-19 17:19:17 -0500351 char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
352
353 cout << "\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n"
354 << "to use one, just hit the Enter key at the below prompt and your MBR\n"
355 << "partition table will be untouched.\n\n\a";
356
357 // Now get the numbers of up to three partitions to add to the
358 // hybrid MBR....
359 cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n"
360 << "added to the hybrid MBR, in sequence: ";
361 junk = fgets(line, 255, stdin);
362 numParts = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
363
364 if (numParts > 0) {
365 cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? ";
366 eeFirst = GetYN();
367 } // if
368
srs5694fad06422010-02-19 17:19:17 -0500369 for (i = 0; i < numParts; i++) {
srs569455d92612010-03-07 22:16:07 -0500370 newNote = new struct PartInfo;
371 j = newNote->gptPartNum = partNums[i] - 1;
srs5694fad06422010-02-19 17:19:17 -0500372 mbrNum = i + (eeFirst == 'Y');
373 cout << "\nCreating entry for GPT partition #" << j + 1
374 << " (MBR partition #" << mbrNum + 1 << ")\n";
srs569455d92612010-03-07 22:16:07 -0500375 newNote->hexCode = GetMBRTypeCode(partitions[j].GetHexType() / 256);
376 newNote->firstLBA = partitions[j].GetFirstLBA();
377 newNote->lastLBA = partitions[j].GetLastLBA();
378 newNote->type = PRIMARY;
srs5694fad06422010-02-19 17:19:17 -0500379 cout << "Set the bootable flag? ";
380 if (GetYN() == 'Y')
srs569455d92612010-03-07 22:16:07 -0500381 newNote->active = 1;
382 else
383 newNote->active = 0;
384 notes.AddToEnd(newNote);
srs5694fad06422010-02-19 17:19:17 -0500385 } // for
386
387 if (numParts > 0) { // User opted to create a hybrid MBR....
388 // Create EFI protective partition that covers the start of the disk.
389 // If this location (covering the main GPT data structures) is omitted,
390 // Linux won't find any partitions on the disk.
srs569455d92612010-03-07 22:16:07 -0500391 newNote = new struct PartInfo;
392 newNote->gptPartNum = MBR_EFI_GPT;
393 newNote->active = 0;
394 newNote->hexCode = 0xEE;
395 newNote->type = PRIMARY;
396 // newNote firstLBA and lastLBA are computed later...
397 if (eeFirst == 'Y') {
398 notes.AddToStart(newNote);
399 } else {
400 notes.AddToEnd(newNote);
401 } // else
srs5694fad06422010-02-19 17:19:17 -0500402 protectiveMBR.SetHybrid();
403
404 // ... and for good measure, if there are any partition spaces left,
405 // optionally create another protective EFI partition to cover as much
406 // space as possible....
srs569455d92612010-03-07 22:16:07 -0500407 if (notes.GetNumPrimary() < 4) { // unused entry....
408 cout << "\nUnused partition space(s) found. Use one to protect more partitions? ";
409 if (GetYN() == 'Y') {
410 while ((hexCode <= 0) || (hexCode > 255)) {
411 cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): ";
412 // Comment on above: Mac OS treats disks with more than one
413 // 0xEE MBR partition as MBR disks, not as GPT disks.
414 junk = fgets(line, 255, stdin);
415 sscanf(line, "%x", &hexCode);
416 if (line[0] == '\n')
417 hexCode = 0x00;
418 } // while
419 newNote = new struct PartInfo;
420 newNote->gptPartNum = MBR_EFI_GPT;
421 newNote->active = 0;
422 newNote->hexCode = hexCode;
423 newNote->type = PRIMARY;
424 // newNote firstLBA and lastLBA are computed later...
425 notes.AddToEnd(newNote);
426 } // if (GetYN() == 'Y')
427 } // if unused entry
428 PartsToMBR(notes);
srs5694fad06422010-02-19 17:19:17 -0500429 if (bootable > 0)
430 protectiveMBR.SetPartBootable(bootable);
431 } // if (numParts > 0)
432} // GPTDataTextUI::MakeHybrid()
433
srs569455d92612010-03-07 22:16:07 -0500434// Assign GPT partitions to primary or logical status for conversion. The
435// function first presents a suggested layout with as many logicals as
436// possible, but gives the user the option to override this suggestion.
437// Returns the number of partitions assigned (0 if problems or if the
438// user aborts)
439int GPTDataTextUI::AssignPrimaryOrLogical(PartNotes & notes) {
440 int i, partNum, allOK = 1, changesWanted = 1, countedParts, numPrimary = 0, numLogical = 0;
441 int newNumParts; // size of GPT table
442
443 // Sort and resize the GPT table. Resized to clear the sector before the
444 // first available sector, if possible, so as to enable turning the
445 // first partition into a logical, should that be desirable/necessary.
446 SortGPT();
447 countedParts = newNumParts = CountParts();
448 i = blockSize / GPT_SIZE;
449 if ((newNumParts % i) != 0) {
450 newNumParts = ((newNumParts / i) + 1) * i;
451 } // if
452 SetGPTSize(newNumParts);
453
454 // Takes notes on existing partitions: Create an initial assignment as
455 // primary or logical, set default MBR types, and then make it legal
456 // (drop partitions as required to fit in the MBR and as logicals).
457 allOK = (notes.PassPartitions(partitions, this, mainHeader.numParts, blockSize) ==
458 (int) mainHeader.numParts);
459 for (i = 0; i < countedParts; i++)
460 notes.SetMbrHexType(i, partitions[i].GetHexType() / 255);
461 notes.MakeItLegal();
462
463 while (allOK && changesWanted) {
464 notes.ShowSummary();
465 cout << "\n";
466 partNum = GetNumber(-1, countedParts, -2,
467 "Type partition to change, 0 to accept, -1 to abort: ");
468 switch (partNum) {
469 case -1:
470 allOK = 0;
471 break;
472 case 0:
473 changesWanted = 0;
474 break;
475 default:
476 allOK = notes.MakeChange(partNum - 1);
477 break;
478 } // switch
479 } // while
480
481 i = 0;
482 if (allOK)
483 for (i = 0; i < countedParts; i++) {
484 switch (notes.GetType(i)) {
485 case PRIMARY:
486 numPrimary++;
487 break;
488 case LOGICAL:
489 numLogical++;
490 break;
491 } // switch
492 if (notes.GetActiveStatus(i))
493 protectiveMBR.SetPartBootable(i);
494 } // for
495
496 if (numPrimary > 4) {
497 cerr << "Warning! More than four primary partitions in "
498 << "GPTDataTextUI::AssignPrimaryOrLogical()!\n";
499 allOK = 0;
500 } // if
501 return (allOK * (numPrimary + numLogical));
502} // GPTDataTextUI::AssignPrimaryOrLogical()
503
504// Convert the GPT to MBR form, storing partitions in the protectiveMBR
505// variable. This function is necessarily limited; it may not be able to
506// convert all partitions, depending on the disk size and available space
507// before each partition (one free sector is required to create a logical
508// partition, which are necessary to convert more than four partitions).
509// Returns the number of converted partitions; if this value
srs5694fad06422010-02-19 17:19:17 -0500510// is over 0, the calling function should call DestroyGPT() to destroy
srs569455d92612010-03-07 22:16:07 -0500511// the GPT data, call SaveMBR() to save the MBR, and then exit.
srs5694fad06422010-02-19 17:19:17 -0500512int GPTDataTextUI::XFormToMBR(void) {
srs569455d92612010-03-07 22:16:07 -0500513 int numParts, numToConvert, numReallyConverted = 0;
514 int origNumParts;
515 PartNotes notes;
516 GPTPart *tempGptParts;
517 uint32_t i;
srs5694fad06422010-02-19 17:19:17 -0500518
srs569455d92612010-03-07 22:16:07 -0500519 // Back up partition array, since we'll be sorting it and we want to
520 // be able to restore it in case the user aborts....
521 origNumParts = mainHeader.numParts;
522 tempGptParts = new GPTPart[mainHeader.numParts];
523 for (i = 0; i < mainHeader.numParts; i++)
524 tempGptParts[i] = partitions[i];
525
srs5694fad06422010-02-19 17:19:17 -0500526 numParts = CountParts();
srs5694fad06422010-02-19 17:19:17 -0500527
srs569455d92612010-03-07 22:16:07 -0500528 numToConvert = AssignPrimaryOrLogical(notes);
srs5694fad06422010-02-19 17:19:17 -0500529
srs569455d92612010-03-07 22:16:07 -0500530 if (numToConvert > 0) {
531 numReallyConverted = PartsToMBR(notes);
532 if (numReallyConverted != numToConvert) {
533 cerr << "Error converting partitions to MBR; tried to convert "
534 << numToConvert << " partitions,\nbut converted " << numReallyConverted
535 << ". Aborting operation!\n";
536 numReallyConverted = 0;
537 protectiveMBR.MakeProtectiveMBR();
538 } // if/else
539 } // if
srs5694fad06422010-02-19 17:19:17 -0500540
srs569455d92612010-03-07 22:16:07 -0500541 // A problem or the user aborted; restore backup of unsorted and
542 // original-sized partition table and delete the sorted and
543 // resized one; otherwise free the backup table's memory....
544 if (numReallyConverted == 0) {
545 delete[] partitions;
546 partitions = tempGptParts;
547 SetGPTSize(origNumParts);
srs5694fad06422010-02-19 17:19:17 -0500548 } else {
srs569455d92612010-03-07 22:16:07 -0500549 delete[] tempGptParts;
550 } // if
551 return numReallyConverted;
srs5694fad06422010-02-19 17:19:17 -0500552} // GPTDataTextUI::XFormToMBR()
553
554/*********************************************************************
555 * *
556 * The following doesn't really belong in the class, since it's MBR- *
557 * specific, but it's also user I/O-related, so I want to keep it in *
558 * this file.... *
559 * *
560 *********************************************************************/
561
562// Get an MBR type code from the user and return it
563int GetMBRTypeCode(int defType) {
564 char line[255];
565 char* junk;
566 int typeCode;
567
568 cout.setf(ios::uppercase);
569 cout.fill('0');
570 do {
571 cout << "Enter an MBR hex code (default " << hex;
572 cout.width(2);
573 cout << defType << "): " << dec;
574 junk = fgets(line, 255, stdin);
575 if (line[0] == '\n')
576 typeCode = defType;
577 else
578 sscanf(line, "%x", &typeCode);
579 } while ((typeCode <= 0) || (typeCode > 255));
580 cout.fill(' ');
581 return typeCode;
srs56941c6f8b02010-02-21 11:09:20 -0500582} // GetMBRTypeCode