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 10e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_CONSTANT_MACROS 11e7b4ff9317fc4e551cf974684eaa88697de5a28srs 12e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdio.h> 13e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdlib.h> 14e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdint.h> 15e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <fcntl.h> 16e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <string.h> 17a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs#include <math.h> 18e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <time.h> 19e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <sys/stat.h> 20e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <errno.h> 21fed16d043a14e8b86c97a6413aec7281fefcbcb5srs#include <iostream> 229a46b042c57144c26a67781d335e6ba4128382d2srs#include <algorithm> 23e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "crc32.h" 24e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "gpt.h" 25221e08768de7fe42ba533ca22baf671420569c07srs#include "bsd.h" 26e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "support.h" 27e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "parttypes.h" 28e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "attributes.h" 29546a9c7c369df465021feecb20f6a8f81b6df6bcsrs#include "diskio.h" 30e7b4ff9317fc4e551cf974684eaa88697de5a28srs 31e7b4ff9317fc4e551cf974684eaa88697de5a28srsusing namespace std; 32e7b4ff9317fc4e551cf974684eaa88697de5a28srs 338f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#ifdef __FreeBSD__ 349ba5421f920e192dbb808d30aa6d34849938bab4srs#define log2(x) (log(x) / M_LN2) 359ba5421f920e192dbb808d30aa6d34849938bab4srs#endif // __FreeBSD__ 369ba5421f920e192dbb808d30aa6d34849938bab4srs 378f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#ifdef _MSC_VER 388f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#define log2(x) (log((double) x) / log(2.0)) 398f1b2d6edcb4ab45c8cf80c6e58c5c776d2e550esrs#endif // Microsoft Visual C++ 409ba5421f920e192dbb808d30aa6d34849938bab4srs 411f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#ifdef EFI 421f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith// in UEFI mode MMX registers are not yet available so using the 431f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith// x86_64 ABI to move "double" values around is not an option. 441f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#ifdef log2 451f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#undef log2 461f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#endif 471f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#define log2(x) log2_32( x ) 481f7822eb54337766002431f01e5934c7d4703628Roderick W. Smithstatic inline uint32_t log2_32(uint32_t v) { 491f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith int r = -1; 501f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith while (v >= 1) { 511f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith r++; 521f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith v >>= 1; 531f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith } 541f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith return r; 551f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith} 561f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith#endif 571f7822eb54337766002431f01e5934c7d4703628Roderick W. Smith 58e7b4ff9317fc4e551cf974684eaa88697de5a28srs/**************************************** 59e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 60e7b4ff9317fc4e551cf974684eaa88697de5a28srs * GPTData class and related structures * 61e7b4ff9317fc4e551cf974684eaa88697de5a28srs * * 62e7b4ff9317fc4e551cf974684eaa88697de5a28srs ****************************************/ 63e7b4ff9317fc4e551cf974684eaa88697de5a28srs 64e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Default constructor 65e7b4ff9317fc4e551cf974684eaa88697de5a28srsGPTData::GPTData(void) { 66e7b4ff9317fc4e551cf974684eaa88697de5a28srs blockSize = SECTOR_SIZE; // set a default 67e7b4ff9317fc4e551cf974684eaa88697de5a28srs diskSize = 0; 68e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions = NULL; 69e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_valid; 70fed16d043a14e8b86c97a6413aec7281fefcbcb5srs device = ""; 715d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs justLooking = 0; 72e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainCrcOk = 0; 73e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondCrcOk = 0; 74e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainPartsCrcOk = 0; 75e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondPartsCrcOk = 0; 76221e08768de7fe42ba533ca22baf671420569c07srs apmFound = 0; 77221e08768de7fe42ba533ca22baf671420569c07srs bsdFound = 0; 780873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default 79ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs beQuiet = 0; 80ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs whichWasUsed = use_new; 811e09372bca227ffbfb9dda48160826d8f63ce9bbsrs mainHeader.numParts = 0; 820283dae41a7db4563be0fe62241ed230e4a101c0srs numParts = 0; 83e7b4ff9317fc4e551cf974684eaa88697de5a28srs SetGPTSize(NUM_GPT_ENTRIES); 84d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // Initialize CRC functions... 85d1b11e8305621d73ff675af940e7f1f28b639b0dsrs chksum_crc32gentab(); 86e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData default constructor 87e7b4ff9317fc4e551cf974684eaa88697de5a28srs 88e7b4ff9317fc4e551cf974684eaa88697de5a28srs// The following constructor loads GPT data from a device file 89fed16d043a14e8b86c97a6413aec7281fefcbcb5srsGPTData::GPTData(string filename) { 90e7b4ff9317fc4e551cf974684eaa88697de5a28srs blockSize = SECTOR_SIZE; // set a default 91e7b4ff9317fc4e551cf974684eaa88697de5a28srs diskSize = 0; 92e7b4ff9317fc4e551cf974684eaa88697de5a28srs partitions = NULL; 93e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_invalid; 94fed16d043a14e8b86c97a6413aec7281fefcbcb5srs device = ""; 955d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs justLooking = 0; 96e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainCrcOk = 0; 97e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondCrcOk = 0; 98e7b4ff9317fc4e551cf974684eaa88697de5a28srs mainPartsCrcOk = 0; 99e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondPartsCrcOk = 0; 100221e08768de7fe42ba533ca22baf671420569c07srs apmFound = 0; 101221e08768de7fe42ba533ca22baf671420569c07srs bsdFound = 0; 1020873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default 103ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs beQuiet = 0; 104ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs whichWasUsed = use_new; 1051e09372bca227ffbfb9dda48160826d8f63ce9bbsrs mainHeader.numParts = 0; 1060283dae41a7db4563be0fe62241ed230e4a101c0srs numParts = 0; 107d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // Initialize CRC functions... 108d1b11e8305621d73ff675af940e7f1f28b639b0dsrs chksum_crc32gentab(); 1093c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (!LoadPartitions(filename)) 1103c0af38237d0f40aaea8233a5cbfdd030a77817dsrs exit(2); 111fed16d043a14e8b86c97a6413aec7281fefcbcb5srs} // GPTData(string filename) constructor 112e7b4ff9317fc4e551cf974684eaa88697de5a28srs 113e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Destructor 114e7b4ff9317fc4e551cf974684eaa88697de5a28srsGPTData::~GPTData(void) { 115cb76c673eeb84344887715d36d44b799042be5a5srs delete[] partitions; 116e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData destructor 117e7b4ff9317fc4e551cf974684eaa88697de5a28srs 11864cbd171067eb34054741bfcd73f0b91d727a371srs// Assignment operator 11964cbd171067eb34054741bfcd73f0b91d727a371srsGPTData & GPTData::operator=(const GPTData & orig) { 12064cbd171067eb34054741bfcd73f0b91d727a371srs uint32_t i; 12164cbd171067eb34054741bfcd73f0b91d727a371srs 12264cbd171067eb34054741bfcd73f0b91d727a371srs mainHeader = orig.mainHeader; 12364cbd171067eb34054741bfcd73f0b91d727a371srs numParts = orig.numParts; 12464cbd171067eb34054741bfcd73f0b91d727a371srs secondHeader = orig.secondHeader; 12564cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR = orig.protectiveMBR; 12664cbd171067eb34054741bfcd73f0b91d727a371srs device = orig.device; 12764cbd171067eb34054741bfcd73f0b91d727a371srs blockSize = orig.blockSize; 12864cbd171067eb34054741bfcd73f0b91d727a371srs diskSize = orig.diskSize; 12964cbd171067eb34054741bfcd73f0b91d727a371srs state = orig.state; 13064cbd171067eb34054741bfcd73f0b91d727a371srs justLooking = orig.justLooking; 13164cbd171067eb34054741bfcd73f0b91d727a371srs mainCrcOk = orig.mainCrcOk; 13264cbd171067eb34054741bfcd73f0b91d727a371srs secondCrcOk = orig.secondCrcOk; 13364cbd171067eb34054741bfcd73f0b91d727a371srs mainPartsCrcOk = orig.mainPartsCrcOk; 13464cbd171067eb34054741bfcd73f0b91d727a371srs secondPartsCrcOk = orig.secondPartsCrcOk; 13564cbd171067eb34054741bfcd73f0b91d727a371srs apmFound = orig.apmFound; 13664cbd171067eb34054741bfcd73f0b91d727a371srs bsdFound = orig.bsdFound; 13764cbd171067eb34054741bfcd73f0b91d727a371srs sectorAlignment = orig.sectorAlignment; 13864cbd171067eb34054741bfcd73f0b91d727a371srs beQuiet = orig.beQuiet; 13964cbd171067eb34054741bfcd73f0b91d727a371srs whichWasUsed = orig.whichWasUsed; 14064cbd171067eb34054741bfcd73f0b91d727a371srs 14164cbd171067eb34054741bfcd73f0b91d727a371srs myDisk.OpenForRead(orig.myDisk.GetName()); 14264cbd171067eb34054741bfcd73f0b91d727a371srs 14364cbd171067eb34054741bfcd73f0b91d727a371srs delete[] partitions; 14401f7f08624f0c942001977415214a578621f6495srs partitions = new GPTPart [numParts]; 1456aae2a9b70e9f88926baad94c1eea40e0b534f01srs if (partitions == NULL) { 14664cbd171067eb34054741bfcd73f0b91d727a371srs cerr << "Error! Could not allocate memory for partitions in GPTData::operator=()!\n" 1476aae2a9b70e9f88926baad94c1eea40e0b534f01srs << "Terminating!\n"; 1486aae2a9b70e9f88926baad94c1eea40e0b534f01srs exit(1); 1496aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 1506aae2a9b70e9f88926baad94c1eea40e0b534f01srs for (i = 0; i < numParts; i++) { 1516aae2a9b70e9f88926baad94c1eea40e0b534f01srs partitions[i] = orig.partitions[i]; 152d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } // for 153d1b11e8305621d73ff675af940e7f1f28b639b0dsrs 15464cbd171067eb34054741bfcd73f0b91d727a371srs return *this; 15564cbd171067eb34054741bfcd73f0b91d727a371srs} // GPTData::operator=() 15664cbd171067eb34054741bfcd73f0b91d727a371srs 157e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/********************************************************************* 158e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 159e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Begin functions that verify data, or that adjust the verification * 160e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * information (compute CRCs, rebuild headers) * 161e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 162e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *********************************************************************/ 163e7b4ff9317fc4e551cf974684eaa88697de5a28srs 164e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Perform detailed verification, reporting on any problems found, but 165e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// do *NOT* recover from these problems. Returns the total number of 166e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// problems identified. 167e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::Verify(void) { 16864cbd171067eb34054741bfcd73f0b91d727a371srs int problems = 0, alignProbs = 0; 169e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i, numSegments; 170e321d444dcca514cf6b53459e388ddcbaab6176csrs uint64_t totalFree, largestSegment; 171e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 172e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // First, check for CRC errors in the GPT data.... 173e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!mainCrcOk) { 174e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 175fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The CRC for the main GPT header is invalid. The main GPT header may\n" 176fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n" 177fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "header ('b' on the recovery & transformation menu). This report may be a false\n" 178fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "alarm if you've already corrected other problems.\n"; 179e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 180e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!mainPartsCrcOk) { 181e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 182fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The CRC for the main partition table is invalid. This table may be\n" 183fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "corrupt. Consider loading the backup partition table ('c' on the recovery &\n" 184fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "transformation menu). This report may be a false alarm if you've already\n" 185fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "corrected other problems.\n"; 186e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 187e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!secondCrcOk) { 188e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 189fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The CRC for the backup GPT header is invalid. The backup GPT header\n" 190fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "may be corrupt. Consider using the main GPT header to rebuild the backup GPT\n" 191fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "header ('d' on the recovery & transformation menu). This report may be a false\n" 192fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "alarm if you've already corrected other problems.\n"; 193e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 194e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!secondPartsCrcOk) { 195e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 196fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nCaution: The CRC for the backup partition table is invalid. This table may\n" 197fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "be corrupt. This program will automatically create a new backup partition\n" 198fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "table when you save your partitions.\n"; 199e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 200e7b4ff9317fc4e551cf974684eaa88697de5a28srs 201978041ca613dcb881763b36cf53639d924e52a56srs // Now check that the main and backup headers both point to themselves.... 202978041ca613dcb881763b36cf53639d924e52a56srs if (mainHeader.currentLBA != 1) { 203978041ca613dcb881763b36cf53639d924e52a56srs problems++; 204fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The main header's self-pointer doesn't point to itself. This problem\n" 205fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "is being automatically corrected, but it may be a symptom of more serious\n" 206fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "problems. Think carefully before saving changes with 'w' or using this disk.\n"; 207978041ca613dcb881763b36cf53639d924e52a56srs mainHeader.currentLBA = 1; 208978041ca613dcb881763b36cf53639d924e52a56srs } // if 209978041ca613dcb881763b36cf53639d924e52a56srs if (secondHeader.currentLBA != (diskSize - UINT64_C(1))) { 210978041ca613dcb881763b36cf53639d924e52a56srs problems++; 211fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: The secondary header's self-pointer indicates that it doesn't reside\n" 212fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "at the end of the disk. If you've added a disk to a RAID array, use the 'e'\n" 213fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "option on the experts' menu to adjust the secondary header's and partition\n" 214fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "table's locations.\n"; 215978041ca613dcb881763b36cf53639d924e52a56srs } // if 216978041ca613dcb881763b36cf53639d924e52a56srs 217978041ca613dcb881763b36cf53639d924e52a56srs // Now check that critical main and backup GPT entries match each other 218e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.currentLBA != secondHeader.backupLBA) { 219e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 220fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's current LBA pointer (" << mainHeader.currentLBA 221fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's alternate LBA pointer(" 222fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.backupLBA << ").\n"; 223e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 224e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.backupLBA != secondHeader.currentLBA) { 225e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 226fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's backup LBA pointer (" << mainHeader.backupLBA 227fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's current LBA pointer (" 228fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.currentLBA << ").\n" 229fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "The 'e' option on the experts' menu may fix this problem.\n"; 230e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 231e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.firstUsableLBA != secondHeader.firstUsableLBA) { 232e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 233fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's first usable LBA pointer (" << mainHeader.firstUsableLBA 234fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's first usable LBA pointer (" 235fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.firstUsableLBA << ")\n"; 236e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 237e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.lastUsableLBA != secondHeader.lastUsableLBA) { 238e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 239fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's last usable LBA pointer (" << mainHeader.lastUsableLBA 240fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's last usable LBA pointer (" 241fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.lastUsableLBA << ")\n" 242fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "The 'e' option on the experts' menu can probably fix this problem.\n"; 243e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 2446699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if ((mainHeader.diskGUID != secondHeader.diskGUID)) { 245e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 2465a081757ea2e32a491349544fea92826ccf739f6srs cout << "\nProblem: main header's disk GUID (" << mainHeader.diskGUID 247fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's disk GUID (" 2485a081757ea2e32a491349544fea92826ccf739f6srs << secondHeader.diskGUID << ")\n" 249fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" 250fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "select one or the other header.\n"; 251e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 252e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.numParts != secondHeader.numParts) { 253e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 254fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's number of partitions (" << mainHeader.numParts 255fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ") doesn't\nmatch the backup GPT header's number of partitions (" 256fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.numParts << ")\n" 257fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "Resizing the partition table ('s' on the experts' menu) may help.\n"; 258e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 259e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (mainHeader.sizeOfPartitionEntries != secondHeader.sizeOfPartitionEntries) { 260e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 261fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: main GPT header's size of partition entries (" 262fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << mainHeader.sizeOfPartitionEntries << ") doesn't\n" 263fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "match the backup GPT header's size of partition entries (" 264fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << secondHeader.sizeOfPartitionEntries << ")\n" 265fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" 266fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "select one or the other header.\n"; 267e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 268e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 269e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now check for a few other miscellaneous problems... 270e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check that the disk size will hold the data... 27164cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.backupLBA >= diskSize) { 272e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 273fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: Disk is too small to hold all the data!\n" 274fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "(Disk size is " << diskSize << " sectors, needs to be " 27564cbd171067eb34054741bfcd73f0b91d727a371srs << mainHeader.backupLBA + UINT64_C(1) << " sectors.)\n" 276fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "The 'e' option on the experts' menu may fix this problem.\n"; 277e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 278e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 279d8eed4629449a325999808a0170dbda53bd4a6dfsrs if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) { 280d8eed4629449a325999808a0170dbda53bd4a6dfsrs problems++; 2810741fa21ac6cb477891ef15f269c8c8f36cac7c6srs cout << "\nProblem: GPT claims the disk is larger than it is! (Claimed last usable\n" 2820741fa21ac6cb477891ef15f269c8c8f36cac7c6srs << "sector is " << mainHeader.lastUsableLBA << ", but backup header is at\n" 2830741fa21ac6cb477891ef15f269c8c8f36cac7c6srs << mainHeader.backupLBA << " and disk size is " << diskSize << " sectors.\n" 2840741fa21ac6cb477891ef15f269c8c8f36cac7c6srs << "The 'e' option on the experts' menu will probably fix this problem\n"; 285d8eed4629449a325999808a0170dbda53bd4a6dfsrs } 286d8eed4629449a325999808a0170dbda53bd4a6dfsrs 287e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for overlapping partitions.... 288e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems += FindOverlaps(); 289e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 29055d926192adc984462509b2966e23bc0d1129bbdsrs // Check for insane partitions (start after end, hugely big, etc.) 29155d926192adc984462509b2966e23bc0d1129bbdsrs problems += FindInsanePartitions(); 29255d926192adc984462509b2966e23bc0d1129bbdsrs 293e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for mismatched MBR and GPT partitions... 294e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems += FindHybridMismatches(); 295e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 296327129e9331f888a8fc08d688dcb0a739a3c17besrs // Check for MBR-specific problems.... 297327129e9331f888a8fc08d688dcb0a739a3c17besrs problems += VerifyMBR(); 298327129e9331f888a8fc08d688dcb0a739a3c17besrs 299042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith // Check for a 0xEE protective partition that's marked as active.... 300042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith if (protectiveMBR.IsEEActive()) { 301042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith cout << "\nWarning: The 0xEE protective partition in the MBR is marked as active. This is\n" 302042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "technically a violation of the GPT specification, and can cause some EFIs to\n" 303042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "ignore the disk, but it is required to boot from a GPT disk on some BIOS-based\n" 304042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "computers. You can clear this flag by creating a fresh protective MBR using\n" 305042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith << "the 'n' option on the experts' menu.\n"; 306042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith } 307042f38a2f716fd4a3b9b03c35951e69f1d1bc942Roderick W. Smith 308e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Verify that partitions don't run into GPT data areas.... 309e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems += CheckGPTSize(); 310e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 3114a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if (!protectiveMBR.DoTheyFit()) { 3124a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith cout << "\nPartition(s) in the protective MBR are too big for the disk! Creating a\n" 3134a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith << "fresh protective or hybrid MBR is recommended.\n"; 3144a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith problems++; 3154a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } 3164a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith 3171d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // Check that partitions are aligned on proper boundaries (for WD Advanced 3181d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // Format and similar disks).... 3190283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 320e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() % sectorAlignment) != 0) { 321fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nCaution: Partition " << i + 1 << " doesn't begin on a " 322fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << sectorAlignment << "-sector boundary. This may\nresult " 323fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "in degraded performance on some modern (2009 and later) hard disks.\n"; 32464cbd171067eb34054741bfcd73f0b91d727a371srs alignProbs++; 3251d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 3261d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // for 32764cbd171067eb34054741bfcd73f0b91d727a371srs if (alignProbs > 0) 32864cbd171067eb34054741bfcd73f0b91d727a371srs cout << "\nConsult http://www.ibm.com/developerworks/linux/library/l-4kb-sector-disks/\n" 32964cbd171067eb34054741bfcd73f0b91d727a371srs << "for information on disk alignment.\n"; 3301d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 331e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now compute available space, but only if no problems found, since 332e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // problems could affect the results 333e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (problems == 0) { 334e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs totalFree = FindFreeBlocks(&numSegments, &largestSegment); 33564cbd171067eb34054741bfcd73f0b91d727a371srs cout << "\nNo problems found. " << totalFree << " free sectors (" 33601f7f08624f0c942001977415214a578621f6495srs << BytesToIeee(totalFree, blockSize) << ") available in " 337fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << numSegments << "\nsegments, the largest of which is " 33801f7f08624f0c942001977415214a578621f6495srs << largestSegment << " (" << BytesToIeee(largestSegment, blockSize) 3390283dae41a7db4563be0fe62241ed230e4a101c0srs << ") in size.\n"; 340e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 3410a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "\nIdentified " << problems << " problems!\n"; 342e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 343e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 344e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (problems); 345e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::Verify() 346e7b4ff9317fc4e551cf974684eaa88697de5a28srs 347e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Checks to see if the GPT tables overrun existing partitions; if they 348221e08768de7fe42ba533ca22baf671420569c07srs// do, issues a warning but takes no action. Returns number of problems 349221e08768de7fe42ba533ca22baf671420569c07srs// detected (0 if OK, 1 to 2 if problems). 350e7b4ff9317fc4e551cf974684eaa88697de5a28srsint GPTData::CheckGPTSize(void) { 351e7b4ff9317fc4e551cf974684eaa88697de5a28srs uint64_t overlap, firstUsedBlock, lastUsedBlock; 352e7b4ff9317fc4e551cf974684eaa88697de5a28srs uint32_t i; 353221e08768de7fe42ba533ca22baf671420569c07srs int numProbs = 0; 354e7b4ff9317fc4e551cf974684eaa88697de5a28srs 355e7b4ff9317fc4e551cf974684eaa88697de5a28srs // first, locate the first & last used blocks 356e7b4ff9317fc4e551cf974684eaa88697de5a28srs firstUsedBlock = UINT64_MAX; 357e7b4ff9317fc4e551cf974684eaa88697de5a28srs lastUsedBlock = 0; 3580283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 359e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].IsUsed()) { 360706e51217a531c46afc743b556e10fd5c0585fcfsrs if (partitions[i].GetFirstLBA() < firstUsedBlock) 361e69e6807cf84fe2b80c48475531ce4bd09563bbasrs firstUsedBlock = partitions[i].GetFirstLBA(); 362e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].GetLastLBA() > lastUsedBlock) { 363e69e6807cf84fe2b80c48475531ce4bd09563bbasrs lastUsedBlock = partitions[i].GetLastLBA(); 364e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 365e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 366e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // for 367e7b4ff9317fc4e551cf974684eaa88697de5a28srs 368e7b4ff9317fc4e551cf974684eaa88697de5a28srs // If the disk size is 0 (the default), then it means that various 369e7b4ff9317fc4e551cf974684eaa88697de5a28srs // variables aren't yet set, so the below tests will be useless; 370e7b4ff9317fc4e551cf974684eaa88697de5a28srs // therefore we should skip everything 371e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (diskSize != 0) { 372e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (mainHeader.firstUsableLBA > firstUsedBlock) { 373e7b4ff9317fc4e551cf974684eaa88697de5a28srs overlap = mainHeader.firstUsableLBA - firstUsedBlock; 374fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Warning! Main partition table overlaps the first partition by " 375fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << overlap << " blocks!\n"; 376221e08768de7fe42ba533ca22baf671420569c07srs if (firstUsedBlock > 2) { 377fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Try reducing the partition table size by " << overlap * 4 378fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " entries.\n(Use the 's' item on the experts' menu.)\n"; 379221e08768de7fe42ba533ca22baf671420569c07srs } else { 380fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "You will need to delete this partition or resize it in another utility.\n"; 381221e08768de7fe42ba533ca22baf671420569c07srs } // if/else 382221e08768de7fe42ba533ca22baf671420569c07srs numProbs++; 383e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // Problem at start of disk 384e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (mainHeader.lastUsableLBA < lastUsedBlock) { 385e7b4ff9317fc4e551cf974684eaa88697de5a28srs overlap = lastUsedBlock - mainHeader.lastUsableLBA; 38655d926192adc984462509b2966e23bc0d1129bbdsrs cout << "\nWarning! Secondary partition table overlaps the last partition by\n" 387fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << overlap << " blocks!\n"; 388221e08768de7fe42ba533ca22baf671420569c07srs if (lastUsedBlock > (diskSize - 2)) { 389fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "You will need to delete this partition or resize it in another utility.\n"; 390221e08768de7fe42ba533ca22baf671420569c07srs } else { 391fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Try reducing the partition table size by " << overlap * 4 392fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " entries.\n(Use the 's' item on the experts' menu.)\n"; 393221e08768de7fe42ba533ca22baf671420569c07srs } // if/else 394221e08768de7fe42ba533ca22baf671420569c07srs numProbs++; 395e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // Problem at end of disk 396e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if (diskSize != 0) 397221e08768de7fe42ba533ca22baf671420569c07srs return numProbs; 398e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::CheckGPTSize() 399e7b4ff9317fc4e551cf974684eaa88697de5a28srs 400e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Check the validity of the GPT header. Returns 1 if the main header 401e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// is valid, 2 if the backup header is valid, 3 if both are valid, and 402d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// 0 if neither is valid. Note that this function checks the GPT signature, 403d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// revision value, and CRCs in both headers. 404e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::CheckHeaderValidity(void) { 405e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int valid = 3; 406221e08768de7fe42ba533ca22baf671420569c07srs 407fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.setf(ios::uppercase); 408fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill('0'); 409fed16d043a14e8b86c97a6413aec7281fefcbcb5srs 410fed16d043a14e8b86c97a6413aec7281fefcbcb5srs // Note: failed GPT signature checks produce no error message because 411fed16d043a14e8b86c97a6413aec7281fefcbcb5srs // a message is displayed in the ReversePartitionBytes() function 412d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if ((mainHeader.signature != GPT_SIGNATURE) || (!CheckHeaderCRC(&mainHeader, 1))) { 413e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 1; 414e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else if ((mainHeader.revision != 0x00010000) && valid) { 415e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 1; 416fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Unsupported GPT version in main header; read 0x"; 417fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 418fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << hex << mainHeader.revision << ", should be\n0x"; 419fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 420fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << UINT32_C(0x00010000) << dec << "\n"; 421e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else/if 422221e08768de7fe42ba533ca22baf671420569c07srs 423d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if ((secondHeader.signature != GPT_SIGNATURE) || (!CheckHeaderCRC(&secondHeader))) { 424e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 2; 425e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else if ((secondHeader.revision != 0x00010000) && valid) { 426e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs valid -= 2; 427fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Unsupported GPT version in backup header; read 0x"; 428fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 429fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << hex << secondHeader.revision << ", should be\n0x"; 430fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(8); 431fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << UINT32_C(0x00010000) << dec << "\n"; 432e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else/if 433221e08768de7fe42ba533ca22baf671420569c07srs 434df9d363d341a0ffdd05250fd4ffb842f59815690srs // Check for an Apple disk signature 435df9d363d341a0ffdd05250fd4ffb842f59815690srs if (((mainHeader.signature << 32) == APM_SIGNATURE1) || 436df9d363d341a0ffdd05250fd4ffb842f59815690srs (mainHeader.signature << 32) == APM_SIGNATURE2) { 437e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs apmFound = 1; // Will display warning message later 4383f2fe99e72648aefc926138132d48efb07a7ad2dsrs } // if 439fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill(' '); 440221e08768de7fe42ba533ca22baf671420569c07srs 441fed16d043a14e8b86c97a6413aec7281fefcbcb5srs return valid; 442e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::CheckHeaderValidity() 443221e08768de7fe42ba533ca22baf671420569c07srs 444e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Check the header CRC to see if it's OK... 445d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Note: Must be called with header in platform-ordered byte order. 446d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Returns 1 if header's computed CRC matches the stored value, 0 if the 447d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// computed and stored values don't match 448d1b11e8305621d73ff675af940e7f1f28b639b0dsrsint GPTData::CheckHeaderCRC(struct GPTHeader* header, int warn) { 449978041ca613dcb881763b36cf53639d924e52a56srs uint32_t oldCRC, newCRC, hSize; 450d1b11e8305621d73ff675af940e7f1f28b639b0dsrs uint8_t *temp; 451221e08768de7fe42ba533ca22baf671420569c07srs 452e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Back up old header CRC and then blank it, since it must be 0 for 453e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // computation to be valid 454e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs oldCRC = header->headerCRC; 455e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs header->headerCRC = UINT32_C(0); 456d1b11e8305621d73ff675af940e7f1f28b639b0dsrs 457978041ca613dcb881763b36cf53639d924e52a56srs hSize = header->headerSize; 458978041ca613dcb881763b36cf53639d924e52a56srs 459d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (IsLittleEndian() == 0) 460d1b11e8305621d73ff675af940e7f1f28b639b0dsrs ReverseHeaderBytes(header); 461221e08768de7fe42ba533ca22baf671420569c07srs 462d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if ((hSize > blockSize) || (hSize < HEADER_SIZE)) { 463d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (warn) { 464d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cerr << "\aWarning! Header size is specified as " << hSize << ", which is invalid.\n"; 465d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cerr << "Setting the header size for CRC computation to " << HEADER_SIZE << "\n"; 466d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } // if 467d1b11e8305621d73ff675af940e7f1f28b639b0dsrs hSize = HEADER_SIZE; 468d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } else if ((hSize > sizeof(GPTHeader)) && warn) { 469d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cout << "\aCaution! Header size for CRC check is " << hSize << ", which is greater than " << sizeof(GPTHeader) << ".\n"; 470d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cout << "If stray data exists after the header on the header sector, it will be ignored,\n" 471d1b11e8305621d73ff675af940e7f1f28b639b0dsrs << "which may result in a CRC false alarm.\n"; 472d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } // if/elseif 473d1b11e8305621d73ff675af940e7f1f28b639b0dsrs temp = new uint8_t[hSize]; 474d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (temp != NULL) { 475d1b11e8305621d73ff675af940e7f1f28b639b0dsrs memset(temp, 0, hSize); 476d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (hSize < sizeof(GPTHeader)) 477d1b11e8305621d73ff675af940e7f1f28b639b0dsrs memcpy(temp, header, hSize); 478d1b11e8305621d73ff675af940e7f1f28b639b0dsrs else 479d1b11e8305621d73ff675af940e7f1f28b639b0dsrs memcpy(temp, header, sizeof(GPTHeader)); 480e7b4ff9317fc4e551cf974684eaa88697de5a28srs 481d1b11e8305621d73ff675af940e7f1f28b639b0dsrs newCRC = chksum_crc32((unsigned char*) temp, hSize); 482d1b11e8305621d73ff675af940e7f1f28b639b0dsrs delete[] temp; 483d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } else { 484d1b11e8305621d73ff675af940e7f1f28b639b0dsrs cerr << "Could not allocate memory in GPTData::CheckHeaderCRC()! Aborting!\n"; 485d1b11e8305621d73ff675af940e7f1f28b639b0dsrs exit(1); 486d1b11e8305621d73ff675af940e7f1f28b639b0dsrs } 487d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (IsLittleEndian() == 0) 488d1b11e8305621d73ff675af940e7f1f28b639b0dsrs ReverseHeaderBytes(header); 489978041ca613dcb881763b36cf53639d924e52a56srs header->headerCRC = oldCRC; 490e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (oldCRC == newCRC); 491e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::CheckHeaderCRC() 492e7b4ff9317fc4e551cf974684eaa88697de5a28srs 4936699b01eda84d24bfaf80ad725304fef2b0e1b2asrs// Recompute all the CRCs. Must be called before saving if any changes have 4946699b01eda84d24bfaf80ad725304fef2b0e1b2asrs// been made. Must be called on platform-ordered data (this function reverses 4956699b01eda84d24bfaf80ad725304fef2b0e1b2asrs// byte order and then undoes that reversal.) 496e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::RecomputeCRCs(void) { 4970283dae41a7db4563be0fe62241ed230e4a101c0srs uint32_t crc, hSize; 498e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int littleEndian = 1; 499e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 500d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // If the header size is bigger than the GPT header data structure, reset it; 501d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // otherwise, set both header sizes to whatever the main one is.... 502d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (mainHeader.headerSize > sizeof(GPTHeader)) 503d1b11e8305621d73ff675af940e7f1f28b639b0dsrs hSize = secondHeader.headerSize = mainHeader.headerSize = HEADER_SIZE; 504d1b11e8305621d73ff675af940e7f1f28b639b0dsrs else 505d1b11e8305621d73ff675af940e7f1f28b639b0dsrs hSize = secondHeader.headerSize = mainHeader.headerSize; 5066699b01eda84d24bfaf80ad725304fef2b0e1b2asrs 5076699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if ((littleEndian = IsLittleEndian()) == 0) { 5086699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReversePartitionBytes(); 5096699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&mainHeader); 5106699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&secondHeader); 5116699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 512e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 513e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Compute CRC of partition tables & store in main and secondary headers 5140283dae41a7db4563be0fe62241ed230e4a101c0srs crc = chksum_crc32((unsigned char*) partitions, numParts * GPT_SIZE); 515e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesCRC = crc; 516e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.partitionEntriesCRC = crc; 517e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (littleEndian == 0) { 518e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&mainHeader.partitionEntriesCRC, 4); 519e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&secondHeader.partitionEntriesCRC, 4); 520e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 521e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 522d1b11e8305621d73ff675af940e7f1f28b639b0dsrs // Zero out GPT headers' own CRCs (required for correct computation) 523e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.headerCRC = 0; 524e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.headerCRC = 0; 525e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 526978041ca613dcb881763b36cf53639d924e52a56srs crc = chksum_crc32((unsigned char*) &mainHeader, hSize); 527e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (littleEndian == 0) 528e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&crc, 4); 529e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.headerCRC = crc; 530978041ca613dcb881763b36cf53639d924e52a56srs crc = chksum_crc32((unsigned char*) &secondHeader, hSize); 531e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (littleEndian == 0) 532e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReverseBytes(&crc, 4); 533e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.headerCRC = crc; 5346699b01eda84d24bfaf80ad725304fef2b0e1b2asrs 535d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (littleEndian == 0) { 5366699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&mainHeader); 5376699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReverseHeaderBytes(&secondHeader); 5386699b01eda84d24bfaf80ad725304fef2b0e1b2asrs ReversePartitionBytes(); 5396699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 540e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::RecomputeCRCs() 541e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 542e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Rebuild the main GPT header, using the secondary header as a model. 543e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Typically called when the main header has been found to be corrupt. 544e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::RebuildMainHeader(void) { 545e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.signature = GPT_SIGNATURE; 546e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.revision = secondHeader.revision; 547978041ca613dcb881763b36cf53639d924e52a56srs mainHeader.headerSize = secondHeader.headerSize; 548e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.headerCRC = UINT32_C(0); 549e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.reserved = secondHeader.reserved; 550e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.currentLBA = secondHeader.backupLBA; 551e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.backupLBA = secondHeader.currentLBA; 552e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.firstUsableLBA = secondHeader.firstUsableLBA; 553e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.lastUsableLBA = secondHeader.lastUsableLBA; 5546699b01eda84d24bfaf80ad725304fef2b0e1b2asrs mainHeader.diskGUID = secondHeader.diskGUID; 555e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesLBA = UINT64_C(2); 556e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.numParts = secondHeader.numParts; 557e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries; 558e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC; 55901f7f08624f0c942001977415214a578621f6495srs memcpy(mainHeader.reserved2, secondHeader.reserved2, sizeof(mainHeader.reserved2)); 560546a9c7c369df465021feecb20f6a8f81b6df6bcsrs mainCrcOk = secondCrcOk; 561706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(mainHeader.numParts, 0); 562e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::RebuildMainHeader() 563e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 564e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Rebuild the secondary GPT header, using the main header as a model. 565e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::RebuildSecondHeader(void) { 566e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.signature = GPT_SIGNATURE; 567e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.revision = mainHeader.revision; 568978041ca613dcb881763b36cf53639d924e52a56srs secondHeader.headerSize = mainHeader.headerSize; 569e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.headerCRC = UINT32_C(0); 570e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.reserved = mainHeader.reserved; 571e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.currentLBA = mainHeader.backupLBA; 572e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.backupLBA = mainHeader.currentLBA; 573e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; 574e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.lastUsableLBA = mainHeader.lastUsableLBA; 5756699b01eda84d24bfaf80ad725304fef2b0e1b2asrs secondHeader.diskGUID = mainHeader.diskGUID; 576e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); 577e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.numParts = mainHeader.numParts; 578e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries; 579e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.partitionEntriesCRC = mainHeader.partitionEntriesCRC; 58001f7f08624f0c942001977415214a578621f6495srs memcpy(secondHeader.reserved2, mainHeader.reserved2, sizeof(secondHeader.reserved2)); 581546a9c7c369df465021feecb20f6a8f81b6df6bcsrs secondCrcOk = mainCrcOk; 582706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(secondHeader.numParts, 0); 583e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::RebuildSecondHeader() 584e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 585e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Search for hybrid MBR entries that have no corresponding GPT partition. 586e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Returns number of such mismatches found 587e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::FindHybridMismatches(void) { 588e321d444dcca514cf6b53459e388ddcbaab6176csrs int i, found, numFound = 0; 589e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t j; 590e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t mbrFirst, mbrLast; 591e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 592e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < 4; i++) { 593e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((protectiveMBR.GetType(i) != 0xEE) && (protectiveMBR.GetType(i) != 0x00)) { 594e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs j = 0; 595e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs found = 0; 596d1b11e8305621d73ff675af940e7f1f28b639b0dsrs mbrFirst = (uint64_t) protectiveMBR.GetFirstSector(i); 597d1b11e8305621d73ff675af940e7f1f28b639b0dsrs mbrLast = mbrFirst + (uint64_t) protectiveMBR.GetLength(i) - UINT64_C(1); 598e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 59924bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if ((j < numParts) && (partitions[j].GetFirstLBA() == mbrFirst) && 600e69e6807cf84fe2b80c48475531ce4bd09563bbasrs (partitions[j].GetLastLBA() == mbrLast) && (partitions[j].IsUsed())) 601e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs found = 1; 602e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs j++; 6030283dae41a7db4563be0fe62241ed230e4a101c0srs } while ((!found) && (j < numParts)); 604e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (!found) { 605e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs numFound++; 606fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nWarning! Mismatched GPT and MBR partition! MBR partition " 607fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << i + 1 << ", of type 0x"; 608fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill('0'); 609fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.setf(ios::uppercase); 610fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.width(2); 611fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << hex << (int) protectiveMBR.GetType(i) << ",\n" 612fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "has no corresponding GPT partition! You may continue, but this condition\n" 613fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "might cause data loss in the future!\a\n" << dec; 614fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout.fill(' '); 615e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 616e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 617e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 618e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numFound; 619e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindHybridMismatches 620e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 621e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find overlapping partitions and warn user about them. Returns number of 622e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// overlapping partitions. 623d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Returns number of overlapping segments found. 624e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::FindOverlaps(void) { 625e321d444dcca514cf6b53459e388ddcbaab6176csrs int problems = 0; 626e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i, j; 627e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 6280283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 1; i < numParts; i++) { 629e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (j = 0; j < i; j++) { 630e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if ((partitions[i].IsUsed()) && (partitions[j].IsUsed()) && 631e69e6807cf84fe2b80c48475531ce4bd09563bbasrs (partitions[i].DoTheyOverlap(partitions[j]))) { 632e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs problems++; 633fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nProblem: partitions " << i + 1 << " and " << j + 1 << " overlap:\n"; 634fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " Partition " << i + 1 << ": " << partitions[i].GetFirstLBA() 635fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " to " << partitions[i].GetLastLBA() << "\n"; 636fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " Partition " << j + 1 << ": " << partitions[j].GetFirstLBA() 637fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " to " << partitions[j].GetLastLBA() << "\n"; 638e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 639e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for j... 640e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for i... 641e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return problems; 642e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindOverlaps() 643e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 64455d926192adc984462509b2966e23bc0d1129bbdsrs// Find partitions that are insane -- they start after they end or are too 64555d926192adc984462509b2966e23bc0d1129bbdsrs// big for the disk. (The latter should duplicate detection of overlaps 64655d926192adc984462509b2966e23bc0d1129bbdsrs// with GPT backup data structures, but better to err on the side of 64755d926192adc984462509b2966e23bc0d1129bbdsrs// redundant tests than to miss something....) 648d1b11e8305621d73ff675af940e7f1f28b639b0dsrs// Returns number of problems found. 64955d926192adc984462509b2966e23bc0d1129bbdsrsint GPTData::FindInsanePartitions(void) { 65055d926192adc984462509b2966e23bc0d1129bbdsrs uint32_t i; 65155d926192adc984462509b2966e23bc0d1129bbdsrs int problems = 0; 65255d926192adc984462509b2966e23bc0d1129bbdsrs 6530283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 654e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].IsUsed()) { 655e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].GetFirstLBA() > partitions[i].GetLastLBA()) { 656e69e6807cf84fe2b80c48475531ce4bd09563bbasrs problems++; 657e69e6807cf84fe2b80c48475531ce4bd09563bbasrs cout << "\nProblem: partition " << i + 1 << " ends before it begins.\n"; 658e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 659e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].GetLastLBA() >= diskSize) { 660e69e6807cf84fe2b80c48475531ce4bd09563bbasrs problems++; 661e69e6807cf84fe2b80c48475531ce4bd09563bbasrs cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n"; 662e69e6807cf84fe2b80c48475531ce4bd09563bbasrs } // if 66355d926192adc984462509b2966e23bc0d1129bbdsrs } // if 66455d926192adc984462509b2966e23bc0d1129bbdsrs } // for 66555d926192adc984462509b2966e23bc0d1129bbdsrs return problems; 66655d926192adc984462509b2966e23bc0d1129bbdsrs} // GPTData::FindInsanePartitions(void) 66755d926192adc984462509b2966e23bc0d1129bbdsrs 66855d926192adc984462509b2966e23bc0d1129bbdsrs 669e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/****************************************************************** 670e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 671e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Begin functions that load data from disk or save data to disk. * 672e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 673e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ******************************************************************/ 674e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 67564cbd171067eb34054741bfcd73f0b91d727a371srs// Change the filename associated with the GPT. Used for duplicating 67664cbd171067eb34054741bfcd73f0b91d727a371srs// the partition table to a new disk and saving backups. 67764cbd171067eb34054741bfcd73f0b91d727a371srs// Returns 1 on success, 0 on failure. 678bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrsint GPTData::SetDisk(const string & deviceFilename) { 67964cbd171067eb34054741bfcd73f0b91d727a371srs int err, allOK = 1; 68064cbd171067eb34054741bfcd73f0b91d727a371srs 68164cbd171067eb34054741bfcd73f0b91d727a371srs device = deviceFilename; 68264cbd171067eb34054741bfcd73f0b91d727a371srs if (allOK && myDisk.OpenForRead(deviceFilename)) { 68364cbd171067eb34054741bfcd73f0b91d727a371srs // store disk information.... 68464cbd171067eb34054741bfcd73f0b91d727a371srs diskSize = myDisk.DiskSize(&err); 68564cbd171067eb34054741bfcd73f0b91d727a371srs blockSize = (uint32_t) myDisk.GetBlockSize(); 68664cbd171067eb34054741bfcd73f0b91d727a371srs } // if 68764cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.SetDisk(&myDisk); 68864cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.SetDiskSize(diskSize); 68964cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.SetBlockSize(blockSize); 69064cbd171067eb34054741bfcd73f0b91d727a371srs return allOK; 691bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs} // GPTData::SetDisk() 69264cbd171067eb34054741bfcd73f0b91d727a371srs 693e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Scan for partition data. This function loads the MBR data (regular MBR or 694e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// protective MBR) and loads BSD disklabel data (which is probably invalid). 695e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// It also looks for APM data, forces a load of GPT data, and summarizes 696e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// the results. 697546a9c7c369df465021feecb20f6a8f81b6df6bcsrsvoid GPTData::PartitionScan(void) { 698e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs BSDData bsdDisklabel; 699e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 700e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Read the MBR & check for BSD disklabel 701546a9c7c369df465021feecb20f6a8f81b6df6bcsrs protectiveMBR.ReadMBRData(&myDisk); 702546a9c7c369df465021feecb20f6a8f81b6df6bcsrs bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1); 703e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 704e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Load the GPT data, whether or not it's valid 705546a9c7c369df465021feecb20f6a8f81b6df6bcsrs ForceLoadGPTData(); 706ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 7074a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith // Some tools create a 0xEE partition that's too big. If this is detected, 7084a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith // normalize it.... 7094a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if ((state == gpt_valid) && !protectiveMBR.DoTheyFit() && (protectiveMBR.GetValidity() == gpt)) { 7104a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if (!beQuiet) { 7114a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith cerr << "\aThe protective MBR's 0xEE partition is oversized! Auto-repairing.\n\n"; 7124a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } // if 7134a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith protectiveMBR.MakeProtectiveMBR(); 7144a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } // if 7154a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith 716ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (!beQuiet) { 717fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Partition table scan:\n"; 718ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs protectiveMBR.ShowState(); 719ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs bsdDisklabel.ShowState(); 720ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs ShowAPMState(); // Show whether there's an Apple Partition Map present 721ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs ShowGPTState(); // Show GPT status 722fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n"; 723ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } // if 724e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 725e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (apmFound) { 726fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n*******************************************************************\n" 727fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "This disk appears to contain an Apple-format (APM) partition table!\n"; 7285d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (!justLooking) { 729fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "It will be destroyed if you continue!\n"; 7305d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 731fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "*******************************************************************\n\n\a"; 732e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 733e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::PartitionScan() 734e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 735e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Read GPT data from a disk. 7360a6973119c9e9984ad47a6da3231e8d16f996c5csrsint GPTData::LoadPartitions(const string & deviceFilename) { 73708bb0da07953af605b4918e268272de15ac151aasrs BSDData bsdDisklabel; 738e321d444dcca514cf6b53459e388ddcbaab6176csrs int err, allOK = 1; 739fed16d043a14e8b86c97a6413aec7281fefcbcb5srs MBRValidity mbrState; 740e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 74155d926192adc984462509b2966e23bc0d1129bbdsrs if (myDisk.OpenForRead(deviceFilename)) { 74255d926192adc984462509b2966e23bc0d1129bbdsrs err = myDisk.OpenForWrite(deviceFilename); 74355d926192adc984462509b2966e23bc0d1129bbdsrs if ((err == 0) && (!justLooking)) { 74455d926192adc984462509b2966e23bc0d1129bbdsrs cout << "\aNOTE: Write test failed with error number " << errno 74555d926192adc984462509b2966e23bc0d1129bbdsrs << ". It will be impossible to save\nchanges to this disk's partition table!\n"; 74608bb0da07953af605b4918e268272de15ac151aasrs#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) 74755d926192adc984462509b2966e23bc0d1129bbdsrs cout << "You may be able to enable writes by exiting this program, typing\n" 74855d926192adc984462509b2966e23bc0d1129bbdsrs << "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n" 74955d926192adc984462509b2966e23bc0d1129bbdsrs << "program.\n"; 7507dbb932233c77cc91ea202ddf5a6198034558ae2srs#endif 75155d926192adc984462509b2966e23bc0d1129bbdsrs cout << "\n"; 75255d926192adc984462509b2966e23bc0d1129bbdsrs } // if 75355d926192adc984462509b2966e23bc0d1129bbdsrs myDisk.Close(); // Close and re-open read-only in case of bugs 75455d926192adc984462509b2966e23bc0d1129bbdsrs } else allOK = 0; // if 755e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 75655d926192adc984462509b2966e23bc0d1129bbdsrs if (allOK && myDisk.OpenForRead(deviceFilename)) { 757e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // store disk information.... 758546a9c7c369df465021feecb20f6a8f81b6df6bcsrs diskSize = myDisk.DiskSize(&err); 759546a9c7c369df465021feecb20f6a8f81b6df6bcsrs blockSize = (uint32_t) myDisk.GetBlockSize(); 760fed16d043a14e8b86c97a6413aec7281fefcbcb5srs device = deviceFilename; 761546a9c7c369df465021feecb20f6a8f81b6df6bcsrs PartitionScan(); // Check for partition types, load GPT, & print summary 762e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 763ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs whichWasUsed = UseWhichPartitions(); 764ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs switch (whichWasUsed) { 765e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case use_mbr: 766e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs XFormPartitions(); 767e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 768e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case use_bsd: 769546a9c7c369df465021feecb20f6a8f81b6df6bcsrs bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1); 770e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// bsdDisklabel.DisplayBSDData(); 771e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ClearGPTData(); 772e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1) 77308bb0da07953af605b4918e268272de15ac151aasrs XFormDisklabel(&bsdDisklabel); 774e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 775e7b4ff9317fc4e551cf974684eaa88697de5a28srs case use_gpt: 776fed16d043a14e8b86c97a6413aec7281fefcbcb5srs mbrState = protectiveMBR.GetValidity(); 777fed16d043a14e8b86c97a6413aec7281fefcbcb5srs if ((mbrState == invalid) || (mbrState == mbr)) 778fed16d043a14e8b86c97a6413aec7281fefcbcb5srs protectiveMBR.MakeProtectiveMBR(); 779e7b4ff9317fc4e551cf974684eaa88697de5a28srs break; 780e7b4ff9317fc4e551cf974684eaa88697de5a28srs case use_new: 781e7b4ff9317fc4e551cf974684eaa88697de5a28srs ClearGPTData(); 782e7b4ff9317fc4e551cf974684eaa88697de5a28srs protectiveMBR.MakeProtectiveMBR(); 783e7b4ff9317fc4e551cf974684eaa88697de5a28srs break; 7843c0af38237d0f40aaea8233a5cbfdd030a77817dsrs case use_abort: 7853c0af38237d0f40aaea8233a5cbfdd030a77817dsrs allOK = 0; 7869ddc14bb9b154518e2b8384d3f4571cf657c7920srs cerr << "Invalid partition data!\n"; 7873c0af38237d0f40aaea8233a5cbfdd030a77817dsrs break; 788e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // switch 789e7b4ff9317fc4e551cf974684eaa88697de5a28srs 79055d926192adc984462509b2966e23bc0d1129bbdsrs if (allOK) 7913c0af38237d0f40aaea8233a5cbfdd030a77817dsrs CheckGPTSize(); 79255d926192adc984462509b2966e23bc0d1129bbdsrs myDisk.Close(); 793a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs ComputeAlignment(); 794e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 795e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 796e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 797e7b4ff9317fc4e551cf974684eaa88697de5a28srs return (allOK); 798e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::LoadPartitions() 799e7b4ff9317fc4e551cf974684eaa88697de5a28srs 800e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Loads the GPT, as much as possible. Returns 1 if this seems to have 801e7b4ff9317fc4e551cf974684eaa88697de5a28srs// succeeded, 0 if there are obvious problems.... 802546a9c7c369df465021feecb20f6a8f81b6df6bcsrsint GPTData::ForceLoadGPTData(void) { 803cb76c673eeb84344887715d36d44b799042be5a5srs int allOK, validHeaders, loadedTable = 1; 804e7b4ff9317fc4e551cf974684eaa88697de5a28srs 805cb76c673eeb84344887715d36d44b799042be5a5srs allOK = LoadHeader(&mainHeader, myDisk, 1, &mainCrcOk); 806cb76c673eeb84344887715d36d44b799042be5a5srs 807cb76c673eeb84344887715d36d44b799042be5a5srs if (mainCrcOk && (mainHeader.backupLBA < diskSize)) { 808cb76c673eeb84344887715d36d44b799042be5a5srs allOK = LoadHeader(&secondHeader, myDisk, mainHeader.backupLBA, &secondCrcOk) && allOK; 809cb76c673eeb84344887715d36d44b799042be5a5srs } else { 81008bb0da07953af605b4918e268272de15ac151aasrs allOK = LoadHeader(&secondHeader, myDisk, diskSize - UINT64_C(1), &secondCrcOk) && allOK; 81108bb0da07953af605b4918e268272de15ac151aasrs if (mainCrcOk && (mainHeader.backupLBA >= diskSize)) 812fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Warning! Disk size is smaller than the main header indicates! Loading\n" 813fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "secondary header from the last sector of the disk! You should use 'v' to\n" 814fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "verify disk integrity, and perhaps options on the experts' menu to repair\n" 815fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "the disk.\n"; 816cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 817cb76c673eeb84344887715d36d44b799042be5a5srs if (!allOK) 818e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_invalid; 819e7b4ff9317fc4e551cf974684eaa88697de5a28srs 820e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Return valid headers code: 0 = both headers bad; 1 = main header 821e7b4ff9317fc4e551cf974684eaa88697de5a28srs // good, backup bad; 2 = backup header good, main header bad; 822e7b4ff9317fc4e551cf974684eaa88697de5a28srs // 3 = both headers good. Note these codes refer to valid GPT 82323d8d54cdffa9bab0395dab92faa1990410bbb9asrs // signatures, version numbers, and CRCs. 824e7b4ff9317fc4e551cf974684eaa88697de5a28srs validHeaders = CheckHeaderValidity(); 825e7b4ff9317fc4e551cf974684eaa88697de5a28srs 826e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Read partitions (from primary array) 827e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (validHeaders > 0) { // if at least one header is OK.... 828e7b4ff9317fc4e551cf974684eaa88697de5a28srs // GPT appears to be valid.... 829e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_valid; 830e7b4ff9317fc4e551cf974684eaa88697de5a28srs 831e7b4ff9317fc4e551cf974684eaa88697de5a28srs // We're calling the GPT valid, but there's a possibility that one 832e7b4ff9317fc4e551cf974684eaa88697de5a28srs // of the two headers is corrupt. If so, use the one that seems to 833e7b4ff9317fc4e551cf974684eaa88697de5a28srs // be in better shape to regenerate the bad one 834546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (validHeaders == 1) { // valid main header, invalid backup header 835fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aCaution: invalid backup GPT header, but valid main header; regenerating\n" 836fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "backup header from main header.\n\n"; 837e7b4ff9317fc4e551cf974684eaa88697de5a28srs RebuildSecondHeader(); 838546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 839e7b4ff9317fc4e551cf974684eaa88697de5a28srs secondCrcOk = mainCrcOk; // Since regenerated, use CRC validity of main 840546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } else if (validHeaders == 2) { // valid backup header, invalid main header 841fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aCaution: invalid main GPT header, but valid backup; regenerating main header\n" 842fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "from backup!\n\n"; 843546a9c7c369df465021feecb20f6a8f81b6df6bcsrs RebuildMainHeader(); 844546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 845546a9c7c369df465021feecb20f6a8f81b6df6bcsrs mainCrcOk = secondCrcOk; // Since copied, use CRC validity of backup 846e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else/if 847e7b4ff9317fc4e551cf974684eaa88697de5a28srs 848546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // Figure out which partition table to load.... 849546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // Load the main partition table, since either its header's CRC is OK or the 850546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // backup header's CRC is not OK.... 851546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (mainCrcOk || !secondCrcOk) { 852546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (LoadMainTable() == 0) 853546a9c7c369df465021feecb20f6a8f81b6df6bcsrs allOK = 0; 854546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } else { // bad main header CRC and backup header CRC is OK 855546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 856546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (LoadSecondTableAsMain()) { 857cb76c673eeb84344887715d36d44b799042be5a5srs loadedTable = 2; 858fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n"; 859546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } else { // backup table bad, bad main header CRC, but try main table in desperation.... 860546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (LoadMainTable() == 0) { 861546a9c7c369df465021feecb20f6a8f81b6df6bcsrs allOK = 0; 862cb76c673eeb84344887715d36d44b799042be5a5srs loadedTable = 0; 863fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\a\aWarning! Unable to load either main or backup partition table!\n"; 864546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } // if 865546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } // if/else (LoadSecondTableAsMain()) 866546a9c7c369df465021feecb20f6a8f81b6df6bcsrs } // if/else (load partition table) 867e7b4ff9317fc4e551cf974684eaa88697de5a28srs 868cb76c673eeb84344887715d36d44b799042be5a5srs if (loadedTable == 1) 869cb76c673eeb84344887715d36d44b799042be5a5srs secondPartsCrcOk = CheckTable(&secondHeader); 870cb76c673eeb84344887715d36d44b799042be5a5srs else if (loadedTable == 2) 871cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = CheckTable(&mainHeader); 872cb76c673eeb84344887715d36d44b799042be5a5srs else 873cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = secondPartsCrcOk = 0; 874e7b4ff9317fc4e551cf974684eaa88697de5a28srs 875546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // Problem with main partition table; if backup is OK, use it instead.... 876546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) { 877546a9c7c369df465021feecb20f6a8f81b6df6bcsrs state = gpt_corrupt; 878546a9c7c369df465021feecb20f6a8f81b6df6bcsrs allOK = allOK && LoadSecondTableAsMain(); 879cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = 0; // LoadSecondTableAsMain() resets this, so re-flag as bad 880fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup " 881fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "partition table\ninstead of main partition table!\n\n"; 882cb76c673eeb84344887715d36d44b799042be5a5srs } // if */ 883546a9c7c369df465021feecb20f6a8f81b6df6bcsrs 884e7b4ff9317fc4e551cf974684eaa88697de5a28srs // Check for valid CRCs and warn if there are problems 885e7b4ff9317fc4e551cf974684eaa88697de5a28srs if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) || 886e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs (secondPartsCrcOk == 0)) { 887fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! One or more CRCs don't match. You should repair the disk!\n\n"; 888e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs state = gpt_corrupt; 889ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } // if 890e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 891e7b4ff9317fc4e551cf974684eaa88697de5a28srs state = gpt_invalid; 892e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 893e7b4ff9317fc4e551cf974684eaa88697de5a28srs return allOK; 894e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::ForceLoadGPTData() 895e7b4ff9317fc4e551cf974684eaa88697de5a28srs 896247657a5acbb7eb21c336ba84a68b801b7c19be0srs// Loads the partition table pointed to by the main GPT header. The 897e7b4ff9317fc4e551cf974684eaa88697de5a28srs// main GPT header in memory MUST be valid for this call to do anything 898e7b4ff9317fc4e551cf974684eaa88697de5a28srs// sensible! 899546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. 900e7b4ff9317fc4e551cf974684eaa88697de5a28srsint GPTData::LoadMainTable(void) { 901cb76c673eeb84344887715d36d44b799042be5a5srs return LoadPartitionTable(mainHeader, myDisk); 902e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // GPTData::LoadMainTable() 903e7b4ff9317fc4e551cf974684eaa88697de5a28srs 904e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Load the second (backup) partition table as the primary partition 905546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// table. Used in repair functions, and when starting up if the main 906546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// partition table is damaged. 907546a9c7c369df465021feecb20f6a8f81b6df6bcsrs// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. 908546a9c7c369df465021feecb20f6a8f81b6df6bcsrsint GPTData::LoadSecondTableAsMain(void) { 909cb76c673eeb84344887715d36d44b799042be5a5srs return LoadPartitionTable(secondHeader, myDisk); 910cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::LoadSecondTableAsMain() 911cb76c673eeb84344887715d36d44b799042be5a5srs 912cb76c673eeb84344887715d36d44b799042be5a5srs// Load a single GPT header (main or backup) from the specified disk device and 913cb76c673eeb84344887715d36d44b799042be5a5srs// sector. Applies byte-order corrections on big-endian platforms. Sets crcOk 914cb76c673eeb84344887715d36d44b799042be5a5srs// value appropriately. 915cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure. Note that CRC errors do NOT qualify as 916cb76c673eeb84344887715d36d44b799042be5a5srs// failure. 917cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::LoadHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector, int *crcOk) { 918cb76c673eeb84344887715d36d44b799042be5a5srs int allOK = 1; 9191c6f8b013e7f5c166abf21c09e319d22b576c41asrs GPTHeader tempHeader; 920cb76c673eeb84344887715d36d44b799042be5a5srs 921cb76c673eeb84344887715d36d44b799042be5a5srs disk.Seek(sector); 9221c6f8b013e7f5c166abf21c09e319d22b576c41asrs if (disk.Read(&tempHeader, 512) != 512) { 923cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; 924cb76c673eeb84344887715d36d44b799042be5a5srs allOK = 0; 925cb76c673eeb84344887715d36d44b799042be5a5srs } // if 926cb76c673eeb84344887715d36d44b799042be5a5srs 9271c6f8b013e7f5c166abf21c09e319d22b576c41asrs // Reverse byte order, if necessary 928cb76c673eeb84344887715d36d44b799042be5a5srs if (IsLittleEndian() == 0) { 92955d926192adc984462509b2966e23bc0d1129bbdsrs ReverseHeaderBytes(&tempHeader); 930cb76c673eeb84344887715d36d44b799042be5a5srs } // if 931d1b11e8305621d73ff675af940e7f1f28b639b0dsrs *crcOk = CheckHeaderCRC(&tempHeader); 9321c6f8b013e7f5c166abf21c09e319d22b576c41asrs 9330283dae41a7db4563be0fe62241ed230e4a101c0srs if (allOK && (numParts != tempHeader.numParts) && *crcOk) { 934706e51217a531c46afc743b556e10fd5c0585fcfsrs allOK = SetGPTSize(tempHeader.numParts, 0); 93555d926192adc984462509b2966e23bc0d1129bbdsrs } 9361c6f8b013e7f5c166abf21c09e319d22b576c41asrs 9371c6f8b013e7f5c166abf21c09e319d22b576c41asrs *header = tempHeader; 938cb76c673eeb84344887715d36d44b799042be5a5srs return allOK; 939cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::LoadHeader 940cb76c673eeb84344887715d36d44b799042be5a5srs 941cb76c673eeb84344887715d36d44b799042be5a5srs// Load a partition table (either main or secondary) from the specified disk, 942cb76c673eeb84344887715d36d44b799042be5a5srs// using header as a reference for what to load. If sector != 0 (the default 943cb76c673eeb84344887715d36d44b799042be5a5srs// is 0), loads from the specified sector; otherwise loads from the sector 944cb76c673eeb84344887715d36d44b799042be5a5srs// indicated in header. 945cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. 946cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::LoadPartitionTable(const struct GPTHeader & header, DiskIO & disk, uint64_t sector) { 947e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t sizeOfParts, newCRC; 948cb76c673eeb84344887715d36d44b799042be5a5srs int retval; 949e7b4ff9317fc4e551cf974684eaa88697de5a28srs 950cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.OpenForRead()) { 951cb76c673eeb84344887715d36d44b799042be5a5srs if (sector == 0) { 952cb76c673eeb84344887715d36d44b799042be5a5srs retval = disk.Seek(header.partitionEntriesLBA); 953cb76c673eeb84344887715d36d44b799042be5a5srs } else { 954cb76c673eeb84344887715d36d44b799042be5a5srs retval = disk.Seek(sector); 955cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 95655d926192adc984462509b2966e23bc0d1129bbdsrs if (retval == 1) 957706e51217a531c46afc743b556e10fd5c0585fcfsrs retval = SetGPTSize(header.numParts, 0); 958546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (retval == 1) { 959cb76c673eeb84344887715d36d44b799042be5a5srs sizeOfParts = header.numParts * header.sizeOfPartitionEntries; 960cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Read(partitions, sizeOfParts) != (int) sizeOfParts) { 961fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n"; 962546a9c7c369df465021feecb20f6a8f81b6df6bcsrs retval = 0; 9635d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 964e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); 965cb76c673eeb84344887715d36d44b799042be5a5srs mainPartsCrcOk = secondPartsCrcOk = (newCRC == header.partitionEntriesCRC); 966e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (IsLittleEndian() == 0) 967e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ReversePartitionBytes(); 968cb76c673eeb84344887715d36d44b799042be5a5srs if (!mainPartsCrcOk) { 969cb76c673eeb84344887715d36d44b799042be5a5srs cout << "Caution! After loading partitions, the CRC doesn't check out!\n"; 970e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 971e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 972cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Error! Couldn't seek to partition table!\n"; 973e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 974e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 975fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Error! Couldn't open device " << device 976cb76c673eeb84344887715d36d44b799042be5a5srs << " when reading partition table!\n"; 977546a9c7c369df465021feecb20f6a8f81b6df6bcsrs retval = 0; 978e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 979546a9c7c369df465021feecb20f6a8f81b6df6bcsrs return retval; 980cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::LoadPartitionsTable() 981cb76c673eeb84344887715d36d44b799042be5a5srs 982cb76c673eeb84344887715d36d44b799042be5a5srs// Check the partition table pointed to by header, but don't keep it 983cb76c673eeb84344887715d36d44b799042be5a5srs// around. 984a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Returns 1 if the CRC is OK & this table matches the one already in memory, 985a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// 0 if not or if there was a read error. 986cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::CheckTable(struct GPTHeader *header) { 987cb76c673eeb84344887715d36d44b799042be5a5srs uint32_t sizeOfParts, newCRC; 988a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs GPTPart *partsToCheck; 989d1b11e8305621d73ff675af940e7f1f28b639b0dsrs GPTHeader *otherHeader; 990a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs int allOK = 0; 991cb76c673eeb84344887715d36d44b799042be5a5srs 9920283dae41a7db4563be0fe62241ed230e4a101c0srs // Load partition table into temporary storage to check 993cb76c673eeb84344887715d36d44b799042be5a5srs // its CRC and store the results, then discard this temporary 994cb76c673eeb84344887715d36d44b799042be5a5srs // storage, since we don't use it in any but recovery operations 995cb76c673eeb84344887715d36d44b799042be5a5srs if (myDisk.Seek(header->partitionEntriesLBA)) { 996a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs partsToCheck = new GPTPart[header->numParts]; 9970283dae41a7db4563be0fe62241ed230e4a101c0srs sizeOfParts = header->numParts * header->sizeOfPartitionEntries; 998a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (partsToCheck == NULL) { 9996aae2a9b70e9f88926baad94c1eea40e0b534f01srs cerr << "Could not allocate memory in GPTData::CheckTable()! Terminating!\n"; 10006aae2a9b70e9f88926baad94c1eea40e0b534f01srs exit(1); 10016aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 1002a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs if (myDisk.Read(partsToCheck, sizeOfParts) != (int) sizeOfParts) { 10030283dae41a7db4563be0fe62241ed230e4a101c0srs cerr << "Warning! Error " << errno << " reading partition table for CRC check!\n"; 1004cb76c673eeb84344887715d36d44b799042be5a5srs } else { 1005d1b11e8305621d73ff675af940e7f1f28b639b0dsrs newCRC = chksum_crc32((unsigned char*) partsToCheck, sizeOfParts); 1006a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs allOK = (newCRC == header->partitionEntriesCRC); 1007d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (header == &mainHeader) 1008d1b11e8305621d73ff675af940e7f1f28b639b0dsrs otherHeader = &secondHeader; 1009d1b11e8305621d73ff675af940e7f1f28b639b0dsrs else 1010d1b11e8305621d73ff675af940e7f1f28b639b0dsrs otherHeader = &mainHeader; 1011d1b11e8305621d73ff675af940e7f1f28b639b0dsrs if (newCRC != otherHeader->partitionEntriesCRC) { 1012a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs cerr << "Warning! Main and backup partition tables differ! Use the 'c' and 'e' options\n" 1013a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs << "on the recovery & transformation menu to examine the two tables.\n\n"; 1014a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs allOK = 0; 1015a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs } // if 1016cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 1017a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs delete[] partsToCheck; 1018cb76c673eeb84344887715d36d44b799042be5a5srs } // if 1019a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs return allOK; 1020cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::CheckTable() 1021e7b4ff9317fc4e551cf974684eaa88697de5a28srs 10224307ef2e863cbec357df56197046c6b679fc5d2dsrs// Writes GPT (and protective MBR) to disk. If quiet==1, moves the second 10234307ef2e863cbec357df56197046c6b679fc5d2dsrs// header later on the disk without asking for permission, if necessary, and 10244307ef2e863cbec357df56197046c6b679fc5d2dsrs// doesn't confirm the operation before writing. If quiet==0, asks permission 10254307ef2e863cbec357df56197046c6b679fc5d2dsrs// before moving the second header and asks for final confirmation of any 10264307ef2e863cbec357df56197046c6b679fc5d2dsrs// write. 1027a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Returns 1 on successful write, 0 if there was a problem. 102864cbd171067eb34054741bfcd73f0b91d727a371srsint GPTData::SaveGPTData(int quiet) { 10294307ef2e863cbec357df56197046c6b679fc5d2dsrs int allOK = 1, syncIt = 1; 1030e321d444dcca514cf6b53459e388ddcbaab6176csrs char answer; 10312a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1032e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // First do some final sanity checks.... 10335d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs 10345d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs // This test should only fail on read-only disks.... 10355d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (justLooking) { 1036fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The justLooking flag is set. This probably means you can't write to the disk.\n"; 10375d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs allOK = 0; 10385d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 10395d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs 104064cbd171067eb34054741bfcd73f0b91d727a371srs // Check that disk is really big enough to handle the second header... 104164cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.backupLBA >= diskSize) { 104264cbd171067eb34054741bfcd73f0b91d727a371srs cerr << "Caution! Secondary header was placed beyond the disk's limits! Moving the\n" 104364cbd171067eb34054741bfcd73f0b91d727a371srs << "header, but other problems may occur!\n"; 104464cbd171067eb34054741bfcd73f0b91d727a371srs MoveSecondHeaderToEnd(); 104564cbd171067eb34054741bfcd73f0b91d727a371srs } // if 104664cbd171067eb34054741bfcd73f0b91d727a371srs 1047e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Is there enough space to hold the GPT headers and partition tables, 1048e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // given the partition sizes? 1049e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (CheckGPTSize() > 0) { 1050e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 10512a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 1052e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1053247657a5acbb7eb21c336ba84a68b801b7c19be0srs // Check that second header is properly placed. Warn and ask if this should 1054247657a5acbb7eb21c336ba84a68b801b7c19be0srs // be corrected if the test fails.... 105564cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) { 105664cbd171067eb34054741bfcd73f0b91d727a371srs if (quiet == 0) { 105764cbd171067eb34054741bfcd73f0b91d727a371srs cout << "Warning! Secondary header is placed too early on the disk! Do you want to\n" 105864cbd171067eb34054741bfcd73f0b91d727a371srs << "correct this problem? "; 105964cbd171067eb34054741bfcd73f0b91d727a371srs if (GetYN() == 'Y') { 106064cbd171067eb34054741bfcd73f0b91d727a371srs MoveSecondHeaderToEnd(); 106164cbd171067eb34054741bfcd73f0b91d727a371srs cout << "Have moved second header and partition table to correct location.\n"; 106264cbd171067eb34054741bfcd73f0b91d727a371srs } else { 106364cbd171067eb34054741bfcd73f0b91d727a371srs cout << "Have not corrected the problem. Strange problems may occur in the future!\n"; 106464cbd171067eb34054741bfcd73f0b91d727a371srs } // if correction requested 106564cbd171067eb34054741bfcd73f0b91d727a371srs } else { // Go ahead and do correction automatically 1066247657a5acbb7eb21c336ba84a68b801b7c19be0srs MoveSecondHeaderToEnd(); 106764cbd171067eb34054741bfcd73f0b91d727a371srs } // if/else quiet 1068247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if 1069e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1070d8eed4629449a325999808a0170dbda53bd4a6dfsrs if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) { 1071d8eed4629449a325999808a0170dbda53bd4a6dfsrs if (quiet == 0) { 1072d8eed4629449a325999808a0170dbda53bd4a6dfsrs cout << "Warning! The claimed last usable sector is incorrect! Do you want to correct\n" 1073d8eed4629449a325999808a0170dbda53bd4a6dfsrs << "this problem? "; 1074d8eed4629449a325999808a0170dbda53bd4a6dfsrs if (GetYN() == 'Y') { 1075d8eed4629449a325999808a0170dbda53bd4a6dfsrs MoveSecondHeaderToEnd(); 1076d8eed4629449a325999808a0170dbda53bd4a6dfsrs cout << "Have adjusted the second header and last usable sector value.\n"; 1077d8eed4629449a325999808a0170dbda53bd4a6dfsrs } else { 1078d8eed4629449a325999808a0170dbda53bd4a6dfsrs cout << "Have not corrected the problem. Strange problems may occur in the future!\n"; 1079d8eed4629449a325999808a0170dbda53bd4a6dfsrs } // if correction requested 1080d8eed4629449a325999808a0170dbda53bd4a6dfsrs } else { // go ahead and do correction automatically 1081d8eed4629449a325999808a0170dbda53bd4a6dfsrs MoveSecondHeaderToEnd(); 1082d8eed4629449a325999808a0170dbda53bd4a6dfsrs } // if/else quiet 1083d8eed4629449a325999808a0170dbda53bd4a6dfsrs } // if 1084d8eed4629449a325999808a0170dbda53bd4a6dfsrs 108555d926192adc984462509b2966e23bc0d1129bbdsrs // Check for overlapping or insane partitions.... 108655d926192adc984462509b2966e23bc0d1129bbdsrs if ((FindOverlaps() > 0) || (FindInsanePartitions() > 0)) { 1087e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1088fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Aborting write operation!\n"; 1089e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1090e7b4ff9317fc4e551cf974684eaa88697de5a28srs 10914a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith // Check that protective MBR fits, and warn if it doesn't.... 10924a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith if (!protectiveMBR.DoTheyFit()) { 10934a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith cerr << "\nPartition(s) in the protective MBR are too big for the disk! Creating a\n" 10944a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith << "fresh protective or hybrid MBR is recommended.\n"; 10954a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith } 10964a702a2e26420e14592cba64701d85ec9f1f70dcRoderick W. Smith 1097e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Check for mismatched MBR and GPT data, but let it pass if found 1098e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // (function displays warning message) 1099e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs FindHybridMismatches(); 1100e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1101e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs RecomputeCRCs(); 1102e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1103ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if ((allOK) && (!quiet)) { 1104fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n" 1105bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs << "PARTITIONS!!\n\nDo you want to proceed? "; 11065d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs answer = GetYN(); 11075d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (answer == 'Y') { 11083488294d718a0e8b7f312c80c9e5729671173f6asrs cout << "OK; writing new GUID partition table (GPT) to " << myDisk.GetName() << ".\n"; 1109e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1110e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1111e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1112e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1113e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1114e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Do it! 1115e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) { 111664cbd171067eb34054741bfcd73f0b91d727a371srs if (myDisk.OpenForWrite()) { 11178a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // As per UEFI specs, write the secondary table and GPT first.... 1118cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SavePartitionTable(myDisk, secondHeader.partitionEntriesLBA); 11194307ef2e863cbec357df56197046c6b679fc5d2dsrs if (!allOK) { 1120cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Unable to save backup partition table! Perhaps the 'e' option on the experts'\n" 1121cb76c673eeb84344887715d36d44b799042be5a5srs << "menu will resolve this problem.\n"; 11224307ef2e863cbec357df56197046c6b679fc5d2dsrs syncIt = 0; 11234307ef2e863cbec357df56197046c6b679fc5d2dsrs } // if 1124e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1125e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now write the secondary GPT header... 11268a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && SaveHeader(&secondHeader, myDisk, mainHeader.backupLBA); 11278a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 11288a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // Now write the main partition tables... 11298a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && SavePartitionTable(myDisk, mainHeader.partitionEntriesLBA); 11308a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 11318a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // Now write the main GPT header... 11328a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && SaveHeader(&mainHeader, myDisk, 1); 11338a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 11348a4ddfc919d5569c68489cf53d9cf5abc94c410csrs // To top it off, write the protective MBR... 11358a4ddfc919d5569c68489cf53d9cf5abc94c410csrs allOK = allOK && protectiveMBR.WriteMBRData(&myDisk); 1136e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1137e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // re-read the partition table 11384307ef2e863cbec357df56197046c6b679fc5d2dsrs // Note: Done even if some write operations failed, but not if all of them failed. 11394307ef2e863cbec357df56197046c6b679fc5d2dsrs // Done this way because I've received one problem report from a user one whose 11404307ef2e863cbec357df56197046c6b679fc5d2dsrs // system the MBR write failed but everything else was OK (on a GPT disk under 11414307ef2e863cbec357df56197046c6b679fc5d2dsrs // Windows), and the failure to sync therefore caused Windows to restore the 11424307ef2e863cbec357df56197046c6b679fc5d2dsrs // original partition table from its cache. OTOH, such restoration might be 11434307ef2e863cbec357df56197046c6b679fc5d2dsrs // desirable if the error occurs later; but that seems unlikely unless the initial 11444307ef2e863cbec357df56197046c6b679fc5d2dsrs // write fails.... 11454307ef2e863cbec357df56197046c6b679fc5d2dsrs if (syncIt) 1146546a9c7c369df465021feecb20f6a8f81b6df6bcsrs myDisk.DiskSync(); 1147e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1148e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) { // writes completed OK 1149fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The operation has completed successfully.\n"; 1150e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1151fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! An error was reported when writing the partition table! This error\n" 11524307ef2e863cbec357df56197046c6b679fc5d2dsrs << "MIGHT be harmless, or the disk might be damaged! Checking it is advisable.\n"; 1153e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 11548a4ddfc919d5569c68489cf53d9cf5abc94c410csrs 1155546a9c7c369df465021feecb20f6a8f81b6df6bcsrs myDisk.Close(); 1156e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 11575a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Unable to open device '" << myDisk.GetName() << "' for writing! Errno is " 1158fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << errno << "! Aborting write!\n"; 1159e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1160e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1161e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 1162fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Aborting write of new partition table.\n"; 1163e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 1164e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1165e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (allOK); 1166e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SaveGPTData() 1167e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1168e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Save GPT data to a backup file. This function does much less error 1169e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// checking than SaveGPTData(). It can therefore preserve many types of 1170e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// corruption for later analysis; however, it preserves only the MBR, 1171e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// the main GPT header, the backup GPT header, and the main partition 1172e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// table; it discards the backup partition table, since it should be 1173e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// identical to the main partition table on healthy disks. 11740a6973119c9e9984ad47a6da3231e8d16f996c5csrsint GPTData::SaveGPTBackup(const string & filename) { 11750a6973119c9e9984ad47a6da3231e8d16f996c5csrs int allOK = 1; 1176546a9c7c369df465021feecb20f6a8f81b6df6bcsrs DiskIO backupFile; 1177e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1178546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (backupFile.OpenForWrite(filename)) { 11796699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // Recomputing the CRCs is likely to alter them, which could be bad 11806699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // if the intent is to save a potentially bad GPT for later analysis; 11816699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // but if we don't do this, we get bogus errors when we load the 11826699b01eda84d24bfaf80ad725304fef2b0e1b2asrs // backup. I'm favoring misses over false alarms.... 11836699b01eda84d24bfaf80ad725304fef2b0e1b2asrs RecomputeCRCs(); 11846699b01eda84d24bfaf80ad725304fef2b0e1b2asrs 1185546a9c7c369df465021feecb20f6a8f81b6df6bcsrs protectiveMBR.WriteMBRData(&backupFile); 1186699941e25a1fcf0beec124203747c8ed20842989srs protectiveMBR.SetDisk(&myDisk); 1187e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1188cb76c673eeb84344887715d36d44b799042be5a5srs if (allOK) { 1189546a9c7c369df465021feecb20f6a8f81b6df6bcsrs // MBR write closed disk, so re-open and seek to end.... 1190546a9c7c369df465021feecb20f6a8f81b6df6bcsrs backupFile.OpenForWrite(); 1191cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SaveHeader(&mainHeader, backupFile, 1); 1192cb76c673eeb84344887715d36d44b799042be5a5srs } // if (allOK) 1193e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1194e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) 1195cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SaveHeader(&secondHeader, backupFile, 2); 1196e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1197cb76c673eeb84344887715d36d44b799042be5a5srs if (allOK) 1198cb76c673eeb84344887715d36d44b799042be5a5srs allOK = SavePartitionTable(backupFile, 3); 1199e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1200e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (allOK) { // writes completed OK 1201fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The operation has completed successfully.\n"; 1202e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1203fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Warning! An error was reported when writing the backup file.\n" 1204fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "It may not be usable!\n"; 1205e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1206546a9c7c369df465021feecb20f6a8f81b6df6bcsrs backupFile.Close(); 1207e7b4ff9317fc4e551cf974684eaa88697de5a28srs } else { 12085a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Unable to open file '" << filename << "' for writing! Aborting!\n"; 1209e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1210e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if/else 1211e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return allOK; 1212e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SaveGPTBackup() 1213e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1214cb76c673eeb84344887715d36d44b799042be5a5srs// Write a GPT header (main or backup) to the specified sector. Used by both 1215cb76c673eeb84344887715d36d44b799042be5a5srs// the SaveGPTData() and SaveGPTBackup() functions. 1216cb76c673eeb84344887715d36d44b799042be5a5srs// Should be passed an architecture-appropriate header (DO NOT call 1217cb76c673eeb84344887715d36d44b799042be5a5srs// ReverseHeaderBytes() on the header before calling this function) 1218cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure 1219cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::SaveHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector) { 1220cb76c673eeb84344887715d36d44b799042be5a5srs int littleEndian, allOK = 1; 1221cb76c673eeb84344887715d36d44b799042be5a5srs 1222cb76c673eeb84344887715d36d44b799042be5a5srs littleEndian = IsLittleEndian(); 1223cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1224cb76c673eeb84344887715d36d44b799042be5a5srs ReverseHeaderBytes(header); 1225cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Seek(sector)) { 1226cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Write(header, 512) == -1) 1227cb76c673eeb84344887715d36d44b799042be5a5srs allOK = 0; 1228cb76c673eeb84344887715d36d44b799042be5a5srs } else allOK = 0; // if (disk.Seek()...) 1229cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1230cb76c673eeb84344887715d36d44b799042be5a5srs ReverseHeaderBytes(header); 1231cb76c673eeb84344887715d36d44b799042be5a5srs return allOK; 1232cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::SaveHeader() 1233cb76c673eeb84344887715d36d44b799042be5a5srs 1234cb76c673eeb84344887715d36d44b799042be5a5srs// Save the partitions to the specified sector. Used by both the SaveGPTData() 1235cb76c673eeb84344887715d36d44b799042be5a5srs// and SaveGPTBackup() functions. 1236cb76c673eeb84344887715d36d44b799042be5a5srs// Should be passed an architecture-appropriate header (DO NOT call 1237cb76c673eeb84344887715d36d44b799042be5a5srs// ReverseHeaderBytes() on the header before calling this function) 1238cb76c673eeb84344887715d36d44b799042be5a5srs// Returns 1 on success, 0 on failure 1239cb76c673eeb84344887715d36d44b799042be5a5srsint GPTData::SavePartitionTable(DiskIO & disk, uint64_t sector) { 1240cb76c673eeb84344887715d36d44b799042be5a5srs int littleEndian, allOK = 1; 1241cb76c673eeb84344887715d36d44b799042be5a5srs 1242cb76c673eeb84344887715d36d44b799042be5a5srs littleEndian = IsLittleEndian(); 1243cb76c673eeb84344887715d36d44b799042be5a5srs if (disk.Seek(sector)) { 1244cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1245cb76c673eeb84344887715d36d44b799042be5a5srs ReversePartitionBytes(); 12460283dae41a7db4563be0fe62241ed230e4a101c0srs if (disk.Write(partitions, mainHeader.sizeOfPartitionEntries * numParts) == -1) 1247cb76c673eeb84344887715d36d44b799042be5a5srs allOK = 0; 1248cb76c673eeb84344887715d36d44b799042be5a5srs if (!littleEndian) 1249cb76c673eeb84344887715d36d44b799042be5a5srs ReversePartitionBytes(); 1250cb76c673eeb84344887715d36d44b799042be5a5srs } else allOK = 0; // if (myDisk.Seek()...) 1251cb76c673eeb84344887715d36d44b799042be5a5srs return allOK; 1252cb76c673eeb84344887715d36d44b799042be5a5srs} // GPTData::SavePartitionTable() 1253cb76c673eeb84344887715d36d44b799042be5a5srs 1254e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Load GPT data from a backup file created by SaveGPTBackup(). This function 1255e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// does minimal error checking. It returns 1 if it completed successfully, 1256e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// 0 if there was a problem. In the latter case, it creates a new empty 1257e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// set of partitions. 12580a6973119c9e9984ad47a6da3231e8d16f996c5csrsint GPTData::LoadGPTBackup(const string & filename) { 1259cb76c673eeb84344887715d36d44b799042be5a5srs int allOK = 1, val, err; 12600541b56fee4e92822340a2b2387508dd58d0ca7csrs int shortBackup = 0; 1261546a9c7c369df465021feecb20f6a8f81b6df6bcsrs DiskIO backupFile; 1262e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1263546a9c7c369df465021feecb20f6a8f81b6df6bcsrs if (backupFile.OpenForRead(filename)) { 1264e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Let the MBRData class load the saved MBR... 1265546a9c7c369df465021feecb20f6a8f81b6df6bcsrs protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size 1266815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs protectiveMBR.SetDisk(&myDisk); 1267e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1268cb76c673eeb84344887715d36d44b799042be5a5srs LoadHeader(&mainHeader, backupFile, 1, &mainCrcOk); 1269e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1270cb76c673eeb84344887715d36d44b799042be5a5srs // Check backup file size and rebuild second header if file is right 1271cb76c673eeb84344887715d36d44b799042be5a5srs // size to be direct dd copy of MBR, main header, and main partition 1272cb76c673eeb84344887715d36d44b799042be5a5srs // table; if other size, treat it like a GPT fdisk-generated backup 1273cb76c673eeb84344887715d36d44b799042be5a5srs // file 1274cb76c673eeb84344887715d36d44b799042be5a5srs shortBackup = ((backupFile.DiskSize(&err) * backupFile.GetBlockSize()) == 1275cb76c673eeb84344887715d36d44b799042be5a5srs (mainHeader.numParts * mainHeader.sizeOfPartitionEntries) + 1024); 1276cb76c673eeb84344887715d36d44b799042be5a5srs if (shortBackup) { 1277cb76c673eeb84344887715d36d44b799042be5a5srs RebuildSecondHeader(); 1278cb76c673eeb84344887715d36d44b799042be5a5srs secondCrcOk = mainCrcOk; 1279cb76c673eeb84344887715d36d44b799042be5a5srs } else { 1280cb76c673eeb84344887715d36d44b799042be5a5srs LoadHeader(&secondHeader, backupFile, 2, &secondCrcOk); 1281cb76c673eeb84344887715d36d44b799042be5a5srs } // if/else 1282e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1283e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Return valid headers code: 0 = both headers bad; 1 = main header 1284e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // good, backup bad; 2 = backup header good, main header bad; 1285e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // 3 = both headers good. Note these codes refer to valid GPT 1286e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // signatures and version numbers; more subtle problems will elude 1287e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // this check! 1288e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((val = CheckHeaderValidity()) > 0) { 1289e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (val == 2) { // only backup header seems to be good 1290706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(secondHeader.numParts, 0); 1291e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { // main header is OK 1292706e51217a531c46afc743b556e10fd5c0585fcfsrs SetGPTSize(mainHeader.numParts, 0); 1293e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1294e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1295e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (secondHeader.currentLBA != diskSize - UINT64_C(1)) { 1296fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Warning! Current disk size doesn't match that of the backup!\n" 1297fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "Adjusting sizes to match, but subsequent problems are possible!\n"; 1298247657a5acbb7eb21c336ba84a68b801b7c19be0srs MoveSecondHeaderToEnd(); 1299e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1300e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1301cb76c673eeb84344887715d36d44b799042be5a5srs if (!LoadPartitionTable(mainHeader, backupFile, (uint64_t) (3 - shortBackup))) 1302cb76c673eeb84344887715d36d44b799042be5a5srs cerr << "Warning! Read error " << errno 1303cb76c673eeb84344887715d36d44b799042be5a5srs << " loading partition table; strange behavior now likely!\n"; 1304e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1305e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 1306e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1307a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs // Something went badly wrong, so blank out partitions 1308a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs if (allOK == 0) { 1309a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs cerr << "Improper backup file! Clearing all partition data!\n"; 1310a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs ClearGPTData(); 1311a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs protectiveMBR.MakeProtectiveMBR(); 1312a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // if 1313e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 1314e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs allOK = 0; 13155a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Unable to open file '" << filename << "' for reading! Aborting!\n"; 1316e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 1317e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1318e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return allOK; 1319e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::LoadGPTBackup() 1320e7b4ff9317fc4e551cf974684eaa88697de5a28srs 132108bb0da07953af605b4918e268272de15ac151aasrsint GPTData::SaveMBR(void) { 132255d926192adc984462509b2966e23bc0d1129bbdsrs return protectiveMBR.WriteMBRData(&myDisk); 132308bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::SaveMBR() 132408bb0da07953af605b4918e268272de15ac151aasrs 132508bb0da07953af605b4918e268272de15ac151aasrs// This function destroys the on-disk GPT structures, but NOT the on-disk 132608bb0da07953af605b4918e268272de15ac151aasrs// MBR. 132708bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if the operation succeeds, 0 if not. 132808bb0da07953af605b4918e268272de15ac151aasrsint GPTData::DestroyGPT(void) { 132901f7f08624f0c942001977415214a578621f6495srs int sum, tableSize, allOK = 1; 133008bb0da07953af605b4918e268272de15ac151aasrs uint8_t blankSector[512]; 133108bb0da07953af605b4918e268272de15ac151aasrs uint8_t* emptyTable; 133208bb0da07953af605b4918e268272de15ac151aasrs 133301f7f08624f0c942001977415214a578621f6495srs memset(blankSector, 0, sizeof(blankSector)); 133484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith ClearGPTData(); 133508bb0da07953af605b4918e268272de15ac151aasrs 133608bb0da07953af605b4918e268272de15ac151aasrs if (myDisk.OpenForWrite()) { 133708bb0da07953af605b4918e268272de15ac151aasrs if (!myDisk.Seek(mainHeader.currentLBA)) 133808bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 133908bb0da07953af605b4918e268272de15ac151aasrs if (myDisk.Write(blankSector, 512) != 512) { // blank it out 134008bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! GPT main header not overwritten! Error is " << errno << "\n"; 134108bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 134208bb0da07953af605b4918e268272de15ac151aasrs } // if 134308bb0da07953af605b4918e268272de15ac151aasrs if (!myDisk.Seek(mainHeader.partitionEntriesLBA)) 134408bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 13450283dae41a7db4563be0fe62241ed230e4a101c0srs tableSize = numParts * mainHeader.sizeOfPartitionEntries; 134608bb0da07953af605b4918e268272de15ac151aasrs emptyTable = new uint8_t[tableSize]; 13476aae2a9b70e9f88926baad94c1eea40e0b534f01srs if (emptyTable == NULL) { 134884aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "Could not allocate memory in GPTData::DestroyGPT()! Terminating!\n"; 134984aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith exit(1); 13506aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 135101f7f08624f0c942001977415214a578621f6495srs memset(emptyTable, 0, tableSize); 135208bb0da07953af605b4918e268272de15ac151aasrs if (allOK) { 135308bb0da07953af605b4918e268272de15ac151aasrs sum = myDisk.Write(emptyTable, tableSize); 135408bb0da07953af605b4918e268272de15ac151aasrs if (sum != tableSize) { 135508bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n"; 135608bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 135708bb0da07953af605b4918e268272de15ac151aasrs } // if write failed 135884aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if 135984aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (!myDisk.Seek(secondHeader.partitionEntriesLBA)) 136084aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith allOK = 0; 136184aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (allOK) { 136284aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith sum = myDisk.Write(emptyTable, tableSize); 136384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (sum != tableSize) { 136484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "Warning! GPT backup partition table not overwritten! Error is " 136584aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith << errno << "\n"; 136608bb0da07953af605b4918e268272de15ac151aasrs allOK = 0; 136784aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if wrong size written 136884aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if 136984aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (!myDisk.Seek(secondHeader.currentLBA)) 137084aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith allOK = 0; 137184aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (allOK) { 137284aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith if (myDisk.Write(blankSector, 512) != 512) { // blank it out 137384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "Warning! GPT backup header not overwritten! Error is " << errno << "\n"; 13745435fcf5c47caf8c77034f7a277642d1e23e90f8Roderick W. Smith allOK = 0; 13755435fcf5c47caf8c77034f7a277642d1e23e90f8Roderick W. Smith } // if 137684aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith } // if 137708bb0da07953af605b4918e268272de15ac151aasrs myDisk.DiskSync(); 137808bb0da07953af605b4918e268272de15ac151aasrs myDisk.Close(); 137908bb0da07953af605b4918e268272de15ac151aasrs cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n" 138008bb0da07953af605b4918e268272de15ac151aasrs << "other utilities.\n"; 138108bb0da07953af605b4918e268272de15ac151aasrs delete[] emptyTable; 138208bb0da07953af605b4918e268272de15ac151aasrs } else { 13835a6085310b7f8fe1c35e56bcab7de161808b488dsrs cerr << "Problem opening '" << device << "' for writing! Program will now terminate.\n"; 138408bb0da07953af605b4918e268272de15ac151aasrs } // if/else (fd != -1) 138508bb0da07953af605b4918e268272de15ac151aasrs return (allOK); 138608bb0da07953af605b4918e268272de15ac151aasrs} // GPTDataTextUI::DestroyGPT() 138708bb0da07953af605b4918e268272de15ac151aasrs 138808bb0da07953af605b4918e268272de15ac151aasrs// Wipe MBR data from the disk (zero it out completely) 138908bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 on success, 0 on failure. 139008bb0da07953af605b4918e268272de15ac151aasrsint GPTData::DestroyMBR(void) { 139101f7f08624f0c942001977415214a578621f6495srs int allOK; 139208bb0da07953af605b4918e268272de15ac151aasrs uint8_t blankSector[512]; 139308bb0da07953af605b4918e268272de15ac151aasrs 139401f7f08624f0c942001977415214a578621f6495srs memset(blankSector, 0, sizeof(blankSector)); 139501f7f08624f0c942001977415214a578621f6495srs 139601f7f08624f0c942001977415214a578621f6495srs allOK = myDisk.OpenForWrite() && myDisk.Seek(0) && (myDisk.Write(blankSector, 512) == 512); 139708bb0da07953af605b4918e268272de15ac151aasrs 139808bb0da07953af605b4918e268272de15ac151aasrs if (!allOK) 139908bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! MBR not overwritten! Error is " << errno << "!\n"; 140008bb0da07953af605b4918e268272de15ac151aasrs return allOK; 140108bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::DestroyMBR(void) 140208bb0da07953af605b4918e268272de15ac151aasrs 1403e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Tell user whether Apple Partition Map (APM) was discovered.... 1404e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::ShowAPMState(void) { 1405e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (apmFound) 1406fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " APM: present\n"; 1407e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs else 1408fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " APM: not present\n"; 1409e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ShowAPMState() 1410e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1411e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Tell user about the state of the GPT data.... 1412e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::ShowGPTState(void) { 1413e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs switch (state) { 1414e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case gpt_invalid: 1415fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " GPT: not present\n"; 1416e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1417e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case gpt_valid: 1418fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " GPT: present\n"; 1419e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1420e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs case gpt_corrupt: 1421fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << " GPT: damaged\n"; 1422e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1423e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs default: 1424fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\a GPT: unknown -- bug!\n"; 1425e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs break; 1426e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // switch 1427e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ShowGPTState() 1428e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1429e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Display the basic GPT data 1430e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::DisplayGPTData(void) { 1431e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i; 1432e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t temp, totalFree; 1433e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1434fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Disk " << device << ": " << diskSize << " sectors, " 143501f7f08624f0c942001977415214a578621f6495srs << BytesToIeee(diskSize, blockSize) << "\n"; 1436fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Logical sector size: " << blockSize << " bytes\n"; 14375a081757ea2e32a491349544fea92826ccf739f6srs cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n"; 14380283dae41a7db4563be0fe62241ed230e4a101c0srs cout << "Partition table holds up to " << numParts << " entries\n"; 1439fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "First usable sector is " << mainHeader.firstUsableLBA 1440fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ", last usable sector is " << mainHeader.lastUsableLBA << "\n"; 1441e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs totalFree = FindFreeBlocks(&i, &temp); 14428a4ddfc919d5569c68489cf53d9cf5abc94c410csrs cout << "Partitions will be aligned on " << sectorAlignment << "-sector boundaries\n"; 1443fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Total free space is " << totalFree << " sectors (" 144401f7f08624f0c942001977415214a578621f6495srs << BytesToIeee(totalFree, blockSize) << ")\n"; 1445fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\nNumber Start (sector) End (sector) Size Code Name\n"; 14460283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 1447978041ca613dcb881763b36cf53639d924e52a56srs partitions[i].ShowSummary(i, blockSize); 1448e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // for 1449e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::DisplayGPTData() 1450e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1451e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Show detailed information on the specified partition 1452d761ff5a2aac9d9b6bd0bc8236419b1cf0128c86Jeff Sharkeyvoid GPTData::ShowPartDetails(uint32_t partNum) { 145324bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if ((partNum < numParts) && !IsFreePartNum(partNum)) { 1454d761ff5a2aac9d9b6bd0bc8236419b1cf0128c86Jeff Sharkey partitions[partNum].ShowDetails(blockSize); 1455e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } else { 145624bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith cout << "Partition #" << partNum + 1 << " does not exist.\n"; 1457221e08768de7fe42ba533ca22baf671420569c07srs } // if 1458e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ShowPartDetails() 1459221e08768de7fe42ba533ca22baf671420569c07srs 1460e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/************************************************************************** 1461e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1462e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Partition table transformation functions (MBR or BSD disklabel to GPT) * 1463e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * (some of these functions may require user interaction) * 1464e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1465e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs **************************************************************************/ 1466e7b4ff9317fc4e551cf974684eaa88697de5a28srs 146708bb0da07953af605b4918e268272de15ac151aasrs// Examines the MBR & GPT data to determine which set of data to use: the 146808bb0da07953af605b4918e268272de15ac151aasrs// MBR (use_mbr), the GPT (use_gpt), the BSD disklabel (use_bsd), or create 146908bb0da07953af605b4918e268272de15ac151aasrs// a new set of partitions (use_new). A return value of use_abort indicates 147008bb0da07953af605b4918e268272de15ac151aasrs// that this function couldn't determine what to do. Overriding functions 147108bb0da07953af605b4918e268272de15ac151aasrs// in derived classes may ask users questions in such cases. 1472e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsWhichToUse GPTData::UseWhichPartitions(void) { 1473e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs WhichToUse which = use_new; 1474e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs MBRValidity mbrState; 1475e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1476e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mbrState = protectiveMBR.GetValidity(); 1477e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1478e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) { 1479fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n***************************************************************\n" 14801eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "Found invalid GPT and valid MBR; converting MBR to GPT format\n" 14811eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "in memory. "; 14825d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs if (!justLooking) { 14831eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith cout << "\aTHIS OPERATION IS POTENTIALLY DESTRUCTIVE! Exit by\n" 14841eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "typing 'q' if you don't want to convert your MBR partitions\n" 14851eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith << "to GPT format!"; 14865d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 14871eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith cout << "\n***************************************************************\n\n"; 1488e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_mbr; 14892a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 14902a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1491e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_invalid) && bsdFound) { 1492fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n**********************************************************************\n" 1493fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n" 1494fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "to GPT format."; 14950a6973119c9e9984ad47a6da3231e8d16f996c5csrs if ((!justLooking) && (!beQuiet)) { 14960283dae41a7db4563be0fe62241ed230e4a101c0srs cout << "\a THIS OPERATION IS POTENTIALLY DESTRUCTIVE! Your first\n" 1497fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "BSD partition will likely be unusable. Exit by typing 'q' if you don't\n" 1498fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "want to convert your BSD partitions to GPT format!"; 14995d58fe0ea12c9c727c8a970c8e1ac08ea7fbe05fsrs } // if 1500fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "\n**********************************************************************\n\n"; 1501e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_bsd; 15022a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 1503e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1504e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == gpt)) { 1505e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_gpt; 15063c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (!beQuiet) 1507fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Found valid GPT with protective MBR; using GPT.\n"; 1508e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1509e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == hybrid)) { 1510e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_gpt; 15113c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (!beQuiet) 1512fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Found valid GPT with hybrid MBR; using GPT.\n"; 1513e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1514e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == invalid)) { 15150a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "\aFound valid GPT with corrupt MBR; using GPT and will write new\n" 1516fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "protective MBR on save.\n"; 1517e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs which = use_gpt; 1518e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1519e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((state == gpt_valid) && (mbrState == mbr)) { 152008bb0da07953af605b4918e268272de15ac151aasrs which = use_abort; 15213c0af38237d0f40aaea8233a5cbfdd030a77817dsrs } // if 15223c0af38237d0f40aaea8233a5cbfdd030a77817dsrs 15233c0af38237d0f40aaea8233a5cbfdd030a77817dsrs if (state == gpt_corrupt) { 152408bb0da07953af605b4918e268272de15ac151aasrs if (mbrState == gpt) { 152508bb0da07953af605b4918e268272de15ac151aasrs cout << "\a\a****************************************************************************\n" 152608bb0da07953af605b4918e268272de15ac151aasrs << "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n" 152708bb0da07953af605b4918e268272de15ac151aasrs << "verification and recovery are STRONGLY recommended.\n" 152808bb0da07953af605b4918e268272de15ac151aasrs << "****************************************************************************\n"; 152908bb0da07953af605b4918e268272de15ac151aasrs which = use_gpt; 15303c0af38237d0f40aaea8233a5cbfdd030a77817dsrs } else { 153108bb0da07953af605b4918e268272de15ac151aasrs which = use_abort; 153208bb0da07953af605b4918e268272de15ac151aasrs } // if/else MBR says disk is GPT 153308bb0da07953af605b4918e268272de15ac151aasrs } // if GPT corrupt 1534e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1535e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (which == use_new) 1536fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Creating new GPT entries.\n"; 1537e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1538e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return which; 1539e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // UseWhichPartitions() 1540e7b4ff9317fc4e551cf974684eaa88697de5a28srs 154108bb0da07953af605b4918e268272de15ac151aasrs// Convert MBR partition table into GPT form. 154208bb0da07953af605b4918e268272de15ac151aasrsvoid GPTData::XFormPartitions(void) { 1543e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int i, numToConvert; 1544e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint8_t origType; 1545221e08768de7fe42ba533ca22baf671420569c07srs 1546e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Clear out old data & prepare basics.... 1547e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ClearGPTData(); 1548e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1549e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Convert the smaller of the # of GPT or MBR partitions 15500283dae41a7db4563be0fe62241ed230e4a101c0srs if (numParts > MAX_MBR_PARTS) 1551978041ca613dcb881763b36cf53639d924e52a56srs numToConvert = MAX_MBR_PARTS; 1552e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs else 15530283dae41a7db4563be0fe62241ed230e4a101c0srs numToConvert = numParts; 1554e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1555e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < numToConvert; i++) { 1556e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs origType = protectiveMBR.GetType(i); 1557e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // don't waste CPU time trying to convert extended, hybrid protective, or 1558e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // null (non-existent) partitions 1559e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 15606699b01eda84d24bfaf80ad725304fef2b0e1b2asrs (origType != 0x00) && (origType != 0xEE)) 1561e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[i] = protectiveMBR.AsGPT(i); 1562e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 1563e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1564e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Convert MBR into protective MBR 1565e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs protectiveMBR.MakeProtectiveMBR(); 1566e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1567e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Record that all original CRCs were OK so as not to raise flags 1568e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // when doing a disk verification 1569e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1; 1570e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::XFormPartitions() 1571e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1572e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Transforms BSD disklabel on the specified partition (numbered from 0). 157308bb0da07953af605b4918e268272de15ac151aasrs// If an invalid partition number is given, the program does nothing. 1574e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Returns the number of new partitions created. 157508bb0da07953af605b4918e268272de15ac151aasrsint GPTData::XFormDisklabel(uint32_t partNum) { 157608bb0da07953af605b4918e268272de15ac151aasrs uint32_t low, high; 1577e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int goOn = 1, numDone = 0; 1578e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs BSDData disklabel; 1579e7b4ff9317fc4e551cf974684eaa88697de5a28srs 158008bb0da07953af605b4918e268272de15ac151aasrs if (GetPartRange(&low, &high) == 0) { 158108bb0da07953af605b4918e268272de15ac151aasrs goOn = 0; 158208bb0da07953af605b4918e268272de15ac151aasrs cout << "No partitions!\n"; 158308bb0da07953af605b4918e268272de15ac151aasrs } // if 158408bb0da07953af605b4918e268272de15ac151aasrs if (partNum > high) { 158508bb0da07953af605b4918e268272de15ac151aasrs goOn = 0; 158608bb0da07953af605b4918e268272de15ac151aasrs cout << "Specified partition is invalid!\n"; 158708bb0da07953af605b4918e268272de15ac151aasrs } // if 1588e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 158908bb0da07953af605b4918e268272de15ac151aasrs // If all is OK, read the disklabel and convert it. 159008bb0da07953af605b4918e268272de15ac151aasrs if (goOn) { 159108bb0da07953af605b4918e268272de15ac151aasrs goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(), 159208bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum].GetLastLBA()); 159308bb0da07953af605b4918e268272de15ac151aasrs if ((goOn) && (disklabel.IsDisklabel())) { 159408bb0da07953af605b4918e268272de15ac151aasrs numDone = XFormDisklabel(&disklabel); 159508bb0da07953af605b4918e268272de15ac151aasrs if (numDone == 1) 159608bb0da07953af605b4918e268272de15ac151aasrs cout << "Converted 1 BSD partition.\n"; 159708bb0da07953af605b4918e268272de15ac151aasrs else 159808bb0da07953af605b4918e268272de15ac151aasrs cout << "Converted " << numDone << " BSD partitions.\n"; 159908bb0da07953af605b4918e268272de15ac151aasrs } else { 160008bb0da07953af605b4918e268272de15ac151aasrs cout << "Unable to convert partitions! Unrecognized BSD disklabel.\n"; 160108bb0da07953af605b4918e268272de15ac151aasrs } // if/else 160208bb0da07953af605b4918e268272de15ac151aasrs } // if 160308bb0da07953af605b4918e268272de15ac151aasrs if (numDone > 0) { // converted partitions; delete carrier 160408bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum].BlankPartition(); 160508bb0da07953af605b4918e268272de15ac151aasrs } // if 1606e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numDone; 160755d926192adc984462509b2966e23bc0d1129bbdsrs} // GPTData::XFormDisklabel(uint32_t i) 1608e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1609e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Transform the partitions on an already-loaded BSD disklabel... 161008bb0da07953af605b4918e268272de15ac151aasrsint GPTData::XFormDisklabel(BSDData* disklabel) { 161108bb0da07953af605b4918e268272de15ac151aasrs int i, partNum = 0, numDone = 0; 1612e7b4ff9317fc4e551cf974684eaa88697de5a28srs 161308bb0da07953af605b4918e268272de15ac151aasrs if (disklabel->IsDisklabel()) { 1614e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < disklabel->GetNumParts(); i++) { 161508bb0da07953af605b4918e268272de15ac151aasrs partNum = FindFirstFreePart(); 161608bb0da07953af605b4918e268272de15ac151aasrs if (partNum >= 0) { 161708bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum] = disklabel->AsGPT(i); 161808bb0da07953af605b4918e268272de15ac151aasrs if (partitions[partNum].IsUsed()) 161908bb0da07953af605b4918e268272de15ac151aasrs numDone++; 162008bb0da07953af605b4918e268272de15ac151aasrs } // if 1621e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 162208bb0da07953af605b4918e268272de15ac151aasrs if (partNum == -1) 162308bb0da07953af605b4918e268272de15ac151aasrs cerr << "Warning! Too many partitions to convert!\n"; 1624e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 1625e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1626e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Record that all original CRCs were OK so as not to raise flags 1627e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // when doing a disk verification 1628e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1; 1629e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 1630e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numDone; 1631e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::XFormDisklabel(BSDData* disklabel) 1632e7b4ff9317fc4e551cf974684eaa88697de5a28srs 163308bb0da07953af605b4918e268272de15ac151aasrs// Add one GPT partition to MBR. Used by PartsToMBR() functions. Created 163408bb0da07953af605b4918e268272de15ac151aasrs// partition has the active/bootable flag UNset and uses the GPT fdisk 163508bb0da07953af605b4918e268272de15ac151aasrs// type code divided by 0x0100 as the MBR type code. 163608bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if operation was 100% successful, 0 if there were ANY 163708bb0da07953af605b4918e268272de15ac151aasrs// problems. 1638978041ca613dcb881763b36cf53639d924e52a56srsint GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) { 163908bb0da07953af605b4918e268272de15ac151aasrs int allOK = 1; 1640fed16d043a14e8b86c97a6413aec7281fefcbcb5srs 1641978041ca613dcb881763b36cf53639d924e52a56srs if ((mbrPart < 0) || (mbrPart > 3)) { 1642fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "MBR partition " << mbrPart + 1 << " is out of range; omitting it.\n"; 1643978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1644978041ca613dcb881763b36cf53639d924e52a56srs } // if 16450283dae41a7db4563be0fe62241ed230e4a101c0srs if (gptPart >= numParts) { 1646fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "GPT partition " << gptPart + 1 << " is out of range; omitting it.\n"; 1647978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1648978041ca613dcb881763b36cf53639d924e52a56srs } // if 1649978041ca613dcb881763b36cf53639d924e52a56srs if (allOK && (partitions[gptPart].GetLastLBA() == UINT64_C(0))) { 1650fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "GPT partition " << gptPart + 1 << " is undefined; omitting it.\n"; 1651978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1652978041ca613dcb881763b36cf53639d924e52a56srs } // if 1653978041ca613dcb881763b36cf53639d924e52a56srs if (allOK && (partitions[gptPart].GetFirstLBA() <= UINT32_MAX) && 1654978041ca613dcb881763b36cf53639d924e52a56srs (partitions[gptPart].GetLengthLBA() <= UINT32_MAX)) { 1655978041ca613dcb881763b36cf53639d924e52a56srs if (partitions[gptPart].GetLastLBA() > UINT32_MAX) { 1656fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Caution: Partition end point past 32-bit pointer boundary;" 1657fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << " some OSes may\nreact strangely.\n"; 165808bb0da07953af605b4918e268272de15ac151aasrs } // if 1659978041ca613dcb881763b36cf53639d924e52a56srs protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(), 166008bb0da07953af605b4918e268272de15ac151aasrs (uint32_t) partitions[gptPart].GetLengthLBA(), 166108bb0da07953af605b4918e268272de15ac151aasrs partitions[gptPart].GetHexType() / 256, 0); 1662978041ca613dcb881763b36cf53639d924e52a56srs } else { // partition out of range 166308bb0da07953af605b4918e268272de15ac151aasrs if (allOK) // Display only if "else" triggered by out-of-bounds condition 166408bb0da07953af605b4918e268272de15ac151aasrs cout << "Partition " << gptPart + 1 << " begins beyond the 32-bit pointer limit of MBR " 166508bb0da07953af605b4918e268272de15ac151aasrs << "partitions, or is\n too big; omitting it.\n"; 1666978041ca613dcb881763b36cf53639d924e52a56srs allOK = 0; 1667978041ca613dcb881763b36cf53639d924e52a56srs } // if/else 1668978041ca613dcb881763b36cf53639d924e52a56srs return allOK; 1669978041ca613dcb881763b36cf53639d924e52a56srs} // GPTData::OnePartToMBR() 1670978041ca613dcb881763b36cf53639d924e52a56srs 1671c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 1672e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/********************************************************************** 1673e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1674e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Functions that adjust GPT data structures WITHOUT user interaction * 1675e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * (they may display information for the user's benefit, though) * 1676e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 1677e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs **********************************************************************/ 1678e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1679e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Resizes GPT to specified number of entries. Creates a new table if 1680706e51217a531c46afc743b556e10fd5c0585fcfsrs// necessary, copies data if it already exists. If fillGPTSectors is 1 1681706e51217a531c46afc743b556e10fd5c0585fcfsrs// (the default), rounds numEntries to fill all the sectors necessary to 1682706e51217a531c46afc743b556e10fd5c0585fcfsrs// hold the GPT. 1683706e51217a531c46afc743b556e10fd5c0585fcfsrs// Returns 1 if all goes well, 0 if an error is encountered. 1684706e51217a531c46afc743b556e10fd5c0585fcfsrsint GPTData::SetGPTSize(uint32_t numEntries, int fillGPTSectors) { 168508bb0da07953af605b4918e268272de15ac151aasrs GPTPart* newParts; 1686706e51217a531c46afc743b556e10fd5c0585fcfsrs uint32_t i, high, copyNum, entriesPerSector; 1687e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int allOK = 1; 1688e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1689e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // First, adjust numEntries upward, if necessary, to get a number 1690e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // that fills the allocated sectors 1691706e51217a531c46afc743b556e10fd5c0585fcfsrs entriesPerSector = blockSize / GPT_SIZE; 1692706e51217a531c46afc743b556e10fd5c0585fcfsrs if (fillGPTSectors && ((numEntries % entriesPerSector) != 0)) { 1693fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "Adjusting GPT size from " << numEntries << " to "; 1694706e51217a531c46afc743b556e10fd5c0585fcfsrs numEntries = ((numEntries / entriesPerSector) + 1) * entriesPerSector; 1695fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << numEntries << " to fill the sector\n"; 1696e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 1697e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1698247657a5acbb7eb21c336ba84a68b801b7c19be0srs // Do the work only if the # of partitions is changing. Along with being 169955d926192adc984462509b2966e23bc0d1129bbdsrs // efficient, this prevents mucking with the location of the secondary 1700247657a5acbb7eb21c336ba84a68b801b7c19be0srs // partition table, which causes problems when loading data from a RAID 1701247657a5acbb7eb21c336ba84a68b801b7c19be0srs // array that's been expanded because this function is called when loading 1702247657a5acbb7eb21c336ba84a68b801b7c19be0srs // data. 17030283dae41a7db4563be0fe62241ed230e4a101c0srs if (((numEntries != numParts) || (partitions == NULL)) && (numEntries > 0)) { 170401f7f08624f0c942001977415214a578621f6495srs newParts = new GPTPart [numEntries]; 1705247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (newParts != NULL) { 1706247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (partitions != NULL) { // existing partitions; copy them over 1707247657a5acbb7eb21c336ba84a68b801b7c19be0srs GetPartRange(&i, &high); 1708247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (numEntries < (high + 1)) { // Highest entry too high for new # 1709fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cout << "The highest-numbered partition is " << high + 1 1710fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << ", which is greater than the requested\n" 1711fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "partition table size of " << numEntries 1712fed16d043a14e8b86c97a6413aec7281fefcbcb5srs << "; cannot resize. Perhaps sorting will help.\n"; 1713247657a5acbb7eb21c336ba84a68b801b7c19be0srs allOK = 0; 1714815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs delete[] newParts; 1715247657a5acbb7eb21c336ba84a68b801b7c19be0srs } else { // go ahead with copy 17160283dae41a7db4563be0fe62241ed230e4a101c0srs if (numEntries < numParts) 1717247657a5acbb7eb21c336ba84a68b801b7c19be0srs copyNum = numEntries; 1718247657a5acbb7eb21c336ba84a68b801b7c19be0srs else 17190283dae41a7db4563be0fe62241ed230e4a101c0srs copyNum = numParts; 1720247657a5acbb7eb21c336ba84a68b801b7c19be0srs for (i = 0; i < copyNum; i++) { 1721247657a5acbb7eb21c336ba84a68b801b7c19be0srs newParts[i] = partitions[i]; 1722247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // for 172301f7f08624f0c942001977415214a578621f6495srs delete[] partitions; 1724247657a5acbb7eb21c336ba84a68b801b7c19be0srs partitions = newParts; 1725247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if 1726247657a5acbb7eb21c336ba84a68b801b7c19be0srs } else { // No existing partition table; just create it 1727e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions = newParts; 1728247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if/else existing partitions 17290283dae41a7db4563be0fe62241ed230e4a101c0srs numParts = numEntries; 1730706e51217a531c46afc743b556e10fd5c0585fcfsrs mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + (((numEntries * GPT_SIZE) % blockSize) != 0) + 2 ; 1731247657a5acbb7eb21c336ba84a68b801b7c19be0srs secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; 1732247657a5acbb7eb21c336ba84a68b801b7c19be0srs MoveSecondHeaderToEnd(); 1733247657a5acbb7eb21c336ba84a68b801b7c19be0srs if (diskSize > 0) 1734247657a5acbb7eb21c336ba84a68b801b7c19be0srs CheckGPTSize(); 1735247657a5acbb7eb21c336ba84a68b801b7c19be0srs } else { // Bad memory allocation 17366aae2a9b70e9f88926baad94c1eea40e0b534f01srs cerr << "Error allocating memory for partition table! Size is unchanged!\n"; 1737247657a5acbb7eb21c336ba84a68b801b7c19be0srs allOK = 0; 1738247657a5acbb7eb21c336ba84a68b801b7c19be0srs } // if/else 1739e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if/else 17400283dae41a7db4563be0fe62241ed230e4a101c0srs mainHeader.numParts = numParts; 17410283dae41a7db4563be0fe62241ed230e4a101c0srs secondHeader.numParts = numParts; 1742e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (allOK); 1743e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SetGPTSize() 1744e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1745e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Blank the partition array 1746e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::BlankPartitions(void) { 1747e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 1748e7b4ff9317fc4e551cf974684eaa88697de5a28srs 17490283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 1750e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[i].BlankPartition(); 1751e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 1752e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::BlankPartitions() 1753e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1754ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// Delete a partition by number. Returns 1 if successful, 1755ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// 0 if there was a problem. Returns 1 if partition was in 1756ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// range, 0 if it was out of range. 1757ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srsint GPTData::DeletePartition(uint32_t partNum) { 1758ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs uint64_t startSector, length; 17590283dae41a7db4563be0fe62241ed230e4a101c0srs uint32_t low, high, numUsedParts, retval = 1;; 1760ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 17610283dae41a7db4563be0fe62241ed230e4a101c0srs numUsedParts = GetPartRange(&low, &high); 17620283dae41a7db4563be0fe62241ed230e4a101c0srs if ((numUsedParts > 0) && (partNum >= low) && (partNum <= high)) { 1763ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs // In case there's a protective MBR, look for & delete matching 1764ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs // MBR partition.... 1765ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs startSector = partitions[partNum].GetFirstLBA(); 1766ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs length = partitions[partNum].GetLengthLBA(); 1767ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs protectiveMBR.DeleteByLocation(startSector, length); 1768ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1769ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs // Now delete the GPT partition 1770ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs partitions[partNum].BlankPartition(); 1771ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else { 1772fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "Partition number " << partNum + 1 << " out of range!\n"; 1773ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs retval = 0; 1774ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } // if/else 1775ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs return retval; 1776ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs} // GPTData::DeletePartition(uint32_t partNum) 1777ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 177808bb0da07953af605b4918e268272de15ac151aasrs// Non-interactively create a partition. 177908bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if the operation was successful, 0 if a problem was discovered. 1780e321d444dcca514cf6b53459e388ddcbaab6176csrsuint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) { 1781ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs int retval = 1; // assume there'll be no problems 17825a081757ea2e32a491349544fea92826ccf739f6srs uint64_t origSector = startSector; 1783ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1784ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (IsFreePartNum(partNum)) { 17855a081757ea2e32a491349544fea92826ccf739f6srs if (Align(&startSector)) { 17865a081757ea2e32a491349544fea92826ccf739f6srs cout << "Information: Moved requested sector from " << origSector << " to " 17875a081757ea2e32a491349544fea92826ccf739f6srs << startSector << " in\norder to align on " << sectorAlignment 17885a081757ea2e32a491349544fea92826ccf739f6srs << "-sector boundaries.\n"; 17895a081757ea2e32a491349544fea92826ccf739f6srs } // if 1790ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (IsFree(startSector) && (startSector <= endSector)) { 1791ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs if (FindLastInFree(startSector) >= endSector) { 1792ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs partitions[partNum].SetFirstLBA(startSector); 1793ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs partitions[partNum].SetLastLBA(endSector); 17940741fa21ac6cb477891ef15f269c8c8f36cac7c6srs partitions[partNum].SetType(DEFAULT_GPT_TYPE); 17956699b01eda84d24bfaf80ad725304fef2b0e1b2asrs partitions[partNum].RandomizeUniqueGUID(); 1796ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else retval = 0; // if free space until endSector 1797ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else retval = 0; // if startSector is free 1798ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs } else retval = 0; // if legal partition number 1799ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs return retval; 1800ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs} // GPTData::CreatePartition(partNum, startSector, endSector) 1801ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1802e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Sort the GPT entries, eliminating gaps and making for a logical 18039a46b042c57144c26a67781d335e6ba4128382d2srs// ordering. 1804e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::SortGPT(void) { 18059a46b042c57144c26a67781d335e6ba4128382d2srs if (numParts > 0) 180601f7f08624f0c942001977415214a578621f6495srs sort(partitions, partitions + numParts); 1807e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SortGPT() 1808e7b4ff9317fc4e551cf974684eaa88697de5a28srs 180908bb0da07953af605b4918e268272de15ac151aasrs// Swap the contents of two partitions. 181008bb0da07953af605b4918e268272de15ac151aasrs// Returns 1 if successful, 0 if either partition is out of range 181108bb0da07953af605b4918e268272de15ac151aasrs// (that is, not a legal number; either or both can be empty). 181208bb0da07953af605b4918e268272de15ac151aasrs// Note that if partNum1 = partNum2 and this number is in range, 181308bb0da07953af605b4918e268272de15ac151aasrs// it will be considered successful. 181408bb0da07953af605b4918e268272de15ac151aasrsint GPTData::SwapPartitions(uint32_t partNum1, uint32_t partNum2) { 181508bb0da07953af605b4918e268272de15ac151aasrs GPTPart temp; 181608bb0da07953af605b4918e268272de15ac151aasrs int allOK = 1; 181708bb0da07953af605b4918e268272de15ac151aasrs 18180283dae41a7db4563be0fe62241ed230e4a101c0srs if ((partNum1 < numParts) && (partNum2 < numParts)) { 181908bb0da07953af605b4918e268272de15ac151aasrs if (partNum1 != partNum2) { 182008bb0da07953af605b4918e268272de15ac151aasrs temp = partitions[partNum1]; 182108bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum1] = partitions[partNum2]; 182208bb0da07953af605b4918e268272de15ac151aasrs partitions[partNum2] = temp; 182308bb0da07953af605b4918e268272de15ac151aasrs } // if 182408bb0da07953af605b4918e268272de15ac151aasrs } else allOK = 0; // partition numbers are valid 182508bb0da07953af605b4918e268272de15ac151aasrs return allOK; 182608bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::SwapPartitions() 182708bb0da07953af605b4918e268272de15ac151aasrs 1828e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Set up data structures for entirely new set of partitions on the 1829e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// specified device. Returns 1 if OK, 0 if there were problems. 1830e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// Note that this function does NOT clear the protectiveMBR data 1831e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// structure, since it may hold the original MBR partitions if the 1832e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// program was launched on an MBR disk, and those may need to be 1833e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs// converted to GPT format. 1834e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::ClearGPTData(void) { 1835e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs int goOn = 1, i; 1836e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1837e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Set up the partition table.... 18389a46b042c57144c26a67781d335e6ba4128382d2srs delete[] partitions; 1839e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions = NULL; 1840e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs SetGPTSize(NUM_GPT_ENTRIES); 1841e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1842e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now initialize a bunch of stuff that's static.... 1843e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.signature = GPT_SIGNATURE; 1844e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.revision = 0x00010000; 1845978041ca613dcb881763b36cf53639d924e52a56srs mainHeader.headerSize = HEADER_SIZE; 1846e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.reserved = 0; 1847e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.currentLBA = UINT64_C(1); 1848e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.partitionEntriesLBA = (uint64_t) 2; 1849e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.sizeOfPartitionEntries = GPT_SIZE; 1850e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs for (i = 0; i < GPT_RESERVED; i++) { 1851e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.reserved2[i] = '\0'; 1852e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 18530873e9d0e9345a2c4418b4718db525c9f1111c83srs if (blockSize > 0) 18540873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize; 18550873e9d0e9345a2c4418b4718db525c9f1111c83srs else 18560873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = DEFAULT_ALIGNMENT; 1857e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1858e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Now some semi-static items (computed based on end of disk) 1859e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.backupLBA = diskSize - UINT64_C(1); 1860e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; 18612a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1862e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Set a unique GUID for the disk, based on random numbers 18636699b01eda84d24bfaf80ad725304fef2b0e1b2asrs mainHeader.diskGUID.Randomize(); 1864e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1865e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Copy main header to backup header 1866e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs RebuildSecondHeader(); 1867e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1868e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Blank out the partitions array.... 1869e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs BlankPartitions(); 18702a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 1871e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Flag all CRCs as being OK.... 1872e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainCrcOk = 1; 1873e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondCrcOk = 1; 1874e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainPartsCrcOk = 1; 1875e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondPartsCrcOk = 1; 1876e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1877e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (goOn); 1878e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::ClearGPTData() 1879e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1880247657a5acbb7eb21c336ba84a68b801b7c19be0srs// Set the location of the second GPT header data to the end of the disk. 188164cbd171067eb34054741bfcd73f0b91d727a371srs// If the disk size has actually changed, this also adjusts the protective 188264cbd171067eb34054741bfcd73f0b91d727a371srs// entry in the MBR, since it's probably no longer correct. 1883247657a5acbb7eb21c336ba84a68b801b7c19be0srs// Used internally and called by the 'e' option on the recovery & 1884247657a5acbb7eb21c336ba84a68b801b7c19be0srs// transformation menu, to help users of RAID arrays who add disk space 188564cbd171067eb34054741bfcd73f0b91d727a371srs// to their arrays or to adjust data structures in restore operations 188664cbd171067eb34054741bfcd73f0b91d727a371srs// involving unequal-sized disks. 1887247657a5acbb7eb21c336ba84a68b801b7c19be0srsvoid GPTData::MoveSecondHeaderToEnd() { 18888bb7876224e60a00f0b7f39e4624ee0961b2f27csrs mainHeader.backupLBA = secondHeader.currentLBA = diskSize - UINT64_C(1); 188964cbd171067eb34054741bfcd73f0b91d727a371srs if (mainHeader.lastUsableLBA != diskSize - mainHeader.firstUsableLBA) { 189064cbd171067eb34054741bfcd73f0b91d727a371srs if (protectiveMBR.GetValidity() == hybrid) { 189164cbd171067eb34054741bfcd73f0b91d727a371srs protectiveMBR.OptimizeEESize(); 189264cbd171067eb34054741bfcd73f0b91d727a371srs RecomputeCHS(); 189364cbd171067eb34054741bfcd73f0b91d727a371srs } // if 189464cbd171067eb34054741bfcd73f0b91d727a371srs if (protectiveMBR.GetValidity() == gpt) 189564cbd171067eb34054741bfcd73f0b91d727a371srs MakeProtectiveMBR(); 189664cbd171067eb34054741bfcd73f0b91d727a371srs } // if 18978bb7876224e60a00f0b7f39e4624ee0961b2f27csrs mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; 18988bb7876224e60a00f0b7f39e4624ee0961b2f27csrs secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); 18998bb7876224e60a00f0b7f39e4624ee0961b2f27csrs} // GPTData::FixSecondHeaderLocation() 19008bb7876224e60a00f0b7f39e4624ee0961b2f27csrs 1901699941e25a1fcf0beec124203747c8ed20842989srs// Sets the partition's name to the specified UnicodeString without 1902699941e25a1fcf0beec124203747c8ed20842989srs// user interaction. 1903699941e25a1fcf0beec124203747c8ed20842989srs// Returns 1 on success, 0 on failure (invalid partition number). 19045a6085310b7f8fe1c35e56bcab7de161808b488dsrsint GPTData::SetName(uint32_t partNum, const UnicodeString & theName) { 1905ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs int retval = 1; 1906fed16d043a14e8b86c97a6413aec7281fefcbcb5srs 1907699941e25a1fcf0beec124203747c8ed20842989srs if (IsUsedPartNum(partNum)) 1908fed16d043a14e8b86c97a6413aec7281fefcbcb5srs partitions[partNum].SetName(theName); 1909699941e25a1fcf0beec124203747c8ed20842989srs else 1910699941e25a1fcf0beec124203747c8ed20842989srs retval = 0; 1911ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 1912ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs return retval; 1913e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SetName 1914e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1915e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Set the disk GUID to the specified value. Note that the header CRCs must 1916e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// be recomputed after calling this function. 1917e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsvoid GPTData::SetDiskGUID(GUIDData newGUID) { 1918e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs mainHeader.diskGUID = newGUID; 1919e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs secondHeader.diskGUID = newGUID; 1920e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // SetDiskGUID() 1921e7b4ff9317fc4e551cf974684eaa88697de5a28srs 1922e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Set the unique GUID of the specified partition. Returns 1 on 1923e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// successful completion, 0 if there were problems (invalid 1924e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// partition number). 1925e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) { 1926e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int retval = 0; 19272a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 19280283dae41a7db4563be0fe62241ed230e4a101c0srs if (pn < numParts) { 1929e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[pn].IsUsed()) { 1930e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs partitions[pn].SetUniqueGUID(theGUID); 1931e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs retval = 1; 19322a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // if 1933e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 1934e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return retval; 1935e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::SetPartitionGUID() 1936e7b4ff9317fc4e551cf974684eaa88697de5a28srs 19379ba5421f920e192dbb808d30aa6d34849938bab4srs// Set new random GUIDs for the disk and all partitions. Intended to be used 19389ba5421f920e192dbb808d30aa6d34849938bab4srs// after disk cloning or similar operations that don't randomize the GUIDs. 19399ba5421f920e192dbb808d30aa6d34849938bab4srsvoid GPTData::RandomizeGUIDs(void) { 19409ba5421f920e192dbb808d30aa6d34849938bab4srs uint32_t i; 19419ba5421f920e192dbb808d30aa6d34849938bab4srs 19429ba5421f920e192dbb808d30aa6d34849938bab4srs mainHeader.diskGUID.Randomize(); 19439ba5421f920e192dbb808d30aa6d34849938bab4srs secondHeader.diskGUID = mainHeader.diskGUID; 19449ba5421f920e192dbb808d30aa6d34849938bab4srs for (i = 0; i < numParts; i++) 19459ba5421f920e192dbb808d30aa6d34849938bab4srs if (partitions[i].IsUsed()) 19469ba5421f920e192dbb808d30aa6d34849938bab4srs partitions[i].RandomizeUniqueGUID(); 19479ba5421f920e192dbb808d30aa6d34849938bab4srs} // GPTData::RandomizeGUIDs() 19489ba5421f920e192dbb808d30aa6d34849938bab4srs 1949ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// Change partition type code non-interactively. Returns 1 if 1950ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs// successful, 0 if not.... 1951327129e9331f888a8fc08d688dcb0a739a3c17besrsint GPTData::ChangePartType(uint32_t partNum, PartType theGUID) { 1952327129e9331f888a8fc08d688dcb0a739a3c17besrs int retval = 1; 1953327129e9331f888a8fc08d688dcb0a739a3c17besrs 1954327129e9331f888a8fc08d688dcb0a739a3c17besrs if (!IsFreePartNum(partNum)) { 1955327129e9331f888a8fc08d688dcb0a739a3c17besrs partitions[partNum].SetType(theGUID); 1956327129e9331f888a8fc08d688dcb0a739a3c17besrs } else retval = 0; 1957327129e9331f888a8fc08d688dcb0a739a3c17besrs return retval; 1958327129e9331f888a8fc08d688dcb0a739a3c17besrs} // GPTData::ChangePartType() 1959327129e9331f888a8fc08d688dcb0a739a3c17besrs 19609ba5421f920e192dbb808d30aa6d34849938bab4srs// Recompute the CHS values of all the MBR partitions. Used to reset 19619ba5421f920e192dbb808d30aa6d34849938bab4srs// CHS values that some BIOSes require, despite the fact that the 19629ba5421f920e192dbb808d30aa6d34849938bab4srs// resulting CHS values violate the GPT standard. 19639ba5421f920e192dbb808d30aa6d34849938bab4srsvoid GPTData::RecomputeCHS(void) { 19649ba5421f920e192dbb808d30aa6d34849938bab4srs int i; 19659ba5421f920e192dbb808d30aa6d34849938bab4srs 19669ba5421f920e192dbb808d30aa6d34849938bab4srs for (i = 0; i < 4; i++) 19679ba5421f920e192dbb808d30aa6d34849938bab4srs protectiveMBR.RecomputeCHS(i); 19689ba5421f920e192dbb808d30aa6d34849938bab4srs} // GPTData::RecomputeCHS() 19699ba5421f920e192dbb808d30aa6d34849938bab4srs 19701d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// Adjust sector number so that it falls on a sector boundary that's a 19711d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// multiple of sectorAlignment. This is done to improve the performance 19721d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// of Western Digital Advanced Format disks and disks with similar 19731d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// technology from other companies, which use 4096-byte sectors 19741d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// internally although they translate to 512-byte sectors for the 19751d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// benefit of the OS. If partitions aren't properly aligned on these 19761d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// disks, some filesystem data structures can span multiple physical 19771d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// sectors, degrading performance. This function should be called 19781d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// only on the FIRST sector of the partition, not the last! 19791d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// This function returns 1 if the alignment was altered, 0 if it 19801d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs// was unchanged. 19811d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srsint GPTData::Align(uint64_t* sector) { 19821d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs int retval = 0, sectorOK = 0; 198300b6d7a4604e759eb3c92b3ecea608d6fe024b81srs uint64_t earlier, later, testSector; 19841d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 19851d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if ((*sector % sectorAlignment) != 0) { 19861d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs earlier = (*sector / sectorAlignment) * sectorAlignment; 19871d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs later = earlier + (uint64_t) sectorAlignment; 19881d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 19891d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // Check to see that every sector between the earlier one and the 19901d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // requested one is clear, and that it's not too early.... 19911d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if (earlier >= mainHeader.firstUsableLBA) { 19921d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = 1; 19931d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs testSector = earlier; 19941d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs do { 19951d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = IsFree(testSector++); 19961d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } while ((sectorOK == 1) && (testSector < *sector)); 19971d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if (sectorOK == 1) { 19981d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs *sector = earlier; 19995a081757ea2e32a491349544fea92826ccf739f6srs retval = 1; 20001d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20011d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if firstUsableLBA check 20021d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 20031d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs // If couldn't move the sector earlier, try to move it later instead.... 20041d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if ((sectorOK != 1) && (later <= mainHeader.lastUsableLBA)) { 20051d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = 1; 20061d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs testSector = later; 20071d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs do { 20081d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs sectorOK = IsFree(testSector--); 20091d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } while ((sectorOK == 1) && (testSector > *sector)); 20101d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs if (sectorOK == 1) { 20111d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs *sector = later; 20125a081757ea2e32a491349544fea92826ccf739f6srs retval = 1; 20131d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20141d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20151d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs } // if 20161d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs return retval; 20171d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs} // GPTData::Align() 20181d1448a82d62ad32a8d597ed9ade46b4f37d8eb5srs 2019e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/******************************************************** 2020e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2021e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Functions that return data about GPT data structures * 2022e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * (most of these are inline in gpt.h) * 2023e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2024e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ********************************************************/ 2025e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2026e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find the low and high used partition numbers (numbered from 0). 2027e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Return value is the number of partitions found. Note that the 2028e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// *low and *high values are both set to 0 when no partitions 2029e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// are found, as well as when a single partition in the first 2030e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// position exists. Thus, the return value is the only way to 2031e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// tell when no partitions exist. 2032e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsint GPTData::GetPartRange(uint32_t *low, uint32_t *high) { 2033e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2034e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int numFound = 0; 20352a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 20360283dae41a7db4563be0fe62241ed230e4a101c0srs *low = numParts + 1; // code for "not found" 2037e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *high = 0; 20389a46b042c57144c26a67781d335e6ba4128382d2srs for (i = 0; i < numParts; i++) { 2039e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if (partitions[i].IsUsed()) { // it exists 20409a46b042c57144c26a67781d335e6ba4128382d2srs *high = i; // since we're counting up, set the high value 20419a46b042c57144c26a67781d335e6ba4128382d2srs // Set the low value only if it's not yet found... 20429a46b042c57144c26a67781d335e6ba4128382d2srs if (*low == (numParts + 1)) *low = i; 20439a46b042c57144c26a67781d335e6ba4128382d2srs numFound++; 20449a46b042c57144c26a67781d335e6ba4128382d2srs } // if 20459a46b042c57144c26a67781d335e6ba4128382d2srs } // for 2046e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2047e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Above will leave *low pointing to its "not found" value if no partitions 2048e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // are defined, so reset to 0 if this is the case.... 20490283dae41a7db4563be0fe62241ed230e4a101c0srs if (*low == (numParts + 1)) 2050e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *low = 0; 2051e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return numFound; 2052e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::GetPartRange() 2053e7b4ff9317fc4e551cf974684eaa88697de5a28srs 205408bb0da07953af605b4918e268272de15ac151aasrs// Returns the value of the first free partition, or -1 if none is 205508bb0da07953af605b4918e268272de15ac151aasrs// unused. 205608bb0da07953af605b4918e268272de15ac151aasrsint GPTData::FindFirstFreePart(void) { 205708bb0da07953af605b4918e268272de15ac151aasrs int i = 0; 205808bb0da07953af605b4918e268272de15ac151aasrs 205908bb0da07953af605b4918e268272de15ac151aasrs if (partitions != NULL) { 20609a46b042c57144c26a67781d335e6ba4128382d2srs while ((i < (int) numParts) && (partitions[i].IsUsed())) 206108bb0da07953af605b4918e268272de15ac151aasrs i++; 20620283dae41a7db4563be0fe62241ed230e4a101c0srs if (i >= (int) numParts) 206308bb0da07953af605b4918e268272de15ac151aasrs i = -1; 206408bb0da07953af605b4918e268272de15ac151aasrs } else i = -1; 206508bb0da07953af605b4918e268272de15ac151aasrs return i; 206608bb0da07953af605b4918e268272de15ac151aasrs} // GPTData::FindFirstFreePart() 206708bb0da07953af605b4918e268272de15ac151aasrs 2068978041ca613dcb881763b36cf53639d924e52a56srs// Returns the number of defined partitions. 2069978041ca613dcb881763b36cf53639d924e52a56srsuint32_t GPTData::CountParts(void) { 2070e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t i, counted = 0; 2071978041ca613dcb881763b36cf53639d924e52a56srs 20720283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 207308bb0da07953af605b4918e268272de15ac151aasrs if (partitions[i].IsUsed()) 2074978041ca613dcb881763b36cf53639d924e52a56srs counted++; 2075978041ca613dcb881763b36cf53639d924e52a56srs } // for 2076978041ca613dcb881763b36cf53639d924e52a56srs return counted; 2077978041ca613dcb881763b36cf53639d924e52a56srs} // GPTData::CountParts() 2078978041ca613dcb881763b36cf53639d924e52a56srs 2079e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/**************************************************** 2080e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2081e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Functions that return data about disk free space * 2082e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2083e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ****************************************************/ 20842a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2085e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find the first available block after the starting point; returns 0 if 2086e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// there are no available blocks left 2087e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsuint64_t GPTData::FindFirstAvailable(uint64_t start) { 2088e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t first; 2089e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2090e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int firstMoved = 0; 2091e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2092e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Begin from the specified starting point or from the first usable 2093e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // LBA, whichever is greater... 2094e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (start < mainHeader.firstUsableLBA) 2095e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = mainHeader.firstUsableLBA; 2096e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs else 2097e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = start; 20982a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2099e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // ...now search through all partitions; if first is within an 2100e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // existing partition, move it to the next sector after that 2101e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // partition and repeat. If first was moved, set firstMoved 2102e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // flag; repeat until firstMoved is not set, so as to catch 2103e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // cases where partitions are out of sequential order.... 2104e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 2105e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs firstMoved = 0; 21060283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2107e69e6807cf84fe2b80c48475531ce4bd09563bbasrs if ((partitions[i].IsUsed()) && (first >= partitions[i].GetFirstLBA()) && 210855d926192adc984462509b2966e23bc0d1129bbdsrs (first <= partitions[i].GetLastLBA())) { // in existing part. 2109e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = partitions[i].GetLastLBA() + 1; 2110e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs firstMoved = 1; 211155d926192adc984462509b2966e23bc0d1129bbdsrs } // if 2112e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 2113e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } while (firstMoved == 1); 2114e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (first > mainHeader.lastUsableLBA) 2115e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs first = 0; 2116e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (first); 2117e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindFirstAvailable() 2118e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2119e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Finds the first available sector in the largest block of unallocated 2120e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// space on the disk. Returns 0 if there are no available blocks left 2121e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsuint64_t GPTData::FindFirstInLargest(void) { 2122e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs uint64_t start, firstBlock, lastBlock, segmentSize, selectedSize = 0, selectedSegment = 0; 2123e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2124e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs start = 0; 2125e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 2126e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs firstBlock = FindFirstAvailable(start); 2127e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (firstBlock != UINT32_C(0)) { // something's free... 2128e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs lastBlock = FindLastInFree(firstBlock); 2129e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs segmentSize = lastBlock - firstBlock + UINT32_C(1); 2130e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (segmentSize > selectedSize) { 2131e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs selectedSize = segmentSize; 2132e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs selectedSegment = firstBlock; 2133e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2134e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs start = lastBlock + 1; 2135e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 2136e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } while (firstBlock != 0); 2137e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return selectedSegment; 2138e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindFirstInLargest() 2139e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2140cb76c673eeb84344887715d36d44b799042be5a5srs// Find the last available block on the disk. 2141f5dfbfa418675ca862408e4fb2240b21dd07d558srs// Returns 0 if there are no available sectors 2142cb76c673eeb84344887715d36d44b799042be5a5srsuint64_t GPTData::FindLastAvailable(void) { 2143e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t last; 2144e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2145e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int lastMoved = 0; 21462a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2147e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // Start by assuming the last usable LBA is available.... 2148e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs last = mainHeader.lastUsableLBA; 2149e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2150e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // ...now, similar to algorithm in FindFirstAvailable(), search 2151e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // through all partitions, moving last when it's in an existing 2152e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // partition. Set the lastMoved flag so we repeat to catch cases 2153e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs // where partitions are out of logical order. 2154e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs do { 2155e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs lastMoved = 0; 21560283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2157e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((last >= partitions[i].GetFirstLBA()) && 215855d926192adc984462509b2966e23bc0d1129bbdsrs (last <= partitions[i].GetLastLBA())) { // in existing part. 2159e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs last = partitions[i].GetFirstLBA() - 1; 2160e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs lastMoved = 1; 216155d926192adc984462509b2966e23bc0d1129bbdsrs } // if 2162e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 2163e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } while (lastMoved == 1); 2164e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if (last < mainHeader.firstUsableLBA) 2165e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs last = 0; 2166e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (last); 2167e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindLastAvailable() 2168e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2169e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Find the last available block in the free space pointed to by start. 2170e4ac11ebee0ad586a538f49b9c0e32ad19cae665srsuint64_t GPTData::FindLastInFree(uint64_t start) { 2171e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t nearestStart; 2172e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2173c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 2174e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs nearestStart = mainHeader.lastUsableLBA; 21750283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2176e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((nearestStart > partitions[i].GetFirstLBA()) && 217755d926192adc984462509b2966e23bc0d1129bbdsrs (partitions[i].GetFirstLBA() > start)) { 2178e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs nearestStart = partitions[i].GetFirstLBA() - 1; 217955d926192adc984462509b2966e23bc0d1129bbdsrs } // if 2180c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs } // for 2181e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return (nearestStart); 2182e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindLastInFree() 2183c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 2184e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// Finds the total number of free blocks, the number of segments in which 2185e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs// they reside, and the size of the largest of those segments 2186e321d444dcca514cf6b53459e388ddcbaab6176csrsuint64_t GPTData::FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment) { 2187e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t start = UINT64_C(0); // starting point for each search 2188e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t totalFound = UINT64_C(0); // running total 2189e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t firstBlock; // first block in a segment 2190e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t lastBlock; // last block in a segment 2191e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint64_t segmentSize; // size of segment in blocks 2192e321d444dcca514cf6b53459e388ddcbaab6176csrs uint32_t num = 0; 2193e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 2194e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *largestSegment = UINT64_C(0); 2195c54e9b406255a81cca066dacf127d587b9dd36e1srs if (diskSize > 0) { 2196c54e9b406255a81cca066dacf127d587b9dd36e1srs do { 2197c54e9b406255a81cca066dacf127d587b9dd36e1srs firstBlock = FindFirstAvailable(start); 2198c54e9b406255a81cca066dacf127d587b9dd36e1srs if (firstBlock != UINT64_C(0)) { // something's free... 2199c54e9b406255a81cca066dacf127d587b9dd36e1srs lastBlock = FindLastInFree(firstBlock); 2200c54e9b406255a81cca066dacf127d587b9dd36e1srs segmentSize = lastBlock - firstBlock + UINT64_C(1); 2201c54e9b406255a81cca066dacf127d587b9dd36e1srs if (segmentSize > *largestSegment) { 2202c54e9b406255a81cca066dacf127d587b9dd36e1srs *largestSegment = segmentSize; 2203c54e9b406255a81cca066dacf127d587b9dd36e1srs } // if 2204c54e9b406255a81cca066dacf127d587b9dd36e1srs totalFound += segmentSize; 2205c54e9b406255a81cca066dacf127d587b9dd36e1srs num++; 2206c54e9b406255a81cca066dacf127d587b9dd36e1srs start = lastBlock + 1; 2207e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // if 2208c54e9b406255a81cca066dacf127d587b9dd36e1srs } while (firstBlock != 0); 2209c54e9b406255a81cca066dacf127d587b9dd36e1srs } // if 2210e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs *numSegments = num; 2211e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs return totalFound; 2212e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::FindFreeBlocks() 2213e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 221455d926192adc984462509b2966e23bc0d1129bbdsrs// Returns 1 if sector is unallocated, 0 if it's allocated to a partition. 221555d926192adc984462509b2966e23bc0d1129bbdsrs// If it's allocated, return the partition number to which it's allocated 221655d926192adc984462509b2966e23bc0d1129bbdsrs// in partNum, if that variable is non-NULL. (A value of UINT32_MAX is 221755d926192adc984462509b2966e23bc0d1129bbdsrs// returned in partNum if the sector is in use by basic GPT data structures.) 221855d926192adc984462509b2966e23bc0d1129bbdsrsint GPTData::IsFree(uint64_t sector, uint32_t *partNum) { 2219e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs int isFree = 1; 2220e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs uint32_t i; 2221e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 22220283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2223e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs if ((sector >= partitions[i].GetFirstLBA()) && 2224e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs (sector <= partitions[i].GetLastLBA())) { 2225e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs isFree = 0; 222655d926192adc984462509b2966e23bc0d1129bbdsrs if (partNum != NULL) 222755d926192adc984462509b2966e23bc0d1129bbdsrs *partNum = i; 222808bb0da07953af605b4918e268272de15ac151aasrs } // if 2229e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs } // for 2230e35eb1beb6381977ff0dd8443d91f4569779cf2dsrs if ((sector < mainHeader.firstUsableLBA) || 2231e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs (sector > mainHeader.lastUsableLBA)) { 2232e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs isFree = 0; 223355d926192adc984462509b2966e23bc0d1129bbdsrs if (partNum != NULL) 223455d926192adc984462509b2966e23bc0d1129bbdsrs *partNum = UINT32_MAX; 223508bb0da07953af605b4918e268272de15ac151aasrs } // if 223608bb0da07953af605b4918e268272de15ac151aasrs return (isFree); 2237e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs} // GPTData::IsFree() 2238e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 2239815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// Returns 1 if partNum is unused AND if it's a legal value. 2240ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srsint GPTData::IsFreePartNum(uint32_t partNum) { 224101f7f08624f0c942001977415214a578621f6495srs return ((partNum < numParts) && (partitions != NULL) && 224201f7f08624f0c942001977415214a578621f6495srs (!partitions[partNum].IsUsed())); 2243ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs} // GPTData::IsFreePartNum() 2244ba00fed2efd6c0cba60da9afb0ce3dff84fc69f9srs 2245815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// Returns 1 if partNum is in use. 2246815fb65195106b8afe1b8dfec5dae605dbd7ccbesrsint GPTData::IsUsedPartNum(uint32_t partNum) { 2247815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs return ((partNum < numParts) && (partitions != NULL) && 2248815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs (partitions[partNum].IsUsed())); 2249815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs} // GPTData::IsUsedPartNum() 2250a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2251a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs/*********************************************************** 2252a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs * * 2253a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs * Change how functions work or return information on them * 2254a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs * * 2255a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs ***********************************************************/ 2256a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2257a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// Set partition alignment value; partitions will begin on multiples of 2258a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// the specified value 2259a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srsvoid GPTData::SetAlignment(uint32_t n) { 22600873e9d0e9345a2c4418b4718db525c9f1111c83srs if (n > 0) 22610873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = n; 22620873e9d0e9345a2c4418b4718db525c9f1111c83srs else 22630873e9d0e9345a2c4418b4718db525c9f1111c83srs cerr << "Attempt to set partition alignment to 0!\n"; 2264a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs} // GPTData::SetAlignment() 2265a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2266a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// Compute sector alignment based on the current partitions (if any). Each 2267a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// partition's starting LBA is examined, and if it's divisible by a power-of-2 22680873e9d0e9345a2c4418b4718db525c9f1111c83srs// value less than or equal to the DEFAULT_ALIGNMENT value (adjusted for the 22690873e9d0e9345a2c4418b4718db525c9f1111c83srs// sector size), but not by the previously-located alignment value, then the 22700873e9d0e9345a2c4418b4718db525c9f1111c83srs// alignment value is adjusted down. If the computed alignment is less than 8 22710873e9d0e9345a2c4418b4718db525c9f1111c83srs// and the disk is bigger than SMALLEST_ADVANCED_FORMAT, resets it to 8. This 2272d8eed4629449a325999808a0170dbda53bd4a6dfsrs// is a safety measure for Advanced Format drives. If no partitions are 2273d8eed4629449a325999808a0170dbda53bd4a6dfsrs// defined, the alignment value is set to DEFAULT_ALIGNMENT (2048) (or an 22740873e9d0e9345a2c4418b4718db525c9f1111c83srs// adjustment of that based on the current sector size). The result is that new 22758a4ddfc919d5569c68489cf53d9cf5abc94c410csrs// drives are aligned to 2048-sector multiples but the program won't complain 22768a4ddfc919d5569c68489cf53d9cf5abc94c410csrs// about other alignments on existing disks unless a smaller-than-8 alignment 2277d8eed4629449a325999808a0170dbda53bd4a6dfsrs// is used on big disks (as safety for Advanced Format drives). 2278a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs// Returns the computed alignment value. 2279a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srsuint32_t GPTData::ComputeAlignment(void) { 2280a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs uint32_t i = 0, found, exponent = 31; 2281ab4b0438394df4ae6bdea86194e254d7d35fdea0srs uint32_t align = DEFAULT_ALIGNMENT; 2282a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 22830873e9d0e9345a2c4418b4718db525c9f1111c83srs if (blockSize > 0) 22840873e9d0e9345a2c4418b4718db525c9f1111c83srs align = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize; 22850873e9d0e9345a2c4418b4718db525c9f1111c83srs exponent = (uint32_t) log2(align); 22860283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2287a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs if (partitions[i].IsUsed()) { 2288a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs found = 0; 2289a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs while (!found) { 22900873e9d0e9345a2c4418b4718db525c9f1111c83srs align = UINT64_C(1) << exponent; 2291a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs if ((partitions[i].GetFirstLBA() % align) == 0) { 2292a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs found = 1; 2293a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } else { 2294a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs exponent--; 2295a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // if/else 2296a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // while 2297a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // if 2298a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs } // for 22990873e9d0e9345a2c4418b4718db525c9f1111c83srs if ((align < MIN_AF_ALIGNMENT) && (diskSize >= SMALLEST_ADVANCED_FORMAT)) 23000873e9d0e9345a2c4418b4718db525c9f1111c83srs align = MIN_AF_ALIGNMENT; 23010873e9d0e9345a2c4418b4718db525c9f1111c83srs sectorAlignment = align; 2302a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs return align; 2303a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs} // GPTData::ComputeAlignment() 2304a8582cfe6c1aa5e5f80458ac72d881a04ae0ba44srs 2305e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs/******************************** 2306e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2307e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * Endianness support functions * 2308e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs * * 2309e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs ********************************/ 2310c0ca8f877e775a54008b27d92deefdb41bfaea5dsrs 23112a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srsvoid GPTData::ReverseHeaderBytes(struct GPTHeader* header) { 2312221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->signature, 8); 2313221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->revision, 4); 2314221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->headerSize, 4); 2315221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->headerCRC, 4); 2316221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->reserved, 4); 2317221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->currentLBA, 8); 2318221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->backupLBA, 8); 2319221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->firstUsableLBA, 8); 2320221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->lastUsableLBA, 8); 2321221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->partitionEntriesLBA, 8); 2322221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->numParts, 4); 2323221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->sizeOfPartitionEntries, 4); 2324221e08768de7fe42ba533ca22baf671420569c07srs ReverseBytes(&header->partitionEntriesCRC, 4); 232508bb0da07953af605b4918e268272de15ac151aasrs ReverseBytes(header->reserved2, GPT_RESERVED); 23262a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs} // GPTData::ReverseHeaderBytes() 23272a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 23280283dae41a7db4563be0fe62241ed230e4a101c0srs// Reverse byte order for all partitions. 23292a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srsvoid GPTData::ReversePartitionBytes() { 23302a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs uint32_t i; 23312a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 23320283dae41a7db4563be0fe62241ed230e4a101c0srs for (i = 0; i < numParts; i++) { 2333221e08768de7fe42ba533ca22baf671420569c07srs partitions[i].ReversePartBytes(); 23342a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs } // for 23352a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs} // GPTData::ReversePartitionBytes() 23362a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 23379ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Validate partition number 23389ddc14bb9b154518e2b8384d3f4571cf657c7920srsbool GPTData::ValidPartNum (const uint32_t partNum) { 23399ddc14bb9b154518e2b8384d3f4571cf657c7920srs if (partNum >= numParts) { 23405a081757ea2e32a491349544fea92826ccf739f6srs cerr << "Partition number out of range: " << partNum << "\n"; 23419ddc14bb9b154518e2b8384d3f4571cf657c7920srs return false; 23429ddc14bb9b154518e2b8384d3f4571cf657c7920srs } // if 23439ddc14bb9b154518e2b8384d3f4571cf657c7920srs return true; 23449ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::ValidPartNum 23459ddc14bb9b154518e2b8384d3f4571cf657c7920srs 23465a081757ea2e32a491349544fea92826ccf739f6srs// Return a single partition for inspection (not modification!) by other 23475a081757ea2e32a491349544fea92826ccf739f6srs// functions. 23485a081757ea2e32a491349544fea92826ccf739f6srsconst GPTPart & GPTData::operator[](uint32_t partNum) const { 23495a081757ea2e32a491349544fea92826ccf739f6srs if (partNum >= numParts) { 2350815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cerr << "Partition number out of range (" << partNum << " requested, but only " 2351815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs << numParts << " available)\n"; 2352815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs exit(1); 2353815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs } // if 2354815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs if (partitions == NULL) { 2355815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs cerr << "No partitions defined in GPTData::operator[]; fatal error!\n"; 2356815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs exit(1); 23575a081757ea2e32a491349544fea92826ccf739f6srs } // if 23585a081757ea2e32a491349544fea92826ccf739f6srs return partitions[partNum]; 23595a081757ea2e32a491349544fea92826ccf739f6srs} // operator[] 23605a081757ea2e32a491349544fea92826ccf739f6srs 23615a081757ea2e32a491349544fea92826ccf739f6srs// Return (not for modification!) the disk's GUID value 23625a081757ea2e32a491349544fea92826ccf739f6srsconst GUIDData & GPTData::GetDiskGUID(void) const { 23635a081757ea2e32a491349544fea92826ccf739f6srs return mainHeader.diskGUID; 23645a081757ea2e32a491349544fea92826ccf739f6srs} // GPTData::GetDiskGUID() 23655a081757ea2e32a491349544fea92826ccf739f6srs 23669ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Manage attributes for a partition, based on commands passed to this function. 23679ddc14bb9b154518e2b8384d3f4571cf657c7920srs// (Function is non-interactive.) 23689ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Returns 1 if a modification command succeeded, 0 if the command should not have 23699ddc14bb9b154518e2b8384d3f4571cf657c7920srs// modified data, and -1 if a modification command failed. 23709ddc14bb9b154518e2b8384d3f4571cf657c7920srsint GPTData::ManageAttributes(int partNum, const string & command, const string & bits) { 23719ddc14bb9b154518e2b8384d3f4571cf657c7920srs int retval = 0; 23729ddc14bb9b154518e2b8384d3f4571cf657c7920srs Attributes theAttr; 23739ddc14bb9b154518e2b8384d3f4571cf657c7920srs 237424bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (partNum >= (int) numParts) { 237524bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith cerr << "Invalid partition number (" << partNum + 1 << ")\n"; 237624bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith retval = -1; 23779ddc14bb9b154518e2b8384d3f4571cf657c7920srs } else { 237824bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (command == "show") { 237924bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith ShowAttributes(partNum); 238024bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } else if (command == "get") { 238124bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith GetAttribute(partNum, bits); 23829ddc14bb9b154518e2b8384d3f4571cf657c7920srs } else { 238324bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith theAttr = partitions[partNum].GetAttributes(); 238424bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (theAttr.OperateOnAttributes(partNum, command, bits)) { 238524bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith partitions[partNum].SetAttributes(theAttr.GetAttributes()); 238624bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith retval = 1; 238724bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } else { 238824bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith retval = -1; 238924bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } // if/else 239024bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } // if/elseif/else 239124bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith } // if/else invalid partition # 23929ddc14bb9b154518e2b8384d3f4571cf657c7920srs 23939ddc14bb9b154518e2b8384d3f4571cf657c7920srs return retval; 23949ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::ManageAttributes() 23959ddc14bb9b154518e2b8384d3f4571cf657c7920srs 23969ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Show all attributes for a specified partition.... 23979ddc14bb9b154518e2b8384d3f4571cf657c7920srsvoid GPTData::ShowAttributes(const uint32_t partNum) { 239824bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if ((partNum < numParts) && partitions[partNum].IsUsed()) 2399e69e6807cf84fe2b80c48475531ce4bd09563bbasrs partitions[partNum].ShowAttributes(partNum); 24009ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::ShowAttributes 24019ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24029ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Show whether a single attribute bit is set (terse output)... 24039ddc14bb9b154518e2b8384d3f4571cf657c7920srsvoid GPTData::GetAttribute(const uint32_t partNum, const string& attributeBits) { 240424bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith if (partNum < numParts) 240524bba6e4f3a57cd8b4812c1976190356919d9c47Roderick W. Smith partitions[partNum].GetAttributes().OperateOnAttributes(partNum, "get", attributeBits); 24069ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // GPTData::GetAttribute 24079ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24089ddc14bb9b154518e2b8384d3f4571cf657c7920srs 24092a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs/****************************************** 24102a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs * * 24112a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs * Additional non-class support functions * 24122a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs * * 24132a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs ******************************************/ 24142a9f5da3c3c4ccccd291462bda9d2aefcd485ff8srs 2415e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Check to be sure that data type sizes are correct. The basic types (uint*_t) should 2416e7b4ff9317fc4e551cf974684eaa88697de5a28srs// never fail these tests, but the struct types may fail depending on compile options. 2417e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Specifically, the -fpack-struct option to gcc may be required to ensure proper structure 2418e7b4ff9317fc4e551cf974684eaa88697de5a28srs// sizes. 2419e7b4ff9317fc4e551cf974684eaa88697de5a28srsint SizesOK(void) { 2420e7b4ff9317fc4e551cf974684eaa88697de5a28srs int allOK = 1; 2421e7b4ff9317fc4e551cf974684eaa88697de5a28srs 2422e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint8_t) != 1) { 2423fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint8_t is " << sizeof(uint8_t) << " bytes, should be 1 byte; aborting!\n"; 2424e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2425e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2426e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint16_t) != 2) { 2427fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint16_t is " << sizeof(uint16_t) << " bytes, should be 2 bytes; aborting!\n"; 2428e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2429e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2430e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint32_t) != 4) { 2431fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint32_t is " << sizeof(uint32_t) << " bytes, should be 4 bytes; aborting!\n"; 2432e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2433e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2434e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(uint64_t) != 8) { 2435fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "uint64_t is " << sizeof(uint64_t) << " bytes, should be 8 bytes; aborting!\n"; 2436e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2437e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2438e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(struct MBRRecord) != 16) { 2439fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "MBRRecord is " << sizeof(MBRRecord) << " bytes, should be 16 bytes; aborting!\n"; 2440e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2441e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2442978041ca613dcb881763b36cf53639d924e52a56srs if (sizeof(struct TempMBR) != 512) { 2443fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "TempMBR is " << sizeof(TempMBR) << " bytes, should be 512 bytes; aborting!\n"; 2444e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2445e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 2446e7b4ff9317fc4e551cf974684eaa88697de5a28srs if (sizeof(struct GPTHeader) != 512) { 2447fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "GPTHeader is " << sizeof(GPTHeader) << " bytes, should be 512 bytes; aborting!\n"; 2448221e08768de7fe42ba533ca22baf671420569c07srs allOK = 0; 2449221e08768de7fe42ba533ca22baf671420569c07srs } // if 2450221e08768de7fe42ba533ca22baf671420569c07srs if (sizeof(GPTPart) != 128) { 2451fed16d043a14e8b86c97a6413aec7281fefcbcb5srs cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n"; 2452e7b4ff9317fc4e551cf974684eaa88697de5a28srs allOK = 0; 2453e7b4ff9317fc4e551cf974684eaa88697de5a28srs } // if 24546699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if (sizeof(GUIDData) != 16) { 24556699b01eda84d24bfaf80ad725304fef2b0e1b2asrs cerr << "GUIDData is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n"; 24566699b01eda84d24bfaf80ad725304fef2b0e1b2asrs allOK = 0; 24576699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 24586699b01eda84d24bfaf80ad725304fef2b0e1b2asrs if (sizeof(PartType) != 16) { 245984aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith cerr << "PartType is " << sizeof(PartType) << " bytes, should be 16 bytes; aborting!\n"; 24606699b01eda84d24bfaf80ad725304fef2b0e1b2asrs allOK = 0; 24616699b01eda84d24bfaf80ad725304fef2b0e1b2asrs } // if 2462e7b4ff9317fc4e551cf974684eaa88697de5a28srs return (allOK); 2463e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // SizesOK() 2464e4ac11ebee0ad586a538f49b9c0e32ad19cae665srs 2465