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 |