1cf200d32Sopenharmony_ci/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
2cf200d32Sopenharmony_ci   data. */
3cf200d32Sopenharmony_ci
4cf200d32Sopenharmony_ci/* Initial coding by Rod Smith, January to February, 2009 */
5cf200d32Sopenharmony_ci
6cf200d32Sopenharmony_ci/* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed
7cf200d32Sopenharmony_ci  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
8cf200d32Sopenharmony_ci
9cf200d32Sopenharmony_ci#define __STDC_LIMIT_MACROS
10cf200d32Sopenharmony_ci#ifndef __STDC_CONSTANT_MACROS
11cf200d32Sopenharmony_ci#define __STDC_CONSTANT_MACROS
12cf200d32Sopenharmony_ci#endif
13cf200d32Sopenharmony_ci
14cf200d32Sopenharmony_ci#include <stdio.h>
15cf200d32Sopenharmony_ci#include <stdlib.h>
16cf200d32Sopenharmony_ci#include <stdint.h>
17cf200d32Sopenharmony_ci#include <fcntl.h>
18cf200d32Sopenharmony_ci#include <string.h>
19cf200d32Sopenharmony_ci#include <time.h>
20cf200d32Sopenharmony_ci#include <sys/stat.h>
21cf200d32Sopenharmony_ci#include <errno.h>
22cf200d32Sopenharmony_ci#include <iostream>
23cf200d32Sopenharmony_ci#include "mbr.h"
24cf200d32Sopenharmony_ci
25cf200d32Sopenharmony_ciusing namespace std;
26cf200d32Sopenharmony_ci
27cf200d32Sopenharmony_ci/****************************************
28cf200d32Sopenharmony_ci *                                      *
29cf200d32Sopenharmony_ci * MBRData class and related structures *
30cf200d32Sopenharmony_ci *                                      *
31cf200d32Sopenharmony_ci ****************************************/
32cf200d32Sopenharmony_ci
33cf200d32Sopenharmony_ciMBRData::~MBRData(void) {
34cf200d32Sopenharmony_ci} // MBRData destructor
35cf200d32Sopenharmony_ci
36cf200d32Sopenharmony_ci// Assignment operator -- copy entire set of MBR data.
37cf200d32Sopenharmony_ciMBRData & MBRData::operator=(const BasicMBRData & orig) {
38cf200d32Sopenharmony_ci   BasicMBRData::operator=(orig);
39cf200d32Sopenharmony_ci   return *this;
40cf200d32Sopenharmony_ci} // MBRData::operator=()
41cf200d32Sopenharmony_ci
42cf200d32Sopenharmony_ci/*****************************************************
43cf200d32Sopenharmony_ci *                                                   *
44cf200d32Sopenharmony_ci * Functions to create, delete, or change partitions *
45cf200d32Sopenharmony_ci *                                                   *
46cf200d32Sopenharmony_ci *****************************************************/
47cf200d32Sopenharmony_ci
48cf200d32Sopenharmony_ci// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
49cf200d32Sopenharmony_civoid MBRData::MakeProtectiveMBR(int clearBoot) {
50cf200d32Sopenharmony_ci
51cf200d32Sopenharmony_ci   EmptyMBR(clearBoot);
52cf200d32Sopenharmony_ci
53cf200d32Sopenharmony_ci   // Initialize variables
54cf200d32Sopenharmony_ci   nulls = 0;
55cf200d32Sopenharmony_ci   MBRSignature = MBR_SIGNATURE;
56cf200d32Sopenharmony_ci   diskSignature = UINT32_C(0);
57cf200d32Sopenharmony_ci
58cf200d32Sopenharmony_ci   partitions[0].SetStatus(0); // Flag the protective part. as unbootable
59cf200d32Sopenharmony_ci
60cf200d32Sopenharmony_ci   partitions[0].SetType(UINT8_C(0xEE));
61cf200d32Sopenharmony_ci   if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
62cf200d32Sopenharmony_ci      partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1));
63cf200d32Sopenharmony_ci   } else { // disk is too big to represent, so fake it...
64cf200d32Sopenharmony_ci      partitions[0].SetLocation(UINT32_C(1), UINT32_MAX);
65cf200d32Sopenharmony_ci   } // if/else
66cf200d32Sopenharmony_ci   partitions[0].SetInclusion(PRIMARY);
67cf200d32Sopenharmony_ci
68cf200d32Sopenharmony_ci   state = gpt;
69cf200d32Sopenharmony_ci} // MBRData::MakeProtectiveMBR()
70cf200d32Sopenharmony_ci
71cf200d32Sopenharmony_ci// Optimizes the size of the 0xEE (EFI GPT) partition
72cf200d32Sopenharmony_civoid MBRData::OptimizeEESize(void) {
73cf200d32Sopenharmony_ci   int i, typeFlag = 0;
74cf200d32Sopenharmony_ci   uint64_t after;
75cf200d32Sopenharmony_ci
76cf200d32Sopenharmony_ci   for (i = 0; i < 4; i++) {
77cf200d32Sopenharmony_ci      // Check for non-empty and non-0xEE partitions
78cf200d32Sopenharmony_ci      if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00))
79cf200d32Sopenharmony_ci         typeFlag++;
80cf200d32Sopenharmony_ci      if (partitions[i].GetType() == 0xEE) {
81cf200d32Sopenharmony_ci         // Blank space before this partition; fill it....
82cf200d32Sopenharmony_ci         if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) {
83cf200d32Sopenharmony_ci            partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1));
84cf200d32Sopenharmony_ci         } // if
85cf200d32Sopenharmony_ci         // Blank space after this partition; fill it....
86cf200d32Sopenharmony_ci         after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA();
87cf200d32Sopenharmony_ci         if (SectorUsedAs(after, 4) == NONE) {
88cf200d32Sopenharmony_ci            partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1);
89cf200d32Sopenharmony_ci         } // if free space after
90cf200d32Sopenharmony_ci         if (after > diskSize) {
91cf200d32Sopenharmony_ci            if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
92cf200d32Sopenharmony_ci               partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA());
93cf200d32Sopenharmony_ci            } else { // disk is too big to represent, so fake it...
94cf200d32Sopenharmony_ci               partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA());
95cf200d32Sopenharmony_ci            } // if/else
96cf200d32Sopenharmony_ci         } // if protective partition is too big
97cf200d32Sopenharmony_ci         RecomputeCHS(i);
98cf200d32Sopenharmony_ci      } // if partition is 0xEE
99cf200d32Sopenharmony_ci   } // for partition loop
100cf200d32Sopenharmony_ci   if (typeFlag == 0) { // No non-hybrid partitions found
101cf200d32Sopenharmony_ci      MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR.
102cf200d32Sopenharmony_ci   } // if
103cf200d32Sopenharmony_ci} // MBRData::OptimizeEESize()
104cf200d32Sopenharmony_ci
105cf200d32Sopenharmony_ci// Delete a partition if one exists at the specified location.
106cf200d32Sopenharmony_ci// Returns 1 if a partition was deleted, 0 otherwise....
107cf200d32Sopenharmony_ci// Used to help keep GPT & hybrid MBR partitions in sync....
108cf200d32Sopenharmony_ciint MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
109cf200d32Sopenharmony_ci   uint32_t start32, length32;
110cf200d32Sopenharmony_ci   int i, deleted = 0;
111cf200d32Sopenharmony_ci
112cf200d32Sopenharmony_ci   if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
113cf200d32Sopenharmony_ci      start32 = (uint32_t) start64;
114cf200d32Sopenharmony_ci      length32 = (uint32_t) length64;
115cf200d32Sopenharmony_ci      for (i = 0; i < MAX_MBR_PARTS; i++) {
116cf200d32Sopenharmony_ci         if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32)
117cf200d32Sopenharmony_ci             && (partitions[i].GetLengthLBA() == length32)) {
118cf200d32Sopenharmony_ci            DeletePartition(i);
119cf200d32Sopenharmony_ci         if (state == hybrid)
120cf200d32Sopenharmony_ci            OptimizeEESize();
121cf200d32Sopenharmony_ci         deleted = 1;
122cf200d32Sopenharmony_ci         } // if (match found)
123cf200d32Sopenharmony_ci      } // for i (partition scan)
124cf200d32Sopenharmony_ci   } // if (hybrid & GPT partition < 2TiB)
125cf200d32Sopenharmony_ci   return deleted;
126cf200d32Sopenharmony_ci} // MBRData::DeleteByLocation()
127cf200d32Sopenharmony_ci
128cf200d32Sopenharmony_ci/******************************************************
129cf200d32Sopenharmony_ci *                                                    *
130cf200d32Sopenharmony_ci * Functions that extract data on specific partitions *
131cf200d32Sopenharmony_ci *                                                    *
132cf200d32Sopenharmony_ci ******************************************************/
133cf200d32Sopenharmony_ci
134cf200d32Sopenharmony_ci// Return the MBR data as a GPT partition....
135cf200d32Sopenharmony_ciGPTPart MBRData::AsGPT(int i) {
136cf200d32Sopenharmony_ci   MBRPart* origPart;
137cf200d32Sopenharmony_ci   GPTPart newPart;
138cf200d32Sopenharmony_ci   uint8_t origType;
139cf200d32Sopenharmony_ci   uint64_t firstSector, lastSector;
140cf200d32Sopenharmony_ci
141cf200d32Sopenharmony_ci   newPart.BlankPartition();
142cf200d32Sopenharmony_ci   origPart = GetPartition(i);
143cf200d32Sopenharmony_ci   if (origPart != NULL) {
144cf200d32Sopenharmony_ci      origType = origPart->GetType();
145cf200d32Sopenharmony_ci
146cf200d32Sopenharmony_ci      // don't convert extended, hybrid protective, or null (non-existent)
147cf200d32Sopenharmony_ci      // partitions (Note similar protection is in GPTData::XFormPartitions(),
148cf200d32Sopenharmony_ci      // but I want it here too in case I call this function in another
149cf200d32Sopenharmony_ci      // context in the future....)
150cf200d32Sopenharmony_ci      if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
151cf200d32Sopenharmony_ci          (origType != 0x00) && (origType != 0xEE)) {
152cf200d32Sopenharmony_ci         firstSector = (uint64_t) origPart->GetStartLBA();
153cf200d32Sopenharmony_ci         newPart.SetFirstLBA(firstSector);
154cf200d32Sopenharmony_ci         lastSector = (uint64_t) origPart->GetLastLBA();
155cf200d32Sopenharmony_ci         newPart.SetLastLBA(lastSector);
156cf200d32Sopenharmony_ci         newPart.SetType(((uint16_t) origType) * 0x0100);
157cf200d32Sopenharmony_ci         newPart.RandomizeUniqueGUID();
158cf200d32Sopenharmony_ci         newPart.SetAttributes(0);
159cf200d32Sopenharmony_ci         newPart.SetName(newPart.GetTypeName());
160cf200d32Sopenharmony_ci      } // if not extended, protective, or non-existent
161cf200d32Sopenharmony_ci   } // if (origPart != NULL)
162cf200d32Sopenharmony_ci   return newPart;
163cf200d32Sopenharmony_ci} // MBRData::AsGPT()
164cf200d32Sopenharmony_ci
165