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