blob: cb8ad2b9a7834113d99859a31169043aa526df1b [file] [log] [blame]
Randall Spanglercefe12c2013-01-30 12:52:02 -08001/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Joel Kitching0b3ce462019-06-14 14:52:41 +08006#include "2sysincludes.h"
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07007#include "cgptlib.h"
8#include "cgptlib_internal.h"
9#include "crc32.h"
10#include "gpt.h"
Dan Ehrenberg7c2beb02014-10-21 16:15:54 -070011#include "gpt_misc.h"
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070012
Sam Hurstd6f52a02018-04-11 08:50:58 -070013const static int MIN_SECTOR_SIZE = 512;
Nam T. Nguyen32004012014-12-12 09:38:35 -080014
Sam Hurstd6f52a02018-04-11 08:50:58 -070015size_t CalculateEntriesSectors(GptHeader* h, uint32_t sector_bytes)
Randall Spanglerfb267152016-10-11 15:28:16 -070016{
17 size_t bytes = h->number_of_entries * h->size_of_entry;
Sam Hurstd6f52a02018-04-11 08:50:58 -070018 size_t ret = (bytes + sector_bytes - 1) / sector_bytes;
Randall Spanglerfb267152016-10-11 15:28:16 -070019 return ret;
Nam T. Nguyen32004012014-12-12 09:38:35 -080020}
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070021
Randall Spanglercefe12c2013-01-30 12:52:02 -080022int CheckParameters(GptData *gpt)
Vadim Bendebury65d3c272012-09-24 17:41:18 -070023{
Sam Hurstd6f52a02018-04-11 08:50:58 -070024 /* Only support 512-byte or larger sectors that are a power of 2 */
25 if (gpt->sector_bytes < MIN_SECTOR_SIZE ||
26 (gpt->sector_bytes & (gpt->sector_bytes - 1)) != 0)
Randall Spanglercefe12c2013-01-30 12:52:02 -080027 return GPT_ERROR_INVALID_SECTOR_SIZE;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070028
Randall Spanglercefe12c2013-01-30 12:52:02 -080029 /*
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -080030 * gpt_drive_sectors should be reasonable. It cannot be unset, and it
31 * cannot differ from streaming_drive_sectors if the GPT structs are
32 * stored on same device.
Nam T. Nguyen6ee52d92014-10-24 13:20:39 -070033 */
34 if (gpt->gpt_drive_sectors == 0 ||
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -080035 (!(gpt->flags & GPT_FLAG_EXTERNAL) &&
36 gpt->gpt_drive_sectors != gpt->streaming_drive_sectors)) {
Nam T. Nguyen6ee52d92014-10-24 13:20:39 -070037 return GPT_ERROR_INVALID_SECTOR_NUMBER;
38 }
39
40 /*
Randall Spanglercefe12c2013-01-30 12:52:02 -080041 * Sector count of a drive should be reasonable. If the given value is
42 * too small to contain basic GPT structure (PMBR + Headers + Entries),
Dan Ehrenbergf3f7fca2015-01-02 14:39:38 -080043 * the value is wrong.
Randall Spanglercefe12c2013-01-30 12:52:02 -080044 */
Dan Ehrenbergf3f7fca2015-01-02 14:39:38 -080045 if (gpt->gpt_drive_sectors <
46 (1 + 2 * (1 + MIN_NUMBER_OF_ENTRIES /
Sam Hurstd6f52a02018-04-11 08:50:58 -070047 (gpt->sector_bytes / sizeof(GptEntry)))))
Randall Spanglercefe12c2013-01-30 12:52:02 -080048 return GPT_ERROR_INVALID_SECTOR_NUMBER;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070049
Randall Spanglercefe12c2013-01-30 12:52:02 -080050 return GPT_SUCCESS;
51}
Vadim Bendebury65d3c272012-09-24 17:41:18 -070052
Randall Spanglercefe12c2013-01-30 12:52:02 -080053uint32_t HeaderCrc(GptHeader *h)
54{
55 uint32_t crc32, original_crc32;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070056
Randall Spanglercefe12c2013-01-30 12:52:02 -080057 /* Original CRC is calculated with the CRC field 0. */
58 original_crc32 = h->header_crc32;
59 h->header_crc32 = 0;
60 crc32 = Crc32((const uint8_t *)h, h->size);
61 h->header_crc32 = original_crc32;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070062
Randall Spanglercefe12c2013-01-30 12:52:02 -080063 return crc32;
64}
Vadim Bendebury65d3c272012-09-24 17:41:18 -070065
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -080066int CheckHeader(GptHeader *h, int is_secondary,
67 uint64_t streaming_drive_sectors,
Sam Hurstd6f52a02018-04-11 08:50:58 -070068 uint64_t gpt_drive_sectors, uint32_t flags,
69 uint32_t sector_bytes)
Randall Spanglercefe12c2013-01-30 12:52:02 -080070{
71 if (!h)
72 return 1;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070073
Randall Spanglercefe12c2013-01-30 12:52:02 -080074 /*
75 * Make sure we're looking at a header of reasonable size before
76 * attempting to calculate CRC.
77 */
Randall Spangler664096b2016-10-13 16:16:41 -070078 if (memcmp(h->signature, GPT_HEADER_SIGNATURE,
Randall Spanglercefe12c2013-01-30 12:52:02 -080079 GPT_HEADER_SIGNATURE_SIZE) &&
Randall Spangler664096b2016-10-13 16:16:41 -070080 memcmp(h->signature, GPT_HEADER_SIGNATURE2,
Randall Spanglercefe12c2013-01-30 12:52:02 -080081 GPT_HEADER_SIGNATURE_SIZE))
82 return 1;
83 if (h->revision != GPT_HEADER_REVISION)
84 return 1;
85 if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
86 return 1;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070087
Randall Spanglercefe12c2013-01-30 12:52:02 -080088 /* Check CRC before looking at remaining fields */
89 if (HeaderCrc(h) != h->header_crc32)
90 return 1;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070091
Randall Spanglercefe12c2013-01-30 12:52:02 -080092 /* Reserved fields must be zero. */
93 if (h->reserved_zero)
94 return 1;
Vadim Bendebury65d3c272012-09-24 17:41:18 -070095
Randall Spanglercefe12c2013-01-30 12:52:02 -080096 /* Could check that padding is zero, but that doesn't matter to us. */
Vadim Bendebury65d3c272012-09-24 17:41:18 -070097
Randall Spanglercefe12c2013-01-30 12:52:02 -080098 /*
99 * If entry size is different than our struct, we won't be able to
100 * parse it. Technically, any size 2^N where N>=7 is valid.
101 */
102 if (h->size_of_entry != sizeof(GptEntry))
103 return 1;
104 if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
105 (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -0800106 (!(flags & GPT_FLAG_EXTERNAL) &&
Dan Ehrenbergf3f7fca2015-01-02 14:39:38 -0800107 h->number_of_entries != MAX_NUMBER_OF_ENTRIES))
Randall Spanglercefe12c2013-01-30 12:52:02 -0800108 return 1;
Vadim Bendebury65d3c272012-09-24 17:41:18 -0700109
Randall Spanglercefe12c2013-01-30 12:52:02 -0800110 /*
111 * Check locations for the header and its entries. The primary
112 * immediately follows the PMBR, and is followed by its entries. The
113 * secondary is at the end of the drive, preceded by its entries.
114 */
115 if (is_secondary) {
Dan Ehrenberga524a3a2014-11-06 16:22:24 -0800116 if (h->my_lba != gpt_drive_sectors - GPT_HEADER_SECTORS)
Randall Spanglercefe12c2013-01-30 12:52:02 -0800117 return 1;
Sam Hurstd6f52a02018-04-11 08:50:58 -0700118 if (h->entries_lba != h->my_lba - CalculateEntriesSectors(h,
119 sector_bytes))
Randall Spanglercefe12c2013-01-30 12:52:02 -0800120 return 1;
121 } else {
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700122 if (h->my_lba != GPT_PMBR_SECTORS)
Randall Spanglercefe12c2013-01-30 12:52:02 -0800123 return 1;
Nam T. Nguyena2d72f72014-08-22 15:01:38 -0700124 if (h->entries_lba < h->my_lba + 1)
Randall Spanglercefe12c2013-01-30 12:52:02 -0800125 return 1;
126 }
127
Nam T. Nguyen6ee52d92014-10-24 13:20:39 -0700128 /* FirstUsableLBA <= LastUsableLBA. */
129 if (h->first_usable_lba > h->last_usable_lba)
130 return 1;
131
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -0800132 if (flags & GPT_FLAG_EXTERNAL) {
133 if (h->last_usable_lba >= streaming_drive_sectors) {
Nam T. Nguyen6ee52d92014-10-24 13:20:39 -0700134 return 1;
135 }
136 return 0;
137 }
138
Randall Spanglercefe12c2013-01-30 12:52:02 -0800139 /*
140 * FirstUsableLBA must be after the end of the primary GPT table array.
141 * LastUsableLBA must be before the start of the secondary GPT table
Nam T. Nguyen6ee52d92014-10-24 13:20:39 -0700142 * array.
Randall Spanglercefe12c2013-01-30 12:52:02 -0800143 */
Nam T. Nguyena2d72f72014-08-22 15:01:38 -0700144 /* TODO(namnguyen): Also check for padding between header & entries. */
Sam Hurstd6f52a02018-04-11 08:50:58 -0700145 if (h->first_usable_lba < 2 + CalculateEntriesSectors(h, sector_bytes))
Randall Spanglercefe12c2013-01-30 12:52:02 -0800146 return 1;
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -0800147 if (h->last_usable_lba >=
Sam Hurstd6f52a02018-04-11 08:50:58 -0700148 streaming_drive_sectors - 1 - CalculateEntriesSectors(h,
149 sector_bytes))
Randall Spanglercefe12c2013-01-30 12:52:02 -0800150 return 1;
Randall Spanglercefe12c2013-01-30 12:52:02 -0800151
152 /* Success */
153 return 0;
154}
155
Randall Spanglercefe12c2013-01-30 12:52:02 -0800156int IsKernelEntry(const GptEntry *e)
157{
158 static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
Randall Spangler664096b2016-10-13 16:16:41 -0700159 return !memcmp(&e->type, &chromeos_kernel, sizeof(Guid));
Randall Spanglercefe12c2013-01-30 12:52:02 -0800160}
161
162int CheckEntries(GptEntry *entries, GptHeader *h)
163{
Nam T. Nguyen5ce83252014-10-30 15:09:43 -0700164 if (!entries)
165 return GPT_ERROR_INVALID_ENTRIES;
Randall Spanglercefe12c2013-01-30 12:52:02 -0800166 GptEntry *entry;
167 uint32_t crc32;
168 uint32_t i;
169
170 /* Check CRC before examining entries. */
171 crc32 = Crc32((const uint8_t *)entries,
172 h->size_of_entry * h->number_of_entries);
173 if (crc32 != h->entries_crc32)
174 return GPT_ERROR_CRC_CORRUPTED;
175
176 /* Check all entries. */
177 for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) {
178 GptEntry *e2;
179 uint32_t i2;
180
181 if (IsUnusedEntry(entry))
182 continue;
183
184 /* Entry must be in valid region. */
185 if ((entry->starting_lba < h->first_usable_lba) ||
186 (entry->ending_lba > h->last_usable_lba) ||
187 (entry->ending_lba < entry->starting_lba))
188 return GPT_ERROR_OUT_OF_REGION;
189
190 /* Entry must not overlap other entries. */
191 for (i2 = 0, e2 = entries; i2 < h->number_of_entries;
192 i2++, e2++) {
193 if (i2 == i || IsUnusedEntry(e2))
194 continue;
195
196 if ((entry->starting_lba >= e2->starting_lba) &&
197 (entry->starting_lba <= e2->ending_lba))
198 return GPT_ERROR_START_LBA_OVERLAP;
199 if ((entry->ending_lba >= e2->starting_lba) &&
200 (entry->ending_lba <= e2->ending_lba))
201 return GPT_ERROR_END_LBA_OVERLAP;
202
203 /* UniqueGuid field must be unique. */
Randall Spangler664096b2016-10-13 16:16:41 -0700204 if (0 == memcmp(&entry->unique, &e2->unique,
Randall Spanglercefe12c2013-01-30 12:52:02 -0800205 sizeof(Guid)))
206 return GPT_ERROR_DUP_GUID;
207 }
208 }
209
210 /* Success */
211 return 0;
212}
213
214int HeaderFieldsSame(GptHeader *h1, GptHeader *h2)
215{
Randall Spangler664096b2016-10-13 16:16:41 -0700216 if (memcmp(h1->signature, h2->signature, sizeof(h1->signature)))
Randall Spanglercefe12c2013-01-30 12:52:02 -0800217 return 1;
218 if (h1->revision != h2->revision)
219 return 1;
220 if (h1->size != h2->size)
221 return 1;
222 if (h1->reserved_zero != h2->reserved_zero)
223 return 1;
224 if (h1->first_usable_lba != h2->first_usable_lba)
225 return 1;
226 if (h1->last_usable_lba != h2->last_usable_lba)
227 return 1;
Randall Spangler664096b2016-10-13 16:16:41 -0700228 if (memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid)))
Randall Spanglercefe12c2013-01-30 12:52:02 -0800229 return 1;
230 if (h1->number_of_entries != h2->number_of_entries)
231 return 1;
232 if (h1->size_of_entry != h2->size_of_entry)
233 return 1;
234 if (h1->entries_crc32 != h2->entries_crc32)
235 return 1;
236
237 return 0;
238}
239
Daisuke Nojiri053592b2020-08-12 15:46:30 -0700240int GptValidityCheck(GptData *gpt)
Randall Spanglercefe12c2013-01-30 12:52:02 -0800241{
242 int retval;
243 GptHeader *header1 = (GptHeader *)(gpt->primary_header);
244 GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
245 GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
246 GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
247 GptHeader *goodhdr = NULL;
248
249 gpt->valid_headers = 0;
250 gpt->valid_entries = 0;
Julius Werner39910d02016-04-19 16:55:36 -0700251 gpt->ignored = 0;
Randall Spanglercefe12c2013-01-30 12:52:02 -0800252
253 retval = CheckParameters(gpt);
254 if (retval != GPT_SUCCESS)
255 return retval;
256
257 /* Check both headers; we need at least one valid header. */
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -0800258 if (0 == CheckHeader(header1, 0, gpt->streaming_drive_sectors,
Sam Hurstd6f52a02018-04-11 08:50:58 -0700259 gpt->gpt_drive_sectors, gpt->flags,
260 gpt->sector_bytes)) {
Randall Spanglercefe12c2013-01-30 12:52:02 -0800261 gpt->valid_headers |= MASK_PRIMARY;
262 goodhdr = header1;
Julius Werner8e8f4b92019-10-28 16:26:18 -0700263 if (0 == CheckEntries(entries1, goodhdr))
264 gpt->valid_entries |= MASK_PRIMARY;
Randall Spangler664096b2016-10-13 16:16:41 -0700265 } else if (header1 && !memcmp(header1->signature,
Julius Werner39910d02016-04-19 16:55:36 -0700266 GPT_HEADER_SIGNATURE_IGNORED, GPT_HEADER_SIGNATURE_SIZE)) {
267 gpt->ignored |= MASK_PRIMARY;
Randall Spanglercefe12c2013-01-30 12:52:02 -0800268 }
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -0800269 if (0 == CheckHeader(header2, 1, gpt->streaming_drive_sectors,
Sam Hurstd6f52a02018-04-11 08:50:58 -0700270 gpt->gpt_drive_sectors, gpt->flags,
271 gpt->sector_bytes)) {
Randall Spanglercefe12c2013-01-30 12:52:02 -0800272 gpt->valid_headers |= MASK_SECONDARY;
273 if (!goodhdr)
274 goodhdr = header2;
Julius Werner8e8f4b92019-10-28 16:26:18 -0700275 /* Check header1+entries2 if it was good, to catch mismatch. */
276 if (0 == CheckEntries(entries2, goodhdr))
277 gpt->valid_entries |= MASK_SECONDARY;
Randall Spangler664096b2016-10-13 16:16:41 -0700278 } else if (header2 && !memcmp(header2->signature,
Julius Werner39910d02016-04-19 16:55:36 -0700279 GPT_HEADER_SIGNATURE_IGNORED, GPT_HEADER_SIGNATURE_SIZE)) {
280 gpt->ignored |= MASK_SECONDARY;
Randall Spanglercefe12c2013-01-30 12:52:02 -0800281 }
282
283 if (!gpt->valid_headers)
284 return GPT_ERROR_INVALID_HEADERS;
285
286 /*
Randall Spanglercefe12c2013-01-30 12:52:02 -0800287 * If both headers are good but neither entries were good, check the
288 * entries with the secondary header.
289 */
290 if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
291 if (0 == CheckEntries(entries1, header2))
292 gpt->valid_entries |= MASK_PRIMARY;
293 if (0 == CheckEntries(entries2, header2))
294 gpt->valid_entries |= MASK_SECONDARY;
295 if (gpt->valid_entries) {
296 /*
297 * Sure enough, header2 had a good CRC for one of the
298 * entries. Mark header1 invalid, so we'll update its
299 * entries CRC.
300 */
301 gpt->valid_headers &= ~MASK_PRIMARY;
302 goodhdr = header2;
303 }
304 }
305
306 if (!gpt->valid_entries)
307 return GPT_ERROR_INVALID_ENTRIES;
308
309 /*
310 * Now that we've determined which header contains a good CRC for
311 * the entries, make sure the headers are otherwise identical.
312 */
313 if (MASK_BOTH == gpt->valid_headers &&
314 0 != HeaderFieldsSame(header1, header2))
315 gpt->valid_headers &= ~MASK_SECONDARY;
316
Julius Werner39910d02016-04-19 16:55:36 -0700317 /*
318 * When we're ignoring a GPT, make it look in memory like the other one
319 * and pretend that everything is fine (until we try to save).
320 */
321 if (MASK_NONE != gpt->ignored) {
322 GptRepair(gpt);
323 gpt->modified = 0;
324 }
325
Randall Spanglercefe12c2013-01-30 12:52:02 -0800326 return GPT_SUCCESS;
327}
328
329void GptRepair(GptData *gpt)
330{
331 GptHeader *header1 = (GptHeader *)(gpt->primary_header);
332 GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
333 GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
334 GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
335 int entries_size;
336
337 /* Need at least one good header and one good set of entries. */
338 if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries)
339 return;
340
341 /* Repair headers if necessary */
342 if (MASK_PRIMARY == gpt->valid_headers) {
343 /* Primary is good, secondary is bad */
Randall Spangler664096b2016-10-13 16:16:41 -0700344 memcpy(header2, header1, sizeof(GptHeader));
Dan Ehrenberga524a3a2014-11-06 16:22:24 -0800345 header2->my_lba = gpt->gpt_drive_sectors - GPT_HEADER_SECTORS;
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700346 header2->alternate_lba = GPT_PMBR_SECTORS; /* Second sector. */
Sam Hurstd6f52a02018-04-11 08:50:58 -0700347 header2->entries_lba = header2->my_lba -
348 CalculateEntriesSectors(header1, gpt->sector_bytes);
Randall Spanglercefe12c2013-01-30 12:52:02 -0800349 header2->header_crc32 = HeaderCrc(header2);
350 gpt->modified |= GPT_MODIFIED_HEADER2;
351 }
352 else if (MASK_SECONDARY == gpt->valid_headers) {
353 /* Secondary is good, primary is bad */
Randall Spangler664096b2016-10-13 16:16:41 -0700354 memcpy(header1, header2, sizeof(GptHeader));
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700355 header1->my_lba = GPT_PMBR_SECTORS; /* Second sector. */
Dan Ehrenbergb3d38f52014-12-09 13:42:15 -0800356 header1->alternate_lba =
357 gpt->streaming_drive_sectors - GPT_HEADER_SECTORS;
Nam T. Nguyena2d72f72014-08-22 15:01:38 -0700358 /* TODO (namnguyen): Preserve (header, entries) padding. */
Randall Spanglercefe12c2013-01-30 12:52:02 -0800359 header1->entries_lba = header1->my_lba + 1;
360 header1->header_crc32 = HeaderCrc(header1);
361 gpt->modified |= GPT_MODIFIED_HEADER1;
362 }
363 gpt->valid_headers = MASK_BOTH;
364
365 /* Repair entries if necessary */
366 entries_size = header1->size_of_entry * header1->number_of_entries;
367 if (MASK_PRIMARY == gpt->valid_entries) {
368 /* Primary is good, secondary is bad */
Randall Spangler664096b2016-10-13 16:16:41 -0700369 memcpy(entries2, entries1, entries_size);
Randall Spanglercefe12c2013-01-30 12:52:02 -0800370 gpt->modified |= GPT_MODIFIED_ENTRIES2;
371 }
372 else if (MASK_SECONDARY == gpt->valid_entries) {
373 /* Secondary is good, primary is bad */
Randall Spangler664096b2016-10-13 16:16:41 -0700374 memcpy(entries1, entries2, entries_size);
Randall Spanglercefe12c2013-01-30 12:52:02 -0800375 gpt->modified |= GPT_MODIFIED_ENTRIES1;
376 }
377 gpt->valid_entries = MASK_BOTH;
378}
379
Ben Chana4a8c022018-01-31 11:39:14 -0800380int GetEntryRequired(const GptEntry *e)
381{
382 return e->attrs.fields.required;
383}
384
Mike Frysinger6c18af52016-09-07 16:45:48 -0400385int GetEntryLegacyBoot(const GptEntry *e)
386{
387 return e->attrs.fields.legacy_boot;
388}
389
Randall Spanglercefe12c2013-01-30 12:52:02 -0800390int GetEntrySuccessful(const GptEntry *e)
391{
392 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
393 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
394}
395
396int GetEntryPriority(const GptEntry *e)
397{
398 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
399 CGPT_ATTRIBUTE_PRIORITY_OFFSET;
400}
401
402int GetEntryTries(const GptEntry *e)
403{
404 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >>
405 CGPT_ATTRIBUTE_TRIES_OFFSET;
406}
407
Ben Chana4a8c022018-01-31 11:39:14 -0800408void SetEntryRequired(GptEntry *e, int required)
409{
410 e->attrs.fields.required = required;
411}
412
Mike Frysinger6c18af52016-09-07 16:45:48 -0400413void SetEntryLegacyBoot(GptEntry *e, int legacy_boot)
414{
415 e->attrs.fields.legacy_boot = legacy_boot;
416}
417
Randall Spanglercefe12c2013-01-30 12:52:02 -0800418void SetEntrySuccessful(GptEntry *e, int successful)
419{
420 if (successful)
421 e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
422 else
423 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
424}
425
426void SetEntryPriority(GptEntry *e, int priority)
427{
428 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
429 e->attrs.fields.gpt_att |=
430 (priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) &
431 CGPT_ATTRIBUTE_PRIORITY_MASK;
432}
433
434void SetEntryTries(GptEntry *e, int tries)
435{
436 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK;
437 e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET) &
438 CGPT_ATTRIBUTE_TRIES_MASK;
439}
440
441void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
442{
443 GptEntry *entries = (GptEntry *)gpt->primary_entries;
444 GptEntry *e = entries + gpt->current_kernel;
Randall Spangler664096b2016-10-13 16:16:41 -0700445 memcpy(dest, &e->unique, sizeof(Guid));
Randall Spanglercefe12c2013-01-30 12:52:02 -0800446}
447
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700448void GptModified(GptData *gpt) {
449 GptHeader *header = (GptHeader *)gpt->primary_header;
450
451 /* Update the CRCs */
452 header->entries_crc32 = Crc32(gpt->primary_entries,
453 header->size_of_entry *
454 header->number_of_entries);
455 header->header_crc32 = HeaderCrc(header);
456 gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
457
458 /*
459 * Use the repair function to update the other copy of the GPT. This
460 * is a tad inefficient, but is much faster than the disk I/O to update
461 * the GPT on disk so it doesn't matter.
462 */
463 gpt->valid_headers = MASK_PRIMARY;
464 gpt->valid_entries = MASK_PRIMARY;
465 GptRepair(gpt);
466}
467
468
Randall Spanglercefe12c2013-01-30 12:52:02 -0800469const char *GptErrorText(int error_code)
470{
471 switch(error_code) {
472 case GPT_SUCCESS:
473 return "none";
474
475 case GPT_ERROR_NO_VALID_KERNEL:
476 return "Invalid kernel";
477
478 case GPT_ERROR_INVALID_HEADERS:
479 return "Invalid headers";
480
481 case GPT_ERROR_INVALID_ENTRIES:
482 return "Invalid entries";
483
484 case GPT_ERROR_INVALID_SECTOR_SIZE:
485 return "Invalid sector size";
486
487 case GPT_ERROR_INVALID_SECTOR_NUMBER:
488 return "Invalid sector number";
489
490 case GPT_ERROR_INVALID_UPDATE_TYPE:
491 return "Invalid update type";
492
493 case GPT_ERROR_CRC_CORRUPTED:
494 return "Entries' crc corrupted";
495
496 case GPT_ERROR_OUT_OF_REGION:
497 return "Entry outside of valid region";
498
499 case GPT_ERROR_START_LBA_OVERLAP:
500 return "Starting LBA overlaps";
501
502 case GPT_ERROR_END_LBA_OVERLAP:
503 return "Ending LBA overlaps";
504
505 case GPT_ERROR_DUP_GUID:
506 return "Duplicated GUID";
507
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700508 case GPT_ERROR_INVALID_FLASH_GEOMETRY:
509 return "Invalid flash geometry";
510
511 case GPT_ERROR_NO_SUCH_ENTRY:
512 return "No entry found";
513
Randall Spanglercefe12c2013-01-30 12:52:02 -0800514 default:
515 break;
516 };
517 return "Unknown";
Vadim Bendebury65d3c272012-09-24 17:41:18 -0700518}