1cf200d32Sopenharmony_ci/* basicmbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
2cf200d32Sopenharmony_ci   data. */
3cf200d32Sopenharmony_ci
4cf200d32Sopenharmony_ci/* Initial coding by Rod Smith, January to February, 2009 */
5cf200d32Sopenharmony_ci
6cf200d32Sopenharmony_ci/* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed
7cf200d32Sopenharmony_ci  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
8cf200d32Sopenharmony_ci
9cf200d32Sopenharmony_ci#define __STDC_LIMIT_MACROS
10cf200d32Sopenharmony_ci#ifndef __STDC_CONSTANT_MACROS
11cf200d32Sopenharmony_ci#define __STDC_CONSTANT_MACROS
12cf200d32Sopenharmony_ci#endif
13cf200d32Sopenharmony_ci
14cf200d32Sopenharmony_ci#include <stdio.h>
15cf200d32Sopenharmony_ci#include <stdlib.h>
16cf200d32Sopenharmony_ci#include <stdint.h>
17cf200d32Sopenharmony_ci#include <fcntl.h>
18cf200d32Sopenharmony_ci#include <string.h>
19cf200d32Sopenharmony_ci#include <time.h>
20cf200d32Sopenharmony_ci#include <sys/stat.h>
21cf200d32Sopenharmony_ci#include <errno.h>
22cf200d32Sopenharmony_ci#include <iostream>
23cf200d32Sopenharmony_ci#include <algorithm>
24cf200d32Sopenharmony_ci#include "mbr.h"
25cf200d32Sopenharmony_ci#include "support.h"
26cf200d32Sopenharmony_ci
27cf200d32Sopenharmony_ciusing namespace std;
28cf200d32Sopenharmony_ci
29cf200d32Sopenharmony_ci/****************************************
30cf200d32Sopenharmony_ci *                                      *
31cf200d32Sopenharmony_ci * MBRData class and related structures *
32cf200d32Sopenharmony_ci *                                      *
33cf200d32Sopenharmony_ci ****************************************/
34cf200d32Sopenharmony_ci
35cf200d32Sopenharmony_ciBasicMBRData::BasicMBRData(void) {
36cf200d32Sopenharmony_ci   blockSize = SECTOR_SIZE;
37cf200d32Sopenharmony_ci   diskSize = 0;
38cf200d32Sopenharmony_ci   device = "";
39cf200d32Sopenharmony_ci   state = invalid;
40cf200d32Sopenharmony_ci   numHeads = MAX_HEADS;
41cf200d32Sopenharmony_ci   numSecspTrack = MAX_SECSPERTRACK;
42cf200d32Sopenharmony_ci   myDisk = NULL;
43cf200d32Sopenharmony_ci   canDeleteMyDisk = 0;
44cf200d32Sopenharmony_ci//   memset(&EbrLocations, 0, MAX_MBR_PARTS * sizeof(uint32_t));
45cf200d32Sopenharmony_ci   EmptyMBR();
46cf200d32Sopenharmony_ci} // BasicMBRData default constructor
47cf200d32Sopenharmony_ci
48cf200d32Sopenharmony_ciBasicMBRData::BasicMBRData(const BasicMBRData & orig) {
49cf200d32Sopenharmony_ci   int i;
50cf200d32Sopenharmony_ci
51cf200d32Sopenharmony_ci   if (&orig != this) {
52cf200d32Sopenharmony_ci      memcpy(code, orig.code, 440);
53cf200d32Sopenharmony_ci      diskSignature = orig.diskSignature;
54cf200d32Sopenharmony_ci      nulls = orig.nulls;
55cf200d32Sopenharmony_ci      MBRSignature = orig.MBRSignature;
56cf200d32Sopenharmony_ci      blockSize = orig.blockSize;
57cf200d32Sopenharmony_ci      diskSize = orig.diskSize;
58cf200d32Sopenharmony_ci      numHeads = orig.numHeads;
59cf200d32Sopenharmony_ci      numSecspTrack = orig.numSecspTrack;
60cf200d32Sopenharmony_ci      canDeleteMyDisk = orig.canDeleteMyDisk;
61cf200d32Sopenharmony_ci      device = orig.device;
62cf200d32Sopenharmony_ci      state = orig.state;
63cf200d32Sopenharmony_ci
64cf200d32Sopenharmony_ci      myDisk = new DiskIO;
65cf200d32Sopenharmony_ci      if (myDisk == NULL) {
66cf200d32Sopenharmony_ci         cerr << "Unable to allocate memory in BasicMBRData copy constructor! Terminating!\n";
67cf200d32Sopenharmony_ci         exit(1);
68cf200d32Sopenharmony_ci      } // if
69cf200d32Sopenharmony_ci      if (orig.myDisk != NULL)
70cf200d32Sopenharmony_ci         myDisk->OpenForRead(orig.myDisk->GetName());
71cf200d32Sopenharmony_ci
72cf200d32Sopenharmony_ci      for (i = 0; i < MAX_MBR_PARTS; i++) {
73cf200d32Sopenharmony_ci         partitions[i] = orig.partitions[i];
74cf200d32Sopenharmony_ci      } // for
75cf200d32Sopenharmony_ci   } // if
76cf200d32Sopenharmony_ci} // BasicMBRData copy constructor
77cf200d32Sopenharmony_ci
78cf200d32Sopenharmony_ciBasicMBRData::BasicMBRData(string filename) {
79cf200d32Sopenharmony_ci   blockSize = SECTOR_SIZE;
80cf200d32Sopenharmony_ci   diskSize = 0;
81cf200d32Sopenharmony_ci   device = filename;
82cf200d32Sopenharmony_ci   state = invalid;
83cf200d32Sopenharmony_ci   numHeads = MAX_HEADS;
84cf200d32Sopenharmony_ci   numSecspTrack = MAX_SECSPERTRACK;
85cf200d32Sopenharmony_ci   myDisk = NULL;
86cf200d32Sopenharmony_ci   canDeleteMyDisk = 0;
87cf200d32Sopenharmony_ci//   memset(&EbrLocations, 0, MAX_MBR_PARTS * sizeof(uint32_t));
88cf200d32Sopenharmony_ci
89cf200d32Sopenharmony_ci   // Try to read the specified partition table, but if it fails....
90cf200d32Sopenharmony_ci   if (!ReadMBRData(filename)) {
91cf200d32Sopenharmony_ci      EmptyMBR();
92cf200d32Sopenharmony_ci      device = "";
93cf200d32Sopenharmony_ci   } // if
94cf200d32Sopenharmony_ci} // BasicMBRData(string filename) constructor
95cf200d32Sopenharmony_ci
96cf200d32Sopenharmony_ci// Free space used by myDisk only if that's OK -- sometimes it will be
97cf200d32Sopenharmony_ci// copied from an outside source, in which case that source should handle
98cf200d32Sopenharmony_ci// it!
99cf200d32Sopenharmony_ciBasicMBRData::~BasicMBRData(void) {
100cf200d32Sopenharmony_ci   if (canDeleteMyDisk)
101cf200d32Sopenharmony_ci      delete myDisk;
102cf200d32Sopenharmony_ci} // BasicMBRData destructor
103cf200d32Sopenharmony_ci
104cf200d32Sopenharmony_ci// Assignment operator -- copy entire set of MBR data.
105cf200d32Sopenharmony_ciBasicMBRData & BasicMBRData::operator=(const BasicMBRData & orig) {
106cf200d32Sopenharmony_ci   int i;
107cf200d32Sopenharmony_ci
108cf200d32Sopenharmony_ci   if (&orig != this) {
109cf200d32Sopenharmony_ci      memcpy(code, orig.code, 440);
110cf200d32Sopenharmony_ci      diskSignature = orig.diskSignature;
111cf200d32Sopenharmony_ci      nulls = orig.nulls;
112cf200d32Sopenharmony_ci      MBRSignature = orig.MBRSignature;
113cf200d32Sopenharmony_ci      blockSize = orig.blockSize;
114cf200d32Sopenharmony_ci      diskSize = orig.diskSize;
115cf200d32Sopenharmony_ci      numHeads = orig.numHeads;
116cf200d32Sopenharmony_ci      numSecspTrack = orig.numSecspTrack;
117cf200d32Sopenharmony_ci      canDeleteMyDisk = orig.canDeleteMyDisk;
118cf200d32Sopenharmony_ci      device = orig.device;
119cf200d32Sopenharmony_ci      state = orig.state;
120cf200d32Sopenharmony_ci
121cf200d32Sopenharmony_ci      myDisk = new DiskIO;
122cf200d32Sopenharmony_ci      if (myDisk == NULL) {
123cf200d32Sopenharmony_ci         cerr << "Unable to allocate memory in BasicMBRData::operator=()! Terminating!\n";
124cf200d32Sopenharmony_ci         exit(1);
125cf200d32Sopenharmony_ci      } // if
126cf200d32Sopenharmony_ci      if (orig.myDisk != NULL)
127cf200d32Sopenharmony_ci         myDisk->OpenForRead(orig.myDisk->GetName());
128cf200d32Sopenharmony_ci
129cf200d32Sopenharmony_ci      for (i = 0; i < MAX_MBR_PARTS; i++) {
130cf200d32Sopenharmony_ci         partitions[i] = orig.partitions[i];
131cf200d32Sopenharmony_ci      } // for
132cf200d32Sopenharmony_ci   } // if
133cf200d32Sopenharmony_ci   return *this;
134cf200d32Sopenharmony_ci} // BasicMBRData::operator=()
135cf200d32Sopenharmony_ci
136cf200d32Sopenharmony_ci/**********************
137cf200d32Sopenharmony_ci *                    *
138cf200d32Sopenharmony_ci * Disk I/O functions *
139cf200d32Sopenharmony_ci *                    *
140cf200d32Sopenharmony_ci **********************/
141cf200d32Sopenharmony_ci
142cf200d32Sopenharmony_ci// Read data from MBR. Returns 1 if read was successful (even if the
143cf200d32Sopenharmony_ci// data isn't a valid MBR), 0 if the read failed.
144cf200d32Sopenharmony_ciint BasicMBRData::ReadMBRData(const string & deviceFilename) {
145cf200d32Sopenharmony_ci   int allOK;
146cf200d32Sopenharmony_ci
147cf200d32Sopenharmony_ci   if (myDisk == NULL) {
148cf200d32Sopenharmony_ci      myDisk = new DiskIO;
149cf200d32Sopenharmony_ci      if (myDisk == NULL) {
150cf200d32Sopenharmony_ci         cerr << "Unable to allocate memory in BasicMBRData::ReadMBRData()! Terminating!\n";
151cf200d32Sopenharmony_ci         exit(1);
152cf200d32Sopenharmony_ci      } // if
153cf200d32Sopenharmony_ci      canDeleteMyDisk = 1;
154cf200d32Sopenharmony_ci   } // if
155cf200d32Sopenharmony_ci   if (myDisk->OpenForRead(deviceFilename)) {
156cf200d32Sopenharmony_ci      allOK = ReadMBRData(myDisk);
157cf200d32Sopenharmony_ci   } else {
158cf200d32Sopenharmony_ci      allOK = 0;
159cf200d32Sopenharmony_ci   } // if
160cf200d32Sopenharmony_ci
161cf200d32Sopenharmony_ci   if (allOK)
162cf200d32Sopenharmony_ci      device = deviceFilename;
163cf200d32Sopenharmony_ci
164cf200d32Sopenharmony_ci   return allOK;
165cf200d32Sopenharmony_ci} // BasicMBRData::ReadMBRData(const string & deviceFilename)
166cf200d32Sopenharmony_ci
167cf200d32Sopenharmony_ci// Read data from MBR. If checkBlockSize == 1 (the default), the block
168cf200d32Sopenharmony_ci// size is checked; otherwise it's set to the default (512 bytes).
169cf200d32Sopenharmony_ci// Note that any extended partition(s) present will be omitted from
170cf200d32Sopenharmony_ci// in the partitions[] array; these partitions must be re-created when
171cf200d32Sopenharmony_ci// the partition table is saved in MBR format.
172cf200d32Sopenharmony_ciint BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
173cf200d32Sopenharmony_ci   int allOK = 1, i, logicalNum = 3;
174cf200d32Sopenharmony_ci   int err = 1;
175cf200d32Sopenharmony_ci   TempMBR tempMBR;
176cf200d32Sopenharmony_ci
177cf200d32Sopenharmony_ci   if ((myDisk != NULL) && (myDisk != theDisk) && (canDeleteMyDisk)) {
178cf200d32Sopenharmony_ci      delete myDisk;
179cf200d32Sopenharmony_ci      canDeleteMyDisk = 0;
180cf200d32Sopenharmony_ci   } // if
181cf200d32Sopenharmony_ci
182cf200d32Sopenharmony_ci   myDisk = theDisk;
183cf200d32Sopenharmony_ci
184cf200d32Sopenharmony_ci   // Empty existing MBR data, including the logical partitions...
185cf200d32Sopenharmony_ci   EmptyMBR(0);
186cf200d32Sopenharmony_ci
187cf200d32Sopenharmony_ci   if (myDisk->Seek(0))
188cf200d32Sopenharmony_ci     if (myDisk->Read(&tempMBR, 512))
189cf200d32Sopenharmony_ci        err = 0;
190cf200d32Sopenharmony_ci   if (err) {
191cf200d32Sopenharmony_ci      cerr << "Problem reading disk in BasicMBRData::ReadMBRData()!\n";
192cf200d32Sopenharmony_ci   } else {
193cf200d32Sopenharmony_ci      for (i = 0; i < 440; i++)
194cf200d32Sopenharmony_ci         code[i] = tempMBR.code[i];
195cf200d32Sopenharmony_ci      diskSignature = tempMBR.diskSignature;
196cf200d32Sopenharmony_ci      nulls = tempMBR.nulls;
197cf200d32Sopenharmony_ci      for (i = 0; i < 4; i++) {
198cf200d32Sopenharmony_ci         partitions[i] = tempMBR.partitions[i];
199cf200d32Sopenharmony_ci         if (partitions[i].GetLengthLBA() > 0)
200cf200d32Sopenharmony_ci            partitions[i].SetInclusion(PRIMARY);
201cf200d32Sopenharmony_ci      } // for i... (reading all four partitions)
202cf200d32Sopenharmony_ci      MBRSignature = tempMBR.MBRSignature;
203cf200d32Sopenharmony_ci      ReadCHSGeom();
204cf200d32Sopenharmony_ci
205cf200d32Sopenharmony_ci      // Reverse the byte order, if necessary
206cf200d32Sopenharmony_ci      if (IsLittleEndian() == 0) {
207cf200d32Sopenharmony_ci         ReverseBytes(&diskSignature, 4);
208cf200d32Sopenharmony_ci         ReverseBytes(&nulls, 2);
209cf200d32Sopenharmony_ci         ReverseBytes(&MBRSignature, 2);
210cf200d32Sopenharmony_ci         for (i = 0; i < 4; i++) {
211cf200d32Sopenharmony_ci            partitions[i].ReverseByteOrder();
212cf200d32Sopenharmony_ci         } // for
213cf200d32Sopenharmony_ci      } // if
214cf200d32Sopenharmony_ci
215cf200d32Sopenharmony_ci      if (MBRSignature != MBR_SIGNATURE) {
216cf200d32Sopenharmony_ci         allOK = 0;
217cf200d32Sopenharmony_ci         state = invalid;
218cf200d32Sopenharmony_ci      } // if
219cf200d32Sopenharmony_ci
220cf200d32Sopenharmony_ci      // Find disk size
221cf200d32Sopenharmony_ci      diskSize = myDisk->DiskSize(&err);
222cf200d32Sopenharmony_ci
223cf200d32Sopenharmony_ci      // Find block size
224cf200d32Sopenharmony_ci      if (checkBlockSize) {
225cf200d32Sopenharmony_ci         blockSize = myDisk->GetBlockSize();
226cf200d32Sopenharmony_ci      } // if (checkBlockSize)
227cf200d32Sopenharmony_ci
228cf200d32Sopenharmony_ci      // Load logical partition data, if any is found....
229cf200d32Sopenharmony_ci      if (allOK) {
230cf200d32Sopenharmony_ci         for (i = 0; i < 4; i++) {
231cf200d32Sopenharmony_ci            if ((partitions[i].GetType() == 0x05) || (partitions[i].GetType() == 0x0f)
232cf200d32Sopenharmony_ci                || (partitions[i].GetType() == 0x85)) {
233cf200d32Sopenharmony_ci               // Found it, so call a function to load everything from them....
234cf200d32Sopenharmony_ci               logicalNum = ReadLogicalParts(partitions[i].GetStartLBA(), abs(logicalNum) + 1);
235cf200d32Sopenharmony_ci               if (logicalNum < 0) {
236cf200d32Sopenharmony_ci                  cerr << "Error reading logical partitions! List may be truncated!\n";
237cf200d32Sopenharmony_ci               } // if maxLogicals valid
238cf200d32Sopenharmony_ci               DeletePartition(i);
239cf200d32Sopenharmony_ci            } // if primary partition is extended
240cf200d32Sopenharmony_ci         } // for primary partition loop
241cf200d32Sopenharmony_ci         if (allOK) { // Loaded logicals OK
242cf200d32Sopenharmony_ci            state = mbr;
243cf200d32Sopenharmony_ci         } else {
244cf200d32Sopenharmony_ci            state = invalid;
245cf200d32Sopenharmony_ci         } // if
246cf200d32Sopenharmony_ci      } // if
247cf200d32Sopenharmony_ci
248cf200d32Sopenharmony_ci      // Check to see if it's in GPT format....
249cf200d32Sopenharmony_ci      if (allOK) {
250cf200d32Sopenharmony_ci         for (i = 0; i < 4; i++) {
251cf200d32Sopenharmony_ci            if (partitions[i].GetType() == UINT8_C(0xEE)) {
252cf200d32Sopenharmony_ci               state = gpt;
253cf200d32Sopenharmony_ci            } // if
254cf200d32Sopenharmony_ci         } // for
255cf200d32Sopenharmony_ci      } // if
256cf200d32Sopenharmony_ci
257cf200d32Sopenharmony_ci      // If there's an EFI GPT partition, look for other partition types,
258cf200d32Sopenharmony_ci      // to flag as hybrid
259cf200d32Sopenharmony_ci      if (state == gpt) {
260cf200d32Sopenharmony_ci         for (i = 0 ; i < 4; i++) {
261cf200d32Sopenharmony_ci            if ((partitions[i].GetType() != UINT8_C(0xEE)) &&
262cf200d32Sopenharmony_ci                (partitions[i].GetType() != UINT8_C(0x00)))
263cf200d32Sopenharmony_ci               state = hybrid;
264cf200d32Sopenharmony_ci            if (logicalNum != 3)
265cf200d32Sopenharmony_ci               cerr << "Warning! MBR Logical partitions found on a hybrid MBR disk! This is an\n"
266cf200d32Sopenharmony_ci                    << "EXTREMELY dangerous configuration!\n\a";
267cf200d32Sopenharmony_ci         } // for
268cf200d32Sopenharmony_ci      } // if (hybrid detection code)
269cf200d32Sopenharmony_ci   } // no initial error
270cf200d32Sopenharmony_ci   return allOK;
271cf200d32Sopenharmony_ci} // BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize)
272cf200d32Sopenharmony_ci
273cf200d32Sopenharmony_ci// This is a function to read all the logical partitions, following the
274cf200d32Sopenharmony_ci// logical partition linked list from the disk and storing the basic data in the
275cf200d32Sopenharmony_ci// partitions[] array. Returns last index to partitions[] used, or -1 times the
276cf200d32Sopenharmony_ci// that index if there was a problem. (Some problems can leave valid logical
277cf200d32Sopenharmony_ci// partition data.)
278cf200d32Sopenharmony_ci// Parameters:
279cf200d32Sopenharmony_ci// extendedStart = LBA of the start of the extended partition
280cf200d32Sopenharmony_ci// partNum = number of first partition in extended partition (normally 4).
281cf200d32Sopenharmony_ciint BasicMBRData::ReadLogicalParts(uint64_t extendedStart, int partNum) {
282cf200d32Sopenharmony_ci   struct TempMBR ebr;
283cf200d32Sopenharmony_ci   int i, another = 1, allOK = 1;
284cf200d32Sopenharmony_ci   uint8_t ebrType;
285cf200d32Sopenharmony_ci   uint64_t offset;
286cf200d32Sopenharmony_ci   uint64_t EbrLocations[MAX_MBR_PARTS];
287cf200d32Sopenharmony_ci
288cf200d32Sopenharmony_ci   offset = extendedStart;
289cf200d32Sopenharmony_ci   memset(&EbrLocations, 0, MAX_MBR_PARTS * sizeof(uint64_t));
290cf200d32Sopenharmony_ci   while (another && (partNum < MAX_MBR_PARTS) && (partNum >= 0) && (allOK > 0)) {
291cf200d32Sopenharmony_ci      for (i = 0; i < MAX_MBR_PARTS; i++) {
292cf200d32Sopenharmony_ci         if (EbrLocations[i] == offset) { // already read this one; infinite logical partition loop!
293cf200d32Sopenharmony_ci            cerr << "Logical partition infinite loop detected! This is being corrected.\n";
294cf200d32Sopenharmony_ci            allOK = -1;
295cf200d32Sopenharmony_ci            if (partNum > 0) //don't go negative
296cf200d32Sopenharmony_ci               partNum -= 1;
297cf200d32Sopenharmony_ci         } // if
298cf200d32Sopenharmony_ci      } // for
299cf200d32Sopenharmony_ci      EbrLocations[partNum] = offset;
300cf200d32Sopenharmony_ci      if (myDisk->Seek(offset) == 0) { // seek to EBR record
301cf200d32Sopenharmony_ci         cerr << "Unable to seek to " << offset << "! Aborting!\n";
302cf200d32Sopenharmony_ci         allOK = -1;
303cf200d32Sopenharmony_ci      }
304cf200d32Sopenharmony_ci      if (myDisk->Read(&ebr, 512) != 512) { // Load the data....
305cf200d32Sopenharmony_ci         cerr << "Error seeking to or reading logical partition data from " << offset
306cf200d32Sopenharmony_ci              << "!\nSome logical partitions may be missing!\n";
307cf200d32Sopenharmony_ci         allOK = -1;
308cf200d32Sopenharmony_ci      } else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
309cf200d32Sopenharmony_ci         ReverseBytes(&ebr.MBRSignature, 2);
310cf200d32Sopenharmony_ci         ReverseBytes(&ebr.partitions[0].firstLBA, 4);
311cf200d32Sopenharmony_ci         ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
312cf200d32Sopenharmony_ci         ReverseBytes(&ebr.partitions[1].firstLBA, 4);
313cf200d32Sopenharmony_ci         ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
314cf200d32Sopenharmony_ci      } // if/else/if
315cf200d32Sopenharmony_ci
316cf200d32Sopenharmony_ci      if (ebr.MBRSignature != MBR_SIGNATURE) {
317cf200d32Sopenharmony_ci         allOK = -1;
318cf200d32Sopenharmony_ci         cerr << "EBR signature for logical partition invalid; read 0x";
319cf200d32Sopenharmony_ci         cerr.fill('0');
320cf200d32Sopenharmony_ci         cerr.width(4);
321cf200d32Sopenharmony_ci         cerr.setf(ios::uppercase);
322cf200d32Sopenharmony_ci         cerr << hex << ebr.MBRSignature << ", but should be 0x";
323cf200d32Sopenharmony_ci         cerr.width(4);
324cf200d32Sopenharmony_ci         cerr << MBR_SIGNATURE << dec << "\n";
325cf200d32Sopenharmony_ci         cerr.fill(' ');
326cf200d32Sopenharmony_ci      } // if
327cf200d32Sopenharmony_ci
328cf200d32Sopenharmony_ci      if ((partNum >= 0) && (partNum < MAX_MBR_PARTS) && (allOK > 0)) {
329cf200d32Sopenharmony_ci         // Sometimes an EBR points directly to another EBR, rather than defining
330cf200d32Sopenharmony_ci         // a logical partition and then pointing to another EBR. Thus, we skip
331cf200d32Sopenharmony_ci         // the logical partition when this is the case....
332cf200d32Sopenharmony_ci         ebrType = ebr.partitions[0].partitionType;
333cf200d32Sopenharmony_ci         if ((ebrType == 0x05) || (ebrType == 0x0f) || (ebrType == 0x85)) {
334cf200d32Sopenharmony_ci            cout << "EBR points to an EBR!\n";
335cf200d32Sopenharmony_ci            offset = extendedStart + ebr.partitions[0].firstLBA;
336cf200d32Sopenharmony_ci         } else {
337cf200d32Sopenharmony_ci            // Copy over the basic data....
338cf200d32Sopenharmony_ci            partitions[partNum] = ebr.partitions[0];
339cf200d32Sopenharmony_ci            // Adjust the start LBA, since it's encoded strangely....
340cf200d32Sopenharmony_ci            partitions[partNum].SetStartLBA(ebr.partitions[0].firstLBA + offset);
341cf200d32Sopenharmony_ci            partitions[partNum].SetInclusion(LOGICAL);
342cf200d32Sopenharmony_ci
343cf200d32Sopenharmony_ci            // Find the next partition (if there is one)
344cf200d32Sopenharmony_ci            if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum < (MAX_MBR_PARTS - 1))) {
345cf200d32Sopenharmony_ci               offset = extendedStart + ebr.partitions[1].firstLBA;
346cf200d32Sopenharmony_ci               partNum++;
347cf200d32Sopenharmony_ci            } else {
348cf200d32Sopenharmony_ci               another = 0;
349cf200d32Sopenharmony_ci            } // if another partition
350cf200d32Sopenharmony_ci         } // if/else
351cf200d32Sopenharmony_ci      } // if
352cf200d32Sopenharmony_ci   } // while()
353cf200d32Sopenharmony_ci   return (partNum * allOK);
354cf200d32Sopenharmony_ci} // BasicMBRData::ReadLogicalPart()
355cf200d32Sopenharmony_ci
356cf200d32Sopenharmony_ci// Write the MBR data to the default defined device. This writes both the
357cf200d32Sopenharmony_ci// MBR itself and any defined logical partitions, provided there's an
358cf200d32Sopenharmony_ci// MBR extended partition.
359cf200d32Sopenharmony_ciint BasicMBRData::WriteMBRData(void) {
360cf200d32Sopenharmony_ci   int allOK;
361cf200d32Sopenharmony_ci
362cf200d32Sopenharmony_ci   if (myDisk != NULL) {
363cf200d32Sopenharmony_ci      if (myDisk->OpenForWrite() != 0) {
364cf200d32Sopenharmony_ci         allOK = WriteMBRData(myDisk);
365cf200d32Sopenharmony_ci         cout << "Done writing data!\n";
366cf200d32Sopenharmony_ci      } else {
367cf200d32Sopenharmony_ci         allOK = 0;
368cf200d32Sopenharmony_ci      } // if/else
369cf200d32Sopenharmony_ci      myDisk->Close();
370cf200d32Sopenharmony_ci   } else allOK = 0;
371cf200d32Sopenharmony_ci   return allOK;
372cf200d32Sopenharmony_ci} // BasicMBRData::WriteMBRData(void)
373cf200d32Sopenharmony_ci
374cf200d32Sopenharmony_ci// Save the MBR data to a file. This writes both the
375cf200d32Sopenharmony_ci// MBR itself and any defined logical partitions.
376cf200d32Sopenharmony_ciint BasicMBRData::WriteMBRData(DiskIO *theDisk) {
377cf200d32Sopenharmony_ci   int i, j, partNum, next, allOK, moreLogicals = 0;
378cf200d32Sopenharmony_ci   uint64_t extFirstLBA = 0;
379cf200d32Sopenharmony_ci   uint64_t writeEbrTo; // 64-bit because we support extended in 2-4TiB range
380cf200d32Sopenharmony_ci   TempMBR tempMBR;
381cf200d32Sopenharmony_ci
382cf200d32Sopenharmony_ci   allOK = CreateExtended();
383cf200d32Sopenharmony_ci   if (allOK) {
384cf200d32Sopenharmony_ci      // First write the main MBR data structure....
385cf200d32Sopenharmony_ci      memcpy(tempMBR.code, code, 440);
386cf200d32Sopenharmony_ci      tempMBR.diskSignature = diskSignature;
387cf200d32Sopenharmony_ci      tempMBR.nulls = nulls;
388cf200d32Sopenharmony_ci      tempMBR.MBRSignature = MBRSignature;
389cf200d32Sopenharmony_ci      for (i = 0; i < 4; i++) {
390cf200d32Sopenharmony_ci         partitions[i].StoreInStruct(&tempMBR.partitions[i]);
391cf200d32Sopenharmony_ci         if (partitions[i].GetType() == 0x0f) {
392cf200d32Sopenharmony_ci            extFirstLBA = partitions[i].GetStartLBA();
393cf200d32Sopenharmony_ci            moreLogicals = 1;
394cf200d32Sopenharmony_ci         } // if
395cf200d32Sopenharmony_ci      } // for i...
396cf200d32Sopenharmony_ci   } // if
397cf200d32Sopenharmony_ci   allOK = allOK && WriteMBRData(tempMBR, theDisk, 0);
398cf200d32Sopenharmony_ci
399cf200d32Sopenharmony_ci   // Set up tempMBR with some constant data for logical partitions...
400cf200d32Sopenharmony_ci   tempMBR.diskSignature = 0;
401cf200d32Sopenharmony_ci   for (i = 2; i < 4; i++) {
402cf200d32Sopenharmony_ci      tempMBR.partitions[i].firstLBA = tempMBR.partitions[i].lengthLBA = 0;
403cf200d32Sopenharmony_ci      tempMBR.partitions[i].partitionType = 0x00;
404cf200d32Sopenharmony_ci      for (j = 0; j < 3; j++) {
405cf200d32Sopenharmony_ci         tempMBR.partitions[i].firstSector[j] = 0;
406cf200d32Sopenharmony_ci         tempMBR.partitions[i].lastSector[j] = 0;
407cf200d32Sopenharmony_ci      } // for j
408cf200d32Sopenharmony_ci   } // for i
409cf200d32Sopenharmony_ci
410cf200d32Sopenharmony_ci   partNum = FindNextInUse(4);
411cf200d32Sopenharmony_ci   writeEbrTo = (uint64_t) extFirstLBA;
412cf200d32Sopenharmony_ci   // Write logicals...
413cf200d32Sopenharmony_ci   while (allOK && moreLogicals && (partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
414cf200d32Sopenharmony_ci      partitions[partNum].StoreInStruct(&tempMBR.partitions[0]);
415cf200d32Sopenharmony_ci      tempMBR.partitions[0].firstLBA = 1;
416cf200d32Sopenharmony_ci      // tempMBR.partitions[1] points to next EBR or terminates EBR linked list...
417cf200d32Sopenharmony_ci      next = FindNextInUse(partNum + 1);
418cf200d32Sopenharmony_ci      if ((next < MAX_MBR_PARTS) && (next > 0) && (partitions[next].GetStartLBA() > 0)) {
419cf200d32Sopenharmony_ci         tempMBR.partitions[1].partitionType = 0x0f;
420cf200d32Sopenharmony_ci         tempMBR.partitions[1].firstLBA = (uint32_t) (partitions[next].GetStartLBA() - extFirstLBA - 1);
421cf200d32Sopenharmony_ci         tempMBR.partitions[1].lengthLBA = (uint32_t) (partitions[next].GetLengthLBA() + 1);
422cf200d32Sopenharmony_ci         LBAtoCHS((uint64_t) tempMBR.partitions[1].firstLBA,
423cf200d32Sopenharmony_ci                  (uint8_t *) &tempMBR.partitions[1].firstSector);
424cf200d32Sopenharmony_ci         LBAtoCHS(tempMBR.partitions[1].lengthLBA - extFirstLBA,
425cf200d32Sopenharmony_ci                  (uint8_t *) &tempMBR.partitions[1].lastSector);
426cf200d32Sopenharmony_ci      } else {
427cf200d32Sopenharmony_ci         tempMBR.partitions[1].partitionType = 0x00;
428cf200d32Sopenharmony_ci         tempMBR.partitions[1].firstLBA = 0;
429cf200d32Sopenharmony_ci         tempMBR.partitions[1].lengthLBA = 0;
430cf200d32Sopenharmony_ci         moreLogicals = 0;
431cf200d32Sopenharmony_ci      } // if/else
432cf200d32Sopenharmony_ci      allOK = WriteMBRData(tempMBR, theDisk, writeEbrTo);
433cf200d32Sopenharmony_ci      writeEbrTo = (uint64_t) tempMBR.partitions[1].firstLBA + (uint64_t) extFirstLBA;
434cf200d32Sopenharmony_ci      partNum = next;
435cf200d32Sopenharmony_ci   } // while
436cf200d32Sopenharmony_ci   DeleteExtendedParts();
437cf200d32Sopenharmony_ci   return allOK;
438cf200d32Sopenharmony_ci} // BasicMBRData::WriteMBRData(DiskIO *theDisk)
439cf200d32Sopenharmony_ci
440cf200d32Sopenharmony_ciint BasicMBRData::WriteMBRData(const string & deviceFilename) {
441cf200d32Sopenharmony_ci   device = deviceFilename;
442cf200d32Sopenharmony_ci   return WriteMBRData();
443cf200d32Sopenharmony_ci} // BasicMBRData::WriteMBRData(const string & deviceFilename)
444cf200d32Sopenharmony_ci
445cf200d32Sopenharmony_ci// Write a single MBR record to the specified sector. Used by the like-named
446cf200d32Sopenharmony_ci// function to write both the MBR and multiple EBR (for logical partition)
447cf200d32Sopenharmony_ci// records.
448cf200d32Sopenharmony_ci// Returns 1 on success, 0 on failure
449cf200d32Sopenharmony_ciint BasicMBRData::WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t sector) {
450cf200d32Sopenharmony_ci   int i, allOK;
451cf200d32Sopenharmony_ci
452cf200d32Sopenharmony_ci   // Reverse the byte order, if necessary
453cf200d32Sopenharmony_ci   if (IsLittleEndian() == 0) {
454cf200d32Sopenharmony_ci      ReverseBytes(&mbr.diskSignature, 4);
455cf200d32Sopenharmony_ci      ReverseBytes(&mbr.nulls, 2);
456cf200d32Sopenharmony_ci      ReverseBytes(&mbr.MBRSignature, 2);
457cf200d32Sopenharmony_ci      for (i = 0; i < 4; i++) {
458cf200d32Sopenharmony_ci         ReverseBytes(&mbr.partitions[i].firstLBA, 4);
459cf200d32Sopenharmony_ci         ReverseBytes(&mbr.partitions[i].lengthLBA, 4);
460cf200d32Sopenharmony_ci      } // for
461cf200d32Sopenharmony_ci   } // if
462cf200d32Sopenharmony_ci
463cf200d32Sopenharmony_ci   // Now write the data structure...
464cf200d32Sopenharmony_ci   allOK = theDisk->OpenForWrite();
465cf200d32Sopenharmony_ci   if (allOK && theDisk->Seek(sector)) {
466cf200d32Sopenharmony_ci      if (theDisk->Write(&mbr, 512) != 512) {
467cf200d32Sopenharmony_ci         allOK = 0;
468cf200d32Sopenharmony_ci         cerr << "Error " << errno << " when saving MBR!\n";
469cf200d32Sopenharmony_ci      } // if
470cf200d32Sopenharmony_ci   } else {
471cf200d32Sopenharmony_ci      allOK = 0;
472cf200d32Sopenharmony_ci      cerr << "Error " << errno << " when seeking to MBR to write it!\n";
473cf200d32Sopenharmony_ci   } // if/else
474cf200d32Sopenharmony_ci   theDisk->Close();
475cf200d32Sopenharmony_ci
476cf200d32Sopenharmony_ci   // Reverse the byte order back, if necessary
477cf200d32Sopenharmony_ci   if (IsLittleEndian() == 0) {
478cf200d32Sopenharmony_ci      ReverseBytes(&mbr.diskSignature, 4);
479cf200d32Sopenharmony_ci      ReverseBytes(&mbr.nulls, 2);
480cf200d32Sopenharmony_ci      ReverseBytes(&mbr.MBRSignature, 2);
481cf200d32Sopenharmony_ci      for (i = 0; i < 4; i++) {
482cf200d32Sopenharmony_ci         ReverseBytes(&mbr.partitions[i].firstLBA, 4);
483cf200d32Sopenharmony_ci         ReverseBytes(&mbr.partitions[i].lengthLBA, 4);
484cf200d32Sopenharmony_ci      } // for
485cf200d32Sopenharmony_ci   }// if
486cf200d32Sopenharmony_ci   return allOK;
487cf200d32Sopenharmony_ci} // BasicMBRData::WriteMBRData(uint64_t sector)
488cf200d32Sopenharmony_ci
489cf200d32Sopenharmony_ci// Set a new disk device; used in copying one disk's partition
490cf200d32Sopenharmony_ci// table to another disk.
491cf200d32Sopenharmony_civoid BasicMBRData::SetDisk(DiskIO *theDisk) {
492cf200d32Sopenharmony_ci   int err;
493cf200d32Sopenharmony_ci
494cf200d32Sopenharmony_ci   myDisk = theDisk;
495cf200d32Sopenharmony_ci   diskSize = theDisk->DiskSize(&err);
496cf200d32Sopenharmony_ci   canDeleteMyDisk = 0;
497cf200d32Sopenharmony_ci   ReadCHSGeom();
498cf200d32Sopenharmony_ci} // BasicMBRData::SetDisk()
499cf200d32Sopenharmony_ci
500cf200d32Sopenharmony_ci/********************************************
501cf200d32Sopenharmony_ci *                                          *
502cf200d32Sopenharmony_ci * Functions that display data for the user *
503cf200d32Sopenharmony_ci *                                          *
504cf200d32Sopenharmony_ci ********************************************/
505cf200d32Sopenharmony_ci
506cf200d32Sopenharmony_ci// Show the MBR data to the user, up to the specified maximum number
507cf200d32Sopenharmony_ci// of partitions....
508cf200d32Sopenharmony_civoid BasicMBRData::DisplayMBRData(void) {
509cf200d32Sopenharmony_ci   int i;
510cf200d32Sopenharmony_ci
511cf200d32Sopenharmony_ci   cout << "\nDisk size is " << diskSize << " sectors ("
512cf200d32Sopenharmony_ci        << BytesToIeee(diskSize, blockSize) << ")\n";
513cf200d32Sopenharmony_ci   cout << "MBR disk identifier: 0x";
514cf200d32Sopenharmony_ci   cout.width(8);
515cf200d32Sopenharmony_ci   cout.fill('0');
516cf200d32Sopenharmony_ci   cout.setf(ios::uppercase);
517cf200d32Sopenharmony_ci   cout << hex << diskSignature << dec << "\n";
518cf200d32Sopenharmony_ci   cout << "MBR partitions:\n\n";
519cf200d32Sopenharmony_ci   if ((state == gpt) || (state == hybrid)) {
520cf200d32Sopenharmony_ci      cout << "Number  Boot  Start Sector   End Sector   Status      Code\n";
521cf200d32Sopenharmony_ci   } else {
522cf200d32Sopenharmony_ci      cout << "                                                   Can Be   Can Be\n";
523cf200d32Sopenharmony_ci      cout << "Number  Boot  Start Sector   End Sector   Status   Logical  Primary   Code\n";
524cf200d32Sopenharmony_ci      UpdateCanBeLogical();
525cf200d32Sopenharmony_ci   } //
526cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
527cf200d32Sopenharmony_ci      if (partitions[i].GetLengthLBA() != 0) {
528cf200d32Sopenharmony_ci         cout.fill(' ');
529cf200d32Sopenharmony_ci         cout.width(4);
530cf200d32Sopenharmony_ci         cout << i + 1 << "      ";
531cf200d32Sopenharmony_ci         partitions[i].ShowData((state == gpt) || (state == hybrid));
532cf200d32Sopenharmony_ci      } // if
533cf200d32Sopenharmony_ci      cout.fill(' ');
534cf200d32Sopenharmony_ci   } // for
535cf200d32Sopenharmony_ci} // BasicMBRData::DisplayMBRData()
536cf200d32Sopenharmony_ci
537cf200d32Sopenharmony_ci// Displays the state, as a word, on stdout. Used for debugging & to
538cf200d32Sopenharmony_ci// tell the user about the MBR state when the program launches....
539cf200d32Sopenharmony_civoid BasicMBRData::ShowState(void) {
540cf200d32Sopenharmony_ci   switch (state) {
541cf200d32Sopenharmony_ci      case invalid:
542cf200d32Sopenharmony_ci         cout << "  MBR: not present\n";
543cf200d32Sopenharmony_ci         break;
544cf200d32Sopenharmony_ci      case gpt:
545cf200d32Sopenharmony_ci         cout << "  MBR: protective\n";
546cf200d32Sopenharmony_ci         break;
547cf200d32Sopenharmony_ci      case hybrid:
548cf200d32Sopenharmony_ci         cout << "  MBR: hybrid\n";
549cf200d32Sopenharmony_ci         break;
550cf200d32Sopenharmony_ci      case mbr:
551cf200d32Sopenharmony_ci         cout << "  MBR: MBR only\n";
552cf200d32Sopenharmony_ci         break;
553cf200d32Sopenharmony_ci      default:
554cf200d32Sopenharmony_ci         cout << "\a  MBR: unknown -- bug!\n";
555cf200d32Sopenharmony_ci         break;
556cf200d32Sopenharmony_ci   } // switch
557cf200d32Sopenharmony_ci} // BasicMBRData::ShowState()
558cf200d32Sopenharmony_ci
559cf200d32Sopenharmony_ci/************************
560cf200d32Sopenharmony_ci *                      *
561cf200d32Sopenharmony_ci * GPT Checks and fixes *
562cf200d32Sopenharmony_ci *                      *
563cf200d32Sopenharmony_ci ************************/
564cf200d32Sopenharmony_ci
565cf200d32Sopenharmony_ci// Perform a very rudimentary check for GPT data on the disk; searches for
566cf200d32Sopenharmony_ci// the GPT signature in the main and backup metadata areas.
567cf200d32Sopenharmony_ci// Returns 0 if GPT data not found, 1 if main data only is found, 2 if
568cf200d32Sopenharmony_ci// backup only is found, 3 if both main and backup data are found, and
569cf200d32Sopenharmony_ci// -1 if a disk error occurred.
570cf200d32Sopenharmony_ciint BasicMBRData::CheckForGPT(void) {
571cf200d32Sopenharmony_ci   int retval = 0, err;
572cf200d32Sopenharmony_ci   char signature1[9], signature2[9];
573cf200d32Sopenharmony_ci
574cf200d32Sopenharmony_ci   if (myDisk != NULL) {
575cf200d32Sopenharmony_ci      if (myDisk->OpenForRead() != 0) {
576cf200d32Sopenharmony_ci         if (myDisk->Seek(1)) {
577cf200d32Sopenharmony_ci            myDisk->Read(signature1, 8);
578cf200d32Sopenharmony_ci            signature1[8] = '\0';
579cf200d32Sopenharmony_ci         } else retval = -1;
580cf200d32Sopenharmony_ci         if (myDisk->Seek(myDisk->DiskSize(&err) - 1)) {
581cf200d32Sopenharmony_ci            myDisk->Read(signature2, 8);
582cf200d32Sopenharmony_ci            signature2[8] = '\0';
583cf200d32Sopenharmony_ci         } else retval = -1;
584cf200d32Sopenharmony_ci         if ((retval >= 0) && (strcmp(signature1, "EFI PART") == 0))
585cf200d32Sopenharmony_ci            retval += 1;
586cf200d32Sopenharmony_ci         if ((retval >= 0) && (strcmp(signature2, "EFI PART") == 0))
587cf200d32Sopenharmony_ci            retval += 2;
588cf200d32Sopenharmony_ci      } else {
589cf200d32Sopenharmony_ci         retval = -1;
590cf200d32Sopenharmony_ci      } // if/else
591cf200d32Sopenharmony_ci      myDisk->Close();
592cf200d32Sopenharmony_ci   } else retval = -1;
593cf200d32Sopenharmony_ci   return retval;
594cf200d32Sopenharmony_ci} // BasicMBRData::CheckForGPT()
595cf200d32Sopenharmony_ci
596cf200d32Sopenharmony_ci// Blanks the 2nd (sector #1, numbered from 0) and last sectors of the disk,
597cf200d32Sopenharmony_ci// but only if GPT data are verified on the disk, and only for the sector(s)
598cf200d32Sopenharmony_ci// with GPT signatures.
599cf200d32Sopenharmony_ci// Returns 1 if operation completes successfully, 0 if not (returns 1 if
600cf200d32Sopenharmony_ci// no GPT data are found on the disk).
601cf200d32Sopenharmony_ciint BasicMBRData::BlankGPTData(void) {
602cf200d32Sopenharmony_ci   int allOK = 1, err;
603cf200d32Sopenharmony_ci   uint8_t blank[512];
604cf200d32Sopenharmony_ci
605cf200d32Sopenharmony_ci   memset(blank, 0, 512);
606cf200d32Sopenharmony_ci   switch (CheckForGPT()) {
607cf200d32Sopenharmony_ci      case -1:
608cf200d32Sopenharmony_ci         allOK = 0;
609cf200d32Sopenharmony_ci         break;
610cf200d32Sopenharmony_ci      case 0:
611cf200d32Sopenharmony_ci         break;
612cf200d32Sopenharmony_ci      case 1:
613cf200d32Sopenharmony_ci         if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
614cf200d32Sopenharmony_ci            if (!((myDisk->Seek(1)) && (myDisk->Write(blank, 512) == 512)))
615cf200d32Sopenharmony_ci               allOK = 0;
616cf200d32Sopenharmony_ci            myDisk->Close();
617cf200d32Sopenharmony_ci         } else allOK = 0;
618cf200d32Sopenharmony_ci         break;
619cf200d32Sopenharmony_ci      case 2:
620cf200d32Sopenharmony_ci         if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
621cf200d32Sopenharmony_ci            if (!((myDisk->Seek(myDisk->DiskSize(&err) - 1)) &&
622cf200d32Sopenharmony_ci               (myDisk->Write(blank, 512) == 512)))
623cf200d32Sopenharmony_ci               allOK = 0;
624cf200d32Sopenharmony_ci            myDisk->Close();
625cf200d32Sopenharmony_ci         } else allOK = 0;
626cf200d32Sopenharmony_ci         break;
627cf200d32Sopenharmony_ci      case 3:
628cf200d32Sopenharmony_ci         if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
629cf200d32Sopenharmony_ci            if (!((myDisk->Seek(1)) && (myDisk->Write(blank, 512) == 512)))
630cf200d32Sopenharmony_ci               allOK = 0;
631cf200d32Sopenharmony_ci            if (!((myDisk->Seek(myDisk->DiskSize(&err) - 1)) &&
632cf200d32Sopenharmony_ci                (myDisk->Write(blank, 512) == 512)))
633cf200d32Sopenharmony_ci                allOK = 0;
634cf200d32Sopenharmony_ci            myDisk->Close();
635cf200d32Sopenharmony_ci         } else allOK = 0;
636cf200d32Sopenharmony_ci         break;
637cf200d32Sopenharmony_ci      default:
638cf200d32Sopenharmony_ci         break;
639cf200d32Sopenharmony_ci   } // switch()
640cf200d32Sopenharmony_ci   return allOK;
641cf200d32Sopenharmony_ci} // BasicMBRData::BlankGPTData
642cf200d32Sopenharmony_ci
643cf200d32Sopenharmony_ci/*********************************************************************
644cf200d32Sopenharmony_ci *                                                                   *
645cf200d32Sopenharmony_ci * Functions that set or get disk metadata (CHS geometry, disk size, *
646cf200d32Sopenharmony_ci * etc.)                                                             *
647cf200d32Sopenharmony_ci *                                                                   *
648cf200d32Sopenharmony_ci *********************************************************************/
649cf200d32Sopenharmony_ci
650cf200d32Sopenharmony_ci// Read the CHS geometry using OS calls, or if that fails, set to
651cf200d32Sopenharmony_ci// the most common value for big disks (255 heads, 63 sectors per
652cf200d32Sopenharmony_ci// track, & however many cylinders that computes to).
653cf200d32Sopenharmony_civoid BasicMBRData::ReadCHSGeom(void) {
654cf200d32Sopenharmony_ci   int err;
655cf200d32Sopenharmony_ci
656cf200d32Sopenharmony_ci   numHeads = myDisk->GetNumHeads();
657cf200d32Sopenharmony_ci   numSecspTrack = myDisk->GetNumSecsPerTrack();
658cf200d32Sopenharmony_ci   diskSize = myDisk->DiskSize(&err);
659cf200d32Sopenharmony_ci   blockSize = myDisk->GetBlockSize();
660cf200d32Sopenharmony_ci   partitions[0].SetGeometry(numHeads, numSecspTrack, diskSize, blockSize);
661cf200d32Sopenharmony_ci} // BasicMBRData::ReadCHSGeom()
662cf200d32Sopenharmony_ci
663cf200d32Sopenharmony_ci// Find the low and high used partition numbers (numbered from 0).
664cf200d32Sopenharmony_ci// Return value is the number of partitions found. Note that the
665cf200d32Sopenharmony_ci// *low and *high values are both set to 0 when no partitions
666cf200d32Sopenharmony_ci// are found, as well as when a single partition in the first
667cf200d32Sopenharmony_ci// position exists. Thus, the return value is the only way to
668cf200d32Sopenharmony_ci// tell when no partitions exist.
669cf200d32Sopenharmony_ciint BasicMBRData::GetPartRange(uint32_t *low, uint32_t *high) {
670cf200d32Sopenharmony_ci   uint32_t i;
671cf200d32Sopenharmony_ci   int numFound = 0;
672cf200d32Sopenharmony_ci
673cf200d32Sopenharmony_ci   *low = MAX_MBR_PARTS + 1; // code for "not found"
674cf200d32Sopenharmony_ci   *high = 0;
675cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
676cf200d32Sopenharmony_ci      if (partitions[i].GetStartLBA() != UINT32_C(0)) { // it exists
677cf200d32Sopenharmony_ci         *high = i; // since we're counting up, set the high value
678cf200d32Sopenharmony_ci         // Set the low value only if it's not yet found...
679cf200d32Sopenharmony_ci         if (*low == (MAX_MBR_PARTS + 1))
680cf200d32Sopenharmony_ci            *low = i;
681cf200d32Sopenharmony_ci         numFound++;
682cf200d32Sopenharmony_ci      } // if
683cf200d32Sopenharmony_ci   } // for
684cf200d32Sopenharmony_ci
685cf200d32Sopenharmony_ci   // Above will leave *low pointing to its "not found" value if no partitions
686cf200d32Sopenharmony_ci   // are defined, so reset to 0 if this is the case....
687cf200d32Sopenharmony_ci   if (*low == (MAX_MBR_PARTS + 1))
688cf200d32Sopenharmony_ci      *low = 0;
689cf200d32Sopenharmony_ci   return numFound;
690cf200d32Sopenharmony_ci} // GPTData::GetPartRange()
691cf200d32Sopenharmony_ci
692cf200d32Sopenharmony_ci// Converts 64-bit LBA value to MBR-style CHS value. Returns 1 if conversion
693cf200d32Sopenharmony_ci// was within the range that can be expressed by CHS (including 0, for an
694cf200d32Sopenharmony_ci// empty partition), 0 if the value is outside that range, and -1 if chs is
695cf200d32Sopenharmony_ci// invalid.
696cf200d32Sopenharmony_ciint BasicMBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
697cf200d32Sopenharmony_ci   uint64_t cylinder, head, sector; // all numbered from 0
698cf200d32Sopenharmony_ci   uint64_t remainder;
699cf200d32Sopenharmony_ci   int retval = 1;
700cf200d32Sopenharmony_ci   int done = 0;
701cf200d32Sopenharmony_ci
702cf200d32Sopenharmony_ci   if (chs != NULL) {
703cf200d32Sopenharmony_ci      // Special case: In case of 0 LBA value, zero out CHS values....
704cf200d32Sopenharmony_ci      if (lba == 0) {
705cf200d32Sopenharmony_ci         chs[0] = chs[1] = chs[2] = UINT8_C(0);
706cf200d32Sopenharmony_ci         done = 1;
707cf200d32Sopenharmony_ci      } // if
708cf200d32Sopenharmony_ci      // If LBA value is too large for CHS, max out CHS values....
709cf200d32Sopenharmony_ci      if ((!done) && (lba >= ((uint64_t) numHeads * numSecspTrack * MAX_CYLINDERS))) {
710cf200d32Sopenharmony_ci         chs[0] = 254;
711cf200d32Sopenharmony_ci         chs[1] = chs[2] = 255;
712cf200d32Sopenharmony_ci         done = 1;
713cf200d32Sopenharmony_ci         retval = 0;
714cf200d32Sopenharmony_ci      } // if
715cf200d32Sopenharmony_ci      // If neither of the above applies, compute CHS values....
716cf200d32Sopenharmony_ci      if (!done) {
717cf200d32Sopenharmony_ci         cylinder = lba / (uint64_t) (numHeads * numSecspTrack);
718cf200d32Sopenharmony_ci         remainder = lba - (cylinder * numHeads * numSecspTrack);
719cf200d32Sopenharmony_ci         head = remainder / numSecspTrack;
720cf200d32Sopenharmony_ci         remainder -= head * numSecspTrack;
721cf200d32Sopenharmony_ci         sector = remainder;
722cf200d32Sopenharmony_ci         if (head < numHeads)
723cf200d32Sopenharmony_ci            chs[0] = (uint8_t) head;
724cf200d32Sopenharmony_ci         else
725cf200d32Sopenharmony_ci            retval = 0;
726cf200d32Sopenharmony_ci         if (sector < numSecspTrack) {
727cf200d32Sopenharmony_ci            chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
728cf200d32Sopenharmony_ci            chs[2] = (uint8_t) (cylinder & UINT64_C(0xFF));
729cf200d32Sopenharmony_ci         } else {
730cf200d32Sopenharmony_ci            retval = 0;
731cf200d32Sopenharmony_ci         } // if/else
732cf200d32Sopenharmony_ci      } // if value is expressible and non-0
733cf200d32Sopenharmony_ci   } else { // Invalid (NULL) chs pointer
734cf200d32Sopenharmony_ci      retval = -1;
735cf200d32Sopenharmony_ci   } // if CHS pointer valid
736cf200d32Sopenharmony_ci   return (retval);
737cf200d32Sopenharmony_ci} // BasicMBRData::LBAtoCHS()
738cf200d32Sopenharmony_ci
739cf200d32Sopenharmony_ci// Look for overlapping partitions. Also looks for a couple of non-error
740cf200d32Sopenharmony_ci// conditions that the user should be told about.
741cf200d32Sopenharmony_ci// Returns the number of problems found
742cf200d32Sopenharmony_ciint BasicMBRData::FindOverlaps(void) {
743cf200d32Sopenharmony_ci   int i, j, numProbs = 0, numEE = 0, ProtectiveOnOne = 0;
744cf200d32Sopenharmony_ci
745cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
746cf200d32Sopenharmony_ci      for (j = i + 1; j < MAX_MBR_PARTS; j++) {
747cf200d32Sopenharmony_ci         if ((partitions[i].GetInclusion() != NONE) && (partitions[j].GetInclusion() != NONE) &&
748cf200d32Sopenharmony_ci             (partitions[i].DoTheyOverlap(partitions[j]))) {
749cf200d32Sopenharmony_ci            numProbs++;
750cf200d32Sopenharmony_ci            cout << "\nProblem: MBR partitions " << i + 1 << " and " << j + 1
751cf200d32Sopenharmony_ci                 << " overlap!\n";
752cf200d32Sopenharmony_ci         } // if
753cf200d32Sopenharmony_ci      } // for (j...)
754cf200d32Sopenharmony_ci      if (partitions[i].GetType() == 0xEE) {
755cf200d32Sopenharmony_ci         numEE++;
756cf200d32Sopenharmony_ci         if (partitions[i].GetStartLBA() == 1)
757cf200d32Sopenharmony_ci            ProtectiveOnOne = 1;
758cf200d32Sopenharmony_ci      } // if
759cf200d32Sopenharmony_ci   } // for (i...)
760cf200d32Sopenharmony_ci
761cf200d32Sopenharmony_ci   if (numEE > 1)
762cf200d32Sopenharmony_ci      cout << "\nCaution: More than one 0xEE MBR partition found. This can cause problems\n"
763cf200d32Sopenharmony_ci           << "in some OSes.\n";
764cf200d32Sopenharmony_ci   if (!ProtectiveOnOne && (numEE > 0))
765cf200d32Sopenharmony_ci      cout << "\nWarning: 0xEE partition doesn't start on sector 1. This can cause "
766cf200d32Sopenharmony_ci           << "problems\nin some OSes.\n";
767cf200d32Sopenharmony_ci
768cf200d32Sopenharmony_ci   return numProbs;
769cf200d32Sopenharmony_ci} // BasicMBRData::FindOverlaps()
770cf200d32Sopenharmony_ci
771cf200d32Sopenharmony_ci// Returns the number of primary partitions, including the extended partition
772cf200d32Sopenharmony_ci// required to hold any logical partitions found.
773cf200d32Sopenharmony_ciint BasicMBRData::NumPrimaries(void) {
774cf200d32Sopenharmony_ci   int i, numPrimaries = 0, logicalsFound = 0;
775cf200d32Sopenharmony_ci
776cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
777cf200d32Sopenharmony_ci      if (partitions[i].GetLengthLBA() > 0) {
778cf200d32Sopenharmony_ci         if (partitions[i].GetInclusion() == PRIMARY)
779cf200d32Sopenharmony_ci            numPrimaries++;
780cf200d32Sopenharmony_ci         if (partitions[i].GetInclusion() == LOGICAL)
781cf200d32Sopenharmony_ci            logicalsFound = 1;
782cf200d32Sopenharmony_ci      } // if
783cf200d32Sopenharmony_ci   } // for
784cf200d32Sopenharmony_ci   return (numPrimaries + logicalsFound);
785cf200d32Sopenharmony_ci} // BasicMBRData::NumPrimaries()
786cf200d32Sopenharmony_ci
787cf200d32Sopenharmony_ci// Returns the number of logical partitions.
788cf200d32Sopenharmony_ciint BasicMBRData::NumLogicals(void) {
789cf200d32Sopenharmony_ci   int i, numLogicals = 0;
790cf200d32Sopenharmony_ci
791cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
792cf200d32Sopenharmony_ci      if (partitions[i].GetInclusion() == LOGICAL)
793cf200d32Sopenharmony_ci         numLogicals++;
794cf200d32Sopenharmony_ci   } // for
795cf200d32Sopenharmony_ci   return numLogicals;
796cf200d32Sopenharmony_ci} // BasicMBRData::NumLogicals()
797cf200d32Sopenharmony_ci
798cf200d32Sopenharmony_ci// Returns the number of partitions (primaries plus logicals), NOT including
799cf200d32Sopenharmony_ci// the extended partition required to house the logicals.
800cf200d32Sopenharmony_ciint BasicMBRData::CountParts(void) {
801cf200d32Sopenharmony_ci   int i, num = 0;
802cf200d32Sopenharmony_ci
803cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
804cf200d32Sopenharmony_ci      if ((partitions[i].GetInclusion() == LOGICAL) ||
805cf200d32Sopenharmony_ci          (partitions[i].GetInclusion() == PRIMARY))
806cf200d32Sopenharmony_ci         num++;
807cf200d32Sopenharmony_ci   } // for
808cf200d32Sopenharmony_ci   return num;
809cf200d32Sopenharmony_ci} // BasicMBRData::CountParts()
810cf200d32Sopenharmony_ci
811cf200d32Sopenharmony_ci// Updates the canBeLogical and canBePrimary flags for all the partitions.
812cf200d32Sopenharmony_civoid BasicMBRData::UpdateCanBeLogical(void) {
813cf200d32Sopenharmony_ci   int i, j, sectorBefore, numPrimaries, numLogicals, usedAsEBR;
814cf200d32Sopenharmony_ci   uint64_t firstLogical, lastLogical, lStart, pStart;
815cf200d32Sopenharmony_ci
816cf200d32Sopenharmony_ci   numPrimaries = NumPrimaries();
817cf200d32Sopenharmony_ci   numLogicals = NumLogicals();
818cf200d32Sopenharmony_ci   firstLogical = FirstLogicalLBA() - 1;
819cf200d32Sopenharmony_ci   lastLogical = LastLogicalLBA();
820cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
821cf200d32Sopenharmony_ci      usedAsEBR = (SectorUsedAs(partitions[i].GetLastLBA()) == EBR);
822cf200d32Sopenharmony_ci      if (usedAsEBR) {
823cf200d32Sopenharmony_ci         partitions[i].SetCanBeLogical(0);
824cf200d32Sopenharmony_ci         partitions[i].SetCanBePrimary(0);
825cf200d32Sopenharmony_ci      } else if (partitions[i].GetLengthLBA() > 0) {
826cf200d32Sopenharmony_ci         // First determine if it can be logical....
827cf200d32Sopenharmony_ci         sectorBefore = SectorUsedAs(partitions[i].GetStartLBA() - 1);
828cf200d32Sopenharmony_ci         lStart = partitions[i].GetStartLBA(); // start of potential logical part.
829cf200d32Sopenharmony_ci         if ((lastLogical > 0) &&
830cf200d32Sopenharmony_ci             ((sectorBefore == EBR) || (sectorBefore == NONE))) {
831cf200d32Sopenharmony_ci            // Assume it can be logical, then search for primaries that make it
832cf200d32Sopenharmony_ci            // not work and, if found, flag appropriately.
833cf200d32Sopenharmony_ci            partitions[i].SetCanBeLogical(1);
834cf200d32Sopenharmony_ci            for (j = 0; j < MAX_MBR_PARTS; j++) {
835cf200d32Sopenharmony_ci               if ((i != j) && (partitions[j].GetInclusion() == PRIMARY)) {
836cf200d32Sopenharmony_ci                  pStart = partitions[j].GetStartLBA();
837cf200d32Sopenharmony_ci                  if (((pStart < lStart) && (firstLogical < pStart)) ||
838cf200d32Sopenharmony_ci                      ((pStart > lStart) && (firstLogical > pStart))) {
839cf200d32Sopenharmony_ci                     partitions[i].SetCanBeLogical(0);
840cf200d32Sopenharmony_ci                  } // if/else
841cf200d32Sopenharmony_ci               } // if
842cf200d32Sopenharmony_ci            } // for
843cf200d32Sopenharmony_ci         } else {
844cf200d32Sopenharmony_ci            if ((sectorBefore != EBR) && (sectorBefore != NONE))
845cf200d32Sopenharmony_ci               partitions[i].SetCanBeLogical(0);
846cf200d32Sopenharmony_ci            else
847cf200d32Sopenharmony_ci               partitions[i].SetCanBeLogical(lastLogical == 0); // can be logical only if no logicals already
848cf200d32Sopenharmony_ci         } // if/else
849cf200d32Sopenharmony_ci         // Now determine if it can be primary. Start by assuming it can be...
850cf200d32Sopenharmony_ci         partitions[i].SetCanBePrimary(1);
851cf200d32Sopenharmony_ci         if ((numPrimaries >= 4) && (partitions[i].GetInclusion() != PRIMARY)) {
852cf200d32Sopenharmony_ci            partitions[i].SetCanBePrimary(0);
853cf200d32Sopenharmony_ci            if ((partitions[i].GetInclusion() == LOGICAL) && (numLogicals == 1) &&
854cf200d32Sopenharmony_ci                (numPrimaries == 4))
855cf200d32Sopenharmony_ci               partitions[i].SetCanBePrimary(1);
856cf200d32Sopenharmony_ci         } // if
857cf200d32Sopenharmony_ci         if ((partitions[i].GetStartLBA() > (firstLogical + 1)) &&
858cf200d32Sopenharmony_ci             (partitions[i].GetLastLBA() < lastLogical))
859cf200d32Sopenharmony_ci            partitions[i].SetCanBePrimary(0);
860cf200d32Sopenharmony_ci      } // else if
861cf200d32Sopenharmony_ci   } // for
862cf200d32Sopenharmony_ci} // BasicMBRData::UpdateCanBeLogical()
863cf200d32Sopenharmony_ci
864cf200d32Sopenharmony_ci// Returns the first sector occupied by any logical partition. Note that
865cf200d32Sopenharmony_ci// this does NOT include the logical partition's EBR! Returns UINT32_MAX
866cf200d32Sopenharmony_ci// if there are no logical partitions defined.
867cf200d32Sopenharmony_ciuint64_t BasicMBRData::FirstLogicalLBA(void) {
868cf200d32Sopenharmony_ci   int i;
869cf200d32Sopenharmony_ci   uint64_t firstFound = UINT32_MAX;
870cf200d32Sopenharmony_ci
871cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
872cf200d32Sopenharmony_ci      if ((partitions[i].GetInclusion() == LOGICAL) &&
873cf200d32Sopenharmony_ci          (partitions[i].GetStartLBA() < firstFound)) {
874cf200d32Sopenharmony_ci         firstFound = partitions[i].GetStartLBA();
875cf200d32Sopenharmony_ci      } // if
876cf200d32Sopenharmony_ci   } // for
877cf200d32Sopenharmony_ci   return firstFound;
878cf200d32Sopenharmony_ci} // BasicMBRData::FirstLogicalLBA()
879cf200d32Sopenharmony_ci
880cf200d32Sopenharmony_ci// Returns the last sector occupied by any logical partition, or 0 if
881cf200d32Sopenharmony_ci// there are no logical partitions defined.
882cf200d32Sopenharmony_ciuint64_t BasicMBRData::LastLogicalLBA(void) {
883cf200d32Sopenharmony_ci   int i;
884cf200d32Sopenharmony_ci   uint64_t lastFound = 0;
885cf200d32Sopenharmony_ci
886cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
887cf200d32Sopenharmony_ci      if ((partitions[i].GetInclusion() == LOGICAL) &&
888cf200d32Sopenharmony_ci          (partitions[i].GetLastLBA() > lastFound))
889cf200d32Sopenharmony_ci         lastFound = partitions[i].GetLastLBA();
890cf200d32Sopenharmony_ci   } // for
891cf200d32Sopenharmony_ci   return lastFound;
892cf200d32Sopenharmony_ci} // BasicMBRData::LastLogicalLBA()
893cf200d32Sopenharmony_ci
894cf200d32Sopenharmony_ci// Returns 1 if logical partitions are contiguous (have no primaries
895cf200d32Sopenharmony_ci// in their midst), or 0 if one or more primaries exist between
896cf200d32Sopenharmony_ci// logicals.
897cf200d32Sopenharmony_ciint BasicMBRData::AreLogicalsContiguous(void) {
898cf200d32Sopenharmony_ci   int allOK = 1, i = 0;
899cf200d32Sopenharmony_ci   uint64_t firstLogical, lastLogical;
900cf200d32Sopenharmony_ci
901cf200d32Sopenharmony_ci   firstLogical = FirstLogicalLBA() - 1; // subtract 1 for EBR
902cf200d32Sopenharmony_ci   lastLogical = LastLogicalLBA();
903cf200d32Sopenharmony_ci   if (lastLogical > 0) {
904cf200d32Sopenharmony_ci      do {
905cf200d32Sopenharmony_ci         if ((partitions[i].GetInclusion() == PRIMARY) &&
906cf200d32Sopenharmony_ci             (partitions[i].GetStartLBA() >= firstLogical) &&
907cf200d32Sopenharmony_ci             (partitions[i].GetStartLBA() <= lastLogical)) {
908cf200d32Sopenharmony_ci            allOK = 0;
909cf200d32Sopenharmony_ci         } // if
910cf200d32Sopenharmony_ci         i++;
911cf200d32Sopenharmony_ci      } while ((i < MAX_MBR_PARTS) && allOK);
912cf200d32Sopenharmony_ci   } // if
913cf200d32Sopenharmony_ci   return allOK;
914cf200d32Sopenharmony_ci} // BasicMBRData::AreLogicalsContiguous()
915cf200d32Sopenharmony_ci
916cf200d32Sopenharmony_ci// Returns 1 if all partitions fit on the disk, given its size; 0 if any
917cf200d32Sopenharmony_ci// partition is too big.
918cf200d32Sopenharmony_ciint BasicMBRData::DoTheyFit(void) {
919cf200d32Sopenharmony_ci   int i, allOK = 1;
920cf200d32Sopenharmony_ci
921cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
922cf200d32Sopenharmony_ci      if ((partitions[i].GetStartLBA() > diskSize) || (partitions[i].GetLastLBA() > diskSize)) {
923cf200d32Sopenharmony_ci         allOK = 0;
924cf200d32Sopenharmony_ci      } // if
925cf200d32Sopenharmony_ci   } // for
926cf200d32Sopenharmony_ci   return allOK;
927cf200d32Sopenharmony_ci} // BasicMBRData::DoTheyFit(void)
928cf200d32Sopenharmony_ci
929cf200d32Sopenharmony_ci// Returns 1 if there's at least one free sector immediately preceding
930cf200d32Sopenharmony_ci// all partitions flagged as logical; 0 if any logical partition lacks
931cf200d32Sopenharmony_ci// this space.
932cf200d32Sopenharmony_ciint BasicMBRData::SpaceBeforeAllLogicals(void) {
933cf200d32Sopenharmony_ci   int i = 0, allOK = 1;
934cf200d32Sopenharmony_ci
935cf200d32Sopenharmony_ci   do {
936cf200d32Sopenharmony_ci      if ((partitions[i].GetStartLBA() > 0) && (partitions[i].GetInclusion() == LOGICAL)) {
937cf200d32Sopenharmony_ci         allOK = allOK && (SectorUsedAs(partitions[i].GetStartLBA() - 1) == EBR);
938cf200d32Sopenharmony_ci      } // if
939cf200d32Sopenharmony_ci      i++;
940cf200d32Sopenharmony_ci   } while (allOK && (i < MAX_MBR_PARTS));
941cf200d32Sopenharmony_ci   return allOK;
942cf200d32Sopenharmony_ci} // BasicMBRData::SpaceBeforeAllLogicals()
943cf200d32Sopenharmony_ci
944cf200d32Sopenharmony_ci// Returns 1 if the partitions describe a legal layout -- all logicals
945cf200d32Sopenharmony_ci// are contiguous and have at least one preceding empty sector,
946cf200d32Sopenharmony_ci// the number of primaries is under 4 (or under 3 if there are any
947cf200d32Sopenharmony_ci// logicals), there are no overlapping partitions, etc.
948cf200d32Sopenharmony_ci// Does NOT assume that primaries are numbered 1-4; uses the
949cf200d32Sopenharmony_ci// IsItPrimary() function of the MBRPart class to determine
950cf200d32Sopenharmony_ci// primary status. Also does NOT consider partition order; there
951cf200d32Sopenharmony_ci// can be gaps and it will still be considered legal.
952cf200d32Sopenharmony_ciint BasicMBRData::IsLegal(void) {
953cf200d32Sopenharmony_ci   int allOK;
954cf200d32Sopenharmony_ci
955cf200d32Sopenharmony_ci   allOK = (FindOverlaps() == 0);
956cf200d32Sopenharmony_ci   allOK = (allOK && (NumPrimaries() <= 4));
957cf200d32Sopenharmony_ci   allOK = (allOK && AreLogicalsContiguous());
958cf200d32Sopenharmony_ci   allOK = (allOK && DoTheyFit());
959cf200d32Sopenharmony_ci   allOK = (allOK && SpaceBeforeAllLogicals());
960cf200d32Sopenharmony_ci   return allOK;
961cf200d32Sopenharmony_ci} // BasicMBRData::IsLegal()
962cf200d32Sopenharmony_ci
963cf200d32Sopenharmony_ci// Returns 1 if the 0xEE partition in the protective/hybrid MBR is marked as
964cf200d32Sopenharmony_ci// active/bootable.
965cf200d32Sopenharmony_ciint BasicMBRData::IsEEActive(void) {
966cf200d32Sopenharmony_ci   int i, IsActive = 0;
967cf200d32Sopenharmony_ci
968cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
969cf200d32Sopenharmony_ci      if ((partitions[i].GetStatus() & 0x80) && (partitions[i].GetType() == 0xEE))
970cf200d32Sopenharmony_ci         IsActive = 1;
971cf200d32Sopenharmony_ci   }
972cf200d32Sopenharmony_ci   return IsActive;
973cf200d32Sopenharmony_ci} // BasicMBRData::IsEEActive()
974cf200d32Sopenharmony_ci
975cf200d32Sopenharmony_ci// Finds the next in-use partition, starting with start (will return start
976cf200d32Sopenharmony_ci// if it's in use). Returns -1 if no subsequent partition is in use.
977cf200d32Sopenharmony_ciint BasicMBRData::FindNextInUse(int start) {
978cf200d32Sopenharmony_ci   if (start >= MAX_MBR_PARTS)
979cf200d32Sopenharmony_ci      start = -1;
980cf200d32Sopenharmony_ci   while ((start < MAX_MBR_PARTS) && (start >= 0) && (partitions[start].GetInclusion() == NONE))
981cf200d32Sopenharmony_ci      start++;
982cf200d32Sopenharmony_ci   if ((start < 0) || (start >= MAX_MBR_PARTS))
983cf200d32Sopenharmony_ci      start = -1;
984cf200d32Sopenharmony_ci   return start;
985cf200d32Sopenharmony_ci} // BasicMBRData::FindFirstLogical();
986cf200d32Sopenharmony_ci
987cf200d32Sopenharmony_ci/*****************************************************
988cf200d32Sopenharmony_ci *                                                   *
989cf200d32Sopenharmony_ci * Functions to create, delete, or change partitions *
990cf200d32Sopenharmony_ci *                                                   *
991cf200d32Sopenharmony_ci *****************************************************/
992cf200d32Sopenharmony_ci
993cf200d32Sopenharmony_ci// Empty all data. Meant mainly for calling by constructors, but it's also
994cf200d32Sopenharmony_ci// used by the hybrid MBR functions in the GPTData class.
995cf200d32Sopenharmony_civoid BasicMBRData::EmptyMBR(int clearBootloader) {
996cf200d32Sopenharmony_ci   int i;
997cf200d32Sopenharmony_ci
998cf200d32Sopenharmony_ci   // Zero out the boot loader section, the disk signature, and the
999cf200d32Sopenharmony_ci   // 2-byte nulls area only if requested to do so. (This is the
1000cf200d32Sopenharmony_ci   // default.)
1001cf200d32Sopenharmony_ci   if (clearBootloader == 1) {
1002cf200d32Sopenharmony_ci      EmptyBootloader();
1003cf200d32Sopenharmony_ci   } // if
1004cf200d32Sopenharmony_ci
1005cf200d32Sopenharmony_ci   // Blank out the partitions
1006cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
1007cf200d32Sopenharmony_ci      partitions[i].Empty();
1008cf200d32Sopenharmony_ci   } // for
1009cf200d32Sopenharmony_ci   MBRSignature = MBR_SIGNATURE;
1010cf200d32Sopenharmony_ci   state = mbr;
1011cf200d32Sopenharmony_ci} // BasicMBRData::EmptyMBR()
1012cf200d32Sopenharmony_ci
1013cf200d32Sopenharmony_ci// Blank out the boot loader area. Done with the initial MBR-to-GPT
1014cf200d32Sopenharmony_ci// conversion, since MBR boot loaders don't understand GPT, and so
1015cf200d32Sopenharmony_ci// need to be replaced....
1016cf200d32Sopenharmony_civoid BasicMBRData::EmptyBootloader(void) {
1017cf200d32Sopenharmony_ci   int i;
1018cf200d32Sopenharmony_ci
1019cf200d32Sopenharmony_ci   for (i = 0; i < 440; i++)
1020cf200d32Sopenharmony_ci      code[i] = 0;
1021cf200d32Sopenharmony_ci   nulls = 0;
1022cf200d32Sopenharmony_ci} // BasicMBRData::EmptyBootloader
1023cf200d32Sopenharmony_ci
1024cf200d32Sopenharmony_ci// Create a partition of the specified number based on the passed
1025cf200d32Sopenharmony_ci// partition. This function does *NO* error checking, so it's possible
1026cf200d32Sopenharmony_ci// to seriously screw up a partition table using this function!
1027cf200d32Sopenharmony_ci// Note: This function should NOT be used to create the 0xEE partition
1028cf200d32Sopenharmony_ci// in a conventional GPT configuration, since that partition has
1029cf200d32Sopenharmony_ci// specific size requirements that this function won't handle. It may
1030cf200d32Sopenharmony_ci// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
1031cf200d32Sopenharmony_ci// since those toss the rulebook away anyhow....
1032cf200d32Sopenharmony_civoid BasicMBRData::AddPart(int num, const MBRPart& newPart) {
1033cf200d32Sopenharmony_ci   partitions[num] = newPart;
1034cf200d32Sopenharmony_ci} // BasicMBRData::AddPart()
1035cf200d32Sopenharmony_ci
1036cf200d32Sopenharmony_ci// Create a partition of the specified number, starting LBA, and
1037cf200d32Sopenharmony_ci// length. This function does almost no error checking, so it's possible
1038cf200d32Sopenharmony_ci// to seriously screw up a partition table using this function!
1039cf200d32Sopenharmony_ci// Note: This function should NOT be used to create the 0xEE partition
1040cf200d32Sopenharmony_ci// in a conventional GPT configuration, since that partition has
1041cf200d32Sopenharmony_ci// specific size requirements that this function won't handle. It may
1042cf200d32Sopenharmony_ci// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
1043cf200d32Sopenharmony_ci// since those toss the rulebook away anyhow....
1044cf200d32Sopenharmony_civoid BasicMBRData::MakePart(int num, uint64_t start, uint64_t length, int type, int bootable) {
1045cf200d32Sopenharmony_ci   if ((num >= 0) && (num < MAX_MBR_PARTS) && (start <= UINT32_MAX) && (length <= UINT32_MAX)) {
1046cf200d32Sopenharmony_ci      partitions[num].Empty();
1047cf200d32Sopenharmony_ci      partitions[num].SetType(type);
1048cf200d32Sopenharmony_ci      partitions[num].SetLocation(start, length);
1049cf200d32Sopenharmony_ci      if (num < 4)
1050cf200d32Sopenharmony_ci         partitions[num].SetInclusion(PRIMARY);
1051cf200d32Sopenharmony_ci      else
1052cf200d32Sopenharmony_ci         partitions[num].SetInclusion(LOGICAL);
1053cf200d32Sopenharmony_ci      SetPartBootable(num, bootable);
1054cf200d32Sopenharmony_ci   } // if valid partition number & size
1055cf200d32Sopenharmony_ci} // BasicMBRData::MakePart()
1056cf200d32Sopenharmony_ci
1057cf200d32Sopenharmony_ci// Set the partition's type code.
1058cf200d32Sopenharmony_ci// Returns 1 if successful, 0 if not (invalid partition number)
1059cf200d32Sopenharmony_ciint BasicMBRData::SetPartType(int num, int type) {
1060cf200d32Sopenharmony_ci   int allOK;
1061cf200d32Sopenharmony_ci
1062cf200d32Sopenharmony_ci   if ((num >= 0) && (num < MAX_MBR_PARTS)) {
1063cf200d32Sopenharmony_ci      if (partitions[num].GetLengthLBA() != UINT32_C(0)) {
1064cf200d32Sopenharmony_ci         allOK = partitions[num].SetType(type);
1065cf200d32Sopenharmony_ci      } else allOK = 0;
1066cf200d32Sopenharmony_ci   } else allOK = 0;
1067cf200d32Sopenharmony_ci   return allOK;
1068cf200d32Sopenharmony_ci} // BasicMBRData::SetPartType()
1069cf200d32Sopenharmony_ci
1070cf200d32Sopenharmony_ci// Set (or remove) the partition's bootable flag. Setting it is the
1071cf200d32Sopenharmony_ci// default; pass 0 as bootable to remove the flag.
1072cf200d32Sopenharmony_ci// Returns 1 if successful, 0 if not (invalid partition number)
1073cf200d32Sopenharmony_ciint BasicMBRData::SetPartBootable(int num, int bootable) {
1074cf200d32Sopenharmony_ci   int allOK = 1;
1075cf200d32Sopenharmony_ci
1076cf200d32Sopenharmony_ci   if ((num >= 0) && (num < MAX_MBR_PARTS)) {
1077cf200d32Sopenharmony_ci      if (partitions[num].GetLengthLBA() != UINT32_C(0)) {
1078cf200d32Sopenharmony_ci         if (bootable == 0)
1079cf200d32Sopenharmony_ci            partitions[num].SetStatus(UINT8_C(0x00));
1080cf200d32Sopenharmony_ci         else
1081cf200d32Sopenharmony_ci            partitions[num].SetStatus(UINT8_C(0x80));
1082cf200d32Sopenharmony_ci      } else allOK = 0;
1083cf200d32Sopenharmony_ci   } else allOK = 0;
1084cf200d32Sopenharmony_ci   return allOK;
1085cf200d32Sopenharmony_ci} // BasicMBRData::SetPartBootable()
1086cf200d32Sopenharmony_ci
1087cf200d32Sopenharmony_ci// Create a partition that fills the most available space. Returns
1088cf200d32Sopenharmony_ci// 1 if partition was created, 0 otherwise. Intended for use in
1089cf200d32Sopenharmony_ci// creating hybrid MBRs.
1090cf200d32Sopenharmony_ciint BasicMBRData::MakeBiggestPart(int i, int type) {
1091cf200d32Sopenharmony_ci   uint64_t start = UINT64_C(1); // starting point for each search
1092cf200d32Sopenharmony_ci   uint64_t firstBlock; // first block in a segment
1093cf200d32Sopenharmony_ci   uint64_t lastBlock; // last block in a segment
1094cf200d32Sopenharmony_ci   uint64_t segmentSize; // size of segment in blocks
1095cf200d32Sopenharmony_ci   uint64_t selectedSegment = UINT64_C(0); // location of largest segment
1096cf200d32Sopenharmony_ci   uint64_t selectedSize = UINT64_C(0); // size of largest segment in blocks
1097cf200d32Sopenharmony_ci   int found = 0;
1098cf200d32Sopenharmony_ci   string anything;
1099cf200d32Sopenharmony_ci
1100cf200d32Sopenharmony_ci   do {
1101cf200d32Sopenharmony_ci      firstBlock = FindFirstAvailable(start);
1102cf200d32Sopenharmony_ci      if (firstBlock > UINT64_C(0)) { // something's free...
1103cf200d32Sopenharmony_ci         lastBlock = FindLastInFree(firstBlock);
1104cf200d32Sopenharmony_ci         segmentSize = lastBlock - firstBlock + UINT64_C(1);
1105cf200d32Sopenharmony_ci         if (segmentSize > selectedSize) {
1106cf200d32Sopenharmony_ci            selectedSize = segmentSize;
1107cf200d32Sopenharmony_ci            selectedSegment = firstBlock;
1108cf200d32Sopenharmony_ci         } // if
1109cf200d32Sopenharmony_ci         start = lastBlock + 1;
1110cf200d32Sopenharmony_ci      } // if
1111cf200d32Sopenharmony_ci   } while (firstBlock != 0);
1112cf200d32Sopenharmony_ci   if ((selectedSize > UINT64_C(0)) && (selectedSize < diskSize)) {
1113cf200d32Sopenharmony_ci      found = 1;
1114cf200d32Sopenharmony_ci      MakePart(i, selectedSegment, selectedSize, type, 0);
1115cf200d32Sopenharmony_ci   } else {
1116cf200d32Sopenharmony_ci      found = 0;
1117cf200d32Sopenharmony_ci   } // if/else
1118cf200d32Sopenharmony_ci   return found;
1119cf200d32Sopenharmony_ci} // BasicMBRData::MakeBiggestPart(int i)
1120cf200d32Sopenharmony_ci
1121cf200d32Sopenharmony_ci// Delete partition #i
1122cf200d32Sopenharmony_civoid BasicMBRData::DeletePartition(int i) {
1123cf200d32Sopenharmony_ci   partitions[i].Empty();
1124cf200d32Sopenharmony_ci} // BasicMBRData::DeletePartition()
1125cf200d32Sopenharmony_ci
1126cf200d32Sopenharmony_ci// Set the inclusion status (PRIMARY, LOGICAL, or NONE) with some sanity
1127cf200d32Sopenharmony_ci// checks to ensure the table remains legal.
1128cf200d32Sopenharmony_ci// Returns 1 on success, 0 on failure.
1129cf200d32Sopenharmony_ciint BasicMBRData::SetInclusionwChecks(int num, int inclStatus) {
1130cf200d32Sopenharmony_ci   int allOK = 1, origValue;
1131cf200d32Sopenharmony_ci
1132cf200d32Sopenharmony_ci   if (IsLegal()) {
1133cf200d32Sopenharmony_ci      if ((inclStatus == PRIMARY) || (inclStatus == LOGICAL) || (inclStatus == NONE)) {
1134cf200d32Sopenharmony_ci         origValue = partitions[num].GetInclusion();
1135cf200d32Sopenharmony_ci         partitions[num].SetInclusion(inclStatus);
1136cf200d32Sopenharmony_ci         if (!IsLegal()) {
1137cf200d32Sopenharmony_ci            partitions[num].SetInclusion(origValue);
1138cf200d32Sopenharmony_ci            cerr << "Specified change is not legal! Aborting change!\n";
1139cf200d32Sopenharmony_ci         } // if
1140cf200d32Sopenharmony_ci      } else {
1141cf200d32Sopenharmony_ci         cerr << "Invalid partition inclusion code in BasicMBRData::SetInclusionwChecks()!\n";
1142cf200d32Sopenharmony_ci      } // if/else
1143cf200d32Sopenharmony_ci   } else {
1144cf200d32Sopenharmony_ci      cerr << "Partition table is not currently in a valid state. Aborting change!\n";
1145cf200d32Sopenharmony_ci      allOK = 0;
1146cf200d32Sopenharmony_ci   } // if/else
1147cf200d32Sopenharmony_ci   return allOK;
1148cf200d32Sopenharmony_ci} // BasicMBRData::SetInclusionwChecks()
1149cf200d32Sopenharmony_ci
1150cf200d32Sopenharmony_ci// Recomputes the CHS values for the specified partition and adjusts the value.
1151cf200d32Sopenharmony_ci// Note that this will create a technically incorrect CHS value for EFI GPT (0xEE)
1152cf200d32Sopenharmony_ci// protective partitions, but this is required by some buggy BIOSes, so I'm
1153cf200d32Sopenharmony_ci// providing a function to do this deliberately at the user's command.
1154cf200d32Sopenharmony_ci// This function does nothing if the partition's length is 0.
1155cf200d32Sopenharmony_civoid BasicMBRData::RecomputeCHS(int partNum) {
1156cf200d32Sopenharmony_ci   partitions[partNum].RecomputeCHS();
1157cf200d32Sopenharmony_ci} // BasicMBRData::RecomputeCHS()
1158cf200d32Sopenharmony_ci
1159cf200d32Sopenharmony_ci// Sorts the partitions starting with partition #start. This function
1160cf200d32Sopenharmony_ci// does NOT pay attention to primary/logical assignment, which is
1161cf200d32Sopenharmony_ci// critical when writing the partitions.
1162cf200d32Sopenharmony_civoid BasicMBRData::SortMBR(int start) {
1163cf200d32Sopenharmony_ci   if ((start < MAX_MBR_PARTS) && (start >= 0))
1164cf200d32Sopenharmony_ci      sort(partitions + start, partitions + MAX_MBR_PARTS);
1165cf200d32Sopenharmony_ci} // BasicMBRData::SortMBR()
1166cf200d32Sopenharmony_ci
1167cf200d32Sopenharmony_ci// Delete any partitions that are too big to fit on the disk
1168cf200d32Sopenharmony_ci// or that are too big for MBR (32-bit limits).
1169cf200d32Sopenharmony_ci// This deletes the partitions by setting values to 0, not just
1170cf200d32Sopenharmony_ci// by setting them as being omitted.
1171cf200d32Sopenharmony_ci// Returns the number of partitions deleted in this way.
1172cf200d32Sopenharmony_ciint BasicMBRData::DeleteOversizedParts() {
1173cf200d32Sopenharmony_ci   int num = 0, i;
1174cf200d32Sopenharmony_ci
1175cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
1176cf200d32Sopenharmony_ci      if ((partitions[i].GetStartLBA() > diskSize) || (partitions[i].GetLastLBA() > diskSize) ||
1177cf200d32Sopenharmony_ci          (partitions[i].GetStartLBA() > UINT32_MAX) || (partitions[i].GetLengthLBA() > UINT32_MAX)) {
1178cf200d32Sopenharmony_ci         cerr << "\aWarning: Deleting oversized partition #" << i + 1 << "! Start = "
1179cf200d32Sopenharmony_ci              << partitions[i].GetStartLBA() << ", length = " << partitions[i].GetLengthLBA() << "\n";
1180cf200d32Sopenharmony_ci         partitions[i].Empty();
1181cf200d32Sopenharmony_ci         num++;
1182cf200d32Sopenharmony_ci      } // if
1183cf200d32Sopenharmony_ci   } // for
1184cf200d32Sopenharmony_ci   return num;
1185cf200d32Sopenharmony_ci} // BasicMBRData::DeleteOversizedParts()
1186cf200d32Sopenharmony_ci
1187cf200d32Sopenharmony_ci// Search for and delete extended partitions.
1188cf200d32Sopenharmony_ci// Returns the number of partitions deleted.
1189cf200d32Sopenharmony_ciint BasicMBRData::DeleteExtendedParts() {
1190cf200d32Sopenharmony_ci   int i, numDeleted = 0;
1191cf200d32Sopenharmony_ci   uint8_t type;
1192cf200d32Sopenharmony_ci
1193cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
1194cf200d32Sopenharmony_ci      type = partitions[i].GetType();
1195cf200d32Sopenharmony_ci      if (((type == 0x05) || (type == 0x0f) || (type == (0x85))) &&
1196cf200d32Sopenharmony_ci          (partitions[i].GetLengthLBA() > 0)) {
1197cf200d32Sopenharmony_ci         partitions[i].Empty();
1198cf200d32Sopenharmony_ci         numDeleted++;
1199cf200d32Sopenharmony_ci      } // if
1200cf200d32Sopenharmony_ci   } // for
1201cf200d32Sopenharmony_ci   return numDeleted;
1202cf200d32Sopenharmony_ci} // BasicMBRData::DeleteExtendedParts()
1203cf200d32Sopenharmony_ci
1204cf200d32Sopenharmony_ci// Finds any overlapping partitions and omits the smaller of the two.
1205cf200d32Sopenharmony_civoid BasicMBRData::OmitOverlaps() {
1206cf200d32Sopenharmony_ci   int i, j;
1207cf200d32Sopenharmony_ci
1208cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
1209cf200d32Sopenharmony_ci      for (j = i + 1; j < MAX_MBR_PARTS; j++) {
1210cf200d32Sopenharmony_ci         if ((partitions[i].GetInclusion() != NONE) &&
1211cf200d32Sopenharmony_ci             partitions[i].DoTheyOverlap(partitions[j])) {
1212cf200d32Sopenharmony_ci            if (partitions[i].GetLengthLBA() < partitions[j].GetLengthLBA())
1213cf200d32Sopenharmony_ci               partitions[i].SetInclusion(NONE);
1214cf200d32Sopenharmony_ci            else
1215cf200d32Sopenharmony_ci               partitions[j].SetInclusion(NONE);
1216cf200d32Sopenharmony_ci         } // if
1217cf200d32Sopenharmony_ci      } // for (j...)
1218cf200d32Sopenharmony_ci   } // for (i...)
1219cf200d32Sopenharmony_ci} // BasicMBRData::OmitOverlaps()
1220cf200d32Sopenharmony_ci
1221cf200d32Sopenharmony_ci// Convert as many partitions into logicals as possible, except for
1222cf200d32Sopenharmony_ci// the first partition, if possible.
1223cf200d32Sopenharmony_civoid BasicMBRData::MaximizeLogicals() {
1224cf200d32Sopenharmony_ci   int earliestPart = 0, earliestPartWas = NONE, i;
1225cf200d32Sopenharmony_ci
1226cf200d32Sopenharmony_ci   for (i = MAX_MBR_PARTS - 1; i >= 0; i--) {
1227cf200d32Sopenharmony_ci      UpdateCanBeLogical();
1228cf200d32Sopenharmony_ci      earliestPart = i;
1229cf200d32Sopenharmony_ci      if (partitions[i].CanBeLogical()) {
1230cf200d32Sopenharmony_ci         partitions[i].SetInclusion(LOGICAL);
1231cf200d32Sopenharmony_ci      } else if (partitions[i].CanBePrimary()) {
1232cf200d32Sopenharmony_ci         partitions[i].SetInclusion(PRIMARY);
1233cf200d32Sopenharmony_ci      } else {
1234cf200d32Sopenharmony_ci         partitions[i].SetInclusion(NONE);
1235cf200d32Sopenharmony_ci      } // if/elseif/else
1236cf200d32Sopenharmony_ci   } // for
1237cf200d32Sopenharmony_ci   // If we have spare primaries, convert back the earliest partition to
1238cf200d32Sopenharmony_ci   // its original state....
1239cf200d32Sopenharmony_ci   if ((NumPrimaries() < 4) && (partitions[earliestPart].GetInclusion() == LOGICAL))
1240cf200d32Sopenharmony_ci      partitions[earliestPart].SetInclusion(earliestPartWas);
1241cf200d32Sopenharmony_ci} // BasicMBRData::MaximizeLogicals()
1242cf200d32Sopenharmony_ci
1243cf200d32Sopenharmony_ci// Add primaries up to the maximum allowed, from the omitted category.
1244cf200d32Sopenharmony_civoid BasicMBRData::MaximizePrimaries() {
1245cf200d32Sopenharmony_ci   int num, i = 0;
1246cf200d32Sopenharmony_ci
1247cf200d32Sopenharmony_ci   num = NumPrimaries();
1248cf200d32Sopenharmony_ci   while ((num < 4) && (i < MAX_MBR_PARTS)) {
1249cf200d32Sopenharmony_ci      if ((partitions[i].GetInclusion() == NONE) && (partitions[i].CanBePrimary())) {
1250cf200d32Sopenharmony_ci         partitions[i].SetInclusion(PRIMARY);
1251cf200d32Sopenharmony_ci         num++;
1252cf200d32Sopenharmony_ci         UpdateCanBeLogical();
1253cf200d32Sopenharmony_ci      } // if
1254cf200d32Sopenharmony_ci      i++;
1255cf200d32Sopenharmony_ci   } // while
1256cf200d32Sopenharmony_ci} // BasicMBRData::MaximizePrimaries()
1257cf200d32Sopenharmony_ci
1258cf200d32Sopenharmony_ci// Remove primary partitions in excess of 4, starting with the later ones,
1259cf200d32Sopenharmony_ci// in terms of the array location....
1260cf200d32Sopenharmony_civoid BasicMBRData::TrimPrimaries(void) {
1261cf200d32Sopenharmony_ci   int numToDelete, i = MAX_MBR_PARTS - 1;
1262cf200d32Sopenharmony_ci
1263cf200d32Sopenharmony_ci   numToDelete = NumPrimaries() - 4;
1264cf200d32Sopenharmony_ci   while ((numToDelete > 0) && (i >= 0)) {
1265cf200d32Sopenharmony_ci      if (partitions[i].GetInclusion() == PRIMARY) {
1266cf200d32Sopenharmony_ci         partitions[i].SetInclusion(NONE);
1267cf200d32Sopenharmony_ci         numToDelete--;
1268cf200d32Sopenharmony_ci      } // if
1269cf200d32Sopenharmony_ci      i--;
1270cf200d32Sopenharmony_ci   } // while (numToDelete > 0)
1271cf200d32Sopenharmony_ci} // BasicMBRData::TrimPrimaries()
1272cf200d32Sopenharmony_ci
1273cf200d32Sopenharmony_ci// Locates primary partitions located between logical partitions and
1274cf200d32Sopenharmony_ci// either converts the primaries into logicals (if possible) or omits
1275cf200d32Sopenharmony_ci// them.
1276cf200d32Sopenharmony_civoid BasicMBRData::MakeLogicalsContiguous(void) {
1277cf200d32Sopenharmony_ci   uint64_t firstLogicalLBA, lastLogicalLBA;
1278cf200d32Sopenharmony_ci   int i;
1279cf200d32Sopenharmony_ci
1280cf200d32Sopenharmony_ci   firstLogicalLBA = FirstLogicalLBA();
1281cf200d32Sopenharmony_ci   lastLogicalLBA = LastLogicalLBA();
1282cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++) {
1283cf200d32Sopenharmony_ci      if ((partitions[i].GetInclusion() == PRIMARY) &&
1284cf200d32Sopenharmony_ci          (partitions[i].GetStartLBA() >= firstLogicalLBA) &&
1285cf200d32Sopenharmony_ci          (partitions[i].GetLastLBA() <= lastLogicalLBA)) {
1286cf200d32Sopenharmony_ci         if (SectorUsedAs(partitions[i].GetStartLBA() - 1) == NONE)
1287cf200d32Sopenharmony_ci            partitions[i].SetInclusion(LOGICAL);
1288cf200d32Sopenharmony_ci         else
1289cf200d32Sopenharmony_ci            partitions[i].SetInclusion(NONE);
1290cf200d32Sopenharmony_ci      } // if
1291cf200d32Sopenharmony_ci   } // for
1292cf200d32Sopenharmony_ci} // BasicMBRData::MakeLogicalsContiguous()
1293cf200d32Sopenharmony_ci
1294cf200d32Sopenharmony_ci// If MBR data aren't legal, adjust primary/logical assignments and,
1295cf200d32Sopenharmony_ci// if necessary, drop partitions, to make the data legal.
1296cf200d32Sopenharmony_civoid BasicMBRData::MakeItLegal(void) {
1297cf200d32Sopenharmony_ci   if (!IsLegal()) {
1298cf200d32Sopenharmony_ci      DeleteOversizedParts();
1299cf200d32Sopenharmony_ci      MaximizeLogicals();
1300cf200d32Sopenharmony_ci      MaximizePrimaries();
1301cf200d32Sopenharmony_ci      if (!AreLogicalsContiguous())
1302cf200d32Sopenharmony_ci         MakeLogicalsContiguous();
1303cf200d32Sopenharmony_ci      if (NumPrimaries() > 4)
1304cf200d32Sopenharmony_ci         TrimPrimaries();
1305cf200d32Sopenharmony_ci      OmitOverlaps();
1306cf200d32Sopenharmony_ci   } // if
1307cf200d32Sopenharmony_ci} // BasicMBRData::MakeItLegal()
1308cf200d32Sopenharmony_ci
1309cf200d32Sopenharmony_ci// Removes logical partitions and deactivated partitions from first four
1310cf200d32Sopenharmony_ci// entries (primary space).
1311cf200d32Sopenharmony_ci// Returns the number of partitions moved.
1312cf200d32Sopenharmony_ciint BasicMBRData::RemoveLogicalsFromFirstFour(void) {
1313cf200d32Sopenharmony_ci   int i, j, numMoved = 0, swapped = 0;
1314cf200d32Sopenharmony_ci   MBRPart temp;
1315cf200d32Sopenharmony_ci
1316cf200d32Sopenharmony_ci   for (i = 0; i < 4; i++) {
1317cf200d32Sopenharmony_ci      if ((partitions[i].GetInclusion() != PRIMARY) && (partitions[i].GetLengthLBA() > 0)) {
1318cf200d32Sopenharmony_ci         j = 4;
1319cf200d32Sopenharmony_ci         swapped = 0;
1320cf200d32Sopenharmony_ci         do {
1321cf200d32Sopenharmony_ci            if ((partitions[j].GetInclusion() == NONE) && (partitions[j].GetLengthLBA() == 0)) {
1322cf200d32Sopenharmony_ci               temp = partitions[j];
1323cf200d32Sopenharmony_ci               partitions[j] = partitions[i];
1324cf200d32Sopenharmony_ci               partitions[i] = temp;
1325cf200d32Sopenharmony_ci               swapped = 1;
1326cf200d32Sopenharmony_ci               numMoved++;
1327cf200d32Sopenharmony_ci            } // if
1328cf200d32Sopenharmony_ci            j++;
1329cf200d32Sopenharmony_ci         } while ((j < MAX_MBR_PARTS) && !swapped);
1330cf200d32Sopenharmony_ci         if (j >= MAX_MBR_PARTS)
1331cf200d32Sopenharmony_ci            cerr << "Warning! Too many partitions in BasicMBRData::RemoveLogicalsFromFirstFour()!\n";
1332cf200d32Sopenharmony_ci      } // if
1333cf200d32Sopenharmony_ci   } // for i...
1334cf200d32Sopenharmony_ci   return numMoved;
1335cf200d32Sopenharmony_ci} // BasicMBRData::RemoveLogicalsFromFirstFour()
1336cf200d32Sopenharmony_ci
1337cf200d32Sopenharmony_ci// Move all primaries into the first four partition spaces
1338cf200d32Sopenharmony_ci// Returns the number of partitions moved.
1339cf200d32Sopenharmony_ciint BasicMBRData::MovePrimariesToFirstFour(void) {
1340cf200d32Sopenharmony_ci   int i, j = 0, numMoved = 0, swapped = 0;
1341cf200d32Sopenharmony_ci   MBRPart temp;
1342cf200d32Sopenharmony_ci
1343cf200d32Sopenharmony_ci   for (i = 4; i < MAX_MBR_PARTS; i++) {
1344cf200d32Sopenharmony_ci      if (partitions[i].GetInclusion() == PRIMARY) {
1345cf200d32Sopenharmony_ci         j = 0;
1346cf200d32Sopenharmony_ci         swapped = 0;
1347cf200d32Sopenharmony_ci         do {
1348cf200d32Sopenharmony_ci            if (partitions[j].GetInclusion() != PRIMARY) {
1349cf200d32Sopenharmony_ci               temp = partitions[j];
1350cf200d32Sopenharmony_ci               partitions[j] = partitions[i];
1351cf200d32Sopenharmony_ci               partitions[i] = temp;
1352cf200d32Sopenharmony_ci               swapped = 1;
1353cf200d32Sopenharmony_ci               numMoved++;
1354cf200d32Sopenharmony_ci            } // if
1355cf200d32Sopenharmony_ci            j++;
1356cf200d32Sopenharmony_ci         } while ((j < 4) && !swapped);
1357cf200d32Sopenharmony_ci      } // if
1358cf200d32Sopenharmony_ci   } // for
1359cf200d32Sopenharmony_ci   return numMoved;
1360cf200d32Sopenharmony_ci} // BasicMBRData::MovePrimariesToFirstFour()
1361cf200d32Sopenharmony_ci
1362cf200d32Sopenharmony_ci// Create an extended partition, if necessary, to hold the logical partitions.
1363cf200d32Sopenharmony_ci// This function also sorts the primaries into the first four positions of
1364cf200d32Sopenharmony_ci// the table.
1365cf200d32Sopenharmony_ci// Returns 1 on success, 0 on failure.
1366cf200d32Sopenharmony_ciint BasicMBRData::CreateExtended(void) {
1367cf200d32Sopenharmony_ci   int allOK = 1, i = 0, swapped = 0;
1368cf200d32Sopenharmony_ci   MBRPart temp;
1369cf200d32Sopenharmony_ci
1370cf200d32Sopenharmony_ci   if (IsLegal()) {
1371cf200d32Sopenharmony_ci      // Move logicals out of primary space...
1372cf200d32Sopenharmony_ci      RemoveLogicalsFromFirstFour();
1373cf200d32Sopenharmony_ci      // Move primaries out of logical space...
1374cf200d32Sopenharmony_ci      MovePrimariesToFirstFour();
1375cf200d32Sopenharmony_ci
1376cf200d32Sopenharmony_ci      // Create the extended partition
1377cf200d32Sopenharmony_ci      if (NumLogicals() > 0) {
1378cf200d32Sopenharmony_ci         SortMBR(4); // sort starting from 4 -- that is, logicals only
1379cf200d32Sopenharmony_ci         temp.Empty();
1380cf200d32Sopenharmony_ci         temp.SetStartLBA(FirstLogicalLBA() - 1);
1381cf200d32Sopenharmony_ci         temp.SetLengthLBA(LastLogicalLBA() - FirstLogicalLBA() + 2);
1382cf200d32Sopenharmony_ci         temp.SetType(0x0f, 1);
1383cf200d32Sopenharmony_ci         temp.SetInclusion(PRIMARY);
1384cf200d32Sopenharmony_ci         do {
1385cf200d32Sopenharmony_ci            if ((partitions[i].GetInclusion() == NONE) || (partitions[i].GetLengthLBA() == 0)) {
1386cf200d32Sopenharmony_ci               partitions[i] = temp;
1387cf200d32Sopenharmony_ci               swapped = 1;
1388cf200d32Sopenharmony_ci            } // if
1389cf200d32Sopenharmony_ci            i++;
1390cf200d32Sopenharmony_ci         } while ((i < 4) && !swapped);
1391cf200d32Sopenharmony_ci         if (!swapped) {
1392cf200d32Sopenharmony_ci            cerr << "Could not create extended partition; no room in primary table!\n";
1393cf200d32Sopenharmony_ci            allOK = 0;
1394cf200d32Sopenharmony_ci         } // if
1395cf200d32Sopenharmony_ci      } // if (NumLogicals() > 0)
1396cf200d32Sopenharmony_ci   } else allOK = 0;
1397cf200d32Sopenharmony_ci   // Do a final check for EFI GPT (0xEE) partitions & flag as a problem if found
1398cf200d32Sopenharmony_ci   // along with an extended partition
1399cf200d32Sopenharmony_ci   for (i = 0; i < MAX_MBR_PARTS; i++)
1400cf200d32Sopenharmony_ci      if (swapped && partitions[i].GetType() == 0xEE)
1401cf200d32Sopenharmony_ci         allOK = 0;
1402cf200d32Sopenharmony_ci   return allOK;
1403cf200d32Sopenharmony_ci} // BasicMBRData::CreateExtended()
1404cf200d32Sopenharmony_ci
1405cf200d32Sopenharmony_ci/****************************************
1406cf200d32Sopenharmony_ci *                                      *
1407cf200d32Sopenharmony_ci * Functions to find data on free space *
1408cf200d32Sopenharmony_ci *                                      *
1409cf200d32Sopenharmony_ci ****************************************/
1410cf200d32Sopenharmony_ci
1411cf200d32Sopenharmony_ci// Finds the first free space on the disk from start onward; returns 0
1412cf200d32Sopenharmony_ci// if none available....
1413cf200d32Sopenharmony_ciuint64_t BasicMBRData::FindFirstAvailable(uint64_t start) {
1414cf200d32Sopenharmony_ci   uint64_t first;
1415cf200d32Sopenharmony_ci   uint64_t i;
1416cf200d32Sopenharmony_ci   int firstMoved;
1417cf200d32Sopenharmony_ci
1418cf200d32Sopenharmony_ci   if ((start >= (UINT32_MAX - 1)) || (start >= (diskSize - 1)))
1419cf200d32Sopenharmony_ci      return 0;
1420cf200d32Sopenharmony_ci
1421cf200d32Sopenharmony_ci   first = start;
1422cf200d32Sopenharmony_ci
1423cf200d32Sopenharmony_ci   // ...now search through all partitions; if first is within an
1424cf200d32Sopenharmony_ci   // existing partition, move it to the next sector after that
1425cf200d32Sopenharmony_ci   // partition and repeat. If first was moved, set firstMoved
1426cf200d32Sopenharmony_ci   // flag; repeat until firstMoved is not set, so as to catch
1427cf200d32Sopenharmony_ci   // cases where partitions are out of sequential order....
1428cf200d32Sopenharmony_ci   do {
1429cf200d32Sopenharmony_ci      firstMoved = 0;
1430cf200d32Sopenharmony_ci      for (i = 0; i < 4; i++) {
1431cf200d32Sopenharmony_ci         // Check if it's in the existing partition
1432cf200d32Sopenharmony_ci         if ((first >= partitions[i].GetStartLBA()) &&
1433cf200d32Sopenharmony_ci             (first < (partitions[i].GetStartLBA() + partitions[i].GetLengthLBA()))) {
1434cf200d32Sopenharmony_ci            first = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA();
1435cf200d32Sopenharmony_ci            firstMoved = 1;
1436cf200d32Sopenharmony_ci         } // if
1437cf200d32Sopenharmony_ci      } // for
1438cf200d32Sopenharmony_ci   } while (firstMoved == 1);
1439cf200d32Sopenharmony_ci   if ((first >= diskSize) || (first > UINT32_MAX))
1440cf200d32Sopenharmony_ci      first = 0;
1441cf200d32Sopenharmony_ci   return (first);
1442cf200d32Sopenharmony_ci} // BasicMBRData::FindFirstAvailable()
1443cf200d32Sopenharmony_ci
1444cf200d32Sopenharmony_ci// Finds the last free sector on the disk from start forward.
1445cf200d32Sopenharmony_ciuint64_t BasicMBRData::FindLastInFree(uint64_t start) {
1446cf200d32Sopenharmony_ci   uint64_t nearestStart;
1447cf200d32Sopenharmony_ci   uint64_t i;
1448cf200d32Sopenharmony_ci
1449cf200d32Sopenharmony_ci   if ((diskSize <= UINT32_MAX) && (diskSize > 0))
1450cf200d32Sopenharmony_ci      nearestStart = diskSize - 1;
1451cf200d32Sopenharmony_ci   else
1452cf200d32Sopenharmony_ci      nearestStart = UINT32_MAX - 1;
1453cf200d32Sopenharmony_ci
1454cf200d32Sopenharmony_ci   for (i = 0; i < 4; i++) {
1455cf200d32Sopenharmony_ci      if ((nearestStart > partitions[i].GetStartLBA()) &&
1456cf200d32Sopenharmony_ci          (partitions[i].GetStartLBA() > start)) {
1457cf200d32Sopenharmony_ci         nearestStart = partitions[i].GetStartLBA() - 1;
1458cf200d32Sopenharmony_ci      } // if
1459cf200d32Sopenharmony_ci   } // for
1460cf200d32Sopenharmony_ci   return (nearestStart);
1461cf200d32Sopenharmony_ci} // BasicMBRData::FindLastInFree()
1462cf200d32Sopenharmony_ci
1463cf200d32Sopenharmony_ci// Finds the first free sector on the disk from start backward.
1464cf200d32Sopenharmony_ciuint64_t BasicMBRData::FindFirstInFree(uint64_t start) {
1465cf200d32Sopenharmony_ci   uint64_t bestLastLBA, thisLastLBA;
1466cf200d32Sopenharmony_ci   int i;
1467cf200d32Sopenharmony_ci
1468cf200d32Sopenharmony_ci   bestLastLBA = 1;
1469cf200d32Sopenharmony_ci   for (i = 0; i < 4; i++) {
1470cf200d32Sopenharmony_ci      thisLastLBA = partitions[i].GetLastLBA() + 1;
1471cf200d32Sopenharmony_ci      if (thisLastLBA > 0)
1472cf200d32Sopenharmony_ci         thisLastLBA--;
1473cf200d32Sopenharmony_ci      if ((thisLastLBA > bestLastLBA) && (thisLastLBA < start))
1474cf200d32Sopenharmony_ci         bestLastLBA = thisLastLBA + 1;
1475cf200d32Sopenharmony_ci   } // for
1476cf200d32Sopenharmony_ci   return (bestLastLBA);
1477cf200d32Sopenharmony_ci} // BasicMBRData::FindFirstInFree()
1478cf200d32Sopenharmony_ci
1479cf200d32Sopenharmony_ci// Returns NONE (unused), PRIMARY, LOGICAL, EBR (for EBR or MBR), or INVALID.
1480cf200d32Sopenharmony_ci// Note: If the sector immediately before a logical partition is in use by
1481cf200d32Sopenharmony_ci// another partition, this function returns PRIMARY or LOGICAL for that
1482cf200d32Sopenharmony_ci// sector, rather than EBR.
1483cf200d32Sopenharmony_ciint BasicMBRData::SectorUsedAs(uint64_t sector, int topPartNum) {
1484cf200d32Sopenharmony_ci   int i = 0, usedAs = NONE;
1485cf200d32Sopenharmony_ci
1486cf200d32Sopenharmony_ci   do {
1487cf200d32Sopenharmony_ci      if ((partitions[i].GetStartLBA() <= sector) && (partitions[i].GetLastLBA() >= sector))
1488cf200d32Sopenharmony_ci         usedAs = partitions[i].GetInclusion();
1489cf200d32Sopenharmony_ci      if ((partitions[i].GetStartLBA() == (sector + 1)) && (partitions[i].GetInclusion() == LOGICAL))
1490cf200d32Sopenharmony_ci         usedAs = EBR;
1491cf200d32Sopenharmony_ci      if (sector == 0)
1492cf200d32Sopenharmony_ci         usedAs = EBR;
1493cf200d32Sopenharmony_ci      if (sector >= diskSize)
1494cf200d32Sopenharmony_ci         usedAs = INVALID;
1495cf200d32Sopenharmony_ci      i++;
1496cf200d32Sopenharmony_ci   } while ((i < topPartNum) && ((usedAs == NONE) || (usedAs == EBR)));
1497cf200d32Sopenharmony_ci   return usedAs;
1498cf200d32Sopenharmony_ci} // BasicMBRData::SectorUsedAs()
1499cf200d32Sopenharmony_ci
1500cf200d32Sopenharmony_ci/******************************************************
1501cf200d32Sopenharmony_ci *                                                    *
1502cf200d32Sopenharmony_ci * Functions that extract data on specific partitions *
1503cf200d32Sopenharmony_ci *                                                    *
1504cf200d32Sopenharmony_ci ******************************************************/
1505cf200d32Sopenharmony_ci
1506cf200d32Sopenharmony_ciuint8_t BasicMBRData::GetStatus(int i) {
1507cf200d32Sopenharmony_ci   MBRPart* thePart;
1508cf200d32Sopenharmony_ci   uint8_t retval;
1509cf200d32Sopenharmony_ci
1510cf200d32Sopenharmony_ci   thePart = GetPartition(i);
1511cf200d32Sopenharmony_ci   if (thePart != NULL)
1512cf200d32Sopenharmony_ci      retval = thePart->GetStatus();
1513cf200d32Sopenharmony_ci   else
1514cf200d32Sopenharmony_ci      retval = UINT8_C(0);
1515cf200d32Sopenharmony_ci   return retval;
1516cf200d32Sopenharmony_ci} // BasicMBRData::GetStatus()
1517cf200d32Sopenharmony_ci
1518cf200d32Sopenharmony_ciuint8_t BasicMBRData::GetType(int i) {
1519cf200d32Sopenharmony_ci   MBRPart* thePart;
1520cf200d32Sopenharmony_ci   uint8_t retval;
1521cf200d32Sopenharmony_ci
1522cf200d32Sopenharmony_ci   thePart = GetPartition(i);
1523cf200d32Sopenharmony_ci   if (thePart != NULL)
1524cf200d32Sopenharmony_ci      retval = thePart->GetType();
1525cf200d32Sopenharmony_ci   else
1526cf200d32Sopenharmony_ci      retval = UINT8_C(0);
1527cf200d32Sopenharmony_ci   return retval;
1528cf200d32Sopenharmony_ci} // BasicMBRData::GetType()
1529cf200d32Sopenharmony_ci
1530cf200d32Sopenharmony_ciuint64_t BasicMBRData::GetFirstSector(int i) {
1531cf200d32Sopenharmony_ci   MBRPart* thePart;
1532cf200d32Sopenharmony_ci   uint64_t retval;
1533cf200d32Sopenharmony_ci
1534cf200d32Sopenharmony_ci   thePart = GetPartition(i);
1535cf200d32Sopenharmony_ci   if (thePart != NULL)
1536cf200d32Sopenharmony_ci      retval = thePart->GetStartLBA();
1537cf200d32Sopenharmony_ci   else
1538cf200d32Sopenharmony_ci      retval = UINT32_C(0);
1539cf200d32Sopenharmony_ci   return retval;
1540cf200d32Sopenharmony_ci} // BasicMBRData::GetFirstSector()
1541cf200d32Sopenharmony_ci
1542cf200d32Sopenharmony_ciuint64_t BasicMBRData::GetLength(int i) {
1543cf200d32Sopenharmony_ci   MBRPart* thePart;
1544cf200d32Sopenharmony_ci   uint64_t retval;
1545cf200d32Sopenharmony_ci
1546cf200d32Sopenharmony_ci   thePart = GetPartition(i);
1547cf200d32Sopenharmony_ci   if (thePart != NULL)
1548cf200d32Sopenharmony_ci      retval = thePart->GetLengthLBA();
1549cf200d32Sopenharmony_ci   else
1550cf200d32Sopenharmony_ci      retval = UINT64_C(0);
1551cf200d32Sopenharmony_ci   return retval;
1552cf200d32Sopenharmony_ci} // BasicMBRData::GetLength()
1553cf200d32Sopenharmony_ci
1554cf200d32Sopenharmony_ci/***********************
1555cf200d32Sopenharmony_ci *                     *
1556cf200d32Sopenharmony_ci * Protected functions *
1557cf200d32Sopenharmony_ci *                     *
1558cf200d32Sopenharmony_ci ***********************/
1559cf200d32Sopenharmony_ci
1560cf200d32Sopenharmony_ci// Return a pointer to a primary or logical partition, or NULL if
1561cf200d32Sopenharmony_ci// the partition is out of range....
1562cf200d32Sopenharmony_ciMBRPart* BasicMBRData::GetPartition(int i) {
1563cf200d32Sopenharmony_ci   MBRPart* thePart = NULL;
1564cf200d32Sopenharmony_ci
1565cf200d32Sopenharmony_ci   if ((i >= 0) && (i < MAX_MBR_PARTS))
1566cf200d32Sopenharmony_ci      thePart = &partitions[i];
1567cf200d32Sopenharmony_ci   return thePart;
1568cf200d32Sopenharmony_ci} // GetPartition()
1569cf200d32Sopenharmony_ci
1570cf200d32Sopenharmony_ci/*******************************************
1571cf200d32Sopenharmony_ci *                                         *
1572cf200d32Sopenharmony_ci * Functions that involve user interaction *
1573cf200d32Sopenharmony_ci *                                         *
1574cf200d32Sopenharmony_ci *******************************************/
1575cf200d32Sopenharmony_ci
1576cf200d32Sopenharmony_ci// Present the MBR operations menu. Note that the 'w' option does not
1577cf200d32Sopenharmony_ci// immediately write data; that's handled by the calling function.
1578cf200d32Sopenharmony_ci// Returns the number of partitions defined on exit, or -1 if the
1579cf200d32Sopenharmony_ci// user selected the 'q' option. (Thus, the caller should save data
1580cf200d32Sopenharmony_ci// if the return value is >0, or possibly >=0 depending on intentions.)
1581cf200d32Sopenharmony_ciint BasicMBRData::DoMenu(const string& prompt) {
1582cf200d32Sopenharmony_ci   int goOn = 1, quitting = 0, retval, num, haveShownInfo = 0;
1583cf200d32Sopenharmony_ci   unsigned int hexCode;
1584cf200d32Sopenharmony_ci   string tempStr;
1585cf200d32Sopenharmony_ci
1586cf200d32Sopenharmony_ci   do {
1587cf200d32Sopenharmony_ci      cout << prompt;
1588cf200d32Sopenharmony_ci      switch (ReadString()[0]) {
1589cf200d32Sopenharmony_ci         case '\0':
1590cf200d32Sopenharmony_ci            goOn = cin.good();
1591cf200d32Sopenharmony_ci            break;
1592cf200d32Sopenharmony_ci         case 'a': case 'A':
1593cf200d32Sopenharmony_ci            num = GetNumber(1, MAX_MBR_PARTS, 1, "Toggle active flag for partition: ") - 1;
1594cf200d32Sopenharmony_ci            if (partitions[num].GetInclusion() != NONE)
1595cf200d32Sopenharmony_ci               partitions[num].SetStatus(partitions[num].GetStatus() ^ 0x80);
1596cf200d32Sopenharmony_ci            break;
1597cf200d32Sopenharmony_ci         case 'c': case 'C':
1598cf200d32Sopenharmony_ci            for (num = 0; num < MAX_MBR_PARTS; num++)
1599cf200d32Sopenharmony_ci               RecomputeCHS(num);
1600cf200d32Sopenharmony_ci            break;
1601cf200d32Sopenharmony_ci         case 'l': case 'L':
1602cf200d32Sopenharmony_ci            num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to set as logical: ") - 1;
1603cf200d32Sopenharmony_ci            SetInclusionwChecks(num, LOGICAL);
1604cf200d32Sopenharmony_ci            break;
1605cf200d32Sopenharmony_ci         case 'o': case 'O':
1606cf200d32Sopenharmony_ci            num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to omit: ") - 1;
1607cf200d32Sopenharmony_ci            SetInclusionwChecks(num, NONE);
1608cf200d32Sopenharmony_ci            break;
1609cf200d32Sopenharmony_ci         case 'p': case 'P':
1610cf200d32Sopenharmony_ci            if (!haveShownInfo) {
1611cf200d32Sopenharmony_ci               cout << "\n** NOTE: Partition numbers do NOT indicate final primary/logical "
1612cf200d32Sopenharmony_ci                    << "status,\n** unlike in most MBR partitioning tools!\n\a";
1613cf200d32Sopenharmony_ci               cout << "\n** Extended partitions are not displayed, but will be generated "
1614cf200d32Sopenharmony_ci                    << "as required.\n";
1615cf200d32Sopenharmony_ci               haveShownInfo = 1;
1616cf200d32Sopenharmony_ci            } // if
1617cf200d32Sopenharmony_ci            DisplayMBRData();
1618cf200d32Sopenharmony_ci            break;
1619cf200d32Sopenharmony_ci         case 'q': case 'Q':
1620cf200d32Sopenharmony_ci            cout << "This will abandon your changes. Are you sure? ";
1621cf200d32Sopenharmony_ci            if (GetYN() == 'Y') {
1622cf200d32Sopenharmony_ci               goOn = 0;
1623cf200d32Sopenharmony_ci               quitting = 1;
1624cf200d32Sopenharmony_ci            } // if
1625cf200d32Sopenharmony_ci            break;
1626cf200d32Sopenharmony_ci         case 'r': case 'R':
1627cf200d32Sopenharmony_ci            num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to set as primary: ") - 1;
1628cf200d32Sopenharmony_ci            SetInclusionwChecks(num, PRIMARY);
1629cf200d32Sopenharmony_ci            break;
1630cf200d32Sopenharmony_ci         case 's': case 'S':
1631cf200d32Sopenharmony_ci            SortMBR();
1632cf200d32Sopenharmony_ci            break;
1633cf200d32Sopenharmony_ci         case 't': case 'T':
1634cf200d32Sopenharmony_ci            num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to change type code: ") - 1;
1635cf200d32Sopenharmony_ci            hexCode = 0x00;
1636cf200d32Sopenharmony_ci            if (partitions[num].GetLengthLBA() > 0) {
1637cf200d32Sopenharmony_ci               while ((hexCode <= 0) || (hexCode > 255)) {
1638cf200d32Sopenharmony_ci                  cout << "Enter an MBR hex code: ";
1639cf200d32Sopenharmony_ci                  tempStr = ReadString();
1640cf200d32Sopenharmony_ci                  if (IsHex(tempStr))
1641cf200d32Sopenharmony_ci                     sscanf(tempStr.c_str(), "%x", &hexCode);
1642cf200d32Sopenharmony_ci               } // while
1643cf200d32Sopenharmony_ci               partitions[num].SetType(hexCode);
1644cf200d32Sopenharmony_ci            } // if
1645cf200d32Sopenharmony_ci            break;
1646cf200d32Sopenharmony_ci         case 'w': case 'W':
1647cf200d32Sopenharmony_ci            goOn = 0;
1648cf200d32Sopenharmony_ci            break;
1649cf200d32Sopenharmony_ci         default:
1650cf200d32Sopenharmony_ci            ShowCommands();
1651cf200d32Sopenharmony_ci            break;
1652cf200d32Sopenharmony_ci      } // switch
1653cf200d32Sopenharmony_ci   } while (goOn);
1654cf200d32Sopenharmony_ci   if (quitting)
1655cf200d32Sopenharmony_ci      retval = -1;
1656cf200d32Sopenharmony_ci   else
1657cf200d32Sopenharmony_ci      retval = CountParts();
1658cf200d32Sopenharmony_ci   return (retval);
1659cf200d32Sopenharmony_ci} // BasicMBRData::DoMenu()
1660cf200d32Sopenharmony_ci
1661cf200d32Sopenharmony_civoid BasicMBRData::ShowCommands(void) {
1662cf200d32Sopenharmony_ci   cout << "a\ttoggle the active/boot flag\n";
1663cf200d32Sopenharmony_ci   cout << "c\trecompute all CHS values\n";
1664cf200d32Sopenharmony_ci   cout << "l\tset partition as logical\n";
1665cf200d32Sopenharmony_ci   cout << "o\tomit partition\n";
1666cf200d32Sopenharmony_ci   cout << "p\tprint the MBR partition table\n";
1667cf200d32Sopenharmony_ci   cout << "q\tquit without saving changes\n";
1668cf200d32Sopenharmony_ci   cout << "r\tset partition as primary\n";
1669cf200d32Sopenharmony_ci   cout << "s\tsort MBR partitions\n";
1670cf200d32Sopenharmony_ci   cout << "t\tchange partition type code\n";
1671cf200d32Sopenharmony_ci   cout << "w\twrite the MBR partition table to disk and exit\n";
1672cf200d32Sopenharmony_ci} // BasicMBRData::ShowCommands()
1673