source: mainline/uspace/lib/gpt/libgpt.c@ 9256d093

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9256d093 was 9bdfde73, checked in by Dominik Taborsky (AT DOT) <brembyseznamcz>, 12 years ago

libgpt improvements

  • Property mode set to 100644
File size: 19.7 KB
RevLine 
[cbd64057]1/*
[5beb1ff]2 * Copyright (c) 2011, 2012, 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:
36 * This implementation only supports fixed size partition entries. Specification
37 * requires otherwise, though. Use void * array and casting to achieve that.
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>
48#include <checksum.h>
[cbd64057]49#include <mem.h>
50
51#include "libgpt.h"
52
[1c8bfe8]53static int load_and_check_header(service_id_t handle, aoff64_t addr, size_t b_size, gpt_header_t *header);
[271e24a]54static gpt_partitions_t * alloc_part_array(uint32_t num);
[1c8bfe8]55static int extend_part_array(gpt_partitions_t *);
56static int reduce_part_array(gpt_partitions_t *);
[7570e800]57static long long nearest_larger_int(double a);
[1c8bfe8]58static uint8_t get_byte(const char *);
[9bdfde73]59static int check_overlap(gpt_part_t * p1, gpt_part_t * p2);
[44c4886]60
61/** Allocate memory for gpt label */
62gpt_label_t * gpt_alloc_label(void)
63{
64 gpt_label_t *label = malloc(sizeof(gpt_label_t));
65 if (label == NULL)
66 return NULL;
67
68 label->gpt = NULL;
69 label->parts = NULL;
70 label->device = 0;
71
72 return label;
73}
74
75/** Free gpt_label_t structure */
76void gpt_free_label(gpt_label_t *label)
77{
78 if (label->gpt != NULL)
79 gpt_free_gpt(label->gpt);
80
81 if (label->parts != NULL)
82 gpt_free_partitions(label->parts);
83
84 free(label);
85}
[7570e800]86
[700f89e]87/** Allocate memory for gpt header */
[44c4886]88gpt_t * gpt_alloc_header(size_t size)
[700f89e]89{
[44c4886]90 gpt_t *gpt = malloc(sizeof(gpt_t));
91 if (gpt == NULL)
92 return NULL;
93
94 // We might need only sizeof(gpt_header_t),
95 // but we should follow specs and have
96 // zeroes through all the rest of the block
97 size_t final_size = size > sizeof(gpt_header_t) ? size : sizeof(gpt_header_t);
98 gpt->header = malloc(final_size);
99 if (gpt->header == NULL) {
100 free(gpt);
101 return NULL;
102 }
103
104 memset(gpt->header, 0, final_size);
105
106 return gpt;
107}
108
109/** free() GPT header including gpt->header_lba */
110void gpt_free_gpt(gpt_t *gpt)
111{
112 free(gpt->header);
113 free(gpt);
[700f89e]114}
115
[cbd64057]116/** Read GPT from specific device
[44c4886]117 * @param label label structure to fill
118 * @param dev_handle device to read GPT from
[d617050]119 *
[44c4886]120 * @return EOK on success, errorcode on error
[cbd64057]121 */
[44c4886]122int gpt_read_header(gpt_label_t *label, service_id_t dev_handle)
[cbd64057]123{
124 int rc;
125 size_t b_size;
[8f6c7785]126
127 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
128 if (rc != EOK)
[44c4886]129 return rc;
[8f6c7785]130
[cbd64057]131 rc = block_get_bsize(dev_handle, &b_size);
[44c4886]132 if (rc != EOK)
133 return rc;
[8f6c7785]134
[44c4886]135 if (label->gpt == NULL) {
136 label->gpt = gpt_alloc_header(b_size);
137 if (label->gpt == NULL)
138 return ENOMEM;
[cbd64057]139 }
[8f6c7785]140
[44c4886]141 rc = load_and_check_header(dev_handle, GPT_HDR_BA, b_size, label->gpt->header);
[cbd64057]142 if (rc == EBADCHECKSUM || rc == EINVAL) {
143 aoff64_t n_blocks;
144 rc = block_get_nblocks(dev_handle, &n_blocks);
[44c4886]145 if (rc != EOK)
[cbd64057]146 goto fail;
[d617050]147
[44c4886]148 rc = load_and_check_header(dev_handle, n_blocks - 1, b_size, label->gpt->header);
149 if (rc == EBADCHECKSUM || rc == EINVAL)
[cbd64057]150 goto fail;
151 }
[8f6c7785]152
[44c4886]153 label->device = dev_handle;
[8f6c7785]154 block_fini(dev_handle);
[44c4886]155 return EOK;
[8f6c7785]156
[cbd64057]157fail:
[8f6c7785]158 block_fini(dev_handle);
[44c4886]159 gpt_free_gpt(label->gpt);
160 label->gpt = NULL;
161 return rc;
[cbd64057]162}
163
164/** Write GPT header to device
[44c4886]165 * @param label GPT label header to be written
166 * @param dev_handle device handle to write the data to
[d617050]167 *
[44c4886]168 * @return EOK on success, libblock error code otherwise
[d617050]169 *
[44c4886]170 * Note: Firstly write partitions (if modified), then gpt header.
[cbd64057]171 */
[44c4886]172int gpt_write_header(gpt_label_t *label, service_id_t dev_handle)
[cbd64057]173{
174 int rc;
175 size_t b_size;
[d617050]176
[44c4886]177 label->gpt->header->header_crc32 = 0;
178 label->gpt->header->header_crc32 = compute_crc32((uint8_t *) label->gpt->header,
179 uint32_t_le2host(label->gpt->header->header_size));
[d617050]180
[8f6c7785]181 rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
[1c8bfe8]182 if (rc != EOK && rc != EEXIST)
[cbd64057]183 return rc;
[d617050]184
[8f6c7785]185 rc = block_get_bsize(dev_handle, &b_size);
[cbd64057]186 if (rc != EOK)
187 return rc;
[d617050]188
[cbd64057]189 /* Write to main GPT header location */
[44c4886]190 rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header);
191 if (rc != EOK) {
[cbd64057]192 block_fini(dev_handle);
193 return rc;
[44c4886]194 }
[d617050]195
[cbd64057]196 aoff64_t n_blocks;
197 rc = block_get_nblocks(dev_handle, &n_blocks);
[44c4886]198 if (rc != EOK) {
199 block_fini(dev_handle);
[cbd64057]200 return rc;
[44c4886]201 }
[d617050]202
[cbd64057]203 /* Write to backup GPT header location */
[7570e800]204 //FIXME: those idiots thought it would be cool to have these fields in reverse order...
[44c4886]205 rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, label->gpt->header);
[cbd64057]206 block_fini(dev_handle);
207 if (rc != EOK)
208 return rc;
[d617050]209
[cbd64057]210 return 0;
211}
212
[700f89e]213/** Alloc partition array */
[44c4886]214gpt_partitions_t * gpt_alloc_partitions()
[700f89e]215{
216 return alloc_part_array(128);
217}
218
[cbd64057]219/** Parse partitions from GPT
[44c4886]220 * @param label GPT label to be parsed
[d617050]221 *
[44c4886]222 * @return EOK on success, errorcode otherwise
[cbd64057]223 */
[44c4886]224int gpt_read_partitions(gpt_label_t *label)
[cbd64057]225{
[7570e800]226 int rc;
227 unsigned int i;
[44c4886]228 uint32_t fill = uint32_t_le2host(label->gpt->header->fillries);
229 uint32_t ent_size = uint32_t_le2host(label->gpt->header->entry_size);
230 uint64_t ent_lba = uint64_t_le2host(label->gpt->header->entry_lba);
231
232 if (label->parts == NULL) {
233 label->parts = alloc_part_array(fill);
234 if (label->parts == NULL) {
235 return ENOMEM;
236 }
[cbd64057]237 }
[d617050]238
[cbd64057]239 /* We can limit comm_size like this:
240 * - we don't need more bytes
241 * - the size of GPT partition entry can be different to 128 bytes */
[44c4886]242 rc = block_init(EXCHANGE_SERIALIZE, label->device, sizeof(gpt_entry_t));
243 if (rc != EOK)
244 goto fail;
[d617050]245
[cbd64057]246 size_t block_size;
[44c4886]247 rc = block_get_bsize(label->device, &block_size);
248 if (rc != EOK)
249 goto fail;
[d617050]250
[cbd64057]251 //size_t bufpos = 0;
252 //size_t buflen = 0;
253 aoff64_t pos = ent_lba * block_size;
[d617050]254
[cbd64057]255 /* Now we read just sizeof(gpt_entry_t) bytes for each entry from the device.
256 * Hopefully, this does not bypass cache (no mention in libblock.c),
257 * and also allows us to have variable partition entry size (but we
258 * will always read just sizeof(gpt_entry_t) bytes - hopefully they
259 * don't break backward compatibility) */
[30440ed]260 for (i = 0; i < fill; ++i) {
[cbd64057]261 //FIXME: this does bypass cache...
[44c4886]262 rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t), label->parts->part_array + i);
[cbd64057]263 //FIXME: but seqread() is just too complex...
264 //rc = block_seqread(gpt->device, &bufpos, &buflen, &pos, res->part_array[i], sizeof(gpt_entry_t));
265 pos += ent_size;
[d617050]266
[44c4886]267 if (rc != EOK)
268 goto fail;
[cbd64057]269 }
[d617050]270
[7570e800]271 /* FIXME: so far my boasting about variable partition entry size
272 * will not work. The CRC32 checksums will be different.
273 * This can't be fixed easily - we'd have to run the checksum
274 * on all of the partition entry array.
275 */
[44c4886]276 uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array, label->parts->fill * sizeof(gpt_entry_t));
[d617050]277
[44c4886]278 if(uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc)
[cbd64057]279 {
[44c4886]280 rc = EBADCHECKSUM;
281 goto fail;
[cbd64057]282 }
[d617050]283
[44c4886]284 return EOK;
285
286fail:
287 gpt_free_partitions(label->parts);
288 label->parts = NULL;
289 return rc;
[cbd64057]290}
291
292/** Write GPT and partitions to device
[9bdfde73]293 * Note: also writes the header.
[44c4886]294 * @param label label to write
295 * @param dev_handle device to write the data to
[d617050]296 *
[44c4886]297 * @return returns EOK on succes, errorcode otherwise
[cbd64057]298 */
[44c4886]299int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle)
[cbd64057]300{
[7570e800]301 int rc;
[cbd64057]302 size_t b_size;
[44c4886]303 uint32_t e_size = uint32_t_le2host(label->gpt->header->entry_size);
[1c8bfe8]304 size_t fill = label->parts->fill > GPT_MIN_PART_NUM ? label->parts->fill : GPT_MIN_PART_NUM;
305
[44c4886]306 label->gpt->header->pe_array_crc32 = compute_crc32(
307 (uint8_t *) label->parts->part_array,
[1c8bfe8]308 fill * e_size);
[44c4886]309
310 /* comm_size of 4096 is ignored */
311 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);
[1c8bfe8]312 if (rc != EOK && rc != EEXIST)
[cbd64057]313 return rc;
[1c8bfe8]314
[8f6c7785]315 rc = block_get_bsize(dev_handle, &b_size);
[cbd64057]316 if (rc != EOK)
[44c4886]317 goto fail;
[1c8bfe8]318
[cbd64057]319 aoff64_t n_blocks;
320 rc = block_get_nblocks(dev_handle, &n_blocks);
321 if (rc != EOK)
[44c4886]322 goto fail;
[1c8bfe8]323
[cbd64057]324 /* Write to backup GPT partition array location */
325 //rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, header->raw_data);
326 if (rc != EOK)
[44c4886]327 goto fail;
[1c8bfe8]328
329 /* Write to main GPT partition array location */
330 rc = block_write_direct(dev_handle, uint64_t_le2host(label->gpt->header->entry_lba),
331 nearest_larger_int((uint64_t_le2host(label->gpt->header->entry_size) * label->parts->fill) / b_size),
332 label->parts->part_array);
333 if (rc != EOK)
334 goto fail;
335
[44c4886]336 return gpt_write_header(label, dev_handle);
337
338fail:
339 block_fini(dev_handle);
340 return rc;
[cbd64057]341}
342
[30440ed]343/** Alloc new partition
[d617050]344 *
[44c4886]345 * @return returns pointer to the new partition or NULL
[d617050]346 *
[44c4886]347 * Note: use either gpt_alloc_partition or gpt_get_partition.
348 * This returns a memory block (zero-filled) and needs gpt_add_partition()
349 * to be called to insert it into a partition array.
[1c8bfe8]350 * Requires you to call gpt_free_partition afterwards.
[44c4886]351 */
352gpt_part_t * gpt_alloc_partition(void)
353{
354 gpt_part_t *p = malloc(sizeof(gpt_part_t));
355 if (p == NULL)
356 return NULL;
357
358 memset(p, 0, sizeof(gpt_part_t));
359
360 return p;
361}
362
363/** Alloc new partition already inside the label
364 *
365 * @param label label to carry new partition
[d617050]366 *
[44c4886]367 * @return returns pointer to the new partition or NULL on ENOMEM
[d617050]368 *
[44c4886]369 * Note: use either gpt_alloc_partition or gpt_get_partition.
[1c8bfe8]370 * This one returns a pointer to the first empty structure already
371 * inside the array, so don't call gpt_add_partition() afterwards.
[44c4886]372 * This is the one you will usually want.
[30440ed]373 */
[44c4886]374gpt_part_t * gpt_get_partition(gpt_label_t *label)
[7570e800]375{
[1c8bfe8]376 gpt_part_t *p;
377
378 /* Find the first empty entry */
379 do {
380 if (label->parts->fill == label->parts->arr_size) {
381 if (extend_part_array(label->parts) == -1)
382 return NULL;
383 }
384
385 p = label->parts->part_array + label->parts->fill++;
386
387 } while (gpt_get_part_type(p) != GPT_PTE_UNUSED);
388
389 return p;
390}
[d617050]391
[1c8bfe8]392/** Get partition already inside the label
393 *
394 * @param label label to carrying the partition
395 * @param idx index of the partition
396 *
397 * @return returns pointer to the partition
398 * or NULL when out of range
399 *
400 * Note: For new partitions use either gpt_alloc_partition or
401 * gpt_get_partition unless you want a partition at a specific place.
402 * This returns a pointer to a structure already inside the array,
403 * so don't call gpt_add_partition() afterwards.
404 * This function is handy when you want to change already existing
405 * partition or to simply write somewhere in the middle. This works only
406 * for indexes smaller than either 128 or the actual number of filled
407 * entries.
408 */
409gpt_part_t * gpt_get_partition_at(gpt_label_t *label, size_t idx)
410{
411 return NULL;
412
413 if (idx >= GPT_MIN_PART_NUM && idx >= label->parts->fill)
414 return NULL;
415
416 return label->parts->part_array + idx;
[30440ed]417}
418
419/** Copy partition into partition array
[d617050]420 *
[44c4886]421 * @param parts target label
[30440ed]422 * @param partition source partition to copy
[d617050]423 *
[30440ed]424 * @return -1 on error, 0 otherwise
[d617050]425 *
[44c4886]426 * Note: for use with gpt_alloc_partition() only. You will get
427 * duplicates with gpt_get_partition().
[9bdfde73]428 * Note: does not call gpt_free_partition()!
[30440ed]429 */
[44c4886]430int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
[30440ed]431{
[44c4886]432 if (label->parts->fill == label->parts->arr_size) {
433 if (extend_part_array(label->parts) == -1)
[d617050]434 return ENOMEM;
[30440ed]435 }
[44c4886]436
[9bdfde73]437 /*FIXME:
438 * Check dimensions and stuff! */
439 gpt_part_foreach(label, p) {
440 if (gpt_get_part_type(p) != GPT_PTE_UNUSED) {
441 if (check_overlap(partition, p))
442 return EINVAL;
443 }
444 }
445
[44c4886]446 memcpy(label->parts->part_array + label->parts->fill++,
447 partition, sizeof(gpt_part_t));
448
[9bdfde73]449
450
[44c4886]451 return EOK;
[7570e800]452}
453
[30440ed]454/** Remove partition from array
[44c4886]455 * @param label label to remove from
456 * @param idx index of the partition to remove
[d617050]457 *
[44c4886]458 * @return EOK on success, ENOMEM on array reduction failure
[d617050]459 *
[30440ed]460 * Note: even if it fails, the partition still gets removed. Only
461 * reducing the array failed.
462 */
[44c4886]463int gpt_remove_partition(gpt_label_t *label, size_t idx)
[7570e800]464{
[1c8bfe8]465 if (idx >= label->parts->fill)
466 return EINVAL;
[44c4886]467
[1c8bfe8]468 /* FIXME!
469 * If we allow blank spots, we break the array. If we have more than
470 * 128 partitions in the array and then remove something from
471 * the first 128 partitions, we would forget to write the last one.*/
472 memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
473
474 label->parts->fill -= 1;
475
[9bdfde73]476 /* FIXME! HOPEFULLY FIXED.
[1c8bfe8]477 * We cannot reduce the array so simply. We may have some partitions
[9bdfde73]478 * there since we allow blank spots. */
479 gpt_part_t * p;
[44c4886]480 if (label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
[9bdfde73]481 for (p = gpt_get_partition_at(label, label->parts->arr_size / 2);
482 p < label->parts->part_array + label->parts->arr_size; ++p) {
483 if (gpt_get_part_type(p) != GPT_PTE_UNUSED)
484 return EOK;
485 }
486
[44c4886]487 if (reduce_part_array(label->parts) == ENOMEM)
488 return ENOMEM;
[30440ed]489 }
[d617050]490
[44c4886]491 return EOK;
[cbd64057]492}
493
494/** Free partition list
[d617050]495 *
[cbd64057]496 * @param parts partition list to be freed
497 */
[271e24a]498void gpt_free_partitions(gpt_partitions_t * parts)
[cbd64057]499{
500 free(parts->part_array);
501 free(parts);
502}
503
[30440ed]504/** Get partition type by linear search
505 * (hopefully this doesn't get slow)
506 */
507size_t gpt_get_part_type(gpt_part_t * p)
508{
509 size_t i;
[1c8bfe8]510
[30440ed]511 for (i = 0; gpt_ptypes[i].guid != NULL; i++) {
[1c8bfe8]512 if (p->part_type[3] == get_byte(gpt_ptypes[i].guid +0) &&
513 p->part_type[2] == get_byte(gpt_ptypes[i].guid +2) &&
514 p->part_type[1] == get_byte(gpt_ptypes[i].guid +4) &&
515 p->part_type[0] == get_byte(gpt_ptypes[i].guid +6) &&
516
517 p->part_type[5] == get_byte(gpt_ptypes[i].guid +8) &&
518 p->part_type[4] == get_byte(gpt_ptypes[i].guid +10) &&
519
520 p->part_type[7] == get_byte(gpt_ptypes[i].guid +12) &&
521 p->part_type[6] == get_byte(gpt_ptypes[i].guid +14) &&
522
523 p->part_type[8] == get_byte(gpt_ptypes[i].guid +16) &&
524 p->part_type[9] == get_byte(gpt_ptypes[i].guid +18) &&
525 p->part_type[10] == get_byte(gpt_ptypes[i].guid +20) &&
526 p->part_type[11] == get_byte(gpt_ptypes[i].guid +22) &&
527 p->part_type[12] == get_byte(gpt_ptypes[i].guid +24) &&
528 p->part_type[13] == get_byte(gpt_ptypes[i].guid +26) &&
529 p->part_type[14] == get_byte(gpt_ptypes[i].guid +28) &&
530 p->part_type[15] == get_byte(gpt_ptypes[i].guid +30))
531 break;
[30440ed]532 }
[1c8bfe8]533
[30440ed]534 return i;
535}
536
[cbd64057]537/** Set partition type
538 * @param p partition to be set
539 * @param type partition type to set
[d617050]540 * - see our fine selection at gpt_ptypes to choose from
[cbd64057]541 */
[d617050]542void gpt_set_part_type(gpt_part_t * p, size_t type)
[cbd64057]543{
544 /* Beware: first 3 blocks are byteswapped! */
[d617050]545 p->part_type[3] = gpt_ptypes[type].guid[0];
546 p->part_type[2] = gpt_ptypes[type].guid[1];
547 p->part_type[1] = gpt_ptypes[type].guid[2];
548 p->part_type[0] = gpt_ptypes[type].guid[3];
549
550 p->part_type[5] = gpt_ptypes[type].guid[4];
551 p->part_type[4] = gpt_ptypes[type].guid[5];
552
553 p->part_type[7] = gpt_ptypes[type].guid[6];
554 p->part_type[6] = gpt_ptypes[type].guid[7];
555
556 p->part_type[8] = gpt_ptypes[type].guid[8];
557 p->part_type[9] = gpt_ptypes[type].guid[9];
558 p->part_type[10] = gpt_ptypes[type].guid[10];
559 p->part_type[11] = gpt_ptypes[type].guid[11];
560 p->part_type[12] = gpt_ptypes[type].guid[12];
561 p->part_type[13] = gpt_ptypes[type].guid[13];
562 p->part_type[14] = gpt_ptypes[type].guid[14];
563 p->part_type[15] = gpt_ptypes[type].guid[15];
564}
565
566/** Get partition starting LBA */
567uint64_t gpt_get_start_lba(gpt_part_t * p)
568{
569 return uint64_t_le2host(p->start_lba);
570}
571
572/** Set partition starting LBA */
573void gpt_set_start_lba(gpt_part_t * p, uint64_t start)
574{
575 p->start_lba = host2uint64_t_le(start);
576}
577
578/** Get partition ending LBA */
579uint64_t gpt_get_end_lba(gpt_part_t * p)
580{
581 return uint64_t_le2host(p->end_lba);
[cbd64057]582}
583
[d617050]584/** Set partition ending LBA */
585void gpt_set_end_lba(gpt_part_t * p, uint64_t end)
[30440ed]586{
[d617050]587 p->end_lba = host2uint64_t_le(end);
588}
589
[44c4886]590/** Get partition name */
[d617050]591unsigned char * gpt_get_part_name(gpt_part_t * p)
592{
593 return p->part_name;
[30440ed]594}
595
[cbd64057]596/** Copy partition name */
[1c8bfe8]597void gpt_set_part_name(gpt_part_t *p, char *name, size_t length)
[cbd64057]598{
[30440ed]599 if (length >= 72)
600 length = 71;
[d617050]601
[cbd64057]602 memcpy(p->part_name, name, length);
[30440ed]603 p->part_name[length] = '\0';
604}
605
606/** Get partition attribute */
[d617050]607bool gpt_get_flag(gpt_part_t * p, GPT_ATTR flag)
[30440ed]608{
[d617050]609 return (p->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
[30440ed]610}
611
612/** Set partition attribute */
[d617050]613void gpt_set_flag(gpt_part_t * p, GPT_ATTR flag, bool value)
[30440ed]614{
[d617050]615 uint64_t attr = p->attributes;
[30440ed]616
617 if (value)
618 attr = attr | (((uint64_t) 1) << flag);
619 else
620 attr = attr ^ (attr & (((uint64_t) 1) << flag));
621
[d617050]622 p->attributes = attr;
[cbd64057]623}
624
625// Internal functions follow //
626
[7570e800]627static int load_and_check_header(service_id_t dev_handle, aoff64_t addr, size_t b_size, gpt_header_t * header)
[cbd64057]628{
[7570e800]629 int rc;
[d617050]630
[7570e800]631 rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header);
[cbd64057]632 if (rc != EOK)
633 return rc;
[d617050]634
[7570e800]635 unsigned int i;
[cbd64057]636 /* Check the EFI signature */
637 for (i = 0; i < 8; ++i) {
[7570e800]638 if (header->efi_signature[i] != efi_signature[i])
[cbd64057]639 return EINVAL;
640 }
[d617050]641
[cbd64057]642 /* Check the CRC32 of the header */
[7570e800]643 uint32_t crc = header->header_crc32;
644 header->header_crc32 = 0;
645 if (crc != compute_crc32((uint8_t *) header, header->header_size))
[cbd64057]646 return EBADCHECKSUM;
647 else
[7570e800]648 header->header_crc32 = crc;
[d617050]649
[cbd64057]650 /* Check for zeroes in the rest of the block */
651 for (i = sizeof(gpt_header_t); i < b_size; ++i) {
[7570e800]652 if (((uint8_t *) header)[i] != 0)
653 return EINVAL;
[cbd64057]654 }
[d617050]655
[cbd64057]656 return EOK;
657}
658
[271e24a]659static gpt_partitions_t * alloc_part_array(uint32_t num)
[cbd64057]660{
[271e24a]661 gpt_partitions_t * res = malloc(sizeof(gpt_partitions_t));
[cbd64057]662 if (res == NULL) {
663 errno = ENOMEM;
664 return NULL;
665 }
[d617050]666
[cbd64057]667 uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
668 res->part_array = malloc(size * sizeof(gpt_entry_t));
[7570e800]669 if (res->part_array == NULL) {
[cbd64057]670 free(res);
671 errno = ENOMEM;
672 return NULL;
673 }
[d617050]674
[30440ed]675 res->fill = num;
[cbd64057]676 res->arr_size = size;
[d617050]677
[cbd64057]678 return res;
679}
680
[271e24a]681static int extend_part_array(gpt_partitions_t * p)
[cbd64057]682{
683 unsigned int nsize = p->arr_size * 2;
684 gpt_entry_t * tmp = malloc(nsize * sizeof(gpt_entry_t));
685 if(tmp == NULL) {
686 errno = ENOMEM;
687 return -1;
688 }
[d617050]689
[30440ed]690 memcpy(tmp, p->part_array, p->fill);
[cbd64057]691 free(p->part_array);
692 p->part_array = tmp;
693 p->arr_size = nsize;
[d617050]694
[cbd64057]695 return 0;
696}
697
[271e24a]698static int reduce_part_array(gpt_partitions_t * p)
[cbd64057]699{
700 if(p->arr_size > GPT_MIN_PART_NUM) {
701 unsigned int nsize = p->arr_size / 2;
[44c4886]702 nsize = nsize > GPT_MIN_PART_NUM ? nsize : GPT_MIN_PART_NUM;
[cbd64057]703 gpt_entry_t * tmp = malloc(nsize * sizeof(gpt_entry_t));
[44c4886]704 if(tmp == NULL)
705 return ENOMEM;
[d617050]706
[30440ed]707 memcpy(tmp, p->part_array, p->fill < nsize ? p->fill : nsize);
[cbd64057]708 free(p->part_array);
709 p->part_array = tmp;
710 p->arr_size = nsize;
711 }
[d617050]712
[cbd64057]713 return 0;
714}
715
716//FIXME: replace this with a library call, if it exists
717static long long nearest_larger_int(double a)
718{
719 if ((long long) a == a) {
720 return (long long) a;
721 }
[d617050]722
[cbd64057]723 return ((long long) a) + 1;
724}
725
[1c8bfe8]726static uint8_t get_byte(const char * c)
[d617050]727{
[1c8bfe8]728 uint8_t val = 0;
729 char hex[3] = {*c, *(c+1), 0};
730
731 errno = str_uint8_t(hex, NULL, 16, false, &val);
732 return val;
[d617050]733}
734
[9bdfde73]735static int check_overlap(gpt_part_t * p1, gpt_part_t * p2)
736{
737 if (gpt_get_start_lba(p1) < gpt_get_start_lba(p2) && gpt_get_end_lba(p1) <= gpt_get_start_lba(p2)) {
738 return 0;
739 } else if (gpt_get_start_lba(p1) > gpt_get_start_lba(p2) && gpt_get_end_lba(p2) <= gpt_get_start_lba(p1)) {
740 return 0;
741 }
[cbd64057]742
[9bdfde73]743 return 1;
744}
[cbd64057]745
746
Note: See TracBrowser for help on using the repository browser.