blob: 5a3aeec7e07c00c7a668c738062a20cdabe75cad [file] [log] [blame]
Jay Srinivasana0581432012-01-26 21:50:05 -08001// Copyright (c) 2012 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#include "cgpt.h"
6
7#include <string.h>
8
9#include "cgptlib_internal.h"
10#include "cgpt_params.h"
11
Jay Srinivasan250549d2012-02-16 17:40:45 -080012// This is an internal helper function which assumes no NULL args are passed.
13// It sets the given attribute values for a single entry at the given index.
14static void set_entry_attributes(struct drive drive,
15 GptEntry *entry,
16 uint32_t index,
17 CgptAddParams *params) {
18 if (params->set_raw) {
19 entry->attrs.fields.gpt_att = params->raw_value;
20 } else {
21 if (params->set_successful)
22 SetSuccessful(&drive.gpt, PRIMARY, index, params->successful);
23 if (params->set_tries)
24 SetTries(&drive.gpt, PRIMARY, index, params->tries);
25 if (params->set_priority)
26 SetPriority(&drive.gpt, PRIMARY, index, params->priority);
27 }
28}
Jay Srinivasana0581432012-01-26 21:50:05 -080029
Jay Srinivasan250549d2012-02-16 17:40:45 -080030// Set the attributes such as is_successful, num_tries_left, priority, etc.
31// from the given values in params.
32int cgpt_set_attributes(CgptAddParams *params) {
Jay Srinivasana0581432012-01-26 21:50:05 -080033 struct drive drive;
34
35 int gpt_retval;
36 GptEntry *entry;
37 uint32_t index;
38
39 if (params == NULL)
40 return CGPT_FAILED;
41
Jay Srinivasan250549d2012-02-16 17:40:45 -080042 if (CGPT_OK != DriveOpen(params->drive_name, &drive))
Jay Srinivasana0581432012-01-26 21:50:05 -080043 return CGPT_FAILED;
44
45 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
46 Error("GptSanityCheck() returned %d: %s\n",
47 gpt_retval, GptError(gpt_retval));
Jay Srinivasan250549d2012-02-16 17:40:45 -080048 goto bad;
Jay Srinivasana0581432012-01-26 21:50:05 -080049 }
50
51 if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
52 ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
53 Error("one of the GPT header/entries is invalid.\n"
54 "please run 'cgpt repair' before adding anything.\n");
Jay Srinivasan250549d2012-02-16 17:40:45 -080055 goto bad;
56 }
57
58 if (params->partition == 0) {
59 Error("invalid partition number: %d\n", params->partition);
60 goto bad;
61 }
62
63 uint32_t max_part = GetNumberOfEntries(&drive.gpt);
64 if (params->partition > max_part) {
65 Error("invalid partition number: %d\n", params->partition);
66 goto bad;
67 }
68
69 index = params->partition - 1;
70 entry = GetEntry(&drive.gpt, PRIMARY, index);
71
72 set_entry_attributes(drive, entry, index, params);
73
74 RepairEntries(&drive.gpt, MASK_PRIMARY);
75 RepairHeader(&drive.gpt, MASK_PRIMARY);
76
77 drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
78 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
79 UpdateCrc(&drive.gpt);
80
81 // Write it all out.
82 return DriveClose(&drive, 1);
83
84bad:
85 DriveClose(&drive, 0);
86 return CGPT_FAILED;
87}
88
89// This method gets the partition details such as the attributes, the
90// guids of the partitions, etc. Input is the partition number or the
91// unique id of the partition. Output is populated in the respective
92// fields of params.
93int cgpt_get_partition_details(CgptAddParams *params) {
94 struct drive drive;
95
96 int gpt_retval;
97 GptEntry *entry;
98 uint32_t index;
99 int result = CGPT_FAILED;
100
101 if (params == NULL)
102 return result;
103
104 if (CGPT_OK != DriveOpen(params->drive_name, &drive)) {
105 Error("Unable to open drive: %s\n", params->drive_name);
106 return result;
107 }
108
109 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
110 Error("GptSanityCheck() returned %d: %s\n",
111 gpt_retval, GptError(gpt_retval));
112 goto bad;
113 }
114
115 if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
116 ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
117 Error("one of the GPT header/entries is invalid.\n"
118 "please run 'cgpt repair' before adding anything.\n");
119 goto bad;
120 }
121
122 uint32_t max_part = GetNumberOfEntries(&drive.gpt);
123
124 if (params->partition) {
125 if (params->partition > max_part) {
126 Error("invalid partition number: %d\n", params->partition);
127 goto bad;
128 }
129
130 // A valid partition number has been specified, so get the entry directly.
131 index = params->partition - 1;
132 entry = GetEntry(&drive.gpt, PRIMARY, index);
133 } else {
134 // Partition number is not specified, try looking up by the unique id.
135 if (!params->set_unique) {
136 Error("either partition or unique_id must be specified\n");
137 goto bad;
138 }
139
140 // A unique id is specified. find the entry that matches it.
141 for (index = 0; index < max_part; index++) {
142 entry = GetEntry(&drive.gpt, PRIMARY, index);
143 if (GuidEqual(&entry->unique, &params->unique_guid)) {
144 params->partition = index + 1;
145 break;
146 }
147 }
148
149 if (index >= max_part) {
150 Error("no partitions with the given unique id available\n");
151 goto bad;
152 }
153 }
154
155 // At this point, irrespective of whether a partition number is specified
156 // or a unique id is specified, we have valid non-null values for all these:
157 // index, entry, params->partition.
158
159 params->begin = entry->starting_lba;
160 params->size = entry->ending_lba - entry->starting_lba + 1;
161 memcpy(&params->type_guid, &entry->type, sizeof(Guid));
162 memcpy(&params->unique_guid, &entry->unique, sizeof(Guid));
163
164 params->raw_value = entry->attrs.fields.gpt_att;
165 params->successful = GetSuccessful(&drive.gpt, PRIMARY, index);
166 params->tries = GetTries(&drive.gpt, PRIMARY, index);
167 params->priority = GetPriority(&drive.gpt, PRIMARY, index);
168 result = CGPT_OK;
169
170bad:
171 DriveClose(&drive, 0);
172 return result;
173}
174
175
176int cgpt_add(CgptAddParams *params) {
177 struct drive drive;
178
179 int gpt_retval;
180 GptEntry *entry;
181 uint32_t index;
182
183 if (params == NULL)
Jay Srinivasana0581432012-01-26 21:50:05 -0800184 return CGPT_FAILED;
Jay Srinivasan250549d2012-02-16 17:40:45 -0800185
186 if (CGPT_OK != DriveOpen(params->drive_name, &drive))
187 return CGPT_FAILED;
188
189 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
190 Error("GptSanityCheck() returned %d: %s\n",
191 gpt_retval, GptError(gpt_retval));
192 goto bad;
193 }
194
195 if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
196 ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
197 Error("one of the GPT header/entries is invalid.\n"
198 "please run 'cgpt repair' before adding anything.\n");
199 goto bad;
Jay Srinivasana0581432012-01-26 21:50:05 -0800200 }
201
202 uint32_t max_part = GetNumberOfEntries(&drive.gpt);
203 if (params->partition) {
204 if (params->partition > max_part) {
205 Error("invalid partition number: %d\n", params->partition);
206 goto bad;
207 }
208 index = params->partition - 1;
209 entry = GetEntry(&drive.gpt, PRIMARY, index);
210 } else {
Jay Srinivasan250549d2012-02-16 17:40:45 -0800211 // Find next empty partition.
Jay Srinivasana0581432012-01-26 21:50:05 -0800212 for (index = 0; index < max_part; index++) {
213 entry = GetEntry(&drive.gpt, PRIMARY, index);
214 if (IsZero(&entry->type)) {
215 params->partition = index + 1;
216 break;
217 }
218 }
219 if (index >= max_part) {
220 Error("no unused partitions available\n");
221 goto bad;
222 }
223 }
224
225 // New partitions must specify type, begin, and size.
226 if (IsZero(&entry->type)) {
227 if (!params->set_begin || !params->set_size || !params->set_type) {
228 Error("-t, -b, and -s options are required for new partitions\n");
229 goto bad;
230 }
231 if (IsZero(&params->type_guid)) {
232 Error("New partitions must have a type other than \"unused\"\n");
233 goto bad;
234 }
235 if (!params->set_unique)
236 uuid_generate((uint8_t *)&entry->unique);
237 }
238
239 if (params->set_begin)
240 entry->starting_lba = params->begin;
241 if (params->set_size)
242 entry->ending_lba = params->begin + params->size - 1;
243 if (params->set_type)
244 memcpy(&entry->type, &params->type_guid, sizeof(Guid));
245 if (params->set_unique)
246 memcpy(&entry->unique, &params->unique_guid, sizeof(Guid));
247 if (params->label) {
248 if (CGPT_OK != UTF8ToUTF16((uint8_t *)params->label, entry->name,
249 sizeof(entry->name) / sizeof(entry->name[0]))) {
250 Error("The label cannot be converted to UTF16.\n");
251 goto bad;
252 }
253 }
Jay Srinivasan250549d2012-02-16 17:40:45 -0800254
255 set_entry_attributes(drive, entry, index, params);
Jay Srinivasana0581432012-01-26 21:50:05 -0800256
257 RepairEntries(&drive.gpt, MASK_PRIMARY);
258 RepairHeader(&drive.gpt, MASK_PRIMARY);
259
260 drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
261 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
262 UpdateCrc(&drive.gpt);
263
Jay Srinivasan250549d2012-02-16 17:40:45 -0800264 // Write it all out.
Jay Srinivasana0581432012-01-26 21:50:05 -0800265 return DriveClose(&drive, 1);
266
267bad:
Jay Srinivasan250549d2012-02-16 17:40:45 -0800268 DriveClose(&drive, 0);
Jay Srinivasana0581432012-01-26 21:50:05 -0800269 return CGPT_FAILED;
270}
Jay Srinivasan250549d2012-02-16 17:40:45 -0800271