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.
operator =(const BasicMBRData & orig)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.
MakeProtectiveMBR(int clearBoot)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
OptimizeEESize(void)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....
DeleteByLocation(uint64_t start64,uint64_t length64)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....
AsGPT(int i)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