| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1 | /* gpt.cc -- Functions for loading, saving, and manipulating legacy MBR and GPT partition | 
 | 2 |    data. */ | 
 | 3 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 4 | /* By Rod Smith, initial coding January to February, 2009 */ | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 5 |  | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 6 | /* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed | 
 | 7 |   under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ | 
 | 8 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 9 | #define __STDC_LIMIT_MACROS | 
 | 10 | #define __STDC_CONSTANT_MACROS | 
 | 11 |  | 
 | 12 | #include <stdio.h> | 
 | 13 | #include <unistd.h> | 
 | 14 | #include <stdlib.h> | 
 | 15 | #include <stdint.h> | 
 | 16 | #include <fcntl.h> | 
 | 17 | #include <string.h> | 
 | 18 | #include <time.h> | 
 | 19 | #include <sys/stat.h> | 
 | 20 | #include <errno.h> | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 21 | #include <iostream> | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 22 | #include "crc32.h" | 
 | 23 | #include "gpt.h" | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 24 | #include "bsd.h" | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 25 | #include "support.h" | 
 | 26 | #include "parttypes.h" | 
 | 27 | #include "attributes.h" | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 28 | #include "diskio.h" | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 29 |  | 
 | 30 | using namespace std; | 
 | 31 |  | 
 | 32 | /**************************************** | 
 | 33 |  *                                      * | 
 | 34 |  * GPTData class and related structures * | 
 | 35 |  *                                      * | 
 | 36 |  ****************************************/ | 
 | 37 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 38 | // Default constructor | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 39 | GPTData::GPTData(void) { | 
 | 40 |    blockSize = SECTOR_SIZE; // set a default | 
 | 41 |    diskSize = 0; | 
 | 42 |    partitions = NULL; | 
 | 43 |    state = gpt_valid; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 44 |    device = ""; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 45 |    justLooking = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 46 |    mainCrcOk = 0; | 
 | 47 |    secondCrcOk = 0; | 
 | 48 |    mainPartsCrcOk = 0; | 
 | 49 |    secondPartsCrcOk = 0; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 50 |    apmFound = 0; | 
 | 51 |    bsdFound = 0; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 52 |    sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 53 |    beQuiet = 0; | 
 | 54 |    whichWasUsed = use_new; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 55 |    srand((unsigned int) time(NULL)); | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 56 |    mainHeader.numParts = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 57 |    SetGPTSize(NUM_GPT_ENTRIES); | 
 | 58 | } // GPTData default constructor | 
 | 59 |  | 
 | 60 | // The following constructor loads GPT data from a device file | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 61 | GPTData::GPTData(string filename) { | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 62 |    blockSize = SECTOR_SIZE; // set a default | 
 | 63 |    diskSize = 0; | 
 | 64 |    partitions = NULL; | 
 | 65 |    state = gpt_invalid; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 66 |    device = ""; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 67 |    justLooking = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 68 |    mainCrcOk = 0; | 
 | 69 |    secondCrcOk = 0; | 
 | 70 |    mainPartsCrcOk = 0; | 
 | 71 |    secondPartsCrcOk = 0; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 72 |    apmFound = 0; | 
 | 73 |    bsdFound = 0; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 74 |    sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 75 |    beQuiet = 0; | 
 | 76 |    whichWasUsed = use_new; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 77 |    srand((unsigned int) time(NULL)); | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 78 |    mainHeader.numParts = 0; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 79 |    if (!LoadPartitions(filename)) | 
 | 80 |       exit(2); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 81 | } // GPTData(string filename) constructor | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 82 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 83 | // Destructor | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 84 | GPTData::~GPTData(void) { | 
 | 85 |    free(partitions); | 
 | 86 | } // GPTData destructor | 
 | 87 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 88 | /********************************************************************* | 
 | 89 |  *                                                                   * | 
 | 90 |  * Begin functions that verify data, or that adjust the verification * | 
 | 91 |  * information (compute CRCs, rebuild headers)                       * | 
 | 92 |  *                                                                   * | 
 | 93 |  *********************************************************************/ | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 94 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 95 | // Perform detailed verification, reporting on any problems found, but | 
 | 96 | // do *NOT* recover from these problems. Returns the total number of | 
 | 97 | // problems identified. | 
 | 98 | int GPTData::Verify(void) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 99 |    int problems = 0; | 
 | 100 |    uint32_t i, numSegments; | 
 | 101 |    uint64_t totalFree, largestSegment; | 
 | 102 |    char siTotal[255], siLargest[255]; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 103 |  | 
 | 104 |    // First, check for CRC errors in the GPT data.... | 
 | 105 |    if (!mainCrcOk) { | 
 | 106 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 107 |       cout << "\nProblem: The CRC for the main GPT header is invalid. The main GPT header may\n" | 
 | 108 |            << "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n" | 
 | 109 |            << "header ('b' on the recovery & transformation menu). This report may be a false\n" | 
 | 110 |            << "alarm if you've already corrected other problems.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 111 |    } // if | 
 | 112 |    if (!mainPartsCrcOk) { | 
 | 113 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 114 |       cout << "\nProblem: The CRC for the main partition table is invalid. This table may be\n" | 
 | 115 |            << "corrupt. Consider loading the backup partition table ('c' on the recovery &\n" | 
 | 116 |            << "transformation menu). This report may be a false alarm if you've already\n" | 
 | 117 |            << "corrected other problems.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 118 |    } // if | 
 | 119 |    if (!secondCrcOk) { | 
 | 120 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 121 |       cout << "\nProblem: The CRC for the backup GPT header is invalid. The backup GPT header\n" | 
 | 122 |            << "may be corrupt. Consider using the main GPT header to rebuild the backup GPT\n" | 
 | 123 |            << "header ('d' on the recovery & transformation menu). This report may be a false\n" | 
 | 124 |            << "alarm if you've already corrected other problems.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 125 |    } // if | 
 | 126 |    if (!secondPartsCrcOk) { | 
 | 127 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 128 |       cout << "\nCaution: The CRC for the backup partition table is invalid. This table may\n" | 
 | 129 |            << "be corrupt. This program will automatically create a new backup partition\n" | 
 | 130 |            << "table when you save your partitions.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 131 |    } // if | 
 | 132 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 133 |    // Now check that the main and backup headers both point to themselves.... | 
 | 134 |    if (mainHeader.currentLBA != 1) { | 
 | 135 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 136 |       cout << "\nProblem: The main header's self-pointer doesn't point to itself. This problem\n" | 
 | 137 |            << "is being automatically corrected, but it may be a symptom of more serious\n" | 
 | 138 |            << "problems. Think carefully before saving changes with 'w' or using this disk.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 139 |       mainHeader.currentLBA = 1; | 
 | 140 |    } // if | 
 | 141 |    if (secondHeader.currentLBA != (diskSize - UINT64_C(1))) { | 
 | 142 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 143 |       cout << "\nProblem: The secondary header's self-pointer indicates that it doesn't reside\n" | 
 | 144 |            << "at the end of the disk. If you've added a disk to a RAID array, use the 'e'\n" | 
 | 145 |            << "option on the experts' menu to adjust the secondary header's and partition\n" | 
 | 146 |            << "table's locations.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 147 |    } // if | 
 | 148 |  | 
 | 149 |    // Now check that critical main and backup GPT entries match each other | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 150 |    if (mainHeader.currentLBA != secondHeader.backupLBA) { | 
 | 151 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 152 |       cout << "\nProblem: main GPT header's current LBA pointer (" << mainHeader.currentLBA | 
 | 153 |            << ") doesn't\nmatch the backup GPT header's alternate LBA pointer(" | 
 | 154 |            << secondHeader.backupLBA << ").\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 155 |    } // if | 
 | 156 |    if (mainHeader.backupLBA != secondHeader.currentLBA) { | 
 | 157 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 158 |       cout << "\nProblem: main GPT header's backup LBA pointer (" << mainHeader.backupLBA | 
 | 159 |            << ") doesn't\nmatch the backup GPT header's current LBA pointer (" | 
 | 160 |            << secondHeader.currentLBA << ").\n" | 
 | 161 |            << "The 'e' option on the experts' menu may fix this problem.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 162 |    } // if | 
 | 163 |    if (mainHeader.firstUsableLBA != secondHeader.firstUsableLBA) { | 
 | 164 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 165 |       cout << "\nProblem: main GPT header's first usable LBA pointer (" << mainHeader.firstUsableLBA | 
 | 166 |            << ") doesn't\nmatch the backup GPT header's first usable LBA pointer (" | 
 | 167 |            << secondHeader.firstUsableLBA << ")\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 168 |    } // if | 
 | 169 |    if (mainHeader.lastUsableLBA != secondHeader.lastUsableLBA) { | 
 | 170 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 171 |       cout << "\nProblem: main GPT header's last usable LBA pointer (" << mainHeader.lastUsableLBA | 
 | 172 |            << ") doesn't\nmatch the backup GPT header's last usable LBA pointer (" | 
 | 173 |            << secondHeader.lastUsableLBA << ")\n" | 
 | 174 |            << "The 'e' option on the experts' menu can probably fix this problem.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 175 |    } // if | 
 | 176 |    if ((mainHeader.diskGUID.data1 != secondHeader.diskGUID.data1) || | 
 | 177 |         (mainHeader.diskGUID.data2 != secondHeader.diskGUID.data2)) { | 
 | 178 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 179 |       cout << "\nProblem: main header's disk GUID (" << GUIDToStr(mainHeader.diskGUID) | 
 | 180 |            << ") doesn't\nmatch the backup GPT header's disk GUID (" | 
 | 181 |            << GUIDToStr(secondHeader.diskGUID) << ")\n" | 
 | 182 |            << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" | 
 | 183 |            << "select one or the other header.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 184 |    } // if | 
 | 185 |    if (mainHeader.numParts != secondHeader.numParts) { | 
 | 186 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 187 |       cout << "\nProblem: main GPT header's number of partitions (" << mainHeader.numParts | 
 | 188 |            << ") doesn't\nmatch the backup GPT header's number of partitions (" | 
 | 189 |            << secondHeader.numParts << ")\n" | 
 | 190 |            << "Resizing the partition table ('s' on the experts' menu) may help.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 191 |    } // if | 
 | 192 |    if (mainHeader.sizeOfPartitionEntries != secondHeader.sizeOfPartitionEntries) { | 
 | 193 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 194 |       cout << "\nProblem: main GPT header's size of partition entries (" | 
 | 195 |            << mainHeader.sizeOfPartitionEntries << ") doesn't\n" | 
 | 196 |            << "match the backup GPT header's size of partition entries (" | 
 | 197 |            << secondHeader.sizeOfPartitionEntries << ")\n" | 
 | 198 |            << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" | 
 | 199 |            << "select one or the other header.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 200 |    } // if | 
 | 201 |  | 
 | 202 |    // Now check for a few other miscellaneous problems... | 
 | 203 |    // Check that the disk size will hold the data... | 
 | 204 |    if (mainHeader.backupLBA > diskSize) { | 
 | 205 |       problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 206 |       cout << "\nProblem: Disk is too small to hold all the data!\n" | 
 | 207 |            << "(Disk size is " << diskSize << " sectors, needs to be " | 
 | 208 |            << mainHeader.backupLBA << " sectors.)\n" | 
 | 209 |            << "The 'e' option on the experts' menu may fix this problem.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 210 |    } // if | 
 | 211 |  | 
 | 212 |    // Check for overlapping partitions.... | 
 | 213 |    problems += FindOverlaps(); | 
 | 214 |  | 
 | 215 |    // Check for mismatched MBR and GPT partitions... | 
 | 216 |    problems += FindHybridMismatches(); | 
 | 217 |  | 
 | 218 |    // Verify that partitions don't run into GPT data areas.... | 
 | 219 |    problems += CheckGPTSize(); | 
 | 220 |  | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 221 |    // Check that partitions are aligned on proper boundaries (for WD Advanced | 
 | 222 |    // Format and similar disks).... | 
 | 223 |    for (i = 0; i < mainHeader.numParts; i++) { | 
 | 224 |       if ((partitions[i].GetFirstLBA() % sectorAlignment) != 0) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 225 |          cout << "\nCaution: Partition " << i + 1 << " doesn't begin on a " | 
 | 226 |               << sectorAlignment << "-sector boundary. This may\nresult " | 
 | 227 |               << "in degraded performance on some modern (2009 and later) hard disks.\n"; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 228 |       } // if | 
 | 229 |    } // for | 
 | 230 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 231 |    // Now compute available space, but only if no problems found, since | 
 | 232 |    // problems could affect the results | 
 | 233 |    if (problems == 0) { | 
 | 234 |       totalFree = FindFreeBlocks(&numSegments, &largestSegment); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 235 |       strcpy(siTotal, BytesToSI(totalFree * (uint64_t) blockSize).c_str()); | 
 | 236 |       strcpy(siLargest, BytesToSI(largestSegment * (uint64_t) blockSize).c_str()); | 
 | 237 |       cout << "No problems found. " << totalFree << " free sectors (" | 
 | 238 |            << BytesToSI(totalFree * (uint64_t) blockSize) << ") available in " | 
 | 239 |            << numSegments << "\nsegments, the largest of which is " | 
 | 240 |            << largestSegment << " (" << BytesToSI(largestSegment * (uint64_t) blockSize) | 
 | 241 |            << ") in size\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 242 |    } else { | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 243 |       cout << "\nIdentified " << problems << " problems!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 244 |    } // if/else | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 245 |  | 
 | 246 |    return (problems); | 
 | 247 | } // GPTData::Verify() | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 248 |  | 
 | 249 | // Checks to see if the GPT tables overrun existing partitions; if they | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 250 | // do, issues a warning but takes no action. Returns number of problems | 
 | 251 | // detected (0 if OK, 1 to 2 if problems). | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 252 | int GPTData::CheckGPTSize(void) { | 
 | 253 |    uint64_t overlap, firstUsedBlock, lastUsedBlock; | 
 | 254 |    uint32_t i; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 255 |    int numProbs = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 256 |  | 
 | 257 |    // first, locate the first & last used blocks | 
 | 258 |    firstUsedBlock = UINT64_MAX; | 
 | 259 |    lastUsedBlock = 0; | 
 | 260 |    for (i = 0; i < mainHeader.numParts; i++) { | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 261 |       if ((partitions[i].GetFirstLBA() < firstUsedBlock) && | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 262 |            (partitions[i].GetFirstLBA() != 0)) | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 263 |          firstUsedBlock = partitions[i].GetFirstLBA(); | 
 | 264 |       if (partitions[i].GetLastLBA() > lastUsedBlock) | 
 | 265 |          lastUsedBlock = partitions[i].GetLastLBA(); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 266 |    } // for | 
 | 267 |  | 
 | 268 |    // If the disk size is 0 (the default), then it means that various | 
 | 269 |    // variables aren't yet set, so the below tests will be useless; | 
 | 270 |    // therefore we should skip everything | 
 | 271 |    if (diskSize != 0) { | 
 | 272 |       if (mainHeader.firstUsableLBA > firstUsedBlock) { | 
 | 273 |          overlap = mainHeader.firstUsableLBA - firstUsedBlock; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 274 |          cout << "Warning! Main partition table overlaps the first partition by " | 
 | 275 |               << overlap << " blocks!\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 276 |          if (firstUsedBlock > 2) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 277 |             cout << "Try reducing the partition table size by " << overlap * 4 | 
 | 278 |                  << " entries.\n(Use the 's' item on the experts' menu.)\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 279 |          } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 280 |             cout << "You will need to delete this partition or resize it in another utility.\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 281 |          } // if/else | 
 | 282 |          numProbs++; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 283 |       } // Problem at start of disk | 
 | 284 |       if (mainHeader.lastUsableLBA < lastUsedBlock) { | 
 | 285 |          overlap = lastUsedBlock - mainHeader.lastUsableLBA; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 286 |          cout << "Warning! Secondary partition table overlaps the last partition by " | 
 | 287 |               << overlap << " blocks!\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 288 |          if (lastUsedBlock > (diskSize - 2)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 289 |             cout << "You will need to delete this partition or resize it in another utility.\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 290 |          } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 291 |             cout << "Try reducing the partition table size by " << overlap * 4 | 
 | 292 |                  << " entries.\n(Use the 's' item on the experts' menu.)\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 293 |          } // if/else | 
 | 294 |          numProbs++; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 295 |       } // Problem at end of disk | 
 | 296 |    } // if (diskSize != 0) | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 297 |    return numProbs; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 298 | } // GPTData::CheckGPTSize() | 
 | 299 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 300 | // Check the validity of the GPT header. Returns 1 if the main header | 
 | 301 | // is valid, 2 if the backup header is valid, 3 if both are valid, and | 
 | 302 | // 0 if neither is valid. Note that this function just checks the GPT | 
 | 303 | // signature and revision numbers, not CRCs or other data. | 
 | 304 | int GPTData::CheckHeaderValidity(void) { | 
 | 305 |    int valid = 3; | 
 | 306 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 307 |    cout.setf(ios::uppercase); | 
 | 308 |    cout.fill('0'); | 
 | 309 |  | 
 | 310 |    // Note: failed GPT signature checks produce no error message because | 
 | 311 |    // a message is displayed in the ReversePartitionBytes() function | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 312 |    if (mainHeader.signature != GPT_SIGNATURE) { | 
 | 313 |       valid -= 1; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 314 |    } else if ((mainHeader.revision != 0x00010000) && valid) { | 
 | 315 |       valid -= 1; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 316 |       cout << "Unsupported GPT version in main header; read 0x"; | 
 | 317 |       cout.width(8); | 
 | 318 |       cout << hex << mainHeader.revision << ", should be\n0x"; | 
 | 319 |       cout.width(8); | 
 | 320 |       cout << UINT32_C(0x00010000) << dec << "\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 321 |    } // if/else/if | 
 | 322 |  | 
 | 323 |    if (secondHeader.signature != GPT_SIGNATURE) { | 
 | 324 |       valid -= 2; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 325 |    } else if ((secondHeader.revision != 0x00010000) && valid) { | 
 | 326 |       valid -= 2; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 327 |       cout << "Unsupported GPT version in backup header; read 0x"; | 
 | 328 |       cout.width(8); | 
 | 329 |       cout << hex << secondHeader.revision << ", should be\n0x"; | 
 | 330 |       cout.width(8); | 
 | 331 |       cout << UINT32_C(0x00010000) << dec << "\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 332 |    } // if/else/if | 
 | 333 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 334 |    // If MBR bad, check for an Apple disk signature | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 335 |    if ((protectiveMBR.GetValidity() == invalid) && | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 336 |         (((mainHeader.signature << 32) == APM_SIGNATURE1) || | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 337 |         (mainHeader.signature << 32) == APM_SIGNATURE2)) { | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 338 |       apmFound = 1; // Will display warning message later | 
| srs5694 | 3f2fe99 | 2009-11-24 18:28:18 -0500 | [diff] [blame] | 339 |    } // if | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 340 |    cout.fill(' '); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 341 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 342 |    return valid; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 343 | } // GPTData::CheckHeaderValidity() | 
 | 344 |  | 
 | 345 | // Check the header CRC to see if it's OK... | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 346 | // Note: Must be called BEFORE byte-order reversal on big-endian | 
 | 347 | // systems! | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 348 | int GPTData::CheckHeaderCRC(struct GPTHeader* header) { | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 349 |    uint32_t oldCRC, newCRC, hSize; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 350 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 351 |    // Back up old header CRC and then blank it, since it must be 0 for | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 352 |    // computation to be valid | 
 | 353 |    oldCRC = header->headerCRC; | 
 | 354 |    header->headerCRC = UINT32_C(0); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 355 |    hSize = header->headerSize; | 
 | 356 |  | 
 | 357 |    // If big-endian system, reverse byte order | 
 | 358 |    if (IsLittleEndian() == 0) { | 
 | 359 |       ReverseBytes(&oldCRC, 4); | 
 | 360 |    } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 361 |  | 
 | 362 |    // Initialize CRC functions... | 
 | 363 |    chksum_crc32gentab(); | 
 | 364 |  | 
 | 365 |    // Compute CRC, restore original, and return result of comparison | 
 | 366 |    newCRC = chksum_crc32((unsigned char*) header, HEADER_SIZE); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 367 |    header->headerCRC = oldCRC; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 368 |    return (oldCRC == newCRC); | 
 | 369 | } // GPTData::CheckHeaderCRC() | 
 | 370 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 371 | // Recompute all the CRCs. Must be called before saving (but after reversing | 
 | 372 | // byte order on big-endian systems) if any changes have been made. | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 373 | void GPTData::RecomputeCRCs(void) { | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 374 |    uint32_t crc, hSize, trueNumParts; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 375 |    int littleEndian = 1; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 376 |  | 
 | 377 |    // Initialize CRC functions... | 
 | 378 |    chksum_crc32gentab(); | 
 | 379 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 380 |    hSize = mainHeader.headerSize; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 381 |    littleEndian = IsLittleEndian(); | 
 | 382 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 383 |    // Compute CRC of partition tables & store in main and secondary headers | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 384 |    trueNumParts = mainHeader.numParts; | 
 | 385 |    if (littleEndian == 0) | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 386 |       ReverseBytes(&trueNumParts, 4); // unreverse this key piece of data.... | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 387 |    crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 388 |    mainHeader.partitionEntriesCRC = crc; | 
 | 389 |    secondHeader.partitionEntriesCRC = crc; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 390 |    if (littleEndian == 0) { | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 391 |       ReverseBytes(&mainHeader.partitionEntriesCRC, 4); | 
 | 392 |       ReverseBytes(&secondHeader.partitionEntriesCRC, 4); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 393 |    } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 394 |  | 
 | 395 |    // Zero out GPT tables' own CRCs (required for correct computation) | 
 | 396 |    mainHeader.headerCRC = 0; | 
 | 397 |    secondHeader.headerCRC = 0; | 
 | 398 |  | 
 | 399 |    // Compute & store CRCs of main & secondary headers... | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 400 |    crc = chksum_crc32((unsigned char*) &mainHeader, hSize); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 401 |    if (littleEndian == 0) | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 402 |       ReverseBytes(&crc, 4); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 403 |    mainHeader.headerCRC = crc; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 404 |    crc = chksum_crc32((unsigned char*) &secondHeader, hSize); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 405 |    if (littleEndian == 0) | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 406 |       ReverseBytes(&crc, 4); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 407 |    secondHeader.headerCRC = crc; | 
 | 408 | } // GPTData::RecomputeCRCs() | 
 | 409 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 410 | // Rebuild the main GPT header, using the secondary header as a model. | 
 | 411 | // Typically called when the main header has been found to be corrupt. | 
 | 412 | void GPTData::RebuildMainHeader(void) { | 
 | 413 |    int i; | 
 | 414 |  | 
 | 415 |    mainHeader.signature = GPT_SIGNATURE; | 
 | 416 |    mainHeader.revision = secondHeader.revision; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 417 |    mainHeader.headerSize = secondHeader.headerSize; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 418 |    mainHeader.headerCRC = UINT32_C(0); | 
 | 419 |    mainHeader.reserved = secondHeader.reserved; | 
 | 420 |    mainHeader.currentLBA = secondHeader.backupLBA; | 
 | 421 |    mainHeader.backupLBA = secondHeader.currentLBA; | 
 | 422 |    mainHeader.firstUsableLBA = secondHeader.firstUsableLBA; | 
 | 423 |    mainHeader.lastUsableLBA = secondHeader.lastUsableLBA; | 
 | 424 |    mainHeader.diskGUID.data1 = secondHeader.diskGUID.data1; | 
 | 425 |    mainHeader.diskGUID.data2 = secondHeader.diskGUID.data2; | 
 | 426 |    mainHeader.partitionEntriesLBA = UINT64_C(2); | 
 | 427 |    mainHeader.numParts = secondHeader.numParts; | 
 | 428 |    mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries; | 
 | 429 |    mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC; | 
 | 430 |    for (i = 0 ; i < GPT_RESERVED; i++) | 
 | 431 |       mainHeader.reserved2[i] = secondHeader.reserved2[i]; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 432 |    mainCrcOk = secondCrcOk; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 433 | } // GPTData::RebuildMainHeader() | 
 | 434 |  | 
 | 435 | // Rebuild the secondary GPT header, using the main header as a model. | 
 | 436 | void GPTData::RebuildSecondHeader(void) { | 
 | 437 |    int i; | 
 | 438 |  | 
 | 439 |    secondHeader.signature = GPT_SIGNATURE; | 
 | 440 |    secondHeader.revision = mainHeader.revision; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 441 |    secondHeader.headerSize = mainHeader.headerSize; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 442 |    secondHeader.headerCRC = UINT32_C(0); | 
 | 443 |    secondHeader.reserved = mainHeader.reserved; | 
 | 444 |    secondHeader.currentLBA = mainHeader.backupLBA; | 
 | 445 |    secondHeader.backupLBA = mainHeader.currentLBA; | 
 | 446 |    secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; | 
 | 447 |    secondHeader.lastUsableLBA = mainHeader.lastUsableLBA; | 
 | 448 |    secondHeader.diskGUID.data1 = mainHeader.diskGUID.data1; | 
 | 449 |    secondHeader.diskGUID.data2 = mainHeader.diskGUID.data2; | 
 | 450 |    secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); | 
 | 451 |    secondHeader.numParts = mainHeader.numParts; | 
 | 452 |    secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries; | 
 | 453 |    secondHeader.partitionEntriesCRC = mainHeader.partitionEntriesCRC; | 
 | 454 |    for (i = 0 ; i < GPT_RESERVED; i++) | 
 | 455 |       secondHeader.reserved2[i] = mainHeader.reserved2[i]; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 456 |    secondCrcOk = mainCrcOk; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 457 | } // GPTData::RebuildSecondHeader() | 
 | 458 |  | 
 | 459 | // Search for hybrid MBR entries that have no corresponding GPT partition. | 
 | 460 | // Returns number of such mismatches found | 
 | 461 | int GPTData::FindHybridMismatches(void) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 462 |    int i, found, numFound = 0; | 
 | 463 |    uint32_t j; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 464 |    uint64_t mbrFirst, mbrLast; | 
 | 465 |  | 
 | 466 |    for (i = 0; i < 4; i++) { | 
 | 467 |       if ((protectiveMBR.GetType(i) != 0xEE) && (protectiveMBR.GetType(i) != 0x00)) { | 
 | 468 |          j = 0; | 
 | 469 |          found = 0; | 
 | 470 |          do { | 
 | 471 |             mbrFirst = (uint64_t) protectiveMBR.GetFirstSector(i); | 
 | 472 |             mbrLast = mbrFirst + (uint64_t) protectiveMBR.GetLength(i) - UINT64_C(1); | 
 | 473 |             if ((partitions[j].GetFirstLBA() == mbrFirst) && | 
 | 474 |                 (partitions[j].GetLastLBA() == mbrLast)) | 
 | 475 |                found = 1; | 
 | 476 |             j++; | 
 | 477 |          } while ((!found) && (j < mainHeader.numParts)); | 
 | 478 |          if (!found) { | 
 | 479 |             numFound++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 480 |             cout << "\nWarning! Mismatched GPT and MBR partition! MBR partition " | 
 | 481 |                  << i + 1 << ", of type 0x"; | 
 | 482 |             cout.fill('0'); | 
 | 483 |             cout.setf(ios::uppercase); | 
 | 484 |             cout.width(2); | 
 | 485 |             cout << hex << (int) protectiveMBR.GetType(i) << ",\n" | 
 | 486 |                  << "has no corresponding GPT partition! You may continue, but this condition\n" | 
 | 487 |                  << "might cause data loss in the future!\a\n" << dec; | 
 | 488 |             cout.fill(' '); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 489 |          } // if | 
 | 490 |       } // if | 
 | 491 |    } // for | 
 | 492 |    return numFound; | 
 | 493 | } // GPTData::FindHybridMismatches | 
 | 494 |  | 
 | 495 | // Find overlapping partitions and warn user about them. Returns number of | 
 | 496 | // overlapping partitions. | 
 | 497 | int GPTData::FindOverlaps(void) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 498 |    int problems = 0; | 
 | 499 |    uint32_t i, j; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 500 |  | 
 | 501 |    for (i = 1; i < mainHeader.numParts; i++) { | 
 | 502 |       for (j = 0; j < i; j++) { | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 503 |          if (partitions[i].DoTheyOverlap(partitions[j])) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 504 |             problems++; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 505 |             cout << "\nProblem: partitions " << i + 1 << " and " << j + 1 << " overlap:\n"; | 
 | 506 |             cout << "  Partition " << i + 1 << ": " << partitions[i].GetFirstLBA() | 
 | 507 |                  << " to " << partitions[i].GetLastLBA() << "\n"; | 
 | 508 |             cout << "  Partition " << j + 1 << ": " << partitions[j].GetFirstLBA() | 
 | 509 |                  << " to " << partitions[j].GetLastLBA() << "\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 510 |          } // if | 
 | 511 |       } // for j... | 
 | 512 |    } // for i... | 
 | 513 |    return problems; | 
 | 514 | } // GPTData::FindOverlaps() | 
 | 515 |  | 
 | 516 | /****************************************************************** | 
 | 517 |  *                                                                * | 
 | 518 |  * Begin functions that load data from disk or save data to disk. * | 
 | 519 |  *                                                                * | 
 | 520 |  ******************************************************************/ | 
 | 521 |  | 
 | 522 | // Scan for partition data. This function loads the MBR data (regular MBR or | 
 | 523 | // protective MBR) and loads BSD disklabel data (which is probably invalid). | 
 | 524 | // It also looks for APM data, forces a load of GPT data, and summarizes | 
 | 525 | // the results. | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 526 | void GPTData::PartitionScan(void) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 527 |    BSDData bsdDisklabel; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 528 |  | 
 | 529 |    // Read the MBR & check for BSD disklabel | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 530 |    protectiveMBR.ReadMBRData(&myDisk); | 
 | 531 |    bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 532 |  | 
 | 533 |    // Load the GPT data, whether or not it's valid | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 534 |    ForceLoadGPTData(); | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 535 |  | 
 | 536 |    if (!beQuiet) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 537 |       cout << "Partition table scan:\n"; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 538 |       protectiveMBR.ShowState(); | 
 | 539 |       bsdDisklabel.ShowState(); | 
 | 540 |       ShowAPMState(); // Show whether there's an Apple Partition Map present | 
 | 541 |       ShowGPTState(); // Show GPT status | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 542 |       cout << "\n"; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 543 |    } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 544 |  | 
 | 545 |    if (apmFound) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 546 |       cout << "\n*******************************************************************\n" | 
 | 547 |            << "This disk appears to contain an Apple-format (APM) partition table!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 548 |       if (!justLooking) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 549 |          cout << "It will be destroyed if you continue!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 550 |       } // if | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 551 |       cout << "*******************************************************************\n\n\a"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 552 |    } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 553 | } // GPTData::PartitionScan() | 
 | 554 |  | 
 | 555 | // Read GPT data from a disk. | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 556 | int GPTData::LoadPartitions(const string & deviceFilename) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 557 |    int err, allOK = 1; | 
 | 558 |    uint32_t i; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 559 |    uint64_t firstBlock, lastBlock; | 
 | 560 |    BSDData bsdDisklabel; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 561 |    MBRValidity mbrState; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 562 |  | 
 | 563 |    // First, do a test to see if writing will be possible later.... | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 564 |    err = myDisk.OpenForWrite(deviceFilename); | 
 | 565 |    if ((err == 0) && (!justLooking)) { | 
 | 566 |       cout << "\aNOTE: Write test failed with error number " << errno | 
 | 567 |            << ". It will be impossible to save\nchanges to this disk's partition table!\n"; | 
| srs5694 | 7dbb932 | 2010-01-20 16:56:30 -0500 | [diff] [blame] | 568 | #ifdef __FreeBSD__ | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 569 |       cout << "You may be able to enable writes by exiting this program, typing\n" | 
 | 570 |            << "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n" | 
 | 571 |            << "program.\n"; | 
| srs5694 | 7dbb932 | 2010-01-20 16:56:30 -0500 | [diff] [blame] | 572 | #endif | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 573 |       cout << "\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 574 |    } // if | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 575 |    myDisk.Close(); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 576 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 577 |    if (myDisk.OpenForRead(deviceFilename)) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 578 |       // store disk information.... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 579 |       diskSize = myDisk.DiskSize(&err); | 
 | 580 |       blockSize = (uint32_t) myDisk.GetBlockSize(); | 
 | 581 |       sectorAlignment = myDisk.FindAlignment(); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 582 |       device = deviceFilename; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 583 |       PartitionScan(); // Check for partition types, load GPT, & print summary | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 584 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 585 |       whichWasUsed = UseWhichPartitions(); | 
 | 586 |       switch (whichWasUsed) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 587 |          case use_mbr: | 
 | 588 |             XFormPartitions(); | 
 | 589 |             break; | 
 | 590 |          case use_bsd: | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 591 |             bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 592 | //            bsdDisklabel.DisplayBSDData(); | 
 | 593 |             ClearGPTData(); | 
 | 594 |             protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1) | 
 | 595 |             XFormDisklabel(&bsdDisklabel, 0); | 
 | 596 |             break; | 
 | 597 |          case use_gpt: | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 598 |             mbrState = protectiveMBR.GetValidity(); | 
 | 599 |             if ((mbrState == invalid) || (mbrState == mbr)) | 
 | 600 |                protectiveMBR.MakeProtectiveMBR(); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 601 |             break; | 
 | 602 |          case use_new: | 
 | 603 |             ClearGPTData(); | 
 | 604 |             protectiveMBR.MakeProtectiveMBR(); | 
 | 605 |             break; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 606 |          case use_abort: | 
 | 607 |             allOK = 0; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 608 |             cerr << "Aborting because of invalid partition data!\n"; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 609 |             break; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 610 |       } // switch | 
 | 611 |  | 
 | 612 |       // Now find the first and last sectors used by partitions... | 
 | 613 |       if (allOK) { | 
 | 614 |          firstBlock = mainHeader.backupLBA; // start high | 
 | 615 |          lastBlock = 0; // start low | 
 | 616 |          for (i = 0; i < mainHeader.numParts; i++) { | 
 | 617 |             if ((partitions[i].GetFirstLBA() < firstBlock) && | 
 | 618 |                  (partitions[i].GetFirstLBA() > 0)) | 
 | 619 |                firstBlock = partitions[i].GetFirstLBA(); | 
 | 620 |             if (partitions[i].GetLastLBA() > lastBlock) | 
 | 621 |                lastBlock = partitions[i].GetLastLBA(); | 
 | 622 |          } // for | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 623 |          CheckGPTSize(); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 624 |       } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 625 |    } else { | 
 | 626 |       allOK = 0; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 627 |       cerr << "Problem opening " << deviceFilename << " for reading! Error is " | 
 | 628 |            << errno << "\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 629 |       if (errno == EACCES) { // User is probably not running as root | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 630 |          cerr << "You must run this program as root or use sudo!\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 631 |       } // if | 
 | 632 |    } // if/else | 
 | 633 |    return (allOK); | 
 | 634 | } // GPTData::LoadPartitions() | 
 | 635 |  | 
 | 636 | // Loads the GPT, as much as possible. Returns 1 if this seems to have | 
 | 637 | // succeeded, 0 if there are obvious problems.... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 638 | int GPTData::ForceLoadGPTData(void) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 639 |    int allOK = 1, validHeaders; | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 640 |    uint64_t seekTo; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 641 |    uint8_t* storage; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 642 |    uint32_t newCRC, sizeOfParts; | 
 | 643 |  | 
 | 644 |    // Seek to and read the main GPT header | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 645 |    if (myDisk.Seek(1)) { | 
 | 646 |       if (myDisk.Read(&mainHeader, 512) != 512) { // read main GPT header | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 647 |          cerr << "Warning! Error " << errno << " reading main GPT header!\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 648 |       } // if read not OK | 
 | 649 |    } else allOK = 0; // if/else seek OK | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 650 |    mainCrcOk = CheckHeaderCRC(&mainHeader); | 
 | 651 |    if (IsLittleEndian() == 0) // big-endian system; adjust header byte order.... | 
 | 652 |       ReverseHeaderBytes(&mainHeader); | 
 | 653 |  | 
| srs5694 | 3f2fe99 | 2009-11-24 18:28:18 -0500 | [diff] [blame] | 654 |    // Load backup header, check its CRC, and store the results of the | 
 | 655 |    // check for future reference. Load backup header using pointer in main | 
 | 656 |    // header if possible; but if main header has a CRC error, or if it | 
 | 657 |    // points to beyond the end of the disk, load the last sector of the | 
 | 658 |    // disk instead. | 
 | 659 |    if (mainCrcOk) { | 
 | 660 |       if (mainHeader.backupLBA < diskSize) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 661 |          seekTo = mainHeader.backupLBA; | 
| srs5694 | 3f2fe99 | 2009-11-24 18:28:18 -0500 | [diff] [blame] | 662 |       } else { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 663 |          seekTo = diskSize - UINT64_C(1); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 664 |          cout << "Warning! Disk size is smaller than the main header indicates! Loading\n" | 
 | 665 |               << "secondary header from the last sector of the disk! You should use 'v' to\n" | 
 | 666 |               << "verify disk integrity, and perhaps options on the experts' menu to repair\n" | 
 | 667 |               << "the disk.\n"; | 
| srs5694 | 3f2fe99 | 2009-11-24 18:28:18 -0500 | [diff] [blame] | 668 |       } // else | 
 | 669 |    } else { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 670 |       seekTo = diskSize - UINT64_C(1); | 
| srs5694 | 3f2fe99 | 2009-11-24 18:28:18 -0500 | [diff] [blame] | 671 |    } // if/else (mainCrcOk) | 
 | 672 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 673 |    if (myDisk.Seek(seekTo)) { | 
 | 674 |       if (myDisk.Read(&secondHeader, 512) != 512) { // read secondary GPT header | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 675 |          cerr << "Warning! Error " << errno << " reading secondary GPT header!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 676 |       } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 677 |       secondCrcOk = CheckHeaderCRC(&secondHeader); | 
 | 678 |       if (IsLittleEndian() == 0) // big-endian system; adjust header byte order.... | 
 | 679 |          ReverseHeaderBytes(&secondHeader); | 
 | 680 |    } else { | 
 | 681 |       allOK = 0; | 
 | 682 |       state = gpt_invalid; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 683 |       cerr << "Unable to seek to secondary GPT header at sector " | 
 | 684 |            << (diskSize - (UINT64_C(1))) << "!\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 685 |    } // if/else lseek | 
 | 686 |  | 
 | 687 |    // Return valid headers code: 0 = both headers bad; 1 = main header | 
 | 688 |    // good, backup bad; 2 = backup header good, main header bad; | 
 | 689 |    // 3 = both headers good. Note these codes refer to valid GPT | 
 | 690 |    // signatures and version numbers; more subtle problems will elude | 
 | 691 |    // this check! | 
 | 692 |    validHeaders = CheckHeaderValidity(); | 
 | 693 |  | 
 | 694 |    // Read partitions (from primary array) | 
 | 695 |    if (validHeaders > 0) { // if at least one header is OK.... | 
 | 696 |       // GPT appears to be valid.... | 
 | 697 |       state = gpt_valid; | 
 | 698 |  | 
 | 699 |       // We're calling the GPT valid, but there's a possibility that one | 
 | 700 |       // of the two headers is corrupt. If so, use the one that seems to | 
 | 701 |       // be in better shape to regenerate the bad one | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 702 |       if (validHeaders == 1) { // valid main header, invalid backup header | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 703 |          cerr << "\aCaution: invalid backup GPT header, but valid main header; regenerating\n" | 
 | 704 |               << "backup header from main header.\n\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 705 |          RebuildSecondHeader(); | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 706 |          state = gpt_corrupt; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 707 |          secondCrcOk = mainCrcOk; // Since regenerated, use CRC validity of main | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 708 |       } else if (validHeaders == 2) { // valid backup header, invalid main header | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 709 |          cerr << "\aCaution: invalid main GPT header, but valid backup; regenerating main header\n" | 
 | 710 |               << "from backup!\n\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 711 |          RebuildMainHeader(); | 
 | 712 |          state = gpt_corrupt; | 
 | 713 |          mainCrcOk = secondCrcOk; // Since copied, use CRC validity of backup | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 714 |       } // if/else/if | 
 | 715 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 716 |       // Figure out which partition table to load.... | 
 | 717 |       // Load the main partition table, since either its header's CRC is OK or the | 
 | 718 |       // backup header's CRC is not OK.... | 
 | 719 |       if (mainCrcOk || !secondCrcOk) { | 
 | 720 |          if (LoadMainTable() == 0) | 
 | 721 |             allOK = 0; | 
 | 722 |       } else { // bad main header CRC and backup header CRC is OK | 
 | 723 |          state = gpt_corrupt; | 
 | 724 |          if (LoadSecondTableAsMain()) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 725 |             cerr << "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 726 |          } else { // backup table bad, bad main header CRC, but try main table in desperation.... | 
 | 727 |             if (LoadMainTable() == 0) { | 
 | 728 |                allOK = 0; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 729 |                cerr << "\a\aWarning! Unable to load either main or backup partition table!\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 730 |             } // if | 
 | 731 |          } // if/else (LoadSecondTableAsMain()) | 
 | 732 |       } // if/else (load partition table) | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 733 |  | 
 | 734 |       // Load backup partition table into temporary storage to check | 
 | 735 |       // its CRC and store the results, then discard this temporary | 
 | 736 |       // storage, since we don't use it in any but recovery operations | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 737 |       seekTo = secondHeader.partitionEntriesLBA; | 
 | 738 |       if ((myDisk.Seek(seekTo)) && (secondCrcOk)) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 739 |          sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 740 |          storage = (uint8_t*) malloc(sizeOfParts); | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 741 |          if (myDisk.Read(storage, sizeOfParts) != (int) sizeOfParts) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 742 |             cerr << "Warning! Error " << errno << " reading backup partition table!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 743 |          } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 744 |          newCRC = chksum_crc32((unsigned char*) storage,  sizeOfParts); | 
 | 745 |          free(storage); | 
 | 746 |          secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC); | 
 | 747 |       } // if | 
 | 748 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 749 |       // Problem with main partition table; if backup is OK, use it instead.... | 
 | 750 |       if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) { | 
 | 751 |          state = gpt_corrupt; | 
 | 752 |          allOK = allOK && LoadSecondTableAsMain(); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 753 |          cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup " | 
 | 754 |               << "partition table\ninstead of main partition table!\n\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 755 |       } // if | 
 | 756 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 757 |       // Check for valid CRCs and warn if there are problems | 
 | 758 |       if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) || | 
 | 759 |            (secondPartsCrcOk == 0)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 760 |          cerr << "Warning! One or more CRCs don't match. You should repair the disk!\n\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 761 |          state = gpt_corrupt; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 762 |       } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 763 |    } else { | 
 | 764 |       state = gpt_invalid; | 
 | 765 |    } // if/else | 
 | 766 |    return allOK; | 
 | 767 | } // GPTData::ForceLoadGPTData() | 
 | 768 |  | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 769 | // Loads the partition table pointed to by the main GPT header. The | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 770 | // main GPT header in memory MUST be valid for this call to do anything | 
 | 771 | // sensible! | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 772 | // Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 773 | int GPTData::LoadMainTable(void) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 774 |    int retval = 1; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 775 |    uint32_t newCRC, sizeOfParts; | 
 | 776 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 777 |    if (myDisk.OpenForRead(device)) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 778 |       // Set internal data structures for number of partitions on the disk | 
 | 779 |       SetGPTSize(mainHeader.numParts); | 
 | 780 |  | 
 | 781 |       // Load main partition table, and record whether its CRC | 
 | 782 |       // matches the stored value | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 783 |       if (!myDisk.Seek(mainHeader.partitionEntriesLBA)) | 
 | 784 |          retval = 0; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 785 |       sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 786 |       if (myDisk.Read(partitions, sizeOfParts) != (int) sizeOfParts) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 787 |          cerr << "Warning! Error " << errno << " when loading the main partition table!\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 788 |          retval = 0; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 789 |       } // if | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 790 |       newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); | 
 | 791 |       mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC); | 
 | 792 |       if (IsLittleEndian() == 0) | 
 | 793 |          ReversePartitionBytes(); | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 794 |    } else retval = 0; // if open for read.... | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 795 |    return retval; | 
 | 796 | } // GPTData::LoadMainTable() | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 797 |  | 
 | 798 | // Load the second (backup) partition table as the primary partition | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 799 | // table. Used in repair functions, and when starting up if the main | 
 | 800 | // partition table is damaged. | 
 | 801 | // Returns 1 on success, 0 on failure. CRC errors do NOT count as failure. | 
 | 802 | int GPTData::LoadSecondTableAsMain(void) { | 
 | 803 |    uint64_t seekTo; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 804 |    uint32_t sizeOfParts, newCRC; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 805 |    int retval = 1; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 806 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 807 |    if (myDisk.OpenForRead(device)) { | 
 | 808 |       seekTo = secondHeader.partitionEntriesLBA; | 
 | 809 |       retval = myDisk.Seek(seekTo); | 
 | 810 |       if (retval == 1) { | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 811 |          SetGPTSize(secondHeader.numParts); | 
 | 812 |          sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 813 |          if (myDisk.Read(partitions, sizeOfParts) != (int) sizeOfParts) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 814 |             cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 815 |             retval = 0; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 816 |          } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 817 |          newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); | 
 | 818 |          secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 819 |          mainPartsCrcOk = secondPartsCrcOk; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 820 |          if (IsLittleEndian() == 0) | 
 | 821 |             ReversePartitionBytes(); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 822 |          if (!secondPartsCrcOk) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 823 |             cout << "Caution! After loading backup partitions, the CRC still doesn't check out!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 824 |          } // if | 
 | 825 |       } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 826 |          cerr << "Error! Couldn't seek to backup partition table!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 827 |       } // if/else | 
 | 828 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 829 |       cerr << "Error! Couldn't open device " << device | 
 | 830 |            << " when recovering backup partition table!\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 831 |       retval = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 832 |    } // if/else | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 833 |    return retval; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 834 | } // GPTData::LoadSecondTableAsMain() | 
 | 835 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 836 | // Writes GPT (and protective MBR) to disk. Returns 1 on successful | 
 | 837 | // write, 0 if there was a problem. | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 838 | int GPTData::SaveGPTData(int quiet) { | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 839 |    int allOK = 1; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 840 |    char answer; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 841 |    uint64_t secondTable; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 842 |    uint32_t numParts; | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 843 |    uint64_t offset; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 844 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 845 |    if (device == "") { | 
 | 846 |       cerr << "Device not defined.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 847 |    } // if | 
 | 848 |  | 
 | 849 |    // First do some final sanity checks.... | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 850 |  | 
 | 851 |    // This test should only fail on read-only disks.... | 
 | 852 |    if (justLooking) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 853 |       cout << "The justLooking flag is set. This probably means you can't write to the disk.\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 854 |       allOK = 0; | 
 | 855 |    } // if | 
 | 856 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 857 |    // Is there enough space to hold the GPT headers and partition tables, | 
 | 858 |    // given the partition sizes? | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 859 |    if (CheckGPTSize() > 0) { | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 860 |       allOK = 0; | 
 | 861 |    } // if | 
 | 862 |  | 
 | 863 |    // Check that disk is really big enough to handle this... | 
 | 864 |    if (mainHeader.backupLBA > diskSize) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 865 |       cerr << "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n" | 
 | 866 |            << "problem (or it might not). Aborting!\n(Disk size is " | 
 | 867 |            << diskSize << " sectors, needs to be " << mainHeader.backupLBA << " sectors.)\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 868 |       allOK = 0; | 
 | 869 |    } // if | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 870 |    // Check that second header is properly placed. Warn and ask if this should | 
 | 871 |    // be corrected if the test fails.... | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 872 |    if ((mainHeader.backupLBA < (diskSize - UINT64_C(1))) && (quiet == 0)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 873 |       cout << "Warning! Secondary header is placed too early on the disk! Do you want to\n" | 
 | 874 |            << "correct this problem? "; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 875 |       if (GetYN() == 'Y') { | 
 | 876 |          MoveSecondHeaderToEnd(); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 877 |          cout << "Have moved second header and partition table to correct location.\n"; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 878 |       } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 879 |          cout << "Have not corrected the problem. Strange problems may occur in the future!\n"; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 880 |       } // if correction requested | 
 | 881 |    } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 882 |  | 
 | 883 |    // Check for overlapping partitions.... | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 884 |    if (FindOverlaps() > 0) { | 
 | 885 |       allOK = 0; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 886 |       cerr << "Aborting write operation!\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 887 |    } // if | 
 | 888 |  | 
 | 889 |    // Check for mismatched MBR and GPT data, but let it pass if found | 
 | 890 |    // (function displays warning message) | 
 | 891 |    FindHybridMismatches(); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 892 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 893 |    // Pull out some data that's needed before doing byte-order reversal on | 
 | 894 |    // big-endian systems.... | 
 | 895 |    numParts = mainHeader.numParts; | 
 | 896 |    secondTable = secondHeader.partitionEntriesLBA; | 
 | 897 |    if (IsLittleEndian() == 0) { | 
 | 898 |       // Reverse partition bytes first, since that function requires non-reversed | 
 | 899 |       // data from the main header.... | 
 | 900 |       ReversePartitionBytes(); | 
 | 901 |       ReverseHeaderBytes(&mainHeader); | 
 | 902 |       ReverseHeaderBytes(&secondHeader); | 
 | 903 |    } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 904 |    RecomputeCRCs(); | 
 | 905 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 906 |    if ((allOK) && (!quiet)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 907 |       cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n" | 
 | 908 |            << "PARTITIONS!!\n\nDo you want to proceed, possibly destroying your data? "; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 909 |       answer = GetYN(); | 
 | 910 |       if (answer == 'Y') { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 911 |          cout << "OK; writing new GUID partition table (GPT).\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 912 |       } else { | 
 | 913 |          allOK = 0; | 
 | 914 |       } // if/else | 
 | 915 |    } // if | 
 | 916 |  | 
 | 917 |    // Do it! | 
 | 918 |    if (allOK) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 919 |       // First, write the protective MBR... | 
 | 920 |       allOK = protectiveMBR.WriteMBRData(&myDisk); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 921 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 922 |       if (allOK && myDisk.OpenForWrite(device)) { | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 923 |          // Now write the main GPT header... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 924 |          if (myDisk.Seek(1) == 1) { | 
 | 925 |             if (myDisk.Write(&mainHeader, 512) != 512) | 
 | 926 |                allOK = 0; | 
 | 927 |          } else allOK = 0; // if (myDisk.Seek()...) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 928 |  | 
 | 929 |          // Now write the main partition tables... | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 930 |          if (allOK) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 931 | 	    offset = mainHeader.partitionEntriesLBA; | 
 | 932 | 	    if (myDisk.Seek(offset)) { | 
 | 933 |                if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1) | 
 | 934 |                   allOK = 0; | 
 | 935 |             } else allOK = 0; // if (myDisk.Seek()...) | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 936 |          } // if (allOK) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 937 |  | 
 | 938 |          // Now seek to near the end to write the secondary GPT.... | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 939 |          if (allOK) { | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 940 |             offset = (uint64_t) secondTable; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 941 |             if (myDisk.Seek(offset) != 1) { | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 942 |                allOK = 0; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 943 |                cerr << "Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n" | 
 | 944 |                     << "will resolve this problem.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 945 |             } // if | 
 | 946 |          } // if | 
 | 947 |  | 
 | 948 |          // Now write the secondary partition tables.... | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 949 |          if (allOK) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 950 |             if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 951 |                allOK = 0; | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 952 | 	 } // if (allOK) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 953 |  | 
 | 954 |          // Now write the secondary GPT header... | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 955 |          if (allOK) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 956 | 	    offset = mainHeader.backupLBA; | 
 | 957 | 	    if (myDisk.Seek(offset)) { | 
 | 958 |                if (myDisk.Write(&secondHeader, 512) == -1) | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 959 |                   allOK = 0; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 960 | 	    } else allOK = 0; // if (myDisk.Seek()...) | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 961 | 	 } // if (allOK) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 962 |  | 
 | 963 |          // re-read the partition table | 
 | 964 |          if (allOK) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 965 |             myDisk.DiskSync(); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 966 |          } // if | 
 | 967 |  | 
 | 968 |          if (allOK) { // writes completed OK | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 969 |             cout << "The operation has completed successfully.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 970 |          } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 971 |             cerr << "Warning! An error was reported when writing the partition table! This error\n" | 
 | 972 |                  << "MIGHT be harmless, but you may have trashed the disk! Use parted and, if\n" | 
 | 973 |                  << "necessary, restore your original partition table.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 974 |          } // if/else | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 975 |          myDisk.Close(); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 976 |       } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 977 |          cerr << "Unable to open device " << device << " for writing! Errno is " | 
 | 978 |               << errno << "! Aborting write!\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 979 |          allOK = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 980 |       } // if/else | 
 | 981 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 982 |       cout << "Aborting write of new partition table.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 983 |    } // if | 
 | 984 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 985 |    if (IsLittleEndian() == 0) { | 
 | 986 |       // Reverse (normalize) header bytes first, since ReversePartitionBytes() | 
 | 987 |       // requires non-reversed data in mainHeader... | 
 | 988 |       ReverseHeaderBytes(&mainHeader); | 
 | 989 |       ReverseHeaderBytes(&secondHeader); | 
 | 990 |       ReversePartitionBytes(); | 
 | 991 |    } // if | 
 | 992 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 993 |    return (allOK); | 
 | 994 | } // GPTData::SaveGPTData() | 
 | 995 |  | 
 | 996 | // Save GPT data to a backup file. This function does much less error | 
 | 997 | // checking than SaveGPTData(). It can therefore preserve many types of | 
 | 998 | // corruption for later analysis; however, it preserves only the MBR, | 
 | 999 | // the main GPT header, the backup GPT header, and the main partition | 
 | 1000 | // table; it discards the backup partition table, since it should be | 
 | 1001 | // identical to the main partition table on healthy disks. | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 1002 | int GPTData::SaveGPTBackup(const string & filename) { | 
 | 1003 |    int allOK = 1; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1004 |    uint32_t numParts; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1005 |    DiskIO backupFile; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1006 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1007 |    if (backupFile.OpenForWrite(filename)) { | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1008 |       // Reverse the byte order, if necessary.... | 
 | 1009 |       numParts = mainHeader.numParts; | 
 | 1010 |       if (IsLittleEndian() == 0) { | 
 | 1011 |          ReversePartitionBytes(); | 
 | 1012 |          ReverseHeaderBytes(&mainHeader); | 
 | 1013 |          ReverseHeaderBytes(&secondHeader); | 
 | 1014 |       } // if | 
 | 1015 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1016 |       // Recomputing the CRCs is likely to alter them, which could be bad | 
 | 1017 |       // if the intent is to save a potentially bad GPT for later analysis; | 
 | 1018 |       // but if we don't do this, we get bogus errors when we load the | 
 | 1019 |       // backup. I'm favoring misses over false alarms.... | 
 | 1020 |       RecomputeCRCs(); | 
 | 1021 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1022 |       // Now write the protective MBR... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1023 |       protectiveMBR.WriteMBRData(&backupFile); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1024 |  | 
 | 1025 |       // Now write the main GPT header... | 
 | 1026 |       if (allOK) | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1027 |          // MBR write closed disk, so re-open and seek to end.... | 
 | 1028 |          backupFile.OpenForWrite(); | 
 | 1029 |          backupFile.Seek(1); | 
 | 1030 |          if (backupFile.Write(&mainHeader, 512) == -1) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1031 |             allOK = 0; | 
 | 1032 |  | 
 | 1033 |       // Now write the secondary GPT header... | 
 | 1034 |       if (allOK) | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1035 |          if (backupFile.Write(&secondHeader, 512) == -1) | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1036 |             allOK = 0; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1037 |  | 
 | 1038 |       // Now write the main partition tables... | 
 | 1039 |       if (allOK) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1040 |          if (backupFile.Write(partitions, GPT_SIZE * numParts) == -1) | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1041 |             allOK = 0; | 
 | 1042 |       } // if | 
 | 1043 |  | 
 | 1044 |       if (allOK) { // writes completed OK | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1045 |          cout << "The operation has completed successfully.\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1046 |       } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1047 |          cerr << "Warning! An error was reported when writing the backup file.\n" | 
 | 1048 |               << "It may not be usable!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1049 |       } // if/else | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1050 |       backupFile.Close(); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1051 |  | 
 | 1052 |       // Now reverse the byte-order reversal, if necessary.... | 
 | 1053 |       if (IsLittleEndian() == 0) { | 
 | 1054 |          ReverseHeaderBytes(&mainHeader); | 
 | 1055 |          ReverseHeaderBytes(&secondHeader); | 
 | 1056 |          ReversePartitionBytes(); | 
 | 1057 |       } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1058 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1059 |       cerr << "Unable to open file " << filename << " for writing! Aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1060 |       allOK = 0; | 
 | 1061 |    } // if/else | 
 | 1062 |    return allOK; | 
 | 1063 | } // GPTData::SaveGPTBackup() | 
 | 1064 |  | 
 | 1065 | // Load GPT data from a backup file created by SaveGPTBackup(). This function | 
 | 1066 | // does minimal error checking. It returns 1 if it completed successfully, | 
 | 1067 | // 0 if there was a problem. In the latter case, it creates a new empty | 
 | 1068 | // set of partitions. | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 1069 | int GPTData::LoadGPTBackup(const string & filename) { | 
 | 1070 |    int allOK = 1, val; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1071 |    uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1072 |    int littleEndian = 1; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1073 |    DiskIO backupFile; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1074 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1075 |    if (backupFile.OpenForRead(filename)) { | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1076 |       if (IsLittleEndian() == 0) | 
 | 1077 |          littleEndian = 0; | 
 | 1078 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1079 |       // Let the MBRData class load the saved MBR... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1080 |       protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1081 |  | 
 | 1082 |       // Load the main GPT header, check its vaility, and set the GPT | 
 | 1083 |       // size based on the data | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1084 |       if (backupFile.Read(&mainHeader, 512) != 512) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1085 |          cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1086 |       } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1087 |       mainCrcOk = CheckHeaderCRC(&mainHeader); | 
 | 1088 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1089 |       // Reverse byte order, if necessary | 
 | 1090 |       if (littleEndian == 0) { | 
 | 1091 |          ReverseHeaderBytes(&mainHeader); | 
 | 1092 |       } // if | 
 | 1093 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1094 |       // Load the backup GPT header in much the same way as the main | 
 | 1095 |       // GPT header.... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1096 |       if (backupFile.Read(&secondHeader, 512) != 512) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1097 |          cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1098 |       } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1099 |       secondCrcOk = CheckHeaderCRC(&secondHeader); | 
 | 1100 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1101 |       // Reverse byte order, if necessary | 
 | 1102 |       if (littleEndian == 0) { | 
 | 1103 |          ReverseHeaderBytes(&secondHeader); | 
 | 1104 |       } // if | 
 | 1105 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1106 |       // Return valid headers code: 0 = both headers bad; 1 = main header | 
 | 1107 |       // good, backup bad; 2 = backup header good, main header bad; | 
 | 1108 |       // 3 = both headers good. Note these codes refer to valid GPT | 
 | 1109 |       // signatures and version numbers; more subtle problems will elude | 
 | 1110 |       // this check! | 
 | 1111 |       if ((val = CheckHeaderValidity()) > 0) { | 
 | 1112 |          if (val == 2) { // only backup header seems to be good | 
 | 1113 |             numParts = secondHeader.numParts; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1114 |             sizeOfEntries = secondHeader.sizeOfPartitionEntries; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1115 |          } else { // main header is OK | 
 | 1116 |             numParts = mainHeader.numParts; | 
 | 1117 |             sizeOfEntries = mainHeader.sizeOfPartitionEntries; | 
 | 1118 |          } // if/else | 
 | 1119 |  | 
 | 1120 |          SetGPTSize(numParts); | 
 | 1121 |  | 
 | 1122 |          // If current disk size doesn't match that of backup.... | 
 | 1123 |          if (secondHeader.currentLBA != diskSize - UINT64_C(1)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1124 |             cout << "Warning! Current disk size doesn't match that of the backup!\n" | 
 | 1125 |                  << "Adjusting sizes to match, but subsequent problems are possible!\n"; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 1126 |             MoveSecondHeaderToEnd(); | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1127 |          } // if | 
 | 1128 |  | 
 | 1129 |          // Load main partition table, and record whether its CRC | 
 | 1130 |          // matches the stored value | 
 | 1131 |          sizeOfParts = numParts * sizeOfEntries; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1132 |          if (backupFile.Read(partitions, sizeOfParts) != (int) sizeOfParts) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1133 |             cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1134 |          } // if | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1135 |  | 
 | 1136 |          newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); | 
 | 1137 |          mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC); | 
 | 1138 |          secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1139 |          // Reverse byte order, if necessary | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1140 |          if (littleEndian == 0) { | 
 | 1141 |             ReversePartitionBytes(); | 
 | 1142 |          } // if | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 1143 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1144 |       } else { | 
 | 1145 |          allOK = 0; | 
 | 1146 |       } // if/else | 
 | 1147 |    } else { | 
 | 1148 |       allOK = 0; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1149 |       cerr << "Unable to open file " << filename << " for reading! Aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1150 |    } // if/else | 
 | 1151 |  | 
 | 1152 |    // Something went badly wrong, so blank out partitions | 
 | 1153 |    if (allOK == 0) { | 
 | 1154 |       ClearGPTData(); | 
 | 1155 |       protectiveMBR.MakeProtectiveMBR(); | 
 | 1156 |    } // if | 
 | 1157 |    return allOK; | 
 | 1158 | } // GPTData::LoadGPTBackup() | 
 | 1159 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1160 | // Tell user whether Apple Partition Map (APM) was discovered.... | 
 | 1161 | void GPTData::ShowAPMState(void) { | 
 | 1162 |    if (apmFound) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1163 |       cout << "  APM: present\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1164 |    else | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1165 |       cout << "  APM: not present\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1166 | } // GPTData::ShowAPMState() | 
 | 1167 |  | 
 | 1168 | // Tell user about the state of the GPT data.... | 
 | 1169 | void GPTData::ShowGPTState(void) { | 
 | 1170 |    switch (state) { | 
 | 1171 |       case gpt_invalid: | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1172 |          cout << "  GPT: not present\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1173 |          break; | 
 | 1174 |       case gpt_valid: | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1175 |          cout << "  GPT: present\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1176 |          break; | 
 | 1177 |       case gpt_corrupt: | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1178 |          cout << "  GPT: damaged\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1179 |          break; | 
 | 1180 |       default: | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1181 |          cout << "\a  GPT: unknown -- bug!\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1182 |          break; | 
 | 1183 |    } // switch | 
 | 1184 | } // GPTData::ShowGPTState() | 
 | 1185 |  | 
 | 1186 | // Display the basic GPT data | 
 | 1187 | void GPTData::DisplayGPTData(void) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1188 |    uint32_t i; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1189 |    uint64_t temp, totalFree; | 
 | 1190 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1191 |    cout << "Disk " << device << ": " << diskSize << " sectors, " | 
 | 1192 |         << BytesToSI(diskSize * blockSize) << "\n"; | 
 | 1193 |    cout << "Logical sector size: " << blockSize << " bytes\n"; | 
 | 1194 |    cout << "Disk identifier (GUID): " << GUIDToStr(mainHeader.diskGUID) << "\n"; | 
 | 1195 |    cout << "Partition table holds up to " << mainHeader.numParts << " entries\n"; | 
 | 1196 |    cout << "First usable sector is " << mainHeader.firstUsableLBA | 
 | 1197 |         << ", last usable sector is " << mainHeader.lastUsableLBA << "\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1198 |    totalFree = FindFreeBlocks(&i, &temp); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1199 |    cout << "Total free space is " << totalFree << " sectors (" | 
 | 1200 |         << BytesToSI(totalFree * (uint64_t) blockSize) << ")\n"; | 
 | 1201 |    cout << "\nNumber  Start (sector)    End (sector)  Size       Code  Name\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1202 |    for (i = 0; i < mainHeader.numParts; i++) { | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1203 |       partitions[i].ShowSummary(i, blockSize); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1204 |    } // for | 
 | 1205 | } // GPTData::DisplayGPTData() | 
 | 1206 |  | 
 | 1207 | // Get partition number from user and then call ShowPartDetails(partNum) | 
 | 1208 | // to show its detailed information | 
 | 1209 | void GPTData::ShowDetails(void) { | 
 | 1210 |    int partNum; | 
 | 1211 |    uint32_t low, high; | 
 | 1212 |  | 
 | 1213 |    if (GetPartRange(&low, &high) > 0) { | 
 | 1214 |       partNum = GetPartNum(); | 
 | 1215 |       ShowPartDetails(partNum); | 
 | 1216 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1217 |       cout << "No partitions\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1218 |    } // if/else | 
 | 1219 | } // GPTData::ShowDetails() | 
 | 1220 |  | 
 | 1221 | // Show detailed information on the specified partition | 
 | 1222 | void GPTData::ShowPartDetails(uint32_t partNum) { | 
 | 1223 |    if (partitions[partNum].GetFirstLBA() != 0) { | 
 | 1224 |       partitions[partNum].ShowDetails(blockSize); | 
 | 1225 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1226 |       cout << "Partition #" << partNum + 1 << " does not exist."; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1227 |    } // if | 
 | 1228 | } // GPTData::ShowPartDetails() | 
 | 1229 |  | 
 | 1230 | /********************************************************************* | 
 | 1231 |  *                                                                   * | 
 | 1232 |  * Begin functions that obtain information from the users, and often * | 
 | 1233 |  * do something with that information (call other functions)         * | 
 | 1234 |  *                                                                   * | 
 | 1235 |  *********************************************************************/ | 
 | 1236 |  | 
 | 1237 | // Prompts user for partition number and returns the result. | 
 | 1238 | uint32_t GPTData::GetPartNum(void) { | 
 | 1239 |    uint32_t partNum; | 
 | 1240 |    uint32_t low, high; | 
 | 1241 |    char prompt[255]; | 
 | 1242 |  | 
 | 1243 |    if (GetPartRange(&low, &high) > 0) { | 
 | 1244 |       sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1); | 
 | 1245 |       partNum = GetNumber(low + 1, high + 1, low, prompt); | 
 | 1246 |    } else partNum = 1; | 
 | 1247 |    return (partNum - 1); | 
 | 1248 | } // GPTData::GetPartNum() | 
 | 1249 |  | 
 | 1250 | // What it says: Resize the partition table. (Default is 128 entries.) | 
 | 1251 | void GPTData::ResizePartitionTable(void) { | 
 | 1252 |    int newSize; | 
 | 1253 |    char prompt[255]; | 
 | 1254 |    uint32_t curLow, curHigh; | 
 | 1255 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1256 |    cout << "Current partition table size is " << mainHeader.numParts << ".\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1257 |    GetPartRange(&curLow, &curHigh); | 
 | 1258 |    curHigh++; // since GetPartRange() returns numbers starting from 0... | 
 | 1259 |    // There's no point in having fewer than four partitions.... | 
 | 1260 |    if (curHigh < 4) | 
 | 1261 |       curHigh = 4; | 
 | 1262 |    sprintf(prompt, "Enter new size (%d up, default %d): ", (int) curHigh, | 
 | 1263 |            (int) NUM_GPT_ENTRIES); | 
 | 1264 |    newSize = GetNumber(4, 65535, 128, prompt); | 
 | 1265 |    if (newSize < 128) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1266 |       cout << "Caution: The partition table size should officially be 16KB or larger,\n" | 
 | 1267 |            << "which works out to 128 entries. In practice, smaller tables seem to\n" | 
 | 1268 |            << "work with most OSes, but this practice is risky. I'm proceeding with\n" | 
 | 1269 |            << "the resize, but you may want to reconsider this action and undo it.\n\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1270 |    } // if | 
 | 1271 |    SetGPTSize(newSize); | 
 | 1272 | } // GPTData::ResizePartitionTable() | 
 | 1273 |  | 
 | 1274 | // Interactively create a partition | 
 | 1275 | void GPTData::CreatePartition(void) { | 
 | 1276 |    uint64_t firstBlock, firstInLargest, lastBlock, sector; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1277 |    uint32_t firstFreePart = 0; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1278 |    char prompt[255]; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1279 |    int partNum; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1280 |  | 
 | 1281 |    // Find first free partition... | 
 | 1282 |    while (partitions[firstFreePart].GetFirstLBA() != 0) { | 
 | 1283 |       firstFreePart++; | 
 | 1284 |    } // while | 
 | 1285 |  | 
 | 1286 |    if (((firstBlock = FindFirstAvailable()) != 0) && | 
 | 1287 |          (firstFreePart < mainHeader.numParts)) { | 
 | 1288 |       lastBlock = FindLastAvailable(firstBlock); | 
 | 1289 |       firstInLargest = FindFirstInLargest(); | 
 | 1290 |  | 
 | 1291 |       // Get partition number.... | 
 | 1292 |       do { | 
 | 1293 |          sprintf(prompt, "Partition number (%d-%d, default %d): ", firstFreePart + 1, | 
 | 1294 |                  mainHeader.numParts, firstFreePart + 1); | 
 | 1295 |          partNum = GetNumber(firstFreePart + 1, mainHeader.numParts, | 
 | 1296 |                              firstFreePart + 1, prompt) - 1; | 
 | 1297 |          if (partitions[partNum].GetFirstLBA() != 0) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1298 |             cout << "partition " << partNum + 1 << " is in use.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1299 |       } while (partitions[partNum].GetFirstLBA() != 0); | 
 | 1300 |  | 
 | 1301 |       // Get first block for new partition... | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1302 |       sprintf(prompt, "First sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ", | 
 | 1303 |               (unsigned long long) firstBlock, (unsigned long long) lastBlock, | 
 | 1304 |               (unsigned long long) firstInLargest); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1305 |       do { | 
 | 1306 |          sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt); | 
 | 1307 |       } while (IsFree(sector) == 0); | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 1308 |       Align(§or); // Align sector to correct multiple | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1309 |       firstBlock = sector; | 
 | 1310 |  | 
 | 1311 |       // Get last block for new partitions... | 
 | 1312 |       lastBlock = FindLastInFree(firstBlock); | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1313 |       sprintf(prompt, "Last sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ", | 
 | 1314 |               (unsigned long long) firstBlock, (unsigned long long) lastBlock, | 
 | 1315 |               (unsigned long long) lastBlock); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1316 |       do { | 
 | 1317 |          sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt); | 
 | 1318 |       } while (IsFree(sector) == 0); | 
 | 1319 |       lastBlock = sector; | 
 | 1320 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1321 |       firstFreePart = CreatePartition(partNum, firstBlock, lastBlock); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1322 |       partitions[partNum].ChangeType(); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1323 |       partitions[partNum].SetName(partitions[partNum].GetNameType()); | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1324 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1325 |       cout << "No free sectors available\n"; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1326 |    } // if/else | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1327 | } // GPTData::CreatePartition() | 
 | 1328 |  | 
 | 1329 | // Interactively delete a partition (duh!) | 
 | 1330 | void GPTData::DeletePartition(void) { | 
 | 1331 |    int partNum; | 
 | 1332 |    uint32_t low, high; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1333 |    char prompt[255]; | 
 | 1334 |  | 
 | 1335 |    if (GetPartRange(&low, &high) > 0) { | 
 | 1336 |       sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1); | 
 | 1337 |       partNum = GetNumber(low + 1, high + 1, low, prompt); | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1338 |       DeletePartition(partNum - 1); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1339 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1340 |       cout << "No partitions\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1341 |    } // if/else | 
 | 1342 | } // GPTData::DeletePartition() | 
 | 1343 |  | 
 | 1344 | // Prompt user for a partition number, then change its type code | 
 | 1345 | // using ChangeGPTType(struct GPTPartition*) function. | 
 | 1346 | void GPTData::ChangePartType(void) { | 
 | 1347 |    int partNum; | 
 | 1348 |    uint32_t low, high; | 
 | 1349 |  | 
 | 1350 |    if (GetPartRange(&low, &high) > 0) { | 
 | 1351 |       partNum = GetPartNum(); | 
 | 1352 |       partitions[partNum].ChangeType(); | 
 | 1353 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1354 |       cout << "No partitions\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1355 |    } // if/else | 
 | 1356 | } // GPTData::ChangePartType() | 
 | 1357 |  | 
 | 1358 | // Partition attributes seem to be rarely used, but I want a way to | 
 | 1359 | // adjust them for completeness.... | 
 | 1360 | void GPTData::SetAttributes(uint32_t partNum) { | 
 | 1361 |    Attributes theAttr; | 
 | 1362 |  | 
 | 1363 |    theAttr.SetAttributes(partitions[partNum].GetAttributes()); | 
 | 1364 |    theAttr.DisplayAttributes(); | 
 | 1365 |    theAttr.ChangeAttributes(); | 
 | 1366 |    partitions[partNum].SetAttributes(theAttr.GetAttributes()); | 
 | 1367 | } // GPTData::SetAttributes() | 
 | 1368 |  | 
| srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 1369 | // This function destroys the on-disk GPT structures. Returns 1 if the | 
 | 1370 | // user confirms destruction, 0 if the user aborts. | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1371 | // If prompt == 0, don't ask user about proceeding and do NOT wipe out | 
 | 1372 | // MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.) | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1373 | // If prompt == -1, don't ask user about proceeding and DO wipe out | 
 | 1374 | // MBR. | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1375 | int GPTData::DestroyGPT(int prompt) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1376 |    int i, sum, tableSize; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1377 |    uint8_t blankSector[512], goOn = 'Y', blank = 'N'; | 
 | 1378 |    uint8_t* emptyTable; | 
| srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 1379 |  | 
 | 1380 |    for (i = 0; i < 512; i++) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1381 |       blankSector[i] = 0; | 
| srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 1382 |    } // for | 
 | 1383 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1384 |    if (((apmFound) || (bsdFound)) && (prompt > 0)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1385 |       cout << "WARNING: APM or BSD disklabel structures detected! This operation could\n" | 
 | 1386 |            << "damage any APM or BSD partitions on this disk!\n"; | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 1387 |    } // if APM or BSD | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1388 |    if (prompt > 0) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1389 |       cout << "\a\aAbout to wipe out GPT on " << device << ". Proceed? "; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1390 |       goOn = GetYN(); | 
 | 1391 |    } // if | 
| srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 1392 |    if (goOn == 'Y') { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1393 |       if (myDisk.OpenForWrite(device)) { | 
 | 1394 |          myDisk.Seek(mainHeader.currentLBA); // seek to GPT header | 
 | 1395 |          if (myDisk.Write(blankSector, 512) != 512) { // blank it out | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1396 |             cerr << "Warning! GPT main header not overwritten! Error is " << errno << "\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1397 |          } // if | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1398 |          myDisk.Seek(mainHeader.partitionEntriesLBA); // seek to partition table | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 1399 |          tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1400 |          emptyTable = (uint8_t*) malloc(tableSize); | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 1401 |          for (i = 0; i < tableSize; i++) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1402 |             emptyTable[i] = 0; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1403 |          sum = myDisk.Write(emptyTable, tableSize); | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 1404 |          if (sum != tableSize) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1405 |             cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1406 |          myDisk.Seek(secondHeader.partitionEntriesLBA); // seek to partition table | 
 | 1407 |          sum = myDisk.Write(emptyTable, tableSize); | 
| srs5694 | 1e09372 | 2010-01-05 00:14:19 -0500 | [diff] [blame] | 1408 |          if (sum != tableSize) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1409 |             cerr << "Warning! GPT backup partition table not overwritten! Error is " << errno << "\n"; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1410 |          myDisk.Seek(secondHeader.currentLBA); // seek to GPT header | 
 | 1411 |          if (myDisk.Write(blankSector, 512) != 512) { // blank it out | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1412 |             cerr << "Warning! GPT backup header not overwritten! Error is " << errno << "\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1413 |          } // if | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1414 |          if (prompt > 0) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1415 |             cout << "Blank out MBR? "; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1416 |             blank = GetYN(); | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1417 |          } // if | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1418 |          // Note on below: Touch the MBR only if the user wants it completely | 
 | 1419 |          // blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote | 
 | 1420 |          // the MBR, but this could wipe out a valid MBR that the program | 
 | 1421 |          // had subsequently discarded (say, if it conflicted with older GPT | 
 | 1422 |          // structures). | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1423 |          if ((blank == 'Y') || (prompt < 0)) { | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1424 |             myDisk.Seek(0); | 
 | 1425 |             if (myDisk.Write(blankSector, 512) != 512) { // blank it out | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1426 |                cerr << "Warning! MBR not overwritten! Error is " << errno << "!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1427 |             } // if | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1428 |          } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1429 |             cout << "MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n" | 
 | 1430 |                  << "with fdisk or another tool.\n"; | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 1431 |          } // if/else | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1432 |          myDisk.DiskSync(); | 
 | 1433 |          myDisk.Close(); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1434 |          cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n" | 
 | 1435 |               << "other utilities. Program will now terminate.\n"; | 
| srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 1436 |       } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1437 |          cerr << "Problem opening " << device << " for writing! Program will now terminate.\n"; | 
| srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 1438 |       } // if/else (fd != -1) | 
 | 1439 |    } // if (goOn == 'Y') | 
 | 1440 |    return (goOn == 'Y'); | 
 | 1441 | } // GPTData::DestroyGPT() | 
 | 1442 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1443 | /************************************************************************** | 
 | 1444 |  *                                                                        * | 
 | 1445 |  * Partition table transformation functions (MBR or BSD disklabel to GPT) * | 
 | 1446 |  * (some of these functions may require user interaction)                 * | 
 | 1447 |  *                                                                        * | 
 | 1448 |  **************************************************************************/ | 
 | 1449 |  | 
 | 1450 | // Examines the MBR & GPT data, and perhaps asks the user questions, to | 
 | 1451 | // determine which set of data to use: the MBR (use_mbr), the GPT (use_gpt), | 
 | 1452 | // or create a new set of partitions (use_new) | 
 | 1453 | WhichToUse GPTData::UseWhichPartitions(void) { | 
 | 1454 |    WhichToUse which = use_new; | 
 | 1455 |    MBRValidity mbrState; | 
 | 1456 |    int answer; | 
 | 1457 |  | 
 | 1458 |    mbrState = protectiveMBR.GetValidity(); | 
 | 1459 |  | 
 | 1460 |    if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1461 |       cout << "\n***************************************************************\n" | 
 | 1462 |            << "Found invalid GPT and valid MBR; converting MBR to GPT format.\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1463 |       if (!justLooking) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1464 |          cout << "\aTHIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n" | 
 | 1465 |               << "you don't want to convert your MBR partitions to GPT format!\n"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1466 |       } // if | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1467 |       cout << "***************************************************************\n\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1468 |       which = use_mbr; | 
 | 1469 |    } // if | 
 | 1470 |  | 
 | 1471 |    if ((state == gpt_invalid) && bsdFound) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1472 |       cout << "\n**********************************************************************\n" | 
 | 1473 |            << "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n" | 
 | 1474 |            << "to GPT format."; | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 1475 |       if ((!justLooking) && (!beQuiet)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1476 |       cout << "\a THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n" | 
 | 1477 |            << "BSD partition will likely be unusable. Exit by typing 'q' if you don't\n" | 
 | 1478 |            << "want to convert your BSD partitions to GPT format!"; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1479 |       } // if | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1480 |       cout << "\n**********************************************************************\n\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1481 |       which = use_bsd; | 
 | 1482 |    } // if | 
 | 1483 |  | 
 | 1484 |    if ((state == gpt_valid) && (mbrState == gpt)) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1485 |       which = use_gpt; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1486 |       if (!beQuiet) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1487 |          cout << "Found valid GPT with protective MBR; using GPT.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1488 |    } // if | 
 | 1489 |    if ((state == gpt_valid) && (mbrState == hybrid)) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1490 |       which = use_gpt; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1491 |       if (!beQuiet) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1492 |          cout << "Found valid GPT with hybrid MBR; using GPT.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1493 |    } // if | 
 | 1494 |    if ((state == gpt_valid) && (mbrState == invalid)) { | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 1495 |       cout << "\aFound valid GPT with corrupt MBR; using GPT and will write new\n" | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1496 |            << "protective MBR on save.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1497 |       which = use_gpt; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1498 |    } // if | 
 | 1499 |    if ((state == gpt_valid) && (mbrState == mbr)) { | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1500 |       if (!beQuiet) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1501 |          cout << "Found valid MBR and GPT. Which do you want to use?\n"; | 
 | 1502 |          answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1503 |          if (answer == 1) { | 
 | 1504 |             which = use_mbr; | 
 | 1505 |          } else if (answer == 2) { | 
 | 1506 |             which = use_gpt; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1507 |             cout << "Using GPT and creating fresh protective MBR.\n"; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1508 |          } else which = use_new; | 
 | 1509 |       } else which = use_abort; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1510 |    } // if | 
 | 1511 |  | 
 | 1512 |    // Nasty decisions here -- GPT is present, but corrupt (bad CRCs or other | 
 | 1513 |    // problems) | 
 | 1514 |    if (state == gpt_corrupt) { | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1515 |       if (beQuiet) { | 
 | 1516 |          which = use_abort; | 
 | 1517 |       } else { | 
 | 1518 |          if ((mbrState == mbr) || (mbrState == hybrid)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1519 |             cout << "Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n" | 
 | 1520 |                  << "GPT MAY permit recovery of GPT data.)\n"; | 
 | 1521 |             answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1522 |             if (answer == 1) { | 
 | 1523 |                which = use_mbr; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1524 |             } else if (answer == 2) { | 
 | 1525 |                which = use_gpt; | 
 | 1526 |             } else which = use_new; | 
 | 1527 |          } else if (mbrState == invalid) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1528 |             cout << "Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n" | 
 | 1529 |                  << "GPT MAY permit recovery of GPT data.)\n"; | 
 | 1530 |             answer = GetNumber(1, 2, 1, " 1 - GPT\n 2 - Create blank GPT\n\nYour answer: "); | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1531 |             if (answer == 1) { | 
 | 1532 |                which = use_gpt; | 
 | 1533 |             } else which = use_new; | 
 | 1534 |          } else { // corrupt GPT, MBR indicates it's a GPT disk.... | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1535 |             cout << "\a\a****************************************************************************\n" | 
 | 1536 |                  << "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n" | 
 | 1537 |                  << "verification and recovery are STRONGLY recommended.\n" | 
 | 1538 |                  << "****************************************************************************\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1539 |             which = use_gpt; | 
| srs5694 | 3c0af38 | 2010-01-15 19:19:18 -0500 | [diff] [blame] | 1540 |          } // if/else/else | 
 | 1541 |       } // else (beQuiet) | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1542 |    } // if (corrupt GPT) | 
 | 1543 |  | 
 | 1544 |    if (which == use_new) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1545 |       cout << "Creating new GPT entries.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1546 |  | 
 | 1547 |    return which; | 
 | 1548 | } // UseWhichPartitions() | 
 | 1549 |  | 
 | 1550 | // Convert MBR partition table into GPT form | 
 | 1551 | int GPTData::XFormPartitions(void) { | 
 | 1552 |    int i, numToConvert; | 
 | 1553 |    uint8_t origType; | 
 | 1554 |    struct newGUID; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1555 |  | 
 | 1556 |    // Clear out old data & prepare basics.... | 
 | 1557 |    ClearGPTData(); | 
 | 1558 |  | 
 | 1559 |    // Convert the smaller of the # of GPT or MBR partitions | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1560 |    if (mainHeader.numParts > (MAX_MBR_PARTS)) | 
 | 1561 |       numToConvert = MAX_MBR_PARTS; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1562 |    else | 
 | 1563 |       numToConvert = mainHeader.numParts; | 
 | 1564 |  | 
 | 1565 |    for (i = 0; i < numToConvert; i++) { | 
 | 1566 |       origType = protectiveMBR.GetType(i); | 
 | 1567 |       // don't waste CPU time trying to convert extended, hybrid protective, or | 
 | 1568 |       // null (non-existent) partitions | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 1569 |       if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1570 |            (origType != 0x00) && (origType != 0xEE)) | 
 | 1571 |          partitions[i] = protectiveMBR.AsGPT(i); | 
 | 1572 |    } // for | 
 | 1573 |  | 
 | 1574 |    // Convert MBR into protective MBR | 
 | 1575 |    protectiveMBR.MakeProtectiveMBR(); | 
 | 1576 |  | 
 | 1577 |    // Record that all original CRCs were OK so as not to raise flags | 
 | 1578 |    // when doing a disk verification | 
 | 1579 |    mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1; | 
 | 1580 |  | 
 | 1581 |    return (1); | 
 | 1582 | } // GPTData::XFormPartitions() | 
 | 1583 |  | 
 | 1584 | // Transforms BSD disklabel on the specified partition (numbered from 0). | 
 | 1585 | // If an invalid partition number is given, the program prompts for one. | 
 | 1586 | // Returns the number of new partitions created. | 
 | 1587 | int GPTData::XFormDisklabel(int i) { | 
 | 1588 |    uint32_t low, high, partNum, startPart; | 
 | 1589 |    uint16_t hexCode; | 
 | 1590 |    int goOn = 1, numDone = 0; | 
 | 1591 |    BSDData disklabel; | 
 | 1592 |  | 
 | 1593 |    if (GetPartRange(&low, &high) != 0) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1594 |       if ((i < (int) low) || (i > (int) high)) | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1595 |          partNum = GetPartNum(); | 
 | 1596 |       else | 
 | 1597 |          partNum = (uint32_t) i; | 
 | 1598 |  | 
 | 1599 |       // Find the partition after the last used one | 
 | 1600 |       startPart = high + 1; | 
 | 1601 |  | 
 | 1602 |       // Now see if the specified partition has a BSD type code.... | 
 | 1603 |       hexCode = partitions[partNum].GetHexType(); | 
 | 1604 |       if ((hexCode != 0xa500) && (hexCode != 0xa900)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1605 |          cout << "Specified partition doesn't have a disklabel partition type " | 
 | 1606 |               << "code.\nContinue anyway? "; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1607 |          goOn = (GetYN() == 'Y'); | 
 | 1608 |       } // if | 
 | 1609 |  | 
 | 1610 |       // If all is OK, read the disklabel and convert it. | 
 | 1611 |       if (goOn) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1612 |          goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(), | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1613 |                                       partitions[partNum].GetLastLBA()); | 
 | 1614 |          if ((goOn) && (disklabel.IsDisklabel())) { | 
 | 1615 |             numDone = XFormDisklabel(&disklabel, startPart); | 
 | 1616 |             if (numDone == 1) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1617 |                cout << "Converted " << numDone << " BSD partition.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1618 |             else | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1619 |                cout << "Converted " << numDone << " BSD partitions.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1620 |          } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1621 |             cout << "Unable to convert partitions! Unrecognized BSD disklabel.\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1622 |          } // if/else | 
 | 1623 |       } // if | 
 | 1624 |       if (numDone > 0) { // converted partitions; delete carrier | 
 | 1625 |          partitions[partNum].BlankPartition(); | 
 | 1626 |       } // if | 
 | 1627 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1628 |       cout << "No partitions\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1629 |    } // if/else | 
 | 1630 |    return numDone; | 
 | 1631 | } // GPTData::XFormDisklable(int i) | 
 | 1632 |  | 
 | 1633 | // Transform the partitions on an already-loaded BSD disklabel... | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1634 | int GPTData::XFormDisklabel(BSDData* disklabel, uint32_t startPart) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1635 |    int i, numDone = 0; | 
 | 1636 |  | 
 | 1637 |    if ((disklabel->IsDisklabel()) && (startPart >= 0) && | 
 | 1638 |         (startPart < mainHeader.numParts)) { | 
 | 1639 |       for (i = 0; i < disklabel->GetNumParts(); i++) { | 
 | 1640 |          partitions[i + startPart] = disklabel->AsGPT(i); | 
 | 1641 |          if (partitions[i + startPart].GetFirstLBA() != UINT64_C(0)) | 
 | 1642 |             numDone++; | 
 | 1643 |       } // for | 
 | 1644 |    } // if | 
 | 1645 |  | 
 | 1646 |    // Record that all original CRCs were OK so as not to raise flags | 
 | 1647 |    // when doing a disk verification | 
 | 1648 |    mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1; | 
 | 1649 |  | 
 | 1650 |    return numDone; | 
 | 1651 | } // GPTData::XFormDisklabel(BSDData* disklabel) | 
 | 1652 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1653 | // Add one GPT partition to MBR. Used by XFormToMBR() and MakeHybrid() | 
 | 1654 | // functions. Returns 1 if operation was successful. | 
 | 1655 | int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) { | 
 | 1656 |    int allOK = 1, typeCode, bootable; | 
 | 1657 |    uint64_t length; | 
 | 1658 |    char line[255]; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1659 |    char* junk; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1660 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1661 |    cout.setf(ios::uppercase); | 
 | 1662 |    cout.fill('0'); | 
 | 1663 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1664 |    if ((mbrPart < 0) || (mbrPart > 3)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1665 |       cout << "MBR partition " << mbrPart + 1 << " is out of range; omitting it.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1666 |       allOK = 0; | 
 | 1667 |    } // if | 
 | 1668 |    if (gptPart >= mainHeader.numParts) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1669 |       cout << "GPT partition " << gptPart + 1 << " is out of range; omitting it.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1670 |       allOK = 0; | 
 | 1671 |    } // if | 
 | 1672 |    if (allOK && (partitions[gptPart].GetLastLBA() == UINT64_C(0))) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1673 |       cout << "GPT partition " << gptPart + 1 << " is undefined; omitting it.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1674 |       allOK = 0; | 
 | 1675 |    } // if | 
 | 1676 |    if (allOK && (partitions[gptPart].GetFirstLBA() <= UINT32_MAX) && | 
 | 1677 |        (partitions[gptPart].GetLengthLBA() <= UINT32_MAX)) { | 
 | 1678 |       if (partitions[gptPart].GetLastLBA() > UINT32_MAX) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1679 |          cout << "Caution: Partition end point past 32-bit pointer boundary;" | 
 | 1680 |               << " some OSes may\nreact strangely.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1681 |       } // if partition ends past 32-bit (usually 2TiB) boundary | 
 | 1682 |       do { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1683 |          cout << "Enter an MBR hex code (default " << hex; | 
 | 1684 |          cout.width(2); | 
 | 1685 |          cout << typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256 << "): "; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1686 |          junk = fgets(line, 255, stdin); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1687 |          if (line[0] == '\n') | 
 | 1688 |             typeCode = partitions[gptPart].GetHexType() / 256; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1689 |          else | 
 | 1690 |             sscanf(line, "%x", &typeCode); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1691 |       } while ((typeCode <= 0) || (typeCode > 255)); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1692 |       cout << "Set the bootable flag? "; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1693 |       bootable = (GetYN() == 'Y'); | 
 | 1694 |       length = partitions[gptPart].GetLengthLBA(); | 
 | 1695 |       protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(), | 
 | 1696 |                              (uint32_t) length, typeCode, bootable); | 
 | 1697 |    } else { // partition out of range | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1698 |       cout << "Partition " << gptPart + 1 << " begins beyond the 32-bit pointer limit of MBR " | 
 | 1699 |            << "partitions, or is\n too big; omitting it.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1700 |       allOK = 0; | 
 | 1701 |    } // if/else | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1702 |    cout.fill(' '); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1703 |    return allOK; | 
 | 1704 | } // GPTData::OnePartToMBR() | 
 | 1705 |  | 
 | 1706 | // Convert the GPT to MBR form. This function is necessarily limited; it | 
 | 1707 | // handles at most four partitions and creates layouts that ignore CHS | 
 | 1708 | // geometries. Returns the number of converted partitions; if this value | 
 | 1709 | // is over 0, the calling function should call DestroyGPT() to destroy | 
 | 1710 | // the GPT data, and then exit. | 
 | 1711 | int GPTData::XFormToMBR(void) { | 
 | 1712 |    char line[255]; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1713 |    char* junk; | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1714 |    int j, numParts, numConverted = 0; | 
 | 1715 |    uint32_t i, partNums[4]; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1716 |  | 
 | 1717 |    // Get the numbers of up to four partitions to add to the | 
 | 1718 |    // hybrid MBR.... | 
 | 1719 |    numParts = CountParts(); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1720 |    cout << "Counted " << numParts << " partitions.\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1721 |  | 
 | 1722 |    // Prepare the MBR for conversion (empty it of existing partitions). | 
 | 1723 |    protectiveMBR.EmptyMBR(0); | 
 | 1724 |    protectiveMBR.SetDiskSize(diskSize); | 
 | 1725 |  | 
 | 1726 |    if (numParts > 4) { // Over four partitions; engage in triage | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1727 |       cout << "Type from one to four GPT partition numbers, separated by spaces, to be\n" | 
 | 1728 |            << "used in the MBR, in sequence: "; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1729 |       junk = fgets(line, 255, stdin); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1730 |       numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1], | 
 | 1731 |                         &partNums[2], &partNums[3]); | 
 | 1732 |    } else { // Four or fewer partitions; convert them all | 
 | 1733 |       i = j = 0; | 
 | 1734 |       while ((j < numParts) && (i < mainHeader.numParts)) { | 
 | 1735 |          if (partitions[i].GetFirstLBA() > 0) { // if GPT part. is defined | 
 | 1736 |             partNums[j++] = ++i; // flag it for conversion | 
 | 1737 |          } else i++; | 
 | 1738 |       } // while | 
 | 1739 |    } // if/else | 
 | 1740 |  | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1741 |    for (i = 0; i < (uint32_t) numParts; i++) { | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1742 |       j = partNums[i] - 1; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1743 |       cout << "\nCreating entry for partition #" << j + 1 << "\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1744 |       numConverted += OnePartToMBR(j, i); | 
 | 1745 |    } // for | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1746 |    cout << "MBR writing returned " << protectiveMBR.WriteMBRData(&myDisk) << "\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1747 |    return numConverted; | 
 | 1748 | } // GPTData::XFormToMBR() | 
 | 1749 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1750 | // Create a hybrid MBR -- an ugly, funky thing that helps GPT work with | 
 | 1751 | // OSes that don't understand GPT. | 
 | 1752 | void GPTData::MakeHybrid(void) { | 
 | 1753 |    uint32_t partNums[3]; | 
 | 1754 |    char line[255]; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1755 |    char* junk; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1756 |    int numParts, numConverted = 0, i, j, typeCode, mbrNum; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1757 |    char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe) | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1758 |    char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1759 |  | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1760 |    cout << "\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n" | 
 | 1761 |         << "to use one, just hit the Enter key at the below prompt and your MBR\n" | 
 | 1762 |         << "partition table will be untouched.\n\n\a"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1763 |  | 
 | 1764 |    // Now get the numbers of up to three partitions to add to the | 
 | 1765 |    // hybrid MBR.... | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1766 |    cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n" | 
 | 1767 |         << "added to the hybrid MBR, in sequence: "; | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1768 |    junk = fgets(line, 255, stdin); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1769 |    numParts = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]); | 
 | 1770 |  | 
 | 1771 |    if (numParts > 0) { | 
 | 1772 |       // Blank out the protective MBR, but leave the boot loader code | 
 | 1773 |       // alone.... | 
 | 1774 |       protectiveMBR.EmptyMBR(0); | 
 | 1775 |       protectiveMBR.SetDiskSize(diskSize); | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1776 |       cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? "; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1777 |       eeFirst = GetYN(); | 
 | 1778 |    } // if | 
 | 1779 |  | 
 | 1780 |    for (i = 0; i < numParts; i++) { | 
 | 1781 |       j = partNums[i] - 1; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1782 |       cout << "\nCreating entry for partition #" << j + 1 << "\n"; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1783 |       if (eeFirst == 'Y') | 
 | 1784 |          mbrNum = i + 1; | 
 | 1785 |       else | 
 | 1786 |          mbrNum = i; | 
 | 1787 |       numConverted += OnePartToMBR(j, mbrNum); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1788 |    } // for | 
 | 1789 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1790 |    if ((numParts > 0) && (numConverted > 0)) { // User opted to create a hybrid MBR.... | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1791 |       // Create EFI protective partition that covers the start of the disk. | 
 | 1792 |       // If this location (covering the main GPT data structures) is omitted, | 
 | 1793 |       // Linux won't find any partitions on the disk. Note that this is | 
 | 1794 |       // NUMBERED AFTER the hybrid partitions, contrary to what the | 
 | 1795 |       // gptsync utility does. This is because Windows seems to choke on | 
 | 1796 |       // disks with a 0xEE partition in the first slot and subsequent | 
 | 1797 |       // additional partitions, unless it boots from the disk. | 
 | 1798 |       if (eeFirst == 'Y') | 
 | 1799 |          mbrNum = 0; | 
 | 1800 |       else | 
 | 1801 |          mbrNum = numParts; | 
 | 1802 |       protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), 0xEE); | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 1803 |       protectiveMBR.SetHybrid(); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1804 |  | 
 | 1805 |       // ... and for good measure, if there are any partition spaces left, | 
 | 1806 |       // optionally create another protective EFI partition to cover as much | 
 | 1807 |       // space as possible.... | 
 | 1808 |       for (i = 0; i < 4; i++) { | 
 | 1809 |          if (protectiveMBR.GetType(i) == 0x00) { // unused entry.... | 
 | 1810 |             if (fillItUp == 'M') { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1811 |                cout << "\nUnused partition space(s) found. Use one to protect more partitions? "; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1812 |                fillItUp = GetYN(); | 
 | 1813 |                typeCode = 0x00; // use this to flag a need to get type code | 
 | 1814 |             } // if | 
 | 1815 |             if (fillItUp == 'Y') { | 
 | 1816 |                while ((typeCode <= 0) || (typeCode > 255)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1817 |                   cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): "; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1818 |                   // Comment on above: Mac OS treats disks with more than one | 
 | 1819 |                   // 0xEE MBR partition as MBR disks, not as GPT disks. | 
| srs5694 | 5d58fe0 | 2010-01-03 20:57:08 -0500 | [diff] [blame] | 1820 |                   junk = fgets(line, 255, stdin); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1821 |                   sscanf(line, "%x", &typeCode); | 
 | 1822 |                   if (line[0] == '\n') | 
 | 1823 |                      typeCode = 0; | 
 | 1824 |                } // while | 
 | 1825 |                protectiveMBR.MakeBiggestPart(i, typeCode); // make a partition | 
 | 1826 |             } // if (fillItUp == 'Y') | 
 | 1827 |          } // if unused entry | 
 | 1828 |       } // for (i = 0; i < 4; i++) | 
 | 1829 |    } // if (numParts > 0) | 
 | 1830 | } // GPTData::MakeHybrid() | 
 | 1831 |  | 
 | 1832 | /********************************************************************** | 
 | 1833 |  *                                                                    * | 
 | 1834 |  * Functions that adjust GPT data structures WITHOUT user interaction * | 
 | 1835 |  * (they may display information for the user's benefit, though)      * | 
 | 1836 |  *                                                                    * | 
 | 1837 |  **********************************************************************/ | 
 | 1838 |  | 
 | 1839 | // Resizes GPT to specified number of entries. Creates a new table if | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1840 | // necessary, copies data if it already exists. Returns 1 if all goes | 
 | 1841 | // well, 0 if an error is encountered. | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1842 | int GPTData::SetGPTSize(uint32_t numEntries) { | 
 | 1843 |    struct GPTPart* newParts; | 
 | 1844 |    struct GPTPart* trash; | 
 | 1845 |    uint32_t i, high, copyNum; | 
 | 1846 |    int allOK = 1; | 
 | 1847 |  | 
 | 1848 |    // First, adjust numEntries upward, if necessary, to get a number | 
 | 1849 |    // that fills the allocated sectors | 
 | 1850 |    i = blockSize / GPT_SIZE; | 
 | 1851 |    if ((numEntries % i) != 0) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1852 |       cout << "Adjusting GPT size from " << numEntries << " to "; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1853 |       numEntries = ((numEntries / i) + 1) * i; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1854 |       cout << numEntries << " to fill the sector\n"; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1855 |    } // if | 
 | 1856 |  | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 1857 |    // Do the work only if the # of partitions is changing. Along with being | 
 | 1858 |    // efficient, this prevents mucking the with location of the secondary | 
 | 1859 |    // partition table, which causes problems when loading data from a RAID | 
 | 1860 |    // array that's been expanded because this function is called when loading | 
 | 1861 |    // data. | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1862 |    if ((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts) | 
 | 1863 |        || (partitions == NULL)) { | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 1864 |       newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart)); | 
 | 1865 |       if (newParts != NULL) { | 
 | 1866 |          if (partitions != NULL) { // existing partitions; copy them over | 
 | 1867 |             GetPartRange(&i, &high); | 
 | 1868 |             if (numEntries < (high + 1)) { // Highest entry too high for new # | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1869 |                cout << "The highest-numbered partition is " << high + 1 | 
 | 1870 |                     << ", which is greater than the requested\n" | 
 | 1871 |                     << "partition table size of " << numEntries | 
 | 1872 |                     << "; cannot resize. Perhaps sorting will help.\n"; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 1873 |                allOK = 0; | 
 | 1874 |             } else { // go ahead with copy | 
 | 1875 |                if (numEntries < mainHeader.numParts) | 
 | 1876 |                   copyNum = numEntries; | 
 | 1877 |                else | 
 | 1878 |                   copyNum = mainHeader.numParts; | 
 | 1879 |                for (i = 0; i < copyNum; i++) { | 
 | 1880 |                   newParts[i] = partitions[i]; | 
 | 1881 |                } // for | 
 | 1882 |                trash = partitions; | 
 | 1883 |                partitions = newParts; | 
 | 1884 |                free(trash); | 
 | 1885 |             } // if | 
 | 1886 |          } else { // No existing partition table; just create it | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1887 |             partitions = newParts; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 1888 |          } // if/else existing partitions | 
 | 1889 |          mainHeader.numParts = numEntries; | 
 | 1890 |          secondHeader.numParts = numEntries; | 
 | 1891 |          mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + 2 ; | 
 | 1892 |          secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; | 
 | 1893 |          MoveSecondHeaderToEnd(); | 
 | 1894 |          if (diskSize > 0) | 
 | 1895 |             CheckGPTSize(); | 
 | 1896 |       } else { // Bad memory allocation | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1897 |          cerr << "Error allocating memory for partition table!\n"; | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 1898 |          allOK = 0; | 
 | 1899 |       } // if/else | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1900 |    } // if/else | 
 | 1901 |    return (allOK); | 
 | 1902 | } // GPTData::SetGPTSize() | 
 | 1903 |  | 
 | 1904 | // Blank the partition array | 
 | 1905 | void GPTData::BlankPartitions(void) { | 
 | 1906 |    uint32_t i; | 
 | 1907 |  | 
 | 1908 |    for (i = 0; i < mainHeader.numParts; i++) { | 
 | 1909 |       partitions[i].BlankPartition(); | 
 | 1910 |    } // for | 
 | 1911 | } // GPTData::BlankPartitions() | 
 | 1912 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1913 | // Delete a partition by number. Returns 1 if successful, | 
 | 1914 | // 0 if there was a problem. Returns 1 if partition was in | 
 | 1915 | // range, 0 if it was out of range. | 
 | 1916 | int GPTData::DeletePartition(uint32_t partNum) { | 
 | 1917 |    uint64_t startSector, length; | 
 | 1918 |    uint32_t low, high, numParts, retval = 1;; | 
 | 1919 |  | 
 | 1920 |    numParts = GetPartRange(&low, &high); | 
 | 1921 |    if ((numParts > 0) && (partNum >= low) && (partNum <= high)) { | 
 | 1922 |       // In case there's a protective MBR, look for & delete matching | 
 | 1923 |       // MBR partition.... | 
 | 1924 |       startSector = partitions[partNum].GetFirstLBA(); | 
 | 1925 |       length = partitions[partNum].GetLengthLBA(); | 
 | 1926 |       protectiveMBR.DeleteByLocation(startSector, length); | 
 | 1927 |  | 
 | 1928 |       // Now delete the GPT partition | 
 | 1929 |       partitions[partNum].BlankPartition(); | 
 | 1930 |    } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 1931 |       cerr << "Partition number " << partNum + 1 << " out of range!\n"; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1932 |       retval = 0; | 
 | 1933 |    } // if/else | 
 | 1934 |    return retval; | 
 | 1935 | } // GPTData::DeletePartition(uint32_t partNum) | 
 | 1936 |  | 
 | 1937 | // Non-interactively create a partition. Note that this function is overloaded | 
 | 1938 | // with another of the same name but different parameters; that one prompts | 
 | 1939 | // the user for data. This one returns 1 if the operation was successful, 0 | 
 | 1940 | // if a problem was discovered. | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 1941 | uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) { | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 1942 |    int retval = 1; // assume there'll be no problems | 
 | 1943 |  | 
 | 1944 |    if (IsFreePartNum(partNum)) { | 
 | 1945 |       Align(&startSector); // Align sector to correct multiple | 
 | 1946 |       if (IsFree(startSector) && (startSector <= endSector)) { | 
 | 1947 |          if (FindLastInFree(startSector) >= endSector) { | 
 | 1948 |             partitions[partNum].SetFirstLBA(startSector); | 
 | 1949 |             partitions[partNum].SetLastLBA(endSector); | 
 | 1950 |             partitions[partNum].SetType(0x0700); | 
 | 1951 |             partitions[partNum].SetUniqueGUID(1); | 
 | 1952 |          } else retval = 0; // if free space until endSector | 
 | 1953 |       } else retval = 0; // if startSector is free | 
 | 1954 |    } else retval = 0; // if legal partition number | 
 | 1955 |    return retval; | 
 | 1956 | } // GPTData::CreatePartition(partNum, startSector, endSector) | 
 | 1957 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1958 | // Sort the GPT entries, eliminating gaps and making for a logical | 
 | 1959 | // ordering. Relies on QuickSortGPT() for the bulk of the work | 
 | 1960 | void GPTData::SortGPT(void) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1961 |    GPTPart temp; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1962 |    uint32_t i, numFound, firstPart, lastPart; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1963 |  | 
 | 1964 |    // First, find the last partition with data, so as not to | 
 | 1965 |    // spend needless time sorting empty entries.... | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1966 |    numFound = GetPartRange(&firstPart, &lastPart); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1967 |  | 
 | 1968 |    // Now swap empties with the last partitions, to simplify the logic | 
 | 1969 |    // in the Quicksort function.... | 
 | 1970 |    i = 0; | 
 | 1971 |    while (i < lastPart) { | 
 | 1972 |       if (partitions[i].GetFirstLBA() == 0) { | 
 | 1973 |          temp = partitions[i]; | 
 | 1974 |          partitions[i] = partitions[lastPart]; | 
 | 1975 |          partitions[lastPart] = temp; | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1976 |          do { | 
 | 1977 |             lastPart--; | 
 | 1978 |          } while ((lastPart > 0) && (partitions[lastPart].GetFirstLBA() == 0)); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1979 |       } // if | 
 | 1980 |       i++; | 
 | 1981 |    } // while | 
 | 1982 |  | 
| srs5694 | 546a9c7 | 2010-01-26 16:00:26 -0500 | [diff] [blame] | 1983 |    // If there are more empties than partitions in the range from 0 to lastPart, | 
 | 1984 |    // the above leaves lastPart set too high, so we've got to adjust it to | 
 | 1985 |    // prevent empties from migrating to the top of the list.... | 
 | 1986 |    GetPartRange(&firstPart, &lastPart); | 
 | 1987 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1988 |    // Now call the recursive quick sort routine to do the real work.... | 
 | 1989 |    QuickSortGPT(partitions, 0, lastPart); | 
 | 1990 | } // GPTData::SortGPT() | 
 | 1991 |  | 
 | 1992 | // Set up data structures for entirely new set of partitions on the | 
 | 1993 | // specified device. Returns 1 if OK, 0 if there were problems. | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 1994 | // Note that this function does NOT clear the protectiveMBR data | 
 | 1995 | // structure, since it may hold the original MBR partitions if the | 
 | 1996 | // program was launched on an MBR disk, and those may need to be | 
 | 1997 | // converted to GPT format. | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 1998 | int GPTData::ClearGPTData(void) { | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 1999 |    int goOn = 1, i; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2000 |  | 
 | 2001 |    // Set up the partition table.... | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2002 |    if (partitions != NULL) | 
 | 2003 |       free(partitions); | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2004 |    partitions = NULL; | 
 | 2005 |    SetGPTSize(NUM_GPT_ENTRIES); | 
 | 2006 |  | 
 | 2007 |    // Now initialize a bunch of stuff that's static.... | 
 | 2008 |    mainHeader.signature = GPT_SIGNATURE; | 
 | 2009 |    mainHeader.revision = 0x00010000; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 2010 |    mainHeader.headerSize = HEADER_SIZE; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2011 |    mainHeader.reserved = 0; | 
 | 2012 |    mainHeader.currentLBA = UINT64_C(1); | 
 | 2013 |    mainHeader.partitionEntriesLBA = (uint64_t) 2; | 
 | 2014 |    mainHeader.sizeOfPartitionEntries = GPT_SIZE; | 
 | 2015 |    for (i = 0; i < GPT_RESERVED; i++) { | 
 | 2016 |       mainHeader.reserved2[i] = '\0'; | 
 | 2017 |    } // for | 
 | 2018 |  | 
 | 2019 |    // Now some semi-static items (computed based on end of disk) | 
 | 2020 |    mainHeader.backupLBA = diskSize - UINT64_C(1); | 
 | 2021 |    mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; | 
 | 2022 |  | 
 | 2023 |    // Set a unique GUID for the disk, based on random numbers | 
 | 2024 |    // rand() is only 32 bits, so multiply together to fill a 64-bit value | 
 | 2025 |    mainHeader.diskGUID.data1 = (uint64_t) rand() * (uint64_t) rand(); | 
 | 2026 |    mainHeader.diskGUID.data2 = (uint64_t) rand() * (uint64_t) rand(); | 
 | 2027 |  | 
 | 2028 |    // Copy main header to backup header | 
 | 2029 |    RebuildSecondHeader(); | 
 | 2030 |  | 
 | 2031 |    // Blank out the partitions array.... | 
 | 2032 |    BlankPartitions(); | 
 | 2033 |  | 
 | 2034 |    // Flag all CRCs as being OK.... | 
 | 2035 |    mainCrcOk = 1; | 
 | 2036 |    secondCrcOk = 1; | 
 | 2037 |    mainPartsCrcOk = 1; | 
 | 2038 |    secondPartsCrcOk = 1; | 
 | 2039 |  | 
 | 2040 |    return (goOn); | 
 | 2041 | } // GPTData::ClearGPTData() | 
 | 2042 |  | 
| srs5694 | 247657a | 2009-11-26 18:36:12 -0500 | [diff] [blame] | 2043 | // Set the location of the second GPT header data to the end of the disk. | 
 | 2044 | // Used internally and called by the 'e' option on the recovery & | 
 | 2045 | // transformation menu, to help users of RAID arrays who add disk space | 
 | 2046 | // to their arrays. | 
 | 2047 | void GPTData::MoveSecondHeaderToEnd() { | 
| srs5694 | 8bb7876 | 2009-11-24 15:43:49 -0500 | [diff] [blame] | 2048 |    mainHeader.backupLBA = secondHeader.currentLBA = diskSize - UINT64_C(1); | 
 | 2049 |    mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; | 
 | 2050 |    secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); | 
 | 2051 | } // GPTData::FixSecondHeaderLocation() | 
 | 2052 |  | 
| srs5694 | 0a69731 | 2010-01-28 21:10:52 -0500 | [diff] [blame] | 2053 | int GPTData::SetName(uint32_t partNum, const string & theName) { | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 2054 |    int retval = 1; | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2055 |  | 
 | 2056 |    if (!IsFreePartNum(partNum)) { | 
 | 2057 |       partitions[partNum].SetName(theName); | 
 | 2058 |    } else retval = 0; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 2059 |  | 
 | 2060 |    return retval; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2061 | } // GPTData::SetName | 
 | 2062 |  | 
 | 2063 | // Set the disk GUID to the specified value. Note that the header CRCs must | 
 | 2064 | // be recomputed after calling this function. | 
 | 2065 | void GPTData::SetDiskGUID(GUIDData newGUID) { | 
 | 2066 |    mainHeader.diskGUID = newGUID; | 
 | 2067 |    secondHeader.diskGUID = newGUID; | 
 | 2068 | } // SetDiskGUID() | 
 | 2069 |  | 
 | 2070 | // Set the unique GUID of the specified partition. Returns 1 on | 
 | 2071 | // successful completion, 0 if there were problems (invalid | 
 | 2072 | // partition number). | 
 | 2073 | int GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) { | 
 | 2074 |    int retval = 0; | 
 | 2075 |  | 
 | 2076 |    if (pn < mainHeader.numParts) { | 
 | 2077 |       if (partitions[pn].GetFirstLBA() != UINT64_C(0)) { | 
 | 2078 |          partitions[pn].SetUniqueGUID(theGUID); | 
 | 2079 |          retval = 1; | 
 | 2080 |       } // if | 
 | 2081 |    } // if | 
 | 2082 |    return retval; | 
 | 2083 | } // GPTData::SetPartitionGUID() | 
 | 2084 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 2085 | // Change partition type code non-interactively. Returns 1 if | 
 | 2086 | // successful, 0 if not.... | 
 | 2087 | int GPTData::ChangePartType(uint32_t partNum, uint16_t hexCode) { | 
 | 2088 |    int retval = 1; | 
 | 2089 |  | 
 | 2090 |    if (!IsFreePartNum(partNum)) { | 
 | 2091 |       partitions[partNum].SetType(hexCode); | 
 | 2092 |    } else retval = 0; | 
 | 2093 |    return retval; | 
 | 2094 | } // GPTData::ChangePartType() | 
 | 2095 |  | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 2096 | // Adjust sector number so that it falls on a sector boundary that's a | 
 | 2097 | // multiple of sectorAlignment. This is done to improve the performance | 
 | 2098 | // of Western Digital Advanced Format disks and disks with similar | 
 | 2099 | // technology from other companies, which use 4096-byte sectors | 
 | 2100 | // internally although they translate to 512-byte sectors for the | 
 | 2101 | // benefit of the OS. If partitions aren't properly aligned on these | 
 | 2102 | // disks, some filesystem data structures can span multiple physical | 
 | 2103 | // sectors, degrading performance. This function should be called | 
 | 2104 | // only on the FIRST sector of the partition, not the last! | 
 | 2105 | // This function returns 1 if the alignment was altered, 0 if it | 
 | 2106 | // was unchanged. | 
 | 2107 | int GPTData::Align(uint64_t* sector) { | 
 | 2108 |    int retval = 0, sectorOK = 0; | 
 | 2109 |    uint64_t earlier, later, testSector, original; | 
 | 2110 |  | 
 | 2111 |    if ((*sector % sectorAlignment) != 0) { | 
 | 2112 |       original = *sector; | 
 | 2113 |       retval = 1; | 
 | 2114 |       earlier = (*sector / sectorAlignment) * sectorAlignment; | 
 | 2115 |       later = earlier + (uint64_t) sectorAlignment; | 
 | 2116 |  | 
 | 2117 |       // Check to see that every sector between the earlier one and the | 
 | 2118 |       // requested one is clear, and that it's not too early.... | 
 | 2119 |       if (earlier >= mainHeader.firstUsableLBA) { | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 2120 |          sectorOK = 1; | 
 | 2121 |          testSector = earlier; | 
 | 2122 |          do { | 
 | 2123 |             sectorOK = IsFree(testSector++); | 
 | 2124 |          } while ((sectorOK == 1) && (testSector < *sector)); | 
 | 2125 |          if (sectorOK == 1) { | 
 | 2126 |             *sector = earlier; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 2127 |          } // if | 
 | 2128 |       } // if firstUsableLBA check | 
 | 2129 |  | 
 | 2130 |       // If couldn't move the sector earlier, try to move it later instead.... | 
 | 2131 |       if ((sectorOK != 1) && (later <= mainHeader.lastUsableLBA)) { | 
 | 2132 |          sectorOK = 1; | 
 | 2133 |          testSector = later; | 
 | 2134 |          do { | 
 | 2135 |             sectorOK = IsFree(testSector--); | 
 | 2136 |          } while ((sectorOK == 1) && (testSector > *sector)); | 
 | 2137 |          if (sectorOK == 1) { | 
 | 2138 |             *sector = later; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 2139 |          } // if | 
 | 2140 |       } // if | 
 | 2141 |  | 
 | 2142 |       // If sector was changed successfully, inform the user of this fact. | 
 | 2143 |       // Otherwise, notify the user that it couldn't be done.... | 
 | 2144 |       if (sectorOK == 1) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2145 |          cout << "Information: Moved requested sector from " << original << " to " | 
 | 2146 |               << *sector << " for\nalignment purposes.\n"; | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 2147 |          if (!beQuiet) | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2148 |             cout << "Use 'l' on the experts' menu to adjust alignment\n"; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 2149 |       } else { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2150 |          cout << "Information: Sector not aligned on " << sectorAlignment | 
 | 2151 |               << "-sector boundary and could not be moved.\n" | 
 | 2152 |               << "If you're using a Western Digital Advanced Format or similar disk with\n" | 
 | 2153 |               << "underlying 4096-byte sectors, performance may suffer.\n"; | 
| srs5694 | 1d1448a | 2009-12-31 21:20:19 -0500 | [diff] [blame] | 2154 |          retval = 0; | 
 | 2155 |       } // if/else | 
 | 2156 |    } // if | 
 | 2157 |    return retval; | 
 | 2158 | } // GPTData::Align() | 
 | 2159 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2160 | /******************************************************** | 
 | 2161 |  *                                                      * | 
 | 2162 |  * Functions that return data about GPT data structures * | 
 | 2163 |  * (most of these are inline in gpt.h)                  * | 
 | 2164 |  *                                                      * | 
 | 2165 |  ********************************************************/ | 
 | 2166 |  | 
 | 2167 | // Find the low and high used partition numbers (numbered from 0). | 
 | 2168 | // Return value is the number of partitions found. Note that the | 
 | 2169 | // *low and *high values are both set to 0 when no partitions | 
 | 2170 | // are found, as well as when a single partition in the first | 
 | 2171 | // position exists. Thus, the return value is the only way to | 
 | 2172 | // tell when no partitions exist. | 
 | 2173 | int GPTData::GetPartRange(uint32_t *low, uint32_t *high) { | 
 | 2174 |    uint32_t i; | 
 | 2175 |    int numFound = 0; | 
 | 2176 |  | 
 | 2177 |    *low = mainHeader.numParts + 1; // code for "not found" | 
 | 2178 |    *high = 0; | 
 | 2179 |    if (mainHeader.numParts > 0) { // only try if partition table exists... | 
 | 2180 |       for (i = 0; i < mainHeader.numParts; i++) { | 
 | 2181 |          if (partitions[i].GetFirstLBA() != UINT64_C(0)) { // it exists | 
 | 2182 |             *high = i; // since we're counting up, set the high value | 
 | 2183 | 	    // Set the low value only if it's not yet found... | 
 | 2184 |             if (*low == (mainHeader.numParts + 1)) *low = i; | 
 | 2185 |             numFound++; | 
 | 2186 |          } // if | 
 | 2187 |       } // for | 
 | 2188 |    } // if | 
 | 2189 |  | 
 | 2190 |    // Above will leave *low pointing to its "not found" value if no partitions | 
 | 2191 |    // are defined, so reset to 0 if this is the case.... | 
 | 2192 |    if (*low == (mainHeader.numParts + 1)) | 
 | 2193 |       *low = 0; | 
 | 2194 |    return numFound; | 
 | 2195 | } // GPTData::GetPartRange() | 
 | 2196 |  | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 2197 | // Returns the number of defined partitions. | 
 | 2198 | uint32_t GPTData::CountParts(void) { | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 2199 |    uint32_t i, counted = 0; | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 2200 |  | 
 | 2201 |    for (i = 0; i < mainHeader.numParts; i++) { | 
 | 2202 |       if (partitions[i].GetFirstLBA() > 0) | 
 | 2203 |          counted++; | 
 | 2204 |    } // for | 
 | 2205 |    return counted; | 
 | 2206 | } // GPTData::CountParts() | 
 | 2207 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2208 | /**************************************************** | 
 | 2209 |  *                                                  * | 
 | 2210 |  * Functions that return data about disk free space * | 
 | 2211 |  *                                                  * | 
 | 2212 |  ****************************************************/ | 
 | 2213 |  | 
 | 2214 | // Find the first available block after the starting point; returns 0 if | 
 | 2215 | // there are no available blocks left | 
 | 2216 | uint64_t GPTData::FindFirstAvailable(uint64_t start) { | 
 | 2217 |    uint64_t first; | 
 | 2218 |    uint32_t i; | 
 | 2219 |    int firstMoved = 0; | 
 | 2220 |  | 
 | 2221 |    // Begin from the specified starting point or from the first usable | 
 | 2222 |    // LBA, whichever is greater... | 
 | 2223 |    if (start < mainHeader.firstUsableLBA) | 
 | 2224 |       first = mainHeader.firstUsableLBA; | 
 | 2225 |    else | 
 | 2226 |       first = start; | 
 | 2227 |  | 
 | 2228 |    // ...now search through all partitions; if first is within an | 
 | 2229 |    // existing partition, move it to the next sector after that | 
 | 2230 |    // partition and repeat. If first was moved, set firstMoved | 
 | 2231 |    // flag; repeat until firstMoved is not set, so as to catch | 
 | 2232 |    // cases where partitions are out of sequential order.... | 
 | 2233 |    do { | 
 | 2234 |       firstMoved = 0; | 
 | 2235 |       for (i = 0; i < mainHeader.numParts; i++) { | 
 | 2236 |          if ((first >= partitions[i].GetFirstLBA()) && | 
 | 2237 |               (first <= partitions[i].GetLastLBA())) { // in existing part. | 
 | 2238 |             first = partitions[i].GetLastLBA() + 1; | 
 | 2239 |             firstMoved = 1; | 
 | 2240 |               } // if | 
 | 2241 |       } // for | 
 | 2242 |    } while (firstMoved == 1); | 
 | 2243 |    if (first > mainHeader.lastUsableLBA) | 
 | 2244 |       first = 0; | 
 | 2245 |    return (first); | 
 | 2246 | } // GPTData::FindFirstAvailable() | 
 | 2247 |  | 
 | 2248 | // Finds the first available sector in the largest block of unallocated | 
 | 2249 | // space on the disk. Returns 0 if there are no available blocks left | 
 | 2250 | uint64_t GPTData::FindFirstInLargest(void) { | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 2251 |    uint64_t start, firstBlock, lastBlock, segmentSize, selectedSize = 0, selectedSegment = 0; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2252 |  | 
 | 2253 |    start = 0; | 
 | 2254 |    do { | 
 | 2255 |       firstBlock = FindFirstAvailable(start); | 
 | 2256 |       if (firstBlock != UINT32_C(0)) { // something's free... | 
 | 2257 |          lastBlock = FindLastInFree(firstBlock); | 
 | 2258 |          segmentSize = lastBlock - firstBlock + UINT32_C(1); | 
 | 2259 |          if (segmentSize > selectedSize) { | 
 | 2260 |             selectedSize = segmentSize; | 
 | 2261 |             selectedSegment = firstBlock; | 
 | 2262 |          } // if | 
 | 2263 |          start = lastBlock + 1; | 
 | 2264 |       } // if | 
 | 2265 |    } while (firstBlock != 0); | 
 | 2266 |    return selectedSegment; | 
 | 2267 | } // GPTData::FindFirstInLargest() | 
 | 2268 |  | 
 | 2269 | // Find the last available block on the disk at or after the start | 
 | 2270 | // block. Returns 0 if there are no available partitions after | 
 | 2271 | // (or including) start. | 
 | 2272 | uint64_t GPTData::FindLastAvailable(uint64_t start) { | 
 | 2273 |    uint64_t last; | 
 | 2274 |    uint32_t i; | 
 | 2275 |    int lastMoved = 0; | 
 | 2276 |  | 
 | 2277 |    // Start by assuming the last usable LBA is available.... | 
 | 2278 |    last = mainHeader.lastUsableLBA; | 
 | 2279 |  | 
 | 2280 |    // ...now, similar to algorithm in FindFirstAvailable(), search | 
 | 2281 |    // through all partitions, moving last when it's in an existing | 
 | 2282 |    // partition. Set the lastMoved flag so we repeat to catch cases | 
 | 2283 |    // where partitions are out of logical order. | 
 | 2284 |    do { | 
 | 2285 |       lastMoved = 0; | 
 | 2286 |       for (i = 0; i < mainHeader.numParts; i++) { | 
 | 2287 |          if ((last >= partitions[i].GetFirstLBA()) && | 
 | 2288 |               (last <= partitions[i].GetLastLBA())) { // in existing part. | 
 | 2289 |             last = partitions[i].GetFirstLBA() - 1; | 
 | 2290 |             lastMoved = 1; | 
 | 2291 |               } // if | 
 | 2292 |       } // for | 
 | 2293 |    } while (lastMoved == 1); | 
 | 2294 |    if (last < mainHeader.firstUsableLBA) | 
 | 2295 |       last = 0; | 
 | 2296 |    return (last); | 
 | 2297 | } // GPTData::FindLastAvailable() | 
 | 2298 |  | 
 | 2299 | // Find the last available block in the free space pointed to by start. | 
 | 2300 | uint64_t GPTData::FindLastInFree(uint64_t start) { | 
 | 2301 |    uint64_t nearestStart; | 
 | 2302 |    uint32_t i; | 
 | 2303 |  | 
 | 2304 |    nearestStart = mainHeader.lastUsableLBA; | 
 | 2305 |    for (i = 0; i < mainHeader.numParts; i++) { | 
 | 2306 |       if ((nearestStart > partitions[i].GetFirstLBA()) && | 
 | 2307 |            (partitions[i].GetFirstLBA() > start)) { | 
 | 2308 |          nearestStart = partitions[i].GetFirstLBA() - 1; | 
 | 2309 |            } // if | 
 | 2310 |    } // for | 
 | 2311 |    return (nearestStart); | 
 | 2312 | } // GPTData::FindLastInFree() | 
 | 2313 |  | 
 | 2314 | // Finds the total number of free blocks, the number of segments in which | 
 | 2315 | // they reside, and the size of the largest of those segments | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 2316 | uint64_t GPTData::FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment) { | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2317 |    uint64_t start = UINT64_C(0); // starting point for each search | 
 | 2318 |    uint64_t totalFound = UINT64_C(0); // running total | 
 | 2319 |    uint64_t firstBlock; // first block in a segment | 
 | 2320 |    uint64_t lastBlock; // last block in a segment | 
 | 2321 |    uint64_t segmentSize; // size of segment in blocks | 
| srs5694 | e321d44 | 2010-01-29 17:44:04 -0500 | [diff] [blame^] | 2322 |    uint32_t num = 0; | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2323 |  | 
 | 2324 |    *largestSegment = UINT64_C(0); | 
 | 2325 |    do { | 
 | 2326 |       firstBlock = FindFirstAvailable(start); | 
 | 2327 |       if (firstBlock != UINT64_C(0)) { // something's free... | 
 | 2328 |          lastBlock = FindLastInFree(firstBlock); | 
 | 2329 |          segmentSize = lastBlock - firstBlock + UINT64_C(1); | 
 | 2330 |          if (segmentSize > *largestSegment) { | 
 | 2331 |             *largestSegment = segmentSize; | 
 | 2332 |          } // if | 
 | 2333 |          totalFound += segmentSize; | 
 | 2334 |          num++; | 
 | 2335 |          start = lastBlock + 1; | 
 | 2336 |       } // if | 
 | 2337 |    } while (firstBlock != 0); | 
 | 2338 |    *numSegments = num; | 
 | 2339 |    return totalFound; | 
 | 2340 | } // GPTData::FindFreeBlocks() | 
 | 2341 |  | 
 | 2342 | // Returns 1 if sector is unallocated, 0 if it's allocated to a partition | 
 | 2343 | int GPTData::IsFree(uint64_t sector) { | 
 | 2344 |    int isFree = 1; | 
 | 2345 |    uint32_t i; | 
 | 2346 |  | 
 | 2347 |    for (i = 0; i < mainHeader.numParts; i++) { | 
 | 2348 |       if ((sector >= partitions[i].GetFirstLBA()) && | 
 | 2349 |            (sector <= partitions[i].GetLastLBA())) { | 
 | 2350 |          isFree = 0; | 
 | 2351 |            } // if | 
 | 2352 |    } // for | 
| srs5694 | e35eb1b | 2009-09-14 00:29:34 -0400 | [diff] [blame] | 2353 |    if ((sector < mainHeader.firstUsableLBA) || | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2354 |         (sector > mainHeader.lastUsableLBA)) { | 
 | 2355 |       isFree = 0; | 
 | 2356 |         } // if | 
 | 2357 |         return (isFree); | 
 | 2358 | } // GPTData::IsFree() | 
 | 2359 |  | 
| srs5694 | ba00fed | 2010-01-12 18:18:36 -0500 | [diff] [blame] | 2360 | // Returns 1 if partNum is unused. | 
 | 2361 | int GPTData::IsFreePartNum(uint32_t partNum) { | 
 | 2362 |    int retval = 1; | 
 | 2363 |  | 
 | 2364 |    if ((partNum >= 0) && (partNum < mainHeader.numParts)) { | 
 | 2365 |       if ((partitions[partNum].GetFirstLBA() != UINT64_C(0)) || | 
 | 2366 |           (partitions[partNum].GetLastLBA() != UINT64_C(0))) { | 
 | 2367 |          retval = 0; | 
 | 2368 |       } // if partition is in use | 
 | 2369 |    } else retval = 0; | 
 | 2370 |  | 
 | 2371 |    return retval; | 
 | 2372 | } // GPTData::IsFreePartNum() | 
 | 2373 |  | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2374 | /******************************** | 
 | 2375 |  *                              * | 
 | 2376 |  * Endianness support functions * | 
 | 2377 |  *                              * | 
 | 2378 |  ********************************/ | 
 | 2379 |  | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 2380 | void GPTData::ReverseHeaderBytes(struct GPTHeader* header) { | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 2381 |    ReverseBytes(&header->signature, 8); | 
 | 2382 |    ReverseBytes(&header->revision, 4); | 
 | 2383 |    ReverseBytes(&header->headerSize, 4); | 
 | 2384 |    ReverseBytes(&header->headerCRC, 4); | 
 | 2385 |    ReverseBytes(&header->reserved, 4); | 
 | 2386 |    ReverseBytes(&header->currentLBA, 8); | 
 | 2387 |    ReverseBytes(&header->backupLBA, 8); | 
 | 2388 |    ReverseBytes(&header->firstUsableLBA, 8); | 
 | 2389 |    ReverseBytes(&header->lastUsableLBA, 8); | 
 | 2390 |    ReverseBytes(&header->partitionEntriesLBA, 8); | 
 | 2391 |    ReverseBytes(&header->numParts, 4); | 
 | 2392 |    ReverseBytes(&header->sizeOfPartitionEntries, 4); | 
 | 2393 |    ReverseBytes(&header->partitionEntriesCRC, 4); | 
 | 2394 |    ReverseBytes(&header->reserved2, GPT_RESERVED); | 
 | 2395 |    ReverseBytes(&header->diskGUID.data1, 8); | 
 | 2396 |    ReverseBytes(&header->diskGUID.data2, 8); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 2397 | } // GPTData::ReverseHeaderBytes() | 
 | 2398 |  | 
 | 2399 | // IMPORTANT NOTE: This function requires non-reversed mainHeader | 
 | 2400 | // structure! | 
 | 2401 | void GPTData::ReversePartitionBytes() { | 
 | 2402 |    uint32_t i; | 
 | 2403 |  | 
 | 2404 |    // Check GPT signature on big-endian systems; this will mismatch | 
 | 2405 |    // if the function is called out of order. Unfortunately, it'll also | 
 | 2406 |    // mismatch if there's data corruption. | 
 | 2407 |    if ((mainHeader.signature != GPT_SIGNATURE) && (IsLittleEndian() == 0)) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2408 |       cerr << "GPT signature mismatch in GPTData::ReversePartitionBytes(). This indicates\n" | 
 | 2409 |            << "data corruption or a misplaced call to this function.\n"; | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 2410 |    } // if signature mismatch.... | 
 | 2411 |    for (i = 0; i < mainHeader.numParts; i++) { | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 2412 |       partitions[i].ReversePartBytes(); | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 2413 |    } // for | 
 | 2414 | } // GPTData::ReversePartitionBytes() | 
 | 2415 |  | 
 | 2416 | /****************************************** | 
 | 2417 |  *                                        * | 
 | 2418 |  * Additional non-class support functions * | 
 | 2419 |  *                                        * | 
 | 2420 |  ******************************************/ | 
 | 2421 |  | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2422 | // Check to be sure that data type sizes are correct. The basic types (uint*_t) should | 
 | 2423 | // never fail these tests, but the struct types may fail depending on compile options. | 
 | 2424 | // Specifically, the -fpack-struct option to gcc may be required to ensure proper structure | 
 | 2425 | // sizes. | 
 | 2426 | int SizesOK(void) { | 
 | 2427 |    int allOK = 1; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2428 |  | 
 | 2429 |    if (sizeof(uint8_t) != 1) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2430 |       cerr << "uint8_t is " << sizeof(uint8_t) << " bytes, should be 1 byte; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2431 |       allOK = 0; | 
 | 2432 |    } // if | 
 | 2433 |    if (sizeof(uint16_t) != 2) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2434 |       cerr << "uint16_t is " << sizeof(uint16_t) << " bytes, should be 2 bytes; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2435 |       allOK = 0; | 
 | 2436 |    } // if | 
 | 2437 |    if (sizeof(uint32_t) != 4) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2438 |       cerr << "uint32_t is " << sizeof(uint32_t) << " bytes, should be 4 bytes; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2439 |       allOK = 0; | 
 | 2440 |    } // if | 
 | 2441 |    if (sizeof(uint64_t) != 8) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2442 |       cerr << "uint64_t is " << sizeof(uint64_t) << " bytes, should be 8 bytes; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2443 |       allOK = 0; | 
 | 2444 |    } // if | 
 | 2445 |    if (sizeof(struct MBRRecord) != 16) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2446 |       cerr << "MBRRecord is " << sizeof(MBRRecord) << " bytes, should be 16 bytes; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2447 |       allOK = 0; | 
 | 2448 |    } // if | 
| srs5694 | 978041c | 2009-09-21 20:51:47 -0400 | [diff] [blame] | 2449 |    if (sizeof(struct TempMBR) != 512) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2450 |       cerr << "TempMBR is " <<  sizeof(TempMBR) << " bytes, should be 512 bytes; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2451 |       allOK = 0; | 
 | 2452 |    } // if | 
 | 2453 |    if (sizeof(struct GPTHeader) != 512) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2454 |       cerr << "GPTHeader is " << sizeof(GPTHeader) << " bytes, should be 512 bytes; aborting!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2455 |       allOK = 0; | 
 | 2456 |    } // if | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 2457 |    if (sizeof(GPTPart) != 128) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2458 |       cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n"; | 
| srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 2459 |       allOK = 0; | 
 | 2460 |    } // if | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2461 |    // Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware | 
| srs5694 | 2a9f5da | 2009-08-26 00:48:01 -0400 | [diff] [blame] | 2462 |    if (IsLittleEndian() == 0) { | 
| srs5694 | fed16d0 | 2010-01-27 23:03:40 -0500 | [diff] [blame] | 2463 |       cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly" | 
 | 2464 |             " tested!\n"; | 
| srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 2465 |    } // if | 
 | 2466 |    return (allOK); | 
 | 2467 | } // SizesOK() | 
| srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame] | 2468 |  |