mbr.cc revision 64cbd171067eb34054741bfcd73f0b91d727a371
1e7b4ff9317fc4e551cf974684eaa88697de5a28srs/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
2e7b4ff9317fc4e551cf974684eaa88697de5a28srs   data. */
3e7b4ff9317fc4e551cf974684eaa88697de5a28srs
4978041ca613dcb881763b36cf53639d924e52a56srs/* Initial coding by Rod Smith, January to February, 2009 */
5e7b4ff9317fc4e551cf974684eaa88697de5a28srs
6221e08768de7fe42ba533ca22baf671420569c07srs/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
7221e08768de7fe42ba533ca22baf671420569c07srs  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
8221e08768de7fe42ba533ca22baf671420569c07srs
9e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_LIMIT_MACROS
10e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_CONSTANT_MACROS
11e7b4ff9317fc4e551cf974684eaa88697de5a28srs
12e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdio.h>
13e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdlib.h>
14e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdint.h>
15e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <fcntl.h>
16e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <string.h>
17e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <time.h>
18e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <sys/stat.h>
19e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <errno.h>
20fed16d043a14e8b86c97a6413aec7281fefcbcb5srs#include <iostream>
21e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "mbr.h"
22e7b4ff9317fc4e551cf974684eaa88697de5a28srs
23e7b4ff9317fc4e551cf974684eaa88697de5a28srsusing namespace std;
24e7b4ff9317fc4e551cf974684eaa88697de5a28srs
25e7b4ff9317fc4e551cf974684eaa88697de5a28srs/****************************************
26e7b4ff9317fc4e551cf974684eaa88697de5a28srs *                                      *
27e7b4ff9317fc4e551cf974684eaa88697de5a28srs * MBRData class and related structures *
28e7b4ff9317fc4e551cf974684eaa88697de5a28srs *                                      *
29e7b4ff9317fc4e551cf974684eaa88697de5a28srs ****************************************/
30e7b4ff9317fc4e551cf974684eaa88697de5a28srs
3164cbd171067eb34054741bfcd73f0b91d727a371srs// Assignment operator -- copy entire set of MBR data.
3264cbd171067eb34054741bfcd73f0b91d727a371srsMBRData & MBRData::operator=(const MBRData & orig) {
3364cbd171067eb34054741bfcd73f0b91d727a371srs   BasicMBRData::operator=(orig);
3464cbd171067eb34054741bfcd73f0b91d727a371srs   return *this;
3564cbd171067eb34054741bfcd73f0b91d727a371srs} // MBRData::operator=() */
36327129e9331f888a8fc08d688dcb0a739a3c17besrs
37978041ca613dcb881763b36cf53639d924e52a56srs/*****************************************************
38978041ca613dcb881763b36cf53639d924e52a56srs *                                                   *
39978041ca613dcb881763b36cf53639d924e52a56srs * Functions to create, delete, or change partitions *
40978041ca613dcb881763b36cf53639d924e52a56srs *                                                   *
41978041ca613dcb881763b36cf53639d924e52a56srs *****************************************************/
42978041ca613dcb881763b36cf53639d924e52a56srs
43221e08768de7fe42ba533ca22baf671420569c07srs// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
44221e08768de7fe42ba533ca22baf671420569c07srsvoid MBRData::MakeProtectiveMBR(int clearBoot) {
45978041ca613dcb881763b36cf53639d924e52a56srs
46978041ca613dcb881763b36cf53639d924e52a56srs   EmptyMBR(clearBoot);
47e7b4ff9317fc4e551cf974684eaa88697de5a28srs
48e7b4ff9317fc4e551cf974684eaa88697de5a28srs   // Initialize variables
49e7b4ff9317fc4e551cf974684eaa88697de5a28srs   nulls = 0;
50e7b4ff9317fc4e551cf974684eaa88697de5a28srs   MBRSignature = MBR_SIGNATURE;
518a4ddfc919d5569c68489cf53d9cf5abc94c410csrs   diskSignature = UINT32_C(0);
52e7b4ff9317fc4e551cf974684eaa88697de5a28srs
53e7b4ff9317fc4e551cf974684eaa88697de5a28srs   partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
54e7b4ff9317fc4e551cf974684eaa88697de5a28srs
55e7b4ff9317fc4e551cf974684eaa88697de5a28srs   partitions[0].partitionType = UINT8_C(0xEE);
56e7b4ff9317fc4e551cf974684eaa88697de5a28srs   partitions[0].firstLBA = UINT32_C(1);
57e7b4ff9317fc4e551cf974684eaa88697de5a28srs   if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
58978041ca613dcb881763b36cf53639d924e52a56srs      partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
59e7b4ff9317fc4e551cf974684eaa88697de5a28srs   } else { // disk is too big to represent, so fake it...
60e7b4ff9317fc4e551cf974684eaa88697de5a28srs      partitions[0].lengthLBA = UINT32_MAX;
61e7b4ff9317fc4e551cf974684eaa88697de5a28srs   } // if/else
62e7b4ff9317fc4e551cf974684eaa88697de5a28srs
6355d926192adc984462509b2966e23bc0d1129bbdsrs   // Write CHS data. This maxes out the use of the disk, as much as
6455d926192adc984462509b2966e23bc0d1129bbdsrs   // possible -- even to the point of exceeding the capacity of sub-8GB
6555d926192adc984462509b2966e23bc0d1129bbdsrs   // disks. The EFI spec says to use 0xffffff as the ending value,
6655d926192adc984462509b2966e23bc0d1129bbdsrs   // although normal MBR disks max out at 0xfeffff. FWIW, both GNU Parted
6755d926192adc984462509b2966e23bc0d1129bbdsrs   // and Apple's Disk Utility use 0xfeffff, and the latter puts that
6855d926192adc984462509b2966e23bc0d1129bbdsrs   // value in for the FIRST sector, too!
6955d926192adc984462509b2966e23bc0d1129bbdsrs   LBAtoCHS(1, partitions[0].firstSector);
7055d926192adc984462509b2966e23bc0d1129bbdsrs   if (LBAtoCHS(partitions[0].lengthLBA, partitions[0].lastSector) == 0)
7155d926192adc984462509b2966e23bc0d1129bbdsrs      partitions[0].lastSector[0] = 0xFF;
7255d926192adc984462509b2966e23bc0d1129bbdsrs
73e7b4ff9317fc4e551cf974684eaa88697de5a28srs   state = gpt;
74e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // MBRData::MakeProtectiveMBR()
75e7b4ff9317fc4e551cf974684eaa88697de5a28srs
76e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Optimizes the size of the 0xEE (EFI GPT) partition
77e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid MBRData::OptimizeEESize(void) {
78e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs   int i, typeFlag = 0;
79e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs   uint32_t after;
80e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs
81e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs   for (i = 0; i < 4; i++) {
82e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs      // Check for non-empty and non-0xEE partitions
83e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs      if ((partitions[i].partitionType != 0xEE) && (partitions[i].partitionType != 0x00))
84e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         typeFlag++;
85e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs      if (partitions[i].partitionType == 0xEE) {
86e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         // Blank space before this partition; fill it....
87e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         if (IsFree(partitions[i].firstLBA - 1)) {
88e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs            partitions[i].firstLBA = FindFirstInFree(partitions[i].firstLBA - 1);
89e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         } // if
90e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         // Blank space after this partition; fill it....
91e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         after = partitions[i].firstLBA + partitions[i].lengthLBA;
92e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         if (IsFree(after)) {
93e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs            partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
94e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs         } // if free space after
9564cbd171067eb34054741bfcd73f0b91d727a371srs         if (after > diskSize) {
9664cbd171067eb34054741bfcd73f0b91d727a371srs            if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
9764cbd171067eb34054741bfcd73f0b91d727a371srs               partitions[0].lengthLBA = (uint32_t) diskSize - partitions[i].firstLBA;
9864cbd171067eb34054741bfcd73f0b91d727a371srs            } else { // disk is too big to represent, so fake it...
9964cbd171067eb34054741bfcd73f0b91d727a371srs               partitions[0].lengthLBA = UINT32_MAX - partitions[i].firstLBA;
10064cbd171067eb34054741bfcd73f0b91d727a371srs            } // if/else
10164cbd171067eb34054741bfcd73f0b91d727a371srs         } // if protective partition is too big
10264cbd171067eb34054741bfcd73f0b91d727a371srs         RecomputeCHS(i);
103e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs      } // if partition is 0xEE
104e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs   } // for partition loop
105978041ca613dcb881763b36cf53639d924e52a56srs   if (typeFlag == 0) { // No non-hybrid partitions found
10664cbd171067eb34054741bfcd73f0b91d727a371srs      MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR.
107e7b4ff9317fc4e551cf974684eaa88697de5a28srs   } // if
108978041ca613dcb881763b36cf53639d924e52a56srs} // MBRData::OptimizeEESize()
109e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs
11064cbd171067eb34054741bfcd73f0b91d727a371srs// Delete a partition if one exists at the specified location.
11164cbd171067eb34054741bfcd73f0b91d727a371srs// Returns 1 if a partition was deleted, 0 otherwise....
11264cbd171067eb34054741bfcd73f0b91d727a371srs// Used to help keep GPT & hybrid MBR partitions in sync....
11364cbd171067eb34054741bfcd73f0b91d727a371srsint MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
11464cbd171067eb34054741bfcd73f0b91d727a371srs   uint32_t start32, length32;
11564cbd171067eb34054741bfcd73f0b91d727a371srs   int i, deleted = 0;
116e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs
11764cbd171067eb34054741bfcd73f0b91d727a371srs   if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
11864cbd171067eb34054741bfcd73f0b91d727a371srs      start32 = (uint32_t) start64;
11964cbd171067eb34054741bfcd73f0b91d727a371srs      length32 = (uint32_t) length64;
12064cbd171067eb34054741bfcd73f0b91d727a371srs      for (i = 0; i < MAX_MBR_PARTS; i++) {
12164cbd171067eb34054741bfcd73f0b91d727a371srs         if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA == length32) &&
12264cbd171067eb34054741bfcd73f0b91d727a371srs            (partitions[i].partitionType != 0xEE)) {
12364cbd171067eb34054741bfcd73f0b91d727a371srs            DeletePartition(i);
12464cbd171067eb34054741bfcd73f0b91d727a371srs         if (state == hybrid)
12564cbd171067eb34054741bfcd73f0b91d727a371srs            OptimizeEESize();
12664cbd171067eb34054741bfcd73f0b91d727a371srs         deleted = 1;
12764cbd171067eb34054741bfcd73f0b91d727a371srs         } // if (match found)
12864cbd171067eb34054741bfcd73f0b91d727a371srs      } // for i (partition scan)
12964cbd171067eb34054741bfcd73f0b91d727a371srs   } // if (hybrid & GPT partition < 2TiB)
13064cbd171067eb34054741bfcd73f0b91d727a371srs   return deleted;
13164cbd171067eb34054741bfcd73f0b91d727a371srs} // MBRData::DeleteByLocation()
132c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs
133978041ca613dcb881763b36cf53639d924e52a56srs/******************************************************
134978041ca613dcb881763b36cf53639d924e52a56srs *                                                    *
135978041ca613dcb881763b36cf53639d924e52a56srs * Functions that extract data on specific partitions *
136978041ca613dcb881763b36cf53639d924e52a56srs *                                                    *
137978041ca613dcb881763b36cf53639d924e52a56srs ******************************************************/
138978041ca613dcb881763b36cf53639d924e52a56srs
139221e08768de7fe42ba533ca22baf671420569c07srs// Return the MBR data as a GPT partition....
140221e08768de7fe42ba533ca22baf671420569c07srsGPTPart MBRData::AsGPT(int i) {
141221e08768de7fe42ba533ca22baf671420569c07srs   MBRRecord* origPart;
142221e08768de7fe42ba533ca22baf671420569c07srs   GPTPart newPart;
143221e08768de7fe42ba533ca22baf671420569c07srs   uint8_t origType;
144221e08768de7fe42ba533ca22baf671420569c07srs   uint64_t firstSector, lastSector;
145221e08768de7fe42ba533ca22baf671420569c07srs
146221e08768de7fe42ba533ca22baf671420569c07srs   newPart.BlankPartition();
147221e08768de7fe42ba533ca22baf671420569c07srs   origPart = GetPartition(i);
148221e08768de7fe42ba533ca22baf671420569c07srs   if (origPart != NULL) {
149221e08768de7fe42ba533ca22baf671420569c07srs      origType = origPart->partitionType;
150221e08768de7fe42ba533ca22baf671420569c07srs
151221e08768de7fe42ba533ca22baf671420569c07srs      // don't convert extended, hybrid protective, or null (non-existent)
152221e08768de7fe42ba533ca22baf671420569c07srs      // partitions (Note similar protection is in GPTData::XFormPartitions(),
153221e08768de7fe42ba533ca22baf671420569c07srs      // but I want it here too in case I call this function in another
154221e08768de7fe42ba533ca22baf671420569c07srs      // context in the future....)
155e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs      if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
156221e08768de7fe42ba533ca22baf671420569c07srs          (origType != 0x00) && (origType != 0xEE)) {
157221e08768de7fe42ba533ca22baf671420569c07srs         firstSector = (uint64_t) origPart->firstLBA;
158221e08768de7fe42ba533ca22baf671420569c07srs         newPart.SetFirstLBA(firstSector);
159221e08768de7fe42ba533ca22baf671420569c07srs         lastSector = firstSector + (uint64_t) origPart->lengthLBA;
160221e08768de7fe42ba533ca22baf671420569c07srs         if (lastSector > 0) lastSector--;
161221e08768de7fe42ba533ca22baf671420569c07srs         newPart.SetLastLBA(lastSector);
162221e08768de7fe42ba533ca22baf671420569c07srs         newPart.SetType(((uint16_t) origType) * 0x0100);
1636699b01eda84d24bfaf80ad725304fef2b0e1b2asrs         newPart.RandomizeUniqueGUID();
164221e08768de7fe42ba533ca22baf671420569c07srs         newPart.SetAttributes(0);
1656699b01eda84d24bfaf80ad725304fef2b0e1b2asrs         newPart.SetName(newPart.GetTypeName());
166978041ca613dcb881763b36cf53639d924e52a56srs      } // if not extended, protective, or non-existent
167978041ca613dcb881763b36cf53639d924e52a56srs   } // if (origPart != NULL)
168221e08768de7fe42ba533ca22baf671420569c07srs   return newPart;
169221e08768de7fe42ba533ca22baf671420569c07srs} // MBRData::AsGPT()
170978041ca613dcb881763b36cf53639d924e52a56srs
171