OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 * Use of this source code is governed by a BSD-style license that can be |
| 3 * found in the LICENSE file. |
| 4 * |
| 5 * Functions to fix, after cgptlib cleanup. |
| 6 */ |
| 7 #include <getopt.h> |
| 8 #include <stdio.h> |
| 9 #include <stdlib.h> |
| 10 #include "cgpt.h" |
| 11 #include "cgptlib_internal.h" |
| 12 #include "cgpt_tofix.h" |
| 13 #include "crc32.h" |
| 14 #include "utility.h" |
| 15 |
| 16 const char *GptError(int errno) { |
| 17 const char *error_string[] = { |
| 18 /* GPT_SUCCESS */ "Success", |
| 19 /* GPT_ERROR_NO_VALID_KERNEL */ "No valid kernel entry", |
| 20 /* GPT_ERROR_INVALID_HEADERS */ "Both primary and secondary headers are " |
| 21 "invalid.", |
| 22 /* GPT_ERROR_INVALID_ENTRIES */ "Both primary and secondary entries are " |
| 23 "invalid.", |
| 24 /* GPT_ERROR_INVALID_SECTOR_SIZE */ "Invalid sector size", |
| 25 /* GPT_ERROR_INVALID_SECTOR_NUMBER */ "Invalid sector number", |
| 26 /* GPT_ERROR_INVALID_UPDATE_TYPE */ "Invalid update type", |
| 27 }; |
| 28 return error_string[errno]; |
| 29 } |
| 30 |
| 31 |
| 32 /* Update CRC value if necessary. */ |
| 33 void UpdateCrc(GptData *gpt) { |
| 34 GptHeader *primary_header, *secondary_header; |
| 35 |
| 36 primary_header = (GptHeader*)gpt->primary_header; |
| 37 secondary_header = (GptHeader*)gpt->secondary_header; |
| 38 |
| 39 if (gpt->modified & GPT_MODIFIED_ENTRIES1) { |
| 40 primary_header->entries_crc32 = |
| 41 Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE); |
| 42 } |
| 43 if (gpt->modified & GPT_MODIFIED_ENTRIES2) { |
| 44 secondary_header->entries_crc32 = |
| 45 Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE); |
| 46 } |
| 47 if (gpt->modified & GPT_MODIFIED_HEADER1) { |
| 48 primary_header->header_crc32 = 0; |
| 49 primary_header->header_crc32 = Crc32( |
| 50 (const uint8_t *)primary_header, primary_header->size); |
| 51 } |
| 52 if (gpt->modified & GPT_MODIFIED_HEADER2) { |
| 53 secondary_header->header_crc32 = 0; |
| 54 secondary_header->header_crc32 = Crc32( |
| 55 (const uint8_t *)secondary_header, secondary_header->size); |
| 56 } |
| 57 } |
| 58 |
| 59 /* Helper function to get a pointer to the partition entry. |
| 60 * 'secondary' is either PRIMARY or SECONDARY. |
| 61 * 'entry_index' is the partition index: [0, number_of_entries). |
| 62 */ |
| 63 GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) { |
| 64 uint8_t *entries; |
| 65 |
| 66 if (secondary == PRIMARY) { |
| 67 entries = gpt->primary_entries; |
| 68 } else { |
| 69 entries = gpt->secondary_entries; |
| 70 } |
| 71 |
| 72 return (GptEntry*)(&entries[GetNumberOfEntries(gpt) * entry_index]); |
| 73 } |
| 74 |
| 75 /* The following functions are helpers to access attributes bit more easily. |
| 76 * 'secondary' is either PRIMARY or SECONDARY. |
| 77 * 'entry_index' is the partition index: [0, number_of_entries). |
| 78 * |
| 79 * Get*() return the exact value (shifted and masked). |
| 80 */ |
| 81 void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) { |
| 82 GptEntry *entry; |
| 83 entry = GetEntry(gpt, secondary, entry_index); |
| 84 |
| 85 assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY); |
| 86 entry->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; |
| 87 entry->attributes |= (uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
| 88 } |
| 89 |
| 90 int GetPriority(GptData *gpt, int secondary, int entry_index) { |
| 91 GptEntry *entry; |
| 92 entry = GetEntry(gpt, secondary, entry_index); |
| 93 return (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >> |
| 94 CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
| 95 } |
| 96 |
| 97 void SetBad(GptData *gpt, int secondary, int entry_index, int bad) { |
| 98 GptEntry *entry; |
| 99 entry = GetEntry(gpt, secondary, entry_index); |
| 100 |
| 101 // There is no bad attribute |
| 102 assert(0); |
| 103 } |
| 104 |
| 105 int GetBad(GptData *gpt, int secondary, int entry_index) { |
| 106 GptEntry *entry; |
| 107 entry = GetEntry(gpt, secondary, entry_index); |
| 108 |
| 109 // There is no bad attribute |
| 110 assert(0); |
| 111 return 0; |
| 112 } |
| 113 |
| 114 void SetTries(GptData *gpt, int secondary, int entry_index, int tries) { |
| 115 GptEntry *entry; |
| 116 entry = GetEntry(gpt, secondary, entry_index); |
| 117 |
| 118 assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES); |
| 119 entry->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK; |
| 120 entry->attributes |= (uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET; |
| 121 } |
| 122 |
| 123 int GetTries(GptData *gpt, int secondary, int entry_index) { |
| 124 GptEntry *entry; |
| 125 entry = GetEntry(gpt, secondary, entry_index); |
| 126 return (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >> |
| 127 CGPT_ATTRIBUTE_TRIES_OFFSET; |
| 128 } |
| 129 |
| 130 void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success) { |
| 131 GptEntry *entry; |
| 132 entry = GetEntry(gpt, secondary, entry_index); |
| 133 |
| 134 assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL); |
| 135 entry->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; |
| 136 entry->attributes |= (uint64_t)success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
| 137 } |
| 138 |
| 139 int GetSuccessful(GptData *gpt, int secondary, int entry_index) { |
| 140 GptEntry *entry; |
| 141 entry = GetEntry(gpt, secondary, entry_index); |
| 142 return (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> |
| 143 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
| 144 } |
| 145 |
| 146 uint32_t GetNumberOfEntries(const GptData *gpt) { |
| 147 GptHeader *header = 0; |
| 148 if (gpt->valid_headers & MASK_PRIMARY) |
| 149 header = (GptHeader*)gpt->primary_header; |
| 150 else if (gpt->valid_headers & MASK_SECONDARY) |
| 151 header = (GptHeader*)gpt->secondary_header; |
| 152 else |
| 153 assert(0); |
| 154 return header->number_of_entries; |
| 155 } |
| 156 |
| 157 /* Two headers are NOT bitwise identical. For example, my_lba pointers to header |
| 158 * itself so that my_lba in primary and secondary is definitely different. |
| 159 * Only the following fields should be identical. |
| 160 * |
| 161 * first_usable_lba |
| 162 * last_usable_lba |
| 163 * number_of_entries |
| 164 * size_of_entry |
| 165 * disk_uuid |
| 166 * |
| 167 * If any of above field are not matched, overwrite secondary with primary since |
| 168 * we always trust primary. |
| 169 * If any one of header is invalid, copy from another. */ |
| 170 int IsSynonymous(const GptHeader* a, const GptHeader* b) { |
| 171 if ((a->first_usable_lba == b->first_usable_lba) && |
| 172 (a->last_usable_lba == b->last_usable_lba) && |
| 173 (a->number_of_entries == b->number_of_entries) && |
| 174 (a->size_of_entry == b->size_of_entry) && |
| 175 (!Memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid)))) |
| 176 return 1; |
| 177 return 0; |
| 178 } |
| 179 |
| 180 /* Primary entries and secondary entries should be bitwise identical. |
| 181 * If two entries tables are valid, compare them. If not the same, |
| 182 * overwrites secondary with primary (primary always has higher priority), |
| 183 * and marks secondary as modified. |
| 184 * If only one is valid, overwrites invalid one. |
| 185 * If all are invalid, does nothing. |
| 186 * This function returns bit masks for GptData.modified field. |
| 187 * Note that CRC is NOT re-computed in this function. |
| 188 */ |
| 189 uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) { |
| 190 if (valid_entries == MASK_BOTH) { |
| 191 if (Memcmp(gpt->primary_entries, gpt->secondary_entries, |
| 192 TOTAL_ENTRIES_SIZE)) { |
| 193 Memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE); |
| 194 return GPT_MODIFIED_ENTRIES2; |
| 195 } |
| 196 } else if (valid_entries == MASK_PRIMARY) { |
| 197 Memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE); |
| 198 return GPT_MODIFIED_ENTRIES2; |
| 199 } else if (valid_entries == MASK_SECONDARY) { |
| 200 Memcpy(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE); |
| 201 return GPT_MODIFIED_ENTRIES1; |
| 202 } |
| 203 |
| 204 return 0; |
| 205 } |
| 206 |
| 207 /* The above five fields are shared between primary and secondary headers. |
| 208 * We can recover one header from another through copying those fields. */ |
| 209 void CopySynonymousParts(GptHeader* target, const GptHeader* source) { |
| 210 target->first_usable_lba = source->first_usable_lba; |
| 211 target->last_usable_lba = source->last_usable_lba; |
| 212 target->number_of_entries = source->number_of_entries; |
| 213 target->size_of_entry = source->size_of_entry; |
| 214 Memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid)); |
| 215 } |
| 216 |
| 217 /* This function repairs primary and secondary headers if possible. |
| 218 * If both headers are valid (CRC32 is correct) but |
| 219 * a) indicate inconsistent usable LBA ranges, |
| 220 * b) inconsistent partition entry size and number, |
| 221 * c) inconsistent disk_uuid, |
| 222 * we will use the primary header to overwrite secondary header. |
| 223 * If primary is invalid (CRC32 is wrong), then we repair it from secondary. |
| 224 * If secondary is invalid (CRC32 is wrong), then we repair it from primary. |
| 225 * This function returns the bitmasks for modified header. |
| 226 * Note that CRC value is NOT re-computed in this function. UpdateCrc() will |
| 227 * do it later. |
| 228 */ |
| 229 uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) { |
| 230 GptHeader *primary_header, *secondary_header; |
| 231 |
| 232 primary_header = (GptHeader*)gpt->primary_header; |
| 233 secondary_header = (GptHeader*)gpt->secondary_header; |
| 234 |
| 235 if (valid_headers == MASK_BOTH) { |
| 236 if (!IsSynonymous(primary_header, secondary_header)) { |
| 237 CopySynonymousParts(secondary_header, primary_header); |
| 238 return GPT_MODIFIED_HEADER2; |
| 239 } |
| 240 } else if (valid_headers == MASK_PRIMARY) { |
| 241 Memcpy(secondary_header, primary_header, primary_header->size); |
| 242 secondary_header->my_lba = gpt->drive_sectors - 1; /* the last sector */ |
| 243 secondary_header->entries_lba = secondary_header->my_lba - |
| 244 GPT_ENTRIES_SECTORS; |
| 245 return GPT_MODIFIED_HEADER2; |
| 246 } else if (valid_headers == MASK_SECONDARY) { |
| 247 Memcpy(primary_header, secondary_header, secondary_header->size); |
| 248 primary_header->my_lba = GPT_PMBR_SECTOR; /* the second sector on drive */ |
| 249 primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTOR; |
| 250 return GPT_MODIFIED_HEADER1; |
| 251 } |
| 252 |
| 253 return 0; |
| 254 } |
| 255 |
| 256 /* TODO: HORRIBLY broken non-implemented functions. These will be |
| 257 * fixed as part of a second stage of refactoring to use the new |
| 258 * cgptlib_internal functions. */ |
| 259 uint32_t CheckOverlappedPartition(GptData *gpt) { |
| 260 return 1; |
| 261 } |
| 262 |
| 263 uint32_t CheckValidEntries(GptData *gpt) { |
| 264 return 1; |
| 265 } |
| 266 |
| 267 int NonZeroGuid(const Guid *guid) { |
| 268 return 1; |
| 269 } |
OLD | NEW |