blob: 415aaf6072b769f0632170f5ace4d4f33c818aaa [file] [log] [blame]
srs5694e7b4ff92009-08-18 13:16:10 -04001/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
2 data. */
3
srs5694978041c2009-09-21 20:51:47 -04004/* Initial coding by Rod Smith, January to February, 2009 */
srs5694e7b4ff92009-08-18 13:16:10 -04005
srs5694221e0872009-08-29 15:00:31 -04006/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
7 under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
8
srs5694e7b4ff92009-08-18 13:16:10 -04009#define __STDC_LIMIT_MACROS
10#define __STDC_CONSTANT_MACROS
11
12#include <stdio.h>
srs5694e7b4ff92009-08-18 13:16:10 -040013#include <stdlib.h>
14#include <stdint.h>
15#include <fcntl.h>
16#include <string.h>
17#include <time.h>
18#include <sys/stat.h>
19#include <errno.h>
srs5694fed16d02010-01-27 23:03:40 -050020#include <iostream>
srs5694e7b4ff92009-08-18 13:16:10 -040021#include "mbr.h"
srs5694e7b4ff92009-08-18 13:16:10 -040022
23using namespace std;
24
25/****************************************
26 * *
27 * MBRData class and related structures *
28 * *
29 ****************************************/
30
srs569464cbd172011-03-01 22:03:54 -050031// Assignment operator -- copy entire set of MBR data.
32MBRData & MBRData::operator=(const MBRData & orig) {
33 BasicMBRData::operator=(orig);
34 return *this;
35} // MBRData::operator=() */
srs5694327129e2010-09-22 01:07:31 -040036
srs5694978041c2009-09-21 20:51:47 -040037/*****************************************************
38 * *
39 * Functions to create, delete, or change partitions *
40 * *
41 *****************************************************/
42
srs5694221e0872009-08-29 15:00:31 -040043// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
44void MBRData::MakeProtectiveMBR(int clearBoot) {
srs5694978041c2009-09-21 20:51:47 -040045
46 EmptyMBR(clearBoot);
srs5694e7b4ff92009-08-18 13:16:10 -040047
48 // Initialize variables
49 nulls = 0;
50 MBRSignature = MBR_SIGNATURE;
srs56948a4ddfc2010-03-21 19:05:49 -040051 diskSignature = UINT32_C(0);
srs5694e7b4ff92009-08-18 13:16:10 -040052
53 partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
54
srs5694e7b4ff92009-08-18 13:16:10 -040055 partitions[0].partitionType = UINT8_C(0xEE);
56 partitions[0].firstLBA = UINT32_C(1);
57 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
srs5694978041c2009-09-21 20:51:47 -040058 partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
srs5694e7b4ff92009-08-18 13:16:10 -040059 } else { // disk is too big to represent, so fake it...
60 partitions[0].lengthLBA = UINT32_MAX;
61 } // if/else
62
srs569455d92612010-03-07 22:16:07 -050063 // Write CHS data. This maxes out the use of the disk, as much as
64 // possible -- even to the point of exceeding the capacity of sub-8GB
65 // disks. The EFI spec says to use 0xffffff as the ending value,
66 // although normal MBR disks max out at 0xfeffff. FWIW, both GNU Parted
67 // and Apple's Disk Utility use 0xfeffff, and the latter puts that
68 // value in for the FIRST sector, too!
69 LBAtoCHS(1, partitions[0].firstSector);
70 if (LBAtoCHS(partitions[0].lengthLBA, partitions[0].lastSector) == 0)
71 partitions[0].lastSector[0] = 0xFF;
72
srs5694e7b4ff92009-08-18 13:16:10 -040073 state = gpt;
74} // MBRData::MakeProtectiveMBR()
75
srs5694e4ac11e2009-08-31 10:13:04 -040076// Optimizes the size of the 0xEE (EFI GPT) partition
77void MBRData::OptimizeEESize(void) {
78 int i, typeFlag = 0;
79 uint32_t after;
80
81 for (i = 0; i < 4; i++) {
82 // Check for non-empty and non-0xEE partitions
83 if ((partitions[i].partitionType != 0xEE) && (partitions[i].partitionType != 0x00))
84 typeFlag++;
85 if (partitions[i].partitionType == 0xEE) {
86 // Blank space before this partition; fill it....
87 if (IsFree(partitions[i].firstLBA - 1)) {
88 partitions[i].firstLBA = FindFirstInFree(partitions[i].firstLBA - 1);
89 } // if
90 // Blank space after this partition; fill it....
91 after = partitions[i].firstLBA + partitions[i].lengthLBA;
92 if (IsFree(after)) {
93 partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
94 } // if free space after
srs569464cbd172011-03-01 22:03:54 -050095 if (after > diskSize) {
96 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
97 partitions[0].lengthLBA = (uint32_t) diskSize - partitions[i].firstLBA;
98 } else { // disk is too big to represent, so fake it...
99 partitions[0].lengthLBA = UINT32_MAX - partitions[i].firstLBA;
100 } // if/else
101 } // if protective partition is too big
102 RecomputeCHS(i);
srs5694e4ac11e2009-08-31 10:13:04 -0400103 } // if partition is 0xEE
srs5694e4ac11e2009-08-31 10:13:04 -0400104 } // for partition loop
srs5694978041c2009-09-21 20:51:47 -0400105 if (typeFlag == 0) { // No non-hybrid partitions found
srs569464cbd172011-03-01 22:03:54 -0500106 MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR.
srs5694978041c2009-09-21 20:51:47 -0400107 } // if
srs5694e4ac11e2009-08-31 10:13:04 -0400108} // MBRData::OptimizeEESize()
109
srs569464cbd172011-03-01 22:03:54 -0500110// Delete a partition if one exists at the specified location.
111// Returns 1 if a partition was deleted, 0 otherwise....
112// Used to help keep GPT & hybrid MBR partitions in sync....
113int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
114 uint32_t start32, length32;
115 int i, deleted = 0;
srs56949ba54212010-05-18 23:24:02 -0400116
srs569464cbd172011-03-01 22:03:54 -0500117 if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
118 start32 = (uint32_t) start64;
119 length32 = (uint32_t) length64;
120 for (i = 0; i < MAX_MBR_PARTS; i++) {
121 if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA == length32) &&
122 (partitions[i].partitionType != 0xEE)) {
123 DeletePartition(i);
124 if (state == hybrid)
125 OptimizeEESize();
126 deleted = 1;
127 } // if (match found)
128 } // for i (partition scan)
129 } // if (hybrid & GPT partition < 2TiB)
130 return deleted;
131} // MBRData::DeleteByLocation()
srs5694c0ca8f82009-08-20 21:35:25 -0400132
srs5694978041c2009-09-21 20:51:47 -0400133/******************************************************
134 * *
135 * Functions that extract data on specific partitions *
136 * *
137 ******************************************************/
138
srs5694221e0872009-08-29 15:00:31 -0400139// Return the MBR data as a GPT partition....
140GPTPart MBRData::AsGPT(int i) {
141 MBRRecord* origPart;
142 GPTPart newPart;
143 uint8_t origType;
144 uint64_t firstSector, lastSector;
srs5694221e0872009-08-29 15:00:31 -0400145
146 newPart.BlankPartition();
147 origPart = GetPartition(i);
148 if (origPart != NULL) {
149 origType = origPart->partitionType;
150
151 // don't convert extended, hybrid protective, or null (non-existent)
152 // partitions (Note similar protection is in GPTData::XFormPartitions(),
153 // but I want it here too in case I call this function in another
154 // context in the future....)
srs5694e35eb1b2009-09-14 00:29:34 -0400155 if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
srs5694221e0872009-08-29 15:00:31 -0400156 (origType != 0x00) && (origType != 0xEE)) {
157 firstSector = (uint64_t) origPart->firstLBA;
158 newPart.SetFirstLBA(firstSector);
159 lastSector = firstSector + (uint64_t) origPart->lengthLBA;
160 if (lastSector > 0) lastSector--;
161 newPart.SetLastLBA(lastSector);
162 newPart.SetType(((uint16_t) origType) * 0x0100);
srs56946699b012010-02-04 00:55:30 -0500163 newPart.RandomizeUniqueGUID();
srs5694221e0872009-08-29 15:00:31 -0400164 newPart.SetAttributes(0);
srs56946699b012010-02-04 00:55:30 -0500165 newPart.SetName(newPart.GetTypeName());
srs5694978041c2009-09-21 20:51:47 -0400166 } // if not extended, protective, or non-existent
167 } // if (origPart != NULL)
srs5694221e0872009-08-29 15:00:31 -0400168 return newPart;
169} // MBRData::AsGPT()
srs5694978041c2009-09-21 20:51:47 -0400170