1e7b4ff9317fc4e551cf974684eaa88697de5a28srs/* gpt.cc -- Functions for loading, saving, and manipulating legacy MBR and GPT partition 2e7b4ff9317fc4e551cf974684eaa88697de5a28srs data. */ 3e7b4ff9317fc4e551cf974684eaa88697de5a28srs 4e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/* By Rod Smith, initial coding January to February, 2009 */ 5e7b4ff9317fc4e551cf974684eaa88697de5a28srs 6e3ee733ff8690af7568dac665bc20ecf869dea1dRoderick W. Smith/* This program is copyright (c) 2009-2013 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 10fcad060a1d83aa5e0b4ad38cf342d10f1922878dAurimas Liutikas#ifndef __STDC_CONSTANT_MACROS 11e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_CONSTANT_MACROS 12fcad060a1d83aa5e0b4ad38cf342d10f1922878dAurimas Liutikas#endif 13e7b4ff9317fc4e551cf974684eaa88697de5a28srs 14e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdio.h> 15e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdlib.h> 16e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdint.h> 17e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <fcntl.h> 18e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <string.h> 19a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs#include <math.h> 20e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <time.h> 21e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <sys/stat.h> 22e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <errno.h> 23fed16d043a14e8b86c97a6413aec7281fefcbcb5srs#include <iostream> 249a46b042c57144c26a67781d335e6ba4128382d2srs#include <algorithm> 25e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "crc32.h" 26e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "gpt.h" 27221e08768de7fe42ba533ca22baf671420569c07srs#include "bsd.h" 28e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "support.h" 29e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "parttypes.h" 30e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "attributes.h" 31546a9c7c369df465021feecb20f6a8f81b6df6bcsrs#include "diskio.h" 32e7b4ff9317fc4e551cf974684eaa88697de5a28srs 33e7b4ff9317fc4e551cf974684eaa88697de5a28srsusing namespace std; 34e7b4ff9317fc4e551cf974684eaa88697de5a28srs 358f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#ifdef __FreeBSD__ 369ba5421f920e192dbb808d30aa6d34849938bab4srs#define log2(x) (log(x) / M_LN2) 379ba5421f920e192dbb808d30aa6d34849938bab4srs#endif // __FreeBSD__ 389ba5421f920e192dbb808d30aa6d34849938bab4srs 398f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#ifdef _MSC_VER 408f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#define log2(x) (log((double) x) / log(2.0)) 418f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#endif // Microsoft Visual C++ 429ba5421f920e192dbb808d30aa6d34849938bab4srs 431f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#ifdef EFI 441f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith// in UEFI mode MMX registers are not yet available so using the 451f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith// x86_64 ABI to move "double" values around is not an option. 461f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#ifdef log2 471f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#undef log2 481f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#endif 491f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#define log2(x) log2_32( x ) 501f7822eb54337766002431f01e5934c7d4703628Roderick W. Smithstatic inline uint32_t log2_32(uint32_t v) { 511f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith int r = -1; 521f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith while (v >= 1) { 531f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith r++; 541f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith v >>= 1; 551f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith } 561f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith return r; 571f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith} 581f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#endif 591f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith 60e7b4ff9317fc4e551cf974684eaa88697de5a28srs/**************************************** 61e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 62e7b4ff9317fc4e551cf974684eaa88697de5a28srs * GPTData class and related structures * 63e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 64e7b4ff9317fc4e551cf974684eaa88697de5a28srs ****************************************/ 65e7b4ff9317fc4e551cf974684eaa88697de5a28srs 66e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Default constructor 67e7b4ff9317fc4e551cf974684eaa88697de5a28srsGPTData::GPTData(void) { 68e7b4ff9317fc4e551cf974684eaa88697de5a28srs blockSize = SECTOR_SIZE; // set a default 69e7b4ff9317fc4e551cf974684eaa88697de5a28srs diskSize = 0; 70e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions = NULL; 71e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_valid; 72fed16d043a14e8b86c97a6413aec7281fefcbcb5srs device = ""; 735d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs justLooking = 0; 742c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman syncing = 1; 75e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainCrcOk = 0; 76e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondCrcOk = 0; 77e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainPartsCrcOk = 0; 78e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondPartsCrcOk = 0; 79221e08768de7fe42ba533ca22baf671420569c07srs apmFound = 0; 80221e08768de7fe42ba533ca22baf671420569c07srs bsdFound = 0; 810873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default 82ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs beQuiet = 0; 83ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs whichWasUsed = use_new; 841e09372bca227ffbfb9dda48160826d8f63ce9bbsrs mainHeader.numParts = 0; 850283dae41a7db4563be0fe62241ed230e4a101c0srs numParts = 0; 86e7b4ff9317fc4e551cf974684eaa88697de5a28srs SetGPTSize(NUM_GPT_ENTRIES); 87d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // Initialize CRC functions... 88d1b11e8305621d73ff675af940e7f1f28b639b0dsrs chksum_crc32gentab(); 89e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData default constructor 90e7b4ff9317fc4e551cf974684eaa88697de5a28srs 91e7b4ff9317fc4e551cf974684eaa88697de5a28srs// The following constructor loads GPT data from a device file 92fed16d043a14e8b86c97a6413aec7281fefcbcb5srsGPTData::GPTData(string filename) { 93e7b4ff9317fc4e551cf974684eaa88697de5a28srs blockSize = SECTOR_SIZE; // set a default 94e7b4ff9317fc4e551cf974684eaa88697de5a28srs diskSize = 0; 95e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions = NULL; 96e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_invalid; 97fed16d043a14e8b86c97a6413aec7281fefcbcb5srs device = ""; 985d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs justLooking = 0; 992c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman syncing = 1; 100e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainCrcOk = 0; 101e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondCrcOk = 0; 102e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainPartsCrcOk = 0; 103e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondPartsCrcOk = 0; 104221e08768de7fe42ba533ca22baf671420569c07srs apmFound = 0; 105221e08768de7fe42ba533ca22baf671420569c07srs bsdFound = 0; 1060873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default 107ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs beQuiet = 0; 108ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs whichWasUsed = use_new; 1091e09372bca227ffbfb9dda48160826d8f63ce9bbsrs mainHeader.numParts = 0; 1100283dae41a7db4563be0fe62241ed230e4a101c0srs numParts = 0; 111d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // Initialize CRC functions... 112d1b11e8305621d73ff675af940e7f1f28b639b0dsrs chksum_crc32gentab(); 1133c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (!LoadPartitions(filename)) 1143c0af38237d0f40aaea8233a5cbfdd030a77817dsrs exit(2); 115fed16d043a14e8b86c97a6413aec7281fefcbcb5srs} // GPTData(string filename) constructor 116e7b4ff9317fc4e551cf974684eaa88697de5a28srs 117e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Destructor 118e7b4ff9317fc4e551cf974684eaa88697de5a28srsGPTData::~GPTData(void) { 119cb76c673eeb84344887715d36d44b799042be5a5srs delete[] partitions; 120e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData destructor 121e7b4ff9317fc4e551cf974684eaa88697de5a28srs 12264cbd171067eb34054741bfcd73f0b91d727a371srs// Assignment operator 12364cbd171067eb34054741bfcd73f0b91d727a371srsGPTData & GPTData::operator=(const GPTData & orig) { 12464cbd171067eb34054741bfcd73f0b91d727a371srs uint32_t i; 12564cbd171067eb34054741bfcd73f0b91d727a371srs 12664cbd171067eb34054741bfcd73f0b91d727a371srs mainHeader = orig.mainHeader; 12764cbd171067eb34054741bfcd73f0b91d727a371srs numParts = orig.numParts; 12864cbd171067eb34054741bfcd73f0b91d727a371srs secondHeader = orig.secondHeader; 12964cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR = orig.protectiveMBR; 13064cbd171067eb34054741bfcd73f0b91d727a371srs device = orig.device; 13164cbd171067eb34054741bfcd73f0b91d727a371srs blockSize = orig.blockSize; 13264cbd171067eb34054741bfcd73f0b91d727a371srs diskSize = orig.diskSize; 13364cbd171067eb34054741bfcd73f0b91d727a371srs state = orig.state; 13464cbd171067eb34054741bfcd73f0b91d727a371srs justLooking = orig.justLooking; 1352c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman syncing = orig.syncing; 13664cbd171067eb34054741bfcd73f0b91d727a371srs mainCrcOk = orig.mainCrcOk; 13764cbd171067eb34054741bfcd73f0b91d727a371srs secondCrcOk = orig.secondCrcOk; 13864cbd171067eb34054741bfcd73f0b91d727a371srs mainPartsCrcOk = orig.mainPartsCrcOk; 13964cbd171067eb34054741bfcd73f0b91d727a371srs secondPartsCrcOk = orig.secondPartsCrcOk; 14064cbd171067eb34054741bfcd73f0b91d727a371srs apmFound = orig.apmFound; 14164cbd171067eb34054741bfcd73f0b91d727a371srs bsdFound = orig.bsdFound; 14264cbd171067eb34054741bfcd73f0b91d727a371srs sectorAlignment = orig.sectorAlignment; 14364cbd171067eb34054741bfcd73f0b91d727a371srs beQuiet = orig.beQuiet; 14464cbd171067eb34054741bfcd73f0b91d727a371srs whichWasUsed = orig.whichWasUsed; 14564cbd171067eb34054741bfcd73f0b91d727a371srs 14664cbd171067eb34054741bfcd73f0b91d727a371srs myDisk.OpenForRead(orig.myDisk.GetName()); 14764cbd171067eb34054741bfcd73f0b91d727a371srs 14864cbd171067eb34054741bfcd73f0b91d727a371srs delete[] partitions; 14901f7f08624f0c942001977415214a578621f6495srs partitions = new GPTPart [numParts]; 1506aae2a9b70e9f88926baad94c1eea40e0b534f01srs if (partitions == NULL) { 15164cbd171067eb34054741bfcd73f0b91d727a371srs cerr << "Error! Could not allocate memory for partitions in GPTData::operator=()!\n" 1526aae2a9b70e9f88926baad94c1eea40e0b534f01srs << "Terminating!\n"; 1536aae2a9b70e9f88926baad94c1eea40e0b534f01srs exit(1); 1546aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 1556aae2a9b70e9f88926baad94c1eea40e0b534f01srs for (i = 0; i < numParts; i++) { 1566aae2a9b70e9f88926baad94c1eea40e0b534f01srs partitions[i] = orig.partitions[i]; 157d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } // for 158d1b11e8305621d73ff675af940e7f1f28b639b0dsrs 15964cbd171067eb34054741bfcd73f0b91d727a371srs return *this; 16064cbd171067eb34054741bfcd73f0b91d727a371srs} // GPTData::operator=() 16164cbd171067eb34054741bfcd73f0b91d727a371srs 162e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/********************************************************************* 163e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 164e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Begin functions that verify data, or that adjust the verification * 165e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * information (compute CRCs, rebuild headers) * 166e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 167e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *********************************************************************/ 168e7b4ff9317fc4e551cf974684eaa88697de5a28srs 169e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Perform detailed verification, reporting on any problems found, but 170e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// do *NOT* recover from these problems. Returns the total number of 171e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// problems identified. 172e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::Verify(void) { 17364cbd171067eb34054741bfcd73f0b91d727a371srs int problems = 0, alignProbs = 0; 174e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i, numSegments; 175e321d444dcca514cf6b53459e388ddcbaab6176csrs uint64_t totalFree, largestSegment; 176e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 177e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // First, check for CRC errors in the GPT data.... 178e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!mainCrcOk) { 179e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 180fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The CRC for the main GPT header is invalid. The main GPT header may\n" 181fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n" 182fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "header ('b' on the recovery & transformation menu). This report may be a false\n" 183fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "alarm if you've already corrected other problems.\n"; 184e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 185e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!mainPartsCrcOk) { 186e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 187fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The CRC for the main partition table is invalid. This table may be\n" 188fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "corrupt. Consider loading the backup partition table ('c' on the recovery &\n" 189fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "transformation menu). This report may be a false alarm if you've already\n" 190fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "corrected other problems.\n"; 191e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 192e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!secondCrcOk) { 193e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 194fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The CRC for the backup GPT header is invalid. The backup GPT header\n" 195fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "may be corrupt. Consider using the main GPT header to rebuild the backup GPT\n" 196fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "header ('d' on the recovery & transformation menu). This report may be a false\n" 197fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "alarm if you've already corrected other problems.\n"; 198e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 199e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!secondPartsCrcOk) { 200e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 201fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nCaution: The CRC for the backup partition table is invalid. This table may\n" 202fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "be corrupt. This program will automatically create a new backup partition\n" 203fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "table when you save your partitions.\n"; 204e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 205e7b4ff9317fc4e551cf974684eaa88697de5a28srs 206978041ca613dcb881763b36cf53639d924e52a56srs // Now check that the main and backup headers both point to themselves.... 207978041ca613dcb881763b36cf53639d924e52a56srs if (mainHeader.currentLBA != 1) { 208978041ca613dcb881763b36cf53639d924e52a56srs problems++; 209fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The main header's self-pointer doesn't point to itself. This problem\n" 210fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "is being automatically corrected, but it may be a symptom of more serious\n" 211fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "problems. Think carefully before saving changes with 'w' or using this disk.\n"; 212978041ca613dcb881763b36cf53639d924e52a56srs mainHeader.currentLBA = 1; 213978041ca613dcb881763b36cf53639d924e52a56srs } // if 214978041ca613dcb881763b36cf53639d924e52a56srs if (secondHeader.currentLBA != (diskSize - UINT64_C(1))) { 215978041ca613dcb881763b36cf53639d924e52a56srs problems++; 216fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The secondary header's self-pointer indicates that it doesn't reside\n" 217fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "at the end of the disk. If you've added a disk to a RAID array, use the 'e'\n" 218fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "option on the experts' menu to adjust the secondary header's and partition\n" 219fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "table's locations.\n"; 220978041ca613dcb881763b36cf53639d924e52a56srs } // if 221978041ca613dcb881763b36cf53639d924e52a56srs 222978041ca613dcb881763b36cf53639d924e52a56srs // Now check that critical main and backup GPT entries match each other 223e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.currentLBA != secondHeader.backupLBA) { 224e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 225fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's current LBA pointer (" << mainHeader.currentLBA 226fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's alternate LBA pointer(" 227fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.backupLBA << ").\n"; 228e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 229e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.backupLBA != secondHeader.currentLBA) { 230e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 231fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's backup LBA pointer (" << mainHeader.backupLBA 232fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's current LBA pointer (" 233fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.currentLBA << ").\n" 234fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "The 'e' option on the experts' menu may fix this problem.\n"; 235e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 236e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.firstUsableLBA != secondHeader.firstUsableLBA) { 237e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 238fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's first usable LBA pointer (" << mainHeader.firstUsableLBA 239fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's first usable LBA pointer (" 240fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.firstUsableLBA << ")\n"; 241e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 242e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.lastUsableLBA != secondHeader.lastUsableLBA) { 243e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 244fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's last usable LBA pointer (" << mainHeader.lastUsableLBA 245fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's last usable LBA pointer (" 246fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.lastUsableLBA << ")\n" 247fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "The 'e' option on the experts' menu can probably fix this problem.\n"; 248e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 2496699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if ((mainHeader.diskGUID != secondHeader.diskGUID)) { 250e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 2515a081757ea2e32a491349544fea92826ccf739f6srs cout << "\nProblem: main header's disk GUID (" << mainHeader.diskGUID 252fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's disk GUID (" 2535a081757ea2e32a491349544fea92826ccf739f6srs << secondHeader.diskGUID << ")\n" 254fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" 255fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "select one or the other header.\n"; 256e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 257e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.numParts != secondHeader.numParts) { 258e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 259fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's number of partitions (" << mainHeader.numParts 260fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's number of partitions (" 261fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.numParts << ")\n" 262fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "Resizing the partition table ('s' on the experts' menu) may help.\n"; 263e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 264e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.sizeOfPartitionEntries != secondHeader.sizeOfPartitionEntries) { 265e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 266fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's size of partition entries (" 267fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << mainHeader.sizeOfPartitionEntries << ") doesn't\n" 268fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "match the backup GPT header's size of partition entries (" 269fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.sizeOfPartitionEntries << ")\n" 270fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" 271fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "select one or the other header.\n"; 272e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 273e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 274e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now check for a few other miscellaneous problems... 275e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check that the disk size will hold the data... 27664cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.backupLBA >= diskSize) { 277e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 278fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: Disk is too small to hold all the data!\n" 279fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "(Disk size is " << diskSize << " sectors, needs to be " 28064cbd171067eb34054741bfcd73f0b91d727a371srs << mainHeader.backupLBA + UINT64_C(1) << " sectors.)\n" 281fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "The 'e' option on the experts' menu may fix this problem.\n"; 282e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 283e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 284d8eed4629449a325999808a0170dbda53bd4a6dfsrs if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) { 285d8eed4629449a325999808a0170dbda53bd4a6dfsrs problems++; 2860741fa21ac6cb477891ef15f269c8c8f36cac7c6srs cout << "\nProblem: GPT claims the disk is larger than it is! (Claimed last usable\n" 2870741fa21ac6cb477891ef15f269c8c8f36cac7c6srs << "sector is " << mainHeader.lastUsableLBA << ", but backup header is at\n" 2880741fa21ac6cb477891ef15f269c8c8f36cac7c6srs << mainHeader.backupLBA << " and disk size is " << diskSize << " sectors.\n" 2890741fa21ac6cb477891ef15f269c8c8f36cac7c6srs << "The 'e' option on the experts' menu will probably fix this problem\n"; 290d8eed4629449a325999808a0170dbda53bd4a6dfsrs } 291d8eed4629449a325999808a0170dbda53bd4a6dfsrs 292e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for overlapping partitions.... 293e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems += FindOverlaps(); 294e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 29555d926192adc984462509b2966e23bc0d1129bbdsrs // Check for insane partitions (start after end, hugely big, etc.) 29655d926192adc984462509b2966e23bc0d1129bbdsrs problems += FindInsanePartitions(); 29755d926192adc984462509b2966e23bc0d1129bbdsrs 298e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for mismatched MBR and GPT partitions... 299e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems += FindHybridMismatches(); 300e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 301327129e9331f888a8fc08d688dcb0a739a3c17besrs // Check for MBR-specific problems.... 302327129e9331f888a8fc08d688dcb0a739a3c17besrs problems += VerifyMBR(); 303327129e9331f888a8fc08d688dcb0a739a3c17besrs 304042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith // Check for a 0xEE protective partition that's marked as active.... 305042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith if (protectiveMBR.IsEEActive()) { 306042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith cout << "\nWarning: The 0xEE protective partition in the MBR is marked as active. This is\n" 307042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "technically a violation of the GPT specification, and can cause some EFIs to\n" 308042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "ignore the disk, but it is required to boot from a GPT disk on some BIOS-based\n" 309042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "computers. You can clear this flag by creating a fresh protective MBR using\n" 310042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "the 'n' option on the experts' menu.\n"; 311042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith } 312042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith 313e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Verify that partitions don't run into GPT data areas.... 314e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems += CheckGPTSize(); 315e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 3164a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if (!protectiveMBR.DoTheyFit()) { 3174a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith cout << "\nPartition(s) in the protective MBR are too big for the disk! Creating a\n" 3184a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith << "fresh protective or hybrid MBR is recommended.\n"; 3194a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith problems++; 3204a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } 3214a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith 3221d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // Check that partitions are aligned on proper boundaries (for WD Advanced 3231d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // Format and similar disks).... 3240283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 325e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() % sectorAlignment) != 0) { 326fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nCaution: Partition " << i + 1 << " doesn't begin on a " 327fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << sectorAlignment << "-sector boundary. This may\nresult " 328fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "in degraded performance on some modern (2009 and later) hard disks.\n"; 32964cbd171067eb34054741bfcd73f0b91d727a371srs alignProbs++; 3301d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 3311d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // for 33264cbd171067eb34054741bfcd73f0b91d727a371srs if (alignProbs > 0) 33364cbd171067eb34054741bfcd73f0b91d727a371srs cout << "\nConsult http://www.ibm.com/developerworks/linux/library/l-4kb-sector-disks/\n" 33464cbd171067eb34054741bfcd73f0b91d727a371srs << "for information on disk alignment.\n"; 3351d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 336e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now compute available space, but only if no problems found, since 337e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // problems could affect the results 338e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (problems == 0) { 339e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs totalFree = FindFreeBlocks(&numSegments, &largestSegment); 34064cbd171067eb34054741bfcd73f0b91d727a371srs cout << "\nNo problems found. " << totalFree << " free sectors (" 34101f7f08624f0c942001977415214a578621f6495srs << BytesToIeee(totalFree, blockSize) << ") available in " 342fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << numSegments << "\nsegments, the largest of which is " 34301f7f08624f0c942001977415214a578621f6495srs << largestSegment << " (" << BytesToIeee(largestSegment, blockSize) 3440283dae41a7db4563be0fe62241ed230e4a101c0srs << ") in size.\n"; 345e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 3460a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "\nIdentified " << problems << " problems!\n"; 347e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 348e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 349e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (problems); 350e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::Verify() 351e7b4ff9317fc4e551cf974684eaa88697de5a28srs 352e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Checks to see if the GPT tables overrun existing partitions; if they 353221e08768de7fe42ba533ca22baf671420569c07srs// do, issues a warning but takes no action. Returns number of problems 354221e08768de7fe42ba533ca22baf671420569c07srs// detected (0 if OK, 1 to 2 if problems). 355e7b4ff9317fc4e551cf974684eaa88697de5a28srsint GPTData::CheckGPTSize(void) { 356e7b4ff9317fc4e551cf974684eaa88697de5a28srs uint64_t overlap, firstUsedBlock, lastUsedBlock; 357e7b4ff9317fc4e551cf974684eaa88697de5a28srs uint32_t i; 358221e08768de7fe42ba533ca22baf671420569c07srs int numProbs = 0; 359e7b4ff9317fc4e551cf974684eaa88697de5a28srs 360e7b4ff9317fc4e551cf974684eaa88697de5a28srs // first, locate the first & last used blocks 361e7b4ff9317fc4e551cf974684eaa88697de5a28srs firstUsedBlock = UINT64_MAX; 362e7b4ff9317fc4e551cf974684eaa88697de5a28srs lastUsedBlock = 0; 3630283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 364e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].IsUsed()) { 365706e51217a531c46afc743b556e10fd5c0585fcfsrs if (partitions[i].GetFirstLBA() < firstUsedBlock) 366e69e6807cf84fe2b80c48475531ce4bd09563bbasrs firstUsedBlock = partitions[i].GetFirstLBA(); 367e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].GetLastLBA() > lastUsedBlock) { 368e69e6807cf84fe2b80c48475531ce4bd09563bbasrs lastUsedBlock = partitions[i].GetLastLBA(); 369e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 370e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 371e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // for 372e7b4ff9317fc4e551cf974684eaa88697de5a28srs 373e7b4ff9317fc4e551cf974684eaa88697de5a28srs // If the disk size is 0 (the default), then it means that various 374e7b4ff9317fc4e551cf974684eaa88697de5a28srs // variables aren't yet set, so the below tests will be useless; 375e7b4ff9317fc4e551cf974684eaa88697de5a28srs // therefore we should skip everything 376e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (diskSize != 0) { 377e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (mainHeader.firstUsableLBA > firstUsedBlock) { 378e7b4ff9317fc4e551cf974684eaa88697de5a28srs overlap = mainHeader.firstUsableLBA - firstUsedBlock; 379fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Warning! Main partition table overlaps the first partition by " 380fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << overlap << " blocks!\n"; 381221e08768de7fe42ba533ca22baf671420569c07srs if (firstUsedBlock > 2) { 382fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Try reducing the partition table size by " << overlap * 4 383fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " entries.\n(Use the 's' item on the experts' menu.)\n"; 384221e08768de7fe42ba533ca22baf671420569c07srs } else { 385fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "You will need to delete this partition or resize it in another utility.\n"; 386221e08768de7fe42ba533ca22baf671420569c07srs } // if/else 387221e08768de7fe42ba533ca22baf671420569c07srs numProbs++; 388e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // Problem at start of disk 389e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (mainHeader.lastUsableLBA < lastUsedBlock) { 390e7b4ff9317fc4e551cf974684eaa88697de5a28srs overlap = lastUsedBlock - mainHeader.lastUsableLBA; 39155d926192adc984462509b2966e23bc0d1129bbdsrs cout << "\nWarning! Secondary partition table overlaps the last partition by\n" 392fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << overlap << " blocks!\n"; 393221e08768de7fe42ba533ca22baf671420569c07srs if (lastUsedBlock > (diskSize - 2)) { 394fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "You will need to delete this partition or resize it in another utility.\n"; 395221e08768de7fe42ba533ca22baf671420569c07srs } else { 396fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Try reducing the partition table size by " << overlap * 4 397fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " entries.\n(Use the 's' item on the experts' menu.)\n"; 398221e08768de7fe42ba533ca22baf671420569c07srs } // if/else 399221e08768de7fe42ba533ca22baf671420569c07srs numProbs++; 400e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // Problem at end of disk 401e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if (diskSize != 0) 402221e08768de7fe42ba533ca22baf671420569c07srs return numProbs; 403e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::CheckGPTSize() 404e7b4ff9317fc4e551cf974684eaa88697de5a28srs 405e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Check the validity of the GPT header. Returns 1 if the main header 406e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// is valid, 2 if the backup header is valid, 3 if both are valid, and 407d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// 0 if neither is valid. Note that this function checks the GPT signature, 408d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// revision value, and CRCs in both headers. 409e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::CheckHeaderValidity(void) { 410e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int valid = 3; 411221e08768de7fe42ba533ca22baf671420569c07srs 412fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.setf(ios::uppercase); 413fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill('0'); 414fed16d043a14e8b86c97a6413aec7281fefcbcb5srs 415fed16d043a14e8b86c97a6413aec7281fefcbcb5srs // Note: failed GPT signature checks produce no error message because 416fed16d043a14e8b86c97a6413aec7281fefcbcb5srs // a message is displayed in the ReversePartitionBytes() function 417d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if ((mainHeader.signature != GPT_SIGNATURE) || (!CheckHeaderCRC(&mainHeader, 1))) { 418e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 1; 419e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else if ((mainHeader.revision != 0x00010000) && valid) { 420e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 1; 421fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Unsupported GPT version in main header; read 0x"; 422fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 423fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << hex << mainHeader.revision << ", should be\n0x"; 424fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 425fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << UINT32_C(0x00010000) << dec << "\n"; 426e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else/if 427221e08768de7fe42ba533ca22baf671420569c07srs 428d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if ((secondHeader.signature != GPT_SIGNATURE) || (!CheckHeaderCRC(&secondHeader))) { 429e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 2; 430e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else if ((secondHeader.revision != 0x00010000) && valid) { 431e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 2; 432fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Unsupported GPT version in backup header; read 0x"; 433fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 434fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << hex << secondHeader.revision << ", should be\n0x"; 435fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 436fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << UINT32_C(0x00010000) << dec << "\n"; 437e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else/if 438221e08768de7fe42ba533ca22baf671420569c07srs 439df9d363d341a0ffdd05250fd4ffb842f59815690srs // Check for an Apple disk signature 440df9d363d341a0ffdd05250fd4ffb842f59815690srs if (((mainHeader.signature << 32) == APM_SIGNATURE1) || 441df9d363d341a0ffdd05250fd4ffb842f59815690srs (mainHeader.signature << 32) == APM_SIGNATURE2) { 442e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs apmFound = 1; // Will display warning message later 4433f2fe99e72648aefc926138132d48efb07a7ad2dsrs } // if 444fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill(' '); 445221e08768de7fe42ba533ca22baf671420569c07srs 446fed16d043a14e8b86c97a6413aec7281fefcbcb5srs return valid; 447e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::CheckHeaderValidity() 448221e08768de7fe42ba533ca22baf671420569c07srs 449e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Check the header CRC to see if it's OK... 450d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Note: Must be called with header in platform-ordered byte order. 451d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Returns 1 if header's computed CRC matches the stored value, 0 if the 452d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// computed and stored values don't match 453d1b11e8305621d73ff675af940e7f1f28b639b0dsrsint GPTData::CheckHeaderCRC(struct GPTHeader* header, int warn) { 454978041ca613dcb881763b36cf53639d924e52a56srs uint32_t oldCRC, newCRC, hSize; 455d1b11e8305621d73ff675af940e7f1f28b639b0dsrs uint8_t *temp; 456221e08768de7fe42ba533ca22baf671420569c07srs 457e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Back up old header CRC and then blank it, since it must be 0 for 458e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // computation to be valid 459e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs oldCRC = header->headerCRC; 460e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs header->headerCRC = UINT32_C(0); 461d1b11e8305621d73ff675af940e7f1f28b639b0dsrs 462978041ca613dcb881763b36cf53639d924e52a56srs hSize = header->headerSize; 463978041ca613dcb881763b36cf53639d924e52a56srs 464d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (IsLittleEndian() == 0) 465d1b11e8305621d73ff675af940e7f1f28b639b0dsrs ReverseHeaderBytes(header); 466221e08768de7fe42ba533ca22baf671420569c07srs 467d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if ((hSize > blockSize) || (hSize < HEADER_SIZE)) { 468d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (warn) { 469d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cerr << "\aWarning! Header size is specified as " << hSize << ", which is invalid.\n"; 470d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cerr << "Setting the header size for CRC computation to " << HEADER_SIZE << "\n"; 471d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } // if 472d1b11e8305621d73ff675af940e7f1f28b639b0dsrs hSize = HEADER_SIZE; 473d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } else if ((hSize > sizeof(GPTHeader)) && warn) { 474d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cout << "\aCaution! Header size for CRC check is " << hSize << ", which is greater than " << sizeof(GPTHeader) << ".\n"; 475d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cout << "If stray data exists after the header on the header sector, it will be ignored,\n" 476d1b11e8305621d73ff675af940e7f1f28b639b0dsrs << "which may result in a CRC false alarm.\n"; 477d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } // if/elseif 478d1b11e8305621d73ff675af940e7f1f28b639b0dsrs temp = new uint8_t[hSize]; 479d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (temp != NULL) { 480d1b11e8305621d73ff675af940e7f1f28b639b0dsrs memset(temp, 0, hSize); 481d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (hSize < sizeof(GPTHeader)) 482d1b11e8305621d73ff675af940e7f1f28b639b0dsrs memcpy(temp, header, hSize); 483d1b11e8305621d73ff675af940e7f1f28b639b0dsrs else 484d1b11e8305621d73ff675af940e7f1f28b639b0dsrs memcpy(temp, header, sizeof(GPTHeader)); 485e7b4ff9317fc4e551cf974684eaa88697de5a28srs 486d1b11e8305621d73ff675af940e7f1f28b639b0dsrs newCRC = chksum_crc32((unsigned char*) temp, hSize); 487d1b11e8305621d73ff675af940e7f1f28b639b0dsrs delete[] temp; 488d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } else { 489d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cerr << "Could not allocate memory in GPTData::CheckHeaderCRC()! Aborting!\n"; 490d1b11e8305621d73ff675af940e7f1f28b639b0dsrs exit(1); 491d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } 492d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (IsLittleEndian() == 0) 493d1b11e8305621d73ff675af940e7f1f28b639b0dsrs ReverseHeaderBytes(header); 494978041ca613dcb881763b36cf53639d924e52a56srs header->headerCRC = oldCRC; 495e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (oldCRC == newCRC); 496e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::CheckHeaderCRC() 497e7b4ff9317fc4e551cf974684eaa88697de5a28srs 4986699b01eda84d24bfaf80ad725304fef2b0e1b2asrs// Recompute all the CRCs. Must be called before saving if any changes have 4996699b01eda84d24bfaf80ad725304fef2b0e1b2asrs// been made. Must be called on platform-ordered data (this function reverses 5006699b01eda84d24bfaf80ad725304fef2b0e1b2asrs// byte order and then undoes that reversal.) 501e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::RecomputeCRCs(void) { 5020283dae41a7db4563be0fe62241ed230e4a101c0srs uint32_t crc, hSize; 503e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int littleEndian = 1; 504e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 505d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // If the header size is bigger than the GPT header data structure, reset it; 506d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // otherwise, set both header sizes to whatever the main one is.... 507d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (mainHeader.headerSize > sizeof(GPTHeader)) 508d1b11e8305621d73ff675af940e7f1f28b639b0dsrs hSize = secondHeader.headerSize = mainHeader.headerSize = HEADER_SIZE; 509d1b11e8305621d73ff675af940e7f1f28b639b0dsrs else 510d1b11e8305621d73ff675af940e7f1f28b639b0dsrs hSize = secondHeader.headerSize = mainHeader.headerSize; 5116699b01eda84d24bfaf80ad725304fef2b0e1b2asrs 5126699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if ((littleEndian = IsLittleEndian()) == 0) { 5136699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReversePartitionBytes(); 5146699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&mainHeader); 5156699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&secondHeader); 5166699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 517e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 518e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Compute CRC of partition tables & store in main and secondary headers 5190283dae41a7db4563be0fe62241ed230e4a101c0srs crc = chksum_crc32((unsigned char*) partitions, numParts * GPT_SIZE); 520e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesCRC = crc; 521e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.partitionEntriesCRC = crc; 522e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (littleEndian == 0) { 523e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&mainHeader.partitionEntriesCRC, 4); 524e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&secondHeader.partitionEntriesCRC, 4); 525e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 526e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 527d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // Zero out GPT headers' own CRCs (required for correct computation) 528e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.headerCRC = 0; 529e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.headerCRC = 0; 530e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 531978041ca613dcb881763b36cf53639d924e52a56srs crc = chksum_crc32((unsigned char*) &mainHeader, hSize); 532e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (littleEndian == 0) 533e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&crc, 4); 534e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.headerCRC = crc; 535978041ca613dcb881763b36cf53639d924e52a56srs crc = chksum_crc32((unsigned char*) &secondHeader, hSize); 536e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (littleEndian == 0) 537e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&crc, 4); 538e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.headerCRC = crc; 5396699b01eda84d24bfaf80ad725304fef2b0e1b2asrs 540d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (littleEndian == 0) { 5416699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&mainHeader); 5426699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&secondHeader); 5436699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReversePartitionBytes(); 5446699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 545e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::RecomputeCRCs() 546e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 547e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Rebuild the main GPT header, using the secondary header as a model. 548e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Typically called when the main header has been found to be corrupt. 549e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::RebuildMainHeader(void) { 550e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.signature = GPT_SIGNATURE; 551e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.revision = secondHeader.revision; 552978041ca613dcb881763b36cf53639d924e52a56srs mainHeader.headerSize = secondHeader.headerSize; 553e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.headerCRC = UINT32_C(0); 554e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.reserved = secondHeader.reserved; 555e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.currentLBA = secondHeader.backupLBA; 556e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.backupLBA = secondHeader.currentLBA; 557e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.firstUsableLBA = secondHeader.firstUsableLBA; 558e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.lastUsableLBA = secondHeader.lastUsableLBA; 5596699b01eda84d24bfaf80ad725304fef2b0e1b2asrs mainHeader.diskGUID = secondHeader.diskGUID; 560e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesLBA = UINT64_C(2); 561e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.numParts = secondHeader.numParts; 562e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries; 563e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC; 56401f7f08624f0c942001977415214a578621f6495srs memcpy(mainHeader.reserved2, secondHeader.reserved2, sizeof(mainHeader.reserved2)); 565546a9c7c369df465021feecb20f6a8f81b6df6bcsrs mainCrcOk = secondCrcOk; 566706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(mainHeader.numParts, 0); 567e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::RebuildMainHeader() 568e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 569e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Rebuild the secondary GPT header, using the main header as a model. 570e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::RebuildSecondHeader(void) { 571e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.signature = GPT_SIGNATURE; 572e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.revision = mainHeader.revision; 573978041ca613dcb881763b36cf53639d924e52a56srs secondHeader.headerSize = mainHeader.headerSize; 574e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.headerCRC = UINT32_C(0); 575e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.reserved = mainHeader.reserved; 576e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.currentLBA = mainHeader.backupLBA; 577e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.backupLBA = mainHeader.currentLBA; 578e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; 579e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.lastUsableLBA = mainHeader.lastUsableLBA; 5806699b01eda84d24bfaf80ad725304fef2b0e1b2asrs secondHeader.diskGUID = mainHeader.diskGUID; 581e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); 582e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.numParts = mainHeader.numParts; 583e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries; 584e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.partitionEntriesCRC = mainHeader.partitionEntriesCRC; 58501f7f08624f0c942001977415214a578621f6495srs memcpy(secondHeader.reserved2, mainHeader.reserved2, sizeof(secondHeader.reserved2)); 586546a9c7c369df465021feecb20f6a8f81b6df6bcsrs secondCrcOk = mainCrcOk; 587706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(secondHeader.numParts, 0); 588e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::RebuildSecondHeader() 589e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 590e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Search for hybrid MBR entries that have no corresponding GPT partition. 591e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Returns number of such mismatches found 592e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::FindHybridMismatches(void) { 593e321d444dcca514cf6b53459e388ddcbaab6176csrs int i, found, numFound = 0; 594e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t j; 595e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t mbrFirst, mbrLast; 596e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 597e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < 4; i++) { 598e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((protectiveMBR.GetType(i) != 0xEE) && (protectiveMBR.GetType(i) != 0x00)) { 599e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs j = 0; 600e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs found = 0; 601d1b11e8305621d73ff675af940e7f1f28b639b0dsrs mbrFirst = (uint64_t) protectiveMBR.GetFirstSector(i); 602d1b11e8305621d73ff675af940e7f1f28b639b0dsrs mbrLast = mbrFirst + (uint64_t) protectiveMBR.GetLength(i) - UINT64_C(1); 603e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 60424bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if ((j < numParts) && (partitions[j].GetFirstLBA() == mbrFirst) && 605e69e6807cf84fe2b80c48475531ce4bd09563bbasrs (partitions[j].GetLastLBA() == mbrLast) && (partitions[j].IsUsed())) 606e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs found = 1; 607e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs j++; 6080283dae41a7db4563be0fe62241ed230e4a101c0srs } while ((!found) && (j < numParts)); 609e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!found) { 610e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs numFound++; 611fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nWarning! Mismatched GPT and MBR partition! MBR partition " 612fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << i + 1 << ", of type 0x"; 613fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill('0'); 614fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.setf(ios::uppercase); 615fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(2); 616fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << hex << (int) protectiveMBR.GetType(i) << ",\n" 617fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "has no corresponding GPT partition! You may continue, but this condition\n" 618fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "might cause data loss in the future!\a\n" << dec; 619fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill(' '); 620e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 621e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 622e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 623e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numFound; 624e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindHybridMismatches 625e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 626e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find overlapping partitions and warn user about them. Returns number of 627e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// overlapping partitions. 628d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Returns number of overlapping segments found. 629e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::FindOverlaps(void) { 630e321d444dcca514cf6b53459e388ddcbaab6176csrs int problems = 0; 631e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i, j; 632e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 6330283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 1; i < numParts; i++) { 634e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (j = 0; j < i; j++) { 635e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if ((partitions[i].IsUsed()) && (partitions[j].IsUsed()) && 636e69e6807cf84fe2b80c48475531ce4bd09563bbasrs (partitions[i].DoTheyOverlap(partitions[j]))) { 637e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 638fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: partitions " << i + 1 << " and " << j + 1 << " overlap:\n"; 639fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " Partition " << i + 1 << ": " << partitions[i].GetFirstLBA() 640fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " to " << partitions[i].GetLastLBA() << "\n"; 641fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " Partition " << j + 1 << ": " << partitions[j].GetFirstLBA() 642fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " to " << partitions[j].GetLastLBA() << "\n"; 643e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 644e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for j... 645e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for i... 646e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return problems; 647e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindOverlaps() 648e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 64955d926192adc984462509b2966e23bc0d1129bbdsrs// Find partitions that are insane -- they start after they end or are too 65055d926192adc984462509b2966e23bc0d1129bbdsrs// big for the disk. (The latter should duplicate detection of overlaps 65155d926192adc984462509b2966e23bc0d1129bbdsrs// with GPT backup data structures, but better to err on the side of 65255d926192adc984462509b2966e23bc0d1129bbdsrs// redundant tests than to miss something....) 653d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Returns number of problems found. 65455d926192adc984462509b2966e23bc0d1129bbdsrsint GPTData::FindInsanePartitions(void) { 65555d926192adc984462509b2966e23bc0d1129bbdsrs uint32_t i; 65655d926192adc984462509b2966e23bc0d1129bbdsrs int problems = 0; 65755d926192adc984462509b2966e23bc0d1129bbdsrs 6580283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 659e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].IsUsed()) { 660e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].GetFirstLBA() > partitions[i].GetLastLBA()) { 661e69e6807cf84fe2b80c48475531ce4bd09563bbasrs problems++; 662e69e6807cf84fe2b80c48475531ce4bd09563bbasrs cout << "\nProblem: partition " << i + 1 << " ends before it begins.\n"; 663e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 664e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].GetLastLBA() >= diskSize) { 665e69e6807cf84fe2b80c48475531ce4bd09563bbasrs problems++; 666e69e6807cf84fe2b80c48475531ce4bd09563bbasrs cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n"; 667e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 66855d926192adc984462509b2966e23bc0d1129bbdsrs } // if 66955d926192adc984462509b2966e23bc0d1129bbdsrs } // for 67055d926192adc984462509b2966e23bc0d1129bbdsrs return problems; 67155d926192adc984462509b2966e23bc0d1129bbdsrs} // GPTData::FindInsanePartitions(void) 67255d926192adc984462509b2966e23bc0d1129bbdsrs 67355d926192adc984462509b2966e23bc0d1129bbdsrs 674e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/****************************************************************** 675e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 676e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Begin functions that load data from disk or save data to disk. * 677e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 678e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ******************************************************************/ 679e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 68064cbd171067eb34054741bfcd73f0b91d727a371srs// Change the filename associated with the GPT. Used for duplicating 68164cbd171067eb34054741bfcd73f0b91d727a371srs// the partition table to a new disk and saving backups. 68264cbd171067eb34054741bfcd73f0b91d727a371srs// Returns 1 on success, 0 on failure. 683bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrsint GPTData::SetDisk(const string & deviceFilename) { 68464cbd171067eb34054741bfcd73f0b91d727a371srs int err, allOK = 1; 68564cbd171067eb34054741bfcd73f0b91d727a371srs 68664cbd171067eb34054741bfcd73f0b91d727a371srs device = deviceFilename; 68764cbd171067eb34054741bfcd73f0b91d727a371srs if (allOK && myDisk.OpenForRead(deviceFilename)) { 68864cbd171067eb34054741bfcd73f0b91d727a371srs // store disk information.... 68964cbd171067eb34054741bfcd73f0b91d727a371srs diskSize = myDisk.DiskSize(&err); 69064cbd171067eb34054741bfcd73f0b91d727a371srs blockSize = (uint32_t) myDisk.GetBlockSize(); 69164cbd171067eb34054741bfcd73f0b91d727a371srs } // if 69264cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.SetDisk(&myDisk); 69364cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.SetDiskSize(diskSize); 69464cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.SetBlockSize(blockSize); 69564cbd171067eb34054741bfcd73f0b91d727a371srs return allOK; 696bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs} // GPTData::SetDisk() 69764cbd171067eb34054741bfcd73f0b91d727a371srs 698e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Scan for partition data. This function loads the MBR data (regular MBR or 699e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// protective MBR) and loads BSD disklabel data (which is probably invalid). 700e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// It also looks for APM data, forces a load of GPT data, and summarizes 701e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// the results. 702546a9c7c369df465021feecb20f6a8f81b6df6bcsrsvoid GPTData::PartitionScan(void) { 703e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs BSDData bsdDisklabel; 704e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 705e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Read the MBR & check for BSD disklabel 706546a9c7c369df465021feecb20f6a8f81b6df6bcsrs protectiveMBR.ReadMBRData(&myDisk); 707546a9c7c369df465021feecb20f6a8f81b6df6bcsrs bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1); 708e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 709e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Load the GPT data, whether or not it's valid 710546a9c7c369df465021feecb20f6a8f81b6df6bcsrs ForceLoadGPTData(); 711ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 7124a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith // Some tools create a 0xEE partition that's too big. If this is detected, 7134a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith // normalize it.... 7144a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if ((state == gpt_valid) && !protectiveMBR.DoTheyFit() && (protectiveMBR.GetValidity() == gpt)) { 7154a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if (!beQuiet) { 7164a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith cerr << "\aThe protective MBR's 0xEE partition is oversized! Auto-repairing.\n\n"; 7174a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } // if 7184a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith protectiveMBR.MakeProtectiveMBR(); 7194a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } // if 7204a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith 721ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (!beQuiet) { 722fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Partition table scan:\n"; 723ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs protectiveMBR.ShowState(); 724ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs bsdDisklabel.ShowState(); 725ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs ShowAPMState(); // Show whether there's an Apple Partition Map present 726ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs ShowGPTState(); // Show GPT status 727fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n"; 728ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } // if 729e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 730e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (apmFound) { 731fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n*******************************************************************\n" 732fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "This disk appears to contain an Apple-format (APM) partition table!\n"; 7335d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (!justLooking) { 734fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "It will be destroyed if you continue!\n"; 7355d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 736fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "*******************************************************************\n\n\a"; 737e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 738e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::PartitionScan() 739e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 740e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Read GPT data from a disk. 7410a6973119c9e9984ad47a6da3231e8d16f996c5csrsint GPTData::LoadPartitions(const string & deviceFilename) { 74208bb0da07953af605b4918e268272de15ac151aasrs BSDData bsdDisklabel; 743e321d444dcca514cf6b53459e388ddcbaab6176csrs int err, allOK = 1; 744fed16d043a14e8b86c97a6413aec7281fefcbcb5srs MBRValidity mbrState; 745e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 74655d926192adc984462509b2966e23bc0d1129bbdsrs if (myDisk.OpenForRead(deviceFilename)) { 74755d926192adc984462509b2966e23bc0d1129bbdsrs err = myDisk.OpenForWrite(deviceFilename); 74855d926192adc984462509b2966e23bc0d1129bbdsrs if ((err == 0) && (!justLooking)) { 74955d926192adc984462509b2966e23bc0d1129bbdsrs cout << "\aNOTE: Write test failed with error number " << errno 75055d926192adc984462509b2966e23bc0d1129bbdsrs << ". It will be impossible to save\nchanges to this disk's partition table!\n"; 75108bb0da07953af605b4918e268272de15ac151aasrs#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) 75255d926192adc984462509b2966e23bc0d1129bbdsrs cout << "You may be able to enable writes by exiting this program, typing\n" 75355d926192adc984462509b2966e23bc0d1129bbdsrs << "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n" 75455d926192adc984462509b2966e23bc0d1129bbdsrs << "program.\n"; 7557dbb932233c77cc91ea202ddf5a6198034558ae2srs#endif 756bdbab02f71097593c879a552951d73969305d0aeAurimas Liutikas cout << "\n"; 75755d926192adc984462509b2966e23bc0d1129bbdsrs } // if 75855d926192adc984462509b2966e23bc0d1129bbdsrs myDisk.Close(); // Close and re-open read-only in case of bugs 75955d926192adc984462509b2966e23bc0d1129bbdsrs } else allOK = 0; // if 760e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 76155d926192adc984462509b2966e23bc0d1129bbdsrs if (allOK && myDisk.OpenForRead(deviceFilename)) { 762e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // store disk information.... 763546a9c7c369df465021feecb20f6a8f81b6df6bcsrs diskSize = myDisk.DiskSize(&err); 764546a9c7c369df465021feecb20f6a8f81b6df6bcsrs blockSize = (uint32_t) myDisk.GetBlockSize(); 765fed16d043a14e8b86c97a6413aec7281fefcbcb5srs device = deviceFilename; 766546a9c7c369df465021feecb20f6a8f81b6df6bcsrs PartitionScan(); // Check for partition types, load GPT, & print summary 767e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 768ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs whichWasUsed = UseWhichPartitions(); 769ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs switch (whichWasUsed) { 770e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case use_mbr: 771e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs XFormPartitions(); 772e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 773e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case use_bsd: 774546a9c7c369df465021feecb20f6a8f81b6df6bcsrs bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1); 775e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// bsdDisklabel.DisplayBSDData(); 776e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ClearGPTData(); 777e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1) 77808bb0da07953af605b4918e268272de15ac151aasrs XFormDisklabel(&bsdDisklabel); 779e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 780e7b4ff9317fc4e551cf974684eaa88697de5a28srs case use_gpt: 781fed16d043a14e8b86c97a6413aec7281fefcbcb5srs mbrState = protectiveMBR.GetValidity(); 782fed16d043a14e8b86c97a6413aec7281fefcbcb5srs if ((mbrState == invalid) || (mbrState == mbr)) 783fed16d043a14e8b86c97a6413aec7281fefcbcb5srs protectiveMBR.MakeProtectiveMBR(); 784e7b4ff9317fc4e551cf974684eaa88697de5a28srs break; 785e7b4ff9317fc4e551cf974684eaa88697de5a28srs case use_new: 786e7b4ff9317fc4e551cf974684eaa88697de5a28srs ClearGPTData(); 787e7b4ff9317fc4e551cf974684eaa88697de5a28srs protectiveMBR.MakeProtectiveMBR(); 788e7b4ff9317fc4e551cf974684eaa88697de5a28srs break; 7893c0af38237d0f40aaea8233a5cbfdd030a77817dsrs case use_abort: 7903c0af38237d0f40aaea8233a5cbfdd030a77817dsrs allOK = 0; 7919ddc14bb9b154518e2b8384d3f4571cf657c7920srs cerr << "Invalid partition data!\n"; 7923c0af38237d0f40aaea8233a5cbfdd030a77817dsrs break; 793e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // switch 794e7b4ff9317fc4e551cf974684eaa88697de5a28srs 79555d926192adc984462509b2966e23bc0d1129bbdsrs if (allOK) 7963c0af38237d0f40aaea8233a5cbfdd030a77817dsrs CheckGPTSize(); 79755d926192adc984462509b2966e23bc0d1129bbdsrs myDisk.Close(); 798a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs ComputeAlignment(); 799e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 800e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 801e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 802e7b4ff9317fc4e551cf974684eaa88697de5a28srs return (allOK); 803e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::LoadPartitions() 804e7b4ff9317fc4e551cf974684eaa88697de5a28srs 805e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Loads the GPT, as much as possible. Returns 1 if this seems to have 806e7b4ff9317fc4e551cf974684eaa88697de5a28srs// succeeded, 0 if there are obvious problems.... 807546a9c7c369df465021feecb20f6a8f81b6df6bcsrsint GPTData::ForceLoadGPTData(void) { 808cb76c673eeb84344887715d36d44b799042be5a5srs int allOK, validHeaders, loadedTable = 1; 809e7b4ff9317fc4e551cf974684eaa88697de5a28srs 810cb76c673eeb84344887715d36d44b799042be5a5srs allOK = LoadHeader(&mainHeader, myDisk, 1, &mainCrcOk); 811cb76c673eeb84344887715d36d44b799042be5a5srs 812cb76c673eeb84344887715d36d44b799042be5a5srs if (mainCrcOk && (mainHeader.backupLBA < diskSize)) { 813cb76c673eeb84344887715d36d44b799042be5a5srs allOK = LoadHeader(&secondHeader, myDisk, mainHeader.backupLBA, &secondCrcOk) && allOK; 814cb76c673eeb84344887715d36d44b799042be5a5srs } else { 81508bb0da07953af605b4918e268272de15ac151aasrs allOK = LoadHeader(&secondHeader, myDisk, diskSize - UINT64_C(1), &secondCrcOk) && allOK; 81608bb0da07953af605b4918e268272de15ac151aasrs if (mainCrcOk && (mainHeader.backupLBA >= diskSize)) 817fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Warning! Disk size is smaller than the main header indicates! Loading\n" 818fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "secondary header from the last sector of the disk! You should use 'v' to\n" 819fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "verify disk integrity, and perhaps options on the experts' menu to repair\n" 820fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "the disk.\n"; 821cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 822cb76c673eeb84344887715d36d44b799042be5a5srs if (!allOK) 823e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_invalid; 824e7b4ff9317fc4e551cf974684eaa88697de5a28srs 825e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Return valid headers code: 0 = both headers bad; 1 = main header 826e7b4ff9317fc4e551cf974684eaa88697de5a28srs // good, backup bad; 2 = backup header good, main header bad; 827e7b4ff9317fc4e551cf974684eaa88697de5a28srs // 3 = both headers good. Note these codes refer to valid GPT 82823d8d54cdffa9bab0395dab92faa1990410bbb9asrs // signatures, version numbers, and CRCs. 829e7b4ff9317fc4e551cf974684eaa88697de5a28srs validHeaders = CheckHeaderValidity(); 830e7b4ff9317fc4e551cf974684eaa88697de5a28srs 831e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Read partitions (from primary array) 832e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (validHeaders > 0) { // if at least one header is OK.... 833e7b4ff9317fc4e551cf974684eaa88697de5a28srs // GPT appears to be valid.... 834e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_valid; 835e7b4ff9317fc4e551cf974684eaa88697de5a28srs 836e7b4ff9317fc4e551cf974684eaa88697de5a28srs // We're calling the GPT valid, but there's a possibility that one 837e7b4ff9317fc4e551cf974684eaa88697de5a28srs // of the two headers is corrupt. If so, use the one that seems to 838e7b4ff9317fc4e551cf974684eaa88697de5a28srs // be in better shape to regenerate the bad one 839546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (validHeaders == 1) { // valid main header, invalid backup header 840fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aCaution: invalid backup GPT header, but valid main header; regenerating\n" 841fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "backup header from main header.\n\n"; 842e7b4ff9317fc4e551cf974684eaa88697de5a28srs RebuildSecondHeader(); 843546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 844e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondCrcOk = mainCrcOk; // Since regenerated, use CRC validity of main 845546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } else if (validHeaders == 2) { // valid backup header, invalid main header 846fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aCaution: invalid main GPT header, but valid backup; regenerating main header\n" 847fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "from backup!\n\n"; 848546a9c7c369df465021feecb20f6a8f81b6df6bcsrs RebuildMainHeader(); 849546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 850546a9c7c369df465021feecb20f6a8f81b6df6bcsrs mainCrcOk = secondCrcOk; // Since copied, use CRC validity of backup 851e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else/if 852e7b4ff9317fc4e551cf974684eaa88697de5a28srs 853546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // Figure out which partition table to load.... 854546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // Load the main partition table, since either its header's CRC is OK or the 855546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // backup header's CRC is not OK.... 856546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (mainCrcOk || !secondCrcOk) { 857546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (LoadMainTable() == 0) 858546a9c7c369df465021feecb20f6a8f81b6df6bcsrs allOK = 0; 859546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } else { // bad main header CRC and backup header CRC is OK 860546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 861546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (LoadSecondTableAsMain()) { 862cb76c673eeb84344887715d36d44b799042be5a5srs loadedTable = 2; 863fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n"; 864546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } else { // backup table bad, bad main header CRC, but try main table in desperation.... 865546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (LoadMainTable() == 0) { 866546a9c7c369df465021feecb20f6a8f81b6df6bcsrs allOK = 0; 867cb76c673eeb84344887715d36d44b799042be5a5srs loadedTable = 0; 868fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\a\aWarning! Unable to load either main or backup partition table!\n"; 869546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } // if 870546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } // if/else (LoadSecondTableAsMain()) 871546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } // if/else (load partition table) 872e7b4ff9317fc4e551cf974684eaa88697de5a28srs 873cb76c673eeb84344887715d36d44b799042be5a5srs if (loadedTable == 1) 874cb76c673eeb84344887715d36d44b799042be5a5srs secondPartsCrcOk = CheckTable(&secondHeader); 875cb76c673eeb84344887715d36d44b799042be5a5srs else if (loadedTable == 2) 876cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = CheckTable(&mainHeader); 877cb76c673eeb84344887715d36d44b799042be5a5srs else 878cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = secondPartsCrcOk = 0; 879e7b4ff9317fc4e551cf974684eaa88697de5a28srs 880546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // Problem with main partition table; if backup is OK, use it instead.... 881546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) { 882546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 883546a9c7c369df465021feecb20f6a8f81b6df6bcsrs allOK = allOK && LoadSecondTableAsMain(); 884cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = 0; // LoadSecondTableAsMain() resets this, so re-flag as bad 885fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup " 886fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "partition table\ninstead of main partition table!\n\n"; 887cb76c673eeb84344887715d36d44b799042be5a5srs } // if */ 888546a9c7c369df465021feecb20f6a8f81b6df6bcsrs 889e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Check for valid CRCs and warn if there are problems 890e7b4ff9317fc4e551cf974684eaa88697de5a28srs if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) || 891e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs (secondPartsCrcOk == 0)) { 892fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! One or more CRCs don't match. You should repair the disk!\n\n"; 893e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs state = gpt_corrupt; 894ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } // if 895e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 896e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_invalid; 897e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 898e7b4ff9317fc4e551cf974684eaa88697de5a28srs return allOK; 899e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::ForceLoadGPTData() 900e7b4ff9317fc4e551cf974684eaa88697de5a28srs 901247657a5acbb7eb21c336ba84a68b801b7c19be0srs// Loads the partition table pointed to by the main GPT header. The 902e7b4ff9317fc4e551cf974684eaa88697de5a28srs// main GPT header in memory MUST be valid for this call to do anything 903e7b4ff9317fc4e551cf974684eaa88697de5a28srs// sensible! 904546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. 905e7b4ff9317fc4e551cf974684eaa88697de5a28srsint GPTData::LoadMainTable(void) { 906cb76c673eeb84344887715d36d44b799042be5a5srs return LoadPartitionTable(mainHeader, myDisk); 907e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::LoadMainTable() 908e7b4ff9317fc4e551cf974684eaa88697de5a28srs 909e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Load the second (backup) partition table as the primary partition 910546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// table. Used in repair functions, and when starting up if the main 911546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// partition table is damaged. 912546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. 913546a9c7c369df465021feecb20f6a8f81b6df6bcsrsint GPTData::LoadSecondTableAsMain(void) { 914cb76c673eeb84344887715d36d44b799042be5a5srs return LoadPartitionTable(secondHeader, myDisk); 915cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::LoadSecondTableAsMain() 916cb76c673eeb84344887715d36d44b799042be5a5srs 917cb76c673eeb84344887715d36d44b799042be5a5srs// Load a single GPT header (main or backup) from the specified disk device and 918cb76c673eeb84344887715d36d44b799042be5a5srs// sector. Applies byte-order corrections on big-endian platforms. Sets crcOk 919cb76c673eeb84344887715d36d44b799042be5a5srs// value appropriately. 920cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure. Note that CRC errors do NOT qualify as 921cb76c673eeb84344887715d36d44b799042be5a5srs// failure. 922cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::LoadHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector, int *crcOk) { 923cb76c673eeb84344887715d36d44b799042be5a5srs int allOK = 1; 9241c6f8b013e7f5c166abf21c09e319d22b576c41asrs GPTHeader tempHeader; 925cb76c673eeb84344887715d36d44b799042be5a5srs 926cb76c673eeb84344887715d36d44b799042be5a5srs disk.Seek(sector); 9271c6f8b013e7f5c166abf21c09e319d22b576c41asrs if (disk.Read(&tempHeader, 512) != 512) { 928cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; 929cb76c673eeb84344887715d36d44b799042be5a5srs allOK = 0; 930cb76c673eeb84344887715d36d44b799042be5a5srs } // if 931cb76c673eeb84344887715d36d44b799042be5a5srs 9321c6f8b013e7f5c166abf21c09e319d22b576c41asrs // Reverse byte order, if necessary 933cb76c673eeb84344887715d36d44b799042be5a5srs if (IsLittleEndian() == 0) { 93455d926192adc984462509b2966e23bc0d1129bbdsrs ReverseHeaderBytes(&tempHeader); 935cb76c673eeb84344887715d36d44b799042be5a5srs } // if 936d1b11e8305621d73ff675af940e7f1f28b639b0dsrs *crcOk = CheckHeaderCRC(&tempHeader); 9371c6f8b013e7f5c166abf21c09e319d22b576c41asrs 9380283dae41a7db4563be0fe62241ed230e4a101c0srs if (allOK && (numParts != tempHeader.numParts) && *crcOk) { 939706e51217a531c46afc743b556e10fd5c0585fcfsrs allOK = SetGPTSize(tempHeader.numParts, 0); 94055d926192adc984462509b2966e23bc0d1129bbdsrs } 9411c6f8b013e7f5c166abf21c09e319d22b576c41asrs 9421c6f8b013e7f5c166abf21c09e319d22b576c41asrs *header = tempHeader; 943cb76c673eeb84344887715d36d44b799042be5a5srs return allOK; 944cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::LoadHeader 945cb76c673eeb84344887715d36d44b799042be5a5srs 946cb76c673eeb84344887715d36d44b799042be5a5srs// Load a partition table (either main or secondary) from the specified disk, 947cb76c673eeb84344887715d36d44b799042be5a5srs// using header as a reference for what to load. If sector != 0 (the default 948cb76c673eeb84344887715d36d44b799042be5a5srs// is 0), loads from the specified sector; otherwise loads from the sector 949cb76c673eeb84344887715d36d44b799042be5a5srs// indicated in header. 950cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. 951cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::LoadPartitionTable(const struct GPTHeader & header, DiskIO & disk, uint64_t sector) { 952e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t sizeOfParts, newCRC; 953cb76c673eeb84344887715d36d44b799042be5a5srs int retval; 954e7b4ff9317fc4e551cf974684eaa88697de5a28srs 955cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.OpenForRead()) { 956cb76c673eeb84344887715d36d44b799042be5a5srs if (sector == 0) { 957cb76c673eeb84344887715d36d44b799042be5a5srs retval = disk.Seek(header.partitionEntriesLBA); 958cb76c673eeb84344887715d36d44b799042be5a5srs } else { 959cb76c673eeb84344887715d36d44b799042be5a5srs retval = disk.Seek(sector); 960cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 96155d926192adc984462509b2966e23bc0d1129bbdsrs if (retval == 1) 962706e51217a531c46afc743b556e10fd5c0585fcfsrs retval = SetGPTSize(header.numParts, 0); 963546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (retval == 1) { 964cb76c673eeb84344887715d36d44b799042be5a5srs sizeOfParts = header.numParts * header.sizeOfPartitionEntries; 965cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Read(partitions, sizeOfParts) != (int) sizeOfParts) { 966fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n"; 967546a9c7c369df465021feecb20f6a8f81b6df6bcsrs retval = 0; 9685d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 969e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); 970cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = secondPartsCrcOk = (newCRC == header.partitionEntriesCRC); 971e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (IsLittleEndian() == 0) 972e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReversePartitionBytes(); 973cb76c673eeb84344887715d36d44b799042be5a5srs if (!mainPartsCrcOk) { 974cb76c673eeb84344887715d36d44b799042be5a5srs cout << "Caution! After loading partitions, the CRC doesn't check out!\n"; 975e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 976e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 977cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Error! Couldn't seek to partition table!\n"; 978e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 979e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 980fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Error! Couldn't open device " << device 981cb76c673eeb84344887715d36d44b799042be5a5srs << " when reading partition table!\n"; 982546a9c7c369df465021feecb20f6a8f81b6df6bcsrs retval = 0; 983e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 984546a9c7c369df465021feecb20f6a8f81b6df6bcsrs return retval; 985cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::LoadPartitionsTable() 986cb76c673eeb84344887715d36d44b799042be5a5srs 987cb76c673eeb84344887715d36d44b799042be5a5srs// Check the partition table pointed to by header, but don't keep it 988cb76c673eeb84344887715d36d44b799042be5a5srs// around. 989a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Returns 1 if the CRC is OK & this table matches the one already in memory, 990a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// 0 if not or if there was a read error. 991cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::CheckTable(struct GPTHeader *header) { 992cb76c673eeb84344887715d36d44b799042be5a5srs uint32_t sizeOfParts, newCRC; 993a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs GPTPart *partsToCheck; 994d1b11e8305621d73ff675af940e7f1f28b639b0dsrs GPTHeader *otherHeader; 995a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs int allOK = 0; 996cb76c673eeb84344887715d36d44b799042be5a5srs 9970283dae41a7db4563be0fe62241ed230e4a101c0srs // Load partition table into temporary storage to check 998cb76c673eeb84344887715d36d44b799042be5a5srs // its CRC and store the results, then discard this temporary 999cb76c673eeb84344887715d36d44b799042be5a5srs // storage, since we don't use it in any but recovery operations 1000cb76c673eeb84344887715d36d44b799042be5a5srs if (myDisk.Seek(header->partitionEntriesLBA)) { 1001a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs partsToCheck = new GPTPart[header->numParts]; 10020283dae41a7db4563be0fe62241ed230e4a101c0srs sizeOfParts = header->numParts * header->sizeOfPartitionEntries; 1003a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (partsToCheck == NULL) { 10046aae2a9b70e9f88926baad94c1eea40e0b534f01srs cerr << "Could not allocate memory in GPTData::CheckTable()! Terminating!\n"; 10056aae2a9b70e9f88926baad94c1eea40e0b534f01srs exit(1); 10066aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 1007a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (myDisk.Read(partsToCheck, sizeOfParts) != (int) sizeOfParts) { 10080283dae41a7db4563be0fe62241ed230e4a101c0srs cerr << "Warning! Error " << errno << " reading partition table for CRC check!\n"; 1009cb76c673eeb84344887715d36d44b799042be5a5srs } else { 1010d1b11e8305621d73ff675af940e7f1f28b639b0dsrs newCRC = chksum_crc32((unsigned char*) partsToCheck, sizeOfParts); 1011a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs allOK = (newCRC == header->partitionEntriesCRC); 1012d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (header == &mainHeader) 1013d1b11e8305621d73ff675af940e7f1f28b639b0dsrs otherHeader = &secondHeader; 1014d1b11e8305621d73ff675af940e7f1f28b639b0dsrs else 1015d1b11e8305621d73ff675af940e7f1f28b639b0dsrs otherHeader = &mainHeader; 1016d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (newCRC != otherHeader->partitionEntriesCRC) { 1017a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cerr << "Warning! Main and backup partition tables differ! Use the 'c' and 'e' options\n" 1018a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << "on the recovery & transformation menu to examine the two tables.\n\n"; 1019a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs allOK = 0; 1020a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 1021cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 1022a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs delete[] partsToCheck; 1023cb76c673eeb84344887715d36d44b799042be5a5srs } // if 1024a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs return allOK; 1025cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::CheckTable() 1026e7b4ff9317fc4e551cf974684eaa88697de5a28srs 10274307ef2e863cbec357df56197046c6b679fc5d2dsrs// Writes GPT (and protective MBR) to disk. If quiet==1, moves the second 10284307ef2e863cbec357df56197046c6b679fc5d2dsrs// header later on the disk without asking for permission, if necessary, and 10294307ef2e863cbec357df56197046c6b679fc5d2dsrs// doesn't confirm the operation before writing. If quiet==0, asks permission 10304307ef2e863cbec357df56197046c6b679fc5d2dsrs// before moving the second header and asks for final confirmation of any 10314307ef2e863cbec357df56197046c6b679fc5d2dsrs// write. 1032a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Returns 1 on successful write, 0 if there was a problem. 103364cbd171067eb34054741bfcd73f0b91d727a371srsint GPTData::SaveGPTData(int quiet) { 10344307ef2e863cbec357df56197046c6b679fc5d2dsrs int allOK = 1, syncIt = 1; 1035e321d444dcca514cf6b53459e388ddcbaab6176csrs char answer; 10362a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1037e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // First do some final sanity checks.... 10385d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs 10395d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs // This test should only fail on read-only disks.... 10405d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (justLooking) { 1041fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The justLooking flag is set. This probably means you can't write to the disk.\n"; 10425d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs allOK = 0; 10435d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 10445d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs 104564cbd171067eb34054741bfcd73f0b91d727a371srs // Check that disk is really big enough to handle the second header... 104664cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.backupLBA >= diskSize) { 104764cbd171067eb34054741bfcd73f0b91d727a371srs cerr << "Caution! Secondary header was placed beyond the disk's limits! Moving the\n" 104864cbd171067eb34054741bfcd73f0b91d727a371srs << "header, but other problems may occur!\n"; 104964cbd171067eb34054741bfcd73f0b91d727a371srs MoveSecondHeaderToEnd(); 105064cbd171067eb34054741bfcd73f0b91d727a371srs } // if 105164cbd171067eb34054741bfcd73f0b91d727a371srs 1052e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Is there enough space to hold the GPT headers and partition tables, 1053e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // given the partition sizes? 1054e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (CheckGPTSize() > 0) { 1055e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 10562a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 1057e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1058247657a5acbb7eb21c336ba84a68b801b7c19be0srs // Check that second header is properly placed. Warn and ask if this should 1059247657a5acbb7eb21c336ba84a68b801b7c19be0srs // be corrected if the test fails.... 106064cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) { 106164cbd171067eb34054741bfcd73f0b91d727a371srs if (quiet == 0) { 106264cbd171067eb34054741bfcd73f0b91d727a371srs cout << "Warning! Secondary header is placed too early on the disk! Do you want to\n" 106364cbd171067eb34054741bfcd73f0b91d727a371srs << "correct this problem? "; 106464cbd171067eb34054741bfcd73f0b91d727a371srs if (GetYN() == 'Y') { 106564cbd171067eb34054741bfcd73f0b91d727a371srs MoveSecondHeaderToEnd(); 106664cbd171067eb34054741bfcd73f0b91d727a371srs cout << "Have moved second header and partition table to correct location.\n"; 106764cbd171067eb34054741bfcd73f0b91d727a371srs } else { 106864cbd171067eb34054741bfcd73f0b91d727a371srs cout << "Have not corrected the problem. Strange problems may occur in the future!\n"; 106964cbd171067eb34054741bfcd73f0b91d727a371srs } // if correction requested 107064cbd171067eb34054741bfcd73f0b91d727a371srs } else { // Go ahead and do correction automatically 1071247657a5acbb7eb21c336ba84a68b801b7c19be0srs MoveSecondHeaderToEnd(); 107264cbd171067eb34054741bfcd73f0b91d727a371srs } // if/else quiet 1073247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if 1074e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1075d8eed4629449a325999808a0170dbda53bd4a6dfsrs if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) { 1076d8eed4629449a325999808a0170dbda53bd4a6dfsrs if (quiet == 0) { 1077d8eed4629449a325999808a0170dbda53bd4a6dfsrs cout << "Warning! The claimed last usable sector is incorrect! Do you want to correct\n" 1078d8eed4629449a325999808a0170dbda53bd4a6dfsrs << "this problem? "; 1079d8eed4629449a325999808a0170dbda53bd4a6dfsrs if (GetYN() == 'Y') { 1080d8eed4629449a325999808a0170dbda53bd4a6dfsrs MoveSecondHeaderToEnd(); 1081d8eed4629449a325999808a0170dbda53bd4a6dfsrs cout << "Have adjusted the second header and last usable sector value.\n"; 1082d8eed4629449a325999808a0170dbda53bd4a6dfsrs } else { 1083d8eed4629449a325999808a0170dbda53bd4a6dfsrs cout << "Have not corrected the problem. Strange problems may occur in the future!\n"; 1084d8eed4629449a325999808a0170dbda53bd4a6dfsrs } // if correction requested 1085d8eed4629449a325999808a0170dbda53bd4a6dfsrs } else { // go ahead and do correction automatically 1086d8eed4629449a325999808a0170dbda53bd4a6dfsrs MoveSecondHeaderToEnd(); 1087d8eed4629449a325999808a0170dbda53bd4a6dfsrs } // if/else quiet 1088d8eed4629449a325999808a0170dbda53bd4a6dfsrs } // if 1089d8eed4629449a325999808a0170dbda53bd4a6dfsrs 109055d926192adc984462509b2966e23bc0d1129bbdsrs // Check for overlapping or insane partitions.... 109155d926192adc984462509b2966e23bc0d1129bbdsrs if ((FindOverlaps() > 0) || (FindInsanePartitions() > 0)) { 1092e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1093fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Aborting write operation!\n"; 1094e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1095e7b4ff9317fc4e551cf974684eaa88697de5a28srs 10964a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith // Check that protective MBR fits, and warn if it doesn't.... 10974a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if (!protectiveMBR.DoTheyFit()) { 10984a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith cerr << "\nPartition(s) in the protective MBR are too big for the disk! Creating a\n" 10994a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith << "fresh protective or hybrid MBR is recommended.\n"; 11004a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } 11014a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith 1102e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for mismatched MBR and GPT data, but let it pass if found 1103e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // (function displays warning message) 1104e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs FindHybridMismatches(); 1105e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1106e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs RecomputeCRCs(); 1107e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1108ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if ((allOK) && (!quiet)) { 1109fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n" 1110bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs << "PARTITIONS!!\n\nDo you want to proceed? "; 11115d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs answer = GetYN(); 11125d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (answer == 'Y') { 11133488294d718a0e8b7f312c80c9e5729671173f6asrs cout << "OK; writing new GUID partition table (GPT) to " << myDisk.GetName() << ".\n"; 1114e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1115e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1116e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1117e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1118e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1119e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Do it! 1120e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) { 112164cbd171067eb34054741bfcd73f0b91d727a371srs if (myDisk.OpenForWrite()) { 11228a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // As per UEFI specs, write the secondary table and GPT first.... 1123cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SavePartitionTable(myDisk, secondHeader.partitionEntriesLBA); 11244307ef2e863cbec357df56197046c6b679fc5d2dsrs if (!allOK) { 1125cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Unable to save backup partition table! Perhaps the 'e' option on the experts'\n" 1126cb76c673eeb84344887715d36d44b799042be5a5srs << "menu will resolve this problem.\n"; 11274307ef2e863cbec357df56197046c6b679fc5d2dsrs syncIt = 0; 11284307ef2e863cbec357df56197046c6b679fc5d2dsrs } // if 1129e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1130e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now write the secondary GPT header... 11318a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && SaveHeader(&secondHeader, myDisk, mainHeader.backupLBA); 11328a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 11338a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // Now write the main partition tables... 11348a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && SavePartitionTable(myDisk, mainHeader.partitionEntriesLBA); 11358a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 11368a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // Now write the main GPT header... 11378a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && SaveHeader(&mainHeader, myDisk, 1); 11388a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 11398a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // To top it off, write the protective MBR... 11408a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && protectiveMBR.WriteMBRData(&myDisk); 1141e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1142e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // re-read the partition table 11434307ef2e863cbec357df56197046c6b679fc5d2dsrs // Note: Done even if some write operations failed, but not if all of them failed. 11444307ef2e863cbec357df56197046c6b679fc5d2dsrs // Done this way because I've received one problem report from a user one whose 11454307ef2e863cbec357df56197046c6b679fc5d2dsrs // system the MBR write failed but everything else was OK (on a GPT disk under 11464307ef2e863cbec357df56197046c6b679fc5d2dsrs // Windows), and the failure to sync therefore caused Windows to restore the 11474307ef2e863cbec357df56197046c6b679fc5d2dsrs // original partition table from its cache. OTOH, such restoration might be 11484307ef2e863cbec357df56197046c6b679fc5d2dsrs // desirable if the error occurs later; but that seems unlikely unless the initial 11494307ef2e863cbec357df56197046c6b679fc5d2dsrs // write fails.... 11502c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman if (syncIt && syncing) 1151546a9c7c369df465021feecb20f6a8f81b6df6bcsrs myDisk.DiskSync(); 1152e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1153e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) { // writes completed OK 1154fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The operation has completed successfully.\n"; 1155e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1156fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! An error was reported when writing the partition table! This error\n" 11574307ef2e863cbec357df56197046c6b679fc5d2dsrs << "MIGHT be harmless, or the disk might be damaged! Checking it is advisable.\n"; 1158e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 11598a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 1160546a9c7c369df465021feecb20f6a8f81b6df6bcsrs myDisk.Close(); 1161e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 11625a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Unable to open device '" << myDisk.GetName() << "' for writing! Errno is " 1163fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << errno << "! Aborting write!\n"; 1164e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1165e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1166e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 1167fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Aborting write of new partition table.\n"; 1168e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 1169e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1170e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (allOK); 1171e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SaveGPTData() 1172e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1173e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Save GPT data to a backup file. This function does much less error 1174e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// checking than SaveGPTData(). It can therefore preserve many types of 1175e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// corruption for later analysis; however, it preserves only the MBR, 1176e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// the main GPT header, the backup GPT header, and the main partition 1177e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// table; it discards the backup partition table, since it should be 1178e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// identical to the main partition table on healthy disks. 11790a6973119c9e9984ad47a6da3231e8d16f996c5csrsint GPTData::SaveGPTBackup(const string & filename) { 11800a6973119c9e9984ad47a6da3231e8d16f996c5csrs int allOK = 1; 1181546a9c7c369df465021feecb20f6a8f81b6df6bcsrs DiskIO backupFile; 1182e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1183546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (backupFile.OpenForWrite(filename)) { 11846699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // Recomputing the CRCs is likely to alter them, which could be bad 11856699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // if the intent is to save a potentially bad GPT for later analysis; 11866699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // but if we don't do this, we get bogus errors when we load the 11876699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // backup. I'm favoring misses over false alarms.... 11886699b01eda84d24bfaf80ad725304fef2b0e1b2asrs RecomputeCRCs(); 11896699b01eda84d24bfaf80ad725304fef2b0e1b2asrs 1190546a9c7c369df465021feecb20f6a8f81b6df6bcsrs protectiveMBR.WriteMBRData(&backupFile); 1191699941e25a1fcf0beec124203747c8ed20842989srs protectiveMBR.SetDisk(&myDisk); 1192e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1193cb76c673eeb84344887715d36d44b799042be5a5srs if (allOK) { 1194546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // MBR write closed disk, so re-open and seek to end.... 1195546a9c7c369df465021feecb20f6a8f81b6df6bcsrs backupFile.OpenForWrite(); 1196cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SaveHeader(&mainHeader, backupFile, 1); 1197cb76c673eeb84344887715d36d44b799042be5a5srs } // if (allOK) 1198e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1199e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) 1200cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SaveHeader(&secondHeader, backupFile, 2); 1201e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1202cb76c673eeb84344887715d36d44b799042be5a5srs if (allOK) 1203cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SavePartitionTable(backupFile, 3); 1204e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1205e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) { // writes completed OK 1206fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The operation has completed successfully.\n"; 1207e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1208fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! An error was reported when writing the backup file.\n" 1209fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "It may not be usable!\n"; 1210e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1211546a9c7c369df465021feecb20f6a8f81b6df6bcsrs backupFile.Close(); 1212e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 12135a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Unable to open file '" << filename << "' for writing! Aborting!\n"; 1214e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1215e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 1216e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return allOK; 1217e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SaveGPTBackup() 1218e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1219cb76c673eeb84344887715d36d44b799042be5a5srs// Write a GPT header (main or backup) to the specified sector. Used by both 1220cb76c673eeb84344887715d36d44b799042be5a5srs// the SaveGPTData() and SaveGPTBackup() functions. 1221cb76c673eeb84344887715d36d44b799042be5a5srs// Should be passed an architecture-appropriate header (DO NOT call 1222cb76c673eeb84344887715d36d44b799042be5a5srs// ReverseHeaderBytes() on the header before calling this function) 1223cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure 1224cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::SaveHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector) { 1225cb76c673eeb84344887715d36d44b799042be5a5srs int littleEndian, allOK = 1; 1226cb76c673eeb84344887715d36d44b799042be5a5srs 1227cb76c673eeb84344887715d36d44b799042be5a5srs littleEndian = IsLittleEndian(); 1228cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1229cb76c673eeb84344887715d36d44b799042be5a5srs ReverseHeaderBytes(header); 1230cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Seek(sector)) { 1231cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Write(header, 512) == -1) 1232cb76c673eeb84344887715d36d44b799042be5a5srs allOK = 0; 1233cb76c673eeb84344887715d36d44b799042be5a5srs } else allOK = 0; // if (disk.Seek()...) 1234cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1235cb76c673eeb84344887715d36d44b799042be5a5srs ReverseHeaderBytes(header); 1236cb76c673eeb84344887715d36d44b799042be5a5srs return allOK; 1237cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::SaveHeader() 1238cb76c673eeb84344887715d36d44b799042be5a5srs 1239cb76c673eeb84344887715d36d44b799042be5a5srs// Save the partitions to the specified sector. Used by both the SaveGPTData() 1240cb76c673eeb84344887715d36d44b799042be5a5srs// and SaveGPTBackup() functions. 1241cb76c673eeb84344887715d36d44b799042be5a5srs// Should be passed an architecture-appropriate header (DO NOT call 1242cb76c673eeb84344887715d36d44b799042be5a5srs// ReverseHeaderBytes() on the header before calling this function) 1243cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure 1244cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::SavePartitionTable(DiskIO & disk, uint64_t sector) { 1245cb76c673eeb84344887715d36d44b799042be5a5srs int littleEndian, allOK = 1; 1246cb76c673eeb84344887715d36d44b799042be5a5srs 1247cb76c673eeb84344887715d36d44b799042be5a5srs littleEndian = IsLittleEndian(); 1248cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Seek(sector)) { 1249cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1250cb76c673eeb84344887715d36d44b799042be5a5srs ReversePartitionBytes(); 12510283dae41a7db4563be0fe62241ed230e4a101c0srs if (disk.Write(partitions, mainHeader.sizeOfPartitionEntries * numParts) == -1) 1252cb76c673eeb84344887715d36d44b799042be5a5srs allOK = 0; 1253cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1254cb76c673eeb84344887715d36d44b799042be5a5srs ReversePartitionBytes(); 1255cb76c673eeb84344887715d36d44b799042be5a5srs } else allOK = 0; // if (myDisk.Seek()...) 1256cb76c673eeb84344887715d36d44b799042be5a5srs return allOK; 1257cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::SavePartitionTable() 1258cb76c673eeb84344887715d36d44b799042be5a5srs 1259e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Load GPT data from a backup file created by SaveGPTBackup(). This function 1260e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// does minimal error checking. It returns 1 if it completed successfully, 1261e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// 0 if there was a problem. In the latter case, it creates a new empty 1262e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// set of partitions. 12630a6973119c9e9984ad47a6da3231e8d16f996c5csrsint GPTData::LoadGPTBackup(const string & filename) { 1264cb76c673eeb84344887715d36d44b799042be5a5srs int allOK = 1, val, err; 12650541b56fee4e92822340a2b2387508dd58d0ca7csrs int shortBackup = 0; 1266546a9c7c369df465021feecb20f6a8f81b6df6bcsrs DiskIO backupFile; 1267e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1268546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (backupFile.OpenForRead(filename)) { 1269e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Let the MBRData class load the saved MBR... 1270546a9c7c369df465021feecb20f6a8f81b6df6bcsrs protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size 1271815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs protectiveMBR.SetDisk(&myDisk); 1272e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1273cb76c673eeb84344887715d36d44b799042be5a5srs LoadHeader(&mainHeader, backupFile, 1, &mainCrcOk); 1274e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1275cb76c673eeb84344887715d36d44b799042be5a5srs // Check backup file size and rebuild second header if file is right 1276cb76c673eeb84344887715d36d44b799042be5a5srs // size to be direct dd copy of MBR, main header, and main partition 1277cb76c673eeb84344887715d36d44b799042be5a5srs // table; if other size, treat it like a GPT fdisk-generated backup 1278cb76c673eeb84344887715d36d44b799042be5a5srs // file 1279cb76c673eeb84344887715d36d44b799042be5a5srs shortBackup = ((backupFile.DiskSize(&err) * backupFile.GetBlockSize()) == 1280cb76c673eeb84344887715d36d44b799042be5a5srs (mainHeader.numParts * mainHeader.sizeOfPartitionEntries) + 1024); 1281cb76c673eeb84344887715d36d44b799042be5a5srs if (shortBackup) { 1282cb76c673eeb84344887715d36d44b799042be5a5srs RebuildSecondHeader(); 1283cb76c673eeb84344887715d36d44b799042be5a5srs secondCrcOk = mainCrcOk; 1284cb76c673eeb84344887715d36d44b799042be5a5srs } else { 1285cb76c673eeb84344887715d36d44b799042be5a5srs LoadHeader(&secondHeader, backupFile, 2, &secondCrcOk); 1286cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 1287e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1288e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Return valid headers code: 0 = both headers bad; 1 = main header 1289e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // good, backup bad; 2 = backup header good, main header bad; 1290e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // 3 = both headers good. Note these codes refer to valid GPT 1291e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // signatures and version numbers; more subtle problems will elude 1292e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // this check! 1293e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((val = CheckHeaderValidity()) > 0) { 1294e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (val == 2) { // only backup header seems to be good 1295706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(secondHeader.numParts, 0); 1296e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { // main header is OK 1297706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(mainHeader.numParts, 0); 1298e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1299e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1300e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (secondHeader.currentLBA != diskSize - UINT64_C(1)) { 1301fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Warning! Current disk size doesn't match that of the backup!\n" 1302fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "Adjusting sizes to match, but subsequent problems are possible!\n"; 1303247657a5acbb7eb21c336ba84a68b801b7c19be0srs MoveSecondHeaderToEnd(); 1304e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1305e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1306cb76c673eeb84344887715d36d44b799042be5a5srs if (!LoadPartitionTable(mainHeader, backupFile, (uint64_t) (3 - shortBackup))) 1307cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Warning! Read error " << errno 1308cb76c673eeb84344887715d36d44b799042be5a5srs << " loading partition table; strange behavior now likely!\n"; 1309e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1310e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1311e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1312a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs // Something went badly wrong, so blank out partitions 1313a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs if (allOK == 0) { 1314a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs cerr << "Improper backup file! Clearing all partition data!\n"; 1315a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs ClearGPTData(); 1316a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs protectiveMBR.MakeProtectiveMBR(); 1317a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // if 1318e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1319e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 13205a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Unable to open file '" << filename << "' for reading! Aborting!\n"; 1321e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1322e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1323e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return allOK; 1324e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::LoadGPTBackup() 1325e7b4ff9317fc4e551cf974684eaa88697de5a28srs 132608bb0da07953af605b4918e268272de15ac151aasrsint GPTData::SaveMBR(void) { 132755d926192adc984462509b2966e23bc0d1129bbdsrs return protectiveMBR.WriteMBRData(&myDisk); 132808bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::SaveMBR() 132908bb0da07953af605b4918e268272de15ac151aasrs 133008bb0da07953af605b4918e268272de15ac151aasrs// This function destroys the on-disk GPT structures, but NOT the on-disk 133108bb0da07953af605b4918e268272de15ac151aasrs// MBR. 133208bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if the operation succeeds, 0 if not. 133308bb0da07953af605b4918e268272de15ac151aasrsint GPTData::DestroyGPT(void) { 133401f7f08624f0c942001977415214a578621f6495srs int sum, tableSize, allOK = 1; 133508bb0da07953af605b4918e268272de15ac151aasrs uint8_t blankSector[512]; 133608bb0da07953af605b4918e268272de15ac151aasrs uint8_t* emptyTable; 133708bb0da07953af605b4918e268272de15ac151aasrs 133801f7f08624f0c942001977415214a578621f6495srs memset(blankSector, 0, sizeof(blankSector)); 133984aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith ClearGPTData(); 134008bb0da07953af605b4918e268272de15ac151aasrs 134108bb0da07953af605b4918e268272de15ac151aasrs if (myDisk.OpenForWrite()) { 134208bb0da07953af605b4918e268272de15ac151aasrs if (!myDisk.Seek(mainHeader.currentLBA)) 134308bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 134408bb0da07953af605b4918e268272de15ac151aasrs if (myDisk.Write(blankSector, 512) != 512) { // blank it out 134508bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! GPT main header not overwritten! Error is " << errno << "\n"; 134608bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 134708bb0da07953af605b4918e268272de15ac151aasrs } // if 134808bb0da07953af605b4918e268272de15ac151aasrs if (!myDisk.Seek(mainHeader.partitionEntriesLBA)) 134908bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 13500283dae41a7db4563be0fe62241ed230e4a101c0srs tableSize = numParts * mainHeader.sizeOfPartitionEntries; 135108bb0da07953af605b4918e268272de15ac151aasrs emptyTable = new uint8_t[tableSize]; 13526aae2a9b70e9f88926baad94c1eea40e0b534f01srs if (emptyTable == NULL) { 135384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "Could not allocate memory in GPTData::DestroyGPT()! Terminating!\n"; 135484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith exit(1); 13556aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 135601f7f08624f0c942001977415214a578621f6495srs memset(emptyTable, 0, tableSize); 135708bb0da07953af605b4918e268272de15ac151aasrs if (allOK) { 135808bb0da07953af605b4918e268272de15ac151aasrs sum = myDisk.Write(emptyTable, tableSize); 135908bb0da07953af605b4918e268272de15ac151aasrs if (sum != tableSize) { 136008bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n"; 136108bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 136208bb0da07953af605b4918e268272de15ac151aasrs } // if write failed 136384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if 136484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (!myDisk.Seek(secondHeader.partitionEntriesLBA)) 136584aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith allOK = 0; 136684aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (allOK) { 136784aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith sum = myDisk.Write(emptyTable, tableSize); 136884aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (sum != tableSize) { 136984aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "Warning! GPT backup partition table not overwritten! Error is " 137084aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith << errno << "\n"; 137108bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 137284aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if wrong size written 137384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if 137484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (!myDisk.Seek(secondHeader.currentLBA)) 137584aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith allOK = 0; 137684aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (allOK) { 137784aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (myDisk.Write(blankSector, 512) != 512) { // blank it out 137884aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "Warning! GPT backup header not overwritten! Error is " << errno << "\n"; 13795435fcf5c47caf8c77034f7a277642d1e23e90f8Roderick W. Smith allOK = 0; 13805435fcf5c47caf8c77034f7a277642d1e23e90f8Roderick W. Smith } // if 138184aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if 13822c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman if (syncing) { 13832c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman myDisk.DiskSync(); 13842c2deeb032f6c158cf4f782e1765a4a21af88cb3Greg Hartman } 138508bb0da07953af605b4918e268272de15ac151aasrs myDisk.Close(); 138608bb0da07953af605b4918e268272de15ac151aasrs cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n" 138708bb0da07953af605b4918e268272de15ac151aasrs << "other utilities.\n"; 138808bb0da07953af605b4918e268272de15ac151aasrs delete[] emptyTable; 138908bb0da07953af605b4918e268272de15ac151aasrs } else { 13905a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Problem opening '" << device << "' for writing! Program will now terminate.\n"; 139108bb0da07953af605b4918e268272de15ac151aasrs } // if/else (fd != -1) 139208bb0da07953af605b4918e268272de15ac151aasrs return (allOK); 139308bb0da07953af605b4918e268272de15ac151aasrs} // GPTDataTextUI::DestroyGPT() 139408bb0da07953af605b4918e268272de15ac151aasrs 139508bb0da07953af605b4918e268272de15ac151aasrs// Wipe MBR data from the disk (zero it out completely) 139608bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 on success, 0 on failure. 139708bb0da07953af605b4918e268272de15ac151aasrsint GPTData::DestroyMBR(void) { 139801f7f08624f0c942001977415214a578621f6495srs int allOK; 139908bb0da07953af605b4918e268272de15ac151aasrs uint8_t blankSector[512]; 140008bb0da07953af605b4918e268272de15ac151aasrs 140101f7f08624f0c942001977415214a578621f6495srs memset(blankSector, 0, sizeof(blankSector)); 140201f7f08624f0c942001977415214a578621f6495srs 140301f7f08624f0c942001977415214a578621f6495srs allOK = myDisk.OpenForWrite() && myDisk.Seek(0) && (myDisk.Write(blankSector, 512) == 512); 140408bb0da07953af605b4918e268272de15ac151aasrs 140508bb0da07953af605b4918e268272de15ac151aasrs if (!allOK) 140608bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! MBR not overwritten! Error is " << errno << "!\n"; 140708bb0da07953af605b4918e268272de15ac151aasrs return allOK; 140808bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::DestroyMBR(void) 140908bb0da07953af605b4918e268272de15ac151aasrs 1410e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Tell user whether Apple Partition Map (APM) was discovered.... 1411e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::ShowAPMState(void) { 1412e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (apmFound) 1413fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " APM: present\n"; 1414e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs else 1415fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " APM: not present\n"; 1416e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ShowAPMState() 1417e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1418e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Tell user about the state of the GPT data.... 1419e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::ShowGPTState(void) { 1420e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs switch (state) { 1421e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case gpt_invalid: 1422fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " GPT: not present\n"; 1423e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1424e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case gpt_valid: 1425fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " GPT: present\n"; 1426e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1427e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case gpt_corrupt: 1428fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " GPT: damaged\n"; 1429e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1430e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs default: 1431fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\a GPT: unknown -- bug!\n"; 1432e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1433e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // switch 1434e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ShowGPTState() 1435e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1436e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Display the basic GPT data 1437e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::DisplayGPTData(void) { 1438e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i; 1439e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t temp, totalFree; 1440e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1441fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Disk " << device << ": " << diskSize << " sectors, " 144201f7f08624f0c942001977415214a578621f6495srs << BytesToIeee(diskSize, blockSize) << "\n"; 1443fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Logical sector size: " << blockSize << " bytes\n"; 14445a081757ea2e32a491349544fea92826ccf739f6srs cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n"; 14450283dae41a7db4563be0fe62241ed230e4a101c0srs cout << "Partition table holds up to " << numParts << " entries\n"; 1446fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "First usable sector is " << mainHeader.firstUsableLBA 1447fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ", last usable sector is " << mainHeader.lastUsableLBA << "\n"; 1448e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs totalFree = FindFreeBlocks(&i, &temp); 14498a4ddfc919d5569c68489cf53d9cf5abc94c410csrs cout << "Partitions will be aligned on " << sectorAlignment << "-sector boundaries\n"; 1450fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Total free space is " << totalFree << " sectors (" 145101f7f08624f0c942001977415214a578621f6495srs << BytesToIeee(totalFree, blockSize) << ")\n"; 1452fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nNumber Start (sector) End (sector) Size Code Name\n"; 14530283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 1454978041ca613dcb881763b36cf53639d924e52a56srs partitions[i].ShowSummary(i, blockSize); 1455e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // for 1456e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::DisplayGPTData() 1457e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1458e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Show detailed information on the specified partition 1459d761ff5a2aac9d9b6bd0bc8236419b1cf0128c86Jeff Sharkeyvoid GPTData::ShowPartDetails(uint32_t partNum) { 146024bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if ((partNum < numParts) && !IsFreePartNum(partNum)) { 1461d761ff5a2aac9d9b6bd0bc8236419b1cf0128c86Jeff Sharkey partitions[partNum].ShowDetails(blockSize); 1462e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 146324bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith cout << "Partition #" << partNum + 1 << " does not exist.\n"; 1464221e08768de7fe42ba533ca22baf671420569c07srs } // if 1465e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ShowPartDetails() 1466221e08768de7fe42ba533ca22baf671420569c07srs 1467e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/************************************************************************** 1468e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1469e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Partition table transformation functions (MBR or BSD disklabel to GPT) * 1470e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * (some of these functions may require user interaction) * 1471e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1472e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs **************************************************************************/ 1473e7b4ff9317fc4e551cf974684eaa88697de5a28srs 147408bb0da07953af605b4918e268272de15ac151aasrs// Examines the MBR & GPT data to determine which set of data to use: the 147508bb0da07953af605b4918e268272de15ac151aasrs// MBR (use_mbr), the GPT (use_gpt), the BSD disklabel (use_bsd), or create 147608bb0da07953af605b4918e268272de15ac151aasrs// a new set of partitions (use_new). A return value of use_abort indicates 147708bb0da07953af605b4918e268272de15ac151aasrs// that this function couldn't determine what to do. Overriding functions 147808bb0da07953af605b4918e268272de15ac151aasrs// in derived classes may ask users questions in such cases. 1479e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsWhichToUse GPTData::UseWhichPartitions(void) { 1480e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs WhichToUse which = use_new; 1481e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs MBRValidity mbrState; 1482e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1483e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mbrState = protectiveMBR.GetValidity(); 1484e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1485e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) { 1486fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n***************************************************************\n" 14871eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "Found invalid GPT and valid MBR; converting MBR to GPT format\n" 14881eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "in memory. "; 14895d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (!justLooking) { 14901eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith cout << "\aTHIS OPERATION IS POTENTIALLY DESTRUCTIVE! Exit by\n" 14911eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "typing 'q' if you don't want to convert your MBR partitions\n" 14921eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "to GPT format!"; 14935d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 14941eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith cout << "\n***************************************************************\n\n"; 1495e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_mbr; 14962a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 14972a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1498e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_invalid) && bsdFound) { 1499fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n**********************************************************************\n" 1500fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n" 1501fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "to GPT format."; 15020a6973119c9e9984ad47a6da3231e8d16f996c5csrs if ((!justLooking) && (!beQuiet)) { 15030283dae41a7db4563be0fe62241ed230e4a101c0srs cout << "\a THIS OPERATION IS POTENTIALLY DESTRUCTIVE! Your first\n" 1504fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "BSD partition will likely be unusable. Exit by typing 'q' if you don't\n" 1505fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "want to convert your BSD partitions to GPT format!"; 15065d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 1507fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n**********************************************************************\n\n"; 1508e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_bsd; 15092a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 1510e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1511e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == gpt)) { 1512e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_gpt; 15133c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (!beQuiet) 1514fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Found valid GPT with protective MBR; using GPT.\n"; 1515e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1516e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == hybrid)) { 1517e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_gpt; 15183c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (!beQuiet) 1519fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Found valid GPT with hybrid MBR; using GPT.\n"; 1520e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1521e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == invalid)) { 15220a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "\aFound valid GPT with corrupt MBR; using GPT and will write new\n" 1523fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "protective MBR on save.\n"; 1524e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_gpt; 1525e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1526e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == mbr)) { 152708bb0da07953af605b4918e268272de15ac151aasrs which = use_abort; 15283c0af38237d0f40aaea8233a5cbfdd030a77817dsrs } // if 15293c0af38237d0f40aaea8233a5cbfdd030a77817dsrs 15303c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (state == gpt_corrupt) { 153108bb0da07953af605b4918e268272de15ac151aasrs if (mbrState == gpt) { 153208bb0da07953af605b4918e268272de15ac151aasrs cout << "\a\a****************************************************************************\n" 153308bb0da07953af605b4918e268272de15ac151aasrs << "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n" 153408bb0da07953af605b4918e268272de15ac151aasrs << "verification and recovery are STRONGLY recommended.\n" 153508bb0da07953af605b4918e268272de15ac151aasrs << "****************************************************************************\n"; 153608bb0da07953af605b4918e268272de15ac151aasrs which = use_gpt; 15373c0af38237d0f40aaea8233a5cbfdd030a77817dsrs } else { 153808bb0da07953af605b4918e268272de15ac151aasrs which = use_abort; 153908bb0da07953af605b4918e268272de15ac151aasrs } // if/else MBR says disk is GPT 154008bb0da07953af605b4918e268272de15ac151aasrs } // if GPT corrupt 1541e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1542e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (which == use_new) 1543fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Creating new GPT entries.\n"; 1544e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1545e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return which; 1546e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // UseWhichPartitions() 1547e7b4ff9317fc4e551cf974684eaa88697de5a28srs 154808bb0da07953af605b4918e268272de15ac151aasrs// Convert MBR partition table into GPT form. 154908bb0da07953af605b4918e268272de15ac151aasrsvoid GPTData::XFormPartitions(void) { 1550e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int i, numToConvert; 1551e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint8_t origType; 1552221e08768de7fe42ba533ca22baf671420569c07srs 1553e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Clear out old data & prepare basics.... 1554e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ClearGPTData(); 1555e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1556e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Convert the smaller of the # of GPT or MBR partitions 15570283dae41a7db4563be0fe62241ed230e4a101c0srs if (numParts > MAX_MBR_PARTS) 1558978041ca613dcb881763b36cf53639d924e52a56srs numToConvert = MAX_MBR_PARTS; 1559e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs else 15600283dae41a7db4563be0fe62241ed230e4a101c0srs numToConvert = numParts; 1561e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1562e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < numToConvert; i++) { 1563e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs origType = protectiveMBR.GetType(i); 1564e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // don't waste CPU time trying to convert extended, hybrid protective, or 1565e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // null (non-existent) partitions 1566e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 15676699b01eda84d24bfaf80ad725304fef2b0e1b2asrs (origType != 0x00) && (origType != 0xEE)) 1568e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[i] = protectiveMBR.AsGPT(i); 1569e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 1570e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1571e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Convert MBR into protective MBR 1572e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs protectiveMBR.MakeProtectiveMBR(); 1573e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1574e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Record that all original CRCs were OK so as not to raise flags 1575e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // when doing a disk verification 1576e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1; 1577e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::XFormPartitions() 1578e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1579e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Transforms BSD disklabel on the specified partition (numbered from 0). 158008bb0da07953af605b4918e268272de15ac151aasrs// If an invalid partition number is given, the program does nothing. 1581e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Returns the number of new partitions created. 158208bb0da07953af605b4918e268272de15ac151aasrsint GPTData::XFormDisklabel(uint32_t partNum) { 158308bb0da07953af605b4918e268272de15ac151aasrs uint32_t low, high; 1584e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int goOn = 1, numDone = 0; 1585e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs BSDData disklabel; 1586e7b4ff9317fc4e551cf974684eaa88697de5a28srs 158708bb0da07953af605b4918e268272de15ac151aasrs if (GetPartRange(&low, &high) == 0) { 158808bb0da07953af605b4918e268272de15ac151aasrs goOn = 0; 158908bb0da07953af605b4918e268272de15ac151aasrs cout << "No partitions!\n"; 159008bb0da07953af605b4918e268272de15ac151aasrs } // if 159108bb0da07953af605b4918e268272de15ac151aasrs if (partNum > high) { 159208bb0da07953af605b4918e268272de15ac151aasrs goOn = 0; 159308bb0da07953af605b4918e268272de15ac151aasrs cout << "Specified partition is invalid!\n"; 159408bb0da07953af605b4918e268272de15ac151aasrs } // if 1595e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 159608bb0da07953af605b4918e268272de15ac151aasrs // If all is OK, read the disklabel and convert it. 159708bb0da07953af605b4918e268272de15ac151aasrs if (goOn) { 159808bb0da07953af605b4918e268272de15ac151aasrs goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(), 159908bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum].GetLastLBA()); 160008bb0da07953af605b4918e268272de15ac151aasrs if ((goOn) && (disklabel.IsDisklabel())) { 160108bb0da07953af605b4918e268272de15ac151aasrs numDone = XFormDisklabel(&disklabel); 160208bb0da07953af605b4918e268272de15ac151aasrs if (numDone == 1) 160308bb0da07953af605b4918e268272de15ac151aasrs cout << "Converted 1 BSD partition.\n"; 160408bb0da07953af605b4918e268272de15ac151aasrs else 160508bb0da07953af605b4918e268272de15ac151aasrs cout << "Converted " << numDone << " BSD partitions.\n"; 160608bb0da07953af605b4918e268272de15ac151aasrs } else { 160708bb0da07953af605b4918e268272de15ac151aasrs cout << "Unable to convert partitions! Unrecognized BSD disklabel.\n"; 160808bb0da07953af605b4918e268272de15ac151aasrs } // if/else 160908bb0da07953af605b4918e268272de15ac151aasrs } // if 161008bb0da07953af605b4918e268272de15ac151aasrs if (numDone > 0) { // converted partitions; delete carrier 161108bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum].BlankPartition(); 161208bb0da07953af605b4918e268272de15ac151aasrs } // if 1613e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numDone; 161455d926192adc984462509b2966e23bc0d1129bbdsrs} // GPTData::XFormDisklabel(uint32_t i) 1615e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1616e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Transform the partitions on an already-loaded BSD disklabel... 161708bb0da07953af605b4918e268272de15ac151aasrsint GPTData::XFormDisklabel(BSDData* disklabel) { 161808bb0da07953af605b4918e268272de15ac151aasrs int i, partNum = 0, numDone = 0; 1619e7b4ff9317fc4e551cf974684eaa88697de5a28srs 162008bb0da07953af605b4918e268272de15ac151aasrs if (disklabel->IsDisklabel()) { 1621e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < disklabel->GetNumParts(); i++) { 162208bb0da07953af605b4918e268272de15ac151aasrs partNum = FindFirstFreePart(); 162308bb0da07953af605b4918e268272de15ac151aasrs if (partNum >= 0) { 162408bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum] = disklabel->AsGPT(i); 162508bb0da07953af605b4918e268272de15ac151aasrs if (partitions[partNum].IsUsed()) 162608bb0da07953af605b4918e268272de15ac151aasrs numDone++; 162708bb0da07953af605b4918e268272de15ac151aasrs } // if 1628e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 162908bb0da07953af605b4918e268272de15ac151aasrs if (partNum == -1) 163008bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! Too many partitions to convert!\n"; 1631e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 1632e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1633e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Record that all original CRCs were OK so as not to raise flags 1634e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // when doing a disk verification 1635e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1; 1636e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1637e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numDone; 1638e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::XFormDisklabel(BSDData* disklabel) 1639e7b4ff9317fc4e551cf974684eaa88697de5a28srs 164008bb0da07953af605b4918e268272de15ac151aasrs// Add one GPT partition to MBR. Used by PartsToMBR() functions. Created 164108bb0da07953af605b4918e268272de15ac151aasrs// partition has the active/bootable flag UNset and uses the GPT fdisk 164208bb0da07953af605b4918e268272de15ac151aasrs// type code divided by 0x0100 as the MBR type code. 164308bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if operation was 100% successful, 0 if there were ANY 164408bb0da07953af605b4918e268272de15ac151aasrs// problems. 1645978041ca613dcb881763b36cf53639d924e52a56srsint GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) { 164608bb0da07953af605b4918e268272de15ac151aasrs int allOK = 1; 1647fed16d043a14e8b86c97a6413aec7281fefcbcb5srs 1648978041ca613dcb881763b36cf53639d924e52a56srs if ((mbrPart < 0) || (mbrPart > 3)) { 1649fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "MBR partition " << mbrPart + 1 << " is out of range; omitting it.\n"; 1650978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1651978041ca613dcb881763b36cf53639d924e52a56srs } // if 16520283dae41a7db4563be0fe62241ed230e4a101c0srs if (gptPart >= numParts) { 1653fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "GPT partition " << gptPart + 1 << " is out of range; omitting it.\n"; 1654978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1655978041ca613dcb881763b36cf53639d924e52a56srs } // if 1656978041ca613dcb881763b36cf53639d924e52a56srs if (allOK && (partitions[gptPart].GetLastLBA() == UINT64_C(0))) { 1657fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "GPT partition " << gptPart + 1 << " is undefined; omitting it.\n"; 1658978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1659978041ca613dcb881763b36cf53639d924e52a56srs } // if 1660978041ca613dcb881763b36cf53639d924e52a56srs if (allOK && (partitions[gptPart].GetFirstLBA() <= UINT32_MAX) && 1661978041ca613dcb881763b36cf53639d924e52a56srs (partitions[gptPart].GetLengthLBA() <= UINT32_MAX)) { 1662978041ca613dcb881763b36cf53639d924e52a56srs if (partitions[gptPart].GetLastLBA() > UINT32_MAX) { 1663fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Caution: Partition end point past 32-bit pointer boundary;" 1664fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " some OSes may\nreact strangely.\n"; 166508bb0da07953af605b4918e268272de15ac151aasrs } // if 1666978041ca613dcb881763b36cf53639d924e52a56srs protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(), 166708bb0da07953af605b4918e268272de15ac151aasrs (uint32_t) partitions[gptPart].GetLengthLBA(), 166808bb0da07953af605b4918e268272de15ac151aasrs partitions[gptPart].GetHexType() / 256, 0); 1669978041ca613dcb881763b36cf53639d924e52a56srs } else { // partition out of range 167008bb0da07953af605b4918e268272de15ac151aasrs if (allOK) // Display only if "else" triggered by out-of-bounds condition 167108bb0da07953af605b4918e268272de15ac151aasrs cout << "Partition " << gptPart + 1 << " begins beyond the 32-bit pointer limit of MBR " 167208bb0da07953af605b4918e268272de15ac151aasrs << "partitions, or is\n too big; omitting it.\n"; 1673978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1674978041ca613dcb881763b36cf53639d924e52a56srs } // if/else 1675978041ca613dcb881763b36cf53639d924e52a56srs return allOK; 1676978041ca613dcb881763b36cf53639d924e52a56srs} // GPTData::OnePartToMBR() 1677978041ca613dcb881763b36cf53639d924e52a56srs 1678c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 1679e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/********************************************************************** 1680e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1681e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Functions that adjust GPT data structures WITHOUT user interaction * 1682e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * (they may display information for the user's benefit, though) * 1683e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1684e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs **********************************************************************/ 1685e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1686e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Resizes GPT to specified number of entries. Creates a new table if 1687706e51217a531c46afc743b556e10fd5c0585fcfsrs// necessary, copies data if it already exists. If fillGPTSectors is 1 1688706e51217a531c46afc743b556e10fd5c0585fcfsrs// (the default), rounds numEntries to fill all the sectors necessary to 1689706e51217a531c46afc743b556e10fd5c0585fcfsrs// hold the GPT. 1690706e51217a531c46afc743b556e10fd5c0585fcfsrs// Returns 1 if all goes well, 0 if an error is encountered. 1691706e51217a531c46afc743b556e10fd5c0585fcfsrsint GPTData::SetGPTSize(uint32_t numEntries, int fillGPTSectors) { 169208bb0da07953af605b4918e268272de15ac151aasrs GPTPart* newParts; 1693706e51217a531c46afc743b556e10fd5c0585fcfsrs uint32_t i, high, copyNum, entriesPerSector; 1694e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int allOK = 1; 1695e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1696e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // First, adjust numEntries upward, if necessary, to get a number 1697e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // that fills the allocated sectors 1698706e51217a531c46afc743b556e10fd5c0585fcfsrs entriesPerSector = blockSize / GPT_SIZE; 1699706e51217a531c46afc743b556e10fd5c0585fcfsrs if (fillGPTSectors && ((numEntries % entriesPerSector) != 0)) { 1700fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Adjusting GPT size from " << numEntries << " to "; 1701706e51217a531c46afc743b556e10fd5c0585fcfsrs numEntries = ((numEntries / entriesPerSector) + 1) * entriesPerSector; 1702fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << numEntries << " to fill the sector\n"; 1703e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1704e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1705247657a5acbb7eb21c336ba84a68b801b7c19be0srs // Do the work only if the # of partitions is changing. Along with being 170655d926192adc984462509b2966e23bc0d1129bbdsrs // efficient, this prevents mucking with the location of the secondary 1707247657a5acbb7eb21c336ba84a68b801b7c19be0srs // partition table, which causes problems when loading data from a RAID 1708247657a5acbb7eb21c336ba84a68b801b7c19be0srs // array that's been expanded because this function is called when loading 1709247657a5acbb7eb21c336ba84a68b801b7c19be0srs // data. 17100283dae41a7db4563be0fe62241ed230e4a101c0srs if (((numEntries != numParts) || (partitions == NULL)) && (numEntries > 0)) { 171101f7f08624f0c942001977415214a578621f6495srs newParts = new GPTPart [numEntries]; 1712247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (newParts != NULL) { 1713247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (partitions != NULL) { // existing partitions; copy them over 1714247657a5acbb7eb21c336ba84a68b801b7c19be0srs GetPartRange(&i, &high); 1715247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (numEntries < (high + 1)) { // Highest entry too high for new # 1716fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The highest-numbered partition is " << high + 1 1717fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ", which is greater than the requested\n" 1718fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "partition table size of " << numEntries 1719fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "; cannot resize. Perhaps sorting will help.\n"; 1720247657a5acbb7eb21c336ba84a68b801b7c19be0srs allOK = 0; 1721815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs delete[] newParts; 1722247657a5acbb7eb21c336ba84a68b801b7c19be0srs } else { // go ahead with copy 17230283dae41a7db4563be0fe62241ed230e4a101c0srs if (numEntries < numParts) 1724247657a5acbb7eb21c336ba84a68b801b7c19be0srs copyNum = numEntries; 1725247657a5acbb7eb21c336ba84a68b801b7c19be0srs else 17260283dae41a7db4563be0fe62241ed230e4a101c0srs copyNum = numParts; 1727247657a5acbb7eb21c336ba84a68b801b7c19be0srs for (i = 0; i < copyNum; i++) { 1728247657a5acbb7eb21c336ba84a68b801b7c19be0srs newParts[i] = partitions[i]; 1729247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // for 173001f7f08624f0c942001977415214a578621f6495srs delete[] partitions; 1731247657a5acbb7eb21c336ba84a68b801b7c19be0srs partitions = newParts; 1732247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if 1733247657a5acbb7eb21c336ba84a68b801b7c19be0srs } else { // No existing partition table; just create it 1734e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions = newParts; 1735247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if/else existing partitions 17360283dae41a7db4563be0fe62241ed230e4a101c0srs numParts = numEntries; 1737706e51217a531c46afc743b556e10fd5c0585fcfsrs mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + (((numEntries * GPT_SIZE) % blockSize) != 0) + 2 ; 1738247657a5acbb7eb21c336ba84a68b801b7c19be0srs secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; 1739247657a5acbb7eb21c336ba84a68b801b7c19be0srs MoveSecondHeaderToEnd(); 1740247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (diskSize > 0) 1741247657a5acbb7eb21c336ba84a68b801b7c19be0srs CheckGPTSize(); 1742247657a5acbb7eb21c336ba84a68b801b7c19be0srs } else { // Bad memory allocation 17436aae2a9b70e9f88926baad94c1eea40e0b534f01srs cerr << "Error allocating memory for partition table! Size is unchanged!\n"; 1744247657a5acbb7eb21c336ba84a68b801b7c19be0srs allOK = 0; 1745247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if/else 1746e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 17470283dae41a7db4563be0fe62241ed230e4a101c0srs mainHeader.numParts = numParts; 17480283dae41a7db4563be0fe62241ed230e4a101c0srs secondHeader.numParts = numParts; 1749e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (allOK); 1750e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SetGPTSize() 1751e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1752e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Blank the partition array 1753e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::BlankPartitions(void) { 1754e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 1755e7b4ff9317fc4e551cf974684eaa88697de5a28srs 17560283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 1757e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[i].BlankPartition(); 1758e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 1759e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::BlankPartitions() 1760e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1761ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// Delete a partition by number. Returns 1 if successful, 1762ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// 0 if there was a problem. Returns 1 if partition was in 1763ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// range, 0 if it was out of range. 1764ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srsint GPTData::DeletePartition(uint32_t partNum) { 1765ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs uint64_t startSector, length; 17660283dae41a7db4563be0fe62241ed230e4a101c0srs uint32_t low, high, numUsedParts, retval = 1;; 1767ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 17680283dae41a7db4563be0fe62241ed230e4a101c0srs numUsedParts = GetPartRange(&low, &high); 17690283dae41a7db4563be0fe62241ed230e4a101c0srs if ((numUsedParts > 0) && (partNum >= low) && (partNum <= high)) { 1770ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs // In case there's a protective MBR, look for & delete matching 1771ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs // MBR partition.... 1772ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs startSector = partitions[partNum].GetFirstLBA(); 1773ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs length = partitions[partNum].GetLengthLBA(); 1774ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs protectiveMBR.DeleteByLocation(startSector, length); 1775ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1776ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs // Now delete the GPT partition 1777ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs partitions[partNum].BlankPartition(); 1778ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else { 1779fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Partition number " << partNum + 1 << " out of range!\n"; 1780ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs retval = 0; 1781ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } // if/else 1782ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs return retval; 1783ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs} // GPTData::DeletePartition(uint32_t partNum) 1784ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 178508bb0da07953af605b4918e268272de15ac151aasrs// Non-interactively create a partition. 178608bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if the operation was successful, 0 if a problem was discovered. 1787e321d444dcca514cf6b53459e388ddcbaab6176csrsuint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) { 1788ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs int retval = 1; // assume there'll be no problems 17895a081757ea2e32a491349544fea92826ccf739f6srs uint64_t origSector = startSector; 1790ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1791ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (IsFreePartNum(partNum)) { 17925a081757ea2e32a491349544fea92826ccf739f6srs if (Align(&startSector)) { 17935a081757ea2e32a491349544fea92826ccf739f6srs cout << "Information: Moved requested sector from " << origSector << " to " 17945a081757ea2e32a491349544fea92826ccf739f6srs << startSector << " in\norder to align on " << sectorAlignment 17955a081757ea2e32a491349544fea92826ccf739f6srs << "-sector boundaries.\n"; 17965a081757ea2e32a491349544fea92826ccf739f6srs } // if 1797ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (IsFree(startSector) && (startSector <= endSector)) { 1798ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (FindLastInFree(startSector) >= endSector) { 1799ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs partitions[partNum].SetFirstLBA(startSector); 1800ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs partitions[partNum].SetLastLBA(endSector); 18010741fa21ac6cb477891ef15f269c8c8f36cac7c6srs partitions[partNum].SetType(DEFAULT_GPT_TYPE); 18026699b01eda84d24bfaf80ad725304fef2b0e1b2asrs partitions[partNum].RandomizeUniqueGUID(); 1803ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else retval = 0; // if free space until endSector 1804ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else retval = 0; // if startSector is free 1805ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else retval = 0; // if legal partition number 1806ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs return retval; 1807ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs} // GPTData::CreatePartition(partNum, startSector, endSector) 1808ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1809e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Sort the GPT entries, eliminating gaps and making for a logical 18109a46b042c57144c26a67781d335e6ba4128382d2srs// ordering. 1811e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::SortGPT(void) { 18129a46b042c57144c26a67781d335e6ba4128382d2srs if (numParts > 0) 181301f7f08624f0c942001977415214a578621f6495srs sort(partitions, partitions + numParts); 1814e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SortGPT() 1815e7b4ff9317fc4e551cf974684eaa88697de5a28srs 181608bb0da07953af605b4918e268272de15ac151aasrs// Swap the contents of two partitions. 181708bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if successful, 0 if either partition is out of range 181808bb0da07953af605b4918e268272de15ac151aasrs// (that is, not a legal number; either or both can be empty). 181908bb0da07953af605b4918e268272de15ac151aasrs// Note that if partNum1 = partNum2 and this number is in range, 182008bb0da07953af605b4918e268272de15ac151aasrs// it will be considered successful. 182108bb0da07953af605b4918e268272de15ac151aasrsint GPTData::SwapPartitions(uint32_t partNum1, uint32_t partNum2) { 182208bb0da07953af605b4918e268272de15ac151aasrs GPTPart temp; 182308bb0da07953af605b4918e268272de15ac151aasrs int allOK = 1; 182408bb0da07953af605b4918e268272de15ac151aasrs 18250283dae41a7db4563be0fe62241ed230e4a101c0srs if ((partNum1 < numParts) && (partNum2 < numParts)) { 182608bb0da07953af605b4918e268272de15ac151aasrs if (partNum1 != partNum2) { 182708bb0da07953af605b4918e268272de15ac151aasrs temp = partitions[partNum1]; 182808bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum1] = partitions[partNum2]; 182908bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum2] = temp; 183008bb0da07953af605b4918e268272de15ac151aasrs } // if 183108bb0da07953af605b4918e268272de15ac151aasrs } else allOK = 0; // partition numbers are valid 183208bb0da07953af605b4918e268272de15ac151aasrs return allOK; 183308bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::SwapPartitions() 183408bb0da07953af605b4918e268272de15ac151aasrs 1835e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Set up data structures for entirely new set of partitions on the 1836e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// specified device. Returns 1 if OK, 0 if there were problems. 1837e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// Note that this function does NOT clear the protectiveMBR data 1838e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// structure, since it may hold the original MBR partitions if the 1839e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// program was launched on an MBR disk, and those may need to be 1840e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// converted to GPT format. 1841e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::ClearGPTData(void) { 1842e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs int goOn = 1, i; 1843e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1844e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Set up the partition table.... 18459a46b042c57144c26a67781d335e6ba4128382d2srs delete[] partitions; 1846e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions = NULL; 1847e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs SetGPTSize(NUM_GPT_ENTRIES); 1848e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1849e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now initialize a bunch of stuff that's static.... 1850e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.signature = GPT_SIGNATURE; 1851e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.revision = 0x00010000; 1852978041ca613dcb881763b36cf53639d924e52a56srs mainHeader.headerSize = HEADER_SIZE; 1853e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.reserved = 0; 1854e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.currentLBA = UINT64_C(1); 1855e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesLBA = (uint64_t) 2; 1856e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.sizeOfPartitionEntries = GPT_SIZE; 1857e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < GPT_RESERVED; i++) { 1858e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.reserved2[i] = '\0'; 1859e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 18600873e9d0e9345a2c4418b4718db525c9f1111c83srs if (blockSize > 0) 18610873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize; 18620873e9d0e9345a2c4418b4718db525c9f1111c83srs else 18630873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = DEFAULT_ALIGNMENT; 1864e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1865e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now some semi-static items (computed based on end of disk) 1866e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.backupLBA = diskSize - UINT64_C(1); 1867e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; 18682a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1869e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Set a unique GUID for the disk, based on random numbers 18706699b01eda84d24bfaf80ad725304fef2b0e1b2asrs mainHeader.diskGUID.Randomize(); 1871e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1872e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Copy main header to backup header 1873e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs RebuildSecondHeader(); 1874e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1875e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Blank out the partitions array.... 1876e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs BlankPartitions(); 18772a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1878e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Flag all CRCs as being OK.... 1879e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainCrcOk = 1; 1880e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondCrcOk = 1; 1881e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainPartsCrcOk = 1; 1882e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondPartsCrcOk = 1; 1883e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1884e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (goOn); 1885e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ClearGPTData() 1886e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1887247657a5acbb7eb21c336ba84a68b801b7c19be0srs// Set the location of the second GPT header data to the end of the disk. 188864cbd171067eb34054741bfcd73f0b91d727a371srs// If the disk size has actually changed, this also adjusts the protective 188964cbd171067eb34054741bfcd73f0b91d727a371srs// entry in the MBR, since it's probably no longer correct. 1890247657a5acbb7eb21c336ba84a68b801b7c19be0srs// Used internally and called by the 'e' option on the recovery & 1891247657a5acbb7eb21c336ba84a68b801b7c19be0srs// transformation menu, to help users of RAID arrays who add disk space 189264cbd171067eb34054741bfcd73f0b91d727a371srs// to their arrays or to adjust data structures in restore operations 189364cbd171067eb34054741bfcd73f0b91d727a371srs// involving unequal-sized disks. 1894247657a5acbb7eb21c336ba84a68b801b7c19be0srsvoid GPTData::MoveSecondHeaderToEnd() { 18958bb7876224e60a00f0b7f39e4624ee0961b2f27csrs mainHeader.backupLBA = secondHeader.currentLBA = diskSize - UINT64_C(1); 189664cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.lastUsableLBA != diskSize - mainHeader.firstUsableLBA) { 189764cbd171067eb34054741bfcd73f0b91d727a371srs if (protectiveMBR.GetValidity() == hybrid) { 189864cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.OptimizeEESize(); 189964cbd171067eb34054741bfcd73f0b91d727a371srs RecomputeCHS(); 190064cbd171067eb34054741bfcd73f0b91d727a371srs } // if 190164cbd171067eb34054741bfcd73f0b91d727a371srs if (protectiveMBR.GetValidity() == gpt) 190264cbd171067eb34054741bfcd73f0b91d727a371srs MakeProtectiveMBR(); 190364cbd171067eb34054741bfcd73f0b91d727a371srs } // if 19048bb7876224e60a00f0b7f39e4624ee0961b2f27csrs mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; 19058bb7876224e60a00f0b7f39e4624ee0961b2f27csrs secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); 19068bb7876224e60a00f0b7f39e4624ee0961b2f27csrs} // GPTData::FixSecondHeaderLocation() 19078bb7876224e60a00f0b7f39e4624ee0961b2f27csrs 1908699941e25a1fcf0beec124203747c8ed20842989srs// Sets the partition's name to the specified UnicodeString without 1909699941e25a1fcf0beec124203747c8ed20842989srs// user interaction. 1910699941e25a1fcf0beec124203747c8ed20842989srs// Returns 1 on success, 0 on failure (invalid partition number). 19115a6085310b7f8fe1c35e56bcab7de161808b488dsrsint GPTData::SetName(uint32_t partNum, const UnicodeString & theName) { 1912ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs int retval = 1; 1913fed16d043a14e8b86c97a6413aec7281fefcbcb5srs 1914699941e25a1fcf0beec124203747c8ed20842989srs if (IsUsedPartNum(partNum)) 1915fed16d043a14e8b86c97a6413aec7281fefcbcb5srs partitions[partNum].SetName(theName); 1916699941e25a1fcf0beec124203747c8ed20842989srs else 1917699941e25a1fcf0beec124203747c8ed20842989srs retval = 0; 1918ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1919ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs return retval; 1920e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SetName 1921e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1922e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Set the disk GUID to the specified value. Note that the header CRCs must 1923e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// be recomputed after calling this function. 1924e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::SetDiskGUID(GUIDData newGUID) { 1925e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.diskGUID = newGUID; 1926e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.diskGUID = newGUID; 1927e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // SetDiskGUID() 1928e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1929e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Set the unique GUID of the specified partition. Returns 1 on 1930e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// successful completion, 0 if there were problems (invalid 1931e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// partition number). 1932e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) { 1933e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int retval = 0; 19342a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 19350283dae41a7db4563be0fe62241ed230e4a101c0srs if (pn < numParts) { 1936e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[pn].IsUsed()) { 1937e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[pn].SetUniqueGUID(theGUID); 1938e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs retval = 1; 19392a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 1940e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 1941e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return retval; 1942e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SetPartitionGUID() 1943e7b4ff9317fc4e551cf974684eaa88697de5a28srs 19449ba5421f920e192dbb808d30aa6d34849938bab4srs// Set new random GUIDs for the disk and all partitions. Intended to be used 19459ba5421f920e192dbb808d30aa6d34849938bab4srs// after disk cloning or similar operations that don't randomize the GUIDs. 19469ba5421f920e192dbb808d30aa6d34849938bab4srsvoid GPTData::RandomizeGUIDs(void) { 19479ba5421f920e192dbb808d30aa6d34849938bab4srs uint32_t i; 19489ba5421f920e192dbb808d30aa6d34849938bab4srs 19499ba5421f920e192dbb808d30aa6d34849938bab4srs mainHeader.diskGUID.Randomize(); 19509ba5421f920e192dbb808d30aa6d34849938bab4srs secondHeader.diskGUID = mainHeader.diskGUID; 19519ba5421f920e192dbb808d30aa6d34849938bab4srs for (i = 0; i < numParts; i++) 19529ba5421f920e192dbb808d30aa6d34849938bab4srs if (partitions[i].IsUsed()) 19539ba5421f920e192dbb808d30aa6d34849938bab4srs partitions[i].RandomizeUniqueGUID(); 19549ba5421f920e192dbb808d30aa6d34849938bab4srs} // GPTData::RandomizeGUIDs() 19559ba5421f920e192dbb808d30aa6d34849938bab4srs 1956ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// Change partition type code non-interactively. Returns 1 if 1957ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// successful, 0 if not.... 1958327129e9331f888a8fc08d688dcb0a739a3c17besrsint GPTData::ChangePartType(uint32_t partNum, PartType theGUID) { 1959327129e9331f888a8fc08d688dcb0a739a3c17besrs int retval = 1; 1960327129e9331f888a8fc08d688dcb0a739a3c17besrs 1961327129e9331f888a8fc08d688dcb0a739a3c17besrs if (!IsFreePartNum(partNum)) { 1962327129e9331f888a8fc08d688dcb0a739a3c17besrs partitions[partNum].SetType(theGUID); 1963327129e9331f888a8fc08d688dcb0a739a3c17besrs } else retval = 0; 1964327129e9331f888a8fc08d688dcb0a739a3c17besrs return retval; 1965327129e9331f888a8fc08d688dcb0a739a3c17besrs} // GPTData::ChangePartType() 1966327129e9331f888a8fc08d688dcb0a739a3c17besrs 19679ba5421f920e192dbb808d30aa6d34849938bab4srs// Recompute the CHS values of all the MBR partitions. Used to reset 19689ba5421f920e192dbb808d30aa6d34849938bab4srs// CHS values that some BIOSes require, despite the fact that the 19699ba5421f920e192dbb808d30aa6d34849938bab4srs// resulting CHS values violate the GPT standard. 19709ba5421f920e192dbb808d30aa6d34849938bab4srsvoid GPTData::RecomputeCHS(void) { 19719ba5421f920e192dbb808d30aa6d34849938bab4srs int i; 19729ba5421f920e192dbb808d30aa6d34849938bab4srs 19739ba5421f920e192dbb808d30aa6d34849938bab4srs for (i = 0; i < 4; i++) 19749ba5421f920e192dbb808d30aa6d34849938bab4srs protectiveMBR.RecomputeCHS(i); 19759ba5421f920e192dbb808d30aa6d34849938bab4srs} // GPTData::RecomputeCHS() 19769ba5421f920e192dbb808d30aa6d34849938bab4srs 19771d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// Adjust sector number so that it falls on a sector boundary that's a 19781d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// multiple of sectorAlignment. This is done to improve the performance 19791d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// of Western Digital Advanced Format disks and disks with similar 19801d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// technology from other companies, which use 4096-byte sectors 19811d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// internally although they translate to 512-byte sectors for the 19821d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// benefit of the OS. If partitions aren't properly aligned on these 19831d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// disks, some filesystem data structures can span multiple physical 19841d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// sectors, degrading performance. This function should be called 19851d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// only on the FIRST sector of the partition, not the last! 19861d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// This function returns 1 if the alignment was altered, 0 if it 19871d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// was unchanged. 19881d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srsint GPTData::Align(uint64_t* sector) { 19891d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs int retval = 0, sectorOK = 0; 199000b6d7a4604e759eb3c92b3ecea608d6fe024b81srs uint64_t earlier, later, testSector; 19911d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 19921d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if ((*sector % sectorAlignment) != 0) { 19931d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs earlier = (*sector / sectorAlignment) * sectorAlignment; 19941d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs later = earlier + (uint64_t) sectorAlignment; 19951d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 19961d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // Check to see that every sector between the earlier one and the 19971d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // requested one is clear, and that it's not too early.... 19981d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if (earlier >= mainHeader.firstUsableLBA) { 19991d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = 1; 20001d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs testSector = earlier; 20011d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs do { 20021d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = IsFree(testSector++); 20031d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } while ((sectorOK == 1) && (testSector < *sector)); 20041d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if (sectorOK == 1) { 20051d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs *sector = earlier; 20065a081757ea2e32a491349544fea92826ccf739f6srs retval = 1; 20071d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20081d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if firstUsableLBA check 20091d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 20101d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // If couldn't move the sector earlier, try to move it later instead.... 20111d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if ((sectorOK != 1) && (later <= mainHeader.lastUsableLBA)) { 20121d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = 1; 20131d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs testSector = later; 20141d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs do { 20151d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = IsFree(testSector--); 20161d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } while ((sectorOK == 1) && (testSector > *sector)); 20171d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if (sectorOK == 1) { 20181d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs *sector = later; 20195a081757ea2e32a491349544fea92826ccf739f6srs retval = 1; 20201d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20211d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20221d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20231d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs return retval; 20241d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs} // GPTData::Align() 20251d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 2026e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/******************************************************** 2027e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2028e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Functions that return data about GPT data structures * 2029e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * (most of these are inline in gpt.h) * 2030e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2031e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ********************************************************/ 2032e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2033e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find the low and high used partition numbers (numbered from 0). 2034e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Return value is the number of partitions found. Note that the 2035e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// *low and *high values are both set to 0 when no partitions 2036e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// are found, as well as when a single partition in the first 2037e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// position exists. Thus, the return value is the only way to 2038e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// tell when no partitions exist. 2039e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::GetPartRange(uint32_t *low, uint32_t *high) { 2040e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2041e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int numFound = 0; 20422a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 20430283dae41a7db4563be0fe62241ed230e4a101c0srs *low = numParts + 1; // code for "not found" 2044e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *high = 0; 20459a46b042c57144c26a67781d335e6ba4128382d2srs for (i = 0; i < numParts; i++) { 2046e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].IsUsed()) { // it exists 20479a46b042c57144c26a67781d335e6ba4128382d2srs *high = i; // since we're counting up, set the high value 20489a46b042c57144c26a67781d335e6ba4128382d2srs // Set the low value only if it's not yet found... 20499a46b042c57144c26a67781d335e6ba4128382d2srs if (*low == (numParts + 1)) *low = i; 20509a46b042c57144c26a67781d335e6ba4128382d2srs numFound++; 20519a46b042c57144c26a67781d335e6ba4128382d2srs } // if 20529a46b042c57144c26a67781d335e6ba4128382d2srs } // for 2053e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2054e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Above will leave *low pointing to its "not found" value if no partitions 2055e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // are defined, so reset to 0 if this is the case.... 20560283dae41a7db4563be0fe62241ed230e4a101c0srs if (*low == (numParts + 1)) 2057e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *low = 0; 2058e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numFound; 2059e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::GetPartRange() 2060e7b4ff9317fc4e551cf974684eaa88697de5a28srs 206108bb0da07953af605b4918e268272de15ac151aasrs// Returns the value of the first free partition, or -1 if none is 206208bb0da07953af605b4918e268272de15ac151aasrs// unused. 206308bb0da07953af605b4918e268272de15ac151aasrsint GPTData::FindFirstFreePart(void) { 206408bb0da07953af605b4918e268272de15ac151aasrs int i = 0; 206508bb0da07953af605b4918e268272de15ac151aasrs 206608bb0da07953af605b4918e268272de15ac151aasrs if (partitions != NULL) { 20679a46b042c57144c26a67781d335e6ba4128382d2srs while ((i < (int) numParts) && (partitions[i].IsUsed())) 206808bb0da07953af605b4918e268272de15ac151aasrs i++; 20690283dae41a7db4563be0fe62241ed230e4a101c0srs if (i >= (int) numParts) 207008bb0da07953af605b4918e268272de15ac151aasrs i = -1; 207108bb0da07953af605b4918e268272de15ac151aasrs } else i = -1; 207208bb0da07953af605b4918e268272de15ac151aasrs return i; 207308bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::FindFirstFreePart() 207408bb0da07953af605b4918e268272de15ac151aasrs 2075978041ca613dcb881763b36cf53639d924e52a56srs// Returns the number of defined partitions. 2076978041ca613dcb881763b36cf53639d924e52a56srsuint32_t GPTData::CountParts(void) { 2077e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i, counted = 0; 2078978041ca613dcb881763b36cf53639d924e52a56srs 20790283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 208008bb0da07953af605b4918e268272de15ac151aasrs if (partitions[i].IsUsed()) 2081978041ca613dcb881763b36cf53639d924e52a56srs counted++; 2082978041ca613dcb881763b36cf53639d924e52a56srs } // for 2083978041ca613dcb881763b36cf53639d924e52a56srs return counted; 2084978041ca613dcb881763b36cf53639d924e52a56srs} // GPTData::CountParts() 2085978041ca613dcb881763b36cf53639d924e52a56srs 2086e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/**************************************************** 2087e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2088e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Functions that return data about disk free space * 2089e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2090e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ****************************************************/ 20912a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2092e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find the first available block after the starting point; returns 0 if 2093e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// there are no available blocks left 2094e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsuint64_t GPTData::FindFirstAvailable(uint64_t start) { 2095e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t first; 2096e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2097e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int firstMoved = 0; 2098e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2099e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Begin from the specified starting point or from the first usable 2100e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // LBA, whichever is greater... 2101e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (start < mainHeader.firstUsableLBA) 2102e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = mainHeader.firstUsableLBA; 2103e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs else 2104e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = start; 21052a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2106e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // ...now search through all partitions; if first is within an 2107e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // existing partition, move it to the next sector after that 2108e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // partition and repeat. If first was moved, set firstMoved 2109e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // flag; repeat until firstMoved is not set, so as to catch 2110e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // cases where partitions are out of sequential order.... 2111e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 2112e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs firstMoved = 0; 21130283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2114e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if ((partitions[i].IsUsed()) && (first >= partitions[i].GetFirstLBA()) && 211555d926192adc984462509b2966e23bc0d1129bbdsrs (first <= partitions[i].GetLastLBA())) { // in existing part. 2116e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = partitions[i].GetLastLBA() + 1; 2117e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs firstMoved = 1; 211855d926192adc984462509b2966e23bc0d1129bbdsrs } // if 2119e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 2120e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } while (firstMoved == 1); 2121e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (first > mainHeader.lastUsableLBA) 2122e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = 0; 2123e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (first); 2124e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindFirstAvailable() 2125e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2126e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Finds the first available sector in the largest block of unallocated 2127e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// space on the disk. Returns 0 if there are no available blocks left 2128e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsuint64_t GPTData::FindFirstInLargest(void) { 2129e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs uint64_t start, firstBlock, lastBlock, segmentSize, selectedSize = 0, selectedSegment = 0; 2130e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2131e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs start = 0; 2132e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 2133e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs firstBlock = FindFirstAvailable(start); 2134e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (firstBlock != UINT32_C(0)) { // something's free... 2135e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs lastBlock = FindLastInFree(firstBlock); 2136e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs segmentSize = lastBlock - firstBlock + UINT32_C(1); 2137e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (segmentSize > selectedSize) { 2138e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs selectedSize = segmentSize; 2139e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs selectedSegment = firstBlock; 2140e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2141e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs start = lastBlock + 1; 2142e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 2143e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } while (firstBlock != 0); 2144e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return selectedSegment; 2145e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindFirstInLargest() 2146e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2147cb76c673eeb84344887715d36d44b799042be5a5srs// Find the last available block on the disk. 2148f5dfbfa418675ca862408e4fb2240b21dd07d558srs// Returns 0 if there are no available sectors 2149cb76c673eeb84344887715d36d44b799042be5a5srsuint64_t GPTData::FindLastAvailable(void) { 2150e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t last; 2151e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2152e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int lastMoved = 0; 21532a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2154e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Start by assuming the last usable LBA is available.... 2155e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs last = mainHeader.lastUsableLBA; 2156e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2157e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // ...now, similar to algorithm in FindFirstAvailable(), search 2158e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // through all partitions, moving last when it's in an existing 2159e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // partition. Set the lastMoved flag so we repeat to catch cases 2160e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // where partitions are out of logical order. 2161e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 2162e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs lastMoved = 0; 21630283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2164e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((last >= partitions[i].GetFirstLBA()) && 216555d926192adc984462509b2966e23bc0d1129bbdsrs (last <= partitions[i].GetLastLBA())) { // in existing part. 2166e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs last = partitions[i].GetFirstLBA() - 1; 2167e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs lastMoved = 1; 216855d926192adc984462509b2966e23bc0d1129bbdsrs } // if 2169e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 2170e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } while (lastMoved == 1); 2171e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (last < mainHeader.firstUsableLBA) 2172e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs last = 0; 2173e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (last); 2174e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindLastAvailable() 2175e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2176e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find the last available block in the free space pointed to by start. 2177e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsuint64_t GPTData::FindLastInFree(uint64_t start) { 2178e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t nearestStart; 2179e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2180c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 2181e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs nearestStart = mainHeader.lastUsableLBA; 21820283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2183e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((nearestStart > partitions[i].GetFirstLBA()) && 218455d926192adc984462509b2966e23bc0d1129bbdsrs (partitions[i].GetFirstLBA() > start)) { 2185e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs nearestStart = partitions[i].GetFirstLBA() - 1; 218655d926192adc984462509b2966e23bc0d1129bbdsrs } // if 2187c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs } // for 2188e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (nearestStart); 2189e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindLastInFree() 2190c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 2191e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Finds the total number of free blocks, the number of segments in which 2192e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// they reside, and the size of the largest of those segments 2193e321d444dcca514cf6b53459e388ddcbaab6176csrsuint64_t GPTData::FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment) { 2194e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t start = UINT64_C(0); // starting point for each search 2195e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t totalFound = UINT64_C(0); // running total 2196e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t firstBlock; // first block in a segment 2197e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t lastBlock; // last block in a segment 2198e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t segmentSize; // size of segment in blocks 2199e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t num = 0; 2200e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 2201e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *largestSegment = UINT64_C(0); 2202c54e9b406255a81cca066dacf127d587b9dd36e1srs if (diskSize > 0) { 2203c54e9b406255a81cca066dacf127d587b9dd36e1srs do { 2204c54e9b406255a81cca066dacf127d587b9dd36e1srs firstBlock = FindFirstAvailable(start); 2205c54e9b406255a81cca066dacf127d587b9dd36e1srs if (firstBlock != UINT64_C(0)) { // something's free... 2206c54e9b406255a81cca066dacf127d587b9dd36e1srs lastBlock = FindLastInFree(firstBlock); 2207c54e9b406255a81cca066dacf127d587b9dd36e1srs segmentSize = lastBlock - firstBlock + UINT64_C(1); 2208c54e9b406255a81cca066dacf127d587b9dd36e1srs if (segmentSize > *largestSegment) { 2209c54e9b406255a81cca066dacf127d587b9dd36e1srs *largestSegment = segmentSize; 2210c54e9b406255a81cca066dacf127d587b9dd36e1srs } // if 2211c54e9b406255a81cca066dacf127d587b9dd36e1srs totalFound += segmentSize; 2212c54e9b406255a81cca066dacf127d587b9dd36e1srs num++; 2213c54e9b406255a81cca066dacf127d587b9dd36e1srs start = lastBlock + 1; 2214e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 2215c54e9b406255a81cca066dacf127d587b9dd36e1srs } while (firstBlock != 0); 2216c54e9b406255a81cca066dacf127d587b9dd36e1srs } // if 2217e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *numSegments = num; 2218e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return totalFound; 2219e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindFreeBlocks() 2220e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 222155d926192adc984462509b2966e23bc0d1129bbdsrs// Returns 1 if sector is unallocated, 0 if it's allocated to a partition. 222255d926192adc984462509b2966e23bc0d1129bbdsrs// If it's allocated, return the partition number to which it's allocated 222355d926192adc984462509b2966e23bc0d1129bbdsrs// in partNum, if that variable is non-NULL. (A value of UINT32_MAX is 222455d926192adc984462509b2966e23bc0d1129bbdsrs// returned in partNum if the sector is in use by basic GPT data structures.) 222555d926192adc984462509b2966e23bc0d1129bbdsrsint GPTData::IsFree(uint64_t sector, uint32_t *partNum) { 2226e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int isFree = 1; 2227e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2228e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 22290283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2230e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((sector >= partitions[i].GetFirstLBA()) && 2231e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs (sector <= partitions[i].GetLastLBA())) { 2232e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs isFree = 0; 223355d926192adc984462509b2966e23bc0d1129bbdsrs if (partNum != NULL) 223455d926192adc984462509b2966e23bc0d1129bbdsrs *partNum = i; 223508bb0da07953af605b4918e268272de15ac151aasrs } // if 2236e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 2237e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs if ((sector < mainHeader.firstUsableLBA) || 2238e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs (sector > mainHeader.lastUsableLBA)) { 2239e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs isFree = 0; 224055d926192adc984462509b2966e23bc0d1129bbdsrs if (partNum != NULL) 224155d926192adc984462509b2966e23bc0d1129bbdsrs *partNum = UINT32_MAX; 224208bb0da07953af605b4918e268272de15ac151aasrs } // if 224308bb0da07953af605b4918e268272de15ac151aasrs return (isFree); 2244e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::IsFree() 2245e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 2246815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// Returns 1 if partNum is unused AND if it's a legal value. 2247ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srsint GPTData::IsFreePartNum(uint32_t partNum) { 224801f7f08624f0c942001977415214a578621f6495srs return ((partNum < numParts) && (partitions != NULL) && 224901f7f08624f0c942001977415214a578621f6495srs (!partitions[partNum].IsUsed())); 2250ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs} // GPTData::IsFreePartNum() 2251ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 2252815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// Returns 1 if partNum is in use. 2253815fb65195106b8afe1b8dfec5dae605dbd7ccbesrsint GPTData::IsUsedPartNum(uint32_t partNum) { 2254815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs return ((partNum < numParts) && (partitions != NULL) && 2255815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs (partitions[partNum].IsUsed())); 2256815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs} // GPTData::IsUsedPartNum() 2257a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2258a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs/*********************************************************** 2259a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs * * 2260a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs * Change how functions work or return information on them * 2261a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs * * 2262a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs ***********************************************************/ 2263a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2264a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// Set partition alignment value; partitions will begin on multiples of 2265a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// the specified value 2266a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srsvoid GPTData::SetAlignment(uint32_t n) { 22670873e9d0e9345a2c4418b4718db525c9f1111c83srs if (n > 0) 22680873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = n; 22690873e9d0e9345a2c4418b4718db525c9f1111c83srs else 22700873e9d0e9345a2c4418b4718db525c9f1111c83srs cerr << "Attempt to set partition alignment to 0!\n"; 2271a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs} // GPTData::SetAlignment() 2272a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2273a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// Compute sector alignment based on the current partitions (if any). Each 2274a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// partition's starting LBA is examined, and if it's divisible by a power-of-2 22750873e9d0e9345a2c4418b4718db525c9f1111c83srs// value less than or equal to the DEFAULT_ALIGNMENT value (adjusted for the 22760873e9d0e9345a2c4418b4718db525c9f1111c83srs// sector size), but not by the previously-located alignment value, then the 22770873e9d0e9345a2c4418b4718db525c9f1111c83srs// alignment value is adjusted down. If the computed alignment is less than 8 22780873e9d0e9345a2c4418b4718db525c9f1111c83srs// and the disk is bigger than SMALLEST_ADVANCED_FORMAT, resets it to 8. This 2279d8eed4629449a325999808a0170dbda53bd4a6dfsrs// is a safety measure for Advanced Format drives. If no partitions are 2280d8eed4629449a325999808a0170dbda53bd4a6dfsrs// defined, the alignment value is set to DEFAULT_ALIGNMENT (2048) (or an 22810873e9d0e9345a2c4418b4718db525c9f1111c83srs// adjustment of that based on the current sector size). The result is that new 22828a4ddfc919d5569c68489cf53d9cf5abc94c410csrs// drives are aligned to 2048-sector multiples but the program won't complain 22838a4ddfc919d5569c68489cf53d9cf5abc94c410csrs// about other alignments on existing disks unless a smaller-than-8 alignment 2284d8eed4629449a325999808a0170dbda53bd4a6dfsrs// is used on big disks (as safety for Advanced Format drives). 2285a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// Returns the computed alignment value. 2286a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srsuint32_t GPTData::ComputeAlignment(void) { 2287a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs uint32_t i = 0, found, exponent = 31; 2288ab4b0438394df4ae6bdea86194e254d7d35fdea0srs uint32_t align = DEFAULT_ALIGNMENT; 2289a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 22900873e9d0e9345a2c4418b4718db525c9f1111c83srs if (blockSize > 0) 22910873e9d0e9345a2c4418b4718db525c9f1111c83srs align = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize; 22920873e9d0e9345a2c4418b4718db525c9f1111c83srs exponent = (uint32_t) log2(align); 22930283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2294a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs if (partitions[i].IsUsed()) { 2295a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs found = 0; 2296a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs while (!found) { 22970873e9d0e9345a2c4418b4718db525c9f1111c83srs align = UINT64_C(1) << exponent; 2298a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs if ((partitions[i].GetFirstLBA() % align) == 0) { 2299a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs found = 1; 2300a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } else { 2301a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs exponent--; 2302a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // if/else 2303a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // while 2304a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // if 2305a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // for 23060873e9d0e9345a2c4418b4718db525c9f1111c83srs if ((align < MIN_AF_ALIGNMENT) && (diskSize >= SMALLEST_ADVANCED_FORMAT)) 23070873e9d0e9345a2c4418b4718db525c9f1111c83srs align = MIN_AF_ALIGNMENT; 23080873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = align; 2309a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs return align; 2310a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs} // GPTData::ComputeAlignment() 2311a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2312e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/******************************** 2313e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2314e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Endianness support functions * 2315e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2316e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ********************************/ 2317c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 23182a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srsvoid GPTData::ReverseHeaderBytes(struct GPTHeader* header) { 2319221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->signature, 8); 2320221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->revision, 4); 2321221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->headerSize, 4); 2322221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->headerCRC, 4); 2323221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->reserved, 4); 2324221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->currentLBA, 8); 2325221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->backupLBA, 8); 2326221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->firstUsableLBA, 8); 2327221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->lastUsableLBA, 8); 2328221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->partitionEntriesLBA, 8); 2329221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->numParts, 4); 2330221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->sizeOfPartitionEntries, 4); 2331221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->partitionEntriesCRC, 4); 233208bb0da07953af605b4918e268272de15ac151aasrs ReverseBytes(header->reserved2, GPT_RESERVED); 23332a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs} // GPTData::ReverseHeaderBytes() 23342a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 23350283dae41a7db4563be0fe62241ed230e4a101c0srs// Reverse byte order for all partitions. 23362a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srsvoid GPTData::ReversePartitionBytes() { 23372a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs uint32_t i; 23382a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 23390283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2340221e08768de7fe42ba533ca22baf671420569c07srs partitions[i].ReversePartBytes(); 23412a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // for 23422a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs} // GPTData::ReversePartitionBytes() 23432a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 23449ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Validate partition number 23459ddc14bb9b154518e2b8384d3f4571cf657c7920srsbool GPTData::ValidPartNum (const uint32_t partNum) { 23469ddc14bb9b154518e2b8384d3f4571cf657c7920srs if (partNum >= numParts) { 23475a081757ea2e32a491349544fea92826ccf739f6srs cerr << "Partition number out of range: " << partNum << "\n"; 23489ddc14bb9b154518e2b8384d3f4571cf657c7920srs return false; 23499ddc14bb9b154518e2b8384d3f4571cf657c7920srs } // if 23509ddc14bb9b154518e2b8384d3f4571cf657c7920srs return true; 23519ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::ValidPartNum 23529ddc14bb9b154518e2b8384d3f4571cf657c7920srs 23535a081757ea2e32a491349544fea92826ccf739f6srs// Return a single partition for inspection (not modification!) by other 23545a081757ea2e32a491349544fea92826ccf739f6srs// functions. 23555a081757ea2e32a491349544fea92826ccf739f6srsconst GPTPart & GPTData::operator[](uint32_t partNum) const { 23565a081757ea2e32a491349544fea92826ccf739f6srs if (partNum >= numParts) { 2357815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cerr << "Partition number out of range (" << partNum << " requested, but only " 2358815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs << numParts << " available)\n"; 2359815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs exit(1); 2360815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs } // if 2361815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs if (partitions == NULL) { 2362815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cerr << "No partitions defined in GPTData::operator[]; fatal error!\n"; 2363815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs exit(1); 23645a081757ea2e32a491349544fea92826ccf739f6srs } // if 23655a081757ea2e32a491349544fea92826ccf739f6srs return partitions[partNum]; 23665a081757ea2e32a491349544fea92826ccf739f6srs} // operator[] 23675a081757ea2e32a491349544fea92826ccf739f6srs 23685a081757ea2e32a491349544fea92826ccf739f6srs// Return (not for modification!) the disk's GUID value 23695a081757ea2e32a491349544fea92826ccf739f6srsconst GUIDData & GPTData::GetDiskGUID(void) const { 23705a081757ea2e32a491349544fea92826ccf739f6srs return mainHeader.diskGUID; 23715a081757ea2e32a491349544fea92826ccf739f6srs} // GPTData::GetDiskGUID() 23725a081757ea2e32a491349544fea92826ccf739f6srs 23739ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Manage attributes for a partition, based on commands passed to this function. 23749ddc14bb9b154518e2b8384d3f4571cf657c7920srs// (Function is non-interactive.) 23759ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Returns 1 if a modification command succeeded, 0 if the command should not have 23769ddc14bb9b154518e2b8384d3f4571cf657c7920srs// modified data, and -1 if a modification command failed. 23779ddc14bb9b154518e2b8384d3f4571cf657c7920srsint GPTData::ManageAttributes(int partNum, const string & command, const string & bits) { 23789ddc14bb9b154518e2b8384d3f4571cf657c7920srs int retval = 0; 23799ddc14bb9b154518e2b8384d3f4571cf657c7920srs Attributes theAttr; 23809ddc14bb9b154518e2b8384d3f4571cf657c7920srs 238124bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (partNum >= (int) numParts) { 238224bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith cerr << "Invalid partition number (" << partNum + 1 << ")\n"; 238324bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith retval = -1; 23849ddc14bb9b154518e2b8384d3f4571cf657c7920srs } else { 238524bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (command == "show") { 238624bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith ShowAttributes(partNum); 238724bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } else if (command == "get") { 238824bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith GetAttribute(partNum, bits); 23899ddc14bb9b154518e2b8384d3f4571cf657c7920srs } else { 239024bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith theAttr = partitions[partNum].GetAttributes(); 239124bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (theAttr.OperateOnAttributes(partNum, command, bits)) { 239224bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith partitions[partNum].SetAttributes(theAttr.GetAttributes()); 239324bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith retval = 1; 239424bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } else { 239524bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith retval = -1; 239624bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } // if/else 239724bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } // if/elseif/else 239824bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } // if/else invalid partition # 23999ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24009ddc14bb9b154518e2b8384d3f4571cf657c7920srs return retval; 24019ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::ManageAttributes() 24029ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24039ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Show all attributes for a specified partition.... 24049ddc14bb9b154518e2b8384d3f4571cf657c7920srsvoid GPTData::ShowAttributes(const uint32_t partNum) { 240524bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if ((partNum < numParts) && partitions[partNum].IsUsed()) 2406e69e6807cf84fe2b80c48475531ce4bd09563bbasrs partitions[partNum].ShowAttributes(partNum); 24079ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::ShowAttributes 24089ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24099ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Show whether a single attribute bit is set (terse output)... 24109ddc14bb9b154518e2b8384d3f4571cf657c7920srsvoid GPTData::GetAttribute(const uint32_t partNum, const string& attributeBits) { 241124bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (partNum < numParts) 241224bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith partitions[partNum].GetAttributes().OperateOnAttributes(partNum, "get", attributeBits); 24139ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::GetAttribute 24149ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24159ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24162a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs/****************************************** 24172a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs * * 24182a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs * Additional non-class support functions * 24192a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs * * 24202a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs ******************************************/ 24212a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2422e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Check to be sure that data type sizes are correct. The basic types (uint*_t) should 2423e7b4ff9317fc4e551cf974684eaa88697de5a28srs// never fail these tests, but the struct types may fail depending on compile options. 2424e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Specifically, the -fpack-struct option to gcc may be required to ensure proper structure 2425e7b4ff9317fc4e551cf974684eaa88697de5a28srs// sizes. 2426e7b4ff9317fc4e551cf974684eaa88697de5a28srsint SizesOK(void) { 2427e7b4ff9317fc4e551cf974684eaa88697de5a28srs int allOK = 1; 2428e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2429e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint8_t) != 1) { 2430fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint8_t is " << sizeof(uint8_t) << " bytes, should be 1 byte; aborting!\n"; 2431e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2432e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2433e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint16_t) != 2) { 2434fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint16_t is " << sizeof(uint16_t) << " bytes, should be 2 bytes; aborting!\n"; 2435e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2436e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2437e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint32_t) != 4) { 2438fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint32_t is " << sizeof(uint32_t) << " bytes, should be 4 bytes; aborting!\n"; 2439e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2440e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2441e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint64_t) != 8) { 2442fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint64_t is " << sizeof(uint64_t) << " bytes, should be 8 bytes; aborting!\n"; 2443e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2444e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2445e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(struct MBRRecord) != 16) { 2446fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "MBRRecord is " << sizeof(MBRRecord) << " bytes, should be 16 bytes; aborting!\n"; 2447e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2448e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2449978041ca613dcb881763b36cf53639d924e52a56srs if (sizeof(struct TempMBR) != 512) { 2450fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "TempMBR is " << sizeof(TempMBR) << " bytes, should be 512 bytes; aborting!\n"; 2451e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2452e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2453e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(struct GPTHeader) != 512) { 2454fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "GPTHeader is " << sizeof(GPTHeader) << " bytes, should be 512 bytes; aborting!\n"; 2455221e08768de7fe42ba533ca22baf671420569c07srs allOK = 0; 2456221e08768de7fe42ba533ca22baf671420569c07srs } // if 2457221e08768de7fe42ba533ca22baf671420569c07srs if (sizeof(GPTPart) != 128) { 2458fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n"; 2459e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2460e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 24616699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if (sizeof(GUIDData) != 16) { 24626699b01eda84d24bfaf80ad725304fef2b0e1b2asrs cerr << "GUIDData is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n"; 24636699b01eda84d24bfaf80ad725304fef2b0e1b2asrs allOK = 0; 24646699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 24656699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if (sizeof(PartType) != 16) { 246684aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "PartType is " << sizeof(PartType) << " bytes, should be 16 bytes; aborting!\n"; 24676699b01eda84d24bfaf80ad725304fef2b0e1b2asrs allOK = 0; 24686699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 2469e7b4ff9317fc4e551cf974684eaa88697de5a28srs return (allOK); 2470e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // SizesOK() 2471e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 2472