summaryrefslogtreecommitdiff
path: root/mbr.cc
blob: c3483a04ac1a17266c465a18fdf84a44984d0bb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* 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
#define __STDC_CONSTANT_MACROS

#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()