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

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

Information structures need updating to new model.

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