blob: d317f522e06a3aa33c178c03df06136d97626e9a [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
Roderick W. Smithe3ee7332013-09-24 12:56:11 -04006/* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed
srs5694221e0872009-08-29 15:00:31 -04007 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
Aurimas Liutikasfcad0602016-05-10 19:16:10 -070010#ifndef __STDC_CONSTANT_MACROS
srs5694e7b4ff92009-08-18 13:16:10 -040011#define __STDC_CONSTANT_MACROS
Aurimas Liutikasfcad0602016-05-10 19:16:10 -070012#endif
srs5694e7b4ff92009-08-18 13:16:10 -040013
14#include <stdio.h>
srs5694e7b4ff92009-08-18 13:16:10 -040015#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>
srs5694fed16d02010-01-27 23:03:40 -050022#include <iostream>
srs5694e7b4ff92009-08-18 13:16:10 -040023#include "mbr.h"
srs5694e7b4ff92009-08-18 13:16:10 -040024
25using namespace std;
26
27/****************************************
28 * *
29 * MBRData class and related structures *
30 * *
31 ****************************************/
32
Aurimas Liutikas74b74902016-05-10 18:53:54 -070033MBRData::~MBRData(void) {
34} // MBRData destructor
35
srs5694bf8950c2011-03-12 01:23:12 -050036/* // Assignment operator -- copy entire set of MBR data.
srs569464cbd172011-03-01 22:03:54 -050037MBRData & MBRData::operator=(const MBRData & orig) {
38 BasicMBRData::operator=(orig);
39 return *this;
40} // MBRData::operator=() */
srs5694327129e2010-09-22 01:07:31 -040041
srs5694bf8950c2011-03-12 01:23:12 -050042// Assignment operator -- copy entire set of MBR data.
43MBRData & MBRData::operator=(const BasicMBRData & orig) {
44 BasicMBRData::operator=(orig);
45 return *this;
46} // MBRData::operator=()
47
srs5694978041c2009-09-21 20:51:47 -040048/*****************************************************
49 * *
50 * Functions to create, delete, or change partitions *
51 * *
52 *****************************************************/
53
srs5694221e0872009-08-29 15:00:31 -040054// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
55void MBRData::MakeProtectiveMBR(int clearBoot) {
srs5694978041c2009-09-21 20:51:47 -040056
57 EmptyMBR(clearBoot);
srs5694e7b4ff92009-08-18 13:16:10 -040058
59 // Initialize variables
60 nulls = 0;
61 MBRSignature = MBR_SIGNATURE;
srs56948a4ddfc2010-03-21 19:05:49 -040062 diskSignature = UINT32_C(0);
srs5694e7b4ff92009-08-18 13:16:10 -040063
srs5694bf8950c2011-03-12 01:23:12 -050064 partitions[0].SetStatus(0); // Flag the protective part. as unbootable
srs5694e7b4ff92009-08-18 13:16:10 -040065
srs5694bf8950c2011-03-12 01:23:12 -050066 partitions[0].SetType(UINT8_C(0xEE));
srs5694e7b4ff92009-08-18 13:16:10 -040067 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
srs5694bf8950c2011-03-12 01:23:12 -050068 partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1));
srs5694e7b4ff92009-08-18 13:16:10 -040069 } else { // disk is too big to represent, so fake it...
srs5694bf8950c2011-03-12 01:23:12 -050070 partitions[0].SetLocation(UINT32_C(1), UINT32_MAX);
srs5694e7b4ff92009-08-18 13:16:10 -040071 } // if/else
srs5694bf8950c2011-03-12 01:23:12 -050072 partitions[0].SetInclusion(PRIMARY);
srs5694e7b4ff92009-08-18 13:16:10 -040073
srs5694e7b4ff92009-08-18 13:16:10 -040074 state = gpt;
75} // MBRData::MakeProtectiveMBR()
76
srs5694e4ac11e2009-08-31 10:13:04 -040077// Optimizes the size of the 0xEE (EFI GPT) partition
78void MBRData::OptimizeEESize(void) {
79 int i, typeFlag = 0;
srs5694bf8950c2011-03-12 01:23:12 -050080 uint64_t after;
srs5694e4ac11e2009-08-31 10:13:04 -040081
82 for (i = 0; i < 4; i++) {
83 // Check for non-empty and non-0xEE partitions
srs5694bf8950c2011-03-12 01:23:12 -050084 if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00))
srs5694e4ac11e2009-08-31 10:13:04 -040085 typeFlag++;
srs5694bf8950c2011-03-12 01:23:12 -050086 if (partitions[i].GetType() == 0xEE) {
srs5694e4ac11e2009-08-31 10:13:04 -040087 // Blank space before this partition; fill it....
srs5694bf8950c2011-03-12 01:23:12 -050088 if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) {
89 partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1));
srs5694e4ac11e2009-08-31 10:13:04 -040090 } // if
91 // Blank space after this partition; fill it....
srs5694bf8950c2011-03-12 01:23:12 -050092 after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA();
93 if (SectorUsedAs(after, 4) == NONE) {
94 partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1);
srs5694e4ac11e2009-08-31 10:13:04 -040095 } // if free space after
srs569464cbd172011-03-01 22:03:54 -050096 if (after > diskSize) {
97 if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
srs5694bf8950c2011-03-12 01:23:12 -050098 partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA());
srs569464cbd172011-03-01 22:03:54 -050099 } else { // disk is too big to represent, so fake it...
srs5694bf8950c2011-03-12 01:23:12 -0500100 partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA());
srs569464cbd172011-03-01 22:03:54 -0500101 } // if/else
102 } // if protective partition is too big
103 RecomputeCHS(i);
srs5694e4ac11e2009-08-31 10:13:04 -0400104 } // if partition is 0xEE
srs5694e4ac11e2009-08-31 10:13:04 -0400105 } // for partition loop
srs5694978041c2009-09-21 20:51:47 -0400106 if (typeFlag == 0) { // No non-hybrid partitions found
srs569464cbd172011-03-01 22:03:54 -0500107 MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR.
srs5694978041c2009-09-21 20:51:47 -0400108 } // if
srs5694e4ac11e2009-08-31 10:13:04 -0400109} // MBRData::OptimizeEESize()
110
srs569464cbd172011-03-01 22:03:54 -0500111// Delete a partition if one exists at the specified location.
112// Returns 1 if a partition was deleted, 0 otherwise....
113// Used to help keep GPT & hybrid MBR partitions in sync....
114int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
115 uint32_t start32, length32;
116 int i, deleted = 0;
srs56949ba54212010-05-18 23:24:02 -0400117
srs569464cbd172011-03-01 22:03:54 -0500118 if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
119 start32 = (uint32_t) start64;
120 length32 = (uint32_t) length64;
121 for (i = 0; i < MAX_MBR_PARTS; i++) {
srs5694bf8950c2011-03-12 01:23:12 -0500122 if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32)
123 && (partitions[i].GetLengthLBA() == length32)) {
srs569464cbd172011-03-01 22:03:54 -0500124 DeletePartition(i);
125 if (state == hybrid)
126 OptimizeEESize();
127 deleted = 1;
128 } // if (match found)
129 } // for i (partition scan)
130 } // if (hybrid & GPT partition < 2TiB)
131 return deleted;
132} // MBRData::DeleteByLocation()
srs5694c0ca8f82009-08-20 21:35:25 -0400133
srs5694978041c2009-09-21 20:51:47 -0400134/******************************************************
135 * *
136 * Functions that extract data on specific partitions *
137 * *
138 ******************************************************/
139
srs5694221e0872009-08-29 15:00:31 -0400140// Return the MBR data as a GPT partition....
141GPTPart MBRData::AsGPT(int i) {
srs5694bf8950c2011-03-12 01:23:12 -0500142 MBRPart* origPart;
srs5694221e0872009-08-29 15:00:31 -0400143 GPTPart newPart;
144 uint8_t origType;
145 uint64_t firstSector, lastSector;
srs5694221e0872009-08-29 15:00:31 -0400146
147 newPart.BlankPartition();
148 origPart = GetPartition(i);
149 if (origPart != NULL) {
srs5694bf8950c2011-03-12 01:23:12 -0500150 origType = origPart->GetType();
srs5694221e0872009-08-29 15:00:31 -0400151
152 // don't convert extended, hybrid protective, or null (non-existent)
153 // partitions (Note similar protection is in GPTData::XFormPartitions(),
154 // but I want it here too in case I call this function in another
155 // context in the future....)
srs5694e35eb1b2009-09-14 00:29:34 -0400156 if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
srs5694221e0872009-08-29 15:00:31 -0400157 (origType != 0x00) && (origType != 0xEE)) {
srs5694bf8950c2011-03-12 01:23:12 -0500158 firstSector = (uint64_t) origPart->GetStartLBA();
srs5694221e0872009-08-29 15:00:31 -0400159 newPart.SetFirstLBA(firstSector);
srs5694bf8950c2011-03-12 01:23:12 -0500160 lastSector = (uint64_t) origPart->GetLastLBA();
srs5694221e0872009-08-29 15:00:31 -0400161 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