/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition data. */ /* Initial coding by Rod Smith, January to February, 2009 */ /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ #define __STDC_LIMIT_MACROS #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif #include #include #include #include #include #include #include #include #include #include "mbr.h" using namespace std; /**************************************** * * * MBRData class and related structures * * * ****************************************/ MBRData::~MBRData(void) { } // MBRData destructor // Assignment operator -- copy entire set of MBR data. MBRData & MBRData::operator=(const BasicMBRData & orig) { BasicMBRData::operator=(orig); return *this; } // MBRData::operator=() /***************************************************** * * * Functions to create, delete, or change partitions * * * *****************************************************/ // Create a protective MBR. Clears the boot loader area if clearBoot > 0. void MBRData::MakeProtectiveMBR(int clearBoot) { EmptyMBR(clearBoot); // Initialize variables nulls = 0; MBRSignature = MBR_SIGNATURE; diskSignature = UINT32_C(0); partitions[0].SetStatus(0); // Flag the protective part. as unbootable partitions[0].SetType(UINT8_C(0xEE)); if (diskSize < UINT32_MAX) { // If the disk is under 2TiB partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1)); } else { // disk is too big to represent, so fake it... partitions[0].SetLocation(UINT32_C(1), UINT32_MAX); } // if/else partitions[0].SetInclusion(PRIMARY); state = gpt; } // MBRData::MakeProtectiveMBR() // Optimizes the size of the 0xEE (EFI GPT) partition void MBRData::OptimizeEESize(void) { int i, typeFlag = 0; uint64_t after; for (i = 0; i < 4; i++) { // Check for non-empty and non-0xEE partitions if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00)) typeFlag++; if (partitions[i].GetType() == 0xEE) { // Blank space before this partition; fill it.... if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) { partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1)); } // if // Blank space after this partition; fill it.... after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA(); if (SectorUsedAs(after, 4) == NONE) { partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1); } // if free space after if (after > diskSize) { if (diskSize < UINT32_MAX) { // If the disk is under 2TiB partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA()); } else { // disk is too big to represent, so fake it... partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA()); } // if/else } // if protective partition is too big RecomputeCHS(i); } // if partition is 0xEE } // for partition loop if (typeFlag == 0) { // No non-hybrid partitions found MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. } // if } // MBRData::OptimizeEESize() // Delete a partition if one exists at the specified location. // Returns 1 if a partition was deleted, 0 otherwise.... // Used to help keep GPT & hybrid MBR partitions in sync.... int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) { uint32_t start32, length32; int i, deleted = 0; if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) { start32 = (uint32_t) start64; length32 = (uint32_t) length64; for (i = 0; i < MAX_MBR_PARTS; i++) { if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32) && (partitions[i].GetLengthLBA() == length32)) { DeletePartition(i); if (state == hybrid) OptimizeEESize(); deleted = 1; } // if (match found) } // for i (partition scan) } // if (hybrid & GPT partition < 2TiB) return deleted; } // MBRData::DeleteByLocation() /****************************************************** * * * Functions that extract data on specific partitions * * * ******************************************************/ // Return the MBR data as a GPT partition.... GPTPart MBRData::AsGPT(int i) { MBRPart* origPart; GPTPart newPart; uint8_t origType; uint64_t firstSector, lastSector; newPart.BlankPartition(); origPart = GetPartition(i); if (origPart != NULL) { origType = origPart->GetType(); // don't convert extended, hybrid protective, or null (non-existent) // partitions (Note similar protection is in GPTData::XFormPartitions(), // but I want it here too in case I call this function in another // context in the future....) if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && (origType != 0x00) && (origType != 0xEE)) { firstSector = (uint64_t) origPart->GetStartLBA(); newPart.SetFirstLBA(firstSector); lastSector = (uint64_t) origPart->GetLastLBA(); newPart.SetLastLBA(lastSector); newPart.SetType(((uint16_t) origType) * 0x0100); newPart.RandomizeUniqueGUID(); newPart.SetAttributes(0); newPart.SetName(newPart.GetTypeName()); } // if not extended, protective, or non-existent } // if (origPart != NULL) return newPart; } // MBRData::AsGPT()