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