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

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

Add GPT partitions only once.

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