source: mainline/uspace/lib/label/src/gpt.c@ a4e78743

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a4e78743 was 2d78d88, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Modifying mount point for a partition.

  • Property mode set to 100644
File size: 22.3 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
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 liblabel
30 * @{
31 */
32/**
33 * @file GUID Partition Table label.
34 */
35
36#include <adt/checksum.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <mem.h>
40#include <stdint.h>
41#include <stdlib.h>
42#include <uuid.h>
43
44#include "std/mbr.h"
45#include "std/gpt.h"
46#include "gpt.h"
47
48static errno_t gpt_open(label_bd_t *, label_t **);
49static errno_t gpt_create(label_bd_t *, label_t **);
50static void gpt_close(label_t *);
51static errno_t gpt_destroy(label_t *);
52static errno_t gpt_get_info(label_t *, label_info_t *);
53static label_part_t *gpt_part_first(label_t *);
54static label_part_t *gpt_part_next(label_part_t *);
55static void gpt_part_get_info(label_part_t *, label_part_info_t *);
56static errno_t gpt_part_create(label_t *, label_part_spec_t *, label_part_t **);
57static errno_t gpt_part_destroy(label_part_t *);
58static errno_t gpt_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
59
60static errno_t gpt_check_free_idx(label_t *, int);
61static errno_t gpt_check_free_range(label_t *, uint64_t, uint64_t);
62
63static void gpt_unused_pte(gpt_entry_t *);
64static errno_t gpt_part_to_pte(label_part_t *, gpt_entry_t *);
65static errno_t gpt_pte_to_part(label_t *, gpt_entry_t *, int);
66static errno_t gpt_pte_update(label_t *, gpt_entry_t *, int);
67
68static errno_t gpt_update_pt_crc(label_t *, uint32_t);
69static void gpt_hdr_compute_crc(gpt_header_t *, size_t);
70static errno_t gpt_hdr_get_crc(gpt_header_t *, size_t, uint32_t *);
71
72static errno_t gpt_pmbr_create(label_bd_t *, size_t, uint64_t);
73static errno_t gpt_pmbr_destroy(label_bd_t *, size_t);
74
75const uint8_t efi_signature[8] = {
76 /* "EFI PART" in ASCII */
77 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
78};
79
80label_ops_t gpt_label_ops = {
81 .open = gpt_open,
82 .create = gpt_create,
83 .close = gpt_close,
84 .destroy = gpt_destroy,
85 .get_info = gpt_get_info,
86 .part_first = gpt_part_first,
87 .part_next = gpt_part_next,
88 .part_get_info = gpt_part_get_info,
89 .part_create = gpt_part_create,
90 .part_destroy = gpt_part_destroy,
91 .suggest_ptype = gpt_suggest_ptype
92};
93
94static errno_t gpt_open(label_bd_t *bd, label_t **rlabel)
95{
96 label_t *label = NULL;
97 gpt_header_t *gpt_hdr[2];
98 gpt_entry_t *eptr;
99 uint8_t *etable[2];
100 size_t bsize;
101 aoff64_t nblocks;
102 uint32_t num_entries;
103 uint32_t esize;
104 uint32_t pt_blocks;
105 uint64_t ptba[2];
106 uint64_t h1ba;
107 uint32_t entry;
108 uint32_t pt_crc;
109 uint64_t ba_min, ba_max;
110 uint32_t hdr_size;
111 uint32_t hdr_crc;
112 int i, j;
113 errno_t rc;
114
115 gpt_hdr[0] = NULL;
116 gpt_hdr[1] = NULL;
117 etable[0] = NULL;
118 etable[1] = NULL;
119
120 rc = bd->ops->get_bsize(bd->arg, &bsize);
121 if (rc != EOK) {
122 rc = EIO;
123 goto error;
124 }
125
126 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
127 if (rc != EOK) {
128 rc = EIO;
129 goto error;
130 }
131
132 if (bsize < 512 || (bsize % 512) != 0) {
133 rc = EINVAL;
134 goto error;
135 }
136
137 gpt_hdr[0] = calloc(1, bsize);
138 if (gpt_hdr[0] == NULL) {
139 rc = ENOMEM;
140 goto error;
141 }
142
143 gpt_hdr[1] = calloc(1, bsize);
144 if (gpt_hdr[1] == NULL) {
145 rc = ENOMEM;
146 goto error;
147 }
148
149 rc = bd->ops->read(bd->arg, gpt_hdr_ba, 1, gpt_hdr[0]);
150 if (rc != EOK) {
151 rc = EIO;
152 goto error;
153 }
154
155 h1ba = uint64_t_le2host(gpt_hdr[0]->alternate_lba);
156
157 if (h1ba >= nblocks) {
158 rc = EINVAL;
159 goto error;
160 }
161
162 rc = bd->ops->read(bd->arg, h1ba, 1, gpt_hdr[1]);
163 if (rc != EOK) {
164 rc = EIO;
165 goto error;
166 }
167
168 label = calloc(1, sizeof(label_t));
169 if (label == NULL)
170 return ENOMEM;
171
172 list_initialize(&label->parts);
173 list_initialize(&label->pri_parts);
174 list_initialize(&label->log_parts);
175
176 for (j = 0; j < 2; j++) {
177 for (i = 0; i < 8; ++i) {
178 if (gpt_hdr[j]->efi_signature[i] != efi_signature[i]) {
179 rc = EINVAL;
180 goto error;
181 }
182 }
183 }
184
185 if (uint32_t_le2host(gpt_hdr[0]->revision) !=
186 uint32_t_le2host(gpt_hdr[1]->revision)) {
187 rc = EINVAL;
188 goto error;
189 }
190
191 if (uint32_t_le2host(gpt_hdr[0]->header_size) !=
192 uint32_t_le2host(gpt_hdr[1]->header_size)) {
193 rc = EINVAL;
194 goto error;
195 }
196
197 hdr_size = uint32_t_le2host(gpt_hdr[0]->header_size);
198 if (hdr_size < sizeof(gpt_header_t) ||
199 hdr_size > bsize) {
200 rc = EINVAL;
201 goto error;
202 }
203
204 for (j = 0; j < 2; j++) {
205 rc = gpt_hdr_get_crc(gpt_hdr[j], hdr_size, &hdr_crc);
206 if (rc != EOK)
207 goto error;
208
209 if (uint32_t_le2host(gpt_hdr[j]->header_crc32) != hdr_crc) {
210 rc = EINVAL;
211 goto error;
212 }
213 }
214
215 if (uint64_t_le2host(gpt_hdr[0]->my_lba) != gpt_hdr_ba) {
216 rc = EINVAL;
217 goto error;
218 }
219
220 if (uint64_t_le2host(gpt_hdr[1]->my_lba) != h1ba) {
221 rc = EINVAL;
222 goto error;
223 }
224
225 if (uint64_t_le2host(gpt_hdr[1]->alternate_lba) != gpt_hdr_ba) {
226 rc = EINVAL;
227 goto error;
228 }
229
230 num_entries = uint32_t_le2host(gpt_hdr[0]->num_entries);
231 esize = uint32_t_le2host(gpt_hdr[0]->entry_size);
232 pt_blocks = (num_entries * esize + bsize - 1) / bsize;
233 ptba[0] = uint64_t_le2host(gpt_hdr[0]->entry_lba);
234 ptba[1] = uint64_t_le2host(gpt_hdr[1]->entry_lba);
235 ba_min = uint64_t_le2host(gpt_hdr[0]->first_usable_lba);
236 ba_max = uint64_t_le2host(gpt_hdr[0]->last_usable_lba);
237 pt_crc = uint32_t_le2host(gpt_hdr[0]->pe_array_crc32);
238
239 if (uint64_t_le2host(gpt_hdr[1]->first_usable_lba) != ba_min) {
240 rc = EINVAL;
241 goto error;
242 }
243
244 if (uint64_t_le2host(gpt_hdr[1]->last_usable_lba) != ba_max) {
245 rc = EINVAL;
246 goto error;
247 }
248
249 for (i = 0; i < 16; i++) {
250 if (gpt_hdr[1]->disk_guid[i] != gpt_hdr[0]->disk_guid[i]) {
251 rc = EINVAL;
252 goto error;
253 }
254 }
255
256 if (uint32_t_le2host(gpt_hdr[1]->num_entries) != num_entries) {
257 rc = EINVAL;
258 goto error;
259 }
260
261 if (uint32_t_le2host(gpt_hdr[1]->entry_size) != esize) {
262 rc = EINVAL;
263 goto error;
264 }
265
266 if (num_entries < 1) {
267 rc = EINVAL;
268 goto error;
269 }
270
271 if (esize < sizeof(gpt_entry_t)) {
272 rc = EINVAL;
273 goto error;
274 }
275
276 if (ba_max < ba_min) {
277 rc = EINVAL;
278 goto error;
279 }
280
281 /* Check fields in backup header for validity */
282
283 for (j = 0; j < 2; j++) {
284 etable[j] = calloc(1, pt_blocks * bsize);
285 if (etable[j] == NULL) {
286 rc = ENOMEM;
287 goto error;
288 }
289
290 rc = bd->ops->read(bd->arg, ptba[j], pt_blocks / 2, etable[j]);
291 if (rc != EOK) {
292 rc = EIO;
293 goto error;
294 }
295
296 if (compute_crc32(etable[j], num_entries * esize) != pt_crc) {
297 rc = EIO;
298 goto error;
299 }
300
301 }
302
303 for (entry = 0; entry < num_entries; entry++) {
304 eptr = (gpt_entry_t *)(etable[0] + entry * esize);
305 rc = gpt_pte_to_part(label, eptr, entry + 1);
306 if (rc != EOK)
307 goto error;
308 }
309
310 free(etable[0]);
311 etable[0] = NULL;
312 free(etable[1]);
313 etable[1] = NULL;
314 free(gpt_hdr[0]);
315 gpt_hdr[0] = NULL;
316 free(gpt_hdr[1]);
317 gpt_hdr[1] = NULL;
318
319 label->ops = &gpt_label_ops;
320 label->ltype = lt_gpt;
321 label->bd = *bd;
322 label->ablock0 = ba_min;
323 label->anblocks = ba_max - ba_min + 1;
324 label->pri_entries = num_entries;
325 label->block_size = bsize;
326
327 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
328 label->lt.gpt.hdr_ba[1] = h1ba;
329 label->lt.gpt.ptable_ba[0] = ptba[0];
330 label->lt.gpt.ptable_ba[1] = ptba[1];
331 label->lt.gpt.esize = esize;
332 label->lt.gpt.pt_blocks = pt_blocks;
333 label->lt.gpt.pt_crc = pt_crc;
334 label->lt.gpt.hdr_size = hdr_size;
335
336 *rlabel = label;
337 return EOK;
338error:
339 free(etable[0]);
340 free(etable[1]);
341 free(gpt_hdr[0]);
342 free(gpt_hdr[1]);
343 free(label);
344 return rc;
345}
346
347static errno_t gpt_create(label_bd_t *bd, label_t **rlabel)
348{
349 label_t *label = NULL;
350 gpt_header_t *gpt_hdr = NULL;
351 uint8_t *etable = NULL;
352 size_t bsize;
353 uint32_t num_entries;
354 uint32_t esize;
355 uint64_t ptba[2];
356 uint64_t hdr_ba[2];
357 uint64_t pt_blocks;
358 uint64_t ba_min, ba_max;
359 aoff64_t nblocks;
360 uint64_t resv_blocks;
361 uint32_t pt_crc;
362 uuid_t disk_uuid;
363 int i, j;
364 errno_t rc;
365
366 rc = bd->ops->get_bsize(bd->arg, &bsize);
367 if (rc != EOK) {
368 rc = EIO;
369 goto error;
370 }
371
372 if (bsize < 512 || (bsize % 512) != 0) {
373 rc = EINVAL;
374 goto error;
375 }
376
377 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
378 if (rc != EOK) {
379 rc = EIO;
380 goto error;
381 }
382
383 /* Number of blocks of a partition table */
384 pt_blocks = gpt_ptable_min_size / bsize;
385 /* Minimum number of reserved (not allocatable) blocks */
386 resv_blocks = 3 + 2 * pt_blocks;
387
388 if (nblocks <= resv_blocks) {
389 rc = ENOSPC;
390 goto error;
391 }
392
393 rc = gpt_pmbr_create(bd, bsize, nblocks);
394 if (rc != EOK) {
395 rc = EIO;
396 goto error;
397 }
398
399 uuid_generate(&disk_uuid);
400
401 hdr_ba[0] = gpt_hdr_ba;
402 hdr_ba[1] = nblocks - 1;
403 ptba[0] = 2;
404 ptba[1] = nblocks - 1 - pt_blocks;
405 ba_min = ptba[0] + pt_blocks;
406 ba_max = ptba[1] - 1;
407 esize = sizeof(gpt_entry_t);
408
409 num_entries = pt_blocks * bsize / sizeof(gpt_entry_t);
410
411 for (i = 0; i < 2; i++) {
412 etable = calloc(1, pt_blocks * bsize);
413 if (etable == NULL) {
414 rc = ENOMEM;
415 goto error;
416 }
417
418 rc = bd->ops->write(bd->arg, ptba[i], pt_blocks, etable);
419 if (rc != EOK) {
420 rc = EIO;
421 goto error;
422 }
423
424 pt_crc = compute_crc32((uint8_t *)etable,
425 num_entries * esize);
426
427 free(etable);
428 etable = NULL;
429
430 gpt_hdr = calloc(1, bsize);
431 if (gpt_hdr == NULL) {
432 rc = ENOMEM;
433 goto error;
434 }
435
436 for (j = 0; j < 8; ++j)
437 gpt_hdr->efi_signature[j] = efi_signature[j];
438 gpt_hdr->revision = host2uint32_t_le(gpt_revision);
439 gpt_hdr->header_size = host2uint32_t_le(sizeof(gpt_header_t));
440 gpt_hdr->header_crc32 = 0;
441 gpt_hdr->my_lba = host2uint64_t_le(hdr_ba[i]);
442 gpt_hdr->alternate_lba = host2uint64_t_le(hdr_ba[1 - i]);
443 gpt_hdr->first_usable_lba = host2uint64_t_le(ba_min);
444 gpt_hdr->last_usable_lba = host2uint64_t_le(ba_max);
445 uuid_encode(&disk_uuid, gpt_hdr->disk_guid);
446 gpt_hdr->entry_lba = host2uint64_t_le(ptba[i]);
447 gpt_hdr->num_entries = host2uint32_t_le(num_entries);
448 gpt_hdr->entry_size = host2uint32_t_le(esize);
449 gpt_hdr->pe_array_crc32 = pt_crc;
450
451 gpt_hdr_compute_crc(gpt_hdr, sizeof(gpt_header_t));
452
453 rc = bd->ops->write(bd->arg, hdr_ba[i], 1, gpt_hdr);
454 if (rc != EOK) {
455 rc = EIO;
456 goto error;
457 }
458
459 free(gpt_hdr);
460 gpt_hdr = NULL;
461 }
462
463 label = calloc(1, sizeof(label_t));
464 if (label == NULL)
465 return ENOMEM;
466
467 list_initialize(&label->parts);
468 list_initialize(&label->pri_parts);
469 list_initialize(&label->log_parts);
470
471 label->ops = &gpt_label_ops;
472 label->ltype = lt_gpt;
473 label->bd = *bd;
474 label->ablock0 = ba_min;
475 label->anblocks = ba_max - ba_min + 1;
476 label->pri_entries = num_entries;
477 label->block_size = bsize;
478
479 label->lt.gpt.hdr_ba[0] = hdr_ba[0];
480 label->lt.gpt.hdr_ba[1] = hdr_ba[1];
481 label->lt.gpt.ptable_ba[0] = ptba[0];
482 label->lt.gpt.ptable_ba[1] = ptba[1];
483 label->lt.gpt.esize = esize;
484 label->lt.gpt.pt_blocks = pt_blocks;
485 label->lt.gpt.pt_crc = pt_crc;
486 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
487
488 *rlabel = label;
489 return EOK;
490error:
491 free(etable);
492 free(gpt_hdr);
493 free(label);
494 return rc;
495}
496
497static void gpt_close(label_t *label)
498{
499 label_part_t *part;
500
501 part = gpt_part_first(label);
502 while (part != NULL) {
503 list_remove(&part->lparts);
504 list_remove(&part->lpri);
505 free(part);
506 part = gpt_part_first(label);
507 }
508
509 free(label);
510}
511
512static errno_t gpt_destroy(label_t *label)
513{
514 gpt_header_t *gpt_hdr = NULL;
515 uint8_t *etable = NULL;
516 label_part_t *part;
517 int i;
518 errno_t rc;
519
520 part = gpt_part_first(label);
521 if (part != NULL) {
522 rc = ENOTEMPTY;
523 goto error;
524 }
525
526 for (i = 0; i < 2; i++) {
527 gpt_hdr = calloc(1, label->block_size);
528 if (gpt_hdr == NULL) {
529 rc = ENOMEM;
530 goto error;
531 }
532
533 rc = label->bd.ops->write(label->bd.arg, label->lt.gpt.hdr_ba[i],
534 1, gpt_hdr);
535 if (rc != EOK) {
536 rc = EIO;
537 goto error;
538 }
539
540 free(gpt_hdr);
541 gpt_hdr = NULL;
542
543 etable = calloc(1, label->lt.gpt.pt_blocks *
544 label->block_size);
545 if (etable == NULL) {
546 rc = ENOMEM;
547 goto error;
548 }
549
550 rc = label->bd.ops->write(label->bd.arg,
551 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
552 etable);
553 if (rc != EOK) {
554 rc = EIO;
555 goto error;
556 }
557
558 free(etable);
559 etable = 0;
560 }
561
562 rc = gpt_pmbr_destroy(&label->bd, label->block_size);
563 if (rc != EOK)
564 goto error;
565
566 free(label);
567 return EOK;
568error:
569 return rc;
570}
571
572static bool gpt_can_create_pri(label_t *label)
573{
574 return list_count(&label->parts) < (size_t)label->pri_entries;
575}
576
577static bool gpt_can_delete_part(label_t *label)
578{
579 return list_count(&label->parts) > 0;
580}
581
582static bool gpt_can_modify_part(label_t *label)
583{
584 return list_count(&label->parts) > 0;
585}
586
587static errno_t gpt_get_info(label_t *label, label_info_t *linfo)
588{
589 memset(linfo, 0, sizeof(label_info_t));
590 linfo->ltype = lt_gpt;
591 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
592 if (gpt_can_create_pri(label))
593 linfo->flags = linfo->flags | lf_can_create_pri;
594 if (gpt_can_delete_part(label))
595 linfo->flags = linfo->flags | lf_can_delete_part;
596 if (gpt_can_modify_part(label))
597 linfo->flags = linfo->flags | lf_can_modify_part;
598 linfo->ablock0 = label->ablock0;
599 linfo->anblocks = label->anblocks;
600 return EOK;
601}
602
603static label_part_t *gpt_part_first(label_t *label)
604{
605 link_t *link;
606
607 link = list_first(&label->parts);
608 if (link == NULL)
609 return NULL;
610
611 return list_get_instance(link, label_part_t, lparts);
612}
613
614static label_part_t *gpt_part_next(label_part_t *part)
615{
616 link_t *link;
617
618 link = list_next(&part->lparts, &part->label->parts);
619 if (link == NULL)
620 return NULL;
621
622 return list_get_instance(link, label_part_t, lparts);
623}
624
625static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
626{
627 pinfo->index = part->index;
628 pinfo->pkind = lpk_primary;
629 pinfo->block0 = part->block0;
630 pinfo->nblocks = part->nblocks;
631}
632
633static errno_t gpt_part_create(label_t *label, label_part_spec_t *pspec,
634 label_part_t **rpart)
635{
636 label_part_t *part;
637 gpt_entry_t pte;
638 errno_t rc;
639
640 part = calloc(1, sizeof(label_part_t));
641 if (part == NULL) {
642 rc = ENOMEM;
643 goto error;
644 }
645
646 /* Verify index is within bounds and free */
647 rc = gpt_check_free_idx(label, pspec->index);
648 if (rc != EOK) {
649 rc = EINVAL;
650 goto error;
651 }
652
653 /* Verify range is within bounds and free */
654 rc = gpt_check_free_range(label, pspec->block0, pspec->nblocks);
655 if (rc != EOK) {
656 rc = EINVAL;
657 goto error;
658 }
659
660 /* GPT only has primary partitions */
661 if (pspec->pkind != lpk_primary) {
662 rc = EINVAL;
663 goto error;
664 }
665
666 /* Partition type must be in UUID format */
667 if (pspec->ptype.fmt != lptf_uuid) {
668 rc = EINVAL;
669 goto error;
670 }
671
672 /* XXX Check if index is used */
673
674 part->label = label;
675 part->index = pspec->index;
676 part->block0 = pspec->block0;
677 part->nblocks = pspec->nblocks;
678 part->ptype = pspec->ptype;
679 uuid_generate(&part->part_uuid);
680
681 /* Prepare partition table entry */
682 rc = gpt_part_to_pte(part, &pte);
683 if (rc != EOK) {
684 rc = EINVAL;
685 goto error;
686 }
687
688 /* Modify partition tables */
689 rc = gpt_pte_update(label, &pte, pspec->index - 1);
690 if (rc != EOK) {
691 rc = EIO;
692 goto error;
693 }
694
695 list_append(&part->lparts, &label->parts);
696 list_append(&part->lpri, &label->pri_parts);
697
698 *rpart = part;
699 return EOK;
700error:
701 free(part);
702 return rc;
703}
704
705static errno_t gpt_part_destroy(label_part_t *part)
706{
707 gpt_entry_t pte;
708 errno_t rc;
709
710 /* Prepare unused partition table entry */
711 gpt_unused_pte(&pte);
712
713 /* Modify partition tables */
714 rc = gpt_pte_update(part->label, &pte, part->index - 1);
715 if (rc != EOK)
716 return EIO;
717
718 list_remove(&part->lparts);
719 list_remove(&part->lpri);
720 free(part);
721 return EOK;
722}
723
724static errno_t gpt_suggest_ptype(label_t *label, label_pcnt_t pcnt,
725 label_ptype_t *ptype)
726{
727 const char *ptid;
728 errno_t rc;
729
730 ptid = NULL;
731
732 switch (pcnt) {
733 case lpc_fat12_16:
734 case lpc_exfat:
735 case lpc_fat32:
736 ptid = GPT_MS_BASIC_DATA;
737 break;
738 case lpc_ext4:
739 ptid = GPT_LINUX_FS_DATA;
740 break;
741 case lpc_minix:
742 ptid = GPT_MINIX_FAKE;
743 break;
744 }
745
746 if (ptid == NULL)
747 return EINVAL;
748
749 ptype->fmt = lptf_uuid;
750 rc = uuid_parse(ptid, &ptype->t.uuid, NULL);
751 assert(rc == EOK);
752
753 return EOK;
754}
755
756/** Verify that the specified index is valid and free. */
757static errno_t gpt_check_free_idx(label_t *label, int index)
758{
759 label_part_t *part;
760
761 if (index < 1 || index > label->pri_entries)
762 return EINVAL;
763
764 part = gpt_part_first(label);
765 while (part != NULL) {
766 if (part->index == index)
767 return EEXIST;
768 part = gpt_part_next(part);
769 }
770
771 return EOK;
772}
773
774/** Determine if two block address ranges overlap. */
775static bool gpt_overlap(uint64_t a0, uint64_t an, uint64_t b0, uint64_t bn)
776{
777 return !(a0 + an <= b0 || b0 + bn <= a0);
778}
779
780static errno_t gpt_check_free_range(label_t *label, uint64_t block0,
781 uint64_t nblocks)
782{
783 label_part_t *part;
784
785 if (block0 < label->ablock0)
786 return EINVAL;
787 if (block0 + nblocks > label->ablock0 + label->anblocks)
788 return EINVAL;
789
790 part = gpt_part_first(label);
791 while (part != NULL) {
792 if (gpt_overlap(block0, nblocks, part->block0, part->nblocks))
793 return EEXIST;
794 part = gpt_part_next(part);
795 }
796
797 return EOK;
798}
799
800static void gpt_unused_pte(gpt_entry_t *pte)
801{
802 memset(pte, 0, sizeof(gpt_entry_t));
803}
804
805static errno_t gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
806{
807 uint64_t eblock;
808
809 eblock = part->block0 + part->nblocks - 1;
810 if (eblock < part->block0)
811 return EINVAL;
812
813 memset(pte, 0, sizeof(gpt_entry_t));
814 uuid_encode(&part->ptype.t.uuid, pte->part_type);
815 uuid_encode(&part->part_uuid, pte->part_id);
816 pte->start_lba = host2uint64_t_le(part->block0);
817 pte->end_lba = host2uint64_t_le(eblock);
818 //pte->attributes
819 //pte->part_name
820 return EOK;
821}
822
823static errno_t gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
824{
825 label_part_t *part;
826 bool present;
827 uint64_t b0, b1;
828 int i;
829
830 present = false;
831 for (i = 0; i < 8; i++)
832 if (pte->part_type[i] != 0x00)
833 present = true;
834
835 if (!present)
836 return EOK;
837
838 b0 = uint64_t_le2host(pte->start_lba);
839 b1 = uint64_t_le2host(pte->end_lba);
840 if (b1 <= b0)
841 return EINVAL;
842
843 part = calloc(1, sizeof(label_part_t));
844 if (part == NULL)
845 return ENOMEM;
846
847 part->index = index;
848 part->block0 = b0;
849 part->nblocks = b1 - b0 + 1;
850 part->ptype.fmt = lptf_uuid;
851 uuid_decode(pte->part_type, &part->ptype.t.uuid);
852 uuid_decode(pte->part_id, &part->part_uuid);
853
854 part->label = label;
855 list_append(&part->lparts, &label->parts);
856 list_append(&part->lpri, &label->pri_parts);
857 return EOK;
858}
859
860/** Update partition table entry at specified index.
861 *
862 * Replace partition entry at index @a index with the contents of
863 * @a pte.
864 */
865static errno_t gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
866{
867 size_t pos;
868 uint64_t ba;
869 uint64_t nblocks;
870 size_t ptbytes;
871 uint8_t *buf;
872 gpt_entry_t *e;
873 uint32_t crc;
874 int i;
875 errno_t rc;
876
877 /* Byte offset of partition entry */
878 pos = index * label->lt.gpt.esize;
879 /* Number of bytes in partition table */
880 ptbytes = label->pri_entries * label->lt.gpt.esize;
881
882 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
883 if (buf == NULL)
884 return ENOMEM;
885
886 /* For both partition tables: read, modify, write */
887 for (i = 0; i < 2; i++) {
888 ba = label->lt.gpt.ptable_ba[i];
889 nblocks = label->lt.gpt.pt_blocks;
890
891 rc = label->bd.ops->read(label->bd.arg, ba, nblocks, buf);
892 if (rc != EOK) {
893 rc = EIO;
894 goto error;
895 }
896
897 crc = compute_crc32(buf, ptbytes);
898 if (crc != label->lt.gpt.pt_crc) {
899 /* Corruption detected */
900 rc = EIO;
901 goto error;
902 }
903
904 /* Replace single entry */
905 e = (gpt_entry_t *)(&buf[pos]);
906 *e = *pte;
907
908 rc = label->bd.ops->write(label->bd.arg, ba, nblocks, buf);
909 if (rc != EOK) {
910 rc = EIO;
911 goto error;
912 }
913
914 crc = compute_crc32(buf, ptbytes);
915 rc = gpt_update_pt_crc(label, crc);
916 if (rc != EOK) {
917 rc = EIO;
918 goto error;
919 }
920 }
921
922 label->lt.gpt.pt_crc = crc;
923 free(buf);
924 return EOK;
925error:
926 free(buf);
927 return rc;
928}
929
930static errno_t gpt_update_pt_crc(label_t *label, uint32_t crc)
931{
932 gpt_header_t *gpt_hdr;
933 errno_t rc;
934 int i;
935
936 gpt_hdr = calloc(1, label->block_size);
937 if (gpt_hdr == NULL) {
938 rc = ENOMEM;
939 goto exit;
940 }
941
942 for (i = 0; i < 2; i++) {
943 rc = label->bd.ops->read(label->bd.arg,
944 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
945 if (rc != EOK) {
946 rc = EIO;
947 goto exit;
948 }
949
950 gpt_hdr->pe_array_crc32 = host2uint32_t_le(crc);
951 gpt_hdr_compute_crc(gpt_hdr, label->lt.gpt.hdr_size);
952
953 rc = label->bd.ops->write(label->bd.arg,
954 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
955 if (rc != EOK) {
956 rc = EIO;
957 goto exit;
958 }
959 }
960
961 rc = EOK;
962
963exit:
964 free(gpt_hdr);
965 return rc;
966}
967
968static void gpt_hdr_compute_crc(gpt_header_t *hdr, size_t hdr_size)
969{
970 uint32_t crc;
971
972 hdr->header_crc32 = 0;
973 crc = compute_crc32((uint8_t *)hdr, hdr_size);
974 hdr->header_crc32 = crc;
975}
976
977static errno_t gpt_hdr_get_crc(gpt_header_t *hdr, size_t hdr_size, uint32_t *crc)
978{
979 gpt_header_t *c;
980
981 c = calloc(1, hdr_size);
982 if (c == NULL)
983 return ENOMEM;
984
985 memcpy(c, hdr, hdr_size);
986 c->header_crc32 = 0;
987 *crc = compute_crc32((uint8_t *)c, hdr_size);
988 free(c);
989
990 return EOK;
991}
992
993/** Create GPT Protective MBR */
994static errno_t gpt_pmbr_create(label_bd_t *bd, size_t bsize, uint64_t nblocks)
995{
996 mbr_br_block_t *pmbr = NULL;
997 uint64_t pmbr_nb;
998 errno_t rc;
999
1000 pmbr = calloc(1, bsize);
1001 if (pmbr == NULL) {
1002 rc = ENOMEM;
1003 goto error;
1004 }
1005
1006 pmbr_nb = nblocks - gpt_hdr_ba;
1007
1008 pmbr->pte[0].ptype = mbr_pt_gpt_protect;
1009 pmbr->pte[0].first_lba = gpt_hdr_ba;
1010
1011 if (pmbr_nb <= UINT32_MAX)
1012 pmbr->pte[0].length = host2uint32_t_le((uint32_t)pmbr_nb);
1013 else
1014 pmbr->pte[0].length = host2uint32_t_le(UINT32_MAX);
1015
1016 pmbr->signature = host2uint16_t_le(mbr_br_signature);
1017
1018 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
1019 if (rc != EOK) {
1020 rc = EIO;
1021 goto error;
1022 }
1023
1024 free(pmbr);
1025 return EOK;
1026error:
1027 free(pmbr);
1028 return rc;
1029}
1030
1031/** Destroy GPT Protective MBR */
1032static errno_t gpt_pmbr_destroy(label_bd_t *bd, size_t bsize)
1033{
1034 mbr_br_block_t *pmbr = NULL;
1035 errno_t rc;
1036
1037 pmbr = calloc(1, bsize);
1038 if (pmbr == NULL) {
1039 rc = ENOMEM;
1040 goto error;
1041 }
1042
1043 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
1044 if (rc != EOK) {
1045 rc = EIO;
1046 goto error;
1047 }
1048
1049 free(pmbr);
1050 return EOK;
1051error:
1052 free(pmbr);
1053 return rc;
1054}
1055
1056/** @}
1057 */
Note: See TracBrowser for help on using the repository browser.