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
Line 
1/*
2 * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
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
40#include <ipc/bd.h>
41#include <async.h>
42#include <stdio.h>
43#include <block.h>
44#include <errno.h>
45#include <stdlib.h>
46#include <assert.h>
47#include <byteorder.h>
48#include <checksum.h>
49#include <mem.h>
50
51#include "libgpt.h"
52
53static int load_and_check_header(service_id_t handle, aoff64_t addr, size_t b_size, gpt_header_t *header);
54static gpt_partitions_t * alloc_part_array(uint32_t num);
55static int extend_part_array(gpt_partitions_t *);
56static int reduce_part_array(gpt_partitions_t *);
57static long long nearest_larger_int(double a);
58static uint8_t get_byte(const char *);
59static int check_overlap(gpt_part_t * p1, gpt_part_t * p2);
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}
86
87/** Allocate memory for gpt header */
88gpt_t * gpt_alloc_header(size_t size)
89{
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);
114}
115
116/** Read GPT from specific device
117 * @param label label structure to fill
118 * @param dev_handle device to read GPT from
119 *
120 * @return EOK on success, errorcode on error
121 */
122int gpt_read_header(gpt_label_t *label, service_id_t dev_handle)
123{
124 int rc;
125 size_t b_size;
126
127 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
128 if (rc != EOK)
129 return rc;
130
131 rc = block_get_bsize(dev_handle, &b_size);
132 if (rc != EOK)
133 return rc;
134
135 if (label->gpt == NULL) {
136 label->gpt = gpt_alloc_header(b_size);
137 if (label->gpt == NULL)
138 return ENOMEM;
139 }
140
141 rc = load_and_check_header(dev_handle, GPT_HDR_BA, b_size, label->gpt->header);
142 if (rc == EBADCHECKSUM || rc == EINVAL) {
143 aoff64_t n_blocks;
144 rc = block_get_nblocks(dev_handle, &n_blocks);
145 if (rc != EOK)
146 goto fail;
147
148 rc = load_and_check_header(dev_handle, n_blocks - 1, b_size, label->gpt->header);
149 if (rc == EBADCHECKSUM || rc == EINVAL)
150 goto fail;
151 }
152
153 label->device = dev_handle;
154 block_fini(dev_handle);
155 return EOK;
156
157fail:
158 block_fini(dev_handle);
159 gpt_free_gpt(label->gpt);
160 label->gpt = NULL;
161 return rc;
162}
163
164/** Write GPT header to device
165 * @param label GPT label header to be written
166 * @param dev_handle device handle to write the data to
167 *
168 * @return EOK on success, libblock error code otherwise
169 *
170 * Note: Firstly write partitions (if modified), then gpt header.
171 */
172int gpt_write_header(gpt_label_t *label, service_id_t dev_handle)
173{
174 int rc;
175 size_t b_size;
176
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));
180
181 rc = block_init(EXCHANGE_ATOMIC, dev_handle, b_size);
182 if (rc != EOK && rc != EEXIST)
183 return rc;
184
185 rc = block_get_bsize(dev_handle, &b_size);
186 if (rc != EOK)
187 return rc;
188
189 /* Write to main GPT header location */
190 rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS, label->gpt->header);
191 if (rc != EOK) {
192 block_fini(dev_handle);
193 return rc;
194 }
195
196 aoff64_t n_blocks;
197 rc = block_get_nblocks(dev_handle, &n_blocks);
198 if (rc != EOK) {
199 block_fini(dev_handle);
200 return rc;
201 }
202
203 /* Write to backup GPT header location */
204 //FIXME: those idiots thought it would be cool to have these fields in reverse order...
205 rc = block_write_direct(dev_handle, n_blocks - 1, GPT_HDR_BS, label->gpt->header);
206 block_fini(dev_handle);
207 if (rc != EOK)
208 return rc;
209
210 return 0;
211}
212
213/** Alloc partition array */
214gpt_partitions_t * gpt_alloc_partitions()
215{
216 return alloc_part_array(128);
217}
218
219/** Parse partitions from GPT
220 * @param label GPT label to be parsed
221 *
222 * @return EOK on success, errorcode otherwise
223 */
224int gpt_read_partitions(gpt_label_t *label)
225{
226 int rc;
227 unsigned int i;
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 }
237 }
238
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 */
242 rc = block_init(EXCHANGE_SERIALIZE, label->device, sizeof(gpt_entry_t));
243 if (rc != EOK)
244 goto fail;
245
246 size_t block_size;
247 rc = block_get_bsize(label->device, &block_size);
248 if (rc != EOK)
249 goto fail;
250
251 //size_t bufpos = 0;
252 //size_t buflen = 0;
253 aoff64_t pos = ent_lba * block_size;
254
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) */
260 for (i = 0; i < fill; ++i) {
261 //FIXME: this does bypass cache...
262 rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t), label->parts->part_array + i);
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;
266
267 if (rc != EOK)
268 goto fail;
269 }
270
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 */
276 uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array, label->parts->fill * sizeof(gpt_entry_t));
277
278 if(uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc)
279 {
280 rc = EBADCHECKSUM;
281 goto fail;
282 }
283
284 return EOK;
285
286fail:
287 gpt_free_partitions(label->parts);
288 label->parts = NULL;
289 return rc;
290}
291
292/** Write GPT and partitions to device
293 * Note: also writes the header.
294 * @param label label to write
295 * @param dev_handle device to write the data to
296 *
297 * @return returns EOK on succes, errorcode otherwise
298 */
299int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle)
300{
301 int rc;
302 size_t b_size;
303 uint32_t e_size = uint32_t_le2host(label->gpt->header->entry_size);
304 size_t fill = label->parts->fill > GPT_MIN_PART_NUM ? label->parts->fill : GPT_MIN_PART_NUM;
305
306 label->gpt->header->pe_array_crc32 = compute_crc32(
307 (uint8_t *) label->parts->part_array,
308 fill * e_size);
309
310 /* comm_size of 4096 is ignored */
311 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);
312 if (rc != EOK && rc != EEXIST)
313 return rc;
314
315 rc = block_get_bsize(dev_handle, &b_size);
316 if (rc != EOK)
317 goto fail;
318
319 aoff64_t n_blocks;
320 rc = block_get_nblocks(dev_handle, &n_blocks);
321 if (rc != EOK)
322 goto fail;
323
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)
327 goto fail;
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
336 return gpt_write_header(label, dev_handle);
337
338fail:
339 block_fini(dev_handle);
340 return rc;
341}
342
343/** Alloc new partition
344 *
345 * @return returns pointer to the new partition or NULL
346 *
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.
350 * Requires you to call gpt_free_partition afterwards.
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
366 *
367 * @return returns pointer to the new partition or NULL on ENOMEM
368 *
369 * Note: use either gpt_alloc_partition or gpt_get_partition.
370 * This one returns a pointer to the first empty structure already
371 * inside the array, so don't call gpt_add_partition() afterwards.
372 * This is the one you will usually want.
373 */
374gpt_part_t * gpt_get_partition(gpt_label_t *label)
375{
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}
391
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;
417}
418
419/** Copy partition into partition array
420 *
421 * @param parts target label
422 * @param partition source partition to copy
423 *
424 * @return -1 on error, 0 otherwise
425 *
426 * Note: for use with gpt_alloc_partition() only. You will get
427 * duplicates with gpt_get_partition().
428 * Note: does not call gpt_free_partition()!
429 */
430int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
431{
432 if (label->parts->fill == label->parts->arr_size) {
433 if (extend_part_array(label->parts) == -1)
434 return ENOMEM;
435 }
436
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
446 memcpy(label->parts->part_array + label->parts->fill++,
447 partition, sizeof(gpt_part_t));
448
449
450
451 return EOK;
452}
453
454/** Remove partition from array
455 * @param label label to remove from
456 * @param idx index of the partition to remove
457 *
458 * @return EOK on success, ENOMEM on array reduction failure
459 *
460 * Note: even if it fails, the partition still gets removed. Only
461 * reducing the array failed.
462 */
463int gpt_remove_partition(gpt_label_t *label, size_t idx)
464{
465 if (idx >= label->parts->fill)
466 return EINVAL;
467
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
476 /* FIXME! HOPEFULLY FIXED.
477 * We cannot reduce the array so simply. We may have some partitions
478 * there since we allow blank spots. */
479 gpt_part_t * p;
480 if (label->parts->fill < (label->parts->arr_size / 2) - GPT_IGNORE_FILL_NUM) {
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
487 if (reduce_part_array(label->parts) == ENOMEM)
488 return ENOMEM;
489 }
490
491 return EOK;
492}
493
494/** Free partition list
495 *
496 * @param parts partition list to be freed
497 */
498void gpt_free_partitions(gpt_partitions_t * parts)
499{
500 free(parts->part_array);
501 free(parts);
502}
503
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;
510
511 for (i = 0; gpt_ptypes[i].guid != NULL; i++) {
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;
532 }
533
534 return i;
535}
536
537/** Set partition type
538 * @param p partition to be set
539 * @param type partition type to set
540 * - see our fine selection at gpt_ptypes to choose from
541 */
542void gpt_set_part_type(gpt_part_t * p, size_t type)
543{
544 /* Beware: first 3 blocks are byteswapped! */
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);
582}
583
584/** Set partition ending LBA */
585void gpt_set_end_lba(gpt_part_t * p, uint64_t end)
586{
587 p->end_lba = host2uint64_t_le(end);
588}
589
590/** Get partition name */
591unsigned char * gpt_get_part_name(gpt_part_t * p)
592{
593 return p->part_name;
594}
595
596/** Copy partition name */
597void gpt_set_part_name(gpt_part_t *p, char *name, size_t length)
598{
599 if (length >= 72)
600 length = 71;
601
602 memcpy(p->part_name, name, length);
603 p->part_name[length] = '\0';
604}
605
606/** Get partition attribute */
607bool gpt_get_flag(gpt_part_t * p, GPT_ATTR flag)
608{
609 return (p->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
610}
611
612/** Set partition attribute */
613void gpt_set_flag(gpt_part_t * p, GPT_ATTR flag, bool value)
614{
615 uint64_t attr = p->attributes;
616
617 if (value)
618 attr = attr | (((uint64_t) 1) << flag);
619 else
620 attr = attr ^ (attr & (((uint64_t) 1) << flag));
621
622 p->attributes = attr;
623}
624
625// Internal functions follow //
626
627static int load_and_check_header(service_id_t dev_handle, aoff64_t addr, size_t b_size, gpt_header_t * header)
628{
629 int rc;
630
631 rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header);
632 if (rc != EOK)
633 return rc;
634
635 unsigned int i;
636 /* Check the EFI signature */
637 for (i = 0; i < 8; ++i) {
638 if (header->efi_signature[i] != efi_signature[i])
639 return EINVAL;
640 }
641
642 /* Check the CRC32 of the header */
643 uint32_t crc = header->header_crc32;
644 header->header_crc32 = 0;
645 if (crc != compute_crc32((uint8_t *) header, header->header_size))
646 return EBADCHECKSUM;
647 else
648 header->header_crc32 = crc;
649
650 /* Check for zeroes in the rest of the block */
651 for (i = sizeof(gpt_header_t); i < b_size; ++i) {
652 if (((uint8_t *) header)[i] != 0)
653 return EINVAL;
654 }
655
656 return EOK;
657}
658
659static gpt_partitions_t * alloc_part_array(uint32_t num)
660{
661 gpt_partitions_t * res = malloc(sizeof(gpt_partitions_t));
662 if (res == NULL) {
663 errno = ENOMEM;
664 return NULL;
665 }
666
667 uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
668 res->part_array = malloc(size * sizeof(gpt_entry_t));
669 if (res->part_array == NULL) {
670 free(res);
671 errno = ENOMEM;
672 return NULL;
673 }
674
675 res->fill = num;
676 res->arr_size = size;
677
678 return res;
679}
680
681static int extend_part_array(gpt_partitions_t * p)
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 }
689
690 memcpy(tmp, p->part_array, p->fill);
691 free(p->part_array);
692 p->part_array = tmp;
693 p->arr_size = nsize;
694
695 return 0;
696}
697
698static int reduce_part_array(gpt_partitions_t * p)
699{
700 if(p->arr_size > GPT_MIN_PART_NUM) {
701 unsigned int nsize = p->arr_size / 2;
702 nsize = nsize > GPT_MIN_PART_NUM ? nsize : GPT_MIN_PART_NUM;
703 gpt_entry_t * tmp = malloc(nsize * sizeof(gpt_entry_t));
704 if(tmp == NULL)
705 return ENOMEM;
706
707 memcpy(tmp, p->part_array, p->fill < nsize ? p->fill : nsize);
708 free(p->part_array);
709 p->part_array = tmp;
710 p->arr_size = nsize;
711 }
712
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 }
722
723 return ((long long) a) + 1;
724}
725
726static uint8_t get_byte(const char * c)
727{
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;
733}
734
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 }
742
743 return 1;
744}
745
746
Note: See TracBrowser for help on using the repository browser.