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
RevLine 
[3faa03d]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
[bf7ddde]36#include <adt/checksum.h>
[3faa03d]37#include <block.h>
38#include <byteorder.h>
39#include <errno.h>
[1626cd4]40#include <mem.h>
[3faa03d]41#include <stdlib.h>
[70815a24]42#include <uuid.h>
[3faa03d]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 *);
[1626cd4]51static int gpt_get_info(label_t *, label_info_t *);
[3faa03d]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 *);
[f57ccb5]57static int gpt_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
[3faa03d]58
[99c23405]59static void gpt_unused_pte(gpt_entry_t *);
60static int gpt_part_to_pte(label_part_t *, gpt_entry_t *);
[1626cd4]61static int gpt_pte_to_part(label_t *, gpt_entry_t *, int);
[99c23405]62static int gpt_pte_update(label_t *, gpt_entry_t *, int);
[3faa03d]63
[bf7ddde]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
[3faa03d]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,
[1626cd4]78 .get_info = gpt_get_info,
[3faa03d]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,
[f57ccb5]83 .part_destroy = gpt_part_destroy,
84 .suggest_ptype = gpt_suggest_ptype
[3faa03d]85};
86
87static int gpt_open(service_id_t sid, label_t **rlabel)
88{
89 label_t *label = NULL;
[99c23405]90 gpt_header_t *gpt_hdr[2];
[3faa03d]91 gpt_entry_t *eptr;
[bf7ddde]92 uint8_t *etable[2];
[3faa03d]93 size_t bsize;
94 uint32_t num_entries;
95 uint32_t esize;
[bf7ddde]96 uint32_t pt_blocks;
[99c23405]97 uint64_t ptba[2];
98 uint64_t h1ba;
[3faa03d]99 uint32_t entry;
[bf7ddde]100 uint32_t pt_crc;
[1626cd4]101 uint64_t ba_min, ba_max;
[bf7ddde]102 uint32_t hdr_size;
103 uint32_t hdr_crc;
[99c23405]104 int i, j;
[3faa03d]105 int rc;
106
[99c23405]107 gpt_hdr[0] = NULL;
108 gpt_hdr[1] = NULL;
[bf7ddde]109 etable[0] = NULL;
110 etable[1] = NULL;
[99c23405]111
[3faa03d]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
[99c23405]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) {
[3faa03d]131 rc = ENOMEM;
132 goto error;
133 }
134
[603c1d1f]135 rc = block_read_direct(sid, gpt_hdr_ba, 1, gpt_hdr[0]);
[99c23405]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]);
[3faa03d]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);
[b7a4d06]154 list_initialize(&label->pri_parts);
155 list_initialize(&label->log_parts);
[3faa03d]156
[99c23405]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 }
[3faa03d]163 }
164 }
165
[bf7ddde]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
[99c23405]211 num_entries = uint32_t_le2host(gpt_hdr[0]->num_entries);
212 esize = uint32_t_le2host(gpt_hdr[0]->entry_size);
[bf7ddde]213 pt_blocks = (num_entries * esize + bsize - 1) / bsize;
[99c23405]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);
[bf7ddde]218 pt_crc = uint32_t_le2host(gpt_hdr[0]->pe_array_crc32);
[3faa03d]219
[bf7ddde]220 if (uint64_t_le2host(gpt_hdr[1]->first_usable_lba) != ba_min) {
[3faa03d]221 rc = EINVAL;
222 goto error;
223 }
224
[bf7ddde]225 if (uint64_t_le2host(gpt_hdr[1]->last_usable_lba) != ba_max) {
[3faa03d]226 rc = EINVAL;
227 goto error;
228 }
229
[bf7ddde]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) {
[1626cd4]238 rc = EINVAL;
239 goto error;
240 }
241
[bf7ddde]242 if (uint32_t_le2host(gpt_hdr[1]->entry_size) != esize) {
243 rc = EINVAL;
[3faa03d]244 goto error;
245 }
246
[bf7ddde]247 if (num_entries < 1) {
248 rc = EINVAL;
[3faa03d]249 goto error;
250 }
251
[bf7ddde]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;
[3faa03d]274 goto error;
[bf7ddde]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 }
[3faa03d]288 }
289
[bf7ddde]290 free(etable[0]);
291 etable[0] = NULL;
292 free(etable[1]);
293 etable[1] = NULL;
[99c23405]294 free(gpt_hdr[0]);
295 gpt_hdr[0] = NULL;
296 free(gpt_hdr[1]);
297 gpt_hdr[1] = NULL;
[3faa03d]298
299 label->ops = &gpt_label_ops;
300 label->ltype = lt_gpt;
[603c1d1f]301 label->svc_id = sid;
[1626cd4]302 label->ablock0 = ba_min;
303 label->anblocks = ba_max - ba_min + 1;
[99c23405]304 label->pri_entries = num_entries;
305 label->block_size = bsize;
306
[603c1d1f]307 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
308 label->lt.gpt.hdr_ba[1] = h1ba;
[99c23405]309 label->lt.gpt.ptable_ba[0] = ptba[0];
310 label->lt.gpt.ptable_ba[1] = ptba[1];
311 label->lt.gpt.esize = esize;
[bf7ddde]312 label->lt.gpt.pt_blocks = pt_blocks;
313 label->lt.gpt.pt_crc = pt_crc;
314 label->lt.gpt.hdr_size = hdr_size;
[99c23405]315
[3faa03d]316 *rlabel = label;
317 return EOK;
318error:
[bf7ddde]319 free(etable[0]);
320 free(etable[1]);
[99c23405]321 free(gpt_hdr[0]);
322 free(gpt_hdr[1]);
[3faa03d]323 free(label);
324 return rc;
325}
326
327static int gpt_create(service_id_t sid, label_t **rlabel)
328{
[603c1d1f]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;
[bf7ddde]341 uint32_t pt_crc;
[70815a24]342 uuid_t disk_uuid;
[603c1d1f]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
[0bde8523]373 uuid_generate(&disk_uuid);
374
[603c1d1f]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++) {
[bf7ddde]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
[603c1d1f]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));
[bf7ddde]414 gpt_hdr->header_crc32 = 0;
[603c1d1f]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);
[70815a24]419 uuid_encode(&disk_uuid, gpt_hdr->disk_guid);
[603c1d1f]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);
[bf7ddde]423 gpt_hdr->pe_array_crc32 = pt_crc;
424
425 gpt_hdr_compute_crc(gpt_hdr, sizeof(gpt_header_t));
[603c1d1f]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);
[b7a4d06]442 list_initialize(&label->pri_parts);
443 list_initialize(&label->log_parts);
[603c1d1f]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;
[bf7ddde]458 label->lt.gpt.pt_blocks = pt_blocks;
459 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
[603c1d1f]460
461 *rlabel = label;
[3faa03d]462 return EOK;
[603c1d1f]463error:
464 free(etable);
465 free(gpt_hdr);
466 free(label);
467 return rc;
[3faa03d]468}
469
470static void gpt_close(label_t *label)
471{
[603c1d1f]472 label_part_t *part;
473
474 part = gpt_part_first(label);
475 while (part != NULL) {
[b7a4d06]476 list_remove(&part->lparts);
477 list_remove(&part->lpri);
[603c1d1f]478 free(part);
479 part = gpt_part_first(label);
480 }
481
[3faa03d]482 free(label);
483}
484
485static int gpt_destroy(label_t *label)
486{
[603c1d1f]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
[bf7ddde]516 etable = calloc(1, label->lt.gpt.pt_blocks *
517 label->block_size);
[603c1d1f]518 if (etable == NULL) {
519 rc = ENOMEM;
520 goto error;
521 }
522
523 rc = block_write_direct(label->svc_id,
[bf7ddde]524 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
525 etable);
[603c1d1f]526 if (rc != EOK) {
527 rc = EIO;
528 goto error;
529 }
530
531 free(etable);
532 etable = 0;
533 }
534
535 free(label);
[3faa03d]536 return EOK;
[603c1d1f]537error:
538 return rc;
[3faa03d]539}
540
[b7a4d06]541static bool gpt_can_create_pri(label_t *label)
542{
543 return list_count(&label->parts) < (size_t)label->pri_entries;
544}
545
[1626cd4]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;
[f57ccb5]550 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
[b7a4d06]551 if (gpt_can_create_pri(label))
552 linfo->flags = linfo->flags | lf_can_create_pri;
[1626cd4]553 linfo->ablock0 = label->ablock0;
554 linfo->anblocks = label->anblocks;
555 return EOK;
556}
557
[3faa03d]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
[b7a4d06]566 return list_get_instance(link, label_part_t, lparts);
[3faa03d]567}
568
569static label_part_t *gpt_part_next(label_part_t *part)
570{
571 link_t *link;
572
[b7a4d06]573 link = list_next(&part->lparts, &part->label->parts);
[3faa03d]574 if (link == NULL)
575 return NULL;
576
[b7a4d06]577 return list_get_instance(link, label_part_t, lparts);
[3faa03d]578}
579
580static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
581{
[1626cd4]582 pinfo->index = part->index;
[b7a4d06]583 pinfo->pkind = lpk_primary;
[3faa03d]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{
[6bc542b]591 label_part_t *part;
[99c23405]592 gpt_entry_t pte;
593 int rc;
[6bc542b]594
595 part = calloc(1, sizeof(label_part_t));
[99c23405]596 if (part == NULL) {
597 rc = ENOMEM;
598 goto error;
599 }
[6bc542b]600
601 /* XXX Verify index, block0, nblocks */
602
[99c23405]603 if (pspec->index < 1 || pspec->index > label->pri_entries) {
604 rc = EINVAL;
605 goto error;
606 }
607
[b7a4d06]608 /* GPT only has primary partitions */
609 if (pspec->pkind != lpk_primary) {
610 rc = EINVAL;
611 goto error;
612 }
613
[f57ccb5]614 /* Partition type must be in UUID format */
615 if (pspec->ptype.fmt != lptf_uuid) {
616 rc = EINVAL;
617 goto error;
618 }
619
[99c23405]620 /* XXX Check if index is used */
621
622 part->label = label;
[6bc542b]623 part->index = pspec->index;
624 part->block0 = pspec->block0;
625 part->nblocks = pspec->nblocks;
[99c23405]626 part->ptype = pspec->ptype;
[70815a24]627 uuid_generate(&part->part_uuid);
[99c23405]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 }
[6bc542b]635
[99c23405]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 }
[6bc542b]642
[b7a4d06]643 list_append(&part->lparts, &label->parts);
644 list_append(&part->lpri, &label->pri_parts);
[6bc542b]645
646 *rpart = part;
647 return EOK;
[99c23405]648error:
649 free(part);
650 return rc;
[3faa03d]651}
652
653static int gpt_part_destroy(label_part_t *part)
654{
[99c23405]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
[b7a4d06]666 list_remove(&part->lparts);
667 list_remove(&part->lpri);
[99c23405]668 free(part);
669 return EOK;
670}
671
[f57ccb5]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
[99c23405]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));
[f57ccb5]718 uuid_encode(&part->ptype.t.uuid, pte->part_type);
[70815a24]719 uuid_encode(&part->part_uuid, pte->part_id);
[99c23405]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;
[3faa03d]725}
726
[1626cd4]727static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
[3faa03d]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
[1626cd4]751 part->index = index;
[3faa03d]752 part->block0 = b0;
753 part->nblocks = b1 - b0 + 1;
[f57ccb5]754 part->ptype.fmt = lptf_uuid;
755 uuid_decode(pte->part_type, &part->ptype.t.uuid);
[70815a24]756 uuid_decode(pte->part_id, &part->part_uuid);
[3faa03d]757
758 part->label = label;
[b7a4d06]759 list_append(&part->lparts, &label->parts);
760 list_append(&part->lpri, &label->pri_parts);
[3faa03d]761 return EOK;
762}
763
[99c23405]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;
[bf7ddde]773 uint64_t nblocks;
774 size_t ptbytes;
[99c23405]775 uint8_t *buf;
776 gpt_entry_t *e;
[bf7ddde]777 uint32_t crc;
[99c23405]778 int i;
779 int rc;
780
[bf7ddde]781 /* Byte offset of partition entry */
[99c23405]782 pos = index * label->lt.gpt.esize;
[bf7ddde]783 /* Number of bytes in partition table */
784 ptbytes = label->pri_entries * label->lt.gpt.esize;
[99c23405]785
[bf7ddde]786 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
[99c23405]787 if (buf == NULL)
788 return ENOMEM;
789
790 /* For both partition tables: read, modify, write */
791 for (i = 0; i < 2; i++) {
[bf7ddde]792 ba = label->lt.gpt.ptable_ba[i];
793 nblocks = label->lt.gpt.pt_blocks;
[99c23405]794
[bf7ddde]795 rc = block_read_direct(label->svc_id, ba, nblocks, buf);
[99c23405]796 if (rc != EOK) {
797 rc = EIO;
798 goto error;
799 }
800
[bf7ddde]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
[99c23405]808 /* Replace single entry */
[bf7ddde]809 e = (gpt_entry_t *)(&buf[pos]);
[99c23405]810 *e = *pte;
811
[bf7ddde]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);
[99c23405]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
[bf7ddde]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
[3faa03d]895/** @}
896 */
Note: See TracBrowser for help on using the repository browser.