blob: 3000308e345468c4dda103f5f18b6f16f4459535 [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";
srs56940283dae2010-04-28 16:44:34 -0400100 answer = GetNumber(1, 2, 1, " 1 - Use current GPT\n 2 - Create blank GPT\n\nYour answer: ");
srs5694fad06422010-02-19 17:19:17 -0500101 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
srs56940283dae2010-04-28 16:44:34 -0400163 cout << "Current partition table size is " << numParts << ".\n";
srs5694fad06422010-02-19 17:19:17 -0500164 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) &&
srs56940283dae2010-04-28 16:44:34 -0400193 (firstFreePart < 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 {
srs56940283dae2010-04-28 16:44:34 -0400199 prompt1 << "Partition number (" << firstFreePart + 1 << "-" << numParts
srs569455d92612010-03-07 22:16:07 -0500200 << ", default " << firstFreePart + 1 << "): ";
srs56940283dae2010-04-28 16:44:34 -0400201 partNum = GetNumber(firstFreePart + 1, numParts,
srs569455d92612010-03-07 22:16:07 -0500202 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();
srs56940283dae2010-04-28 16:44:34 -0400286 if (high >= numParts - 1)
srs5694fad06422010-02-19 17:19:17 -0500287 high = 0;
srs56940283dae2010-04-28 16:44:34 -0400288 prompt << "New partition number (1-" << numParts
srs569455d92612010-03-07 22:16:07 -0500289 << ", default " << high + 2 << "): ";
srs56940283dae2010-04-28 16:44:34 -0400290 partNum2 = GetNumber(1, numParts, high + 2, prompt.str()) - 1;
srs5694fad06422010-02-19 17:19:17 -0500291 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;
srs56940283dae2010-04-28 16:44:34 -0400347 int numPartsToCvt, i, j, mbrNum, bootable = 0;
srs569455d92612010-03-07 22:16:07 -0500348 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);
srs56940283dae2010-04-28 16:44:34 -0400362 numPartsToCvt = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
srs5694fad06422010-02-19 17:19:17 -0500363
srs56940283dae2010-04-28 16:44:34 -0400364 if (numPartsToCvt > 0) {
srs5694fad06422010-02-19 17:19:17 -0500365 cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? ";
366 eeFirst = GetYN();
367 } // if
368
srs56940283dae2010-04-28 16:44:34 -0400369 for (i = 0; i < numPartsToCvt; 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
srs56940283dae2010-04-28 16:44:34 -0400387 if (numPartsToCvt > 0) { // User opted to create a hybrid MBR....
srs5694fad06422010-02-19 17:19:17 -0500388 // 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);
srs56940283dae2010-04-28 16:44:34 -0400431 } // if (numPartsToCvt > 0)
srs5694fad06422010-02-19 17:19:17 -0500432} // 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).
srs56940283dae2010-04-28 16:44:34 -0400457 allOK = (notes.PassPartitions(partitions, this, numParts, blockSize) == (int) numParts);
srs569455d92612010-03-07 22:16:07 -0500458 for (i = 0; i < countedParts; i++)
459 notes.SetMbrHexType(i, partitions[i].GetHexType() / 255);
460 notes.MakeItLegal();
461
462 while (allOK && changesWanted) {
463 notes.ShowSummary();
464 cout << "\n";
465 partNum = GetNumber(-1, countedParts, -2,
466 "Type partition to change, 0 to accept, -1 to abort: ");
467 switch (partNum) {
468 case -1:
469 allOK = 0;
470 break;
471 case 0:
472 changesWanted = 0;
473 break;
474 default:
475 allOK = notes.MakeChange(partNum - 1);
476 break;
477 } // switch
478 } // while
479
480 i = 0;
481 if (allOK)
482 for (i = 0; i < countedParts; i++) {
483 switch (notes.GetType(i)) {
484 case PRIMARY:
485 numPrimary++;
486 break;
487 case LOGICAL:
488 numLogical++;
489 break;
490 } // switch
491 if (notes.GetActiveStatus(i))
492 protectiveMBR.SetPartBootable(i);
493 } // for
494
495 if (numPrimary > 4) {
496 cerr << "Warning! More than four primary partitions in "
497 << "GPTDataTextUI::AssignPrimaryOrLogical()!\n";
498 allOK = 0;
499 } // if
500 return (allOK * (numPrimary + numLogical));
501} // GPTDataTextUI::AssignPrimaryOrLogical()
502
503// Convert the GPT to MBR form, storing partitions in the protectiveMBR
504// variable. This function is necessarily limited; it may not be able to
505// convert all partitions, depending on the disk size and available space
506// before each partition (one free sector is required to create a logical
507// partition, which are necessary to convert more than four partitions).
508// Returns the number of converted partitions; if this value
srs5694fad06422010-02-19 17:19:17 -0500509// is over 0, the calling function should call DestroyGPT() to destroy
srs569455d92612010-03-07 22:16:07 -0500510// the GPT data, call SaveMBR() to save the MBR, and then exit.
srs5694fad06422010-02-19 17:19:17 -0500511int GPTDataTextUI::XFormToMBR(void) {
srs56940283dae2010-04-28 16:44:34 -0400512 int numToConvert, numReallyConverted = 0;
srs569455d92612010-03-07 22:16:07 -0500513 int origNumParts;
514 PartNotes notes;
515 GPTPart *tempGptParts;
516 uint32_t i;
srs5694fad06422010-02-19 17:19:17 -0500517
srs569455d92612010-03-07 22:16:07 -0500518 // Back up partition array, since we'll be sorting it and we want to
519 // be able to restore it in case the user aborts....
srs56940283dae2010-04-28 16:44:34 -0400520 origNumParts = numParts;
521 tempGptParts = new GPTPart[numParts];
522 for (i = 0; i < numParts; i++)
srs569455d92612010-03-07 22:16:07 -0500523 tempGptParts[i] = partitions[i];
524
srs569455d92612010-03-07 22:16:07 -0500525 numToConvert = AssignPrimaryOrLogical(notes);
srs5694fad06422010-02-19 17:19:17 -0500526
srs569455d92612010-03-07 22:16:07 -0500527 if (numToConvert > 0) {
528 numReallyConverted = PartsToMBR(notes);
529 if (numReallyConverted != numToConvert) {
530 cerr << "Error converting partitions to MBR; tried to convert "
531 << numToConvert << " partitions,\nbut converted " << numReallyConverted
532 << ". Aborting operation!\n";
533 numReallyConverted = 0;
534 protectiveMBR.MakeProtectiveMBR();
535 } // if/else
536 } // if
srs5694fad06422010-02-19 17:19:17 -0500537
srs569455d92612010-03-07 22:16:07 -0500538 // A problem or the user aborted; restore backup of unsorted and
539 // original-sized partition table and delete the sorted and
540 // resized one; otherwise free the backup table's memory....
541 if (numReallyConverted == 0) {
542 delete[] partitions;
543 partitions = tempGptParts;
544 SetGPTSize(origNumParts);
srs5694fad06422010-02-19 17:19:17 -0500545 } else {
srs569455d92612010-03-07 22:16:07 -0500546 delete[] tempGptParts;
547 } // if
548 return numReallyConverted;
srs5694fad06422010-02-19 17:19:17 -0500549} // GPTDataTextUI::XFormToMBR()
550
551/*********************************************************************
552 * *
553 * The following doesn't really belong in the class, since it's MBR- *
554 * specific, but it's also user I/O-related, so I want to keep it in *
555 * this file.... *
556 * *
557 *********************************************************************/
558
559// Get an MBR type code from the user and return it
560int GetMBRTypeCode(int defType) {
561 char line[255];
562 char* junk;
563 int typeCode;
564
565 cout.setf(ios::uppercase);
566 cout.fill('0');
567 do {
568 cout << "Enter an MBR hex code (default " << hex;
569 cout.width(2);
570 cout << defType << "): " << dec;
571 junk = fgets(line, 255, stdin);
572 if (line[0] == '\n')
573 typeCode = defType;
574 else
575 sscanf(line, "%x", &typeCode);
576 } while ((typeCode <= 0) || (typeCode > 255));
577 cout.fill(' ');
578 return typeCode;
srs56941c6f8b02010-02-21 11:09:20 -0500579} // GetMBRTypeCode