Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
Randall Spangler | 3dcf9dc | 2010-06-02 12:46:17 -0700 | [diff] [blame] | 2 | * Use of this source code is governed by a BSD-style license that can be |
| 3 | * found in the LICENSE file. |
| 4 | */ |
| 5 | |
Bill Richardson | 0c3ba24 | 2013-03-29 11:09:30 -0700 | [diff] [blame] | 6 | #include "sysincludes.h" |
| 7 | |
Randall Spangler | 3dcf9dc | 2010-06-02 12:46:17 -0700 | [diff] [blame] | 8 | #include "cgptlib.h" |
| 9 | #include "cgptlib_internal.h" |
| 10 | #include "crc32.h" |
| 11 | #include "gpt.h" |
Dan Ehrenberg | 7c2beb0 | 2014-10-21 16:15:54 -0700 | [diff] [blame] | 12 | #include "gpt_misc.h" |
Randall Spangler | 3dcf9dc | 2010-06-02 12:46:17 -0700 | [diff] [blame] | 13 | #include "utility.h" |
| 14 | |
| 15 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 16 | int CheckParameters(GptData *gpt) |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 17 | { |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 18 | /* Currently, we only support 512-byte sectors. */ |
| 19 | if (gpt->sector_bytes != 512) |
| 20 | return GPT_ERROR_INVALID_SECTOR_SIZE; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 21 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 22 | /* |
Nam T. Nguyen | 6ee52d9 | 2014-10-24 13:20:39 -0700 | [diff] [blame] | 23 | * gpt_drive_sectors should be reasonable. It cannot be unset, and it cannot |
| 24 | * differ from drive_sectors if the GPT structs are stored on same device. |
| 25 | */ |
| 26 | if (gpt->gpt_drive_sectors == 0 || |
| 27 | (gpt->stored_on_device == GPT_STORED_ON_DEVICE && |
| 28 | gpt->gpt_drive_sectors != gpt->drive_sectors)) { |
| 29 | return GPT_ERROR_INVALID_SECTOR_NUMBER; |
| 30 | } |
| 31 | |
| 32 | /* |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 33 | * Sector count of a drive should be reasonable. If the given value is |
| 34 | * too small to contain basic GPT structure (PMBR + Headers + Entries), |
| 35 | * the value is wrong. |
| 36 | */ |
Nam T. Nguyen | ab89959 | 2014-11-13 19:30:46 -0800 | [diff] [blame] | 37 | if (gpt->gpt_drive_sectors < (1 + 2 * (1 + GPT_ENTRIES_SECTORS))) |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 38 | return GPT_ERROR_INVALID_SECTOR_NUMBER; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 39 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 40 | return GPT_SUCCESS; |
| 41 | } |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 42 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 43 | uint32_t HeaderCrc(GptHeader *h) |
| 44 | { |
| 45 | uint32_t crc32, original_crc32; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 46 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 47 | /* Original CRC is calculated with the CRC field 0. */ |
| 48 | original_crc32 = h->header_crc32; |
| 49 | h->header_crc32 = 0; |
| 50 | crc32 = Crc32((const uint8_t *)h, h->size); |
| 51 | h->header_crc32 = original_crc32; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 52 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 53 | return crc32; |
| 54 | } |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 55 | |
Nam T. Nguyen | 6ee52d9 | 2014-10-24 13:20:39 -0700 | [diff] [blame] | 56 | int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors, |
Dan Ehrenberg | a524a3a | 2014-11-06 16:22:24 -0800 | [diff] [blame] | 57 | uint64_t gpt_drive_sectors, uint8_t stored_on_device) |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 58 | { |
| 59 | if (!h) |
| 60 | return 1; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 61 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 62 | /* |
| 63 | * Make sure we're looking at a header of reasonable size before |
| 64 | * attempting to calculate CRC. |
| 65 | */ |
| 66 | if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, |
| 67 | GPT_HEADER_SIGNATURE_SIZE) && |
| 68 | Memcmp(h->signature, GPT_HEADER_SIGNATURE2, |
| 69 | GPT_HEADER_SIGNATURE_SIZE)) |
| 70 | return 1; |
| 71 | if (h->revision != GPT_HEADER_REVISION) |
| 72 | return 1; |
| 73 | if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER) |
| 74 | return 1; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 75 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 76 | /* Check CRC before looking at remaining fields */ |
| 77 | if (HeaderCrc(h) != h->header_crc32) |
| 78 | return 1; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 79 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 80 | /* Reserved fields must be zero. */ |
| 81 | if (h->reserved_zero) |
| 82 | return 1; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 83 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 84 | /* Could check that padding is zero, but that doesn't matter to us. */ |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 85 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 86 | /* |
| 87 | * If entry size is different than our struct, we won't be able to |
| 88 | * parse it. Technically, any size 2^N where N>=7 is valid. |
| 89 | */ |
| 90 | if (h->size_of_entry != sizeof(GptEntry)) |
| 91 | return 1; |
| 92 | if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) || |
| 93 | (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) || |
Nam T. Nguyen | 6ee52d9 | 2014-10-24 13:20:39 -0700 | [diff] [blame] | 94 | (stored_on_device == GPT_STORED_ON_DEVICE && |
| 95 | h->number_of_entries * h->size_of_entry != TOTAL_ENTRIES_SIZE)) |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 96 | return 1; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 97 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 98 | /* |
| 99 | * Check locations for the header and its entries. The primary |
| 100 | * immediately follows the PMBR, and is followed by its entries. The |
| 101 | * secondary is at the end of the drive, preceded by its entries. |
| 102 | */ |
| 103 | if (is_secondary) { |
Dan Ehrenberg | a524a3a | 2014-11-06 16:22:24 -0800 | [diff] [blame] | 104 | if (h->my_lba != gpt_drive_sectors - GPT_HEADER_SECTORS) |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 105 | return 1; |
| 106 | if (h->entries_lba != h->my_lba - GPT_ENTRIES_SECTORS) |
| 107 | return 1; |
| 108 | } else { |
Nam T. Nguyen | 88458d9 | 2014-08-28 10:58:47 -0700 | [diff] [blame] | 109 | if (h->my_lba != GPT_PMBR_SECTORS) |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 110 | return 1; |
Nam T. Nguyen | a2d72f7 | 2014-08-22 15:01:38 -0700 | [diff] [blame] | 111 | if (h->entries_lba < h->my_lba + 1) |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 112 | return 1; |
| 113 | } |
| 114 | |
Nam T. Nguyen | 6ee52d9 | 2014-10-24 13:20:39 -0700 | [diff] [blame] | 115 | /* FirstUsableLBA <= LastUsableLBA. */ |
| 116 | if (h->first_usable_lba > h->last_usable_lba) |
| 117 | return 1; |
| 118 | |
| 119 | if (stored_on_device != GPT_STORED_ON_DEVICE) { |
| 120 | if (h->last_usable_lba >= drive_sectors) { |
| 121 | return 1; |
| 122 | } |
| 123 | return 0; |
| 124 | } |
| 125 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 126 | /* |
| 127 | * FirstUsableLBA must be after the end of the primary GPT table array. |
| 128 | * LastUsableLBA must be before the start of the secondary GPT table |
Nam T. Nguyen | 6ee52d9 | 2014-10-24 13:20:39 -0700 | [diff] [blame] | 129 | * array. |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 130 | */ |
Nam T. Nguyen | a2d72f7 | 2014-08-22 15:01:38 -0700 | [diff] [blame] | 131 | /* TODO(namnguyen): Also check for padding between header & entries. */ |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 132 | if (h->first_usable_lba < 2 + GPT_ENTRIES_SECTORS) |
| 133 | return 1; |
| 134 | if (h->last_usable_lba >= drive_sectors - 1 - GPT_ENTRIES_SECTORS) |
| 135 | return 1; |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 136 | |
| 137 | /* Success */ |
| 138 | return 0; |
| 139 | } |
| 140 | |
| 141 | int IsUnusedEntry(const GptEntry *e) |
| 142 | { |
| 143 | static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}}; |
| 144 | return !Memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero)); |
| 145 | } |
| 146 | |
| 147 | int IsKernelEntry(const GptEntry *e) |
| 148 | { |
| 149 | static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; |
| 150 | return !Memcmp(&e->type, &chromeos_kernel, sizeof(Guid)); |
| 151 | } |
| 152 | |
| 153 | int CheckEntries(GptEntry *entries, GptHeader *h) |
| 154 | { |
Nam T. Nguyen | 5ce8325 | 2014-10-30 15:09:43 -0700 | [diff] [blame] | 155 | if (!entries) |
| 156 | return GPT_ERROR_INVALID_ENTRIES; |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 157 | GptEntry *entry; |
| 158 | uint32_t crc32; |
| 159 | uint32_t i; |
| 160 | |
| 161 | /* Check CRC before examining entries. */ |
| 162 | crc32 = Crc32((const uint8_t *)entries, |
| 163 | h->size_of_entry * h->number_of_entries); |
| 164 | if (crc32 != h->entries_crc32) |
| 165 | return GPT_ERROR_CRC_CORRUPTED; |
| 166 | |
| 167 | /* Check all entries. */ |
| 168 | for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) { |
| 169 | GptEntry *e2; |
| 170 | uint32_t i2; |
| 171 | |
| 172 | if (IsUnusedEntry(entry)) |
| 173 | continue; |
| 174 | |
| 175 | /* Entry must be in valid region. */ |
| 176 | if ((entry->starting_lba < h->first_usable_lba) || |
| 177 | (entry->ending_lba > h->last_usable_lba) || |
| 178 | (entry->ending_lba < entry->starting_lba)) |
| 179 | return GPT_ERROR_OUT_OF_REGION; |
| 180 | |
| 181 | /* Entry must not overlap other entries. */ |
| 182 | for (i2 = 0, e2 = entries; i2 < h->number_of_entries; |
| 183 | i2++, e2++) { |
| 184 | if (i2 == i || IsUnusedEntry(e2)) |
| 185 | continue; |
| 186 | |
| 187 | if ((entry->starting_lba >= e2->starting_lba) && |
| 188 | (entry->starting_lba <= e2->ending_lba)) |
| 189 | return GPT_ERROR_START_LBA_OVERLAP; |
| 190 | if ((entry->ending_lba >= e2->starting_lba) && |
| 191 | (entry->ending_lba <= e2->ending_lba)) |
| 192 | return GPT_ERROR_END_LBA_OVERLAP; |
| 193 | |
| 194 | /* UniqueGuid field must be unique. */ |
| 195 | if (0 == Memcmp(&entry->unique, &e2->unique, |
| 196 | sizeof(Guid))) |
| 197 | return GPT_ERROR_DUP_GUID; |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | /* Success */ |
| 202 | return 0; |
| 203 | } |
| 204 | |
| 205 | int HeaderFieldsSame(GptHeader *h1, GptHeader *h2) |
| 206 | { |
| 207 | if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature))) |
| 208 | return 1; |
| 209 | if (h1->revision != h2->revision) |
| 210 | return 1; |
| 211 | if (h1->size != h2->size) |
| 212 | return 1; |
| 213 | if (h1->reserved_zero != h2->reserved_zero) |
| 214 | return 1; |
| 215 | if (h1->first_usable_lba != h2->first_usable_lba) |
| 216 | return 1; |
| 217 | if (h1->last_usable_lba != h2->last_usable_lba) |
| 218 | return 1; |
| 219 | if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid))) |
| 220 | return 1; |
| 221 | if (h1->number_of_entries != h2->number_of_entries) |
| 222 | return 1; |
| 223 | if (h1->size_of_entry != h2->size_of_entry) |
| 224 | return 1; |
| 225 | if (h1->entries_crc32 != h2->entries_crc32) |
| 226 | return 1; |
| 227 | |
| 228 | return 0; |
| 229 | } |
| 230 | |
| 231 | int GptSanityCheck(GptData *gpt) |
| 232 | { |
| 233 | int retval; |
| 234 | GptHeader *header1 = (GptHeader *)(gpt->primary_header); |
| 235 | GptHeader *header2 = (GptHeader *)(gpt->secondary_header); |
| 236 | GptEntry *entries1 = (GptEntry *)(gpt->primary_entries); |
| 237 | GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries); |
| 238 | GptHeader *goodhdr = NULL; |
| 239 | |
| 240 | gpt->valid_headers = 0; |
| 241 | gpt->valid_entries = 0; |
| 242 | |
| 243 | retval = CheckParameters(gpt); |
| 244 | if (retval != GPT_SUCCESS) |
| 245 | return retval; |
| 246 | |
| 247 | /* Check both headers; we need at least one valid header. */ |
Dan Ehrenberg | a524a3a | 2014-11-06 16:22:24 -0800 | [diff] [blame] | 248 | if (0 == CheckHeader(header1, 0, gpt->drive_sectors, |
| 249 | gpt->gpt_drive_sectors, gpt->stored_on_device)) { |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 250 | gpt->valid_headers |= MASK_PRIMARY; |
| 251 | goodhdr = header1; |
| 252 | } |
Dan Ehrenberg | a524a3a | 2014-11-06 16:22:24 -0800 | [diff] [blame] | 253 | if (0 == CheckHeader(header2, 1, gpt->drive_sectors, |
| 254 | gpt->gpt_drive_sectors, gpt->stored_on_device)) { |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 255 | gpt->valid_headers |= MASK_SECONDARY; |
| 256 | if (!goodhdr) |
| 257 | goodhdr = header2; |
| 258 | } |
| 259 | |
| 260 | if (!gpt->valid_headers) |
| 261 | return GPT_ERROR_INVALID_HEADERS; |
| 262 | |
| 263 | /* |
| 264 | * Check if entries are valid. |
| 265 | * |
| 266 | * Note that we use the same header in both checks. This way we'll |
| 267 | * catch the case where (header1,entries1) and (header2,entries2) are |
| 268 | * both valid, but (entries1 != entries2). |
| 269 | */ |
| 270 | if (0 == CheckEntries(entries1, goodhdr)) |
| 271 | gpt->valid_entries |= MASK_PRIMARY; |
| 272 | if (0 == CheckEntries(entries2, goodhdr)) |
| 273 | gpt->valid_entries |= MASK_SECONDARY; |
| 274 | |
| 275 | /* |
| 276 | * If both headers are good but neither entries were good, check the |
| 277 | * entries with the secondary header. |
| 278 | */ |
| 279 | if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) { |
| 280 | if (0 == CheckEntries(entries1, header2)) |
| 281 | gpt->valid_entries |= MASK_PRIMARY; |
| 282 | if (0 == CheckEntries(entries2, header2)) |
| 283 | gpt->valid_entries |= MASK_SECONDARY; |
| 284 | if (gpt->valid_entries) { |
| 285 | /* |
| 286 | * Sure enough, header2 had a good CRC for one of the |
| 287 | * entries. Mark header1 invalid, so we'll update its |
| 288 | * entries CRC. |
| 289 | */ |
| 290 | gpt->valid_headers &= ~MASK_PRIMARY; |
| 291 | goodhdr = header2; |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | if (!gpt->valid_entries) |
| 296 | return GPT_ERROR_INVALID_ENTRIES; |
| 297 | |
| 298 | /* |
| 299 | * Now that we've determined which header contains a good CRC for |
| 300 | * the entries, make sure the headers are otherwise identical. |
| 301 | */ |
| 302 | if (MASK_BOTH == gpt->valid_headers && |
| 303 | 0 != HeaderFieldsSame(header1, header2)) |
| 304 | gpt->valid_headers &= ~MASK_SECONDARY; |
| 305 | |
| 306 | return GPT_SUCCESS; |
| 307 | } |
| 308 | |
| 309 | void GptRepair(GptData *gpt) |
| 310 | { |
| 311 | GptHeader *header1 = (GptHeader *)(gpt->primary_header); |
| 312 | GptHeader *header2 = (GptHeader *)(gpt->secondary_header); |
| 313 | GptEntry *entries1 = (GptEntry *)(gpt->primary_entries); |
| 314 | GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries); |
| 315 | int entries_size; |
| 316 | |
| 317 | /* Need at least one good header and one good set of entries. */ |
| 318 | if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries) |
| 319 | return; |
| 320 | |
| 321 | /* Repair headers if necessary */ |
| 322 | if (MASK_PRIMARY == gpt->valid_headers) { |
| 323 | /* Primary is good, secondary is bad */ |
| 324 | Memcpy(header2, header1, sizeof(GptHeader)); |
Dan Ehrenberg | a524a3a | 2014-11-06 16:22:24 -0800 | [diff] [blame] | 325 | header2->my_lba = gpt->gpt_drive_sectors - GPT_HEADER_SECTORS; |
Nam T. Nguyen | 88458d9 | 2014-08-28 10:58:47 -0700 | [diff] [blame] | 326 | header2->alternate_lba = GPT_PMBR_SECTORS; /* Second sector. */ |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 327 | header2->entries_lba = header2->my_lba - GPT_ENTRIES_SECTORS; |
| 328 | header2->header_crc32 = HeaderCrc(header2); |
| 329 | gpt->modified |= GPT_MODIFIED_HEADER2; |
| 330 | } |
| 331 | else if (MASK_SECONDARY == gpt->valid_headers) { |
| 332 | /* Secondary is good, primary is bad */ |
| 333 | Memcpy(header1, header2, sizeof(GptHeader)); |
Nam T. Nguyen | 88458d9 | 2014-08-28 10:58:47 -0700 | [diff] [blame] | 334 | header1->my_lba = GPT_PMBR_SECTORS; /* Second sector. */ |
| 335 | header1->alternate_lba = gpt->drive_sectors - GPT_HEADER_SECTORS; |
Nam T. Nguyen | a2d72f7 | 2014-08-22 15:01:38 -0700 | [diff] [blame] | 336 | /* TODO (namnguyen): Preserve (header, entries) padding. */ |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 337 | header1->entries_lba = header1->my_lba + 1; |
| 338 | header1->header_crc32 = HeaderCrc(header1); |
| 339 | gpt->modified |= GPT_MODIFIED_HEADER1; |
| 340 | } |
| 341 | gpt->valid_headers = MASK_BOTH; |
| 342 | |
| 343 | /* Repair entries if necessary */ |
| 344 | entries_size = header1->size_of_entry * header1->number_of_entries; |
| 345 | if (MASK_PRIMARY == gpt->valid_entries) { |
| 346 | /* Primary is good, secondary is bad */ |
| 347 | Memcpy(entries2, entries1, entries_size); |
| 348 | gpt->modified |= GPT_MODIFIED_ENTRIES2; |
| 349 | } |
| 350 | else if (MASK_SECONDARY == gpt->valid_entries) { |
| 351 | /* Secondary is good, primary is bad */ |
| 352 | Memcpy(entries1, entries2, entries_size); |
| 353 | gpt->modified |= GPT_MODIFIED_ENTRIES1; |
| 354 | } |
| 355 | gpt->valid_entries = MASK_BOTH; |
| 356 | } |
| 357 | |
| 358 | int GetEntrySuccessful(const GptEntry *e) |
| 359 | { |
| 360 | return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> |
| 361 | CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
| 362 | } |
| 363 | |
| 364 | int GetEntryPriority(const GptEntry *e) |
| 365 | { |
| 366 | return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >> |
| 367 | CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
| 368 | } |
| 369 | |
| 370 | int GetEntryTries(const GptEntry *e) |
| 371 | { |
| 372 | return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >> |
| 373 | CGPT_ATTRIBUTE_TRIES_OFFSET; |
| 374 | } |
| 375 | |
| 376 | void SetEntrySuccessful(GptEntry *e, int successful) |
| 377 | { |
| 378 | if (successful) |
| 379 | e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK; |
| 380 | else |
| 381 | e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; |
| 382 | } |
| 383 | |
| 384 | void SetEntryPriority(GptEntry *e, int priority) |
| 385 | { |
| 386 | e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; |
| 387 | e->attrs.fields.gpt_att |= |
| 388 | (priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) & |
| 389 | CGPT_ATTRIBUTE_PRIORITY_MASK; |
| 390 | } |
| 391 | |
| 392 | void SetEntryTries(GptEntry *e, int tries) |
| 393 | { |
| 394 | e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK; |
| 395 | e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET) & |
| 396 | CGPT_ATTRIBUTE_TRIES_MASK; |
| 397 | } |
| 398 | |
| 399 | void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) |
| 400 | { |
| 401 | GptEntry *entries = (GptEntry *)gpt->primary_entries; |
| 402 | GptEntry *e = entries + gpt->current_kernel; |
| 403 | Memcpy(dest, &e->unique, sizeof(Guid)); |
| 404 | } |
| 405 | |
Albert Chaulk | 5c9e453 | 2013-03-20 16:03:49 -0700 | [diff] [blame] | 406 | void GptModified(GptData *gpt) { |
| 407 | GptHeader *header = (GptHeader *)gpt->primary_header; |
| 408 | |
| 409 | /* Update the CRCs */ |
| 410 | header->entries_crc32 = Crc32(gpt->primary_entries, |
| 411 | header->size_of_entry * |
| 412 | header->number_of_entries); |
| 413 | header->header_crc32 = HeaderCrc(header); |
| 414 | gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1; |
| 415 | |
| 416 | /* |
| 417 | * Use the repair function to update the other copy of the GPT. This |
| 418 | * is a tad inefficient, but is much faster than the disk I/O to update |
| 419 | * the GPT on disk so it doesn't matter. |
| 420 | */ |
| 421 | gpt->valid_headers = MASK_PRIMARY; |
| 422 | gpt->valid_entries = MASK_PRIMARY; |
| 423 | GptRepair(gpt); |
| 424 | } |
| 425 | |
| 426 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 427 | const char *GptErrorText(int error_code) |
| 428 | { |
| 429 | switch(error_code) { |
| 430 | case GPT_SUCCESS: |
| 431 | return "none"; |
| 432 | |
| 433 | case GPT_ERROR_NO_VALID_KERNEL: |
| 434 | return "Invalid kernel"; |
| 435 | |
| 436 | case GPT_ERROR_INVALID_HEADERS: |
| 437 | return "Invalid headers"; |
| 438 | |
| 439 | case GPT_ERROR_INVALID_ENTRIES: |
| 440 | return "Invalid entries"; |
| 441 | |
| 442 | case GPT_ERROR_INVALID_SECTOR_SIZE: |
| 443 | return "Invalid sector size"; |
| 444 | |
| 445 | case GPT_ERROR_INVALID_SECTOR_NUMBER: |
| 446 | return "Invalid sector number"; |
| 447 | |
| 448 | case GPT_ERROR_INVALID_UPDATE_TYPE: |
| 449 | return "Invalid update type"; |
| 450 | |
| 451 | case GPT_ERROR_CRC_CORRUPTED: |
| 452 | return "Entries' crc corrupted"; |
| 453 | |
| 454 | case GPT_ERROR_OUT_OF_REGION: |
| 455 | return "Entry outside of valid region"; |
| 456 | |
| 457 | case GPT_ERROR_START_LBA_OVERLAP: |
| 458 | return "Starting LBA overlaps"; |
| 459 | |
| 460 | case GPT_ERROR_END_LBA_OVERLAP: |
| 461 | return "Ending LBA overlaps"; |
| 462 | |
| 463 | case GPT_ERROR_DUP_GUID: |
| 464 | return "Duplicated GUID"; |
| 465 | |
Albert Chaulk | 5c9e453 | 2013-03-20 16:03:49 -0700 | [diff] [blame] | 466 | case GPT_ERROR_INVALID_FLASH_GEOMETRY: |
| 467 | return "Invalid flash geometry"; |
| 468 | |
| 469 | case GPT_ERROR_NO_SUCH_ENTRY: |
| 470 | return "No entry found"; |
| 471 | |
Randall Spangler | cefe12c | 2013-01-30 12:52:02 -0800 | [diff] [blame] | 472 | default: |
| 473 | break; |
| 474 | }; |
| 475 | return "Unknown"; |
Vadim Bendebury | 65d3c27 | 2012-09-24 17:41:18 -0700 | [diff] [blame] | 476 | } |