srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1 | /* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition |
| 2 | data. */ |
| 3 | |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 4 | /* Initial coding by Rod Smith, January to February, 2009 */ |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 5 | |
Roderick W. Smith | e3ee733 | 2013-09-24 12:56:11 -0400 | [diff] [blame] | 6 | /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 7 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ |
| 8 | |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 9 | #define __STDC_LIMIT_MACROS |
Aurimas Liutikas | fcad060 | 2016-05-10 19:16:10 -0700 | [diff] [blame] | 10 | #ifndef __STDC_CONSTANT_MACROS |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 11 | #define __STDC_CONSTANT_MACROS |
Aurimas Liutikas | fcad060 | 2016-05-10 19:16:10 -0700 | [diff] [blame] | 12 | #endif |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 13 | |
| 14 | #include <stdio.h> |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 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> |
srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 22 | #include <iostream> |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 23 | #include "mbr.h" |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 24 | |
| 25 | using namespace std; |
| 26 | |
| 27 | /**************************************** |
| 28 | * * |
| 29 | * MBRData class and related structures * |
| 30 | * * |
| 31 | ****************************************/ |
| 32 | |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 33 | /* // Assignment operator -- copy entire set of MBR data. |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 34 | MBRData & MBRData::operator=(const MBRData & orig) { |
| 35 | BasicMBRData::operator=(orig); |
| 36 | return *this; |
| 37 | } // MBRData::operator=() */ |
srs5694 | 327129e | 2010-09-22 01:07:31 -0400 | [diff] [blame] | 38 | |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 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 | |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 45 | /***************************************************** |
| 46 | * * |
| 47 | * Functions to create, delete, or change partitions * |
| 48 | * * |
| 49 | *****************************************************/ |
| 50 | |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 51 | // Create a protective MBR. Clears the boot loader area if clearBoot > 0. |
| 52 | void MBRData::MakeProtectiveMBR(int clearBoot) { |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 53 | |
| 54 | EmptyMBR(clearBoot); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 55 | |
| 56 | // Initialize variables |
| 57 | nulls = 0; |
| 58 | MBRSignature = MBR_SIGNATURE; |
srs5694 | 8a4ddfc | 2010-03-21 19:05:49 -0400 | [diff] [blame] | 59 | diskSignature = UINT32_C(0); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 60 | |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 61 | partitions[0].SetStatus(0); // Flag the protective part. as unbootable |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 62 | |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 63 | partitions[0].SetType(UINT8_C(0xEE)); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 64 | if (diskSize < UINT32_MAX) { // If the disk is under 2TiB |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 65 | partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1)); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 66 | } else { // disk is too big to represent, so fake it... |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 67 | partitions[0].SetLocation(UINT32_C(1), UINT32_MAX); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 68 | } // if/else |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 69 | partitions[0].SetInclusion(PRIMARY); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 70 | |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 71 | state = gpt; |
| 72 | } // MBRData::MakeProtectiveMBR() |
| 73 | |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 74 | // Optimizes the size of the 0xEE (EFI GPT) partition |
| 75 | void MBRData::OptimizeEESize(void) { |
| 76 | int i, typeFlag = 0; |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 77 | uint64_t after; |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 78 | |
| 79 | for (i = 0; i < 4; i++) { |
| 80 | // Check for non-empty and non-0xEE partitions |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 81 | if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00)) |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 82 | typeFlag++; |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 83 | if (partitions[i].GetType() == 0xEE) { |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 84 | // Blank space before this partition; fill it.... |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 85 | if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) { |
| 86 | partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1)); |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 87 | } // if |
| 88 | // Blank space after this partition; fill it.... |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 89 | after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA(); |
| 90 | if (SectorUsedAs(after, 4) == NONE) { |
| 91 | partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1); |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 92 | } // if free space after |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 93 | if (after > diskSize) { |
| 94 | if (diskSize < UINT32_MAX) { // If the disk is under 2TiB |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 95 | partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA()); |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 96 | } else { // disk is too big to represent, so fake it... |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 97 | partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA()); |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 98 | } // if/else |
| 99 | } // if protective partition is too big |
| 100 | RecomputeCHS(i); |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 101 | } // if partition is 0xEE |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 102 | } // for partition loop |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 103 | if (typeFlag == 0) { // No non-hybrid partitions found |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 104 | MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 105 | } // if |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 106 | } // MBRData::OptimizeEESize() |
| 107 | |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 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; |
srs5694 | 9ba5421 | 2010-05-18 23:24:02 -0400 | [diff] [blame] | 114 | |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 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++) { |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 119 | if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32) |
| 120 | && (partitions[i].GetLengthLBA() == length32)) { |
srs5694 | 64cbd17 | 2011-03-01 22:03:54 -0500 | [diff] [blame] | 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() |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 130 | |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 131 | /****************************************************** |
| 132 | * * |
| 133 | * Functions that extract data on specific partitions * |
| 134 | * * |
| 135 | ******************************************************/ |
| 136 | |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 137 | // Return the MBR data as a GPT partition.... |
| 138 | GPTPart MBRData::AsGPT(int i) { |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 139 | MBRPart* origPart; |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 140 | GPTPart newPart; |
| 141 | uint8_t origType; |
| 142 | uint64_t firstSector, lastSector; |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 143 | |
| 144 | newPart.BlankPartition(); |
| 145 | origPart = GetPartition(i); |
| 146 | if (origPart != NULL) { |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 147 | origType = origPart->GetType(); |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 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....) |
srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 153 | if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 154 | (origType != 0x00) && (origType != 0xEE)) { |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 155 | firstSector = (uint64_t) origPart->GetStartLBA(); |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 156 | newPart.SetFirstLBA(firstSector); |
srs5694 | bf8950c | 2011-03-12 01:23:12 -0500 | [diff] [blame] | 157 | lastSector = (uint64_t) origPart->GetLastLBA(); |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 158 | newPart.SetLastLBA(lastSector); |
| 159 | newPart.SetType(((uint16_t) origType) * 0x0100); |
srs5694 | 6699b01 | 2010-02-04 00:55:30 -0500 | [diff] [blame] | 160 | newPart.RandomizeUniqueGUID(); |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 161 | newPart.SetAttributes(0); |
srs5694 | 6699b01 | 2010-02-04 00:55:30 -0500 | [diff] [blame] | 162 | newPart.SetName(newPart.GetTypeName()); |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 163 | } // if not extended, protective, or non-existent |
| 164 | } // if (origPart != NULL) |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 165 | return newPart; |
| 166 | } // MBRData::AsGPT() |
srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 167 | |