1cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
23dcf9dce04301d6d735f265652625fffb6758430Randall Spangler * Use of this source code is governed by a BSD-style license that can be
33dcf9dce04301d6d735f265652625fffb6758430Randall Spangler * found in the LICENSE file.
43dcf9dce04301d6d735f265652625fffb6758430Randall Spangler */
53dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
60c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "sysincludes.h"
70c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson
83dcf9dce04301d6d735f265652625fffb6758430Randall Spangler#include "cgptlib.h"
93dcf9dce04301d6d735f265652625fffb6758430Randall Spangler#include "cgptlib_internal.h"
103dcf9dce04301d6d735f265652625fffb6758430Randall Spangler#include "crc32.h"
113dcf9dce04301d6d735f265652625fffb6758430Randall Spangler#include "gpt.h"
127c2beb08380410ca6847abdac23e11ded2d1b625Dan Ehrenberg#include "gpt_misc.h"
133dcf9dce04301d6d735f265652625fffb6758430Randall Spangler#include "utility.h"
143dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
153200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyenconst static int SECTOR_SIZE = 512;
163200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen
173200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyensize_t CalculateEntriesSectors(GptHeader* h) {
183200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen  size_t bytes = h->number_of_entries * h->size_of_entry;
193200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen  size_t ret = (bytes + SECTOR_SIZE - 1) / SECTOR_SIZE;
203200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen  return ret;
213200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen}
223dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
23cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint CheckParameters(GptData *gpt)
24cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
25cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Currently, we only support 512-byte sectors. */
263200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen	if (gpt->sector_bytes != SECTOR_SIZE)
27cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return GPT_ERROR_INVALID_SECTOR_SIZE;
28cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
29cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
30b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	 * gpt_drive_sectors should be reasonable. It cannot be unset, and it
31b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	 * cannot differ from streaming_drive_sectors if the GPT structs are
32b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	 * stored on same device.
336ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	 */
346ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	if (gpt->gpt_drive_sectors == 0 ||
35b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg		(!(gpt->flags & GPT_FLAG_EXTERNAL) &&
36b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg		 gpt->gpt_drive_sectors != gpt->streaming_drive_sectors)) {
376ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen		return GPT_ERROR_INVALID_SECTOR_NUMBER;
386ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	}
396ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen
406ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	/*
41cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * Sector count of a drive should be reasonable. If the given value is
42cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * too small to contain basic GPT structure (PMBR + Headers + Entries),
43f3f7fca07fbcb6bb9655a71257f09c71b0a1458dDan Ehrenberg	 * the value is wrong.
44cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
45f3f7fca07fbcb6bb9655a71257f09c71b0a1458dDan Ehrenberg	if (gpt->gpt_drive_sectors <
46f3f7fca07fbcb6bb9655a71257f09c71b0a1458dDan Ehrenberg		(1 + 2 * (1 + MIN_NUMBER_OF_ENTRIES /
47f3f7fca07fbcb6bb9655a71257f09c71b0a1458dDan Ehrenberg				(SECTOR_SIZE / sizeof(GptEntry)))))
48cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return GPT_ERROR_INVALID_SECTOR_NUMBER;
49cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
50cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return GPT_SUCCESS;
513dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
523dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
53cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangleruint32_t HeaderCrc(GptHeader *h)
54cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
55cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	uint32_t crc32, original_crc32;
563dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
57cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Original CRC is calculated with the CRC field 0. */
58cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	original_crc32 = h->header_crc32;
59cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	h->header_crc32 = 0;
60cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	crc32 = Crc32((const uint8_t *)h, h->size);
61cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	h->header_crc32 = original_crc32;
623dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
63cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return crc32;
643dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
653dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
66b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenbergint CheckHeader(GptHeader *h, int is_secondary,
67b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg		uint64_t streaming_drive_sectors,
68b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg		uint64_t gpt_drive_sectors, uint32_t flags)
69cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
70cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (!h)
71cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
72cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
73cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
74cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * Make sure we're looking at a header of reasonable size before
75cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * attempting to calculate CRC.
76cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
77cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (Memcmp(h->signature, GPT_HEADER_SIGNATURE,
78cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		   GPT_HEADER_SIGNATURE_SIZE) &&
79cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	    Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
80cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		   GPT_HEADER_SIGNATURE_SIZE))
81cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
82cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h->revision != GPT_HEADER_REVISION)
83cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
84cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
85cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
86cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
87cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Check CRC before looking at remaining fields */
88cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (HeaderCrc(h) != h->header_crc32)
89cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
90cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
91cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Reserved fields must be zero. */
92cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h->reserved_zero)
93cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
94cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
95cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Could check that padding is zero, but that doesn't matter to us. */
96cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
97cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
98cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * If entry size is different than our struct, we won't be able to
99cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * parse it.  Technically, any size 2^N where N>=7 is valid.
100cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
101cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h->size_of_entry != sizeof(GptEntry))
102cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
103cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
104cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	    (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
105b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	    (!(flags & GPT_FLAG_EXTERNAL) &&
106f3f7fca07fbcb6bb9655a71257f09c71b0a1458dDan Ehrenberg	    h->number_of_entries != MAX_NUMBER_OF_ENTRIES))
107cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
108cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
109cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
110cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * Check locations for the header and its entries.  The primary
111cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * immediately follows the PMBR, and is followed by its entries.  The
112cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * secondary is at the end of the drive, preceded by its entries.
113cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
114cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (is_secondary) {
115a524a3a51591618c1395cb9e1238ee72b3f5e767Dan Ehrenberg		if (h->my_lba != gpt_drive_sectors - GPT_HEADER_SECTORS)
116cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			return 1;
1173200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen		if (h->entries_lba != h->my_lba - CalculateEntriesSectors(h))
118cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			return 1;
119cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	} else {
12088458d9b5281aca162821a369707781ac9abb44eNam T. Nguyen		if (h->my_lba != GPT_PMBR_SECTORS)
121cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			return 1;
122a2d72f70c18905aba25eb0971f6f601dd1fa5a60Nam T. Nguyen		if (h->entries_lba < h->my_lba + 1)
123cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			return 1;
124cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
125cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
1266ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	/* FirstUsableLBA <= LastUsableLBA. */
1276ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	if (h->first_usable_lba > h->last_usable_lba)
1286ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen		return 1;
1296ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen
130b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	if (flags & GPT_FLAG_EXTERNAL) {
131b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg		if (h->last_usable_lba >= streaming_drive_sectors) {
1326ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen			return 1;
1336ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen		}
1346ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen		return 0;
1356ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	}
1366ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen
137cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
138cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * FirstUsableLBA must be after the end of the primary GPT table array.
139cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * LastUsableLBA must be before the start of the secondary GPT table
1406ee52d9a929d00e871e7316240b54f381146fbc6Nam T. Nguyen	 * array.
141cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
142a2d72f70c18905aba25eb0971f6f601dd1fa5a60Nam T. Nguyen	/* TODO(namnguyen): Also check for padding between header & entries. */
1433200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen	if (h->first_usable_lba < 2 + CalculateEntriesSectors(h))
144cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
145b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	if (h->last_usable_lba >=
1463200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen			streaming_drive_sectors - 1 - CalculateEntriesSectors(h))
147cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
148cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
149cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Success */
150cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return 0;
1513dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
1523dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
153cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint IsKernelEntry(const GptEntry *e)
154cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
155cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
156cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return !Memcmp(&e->type, &chromeos_kernel, sizeof(Guid));
1573dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
1583dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
159cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint CheckEntries(GptEntry *entries, GptHeader *h)
160cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
1615ce8325f4ac4662d0daef63878c85462a8e59ff4Nam T. Nguyen	if (!entries)
1625ce8325f4ac4662d0daef63878c85462a8e59ff4Nam T. Nguyen		return GPT_ERROR_INVALID_ENTRIES;
163cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *entry;
164cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	uint32_t crc32;
165cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	uint32_t i;
166cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
167cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Check CRC before examining entries. */
168cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	crc32 = Crc32((const uint8_t *)entries,
169cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		      h->size_of_entry * h->number_of_entries);
170cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (crc32 != h->entries_crc32)
171cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return GPT_ERROR_CRC_CORRUPTED;
172cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
173cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Check all entries. */
174cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) {
175cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		GptEntry *e2;
176cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		uint32_t i2;
177cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
178cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		if (IsUnusedEntry(entry))
179cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			continue;
180cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
181cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		/* Entry must be in valid region. */
182cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		if ((entry->starting_lba < h->first_usable_lba) ||
183cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		    (entry->ending_lba > h->last_usable_lba) ||
184cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		    (entry->ending_lba < entry->starting_lba))
185cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			return GPT_ERROR_OUT_OF_REGION;
186cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
187cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		/* Entry must not overlap other entries. */
188cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		for (i2 = 0, e2 = entries; i2 < h->number_of_entries;
189cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		     i2++, e2++) {
190cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			if (i2 == i || IsUnusedEntry(e2))
191cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler				continue;
192cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
193cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			if ((entry->starting_lba >= e2->starting_lba) &&
194cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			    (entry->starting_lba <= e2->ending_lba))
195cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler				return GPT_ERROR_START_LBA_OVERLAP;
196cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			if ((entry->ending_lba >= e2->starting_lba) &&
197cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			    (entry->ending_lba <= e2->ending_lba))
198cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler				return GPT_ERROR_END_LBA_OVERLAP;
199cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
200cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			/* UniqueGuid field must be unique. */
201cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			if (0 == Memcmp(&entry->unique, &e2->unique,
202cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler					sizeof(Guid)))
203cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler				return GPT_ERROR_DUP_GUID;
204cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		}
205cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
206cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
207cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Success */
208cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return 0;
2093dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
2103dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
211cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint HeaderFieldsSame(GptHeader *h1, GptHeader *h2)
212cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
213cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature)))
214cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
215cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->revision != h2->revision)
216cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
217cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->size != h2->size)
218cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
219cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->reserved_zero != h2->reserved_zero)
220cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
221cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->first_usable_lba != h2->first_usable_lba)
222cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
223cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->last_usable_lba != h2->last_usable_lba)
224cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
225cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid)))
226cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
227cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->number_of_entries != h2->number_of_entries)
228cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
229cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->size_of_entry != h2->size_of_entry)
230cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
231cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (h1->entries_crc32 != h2->entries_crc32)
232cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return 1;
233cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
234cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return 0;
2353dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
2363dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
237cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint GptSanityCheck(GptData *gpt)
238cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
239cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	int retval;
240cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptHeader *header1 = (GptHeader *)(gpt->primary_header);
241cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
242cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
243cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
244cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptHeader *goodhdr = NULL;
245cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
246cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	gpt->valid_headers = 0;
247cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	gpt->valid_entries = 0;
248cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
249cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	retval = CheckParameters(gpt);
250cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (retval != GPT_SUCCESS)
251cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return retval;
252cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
253cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Check both headers; we need at least one valid header. */
254b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	if (0 == CheckHeader(header1, 0, gpt->streaming_drive_sectors,
255b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg			     gpt->gpt_drive_sectors, gpt->flags)) {
256cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->valid_headers |= MASK_PRIMARY;
257cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		goodhdr = header1;
258cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
259b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg	if (0 == CheckHeader(header2, 1, gpt->streaming_drive_sectors,
260b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg			     gpt->gpt_drive_sectors, gpt->flags)) {
261cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->valid_headers |= MASK_SECONDARY;
262cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		if (!goodhdr)
263cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			goodhdr = header2;
264cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
265cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
266cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (!gpt->valid_headers)
267cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return GPT_ERROR_INVALID_HEADERS;
268cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
269cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
270cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * Check if entries are valid.
271cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 *
272cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * Note that we use the same header in both checks.  This way we'll
273cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * catch the case where (header1,entries1) and (header2,entries2) are
274cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * both valid, but (entries1 != entries2).
275cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
276cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (0 == CheckEntries(entries1, goodhdr))
277cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->valid_entries |= MASK_PRIMARY;
278cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (0 == CheckEntries(entries2, goodhdr))
279cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->valid_entries |= MASK_SECONDARY;
280cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
281cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
282cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * If both headers are good but neither entries were good, check the
283cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * entries with the secondary header.
284cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
285cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
286cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		if (0 == CheckEntries(entries1, header2))
287cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			gpt->valid_entries |= MASK_PRIMARY;
288cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		if (0 == CheckEntries(entries2, header2))
289cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			gpt->valid_entries |= MASK_SECONDARY;
290cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		if (gpt->valid_entries) {
291cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			/*
292cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			 * Sure enough, header2 had a good CRC for one of the
293cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			 * entries.  Mark header1 invalid, so we'll update its
294cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			 * entries CRC.
295cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			 */
296cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			gpt->valid_headers &= ~MASK_PRIMARY;
297cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler			goodhdr = header2;
298cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		}
299cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
300cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
301cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (!gpt->valid_entries)
302cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return GPT_ERROR_INVALID_ENTRIES;
303cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
304cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/*
305cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * Now that we've determined which header contains a good CRC for
306cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 * the entries, make sure the headers are otherwise identical.
307cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	 */
308cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (MASK_BOTH == gpt->valid_headers &&
309cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	    0 != HeaderFieldsSame(header1, header2))
310cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->valid_headers &= ~MASK_SECONDARY;
311cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
312cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return GPT_SUCCESS;
3133dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3143dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
315cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglervoid GptRepair(GptData *gpt)
316cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
317cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptHeader *header1 = (GptHeader *)(gpt->primary_header);
318cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
319cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
320cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
321cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	int entries_size;
322cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
323cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Need at least one good header and one good set of entries. */
324cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries)
325cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return;
326cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
327cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Repair headers if necessary */
328cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (MASK_PRIMARY == gpt->valid_headers) {
329cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		/* Primary is good, secondary is bad */
330cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		Memcpy(header2, header1, sizeof(GptHeader));
331a524a3a51591618c1395cb9e1238ee72b3f5e767Dan Ehrenberg		header2->my_lba = gpt->gpt_drive_sectors - GPT_HEADER_SECTORS;
33288458d9b5281aca162821a369707781ac9abb44eNam T. Nguyen		header2->alternate_lba = GPT_PMBR_SECTORS;  /* Second sector. */
3333200401242aec1521e7c4a8b1906366fcabfb1a2Nam T. Nguyen		header2->entries_lba = header2->my_lba - CalculateEntriesSectors(header1);
334cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		header2->header_crc32 = HeaderCrc(header2);
335cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->modified |= GPT_MODIFIED_HEADER2;
336cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
337cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	else if (MASK_SECONDARY == gpt->valid_headers) {
338cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		/* Secondary is good, primary is bad */
339cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		Memcpy(header1, header2, sizeof(GptHeader));
34088458d9b5281aca162821a369707781ac9abb44eNam T. Nguyen		header1->my_lba = GPT_PMBR_SECTORS;  /* Second sector. */
341b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg		header1->alternate_lba =
342b3d38f5c620da89662deb1a08971c5025d6c1132Dan Ehrenberg			gpt->streaming_drive_sectors - GPT_HEADER_SECTORS;
343a2d72f70c18905aba25eb0971f6f601dd1fa5a60Nam T. Nguyen		/* TODO (namnguyen): Preserve (header, entries) padding. */
344cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		header1->entries_lba = header1->my_lba + 1;
345cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		header1->header_crc32 = HeaderCrc(header1);
346cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->modified |= GPT_MODIFIED_HEADER1;
347cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
348cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	gpt->valid_headers = MASK_BOTH;
349cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler
350cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	/* Repair entries if necessary */
351cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	entries_size = header1->size_of_entry * header1->number_of_entries;
352cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (MASK_PRIMARY == gpt->valid_entries) {
353cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		/* Primary is good, secondary is bad */
354cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		Memcpy(entries2, entries1, entries_size);
355cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->modified |= GPT_MODIFIED_ENTRIES2;
356cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
357cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	else if (MASK_SECONDARY == gpt->valid_entries) {
358cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		/* Secondary is good, primary is bad */
359cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		Memcpy(entries1, entries2, entries_size);
360cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		gpt->modified |= GPT_MODIFIED_ENTRIES1;
361cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	}
362cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	gpt->valid_entries = MASK_BOTH;
3633dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3643dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
365cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint GetEntrySuccessful(const GptEntry *e)
366cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
367cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
368cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
3693dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3703dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
371cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint GetEntryPriority(const GptEntry *e)
372cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
373cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
374cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		CGPT_ATTRIBUTE_PRIORITY_OFFSET;
3753dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3763dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
377cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerint GetEntryTries(const GptEntry *e)
378cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
379cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >>
380cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		CGPT_ATTRIBUTE_TRIES_OFFSET;
3813dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3823dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
383cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglervoid SetEntrySuccessful(GptEntry *e, int successful)
384cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
385cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	if (successful)
386cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
387cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	else
388cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
3893dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3903dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
391cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglervoid SetEntryPriority(GptEntry *e, int priority)
392cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
393cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
394cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	e->attrs.fields.gpt_att |=
395cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		(priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) &
396cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		CGPT_ATTRIBUTE_PRIORITY_MASK;
3973dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
3983dcf9dce04301d6d735f265652625fffb6758430Randall Spangler
399cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglervoid SetEntryTries(GptEntry *e, int tries)
400cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
401cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK;
402cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET) &
403cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		CGPT_ATTRIBUTE_TRIES_MASK;
4043dcf9dce04301d6d735f265652625fffb6758430Randall Spangler}
4055deb67f22507481cf5cb8f991976a9969fa90a22Bill Richardson
406cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglervoid GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
407cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler{
408cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *entries = (GptEntry *)gpt->primary_entries;
409cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	GptEntry *e = entries + gpt->current_kernel;
410cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	Memcpy(dest, &e->unique, sizeof(Guid));
4115deb67f22507481cf5cb8f991976a9969fa90a22Bill Richardson}
41265d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
4135c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulkvoid GptModified(GptData *gpt) {
4145c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	GptHeader *header = (GptHeader *)gpt->primary_header;
4155c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk
4165c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	/* Update the CRCs */
4175c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	header->entries_crc32 = Crc32(gpt->primary_entries,
4185c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk				      header->size_of_entry *
4195c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk				      header->number_of_entries);
4205c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	header->header_crc32 = HeaderCrc(header);
4215c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
4225c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk
4235c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	/*
4245c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	 * Use the repair function to update the other copy of the GPT.  This
4255c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	 * is a tad inefficient, but is much faster than the disk I/O to update
4265c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	 * the GPT on disk so it doesn't matter.
4275c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	 */
4285c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	gpt->valid_headers = MASK_PRIMARY;
4295c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	gpt->valid_entries = MASK_PRIMARY;
4305c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	GptRepair(gpt);
4315c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk}
4325c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk
4335c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk
434cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spanglerconst char *GptErrorText(int error_code)
43565d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury{
436cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	switch(error_code) {
437cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_SUCCESS:
438cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "none";
43965d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
440cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_NO_VALID_KERNEL:
441cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Invalid kernel";
44265d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
443cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_INVALID_HEADERS:
444cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Invalid headers";
44565d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
446cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_INVALID_ENTRIES:
447cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Invalid entries";
44865d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
449cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_INVALID_SECTOR_SIZE:
450cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Invalid sector size";
45165d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
452cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_INVALID_SECTOR_NUMBER:
453cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Invalid sector number";
45465d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
455cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_INVALID_UPDATE_TYPE:
456cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Invalid update type";
45765d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
458cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_CRC_CORRUPTED:
459cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Entries' crc corrupted";
46065d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
461cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_OUT_OF_REGION:
462cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Entry outside of valid region";
46365d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
464cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_START_LBA_OVERLAP:
465cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Starting LBA overlaps";
46665d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
467cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_END_LBA_OVERLAP:
468cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Ending LBA overlaps";
46965d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
470cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	case GPT_ERROR_DUP_GUID:
471cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		return "Duplicated GUID";
47265d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury
4735c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	case GPT_ERROR_INVALID_FLASH_GEOMETRY:
4745c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk		return "Invalid flash geometry";
4755c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk
4765c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk	case GPT_ERROR_NO_SUCH_ENTRY:
4775c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk		return "No entry found";
4785c9e4532b9bc45cff22f37d3556da679809a60a7Albert Chaulk
479cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	default:
480cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler		break;
481cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	};
482cefe12c105a91e6ee9f44bca218bd6e4f89bcb71Randall Spangler	return "Unknown";
48365d3c277a2098d6149fb79f7881da5d78133ae57Vadim Bendebury}
484