source: mainline/uspace/lib/gpt/libgpt.c@ 80bee81

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 80bee81 was fc22069, checked in by Martin Decky <martin@…>, 10 years ago

block devices use the same interface, therefore the API of libblock should not expose the implementation details

  • Property mode set to 100644
File size: 22.5 KB
RevLine 
[cbd64057]1/*
[6453e306]2 * Copyright (c) 2011-2013 Dominik Taborsky
[cbd64057]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libgpt
30 * @{
31 */
32/** @file
33 */
34
35/* TODO:
[6453e306]36 * The implementation currently supports fixed size partition entries only.
37 * The specification requires otherwise, though.
[cbd64057]38 */
39
[7570e800]40#include <ipc/bd.h>
41#include <async.h>
42#include <stdio.h>
43#include <block.h>
[cbd64057]44#include <errno.h>
[7570e800]45#include <stdlib.h>
46#include <assert.h>
47#include <byteorder.h>
[6453e306]48#include <adt/checksum.h>
[cbd64057]49#include <mem.h>
[0435fe41]50#include <sys/typefmt.h>
[8c95dff]51#include <mbr.h>
[6453e306]52#include <align.h>
[cbd64057]53#include "libgpt.h"
54
[dc76f4a]55static int load_and_check_header(service_id_t, aoff64_t, size_t, gpt_header_t *);
[6453e306]56static gpt_partitions_t *alloc_part_array(uint32_t);
[1c8bfe8]57static int extend_part_array(gpt_partitions_t *);
58static int reduce_part_array(gpt_partitions_t *);
59static uint8_t get_byte(const char *);
[dc76f4a]60static bool check_overlap(gpt_part_t *, gpt_part_t *);
[2b55edb]61static bool check_encaps(gpt_part_t *, uint64_t, uint64_t);
[44c4886]62
[6453e306]63/** Allocate a GPT label */
64gpt_label_t *gpt_alloc_label(void)
[44c4886]65{
66 gpt_label_t *label = malloc(sizeof(gpt_label_t));
67 if (label == NULL)
68 return NULL;
69
[dc76f4a]70 label->parts = gpt_alloc_partitions();
[6453e306]71 if (label->parts == NULL) {
[dc76f4a]72 free(label);
73 return NULL;
74 }
75
[44c4886]76 label->gpt = NULL;
77 label->device = 0;
78
79 return label;
80}
81
[6453e306]82/** Free a GPT label */
[44c4886]83void gpt_free_label(gpt_label_t *label)
84{
85 if (label->gpt != NULL)
86 gpt_free_gpt(label->gpt);
87
88 if (label->parts != NULL)
89 gpt_free_partitions(label->parts);
90
91 free(label);
92}
[7570e800]93
[6453e306]94/** Allocate a GPT header */
95gpt_t *gpt_alloc_header(size_t size)
[700f89e]96{
[44c4886]97 gpt_t *gpt = malloc(sizeof(gpt_t));
98 if (gpt == NULL)
99 return NULL;
100
[6453e306]101 /*
102 * We might need only sizeof(gpt_header_t), but we should follow
[dc76f4a]103 * specs and have zeroes through all the rest of the block
104 */
[6453e306]105 size_t final_size = max(size, sizeof(gpt_header_t));
[44c4886]106 gpt->header = malloc(final_size);
107 if (gpt->header == NULL) {
108 free(gpt);
109 return NULL;
110 }
111
112 memset(gpt->header, 0, final_size);
[8c95dff]113 memcpy(gpt->header->efi_signature, efi_signature, 8);
114 memcpy(gpt->header->revision, revision, 4);
115 gpt->header->header_size = host2uint32_t_le(final_size);
116 gpt->header->entry_lba = host2uint64_t_le((uint64_t) 2);
117 gpt->header->entry_size = host2uint32_t_le(sizeof(gpt_entry_t));
118
[44c4886]119 return gpt;
120}
121
[6453e306]122/** Free a GPT header */
[44c4886]123void gpt_free_gpt(gpt_t *gpt)
124{
125 free(gpt->header);
126 free(gpt);
[700f89e]127}
128
[6453e306]129/** Read GPT from a device
130 *
131 * @param label Label to read.
132 * @param dev_handle Device to read GPT from.
133 *
134 * @return EOK on success, error code on error.
[d617050]135 *
[cbd64057]136 */
[44c4886]137int gpt_read_header(gpt_label_t *label, service_id_t dev_handle)
[cbd64057]138{
[fc22069]139 int rc = block_init(dev_handle, 512);
[8f6c7785]140 if (rc != EOK)
[6453e306]141 return rc;
[8f6c7785]142
[6453e306]143 size_t block_size;
144 rc = block_get_bsize(dev_handle, &block_size);
[44c4886]145 if (rc != EOK)
[6453e306]146 goto end;
[8f6c7785]147
[44c4886]148 if (label->gpt == NULL) {
[6453e306]149 label->gpt = gpt_alloc_header(block_size);
[8559fa0]150 if (label->gpt == NULL) {
151 rc = ENOMEM;
[6453e306]152 goto end;
[8559fa0]153 }
[cbd64057]154 }
[8f6c7785]155
[6453e306]156 rc = load_and_check_header(dev_handle, GPT_HDR_BA, block_size,
157 label->gpt->header);
158 if ((rc == EBADCHECKSUM) || (rc == EINVAL)) {
159 aoff64_t blocks;
160 rc = block_get_nblocks(dev_handle, &blocks);
161 if (rc != EOK) {
162 gpt_free_gpt(label->gpt);
163 goto end;
164 }
165
166 rc = load_and_check_header(dev_handle, blocks - 1, block_size,
167 label->gpt->header);
168 if ((rc == EBADCHECKSUM) || (rc == EINVAL)) {
169 gpt_free_gpt(label->gpt);
170 goto end;
171 }
[cbd64057]172 }
[8f6c7785]173
[44c4886]174 label->device = dev_handle;
[6453e306]175 rc = EOK;
[8f6c7785]176
[6453e306]177end:
[8559fa0]178 block_fini(dev_handle);
[44c4886]179 return rc;
[cbd64057]180}
181
182/** Write GPT header to device
[d617050]183 *
[6453e306]184 * @param label Label to be written.
185 * @param dev_handle Device to write the GPT to.
186 *
187 * @return EOK on success, libblock error code otherwise.
[d617050]188 *
[cbd64057]189 */
[44c4886]190int gpt_write_header(gpt_label_t *label, service_id_t dev_handle)
[cbd64057]191{
[dc76f4a]192 /* The comm_size argument (the last one) is ignored */
[fc22069]193 int rc = block_init(dev_handle, 4096);
[6453e306]194 if ((rc != EOK) && (rc != EEXIST))
[cbd64057]195 return rc;
[dc76f4a]196
[6453e306]197 size_t block_size;
198 rc = block_get_bsize(dev_handle, &block_size);
[cbd64057]199 if (rc != EOK)
[6453e306]200 goto end;
[dc76f4a]201
[6453e306]202 aoff64_t blocks;
203 rc = block_get_nblocks(dev_handle, &blocks);
204 if (rc != EOK)
205 goto end;
[dc76f4a]206
[8c95dff]207 gpt_set_random_uuid(label->gpt->header->disk_guid);
208
[dc76f4a]209 /* Prepare the backup header */
[6453e306]210 label->gpt->header->alternate_lba = label->gpt->header->current_lba;
211 label->gpt->header->current_lba = host2uint64_t_le(blocks - 1);
[dc76f4a]212
[6453e306]213 uint64_t lba = label->gpt->header->entry_lba;
214 label->gpt->header->entry_lba = host2uint64_t_le(blocks -
215 (uint32_t_le2host(label->gpt->header->fillries) *
216 sizeof(gpt_entry_t)) / block_size - 1);
[dc76f4a]217
218 label->gpt->header->header_crc32 = 0;
[6453e306]219 label->gpt->header->header_crc32 =
220 host2uint32_t_le(compute_crc32((uint8_t *) label->gpt->header,
221 uint32_t_le2host(label->gpt->header->header_size)));
[dc76f4a]222
[cbd64057]223 /* Write to backup GPT header location */
[6453e306]224 rc = block_write_direct(dev_handle, blocks - 1, GPT_HDR_BS,
225 label->gpt->header);
226 if (rc != EOK)
227 goto end;
[dc76f4a]228
229 /* Prepare the main header */
[6453e306]230 label->gpt->header->entry_lba = lba;
[dc76f4a]231
[6453e306]232 lba = label->gpt->header->alternate_lba;
233 label->gpt->header->alternate_lba = label->gpt->header->current_lba;
234 label->gpt->header->current_lba = lba;
[dc76f4a]235
236 label->gpt->header->header_crc32 = 0;
[6453e306]237 label->gpt->header->header_crc32 =
238 host2uint32_t_le(compute_crc32((uint8_t *) label->gpt->header,
239 uint32_t_le2host(label->gpt->header->header_size)));
[dc76f4a]240
241 /* Write to main GPT header location */
[6453e306]242 rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS,
243 label->gpt->header);
[cbd64057]244 if (rc != EOK)
[6453e306]245 goto end;
[dc76f4a]246
[8c95dff]247 /* Write Protective MBR */
248 br_block_t mbr;
249 memset(&mbr, 0, 512);
[6453e306]250
[8c95dff]251 memset(mbr.pte[0].first_chs, 1, 3);
252 mbr.pte[0].ptype = 0xEE;
[6453e306]253 memset(mbr.pte[0].last_chs, 0xff, 3);
[8c95dff]254 mbr.pte[0].first_lba = host2uint32_t_le(1);
[6453e306]255 mbr.pte[0].length = 0xffffffff;
[8c95dff]256 mbr.signature = host2uint16_t_le(BR_SIGNATURE);
257
258 rc = block_write_direct(dev_handle, 0, 1, &mbr);
[dc76f4a]259
[6453e306]260end:
261 block_fini(dev_handle);
262 return rc;
[cbd64057]263}
264
[700f89e]265/** Alloc partition array */
[6453e306]266gpt_partitions_t *gpt_alloc_partitions(void)
[700f89e]267{
[dc76f4a]268 return alloc_part_array(GPT_MIN_PART_NUM);
[700f89e]269}
270
[cbd64057]271/** Parse partitions from GPT
[d617050]272 *
[6453e306]273 * @param label GPT label to be parsed.
274 *
275 * @return EOK on success, error code otherwise.
276 *
[cbd64057]277 */
[44c4886]278int gpt_read_partitions(gpt_label_t *label)
[cbd64057]279{
[c3cbbb2]280 uint32_t fillries = uint32_t_le2host(label->gpt->header->fillries);
[44c4886]281 uint32_t ent_size = uint32_t_le2host(label->gpt->header->entry_size);
282 uint64_t ent_lba = uint64_t_le2host(label->gpt->header->entry_lba);
283
284 if (label->parts == NULL) {
[c3cbbb2]285 label->parts = alloc_part_array(fillries);
[6453e306]286 if (label->parts == NULL)
[44c4886]287 return ENOMEM;
[cbd64057]288 }
[6453e306]289
[fc22069]290 int rc = block_init(label->device, sizeof(gpt_entry_t));
[6453e306]291 if (rc != EOK) {
292 gpt_free_partitions(label->parts);
293 label->parts = NULL;
294 goto end;
295 }
296
[cbd64057]297 size_t block_size;
[44c4886]298 rc = block_get_bsize(label->device, &block_size);
[6453e306]299 if (rc != EOK) {
300 gpt_free_partitions(label->parts);
301 label->parts = NULL;
302 goto end;
303 }
304
[cbd64057]305 aoff64_t pos = ent_lba * block_size;
[6453e306]306
307 for (uint32_t i = 0; i < fillries; i++) {
308 rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t),
309 label->parts->part_array + i);
[cbd64057]310 pos += ent_size;
[6453e306]311
312 if (rc != EOK) {
313 gpt_free_partitions(label->parts);
314 label->parts = NULL;
315 goto end;
316 }
[cbd64057]317 }
[2b55edb]318
[6453e306]319 uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array,
320 fillries * ent_size);
321
322 if (uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc) {
[44c4886]323 rc = EBADCHECKSUM;
[6453e306]324 gpt_free_partitions(label->parts);
325 label->parts = NULL;
326 goto end;
[cbd64057]327 }
[8559fa0]328
[6453e306]329 rc = EOK;
[44c4886]330
[6453e306]331end:
[8559fa0]332 block_fini(label->device);
[44c4886]333 return rc;
[cbd64057]334}
335
336/** Write GPT and partitions to device
[d617050]337 *
[6453e306]338 * Note: Also writes the header.
339 *
340 * @param label Label to write.
341 * @param dev_handle Device to write the data to.
342 *
343 * @return EOK on succes, error code otherwise
344 *
[cbd64057]345 */
[44c4886]346int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle)
[cbd64057]347{
[44c4886]348 /* comm_size of 4096 is ignored */
[fc22069]349 int rc = block_init(dev_handle, 4096);
[6453e306]350 if ((rc != EOK) && (rc != EEXIST))
[cbd64057]351 return rc;
[1c8bfe8]352
[6453e306]353 size_t block_size;
354 rc = block_get_bsize(dev_handle, &block_size);
[cbd64057]355 if (rc != EOK)
[44c4886]356 goto fail;
[1c8bfe8]357
[6453e306]358 aoff64_t blocks;
359 rc = block_get_nblocks(dev_handle, &blocks);
[cbd64057]360 if (rc != EOK)
[44c4886]361 goto fail;
[1c8bfe8]362
[6453e306]363 if (label->gpt == NULL)
364 label->gpt = gpt_alloc_header(block_size);
[8c95dff]365
[6453e306]366 uint32_t entry_size =
367 uint32_t_le2host(label->gpt->header->entry_size);
368 size_t fillries = (label->parts->fill > GPT_MIN_PART_NUM) ?
369 label->parts->fill : GPT_MIN_PART_NUM;
[f4a47e52]370
[6453e306]371 if (entry_size != sizeof(gpt_entry_t))
[8c95dff]372 return ENOTSUP;
[6453e306]373
[2b55edb]374 label->gpt->header->fillries = host2uint32_t_le(fillries);
[6453e306]375
376 uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / block_size;
377
378 /* Include Protective MBR */
379 uint64_t gpt_space = arr_blocks + GPT_HDR_BS + 1;
380
[493b881]381 label->gpt->header->first_usable_lba = host2uint64_t_le(gpt_space);
[6453e306]382 label->gpt->header->last_usable_lba =
383 host2uint64_t_le(blocks - gpt_space - 1);
[f4a47e52]384
[2b55edb]385 /* Perform checks */
[0435fe41]386 gpt_part_foreach (label, p) {
[2b55edb]387 if (gpt_get_part_type(p) == GPT_PTE_UNUSED)
388 continue;
389
[6453e306]390 if (!check_encaps(p, blocks, gpt_space)) {
[2b55edb]391 rc = ERANGE;
392 goto fail;
393 }
394
[0435fe41]395 gpt_part_foreach (label, q) {
[2b55edb]396 if (p == q)
397 continue;
398
399 if (gpt_get_part_type(p) != GPT_PTE_UNUSED) {
400 if (check_overlap(p, q)) {
401 rc = ERANGE;
402 goto fail;
403 }
404 }
405 }
406 }
[f4a47e52]407
[6453e306]408 label->gpt->header->pe_array_crc32 =
409 host2uint32_t_le(compute_crc32((uint8_t *) label->parts->part_array,
410 fillries * entry_size));
[f4a47e52]411
[cbd64057]412 /* Write to backup GPT partition array location */
[6453e306]413 rc = block_write_direct(dev_handle, blocks - arr_blocks - 1,
414 arr_blocks, label->parts->part_array);
[cbd64057]415 if (rc != EOK)
[44c4886]416 goto fail;
[f4a47e52]417
[1c8bfe8]418 /* Write to main GPT partition array location */
[6453e306]419 rc = block_write_direct(dev_handle,
420 uint64_t_le2host(label->gpt->header->entry_lba),
421 arr_blocks, label->parts->part_array);
[1c8bfe8]422 if (rc != EOK)
423 goto fail;
[f4a47e52]424
[44c4886]425 return gpt_write_header(label, dev_handle);
426
427fail:
428 block_fini(dev_handle);
429 return rc;
[cbd64057]430}
431
[6453e306]432/** Allocate a new partition
[d617050]433 *
[6453e306]434 * Note: Use either gpt_alloc_partition() or gpt_get_partition().
[44c4886]435 * This returns a memory block (zero-filled) and needs gpt_add_partition()
436 * to be called to insert it into a partition array.
[1c8bfe8]437 * Requires you to call gpt_free_partition afterwards.
[6453e306]438 *
439 * @return Pointer to the new partition or NULL.
440 *
[44c4886]441 */
[6453e306]442gpt_part_t *gpt_alloc_partition(void)
[44c4886]443{
[6453e306]444 gpt_part_t *partition = malloc(sizeof(gpt_part_t));
445 if (partition == NULL)
[44c4886]446 return NULL;
447
[6453e306]448 memset(partition, 0, sizeof(gpt_part_t));
[44c4886]449
[6453e306]450 return partition;
[44c4886]451}
452
[6453e306]453/** Allocate a new partition already inside the label
[44c4886]454 *
[6453e306]455 * Note: Use either gpt_alloc_partition() or gpt_get_partition().
[1c8bfe8]456 * This one returns a pointer to the first empty structure already
457 * inside the array, so don't call gpt_add_partition() afterwards.
[44c4886]458 * This is the one you will usually want.
[6453e306]459 *
460 * @param label Label to carry new partition.
461 *
462 * @return Pointer to the new partition or NULL.
463 *
[30440ed]464 */
[6453e306]465gpt_part_t *gpt_get_partition(gpt_label_t *label)
[7570e800]466{
[6453e306]467 gpt_part_t *partition;
[c3cbbb2]468
[1c8bfe8]469 /* Find the first empty entry */
470 do {
471 if (label->parts->fill == label->parts->arr_size) {
472 if (extend_part_array(label->parts) == -1)
473 return NULL;
474 }
475
[6453e306]476 partition = label->parts->part_array + label->parts->fill++;
477 } while (gpt_get_part_type(partition) != GPT_PTE_UNUSED);
[1c8bfe8]478
[6453e306]479 return partition;
[1c8bfe8]480}
[d617050]481
[1c8bfe8]482/** Get partition already inside the label
483 *
[6453e306]484 * Note: For new partitions use either gpt_alloc_partition() or
485 * gpt_get_partition() unless you want a partition at a specific place.
[1c8bfe8]486 * This returns a pointer to a structure already inside the array,
487 * so don't call gpt_add_partition() afterwards.
488 * This function is handy when you want to change already existing
489 * partition or to simply write somewhere in the middle. This works only
490 * for indexes smaller than either 128 or the actual number of filled
491 * entries.
[6453e306]492 *
493 * @param label Label to carrying the partition.
494 * @param idx Index of the partition.
495 *
496 * @return Pointer to the partition or NULL when out of range.
497 *
[1c8bfe8]498 */
[6453e306]499gpt_part_t *gpt_get_partition_at(gpt_label_t *label, size_t idx)
[1c8bfe8]500{
[6453e306]501 if ((idx >= GPT_MIN_PART_NUM) && (idx >= label->parts->fill))
[1c8bfe8]502 return NULL;
503
504 return label->parts->part_array + idx;
[30440ed]505}
506
507/** Copy partition into partition array
[d617050]508 *
[6453e306]509 * Note: For use with gpt_alloc_partition() only. You will get
510 * duplicates with gpt_get_partition().
511 * Note: Does not call gpt_free_partition()!
[d617050]512 *
[6453e306]513 * @param parts Target label
514 * @param partition Source partition to copy
515 *
516 * @return EOK on succes, error code otherwise
[d617050]517 *
[30440ed]518 */
[44c4886]519int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
[30440ed]520{
[dc76f4a]521 /* Find the first empty entry */
[6453e306]522
523 gpt_part_t *part;
524
[dc76f4a]525 do {
526 if (label->parts->fill == label->parts->arr_size) {
527 if (extend_part_array(label->parts) == -1)
528 return ENOMEM;
529 }
530
[6453e306]531 part = label->parts->part_array + label->parts->fill++;
532 } while (gpt_get_part_type(part) != GPT_PTE_UNUSED);
[9bdfde73]533
[6453e306]534 memcpy(part, partition, sizeof(gpt_entry_t));
[44c4886]535 return EOK;
[7570e800]536}
537
[30440ed]538/** Remove partition from array
[d617050]539 *
[6453e306]540 * Note: Even if it fails, the partition still gets removed. Only
[30440ed]541 * reducing the array failed.
[6453e306]542 *
543 * @param label Label to remove from
544 * @param idx Index of the partition to remove
545 *
546 * @return EOK on success, ENOMEM on array reduction failure
547 *
[30440ed]548 */
[44c4886]549int gpt_remove_partition(gpt_label_t *label, size_t idx)
[7570e800]550{
[dc76f4a]551 if (idx >= label->parts->arr_size)
[1c8bfe8]552 return EINVAL;
[44c4886]553
[6453e306]554 /*
555 * FIXME:
[1c8bfe8]556 * If we allow blank spots, we break the array. If we have more than
557 * 128 partitions in the array and then remove something from
[dc76f4a]558 * the first 128 partitions, we would forget to write the last one.
559 */
[6453e306]560
[1c8bfe8]561 memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
562
[dc76f4a]563 if (label->parts->fill > idx)
564 label->parts->fill = idx;
[1c8bfe8]565
[6453e306]566 gpt_part_t *partition;
567
568 if ((label->parts->fill > GPT_MIN_PART_NUM) &&
569 (label->parts->fill < (label->parts->arr_size / 2) -
570 GPT_IGNORE_FILL_NUM)) {
571 for (partition = gpt_get_partition_at(label, label->parts->arr_size / 2);
572 partition < label->parts->part_array + label->parts->arr_size;
573 partition++) {
574 if (gpt_get_part_type(partition) != GPT_PTE_UNUSED)
575 return EOK;
[9bdfde73]576 }
577
[44c4886]578 if (reduce_part_array(label->parts) == ENOMEM)
579 return ENOMEM;
[30440ed]580 }
[6453e306]581
[44c4886]582 return EOK;
[cbd64057]583}
584
585/** Free partition list
[d617050]586 *
[6453e306]587 * @param parts Partition list to be freed
588 *
[cbd64057]589 */
[6453e306]590void gpt_free_partitions(gpt_partitions_t *parts)
[cbd64057]591{
592 free(parts->part_array);
593 free(parts);
594}
595
[6453e306]596/** Get partition type */
597size_t gpt_get_part_type(gpt_part_t *partition)
[30440ed]598{
599 size_t i;
[1c8bfe8]600
[30440ed]601 for (i = 0; gpt_ptypes[i].guid != NULL; i++) {
[6453e306]602 if ((partition->part_type[3] == get_byte(gpt_ptypes[i].guid + 0)) &&
603 (partition->part_type[2] == get_byte(gpt_ptypes[i].guid + 2)) &&
604 (partition->part_type[1] == get_byte(gpt_ptypes[i].guid + 4)) &&
605 (partition->part_type[0] == get_byte(gpt_ptypes[i].guid + 6)) &&
606 (partition->part_type[5] == get_byte(gpt_ptypes[i].guid + 8)) &&
607 (partition->part_type[4] == get_byte(gpt_ptypes[i].guid + 10)) &&
608 (partition->part_type[7] == get_byte(gpt_ptypes[i].guid + 12)) &&
609 (partition->part_type[6] == get_byte(gpt_ptypes[i].guid + 14)) &&
610 (partition->part_type[8] == get_byte(gpt_ptypes[i].guid + 16)) &&
611 (partition->part_type[9] == get_byte(gpt_ptypes[i].guid + 18)) &&
612 (partition->part_type[10] == get_byte(gpt_ptypes[i].guid + 20)) &&
613 (partition->part_type[11] == get_byte(gpt_ptypes[i].guid + 22)) &&
614 (partition->part_type[12] == get_byte(gpt_ptypes[i].guid + 24)) &&
615 (partition->part_type[13] == get_byte(gpt_ptypes[i].guid + 26)) &&
616 (partition->part_type[14] == get_byte(gpt_ptypes[i].guid + 28)) &&
617 (partition->part_type[15] == get_byte(gpt_ptypes[i].guid + 30)))
618 return i;
[30440ed]619 }
[1c8bfe8]620
[30440ed]621 return i;
622}
623
[6453e306]624/** Set partition type */
625void gpt_set_part_type(gpt_part_t *partition, size_t type)
[cbd64057]626{
627 /* Beware: first 3 blocks are byteswapped! */
[6453e306]628 partition->part_type[3] = get_byte(gpt_ptypes[type].guid + 0);
629 partition->part_type[2] = get_byte(gpt_ptypes[type].guid + 2);
630 partition->part_type[1] = get_byte(gpt_ptypes[type].guid + 4);
631 partition->part_type[0] = get_byte(gpt_ptypes[type].guid + 6);
632
633 partition->part_type[5] = get_byte(gpt_ptypes[type].guid + 8);
634 partition->part_type[4] = get_byte(gpt_ptypes[type].guid + 10);
635
636 partition->part_type[7] = get_byte(gpt_ptypes[type].guid + 12);
637 partition->part_type[6] = get_byte(gpt_ptypes[type].guid + 14);
638
639 partition->part_type[8] = get_byte(gpt_ptypes[type].guid + 16);
640 partition->part_type[9] = get_byte(gpt_ptypes[type].guid + 18);
641 partition->part_type[10] = get_byte(gpt_ptypes[type].guid + 20);
642 partition->part_type[11] = get_byte(gpt_ptypes[type].guid + 22);
643 partition->part_type[12] = get_byte(gpt_ptypes[type].guid + 24);
644 partition->part_type[13] = get_byte(gpt_ptypes[type].guid + 26);
645 partition->part_type[14] = get_byte(gpt_ptypes[type].guid + 28);
646 partition->part_type[15] = get_byte(gpt_ptypes[type].guid + 30);
[d617050]647}
648
649/** Get partition starting LBA */
[6453e306]650uint64_t gpt_get_start_lba(gpt_part_t *partition)
[d617050]651{
[6453e306]652 return uint64_t_le2host(partition->start_lba);
[d617050]653}
654
655/** Set partition starting LBA */
[6453e306]656void gpt_set_start_lba(gpt_part_t *partition, uint64_t start)
[d617050]657{
[6453e306]658 partition->start_lba = host2uint64_t_le(start);
[d617050]659}
660
661/** Get partition ending LBA */
[6453e306]662uint64_t gpt_get_end_lba(gpt_part_t *partition)
[d617050]663{
[6453e306]664 return uint64_t_le2host(partition->end_lba);
[cbd64057]665}
666
[d617050]667/** Set partition ending LBA */
[6453e306]668void gpt_set_end_lba(gpt_part_t *partition, uint64_t end)
[30440ed]669{
[6453e306]670 partition->end_lba = host2uint64_t_le(end);
[d617050]671}
672
[44c4886]673/** Get partition name */
[6453e306]674unsigned char * gpt_get_part_name(gpt_part_t *partition)
[d617050]675{
[6453e306]676 return partition->part_name;
[30440ed]677}
678
[cbd64057]679/** Copy partition name */
[6453e306]680void gpt_set_part_name(gpt_part_t *partition, char *name, size_t length)
[cbd64057]681{
[30440ed]682 if (length >= 72)
683 length = 71;
[6453e306]684
685 memcpy(partition->part_name, name, length);
686 partition->part_name[length] = '\0';
[30440ed]687}
688
689/** Get partition attribute */
[6453e306]690bool gpt_get_flag(gpt_part_t *partition, gpt_attr_t flag)
[30440ed]691{
[6453e306]692 return (partition->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
[30440ed]693}
694
695/** Set partition attribute */
[6453e306]696void gpt_set_flag(gpt_part_t *partition, gpt_attr_t flag, bool value)
[30440ed]697{
[6453e306]698 uint64_t attr = partition->attributes;
699
[30440ed]700 if (value)
701 attr = attr | (((uint64_t) 1) << flag);
702 else
703 attr = attr ^ (attr & (((uint64_t) 1) << flag));
[6453e306]704
705 partition->attributes = attr;
[cbd64057]706}
707
[8cffdf5]708/** Generate a new pseudo-random UUID compliant with RFC 4122 */
[6453e306]709void gpt_set_random_uuid(uint8_t *uuid)
[c3cbbb2]710{
[0435fe41]711 srandom((unsigned int) (size_t) uuid);
[c3cbbb2]712
[6453e306]713 for (size_t i = 0; i < 16; i++)
714 uuid[i] = random();
[8cffdf5]715
716 /*
717 * Set version (stored in bits 4-7 of seventh byte) to 4 (random
718 * UUID) and bits 6 and 7 of ninth byte to 0 and 1 respectively -
719 * according to RFC 4122, section 4.4.
720 */
721 uuid[6] &= 0x0f;
722 uuid[6] |= (0x4 << 4);
723 uuid[8] &= 0x3f;
724 uuid[8] |= (1 << 7);
[c3cbbb2]725}
726
[dc76f4a]727/** Get next aligned address */
728uint64_t gpt_get_next_aligned(uint64_t addr, unsigned int alignment)
729{
[6453e306]730 return ALIGN_UP(addr + 1, alignment);
[dc76f4a]731}
732
[6453e306]733static int load_and_check_header(service_id_t dev_handle, aoff64_t addr,
734 size_t block_size, gpt_header_t *header)
[cbd64057]735{
[6453e306]736 int rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header);
[cbd64057]737 if (rc != EOK)
738 return rc;
[6453e306]739
[cbd64057]740 /* Check the EFI signature */
[6453e306]741 for (unsigned int i = 0; i < 8; i++) {
[7570e800]742 if (header->efi_signature[i] != efi_signature[i])
[cbd64057]743 return EINVAL;
744 }
[6453e306]745
[cbd64057]746 /* Check the CRC32 of the header */
[7570e800]747 uint32_t crc = header->header_crc32;
748 header->header_crc32 = 0;
[6453e306]749
[7570e800]750 if (crc != compute_crc32((uint8_t *) header, header->header_size))
[cbd64057]751 return EBADCHECKSUM;
752 else
[7570e800]753 header->header_crc32 = crc;
[6453e306]754
[cbd64057]755 /* Check for zeroes in the rest of the block */
[6453e306]756 for (size_t i = sizeof(gpt_header_t); i < block_size; i++) {
[7570e800]757 if (((uint8_t *) header)[i] != 0)
758 return EINVAL;
[cbd64057]759 }
[6453e306]760
[cbd64057]761 return EOK;
762}
763
[6453e306]764static gpt_partitions_t *alloc_part_array(uint32_t num)
[cbd64057]765{
[6453e306]766 gpt_partitions_t *res = malloc(sizeof(gpt_partitions_t));
767 if (res == NULL)
[cbd64057]768 return NULL;
[dc76f4a]769
[cbd64057]770 uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
771 res->part_array = malloc(size * sizeof(gpt_entry_t));
[7570e800]772 if (res->part_array == NULL) {
[cbd64057]773 free(res);
774 return NULL;
775 }
[dc76f4a]776
777 memset(res->part_array, 0, size * sizeof(gpt_entry_t));
778
[c3cbbb2]779 res->fill = 0;
780 res->arr_size = num;
[6453e306]781
[cbd64057]782 return res;
783}
784
[6453e306]785static int extend_part_array(gpt_partitions_t *partition)
[cbd64057]786{
[6453e306]787 size_t nsize = partition->arr_size * 2;
788 gpt_entry_t *entry = malloc(nsize * sizeof(gpt_entry_t));
789 if (entry == NULL)
790 return ENOMEM;
[c3cbbb2]791
[6453e306]792 memcpy(entry, partition->part_array, partition->fill *
793 sizeof(gpt_entry_t));
794 free(partition->part_array);
795
796 partition->part_array = entry;
797 partition->arr_size = nsize;
798
799 return EOK;
[cbd64057]800}
801
[6453e306]802static int reduce_part_array(gpt_partitions_t *partition)
[cbd64057]803{
[6453e306]804 if (partition->arr_size > GPT_MIN_PART_NUM) {
805 unsigned int nsize = partition->arr_size / 2;
[44c4886]806 nsize = nsize > GPT_MIN_PART_NUM ? nsize : GPT_MIN_PART_NUM;
[6453e306]807
808 gpt_entry_t *entry = malloc(nsize * sizeof(gpt_entry_t));
809 if (entry == NULL)
[44c4886]810 return ENOMEM;
[6453e306]811
812 memcpy(entry, partition->part_array,
813 partition->fill < nsize ? partition->fill : nsize);
814 free(partition->part_array);
815
816 partition->part_array = entry;
817 partition->arr_size = nsize;
[cbd64057]818 }
[6453e306]819
820 return EOK;
[cbd64057]821}
822
[6453e306]823/* Parse a byte from a string in hexadecimal */
824static uint8_t get_byte(const char *c)
[d617050]825{
[1c8bfe8]826 uint8_t val = 0;
[6453e306]827 char hex[3] = {*c, *(c + 1), 0};
[1c8bfe8]828
[6453e306]829 str_uint8_t(hex, NULL, 16, false, &val);
[1c8bfe8]830 return val;
[d617050]831}
832
[6453e306]833static bool check_overlap(gpt_part_t *part1, gpt_part_t *part2)
[9bdfde73]834{
[6453e306]835 if ((gpt_get_start_lba(part1) < gpt_get_start_lba(part2)) &&
836 (gpt_get_end_lba(part1) < gpt_get_start_lba(part2)))
[dc76f4a]837 return false;
[6453e306]838
839 if ((gpt_get_start_lba(part1) > gpt_get_start_lba(part2)) &&
840 (gpt_get_end_lba(part2) < gpt_get_start_lba(part1)))
[dc76f4a]841 return false;
[6453e306]842
[dc76f4a]843 return true;
[9bdfde73]844}
[cbd64057]845
[6453e306]846static bool check_encaps(gpt_part_t *part, uint64_t blocks,
847 uint64_t first_lba)
[2b55edb]848{
[6453e306]849 /*
850 * We allow "<=" in the second expression because it lacks
851 * MBR so it is smaller by 1 block.
[493b881]852 */
[6453e306]853 if ((gpt_get_start_lba(part) >= first_lba) &&
854 (gpt_get_end_lba(part) <= blocks - first_lba))
[2b55edb]855 return true;
856
857 return false;
858}
Note: See TracBrowser for help on using the repository browser.