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