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