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

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

Cached GPT partition table CRC updates missed.

  • Property mode set to 100644
File size: 19.2 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.pt_crc = pt_crc;
461 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
462
463 *rlabel = label;
464 return EOK;
465error:
466 free(etable);
467 free(gpt_hdr);
468 free(label);
469 return rc;
470}
471
472static void gpt_close(label_t *label)
473{
474 label_part_t *part;
475
476 part = gpt_part_first(label);
477 while (part != NULL) {
478 list_remove(&part->lparts);
479 list_remove(&part->lpri);
480 free(part);
481 part = gpt_part_first(label);
482 }
483
484 free(label);
485}
486
487static int gpt_destroy(label_t *label)
488{
489 gpt_header_t *gpt_hdr = NULL;
490 uint8_t *etable = NULL;
491 label_part_t *part;
492 int i;
493 int rc;
494
495 part = gpt_part_first(label);
496 if (part != NULL) {
497 rc = ENOTEMPTY;
498 goto error;
499 }
500
501 for (i = 0; i < 2; i++) {
502 gpt_hdr = calloc(1, label->block_size);
503 if (gpt_hdr == NULL) {
504 rc = ENOMEM;
505 goto error;
506 }
507
508 rc = block_write_direct(label->svc_id, label->lt.gpt.hdr_ba[i],
509 1, gpt_hdr);
510 if (rc != EOK) {
511 rc = EIO;
512 goto error;
513 }
514
515 free(gpt_hdr);
516 gpt_hdr = NULL;
517
518 etable = calloc(1, label->lt.gpt.pt_blocks *
519 label->block_size);
520 if (etable == NULL) {
521 rc = ENOMEM;
522 goto error;
523 }
524
525 rc = block_write_direct(label->svc_id,
526 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
527 etable);
528 if (rc != EOK) {
529 rc = EIO;
530 goto error;
531 }
532
533 free(etable);
534 etable = 0;
535 }
536
537 free(label);
538 return EOK;
539error:
540 return rc;
541}
542
543static bool gpt_can_create_pri(label_t *label)
544{
545 return list_count(&label->parts) < (size_t)label->pri_entries;
546}
547
548static bool gpt_can_delete_part(label_t *label)
549{
550 return list_count(&label->parts) > 0;
551}
552
553static int gpt_get_info(label_t *label, label_info_t *linfo)
554{
555 memset(linfo, 0, sizeof(label_info_t));
556 linfo->ltype = lt_gpt;
557 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
558 if (gpt_can_create_pri(label))
559 linfo->flags = linfo->flags | lf_can_create_pri;
560 if (gpt_can_delete_part(label))
561 linfo->flags = linfo->flags | lf_can_delete_part;
562 linfo->ablock0 = label->ablock0;
563 linfo->anblocks = label->anblocks;
564 return EOK;
565}
566
567static label_part_t *gpt_part_first(label_t *label)
568{
569 link_t *link;
570
571 link = list_first(&label->parts);
572 if (link == NULL)
573 return NULL;
574
575 return list_get_instance(link, label_part_t, lparts);
576}
577
578static label_part_t *gpt_part_next(label_part_t *part)
579{
580 link_t *link;
581
582 link = list_next(&part->lparts, &part->label->parts);
583 if (link == NULL)
584 return NULL;
585
586 return list_get_instance(link, label_part_t, lparts);
587}
588
589static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
590{
591 pinfo->index = part->index;
592 pinfo->pkind = lpk_primary;
593 pinfo->block0 = part->block0;
594 pinfo->nblocks = part->nblocks;
595}
596
597static int gpt_part_create(label_t *label, label_part_spec_t *pspec,
598 label_part_t **rpart)
599{
600 label_part_t *part;
601 gpt_entry_t pte;
602 int rc;
603
604 part = calloc(1, sizeof(label_part_t));
605 if (part == NULL) {
606 rc = ENOMEM;
607 goto error;
608 }
609
610 /* XXX Verify index, block0, nblocks */
611
612 if (pspec->index < 1 || pspec->index > label->pri_entries) {
613 rc = EINVAL;
614 goto error;
615 }
616
617 /* GPT only has primary partitions */
618 if (pspec->pkind != lpk_primary) {
619 rc = EINVAL;
620 goto error;
621 }
622
623 /* Partition type must be in UUID format */
624 if (pspec->ptype.fmt != lptf_uuid) {
625 rc = EINVAL;
626 goto error;
627 }
628
629 /* XXX Check if index is used */
630
631 part->label = label;
632 part->index = pspec->index;
633 part->block0 = pspec->block0;
634 part->nblocks = pspec->nblocks;
635 part->ptype = pspec->ptype;
636 uuid_generate(&part->part_uuid);
637
638 /* Prepare partition table entry */
639 rc = gpt_part_to_pte(part, &pte);
640 if (rc != EOK) {
641 rc = EINVAL;
642 goto error;
643 }
644
645 /* Modify partition tables */
646 rc = gpt_pte_update(label, &pte, pspec->index - 1);
647 if (rc != EOK) {
648 rc = EIO;
649 goto error;
650 }
651
652 list_append(&part->lparts, &label->parts);
653 list_append(&part->lpri, &label->pri_parts);
654
655 *rpart = part;
656 return EOK;
657error:
658 free(part);
659 return rc;
660}
661
662static int gpt_part_destroy(label_part_t *part)
663{
664 gpt_entry_t pte;
665 int rc;
666
667 /* Prepare unused partition table entry */
668 gpt_unused_pte(&pte);
669
670 /* Modify partition tables */
671 rc = gpt_pte_update(part->label, &pte, part->index - 1);
672 if (rc != EOK)
673 return EIO;
674
675 list_remove(&part->lparts);
676 list_remove(&part->lpri);
677 free(part);
678 return EOK;
679}
680
681static int gpt_suggest_ptype(label_t *label, label_pcnt_t pcnt,
682 label_ptype_t *ptype)
683{
684 const char *ptid;
685 int rc;
686
687 ptid = NULL;
688
689 switch (pcnt) {
690 case lpc_fat12_16:
691 case lpc_exfat:
692 case lpc_fat32:
693 ptid = GPT_MS_BASIC_DATA;
694 break;
695 case lpc_ext4:
696 ptid = GPT_LINUX_FS_DATA;
697 break;
698 case lpc_minix:
699 ptid = GPT_MINIX_FAKE;
700 break;
701 }
702
703 if (ptid == NULL)
704 return EINVAL;
705
706 ptype->fmt = lptf_uuid;
707 rc = uuid_parse(ptid, &ptype->t.uuid, NULL);
708 assert(rc == EOK);
709
710 return EOK;
711}
712
713static void gpt_unused_pte(gpt_entry_t *pte)
714{
715 memset(pte, 0, sizeof(gpt_entry_t));
716}
717
718static int gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
719{
720 uint64_t eblock;
721
722 eblock = part->block0 + part->nblocks - 1;
723 if (eblock < part->block0)
724 return EINVAL;
725
726 memset(pte, 0, sizeof(gpt_entry_t));
727 uuid_encode(&part->ptype.t.uuid, pte->part_type);
728 uuid_encode(&part->part_uuid, pte->part_id);
729 pte->start_lba = host2uint64_t_le(part->block0);
730 pte->end_lba = host2uint64_t_le(eblock);
731// pte->attributes
732// pte->part_name
733 return EOK;
734}
735
736static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
737{
738 label_part_t *part;
739 bool present;
740 uint64_t b0, b1;
741 int i;
742
743 present = false;
744 for (i = 0; i < 8; i++)
745 if (pte->part_type[i] != 0x00)
746 present = true;
747
748 if (!present)
749 return EOK;
750
751 part = calloc(1, sizeof(label_part_t));
752 if (part == NULL)
753 return ENOMEM;
754
755 b0 = uint64_t_le2host(pte->start_lba);
756 b1 = uint64_t_le2host(pte->end_lba);
757 if (b1 <= b0)
758 return EINVAL;
759
760 part->index = index;
761 part->block0 = b0;
762 part->nblocks = b1 - b0 + 1;
763 part->ptype.fmt = lptf_uuid;
764 uuid_decode(pte->part_type, &part->ptype.t.uuid);
765 uuid_decode(pte->part_id, &part->part_uuid);
766
767 part->label = label;
768 list_append(&part->lparts, &label->parts);
769 list_append(&part->lpri, &label->pri_parts);
770 return EOK;
771}
772
773/** Update partition table entry at specified index.
774 *
775 * Replace partition entry at index @a index with the contents of
776 * @a pte.
777 */
778static int gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
779{
780 size_t pos;
781 uint64_t ba;
782 uint64_t nblocks;
783 size_t ptbytes;
784 uint8_t *buf;
785 gpt_entry_t *e;
786 uint32_t crc;
787 int i;
788 int rc;
789
790 /* Byte offset of partition entry */
791 pos = index * label->lt.gpt.esize;
792 /* Number of bytes in partition table */
793 ptbytes = label->pri_entries * label->lt.gpt.esize;
794
795 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
796 if (buf == NULL)
797 return ENOMEM;
798
799 /* For both partition tables: read, modify, write */
800 for (i = 0; i < 2; i++) {
801 ba = label->lt.gpt.ptable_ba[i];
802 nblocks = label->lt.gpt.pt_blocks;
803
804 rc = block_read_direct(label->svc_id, ba, nblocks, buf);
805 if (rc != EOK) {
806 rc = EIO;
807 goto error;
808 }
809
810 crc = compute_crc32(buf, ptbytes);
811 if (crc != label->lt.gpt.pt_crc) {
812 /* Corruption detected */
813 rc = EIO;
814 goto error;
815 }
816
817 /* Replace single entry */
818 e = (gpt_entry_t *)(&buf[pos]);
819 *e = *pte;
820
821 rc = block_write_direct(label->svc_id, ba, nblocks, buf);
822 if (rc != EOK) {
823 rc = EIO;
824 goto error;
825 }
826
827 crc = compute_crc32(buf, ptbytes);
828 rc = gpt_update_pt_crc(label, crc);
829 if (rc != EOK) {
830 rc = EIO;
831 goto error;
832 }
833 }
834
835 label->lt.gpt.pt_crc = crc;
836 free(buf);
837 return EOK;
838error:
839 free(buf);
840 return rc;
841}
842
843static int gpt_update_pt_crc(label_t *label, uint32_t crc)
844{
845 gpt_header_t *gpt_hdr;
846 int rc;
847 int i;
848
849 gpt_hdr = calloc(1, label->block_size);
850 if (gpt_hdr == NULL) {
851 rc = ENOMEM;
852 goto error;
853 }
854
855 for (i = 0; i < 2; i++) {
856 rc = block_read_direct(label->svc_id,
857 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
858 if (rc != EOK) {
859 rc = EIO;
860 goto error;
861 }
862
863 gpt_hdr->pe_array_crc32 = host2uint32_t_le(crc);
864 gpt_hdr_compute_crc(gpt_hdr, label->lt.gpt.hdr_size);
865
866 rc = block_write_direct(label->svc_id,
867 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
868 if (rc != EOK) {
869 rc = EIO;
870 goto error;
871 }
872 }
873
874 free(gpt_hdr);
875 return EOK;
876error:
877 return rc;
878}
879
880static void gpt_hdr_compute_crc(gpt_header_t *hdr, size_t hdr_size)
881{
882 uint32_t crc;
883
884 hdr->header_crc32 = 0;
885 crc = compute_crc32((uint8_t *)hdr, hdr_size);
886 hdr->header_crc32 = crc;
887}
888
889static int gpt_hdr_get_crc(gpt_header_t *hdr, size_t hdr_size, uint32_t *crc)
890{
891 gpt_header_t *c;
892
893 c = calloc(1, sizeof(gpt_header_t));
894 if (c == NULL)
895 return ENOMEM;
896
897 memcpy(c, hdr, hdr_size);
898 c->header_crc32 = 0;
899 *crc = compute_crc32((uint8_t *)c, hdr_size);
900 free(c);
901
902 return EOK;
903}
904
905/** @}
906 */
Note: See TracBrowser for help on using the repository browser.