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