You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
6.0 KiB
165 lines
6.0 KiB
/* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <iostream>
|
|
#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()
|
|
|