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

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

Handle dummy partition addition/removal during label destruction/creation. Handle dummy label properly in fdisk.

  • 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 for (entry = 0; entry < num_entries; entry++) {
283 eptr = (gpt_entry_t *)(etable[j] + entry * esize);
284 rc = gpt_pte_to_part(label, eptr, entry + 1);
285 if (rc != EOK)
286 goto error;
287 }
288 }
289
290 free(etable[0]);
291 etable[0] = NULL;
292 free(etable[1]);
293 etable[1] = NULL;
294 free(gpt_hdr[0]);
295 gpt_hdr[0] = NULL;
296 free(gpt_hdr[1]);
297 gpt_hdr[1] = NULL;
298
299 label->ops = &gpt_label_ops;
300 label->ltype = lt_gpt;
301 label->svc_id = sid;
302 label->ablock0 = ba_min;
303 label->anblocks = ba_max - ba_min + 1;
304 label->pri_entries = num_entries;
305 label->block_size = bsize;
306
307 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
308 label->lt.gpt.hdr_ba[1] = h1ba;
309 label->lt.gpt.ptable_ba[0] = ptba[0];
310 label->lt.gpt.ptable_ba[1] = ptba[1];
311 label->lt.gpt.esize = esize;
312 label->lt.gpt.pt_blocks = pt_blocks;
313 label->lt.gpt.pt_crc = pt_crc;
314 label->lt.gpt.hdr_size = hdr_size;
315
316 *rlabel = label;
317 return EOK;
318error:
319 free(etable[0]);
320 free(etable[1]);
321 free(gpt_hdr[0]);
322 free(gpt_hdr[1]);
323 free(label);
324 return rc;
325}
326
327static int gpt_create(service_id_t sid, label_t **rlabel)
328{
329 label_t *label = NULL;
330 gpt_header_t *gpt_hdr = NULL;
331 uint8_t *etable = NULL;
332 size_t bsize;
333 uint32_t num_entries;
334 uint32_t esize;
335 uint64_t ptba[2];
336 uint64_t hdr_ba[2];
337 uint64_t pt_blocks;
338 uint64_t ba_min, ba_max;
339 aoff64_t nblocks;
340 uint64_t resv_blocks;
341 uint32_t pt_crc;
342 uuid_t disk_uuid;
343 int i, j;
344 int rc;
345
346 rc = block_get_bsize(sid, &bsize);
347 if (rc != EOK) {
348 rc = EIO;
349 goto error;
350 }
351
352 if (bsize < 512 || (bsize % 512) != 0) {
353 rc = EINVAL;
354 goto error;
355 }
356
357 rc = block_get_nblocks(sid, &nblocks);
358 if (rc != EOK) {
359 rc = EIO;
360 goto error;
361 }
362
363 /* Number of blocks of a partition table */
364 pt_blocks = gpt_ptable_min_size / bsize;
365 /* Minimum number of reserved (not allocatable) blocks */
366 resv_blocks = 3 + 2 * pt_blocks;
367
368 if (nblocks <= resv_blocks) {
369 rc = ENOSPC;
370 goto error;
371 }
372
373 uuid_generate(&disk_uuid);
374
375 hdr_ba[0] = gpt_hdr_ba;
376 hdr_ba[1] = nblocks - 1;
377 ptba[0] = 2;
378 ptba[1] = nblocks - 1 - pt_blocks;
379 ba_min = ptba[0] + pt_blocks;
380 ba_max = ptba[1] - 1;
381 esize = sizeof(gpt_entry_t);
382
383 num_entries = pt_blocks * bsize / sizeof(gpt_entry_t);
384
385 for (i = 0; i < 2; i++) {
386 etable = calloc(1, pt_blocks * bsize);
387 if (etable == NULL) {
388 rc = ENOMEM;
389 goto error;
390 }
391
392 rc = block_write_direct(sid, ptba[i], pt_blocks, etable);
393 if (rc != EOK) {
394 rc = EIO;
395 goto error;
396 }
397
398 pt_crc = compute_crc32((uint8_t *)etable,
399 num_entries * esize);
400
401 free(etable);
402 etable = NULL;
403
404 gpt_hdr = calloc(1, bsize);
405 if (gpt_hdr == NULL) {
406 rc = ENOMEM;
407 goto error;
408 }
409
410 for (j = 0; j < 8; ++j)
411 gpt_hdr->efi_signature[j] = efi_signature[j];
412 gpt_hdr->revision = host2uint32_t_le(gpt_revision);
413 gpt_hdr->header_size = host2uint32_t_le(sizeof(gpt_header_t));
414 gpt_hdr->header_crc32 = 0;
415 gpt_hdr->my_lba = host2uint64_t_le(hdr_ba[i]);
416 gpt_hdr->alternate_lba = host2uint64_t_le(hdr_ba[1 - i]);
417 gpt_hdr->first_usable_lba = host2uint64_t_le(ba_min);
418 gpt_hdr->last_usable_lba = host2uint64_t_le(ba_max);
419 uuid_encode(&disk_uuid, gpt_hdr->disk_guid);
420 gpt_hdr->entry_lba = host2uint64_t_le(ptba[i]);
421 gpt_hdr->num_entries = host2uint32_t_le(num_entries);
422 gpt_hdr->entry_size = host2uint32_t_le(esize);
423 gpt_hdr->pe_array_crc32 = pt_crc;
424
425 gpt_hdr_compute_crc(gpt_hdr, sizeof(gpt_header_t));
426
427 rc = block_write_direct(sid, hdr_ba[i], 1, gpt_hdr);
428 if (rc != EOK) {
429 rc = EIO;
430 goto error;
431 }
432
433 free(gpt_hdr);
434 gpt_hdr = NULL;
435 }
436
437 label = calloc(1, sizeof(label_t));
438 if (label == NULL)
439 return ENOMEM;
440
441 list_initialize(&label->parts);
442 list_initialize(&label->pri_parts);
443 list_initialize(&label->log_parts);
444
445 label->ops = &gpt_label_ops;
446 label->ltype = lt_gpt;
447 label->svc_id = sid;
448 label->ablock0 = ba_min;
449 label->anblocks = ba_max - ba_min + 1;
450 label->pri_entries = num_entries;
451 label->block_size = bsize;
452
453 label->lt.gpt.hdr_ba[0] = hdr_ba[0];
454 label->lt.gpt.hdr_ba[1] = hdr_ba[1];
455 label->lt.gpt.ptable_ba[0] = ptba[0];
456 label->lt.gpt.ptable_ba[1] = ptba[1];
457 label->lt.gpt.esize = esize;
458 label->lt.gpt.pt_blocks = pt_blocks;
459 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
460
461 *rlabel = label;
462 return EOK;
463error:
464 free(etable);
465 free(gpt_hdr);
466 free(label);
467 return rc;
468}
469
470static void gpt_close(label_t *label)
471{
472 label_part_t *part;
473
474 part = gpt_part_first(label);
475 while (part != NULL) {
476 list_remove(&part->lparts);
477 list_remove(&part->lpri);
478 free(part);
479 part = gpt_part_first(label);
480 }
481
482 free(label);
483}
484
485static int gpt_destroy(label_t *label)
486{
487 gpt_header_t *gpt_hdr = NULL;
488 uint8_t *etable = NULL;
489 label_part_t *part;
490 int i;
491 int rc;
492
493 part = gpt_part_first(label);
494 if (part != NULL) {
495 rc = ENOTEMPTY;
496 goto error;
497 }
498
499 for (i = 0; i < 2; i++) {
500 gpt_hdr = calloc(1, label->block_size);
501 if (gpt_hdr == NULL) {
502 rc = ENOMEM;
503 goto error;
504 }
505
506 rc = block_write_direct(label->svc_id, label->lt.gpt.hdr_ba[i],
507 1, gpt_hdr);
508 if (rc != EOK) {
509 rc = EIO;
510 goto error;
511 }
512
513 free(gpt_hdr);
514 gpt_hdr = NULL;
515
516 etable = calloc(1, label->lt.gpt.pt_blocks *
517 label->block_size);
518 if (etable == NULL) {
519 rc = ENOMEM;
520 goto error;
521 }
522
523 rc = block_write_direct(label->svc_id,
524 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
525 etable);
526 if (rc != EOK) {
527 rc = EIO;
528 goto error;
529 }
530
531 free(etable);
532 etable = 0;
533 }
534
535 free(label);
536 return EOK;
537error:
538 return rc;
539}
540
541static bool gpt_can_create_pri(label_t *label)
542{
543 return list_count(&label->parts) < (size_t)label->pri_entries;
544}
545
546static bool gpt_can_delete_part(label_t *label)
547{
548 return list_count(&label->parts) > 0;
549}
550
551static int gpt_get_info(label_t *label, label_info_t *linfo)
552{
553 memset(linfo, 0, sizeof(label_info_t));
554 linfo->ltype = lt_gpt;
555 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
556 if (gpt_can_create_pri(label))
557 linfo->flags = linfo->flags | lf_can_create_pri;
558 if (gpt_can_delete_part(label))
559 linfo->flags = linfo->flags | lf_can_delete_part;
560 linfo->ablock0 = label->ablock0;
561 linfo->anblocks = label->anblocks;
562 return EOK;
563}
564
565static label_part_t *gpt_part_first(label_t *label)
566{
567 link_t *link;
568
569 link = list_first(&label->parts);
570 if (link == NULL)
571 return NULL;
572
573 return list_get_instance(link, label_part_t, lparts);
574}
575
576static label_part_t *gpt_part_next(label_part_t *part)
577{
578 link_t *link;
579
580 link = list_next(&part->lparts, &part->label->parts);
581 if (link == NULL)
582 return NULL;
583
584 return list_get_instance(link, label_part_t, lparts);
585}
586
587static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
588{
589 pinfo->index = part->index;
590 pinfo->pkind = lpk_primary;
591 pinfo->block0 = part->block0;
592 pinfo->nblocks = part->nblocks;
593}
594
595static int gpt_part_create(label_t *label, label_part_spec_t *pspec,
596 label_part_t **rpart)
597{
598 label_part_t *part;
599 gpt_entry_t pte;
600 int rc;
601
602 part = calloc(1, sizeof(label_part_t));
603 if (part == NULL) {
604 rc = ENOMEM;
605 goto error;
606 }
607
608 /* XXX Verify index, block0, nblocks */
609
610 if (pspec->index < 1 || pspec->index > label->pri_entries) {
611 rc = EINVAL;
612 goto error;
613 }
614
615 /* GPT only has primary partitions */
616 if (pspec->pkind != lpk_primary) {
617 rc = EINVAL;
618 goto error;
619 }
620
621 /* Partition type must be in UUID format */
622 if (pspec->ptype.fmt != lptf_uuid) {
623 rc = EINVAL;
624 goto error;
625 }
626
627 /* XXX Check if index is used */
628
629 part->label = label;
630 part->index = pspec->index;
631 part->block0 = pspec->block0;
632 part->nblocks = pspec->nblocks;
633 part->ptype = pspec->ptype;
634 uuid_generate(&part->part_uuid);
635
636 /* Prepare partition table entry */
637 rc = gpt_part_to_pte(part, &pte);
638 if (rc != EOK) {
639 rc = EINVAL;
640 goto error;
641 }
642
643 /* Modify partition tables */
644 rc = gpt_pte_update(label, &pte, pspec->index - 1);
645 if (rc != EOK) {
646 rc = EIO;
647 goto error;
648 }
649
650 list_append(&part->lparts, &label->parts);
651 list_append(&part->lpri, &label->pri_parts);
652
653 *rpart = part;
654 return EOK;
655error:
656 free(part);
657 return rc;
658}
659
660static int gpt_part_destroy(label_part_t *part)
661{
662 gpt_entry_t pte;
663 int rc;
664
665 /* Prepare unused partition table entry */
666 gpt_unused_pte(&pte);
667
668 /* Modify partition tables */
669 rc = gpt_pte_update(part->label, &pte, part->index - 1);
670 if (rc != EOK)
671 return EIO;
672
673 list_remove(&part->lparts);
674 list_remove(&part->lpri);
675 free(part);
676 return EOK;
677}
678
679static int gpt_suggest_ptype(label_t *label, label_pcnt_t pcnt,
680 label_ptype_t *ptype)
681{
682 const char *ptid;
683 int rc;
684
685 ptid = NULL;
686
687 switch (pcnt) {
688 case lpc_fat12_16:
689 case lpc_exfat:
690 case lpc_fat32:
691 ptid = GPT_MS_BASIC_DATA;
692 break;
693 case lpc_ext4:
694 ptid = GPT_LINUX_FS_DATA;
695 break;
696 case lpc_minix:
697 ptid = GPT_MINIX_FAKE;
698 break;
699 }
700
701 if (ptid == NULL)
702 return EINVAL;
703
704 ptype->fmt = lptf_uuid;
705 rc = uuid_parse(ptid, &ptype->t.uuid, NULL);
706 assert(rc == EOK);
707
708 return EOK;
709}
710
711static void gpt_unused_pte(gpt_entry_t *pte)
712{
713 memset(pte, 0, sizeof(gpt_entry_t));
714}
715
716static int gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
717{
718 uint64_t eblock;
719
720 eblock = part->block0 + part->nblocks - 1;
721 if (eblock < part->block0)
722 return EINVAL;
723
724 memset(pte, 0, sizeof(gpt_entry_t));
725 uuid_encode(&part->ptype.t.uuid, pte->part_type);
726 uuid_encode(&part->part_uuid, pte->part_id);
727 pte->start_lba = host2uint64_t_le(part->block0);
728 pte->end_lba = host2uint64_t_le(eblock);
729// pte->attributes
730// pte->part_name
731 return EOK;
732}
733
734static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
735{
736 label_part_t *part;
737 bool present;
738 uint64_t b0, b1;
739 int i;
740
741 present = false;
742 for (i = 0; i < 8; i++)
743 if (pte->part_type[i] != 0x00)
744 present = true;
745
746 if (!present)
747 return EOK;
748
749 part = calloc(1, sizeof(label_part_t));
750 if (part == NULL)
751 return ENOMEM;
752
753 b0 = uint64_t_le2host(pte->start_lba);
754 b1 = uint64_t_le2host(pte->end_lba);
755 if (b1 <= b0)
756 return EINVAL;
757
758 part->index = index;
759 part->block0 = b0;
760 part->nblocks = b1 - b0 + 1;
761 part->ptype.fmt = lptf_uuid;
762 uuid_decode(pte->part_type, &part->ptype.t.uuid);
763 uuid_decode(pte->part_id, &part->part_uuid);
764
765 part->label = label;
766 list_append(&part->lparts, &label->parts);
767 list_append(&part->lpri, &label->pri_parts);
768 return EOK;
769}
770
771/** Update partition table entry at specified index.
772 *
773 * Replace partition entry at index @a index with the contents of
774 * @a pte.
775 */
776static int gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
777{
778 size_t pos;
779 uint64_t ba;
780 uint64_t nblocks;
781 size_t ptbytes;
782 uint8_t *buf;
783 gpt_entry_t *e;
784 uint32_t crc;
785 int i;
786 int rc;
787
788 /* Byte offset of partition entry */
789 pos = index * label->lt.gpt.esize;
790 /* Number of bytes in partition table */
791 ptbytes = label->pri_entries * label->lt.gpt.esize;
792
793 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
794 if (buf == NULL)
795 return ENOMEM;
796
797 /* For both partition tables: read, modify, write */
798 for (i = 0; i < 2; i++) {
799 ba = label->lt.gpt.ptable_ba[i];
800 nblocks = label->lt.gpt.pt_blocks;
801
802 rc = block_read_direct(label->svc_id, ba, nblocks, buf);
803 if (rc != EOK) {
804 rc = EIO;
805 goto error;
806 }
807
808 crc = compute_crc32(buf, ptbytes);
809 if (crc != label->lt.gpt.pt_crc) {
810 /* Corruption detected */
811 rc = EIO;
812 goto error;
813 }
814
815 /* Replace single entry */
816 e = (gpt_entry_t *)(&buf[pos]);
817 *e = *pte;
818
819 rc = block_write_direct(label->svc_id, ba, nblocks, buf);
820 if (rc != EOK) {
821 rc = EIO;
822 goto error;
823 }
824
825 crc = compute_crc32(buf, ptbytes);
826 rc = gpt_update_pt_crc(label, crc);
827 if (rc != EOK) {
828 rc = EIO;
829 goto error;
830 }
831 }
832
833 free(buf);
834 return EOK;
835error:
836 free(buf);
837 return rc;
838}
839
840static int gpt_update_pt_crc(label_t *label, uint32_t crc)
841{
842 gpt_header_t *gpt_hdr;
843 int rc;
844 int i;
845
846 gpt_hdr = calloc(1, label->block_size);
847 if (gpt_hdr == NULL) {
848 rc = ENOMEM;
849 goto error;
850 }
851
852 for (i = 0; i < 2; i++) {
853 rc = block_read_direct(label->svc_id,
854 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
855 if (rc != EOK) {
856 rc = EIO;
857 goto error;
858 }
859
860 gpt_hdr->pe_array_crc32 = host2uint32_t_le(crc);
861 gpt_hdr_compute_crc(gpt_hdr, label->lt.gpt.hdr_size);
862
863 rc = block_write_direct(label->svc_id,
864 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
865 if (rc != EOK) {
866 rc = EIO;
867 goto error;
868 }
869 }
870
871 free(gpt_hdr);
872 return EOK;
873error:
874 return rc;
875}
876
877static void gpt_hdr_compute_crc(gpt_header_t *hdr, size_t hdr_size)
878{
879 uint32_t crc;
880
881 hdr->header_crc32 = 0;
882 crc = compute_crc32((uint8_t *)hdr, hdr_size);
883 hdr->header_crc32 = crc;
884}
885
886static int gpt_hdr_get_crc(gpt_header_t *hdr, size_t hdr_size, uint32_t *crc)
887{
888 gpt_header_t *c;
889
890 c = calloc(1, sizeof(gpt_header_t));
891 if (c == NULL)
892 return ENOMEM;
893
894 memcpy(c, hdr, hdr_size);
895 c->header_crc32 = 0;
896 *crc = compute_crc32((uint8_t *)c, hdr_size);
897 free(c);
898
899 return EOK;
900}
901
902/** @}
903 */
Note: See TracBrowser for help on using the repository browser.