1 /* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition 2 data. */ 3 4 /* Initial coding by Rod Smith, January to February, 2009 */ 5 6 /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 7 under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8 9 #define __STDC_LIMIT_MACROS 10 #ifndef __STDC_CONSTANT_MACROS 11 #define __STDC_CONSTANT_MACROS 12 #endif 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <stdint.h> 17 #include <fcntl.h> 18 #include <string.h> 19 #include <time.h> 20 #include <sys/stat.h> 21 #include <errno.h> 22 #include <iostream> 23 #include "mbr.h" 24 25 using namespace std; 26 27 /**************************************** 28 * * 29 * MBRData class and related structures * 30 * * 31 ****************************************/ 32 33 MBRData::~MBRData(void) { 34 } // MBRData destructor 35 36 // Assignment operator -- copy entire set of MBR data. 37 MBRData & MBRData::operator=(const BasicMBRData & orig) { 38 BasicMBRData::operator=(orig); 39 return *this; 40 } // MBRData::operator=() 41 42 /***************************************************** 43 * * 44 * Functions to create, delete, or change partitions * 45 * * 46 *****************************************************/ 47 48 // Create a protective MBR. Clears the boot loader area if clearBoot > 0. 49 void MBRData::MakeProtectiveMBR(int clearBoot) { 50 51 EmptyMBR(clearBoot); 52 53 // Initialize variables 54 nulls = 0; 55 MBRSignature = MBR_SIGNATURE; 56 diskSignature = UINT32_C(0); 57 58 partitions[0].SetStatus(0); // Flag the protective part. as unbootable 59 60 partitions[0].SetType(UINT8_C(0xEE)); 61 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 62 partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1)); 63 } else { // disk is too big to represent, so fake it... 64 partitions[0].SetLocation(UINT32_C(1), UINT32_MAX); 65 } // if/else 66 partitions[0].SetInclusion(PRIMARY); 67 68 state = gpt; 69 } // MBRData::MakeProtectiveMBR() 70 71 // Optimizes the size of the 0xEE (EFI GPT) partition 72 void MBRData::OptimizeEESize(void) { 73 int i, typeFlag = 0; 74 uint64_t after; 75 76 for (i = 0; i < 4; i++) { 77 // Check for non-empty and non-0xEE partitions 78 if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00)) 79 typeFlag++; 80 if (partitions[i].GetType() == 0xEE) { 81 // Blank space before this partition; fill it.... 82 if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) { 83 partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1)); 84 } // if 85 // Blank space after this partition; fill it.... 86 after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA(); 87 if (SectorUsedAs(after, 4) == NONE) { 88 partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1); 89 } // if free space after 90 if (after > diskSize) { 91 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 92 partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA()); 93 } else { // disk is too big to represent, so fake it... 94 partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA()); 95 } // if/else 96 } // if protective partition is too big 97 RecomputeCHS(i); 98 } // if partition is 0xEE 99 } // for partition loop 100 if (typeFlag == 0) { // No non-hybrid partitions found 101 MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. 102 } // if 103 } // MBRData::OptimizeEESize() 104 105 // Delete a partition if one exists at the specified location. 106 // Returns 1 if a partition was deleted, 0 otherwise.... 107 // Used to help keep GPT & hybrid MBR partitions in sync.... 108 int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) { 109 uint32_t start32, length32; 110 int i, deleted = 0; 111 112 if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) { 113 start32 = (uint32_t) start64; 114 length32 = (uint32_t) length64; 115 for (i = 0; i < MAX_MBR_PARTS; i++) { 116 if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32) 117 && (partitions[i].GetLengthLBA() == length32)) { 118 DeletePartition(i); 119 if (state == hybrid) 120 OptimizeEESize(); 121 deleted = 1; 122 } // if (match found) 123 } // for i (partition scan) 124 } // if (hybrid & GPT partition < 2TiB) 125 return deleted; 126 } // MBRData::DeleteByLocation() 127 128 /****************************************************** 129 * * 130 * Functions that extract data on specific partitions * 131 * * 132 ******************************************************/ 133 134 // Return the MBR data as a GPT partition.... 135 GPTPart MBRData::AsGPT(int i) { 136 MBRPart* origPart; 137 GPTPart newPart; 138 uint8_t origType; 139 uint64_t firstSector, lastSector; 140 141 newPart.BlankPartition(); 142 origPart = GetPartition(i); 143 if (origPart != NULL) { 144 origType = origPart->GetType(); 145 146 // don't convert extended, hybrid protective, or null (non-existent) 147 // partitions (Note similar protection is in GPTData::XFormPartitions(), 148 // but I want it here too in case I call this function in another 149 // context in the future....) 150 if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 151 (origType != 0x00) && (origType != 0xEE)) { 152 firstSector = (uint64_t) origPart->GetStartLBA(); 153 newPart.SetFirstLBA(firstSector); 154 lastSector = (uint64_t) origPart->GetLastLBA(); 155 newPart.SetLastLBA(lastSector); 156 newPart.SetType(((uint16_t) origType) * 0x0100); 157 newPart.RandomizeUniqueGUID(); 158 newPart.SetAttributes(0); 159 newPart.SetName(newPart.GetTypeName()); 160 } // if not extended, protective, or non-existent 161 } // if (origPart != NULL) 162 return newPart; 163 } // MBRData::AsGPT() 164 165