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

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

Set partition type based on selected filesystem type.

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