1e7b4ff9317fc4e551cf974684eaa88697de5a28srs/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition 2e7b4ff9317fc4e551cf974684eaa88697de5a28srs data. */ 3e7b4ff9317fc4e551cf974684eaa88697de5a28srs 4978041ca613dcb881763b36cf53639d924e52a56srs/* Initial coding by Rod Smith, January to February, 2009 */ 5e7b4ff9317fc4e551cf974684eaa88697de5a28srs 6e3ee733ff8690af7568dac665bc20ecf869dea1dRoderick W. Smith/* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 7221e08768de7fe42ba533ca22baf671420569c07srs under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8221e08768de7fe42ba533ca22baf671420569c07srs 9e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_LIMIT_MACROS 10fcad060a1d83aa5e0b4ad38cf342d10f1922878dAurimas Liutikas#ifndef __STDC_CONSTANT_MACROS 11e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_CONSTANT_MACROS 12fcad060a1d83aa5e0b4ad38cf342d10f1922878dAurimas Liutikas#endif 13e7b4ff9317fc4e551cf974684eaa88697de5a28srs 14e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdio.h> 15e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdlib.h> 16e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdint.h> 17e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <fcntl.h> 18e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <string.h> 19e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <time.h> 20e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <sys/stat.h> 21e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <errno.h> 22fed16d043a14e8b86c97a6413aec7281fefcbcb5srs#include <iostream> 23e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "mbr.h" 24e7b4ff9317fc4e551cf974684eaa88697de5a28srs 25e7b4ff9317fc4e551cf974684eaa88697de5a28srsusing namespace std; 26e7b4ff9317fc4e551cf974684eaa88697de5a28srs 27e7b4ff9317fc4e551cf974684eaa88697de5a28srs/**************************************** 28e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 29e7b4ff9317fc4e551cf974684eaa88697de5a28srs * MBRData class and related structures * 30e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 31e7b4ff9317fc4e551cf974684eaa88697de5a28srs ****************************************/ 32e7b4ff9317fc4e551cf974684eaa88697de5a28srs 33bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs/* // Assignment operator -- copy entire set of MBR data. 3464cbd171067eb34054741bfcd73f0b91d727a371srsMBRData & MBRData::operator=(const MBRData & orig) { 3564cbd171067eb34054741bfcd73f0b91d727a371srs BasicMBRData::operator=(orig); 3664cbd171067eb34054741bfcd73f0b91d727a371srs return *this; 3764cbd171067eb34054741bfcd73f0b91d727a371srs} // MBRData::operator=() */ 38327129e9331f888a8fc08d688dcb0a739a3c17besrs 39bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs// Assignment operator -- copy entire set of MBR data. 40bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrsMBRData & MBRData::operator=(const BasicMBRData & orig) { 41bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs BasicMBRData::operator=(orig); 42bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs return *this; 43bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs} // MBRData::operator=() 44bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs 45978041ca613dcb881763b36cf53639d924e52a56srs/***************************************************** 46978041ca613dcb881763b36cf53639d924e52a56srs * * 47978041ca613dcb881763b36cf53639d924e52a56srs * Functions to create, delete, or change partitions * 48978041ca613dcb881763b36cf53639d924e52a56srs * * 49978041ca613dcb881763b36cf53639d924e52a56srs *****************************************************/ 50978041ca613dcb881763b36cf53639d924e52a56srs 51221e08768de7fe42ba533ca22baf671420569c07srs// Create a protective MBR. Clears the boot loader area if clearBoot > 0. 52221e08768de7fe42ba533ca22baf671420569c07srsvoid MBRData::MakeProtectiveMBR(int clearBoot) { 53978041ca613dcb881763b36cf53639d924e52a56srs 54978041ca613dcb881763b36cf53639d924e52a56srs EmptyMBR(clearBoot); 55e7b4ff9317fc4e551cf974684eaa88697de5a28srs 56e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Initialize variables 57e7b4ff9317fc4e551cf974684eaa88697de5a28srs nulls = 0; 58e7b4ff9317fc4e551cf974684eaa88697de5a28srs MBRSignature = MBR_SIGNATURE; 598a4ddfc919d5569c68489cf53d9cf5abc94c410csrs diskSignature = UINT32_C(0); 60e7b4ff9317fc4e551cf974684eaa88697de5a28srs 61bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[0].SetStatus(0); // Flag the protective part. as unbootable 62e7b4ff9317fc4e551cf974684eaa88697de5a28srs 63bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[0].SetType(UINT8_C(0xEE)); 64e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 65bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1)); 66e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { // disk is too big to represent, so fake it... 67bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[0].SetLocation(UINT32_C(1), UINT32_MAX); 68e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 69bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[0].SetInclusion(PRIMARY); 70e7b4ff9317fc4e551cf974684eaa88697de5a28srs 71e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt; 72e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // MBRData::MakeProtectiveMBR() 73e7b4ff9317fc4e551cf974684eaa88697de5a28srs 74e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Optimizes the size of the 0xEE (EFI GPT) partition 75e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid MBRData::OptimizeEESize(void) { 76e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int i, typeFlag = 0; 77bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs uint64_t after; 78e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 79e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < 4; i++) { 80e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for non-empty and non-0xEE partitions 81bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00)) 82e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs typeFlag++; 83bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if (partitions[i].GetType() == 0xEE) { 84e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Blank space before this partition; fill it.... 85bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) { 86bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1)); 87e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 88e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Blank space after this partition; fill it.... 89bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA(); 90bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if (SectorUsedAs(after, 4) == NONE) { 91bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1); 92e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if free space after 9364cbd171067eb34054741bfcd73f0b91d727a371srs if (after > diskSize) { 9464cbd171067eb34054741bfcd73f0b91d727a371srs if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 95bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA()); 9664cbd171067eb34054741bfcd73f0b91d727a371srs } else { // disk is too big to represent, so fake it... 97bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA()); 9864cbd171067eb34054741bfcd73f0b91d727a371srs } // if/else 9964cbd171067eb34054741bfcd73f0b91d727a371srs } // if protective partition is too big 10064cbd171067eb34054741bfcd73f0b91d727a371srs RecomputeCHS(i); 101e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if partition is 0xEE 102e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for partition loop 103978041ca613dcb881763b36cf53639d924e52a56srs if (typeFlag == 0) { // No non-hybrid partitions found 10464cbd171067eb34054741bfcd73f0b91d727a371srs MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. 105e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 106978041ca613dcb881763b36cf53639d924e52a56srs} // MBRData::OptimizeEESize() 107e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs 10864cbd171067eb34054741bfcd73f0b91d727a371srs// Delete a partition if one exists at the specified location. 10964cbd171067eb34054741bfcd73f0b91d727a371srs// Returns 1 if a partition was deleted, 0 otherwise.... 11064cbd171067eb34054741bfcd73f0b91d727a371srs// Used to help keep GPT & hybrid MBR partitions in sync.... 11164cbd171067eb34054741bfcd73f0b91d727a371srsint MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) { 11264cbd171067eb34054741bfcd73f0b91d727a371srs uint32_t start32, length32; 11364cbd171067eb34054741bfcd73f0b91d727a371srs int i, deleted = 0; 114e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 11564cbd171067eb34054741bfcd73f0b91d727a371srs if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) { 11664cbd171067eb34054741bfcd73f0b91d727a371srs start32 = (uint32_t) start64; 11764cbd171067eb34054741bfcd73f0b91d727a371srs length32 = (uint32_t) length64; 11864cbd171067eb34054741bfcd73f0b91d727a371srs for (i = 0; i < MAX_MBR_PARTS; i++) { 119bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32) 120bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs && (partitions[i].GetLengthLBA() == length32)) { 12164cbd171067eb34054741bfcd73f0b91d727a371srs DeletePartition(i); 12264cbd171067eb34054741bfcd73f0b91d727a371srs if (state == hybrid) 12364cbd171067eb34054741bfcd73f0b91d727a371srs OptimizeEESize(); 12464cbd171067eb34054741bfcd73f0b91d727a371srs deleted = 1; 12564cbd171067eb34054741bfcd73f0b91d727a371srs } // if (match found) 12664cbd171067eb34054741bfcd73f0b91d727a371srs } // for i (partition scan) 12764cbd171067eb34054741bfcd73f0b91d727a371srs } // if (hybrid & GPT partition < 2TiB) 12864cbd171067eb34054741bfcd73f0b91d727a371srs return deleted; 12964cbd171067eb34054741bfcd73f0b91d727a371srs} // MBRData::DeleteByLocation() 130c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 131978041ca613dcb881763b36cf53639d924e52a56srs/****************************************************** 132978041ca613dcb881763b36cf53639d924e52a56srs * * 133978041ca613dcb881763b36cf53639d924e52a56srs * Functions that extract data on specific partitions * 134978041ca613dcb881763b36cf53639d924e52a56srs * * 135978041ca613dcb881763b36cf53639d924e52a56srs ******************************************************/ 136978041ca613dcb881763b36cf53639d924e52a56srs 137221e08768de7fe42ba533ca22baf671420569c07srs// Return the MBR data as a GPT partition.... 138221e08768de7fe42ba533ca22baf671420569c07srsGPTPart MBRData::AsGPT(int i) { 139bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs MBRPart* origPart; 140221e08768de7fe42ba533ca22baf671420569c07srs GPTPart newPart; 141221e08768de7fe42ba533ca22baf671420569c07srs uint8_t origType; 142221e08768de7fe42ba533ca22baf671420569c07srs uint64_t firstSector, lastSector; 143221e08768de7fe42ba533ca22baf671420569c07srs 144221e08768de7fe42ba533ca22baf671420569c07srs newPart.BlankPartition(); 145221e08768de7fe42ba533ca22baf671420569c07srs origPart = GetPartition(i); 146221e08768de7fe42ba533ca22baf671420569c07srs if (origPart != NULL) { 147bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs origType = origPart->GetType(); 148221e08768de7fe42ba533ca22baf671420569c07srs 149221e08768de7fe42ba533ca22baf671420569c07srs // don't convert extended, hybrid protective, or null (non-existent) 150221e08768de7fe42ba533ca22baf671420569c07srs // partitions (Note similar protection is in GPTData::XFormPartitions(), 151221e08768de7fe42ba533ca22baf671420569c07srs // but I want it here too in case I call this function in another 152221e08768de7fe42ba533ca22baf671420569c07srs // context in the future....) 153e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 154221e08768de7fe42ba533ca22baf671420569c07srs (origType != 0x00) && (origType != 0xEE)) { 155bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs firstSector = (uint64_t) origPart->GetStartLBA(); 156221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetFirstLBA(firstSector); 157bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs lastSector = (uint64_t) origPart->GetLastLBA(); 158221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetLastLBA(lastSector); 159221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetType(((uint16_t) origType) * 0x0100); 1606699b01eda84d24bfaf80ad725304fef2b0e1b2asrs newPart.RandomizeUniqueGUID(); 161221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetAttributes(0); 1626699b01eda84d24bfaf80ad725304fef2b0e1b2asrs newPart.SetName(newPart.GetTypeName()); 163978041ca613dcb881763b36cf53639d924e52a56srs } // if not extended, protective, or non-existent 164978041ca613dcb881763b36cf53639d924e52a56srs } // if (origPart != NULL) 165221e08768de7fe42ba533ca22baf671420569c07srs return newPart; 166221e08768de7fe42ba533ca22baf671420569c07srs} // MBRData::AsGPT() 167978041ca613dcb881763b36cf53639d924e52a56srs 168