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