Blame mbr.cc

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