mbr.cc revision 64cbd171067eb34054741bfcd73f0b91d727a371
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 6221e08768de7fe42ba533ca22baf671420569c07srs/* This program is copyright (c) 2009 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 10e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_CONSTANT_MACROS 11e7b4ff9317fc4e551cf974684eaa88697de5a28srs 12e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdio.h> 13e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdlib.h> 14e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdint.h> 15e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <fcntl.h> 16e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <string.h> 17e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <time.h> 18e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <sys/stat.h> 19e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <errno.h> 20fed16d043a14e8b86c97a6413aec7281fefcbcb5srs#include <iostream> 21e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "mbr.h" 22e7b4ff9317fc4e551cf974684eaa88697de5a28srs 23e7b4ff9317fc4e551cf974684eaa88697de5a28srsusing namespace std; 24e7b4ff9317fc4e551cf974684eaa88697de5a28srs 25e7b4ff9317fc4e551cf974684eaa88697de5a28srs/**************************************** 26e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 27e7b4ff9317fc4e551cf974684eaa88697de5a28srs * MBRData class and related structures * 28e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 29e7b4ff9317fc4e551cf974684eaa88697de5a28srs ****************************************/ 30e7b4ff9317fc4e551cf974684eaa88697de5a28srs 3164cbd171067eb34054741bfcd73f0b91d727a371srs// Assignment operator -- copy entire set of MBR data. 3264cbd171067eb34054741bfcd73f0b91d727a371srsMBRData & MBRData::operator=(const MBRData & orig) { 3364cbd171067eb34054741bfcd73f0b91d727a371srs BasicMBRData::operator=(orig); 3464cbd171067eb34054741bfcd73f0b91d727a371srs return *this; 3564cbd171067eb34054741bfcd73f0b91d727a371srs} // MBRData::operator=() */ 36327129e9331f888a8fc08d688dcb0a739a3c17besrs 37978041ca613dcb881763b36cf53639d924e52a56srs/***************************************************** 38978041ca613dcb881763b36cf53639d924e52a56srs * * 39978041ca613dcb881763b36cf53639d924e52a56srs * Functions to create, delete, or change partitions * 40978041ca613dcb881763b36cf53639d924e52a56srs * * 41978041ca613dcb881763b36cf53639d924e52a56srs *****************************************************/ 42978041ca613dcb881763b36cf53639d924e52a56srs 43221e08768de7fe42ba533ca22baf671420569c07srs// Create a protective MBR. Clears the boot loader area if clearBoot > 0. 44221e08768de7fe42ba533ca22baf671420569c07srsvoid MBRData::MakeProtectiveMBR(int clearBoot) { 45978041ca613dcb881763b36cf53639d924e52a56srs 46978041ca613dcb881763b36cf53639d924e52a56srs EmptyMBR(clearBoot); 47e7b4ff9317fc4e551cf974684eaa88697de5a28srs 48e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Initialize variables 49e7b4ff9317fc4e551cf974684eaa88697de5a28srs nulls = 0; 50e7b4ff9317fc4e551cf974684eaa88697de5a28srs MBRSignature = MBR_SIGNATURE; 518a4ddfc919d5569c68489cf53d9cf5abc94c410csrs diskSignature = UINT32_C(0); 52e7b4ff9317fc4e551cf974684eaa88697de5a28srs 53e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable 54e7b4ff9317fc4e551cf974684eaa88697de5a28srs 55e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions[0].partitionType = UINT8_C(0xEE); 56e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions[0].firstLBA = UINT32_C(1); 57e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 58978041ca613dcb881763b36cf53639d924e52a56srs partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1); 59e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { // disk is too big to represent, so fake it... 60e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions[0].lengthLBA = UINT32_MAX; 61e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 62e7b4ff9317fc4e551cf974684eaa88697de5a28srs 6355d926192adc984462509b2966e23bc0d1129bbdsrs // Write CHS data. This maxes out the use of the disk, as much as 6455d926192adc984462509b2966e23bc0d1129bbdsrs // possible -- even to the point of exceeding the capacity of sub-8GB 6555d926192adc984462509b2966e23bc0d1129bbdsrs // disks. The EFI spec says to use 0xffffff as the ending value, 6655d926192adc984462509b2966e23bc0d1129bbdsrs // although normal MBR disks max out at 0xfeffff. FWIW, both GNU Parted 6755d926192adc984462509b2966e23bc0d1129bbdsrs // and Apple's Disk Utility use 0xfeffff, and the latter puts that 6855d926192adc984462509b2966e23bc0d1129bbdsrs // value in for the FIRST sector, too! 6955d926192adc984462509b2966e23bc0d1129bbdsrs LBAtoCHS(1, partitions[0].firstSector); 7055d926192adc984462509b2966e23bc0d1129bbdsrs if (LBAtoCHS(partitions[0].lengthLBA, partitions[0].lastSector) == 0) 7155d926192adc984462509b2966e23bc0d1129bbdsrs partitions[0].lastSector[0] = 0xFF; 7255d926192adc984462509b2966e23bc0d1129bbdsrs 73e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt; 74e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // MBRData::MakeProtectiveMBR() 75e7b4ff9317fc4e551cf974684eaa88697de5a28srs 76e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Optimizes the size of the 0xEE (EFI GPT) partition 77e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid MBRData::OptimizeEESize(void) { 78e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int i, typeFlag = 0; 79e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t after; 80e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 81e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < 4; i++) { 82e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for non-empty and non-0xEE partitions 83e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((partitions[i].partitionType != 0xEE) && (partitions[i].partitionType != 0x00)) 84e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs typeFlag++; 85e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (partitions[i].partitionType == 0xEE) { 86e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Blank space before this partition; fill it.... 87e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (IsFree(partitions[i].firstLBA - 1)) { 88e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[i].firstLBA = FindFirstInFree(partitions[i].firstLBA - 1); 89e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 90e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Blank space after this partition; fill it.... 91e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs after = partitions[i].firstLBA + partitions[i].lengthLBA; 92e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (IsFree(after)) { 93e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1; 94e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if free space after 9564cbd171067eb34054741bfcd73f0b91d727a371srs if (after > diskSize) { 9664cbd171067eb34054741bfcd73f0b91d727a371srs if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 9764cbd171067eb34054741bfcd73f0b91d727a371srs partitions[0].lengthLBA = (uint32_t) diskSize - partitions[i].firstLBA; 9864cbd171067eb34054741bfcd73f0b91d727a371srs } else { // disk is too big to represent, so fake it... 9964cbd171067eb34054741bfcd73f0b91d727a371srs partitions[0].lengthLBA = UINT32_MAX - partitions[i].firstLBA; 10064cbd171067eb34054741bfcd73f0b91d727a371srs } // if/else 10164cbd171067eb34054741bfcd73f0b91d727a371srs } // if protective partition is too big 10264cbd171067eb34054741bfcd73f0b91d727a371srs RecomputeCHS(i); 103e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if partition is 0xEE 104e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for partition loop 105978041ca613dcb881763b36cf53639d924e52a56srs if (typeFlag == 0) { // No non-hybrid partitions found 10664cbd171067eb34054741bfcd73f0b91d727a371srs MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. 107e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 108978041ca613dcb881763b36cf53639d924e52a56srs} // MBRData::OptimizeEESize() 109e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs 11064cbd171067eb34054741bfcd73f0b91d727a371srs// Delete a partition if one exists at the specified location. 11164cbd171067eb34054741bfcd73f0b91d727a371srs// Returns 1 if a partition was deleted, 0 otherwise.... 11264cbd171067eb34054741bfcd73f0b91d727a371srs// Used to help keep GPT & hybrid MBR partitions in sync.... 11364cbd171067eb34054741bfcd73f0b91d727a371srsint MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) { 11464cbd171067eb34054741bfcd73f0b91d727a371srs uint32_t start32, length32; 11564cbd171067eb34054741bfcd73f0b91d727a371srs int i, deleted = 0; 116e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 11764cbd171067eb34054741bfcd73f0b91d727a371srs if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) { 11864cbd171067eb34054741bfcd73f0b91d727a371srs start32 = (uint32_t) start64; 11964cbd171067eb34054741bfcd73f0b91d727a371srs length32 = (uint32_t) length64; 12064cbd171067eb34054741bfcd73f0b91d727a371srs for (i = 0; i < MAX_MBR_PARTS; i++) { 12164cbd171067eb34054741bfcd73f0b91d727a371srs if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA == length32) && 12264cbd171067eb34054741bfcd73f0b91d727a371srs (partitions[i].partitionType != 0xEE)) { 12364cbd171067eb34054741bfcd73f0b91d727a371srs DeletePartition(i); 12464cbd171067eb34054741bfcd73f0b91d727a371srs if (state == hybrid) 12564cbd171067eb34054741bfcd73f0b91d727a371srs OptimizeEESize(); 12664cbd171067eb34054741bfcd73f0b91d727a371srs deleted = 1; 12764cbd171067eb34054741bfcd73f0b91d727a371srs } // if (match found) 12864cbd171067eb34054741bfcd73f0b91d727a371srs } // for i (partition scan) 12964cbd171067eb34054741bfcd73f0b91d727a371srs } // if (hybrid & GPT partition < 2TiB) 13064cbd171067eb34054741bfcd73f0b91d727a371srs return deleted; 13164cbd171067eb34054741bfcd73f0b91d727a371srs} // MBRData::DeleteByLocation() 132c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 133978041ca613dcb881763b36cf53639d924e52a56srs/****************************************************** 134978041ca613dcb881763b36cf53639d924e52a56srs * * 135978041ca613dcb881763b36cf53639d924e52a56srs * Functions that extract data on specific partitions * 136978041ca613dcb881763b36cf53639d924e52a56srs * * 137978041ca613dcb881763b36cf53639d924e52a56srs ******************************************************/ 138978041ca613dcb881763b36cf53639d924e52a56srs 139221e08768de7fe42ba533ca22baf671420569c07srs// Return the MBR data as a GPT partition.... 140221e08768de7fe42ba533ca22baf671420569c07srsGPTPart MBRData::AsGPT(int i) { 141221e08768de7fe42ba533ca22baf671420569c07srs MBRRecord* origPart; 142221e08768de7fe42ba533ca22baf671420569c07srs GPTPart newPart; 143221e08768de7fe42ba533ca22baf671420569c07srs uint8_t origType; 144221e08768de7fe42ba533ca22baf671420569c07srs uint64_t firstSector, lastSector; 145221e08768de7fe42ba533ca22baf671420569c07srs 146221e08768de7fe42ba533ca22baf671420569c07srs newPart.BlankPartition(); 147221e08768de7fe42ba533ca22baf671420569c07srs origPart = GetPartition(i); 148221e08768de7fe42ba533ca22baf671420569c07srs if (origPart != NULL) { 149221e08768de7fe42ba533ca22baf671420569c07srs origType = origPart->partitionType; 150221e08768de7fe42ba533ca22baf671420569c07srs 151221e08768de7fe42ba533ca22baf671420569c07srs // don't convert extended, hybrid protective, or null (non-existent) 152221e08768de7fe42ba533ca22baf671420569c07srs // partitions (Note similar protection is in GPTData::XFormPartitions(), 153221e08768de7fe42ba533ca22baf671420569c07srs // but I want it here too in case I call this function in another 154221e08768de7fe42ba533ca22baf671420569c07srs // context in the future....) 155e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 156221e08768de7fe42ba533ca22baf671420569c07srs (origType != 0x00) && (origType != 0xEE)) { 157221e08768de7fe42ba533ca22baf671420569c07srs firstSector = (uint64_t) origPart->firstLBA; 158221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetFirstLBA(firstSector); 159221e08768de7fe42ba533ca22baf671420569c07srs lastSector = firstSector + (uint64_t) origPart->lengthLBA; 160221e08768de7fe42ba533ca22baf671420569c07srs if (lastSector > 0) lastSector--; 161221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetLastLBA(lastSector); 162221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetType(((uint16_t) origType) * 0x0100); 1636699b01eda84d24bfaf80ad725304fef2b0e1b2asrs newPart.RandomizeUniqueGUID(); 164221e08768de7fe42ba533ca22baf671420569c07srs newPart.SetAttributes(0); 1656699b01eda84d24bfaf80ad725304fef2b0e1b2asrs newPart.SetName(newPart.GetTypeName()); 166978041ca613dcb881763b36cf53639d924e52a56srs } // if not extended, protective, or non-existent 167978041ca613dcb881763b36cf53639d924e52a56srs } // if (origPart != NULL) 168221e08768de7fe42ba533ca22baf671420569c07srs return newPart; 169221e08768de7fe42ba533ca22baf671420569c07srs} // MBRData::AsGPT() 170978041ca613dcb881763b36cf53639d924e52a56srs 171