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 /* // Assignment operator -- copy entire set of MBR data. 34 MBRData & MBRData::operator=(const MBRData & orig) { 35 BasicMBRData::operator=(orig); 36 return *this; 37 } // MBRData::operator=() */ 38 39 // Assignment operator -- copy entire set of MBR data. 40 MBRData & MBRData::operator=(const BasicMBRData & orig) { 41 BasicMBRData::operator=(orig); 42 return *this; 43 } // MBRData::operator=() 44 45 /***************************************************** 46 * * 47 * Functions to create, delete, or change partitions * 48 * * 49 *****************************************************/ 50 51 // Create a protective MBR. Clears the boot loader area if clearBoot > 0. 52 void MBRData::MakeProtectiveMBR(int clearBoot) { 53 54 EmptyMBR(clearBoot); 55 56 // Initialize variables 57 nulls = 0; 58 MBRSignature = MBR_SIGNATURE; 59 diskSignature = UINT32_C(0); 60 61 partitions[0].SetStatus(0); // Flag the protective part. as unbootable 62 63 partitions[0].SetType(UINT8_C(0xEE)); 64 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 65 partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1)); 66 } else { // disk is too big to represent, so fake it... 67 partitions[0].SetLocation(UINT32_C(1), UINT32_MAX); 68 } // if/else 69 partitions[0].SetInclusion(PRIMARY); 70 71 state = gpt; 72 } // MBRData::MakeProtectiveMBR() 73 74 // Optimizes the size of the 0xEE (EFI GPT) partition 75 void MBRData::OptimizeEESize(void) { 76 int i, typeFlag = 0; 77 uint64_t after; 78 79 for (i = 0; i < 4; i++) { 80 // Check for non-empty and non-0xEE partitions 81 if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00)) 82 typeFlag++; 83 if (partitions[i].GetType() == 0xEE) { 84 // Blank space before this partition; fill it.... 85 if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) { 86 partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1)); 87 } // if 88 // Blank space after this partition; fill it.... 89 after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA(); 90 if (SectorUsedAs(after, 4) == NONE) { 91 partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1); 92 } // if free space after 93 if (after > diskSize) { 94 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 95 partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA()); 96 } else { // disk is too big to represent, so fake it... 97 partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA()); 98 } // if/else 99 } // if protective partition is too big 100 RecomputeCHS(i); 101 } // if partition is 0xEE 102 } // for partition loop 103 if (typeFlag == 0) { // No non-hybrid partitions found 104 MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. 105 } // if 106 } // MBRData::OptimizeEESize() 107 108 // Delete a partition if one exists at the specified location. 109 // Returns 1 if a partition was deleted, 0 otherwise.... 110 // Used to help keep GPT & hybrid MBR partitions in sync.... 111 int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) { 112 uint32_t start32, length32; 113 int i, deleted = 0; 114 115 if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) { 116 start32 = (uint32_t) start64; 117 length32 = (uint32_t) length64; 118 for (i = 0; i < MAX_MBR_PARTS; i++) { 119 if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32) 120 && (partitions[i].GetLengthLBA() == length32)) { 121 DeletePartition(i); 122 if (state == hybrid) 123 OptimizeEESize(); 124 deleted = 1; 125 } // if (match found) 126 } // for i (partition scan) 127 } // if (hybrid & GPT partition < 2TiB) 128 return deleted; 129 } // MBRData::DeleteByLocation() 130 131 /****************************************************** 132 * * 133 * Functions that extract data on specific partitions * 134 * * 135 ******************************************************/ 136 137 // Return the MBR data as a GPT partition.... 138 GPTPart MBRData::AsGPT(int i) { 139 MBRPart* origPart; 140 GPTPart newPart; 141 uint8_t origType; 142 uint64_t firstSector, lastSector; 143 144 newPart.BlankPartition(); 145 origPart = GetPartition(i); 146 if (origPart != NULL) { 147 origType = origPart->GetType(); 148 149 // don't convert extended, hybrid protective, or null (non-existent) 150 // partitions (Note similar protection is in GPTData::XFormPartitions(), 151 // but I want it here too in case I call this function in another 152 // context in the future....) 153 if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 154 (origType != 0x00) && (origType != 0xEE)) { 155 firstSector = (uint64_t) origPart->GetStartLBA(); 156 newPart.SetFirstLBA(firstSector); 157 lastSector = (uint64_t) origPart->GetLastLBA(); 158 newPart.SetLastLBA(lastSector); 159 newPart.SetType(((uint16_t) origType) * 0x0100); 160 newPart.RandomizeUniqueGUID(); 161 newPart.SetAttributes(0); 162 newPart.SetName(newPart.GetTypeName()); 163 } // if not extended, protective, or non-existent 164 } // if (origPart != NULL) 165 return newPart; 166 } // MBRData::AsGPT() 167 168