source: mainline/uspace/lib/label/src/mbr.c@ 6ff23ff

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6ff23ff was b7fd2a0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use errno_t in all uspace and kernel code.

Change type of every variable, parameter and return value that holds an
<errno.h> constant to either errno_t (the usual case), or sys_errno_t
(some places in kernel). This is for the purpose of self-documentation,
as well as for type-checking with a bit of type definition hackery.

Although this is a massive commit, it is a simple text replacement, and thus
is very easy to verify. Simply do the following:

`
git checkout <this commit's hash>
git reset HEAD
git add .
tools/srepl '\berrno_t\b' int
git add .
tools/srepl '\bsys_errno_t\b' sysarg_t
git reset
git diff
`

While this doesn't ensure that the replacements are correct, it does ensure
that the commit doesn't do anything except those replacements. Since errno_t
is typedef'd to int in the usual case (and sys_errno_t to sysarg_t), even if
incorrect, this commit cannot change behavior.

  • Property mode set to 100644
File size: 25.7 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 Master Boot Record label
34 */
35
36#include <byteorder.h>
37#include <errno.h>
[1626cd4]38#include <mem.h>
[3faa03d]39#include <stdlib.h>
40
[9e7615d]41#include "std/fat.h"
[3faa03d]42#include "std/mbr.h"
43#include "mbr.h"
44
[b7fd2a0]45static errno_t mbr_open(label_bd_t *, label_t **);
46static errno_t mbr_open_ext(label_t *);
47static errno_t mbr_create(label_bd_t *, label_t **);
[3faa03d]48static void mbr_close(label_t *);
[b7fd2a0]49static errno_t mbr_destroy(label_t *);
50static errno_t mbr_get_info(label_t *, label_info_t *);
[3faa03d]51static label_part_t *mbr_part_first(label_t *);
52static label_part_t *mbr_part_next(label_part_t *);
53static void mbr_part_get_info(label_part_t *, label_part_info_t *);
[b7fd2a0]54static errno_t mbr_part_create(label_t *, label_part_spec_t *, label_part_t **);
55static errno_t mbr_part_destroy(label_part_t *);
56static errno_t mbr_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
[3faa03d]57
[b7fd2a0]58static errno_t mbr_check_free_idx(label_t *, int);
59static errno_t mbr_check_free_pri_range(label_t *, uint64_t, uint64_t);
60static errno_t mbr_check_free_log_range(label_t *, uint64_t, uint64_t, uint64_t);
[d8513177]61
[99c23405]62static void mbr_unused_pte(mbr_pte_t *);
[b7fd2a0]63static errno_t mbr_part_to_pte(label_part_t *, mbr_pte_t *);
64static errno_t mbr_pte_to_part(label_t *, mbr_pte_t *, int);
65static errno_t mbr_pte_to_log_part(label_t *, uint64_t, mbr_pte_t *);
[c02d098]66static void mbr_log_part_to_ptes(label_part_t *, mbr_pte_t *, mbr_pte_t *);
[b7fd2a0]67static errno_t mbr_pte_update(label_t *, mbr_pte_t *, int);
68static errno_t mbr_log_part_insert(label_t *, label_part_t *);
69static errno_t mbr_ebr_create(label_t *, label_part_t *);
70static errno_t mbr_ebr_delete(label_t *, label_part_t *);
71static errno_t mbr_ebr_update_next(label_t *, label_part_t *);
[c02d098]72static void mbr_update_log_indices(label_t *);
[3faa03d]73
74label_ops_t mbr_label_ops = {
75 .open = mbr_open,
76 .create = mbr_create,
77 .close = mbr_close,
78 .destroy = mbr_destroy,
[1626cd4]79 .get_info = mbr_get_info,
[3faa03d]80 .part_first = mbr_part_first,
81 .part_next = mbr_part_next,
82 .part_get_info = mbr_part_get_info,
83 .part_create = mbr_part_create,
[f57ccb5]84 .part_destroy = mbr_part_destroy,
85 .suggest_ptype = mbr_suggest_ptype
[3faa03d]86};
87
[b7fd2a0]88static errno_t mbr_open(label_bd_t *bd, label_t **rlabel)
[3faa03d]89{
90 label_t *label = NULL;
91 mbr_br_block_t *mbr = NULL;
[9e7615d]92 fat_bs_t *bs;
[3faa03d]93 mbr_pte_t *eptr;
94 uint16_t sgn;
95 size_t bsize;
[1626cd4]96 aoff64_t nblocks;
[3faa03d]97 uint32_t entry;
[b7fd2a0]98 errno_t rc;
[3faa03d]99
[deacc58d]100 rc = bd->ops->get_bsize(bd->arg, &bsize);
[3faa03d]101 if (rc != EOK) {
102 rc = EIO;
103 goto error;
104 }
105
[deacc58d]106 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
[1626cd4]107 if (rc != EOK) {
108 rc = EIO;
109 goto error;
110 }
111
[3faa03d]112 if (bsize < 512 || (bsize % 512) != 0) {
113 rc = EINVAL;
114 goto error;
115 }
116
[1626cd4]117 if (nblocks < mbr_ablock0) {
118 rc = EINVAL;
119 goto error;
120 }
121
[3faa03d]122 mbr = calloc(1, bsize);
123 if (mbr == NULL) {
124 rc = ENOMEM;
125 goto error;
126 }
127
[9e7615d]128 bs = (fat_bs_t *)mbr;
129
[deacc58d]130 rc = bd->ops->read(bd->arg, mbr_ba, 1, mbr);
[3faa03d]131 if (rc != EOK) {
132 rc = EIO;
133 goto error;
134 }
135
136 label = calloc(1, sizeof(label_t));
137 if (label == NULL)
138 return ENOMEM;
139
140 list_initialize(&label->parts);
[b7a4d06]141 list_initialize(&label->pri_parts);
142 list_initialize(&label->log_parts);
[3faa03d]143
144 /* Verify boot record signature */
145 sgn = uint16_t_le2host(mbr->signature);
146 if (sgn != mbr_br_signature) {
147 rc = EIO;
148 goto error;
149 }
150
[9e7615d]151 /*
152 * We can't really tell whether this is an MBR. Make sure
[9f64c1e]153 * this is not actually the BR of a 12/16-bit FAT file system
[9e7615d]154 */
155 if (bs->type[0] == 'F' && bs->type[1] == 'A' && bs->type[2] == 'T') {
156 rc = EIO;
157 goto error;
158 }
[c02d098]159
[9f64c1e]160 /*
161 * Or a 32-bit FAT file system
162 */
163 if (bs->fat32.type[0] == 'F' && bs->fat32.type[1] == 'A' &&
164 bs->fat32.type[2] == 'T') {
165 rc = EIO;
166 goto error;
167 }
168
[c02d098]169 label->ext_part = NULL;
[3faa03d]170 for (entry = 0; entry < mbr_nprimary; entry++) {
171 eptr = &mbr->pte[entry];
[1626cd4]172 rc = mbr_pte_to_part(label, eptr, entry + 1);
[3faa03d]173 if (rc != EOK)
174 goto error;
175 }
176
177 free(mbr);
178 mbr = NULL;
179
180 label->ops = &mbr_label_ops;
181 label->ltype = lt_mbr;
[deacc58d]182 label->bd = *bd;
[603c1d1f]183 label->block_size = bsize;
[1626cd4]184 label->ablock0 = mbr_ablock0;
185 label->anblocks = nblocks - mbr_ablock0;
[99c23405]186 label->pri_entries = mbr_nprimary;
[c02d098]187
188 if (label->ext_part != NULL) {
189 /* Open extended partition */
190 rc = mbr_open_ext(label);
191 if (rc != EOK)
192 goto error;
193 }
194
[3faa03d]195 *rlabel = label;
196 return EOK;
197error:
198 free(mbr);
[c02d098]199 mbr_close(label);
200 return rc;
201}
202
203/** Open extended partition */
[b7fd2a0]204static errno_t mbr_open_ext(label_t *label)
[c02d098]205{
206 mbr_br_block_t *ebr = NULL;
207 mbr_pte_t *ethis;
208 mbr_pte_t *enext;
209 uint64_t ebr_b0;
210 uint64_t ebr_nblocks_min;
211 uint64_t ebr_nblocks_max;
212 uint64_t pebr_b0;
213 uint64_t pebr_nblocks;
214 uint64_t pb0;
215 uint64_t pnblocks;
216 uint64_t ep_b0;
[b7fd2a0]217 errno_t rc;
[c02d098]218
219 ebr = calloc(1, label->block_size);
220 if (ebr == NULL) {
221 rc = ENOMEM;
222 goto error;
223 }
224
225 /* First block of extended partition */
226 ep_b0 = label->ext_part->block0;
227
228 /* First block of current EBR */
229 ebr_b0 = label->ext_part->block0;
230
231 /*
232 * We don't have bounds for the first EBR, so for purpose of
233 * verification let's say it contains at least one block and
234 * at most all blocks from the extended partition.
235 */
236 ebr_nblocks_min = 1;
237 ebr_nblocks_max = label->ext_part->nblocks;
238
239 while (true) {
240 /* Read EBR */
[deacc58d]241 rc = label->bd.ops->read(label->bd.arg, ebr_b0, 1, ebr);
[c02d098]242 if (rc != EOK) {
243 rc = EIO;
244 goto error;
245 }
246
247 ethis = &ebr->pte[mbr_ebr_pte_this];
248 enext = &ebr->pte[mbr_ebr_pte_next];
249
250 pb0 = ebr_b0 + uint32_t_le2host(ethis->first_lba);
251 pnblocks = uint32_t_le2host(ethis->length);
252
253 if (ethis->ptype == mbr_pt_unused || pnblocks == 0)
254 break;
255
256 /* Verify partition lies within the range of EBR */
257 if (pb0 + pnblocks > ebr_b0 + ebr_nblocks_max) {
258 rc = EIO;
259 goto error;
260 }
261
262 /* Create partition structure */
263 rc = mbr_pte_to_log_part(label, ebr_b0, ethis);
264 if (rc != EOK) {
[22747e8]265 rc = EIO;
[c02d098]266 goto error;
267 }
268
269 /* Save previous EBR range */
270 pebr_b0 = ebr_b0;
271 pebr_nblocks = ebr_nblocks_min;
272
273 /* Proceed to next EBR */
274 ebr_b0 = ep_b0 + uint32_t_le2host(enext->first_lba);
275 ebr_nblocks_min = uint32_t_le2host(enext->length);
276 ebr_nblocks_max = ebr_nblocks_min;
277
278 if (enext->ptype == mbr_pt_unused || ebr_nblocks_min == 0)
279 break;
280
281 /* Verify next EBR does not overlap this EBR */
282 if (ebr_b0 < pebr_b0 + pebr_nblocks) {
283 rc = EIO;
284 goto error;
285 }
286
287 /* Verify next EBR does not extend beyond end of label */
288 if (ebr_b0 + ebr_nblocks_max > label->ablock0 + label->anblocks) {
289 rc = EIO;
290 goto error;
291 }
292 }
293
294 free(ebr);
295 return EOK;
296error:
297 /* Note that logical partitions need to be deleted by caller */
298 free(ebr);
[3faa03d]299 return rc;
300}
301
[b7fd2a0]302static errno_t mbr_create(label_bd_t *bd, label_t **rlabel)
[3faa03d]303{
[603c1d1f]304 label_t *label = NULL;
305 mbr_br_block_t *mbr = NULL;
306 aoff64_t nblocks;
307 size_t bsize;
308 int i;
[b7fd2a0]309 errno_t rc;
[603c1d1f]310
[deacc58d]311 rc = bd->ops->get_bsize(bd->arg, &bsize);
[603c1d1f]312 if (rc != EOK) {
313 rc = EIO;
314 goto error;
315 }
316
[deacc58d]317 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
[603c1d1f]318 if (rc != EOK) {
319 rc = EIO;
320 goto error;
321 }
322
323 mbr = calloc(1, bsize);
324 if (mbr == NULL) {
325 rc = ENOMEM;
326 goto error;
327 }
328
329 label = calloc(1, sizeof(label_t));
330 if (label == NULL)
331 return ENOMEM;
332
333 list_initialize(&label->parts);
[b7a4d06]334 list_initialize(&label->pri_parts);
335 list_initialize(&label->log_parts);
[603c1d1f]336
337 mbr->media_id = 0;
338 mbr->pad0 = 0;
339 for (i = 0; i < mbr_nprimary; i++)
340 mbr_unused_pte(&mbr->pte[i]);
341 mbr->signature = host2uint16_t_le(mbr_br_signature);
342
[deacc58d]343 rc = bd->ops->write(bd->arg, mbr_ba, 1, mbr);
[603c1d1f]344 if (rc != EOK) {
345 rc = EIO;
346 goto error;
347 }
348
349 free(mbr);
350 mbr = NULL;
351
352 label->ops = &mbr_label_ops;
353 label->ltype = lt_mbr;
354 label->block_size = bsize;
[deacc58d]355 label->bd = *bd;
[603c1d1f]356 label->ablock0 = mbr_ablock0;
357 label->anblocks = nblocks - mbr_ablock0;
358 label->pri_entries = mbr_nprimary;
[c02d098]359 label->ext_part = NULL;
[603c1d1f]360
361 *rlabel = label;
[3faa03d]362 return EOK;
[603c1d1f]363error:
364 free(mbr);
365 free(label);
366 return rc;
[3faa03d]367}
368
369static void mbr_close(label_t *label)
370{
[603c1d1f]371 label_part_t *part;
372
[c02d098]373 if (label == NULL)
374 return;
375
[603c1d1f]376 part = mbr_part_first(label);
377 while (part != NULL) {
[b7a4d06]378 list_remove(&part->lparts);
379 if (link_used(&part->lpri))
380 list_remove(&part->lpri);
381 if (link_used(&part->llog))
382 list_remove(&part->llog);
[603c1d1f]383 free(part);
384
385 part = mbr_part_first(label);
386 }
387
[3faa03d]388 free(label);
389}
390
[b7fd2a0]391static errno_t mbr_destroy(label_t *label)
[3faa03d]392{
[603c1d1f]393 mbr_br_block_t *mbr = NULL;
394 label_part_t *part;
[b7fd2a0]395 errno_t rc;
[603c1d1f]396
397 part = mbr_part_first(label);
398 if (part != NULL) {
399 rc = ENOTEMPTY;
400 goto error;
401 }
402
403 mbr = calloc(1, label->block_size);
404 if (mbr == NULL) {
405 rc = ENOMEM;
406 goto error;
407 }
408
[deacc58d]409 rc = label->bd.ops->write(label->bd.arg, mbr_ba, 1, mbr);
[603c1d1f]410 if (rc != EOK) {
411 rc = EIO;
412 goto error;
413 }
414
415 free(mbr);
416 mbr = NULL;
417
418 free(label);
[3faa03d]419 return EOK;
[603c1d1f]420error:
421 free(mbr);
422 return rc;
[3faa03d]423}
424
[edebb4a1]425static bool mbr_can_delete_part(label_t *label)
426{
427 return list_count(&label->parts) > 0;
428}
429
[b7fd2a0]430static errno_t mbr_get_info(label_t *label, label_info_t *linfo)
[1626cd4]431{
432 memset(linfo, 0, sizeof(label_info_t));
433 linfo->ltype = lt_mbr;
[b7a4d06]434
435 /* We support extended partitions */
436 linfo->flags = lf_ext_supp;
437
438 /** Can create primary if there is a free slot */
439 if (list_count(&label->pri_parts) < mbr_nprimary)
440 linfo->flags |= lf_can_create_pri;
441 /* Can create extended if there is a free slot and no extended */
[c02d098]442 if ((linfo->flags & lf_can_create_pri) != 0 && label->ext_part == NULL)
[b7a4d06]443 linfo->flags |= lf_can_create_ext;
444 /* Can create logical if there is an extended partition */
[c02d098]445 if (label->ext_part != NULL)
[b7a4d06]446 linfo->flags |= lf_can_create_log;
[edebb4a1]447 /* Can delete partition */
448 if (mbr_can_delete_part(label))
449 linfo->flags |= lf_can_delete_part;
[b7a4d06]450
[1626cd4]451 linfo->ablock0 = label->ablock0;
452 linfo->anblocks = label->anblocks;
[b7a4d06]453
[1626cd4]454 return EOK;
455}
456
[3faa03d]457static label_part_t *mbr_part_first(label_t *label)
458{
459 link_t *link;
460
461 link = list_first(&label->parts);
462 if (link == NULL)
463 return NULL;
464
[b7a4d06]465 return list_get_instance(link, label_part_t, lparts);
[3faa03d]466}
467
468static label_part_t *mbr_part_next(label_part_t *part)
469{
470 link_t *link;
471
[b7a4d06]472 link = list_next(&part->lparts, &part->label->parts);
[3faa03d]473 if (link == NULL)
474 return NULL;
475
[b7a4d06]476 return list_get_instance(link, label_part_t, lparts);
[3faa03d]477}
478
[c02d098]479static label_part_t *mbr_log_part_first(label_t *label)
480{
481 link_t *link;
482
483 link = list_first(&label->log_parts);
484 if (link == NULL)
485 return NULL;
486
487 return list_get_instance(link, label_part_t, llog);
488}
489
490static label_part_t *mbr_log_part_next(label_part_t *part)
491{
492 link_t *link;
493
494 link = list_next(&part->llog, &part->label->log_parts);
495 if (link == NULL)
496 return NULL;
497
498 return list_get_instance(link, label_part_t, llog);
499}
500
501static label_part_t *mbr_log_part_prev(label_part_t *part)
502{
503 link_t *link;
504
505 link = list_prev(&part->llog, &part->label->log_parts);
506 if (link == NULL)
507 return NULL;
508
509 return list_get_instance(link, label_part_t, llog);
510}
511
[d8513177]512static label_part_t *mbr_pri_part_first(label_t *label)
513{
514 link_t *link;
515
516 link = list_first(&label->pri_parts);
517 if (link == NULL)
518 return NULL;
519
520 return list_get_instance(link, label_part_t, lpri);
521}
522
523static label_part_t *mbr_pri_part_next(label_part_t *part)
524{
525 link_t *link;
526
527 link = list_next(&part->lpri, &part->label->pri_parts);
528 if (link == NULL)
529 return NULL;
530
531 return list_get_instance(link, label_part_t, lpri);
532}
533
[3faa03d]534static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
535{
[1626cd4]536 pinfo->index = part->index;
[3faa03d]537 pinfo->block0 = part->block0;
538 pinfo->nblocks = part->nblocks;
[b7a4d06]539
540 if (link_used(&part->llog))
541 pinfo->pkind = lpk_logical;
[f57ccb5]542 else if (part->ptype.t.num == mbr_pt_extended)
[b7a4d06]543 pinfo->pkind = lpk_extended;
544 else
545 pinfo->pkind = lpk_primary;
[3faa03d]546}
547
[b7fd2a0]548static errno_t mbr_part_create(label_t *label, label_part_spec_t *pspec,
[3faa03d]549 label_part_t **rpart)
550{
[6bc542b]551 label_part_t *part;
[c02d098]552 label_part_t *prev;
553 label_part_t *next;
[99c23405]554 mbr_pte_t pte;
[b7fd2a0]555 errno_t rc;
[6bc542b]556
[f57ccb5]557 if (pspec->ptype.fmt != lptf_num)
558 return EINVAL;
559
[6bc542b]560 part = calloc(1, sizeof(label_part_t));
561 if (part == NULL)
562 return ENOMEM;
563
[99c23405]564 /* XXX Check if index is used */
565 part->label = label;
[6bc542b]566 part->index = pspec->index;
567 part->block0 = pspec->block0;
568 part->nblocks = pspec->nblocks;
[c02d098]569 part->hdr_blocks = pspec->hdr_blocks;
[6bc542b]570
[b7a4d06]571 switch (pspec->pkind) {
572 case lpk_primary:
573 part->ptype = pspec->ptype;
574 break;
575 case lpk_extended:
[f57ccb5]576 part->ptype.fmt = lptf_num;
577 part->ptype.t.num = mbr_pt_extended;
578 if (pspec->ptype.t.num != 0) {
[b7a4d06]579 rc = EINVAL;
580 goto error;
581 }
[c02d098]582 if (label->ext_part != NULL) {
[ff381a7]583 rc = EEXIST;
[b7a4d06]584 goto error;
585 }
586 break;
587 case lpk_logical:
588 part->ptype = pspec->ptype;
589 if (pspec->index != 0) {
590 rc = EINVAL;
591 goto error;
592 }
593 break;
[99c23405]594 }
595
[b7a4d06]596 if (pspec->pkind != lpk_logical) {
597 /* Primary or extended partition */
598
[d8513177]599 /* Verify index is within bounds and free */
600 rc = mbr_check_free_idx(label, pspec->index);
601 if (rc != EOK) {
602 rc = EINVAL;
603 goto error;
604 }
605
606 /* Verify range is within bounds and free */
607 rc = mbr_check_free_pri_range(label, pspec->block0, pspec->nblocks);
608 if (rc != EOK) {
[b7a4d06]609 rc = EINVAL;
610 goto error;
611 }
612
[c02d098]613 if (pspec->hdr_blocks != 0) {
614 rc = EINVAL;
615 goto error;
616 }
617
[b7a4d06]618 rc = mbr_part_to_pte(part, &pte);
619 if (rc != EOK) {
620 rc = EINVAL;
621 goto error;
622 }
623
624 rc = mbr_pte_update(label, &pte, pspec->index - 1);
625 if (rc != EOK) {
626 rc = EIO;
627 goto error;
628 }
629
[d8513177]630 if (pspec->pkind == lpk_extended) {
631 label->ext_part = part;
632
633 /* Create EBR for empty partition chain */
634 rc = mbr_ebr_create(label, NULL);
635 if (rc != EOK) {
636 label->ext_part = NULL;
637 rc = EIO;
638 goto error;
639 }
640 }
641
[b7a4d06]642 list_append(&part->lparts, &label->parts);
643 list_append(&part->lpri, &label->pri_parts);
644 } else {
[d8513177]645 /* Verify range is within bounds and free */
646 rc = mbr_check_free_log_range(label, pspec->hdr_blocks,
647 pspec->block0, pspec->nblocks);
648 if (rc != EOK) {
649 rc = EINVAL;
650 goto error;
651 }
652
[b7a4d06]653 /* Logical partition */
[c02d098]654 rc = mbr_log_part_insert(label, part);
655 if (rc != EOK)
656 goto error;
657
658 /* Create EBR for new partition */
659 rc = mbr_ebr_create(label, part);
660 if (rc != EOK)
661 goto error;
662
663 prev = mbr_log_part_prev(part);
664 if (prev != NULL) {
665 /* Update 'next' PTE in EBR of previous partition */
666 rc = mbr_ebr_update_next(label, prev);
667 if (rc != EOK) {
668 goto error;
669 }
670 } else {
671 /* New partition is now the first one */
672 next = mbr_log_part_next(part);
673 if (next != NULL) {
674 /*
675 * Create new, relocated EBR for the former
676 * first partition
677 */
678 next->hdr_blocks = pspec->hdr_blocks;
679 rc = mbr_ebr_create(label, next);
680 if (rc != EOK)
681 goto error;
682 }
683 }
684
685 /* This also sets index for the new partition. */
686 mbr_update_log_indices(label);
[99c23405]687 }
688
[6bc542b]689 *rpart = part;
690 return EOK;
[99c23405]691error:
692 free(part);
693 return rc;
[3faa03d]694}
695
[b7fd2a0]696static errno_t mbr_part_destroy(label_part_t *part)
[3faa03d]697{
[99c23405]698 mbr_pte_t pte;
[c02d098]699 label_part_t *prev;
[22747e8]700 label_part_t *next;
701 uint64_t ep_b0;
[b7fd2a0]702 errno_t rc;
[99c23405]703
[c02d098]704 if (link_used(&part->lpri)) {
705 /* Primary/extended partition */
[99c23405]706
[c02d098]707 /* Prepare unused partition table entry */
708 mbr_unused_pte(&pte);
[99c23405]709
[c02d098]710 /* Modify partition table */
711 rc = mbr_pte_update(part->label, &pte, part->index - 1);
712 if (rc != EOK)
713 return EIO;
714
715 /* If it was the extended partition, clear ext. part. pointer */
716 if (part == part->label->ext_part)
717 part->label->ext_part = NULL;
[b7a4d06]718
719 list_remove(&part->lpri);
[c02d098]720 } else {
721 /* Logical partition */
722
723 prev = mbr_log_part_prev(part);
724 if (prev != NULL) {
725 /* Update next link in previous EBR */
726 list_remove(&part->llog);
727
728 rc = mbr_ebr_update_next(part->label, prev);
729 if (rc != EOK) {
730 /* Roll back */
731 list_insert_after(&part->llog, &prev->llog);
732 return EIO;
733 }
[22747e8]734
735 /* Delete EBR */
736 rc = mbr_ebr_delete(part->label, part);
737 if (rc != EOK)
738 return EIO;
[c02d098]739 } else {
[22747e8]740 next = mbr_log_part_next(part);
[c02d098]741 list_remove(&part->llog);
742
[22747e8]743 if (next != NULL) {
744 /*
[83dd743]745 * Relocate next partition's EBR to the beginning
746 * of the extended partition. This also
747 * overwrites the EBR of the former first
748 * partition.
[22747e8]749 */
750
751 /* First block of extended partition */
752 ep_b0 = part->label->ext_part->block0;
753
754 next->hdr_blocks = next->block0 - ep_b0;
755
756 rc = mbr_ebr_create(part->label, next);
757 if (rc != EOK) {
758 list_prepend(&part->llog, &part->label->log_parts);
759 return EIO;
760 }
761 } else {
762 /* Delete EBR */
763 rc = mbr_ebr_delete(part->label, part);
764 if (rc != EOK)
765 return EIO;
766 }
767 }
[100b1d1]768
769 /* Update indices */
770 mbr_update_log_indices(part->label);
[c02d098]771 }
772
773 list_remove(&part->lparts);
[99c23405]774 free(part);
775 return EOK;
776}
777
[b7fd2a0]778static errno_t mbr_suggest_ptype(label_t *label, label_pcnt_t pcnt,
[f57ccb5]779 label_ptype_t *ptype)
780{
781 ptype->fmt = lptf_num;
782 ptype->t.num = 0;
783
784 switch (pcnt) {
785 case lpc_exfat:
786 ptype->t.num = mbr_pt_ms_advanced;
787 break;
788 case lpc_ext4:
789 ptype->t.num = mbr_pt_linux;
790 break;
791 case lpc_fat12_16:
792 ptype->t.num = mbr_pt_fat16_lba;
793 break;
794 case lpc_fat32:
795 ptype->t.num = mbr_pt_fat32_lba;
796 break;
797 case lpc_minix:
798 ptype->t.num = mbr_pt_minix;
799 break;
800 }
801
802 if (ptype->t.num == 0)
803 return EINVAL;
804
805 return EOK;
806}
807
[d8513177]808/** Determine if two block address ranges overlap. */
809static bool mbr_overlap(uint64_t a0, uint64_t an, uint64_t b0, uint64_t bn)
810{
811 return !(a0 + an <= b0 || b0 + bn <= a0);
812}
813
814/** Verify that the specified index is valid and free. */
[b7fd2a0]815static errno_t mbr_check_free_idx(label_t *label, int index)
[d8513177]816{
817 label_part_t *part;
818
819 if (index < 1 || index > label->pri_entries)
820 return EINVAL;
821
822 part = mbr_pri_part_first(label);
823 while (part != NULL) {
824 if (part->index == index)
825 return EEXIST;
826 part = mbr_pri_part_next(part);
827 }
828
829 return EOK;
830}
831
[b7fd2a0]832static errno_t mbr_check_free_pri_range(label_t *label, uint64_t block0,
[d8513177]833 uint64_t nblocks)
834{
835 label_part_t *part;
836
837 if (block0 < label->ablock0)
838 return EINVAL;
839 if (block0 + nblocks > label->ablock0 + label->anblocks)
840 return EINVAL;
841
842 part = mbr_pri_part_first(label);
843 while (part != NULL) {
844 if (mbr_overlap(block0, nblocks, part->block0, part->nblocks))
845 return EEXIST;
846 part = mbr_pri_part_next(part);
847 }
848
849 return EOK;
850}
851
[b7fd2a0]852static errno_t mbr_check_free_log_range(label_t *label, uint64_t hdr_blocks,
[d8513177]853 uint64_t block0, uint64_t nblocks)
854{
855 label_part_t *part;
856
857 if (block0 - hdr_blocks < label->ext_part->block0)
858 return EINVAL;
859 if (block0 + nblocks > label->ext_part->block0 + label->ext_part->nblocks)
860 return EINVAL;
861
862 part = mbr_log_part_first(label);
863 while (part != NULL) {
864 if (mbr_overlap(block0 - hdr_blocks, nblocks + hdr_blocks,
865 part->block0 - part->hdr_blocks, part->nblocks + part->hdr_blocks))
866 return EEXIST;
867 part = mbr_log_part_next(part);
868 }
869
870 return EOK;
871}
872
[f57ccb5]873
[99c23405]874static void mbr_unused_pte(mbr_pte_t *pte)
875{
876 memset(pte, 0, sizeof(mbr_pte_t));
877}
878
[b7fd2a0]879static errno_t mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
[99c23405]880{
881 if ((part->block0 >> 32) != 0)
882 return EINVAL;
883 if ((part->nblocks >> 32) != 0)
884 return EINVAL;
[f57ccb5]885 if ((part->ptype.t.num >> 8) != 0)
[99c23405]886 return EINVAL;
887
888 memset(pte, 0, sizeof(mbr_pte_t));
[f57ccb5]889 pte->ptype = part->ptype.t.num;
[99c23405]890 pte->first_lba = host2uint32_t_le(part->block0);
891 pte->length = host2uint32_t_le(part->nblocks);
892 return EOK;
[3faa03d]893}
894
[b7fd2a0]895static errno_t mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
[3faa03d]896{
897 label_part_t *part;
898 uint32_t block0;
899 uint32_t nblocks;
900
901 block0 = uint32_t_le2host(pte->first_lba);
902 nblocks = uint32_t_le2host(pte->length);
903
904 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
[b7a4d06]905 if (pte->ptype == mbr_pt_unused || nblocks == 0)
[3faa03d]906 return EOK;
907
908 part = calloc(1, sizeof(label_part_t));
909 if (part == NULL)
910 return ENOMEM;
911
[f57ccb5]912 part->ptype.fmt = lptf_num;
913 part->ptype.t.num = pte->ptype;
[1626cd4]914 part->index = index;
[3faa03d]915 part->block0 = block0;
916 part->nblocks = nblocks;
917
918 /*
919 * TODO: Verify
920 * - partition must reside on disk
921 * - partition must not overlap any other partition
922 */
923
924 part->label = label;
[b7a4d06]925 list_append(&part->lparts, &label->parts);
926 list_append(&part->lpri, &label->pri_parts);
927
928 if (pte->ptype == mbr_pt_extended)
[c02d098]929 label->ext_part = part;
930 return EOK;
931}
932
[b7fd2a0]933static errno_t mbr_pte_to_log_part(label_t *label, uint64_t ebr_b0,
[c02d098]934 mbr_pte_t *pte)
935{
936 label_part_t *part;
937 uint32_t block0;
938 uint32_t nblocks;
939 size_t nlparts;
940
941 block0 = ebr_b0 + uint32_t_le2host(pte->first_lba);
942 nblocks = uint32_t_le2host(pte->length);
943
944 if (pte->ptype == mbr_pt_unused || nblocks == 0)
945 return EOK;
946
947 part = calloc(1, sizeof(label_part_t));
948 if (part == NULL)
949 return ENOMEM;
950
951 nlparts = list_count(&label->log_parts);
952
[f57ccb5]953 part->ptype.fmt = lptf_num;
954 part->ptype.t.num = pte->ptype;
[c02d098]955 part->index = mbr_nprimary + 1 + nlparts;
956 part->block0 = block0;
957 part->nblocks = nblocks;
[100b1d1]958 part->hdr_blocks = block0 - ebr_b0;
[c02d098]959
960 part->label = label;
961 list_append(&part->lparts, &label->parts);
962 list_append(&part->llog, &label->log_parts);
963
[3faa03d]964 return EOK;
965}
[22747e8]966
[c02d098]967static void mbr_log_part_to_ptes(label_part_t *part, mbr_pte_t *pthis,
968 mbr_pte_t *pnext)
969{
970 label_part_t *next;
971 uint64_t ep_b0;
972 uint64_t totsize;
973
974 /* First block of extended partition */
975 ep_b0 = part->label->ext_part->block0;
976
977 assert(link_used(&part->llog));
978 assert(part->block0 >= ep_b0);
979 assert(part->hdr_blocks <= part->block0 - ep_b0);
980
981 /* 'This' EBR entry */
982 if (pthis != NULL) {
983 memset(pthis, 0, sizeof(mbr_pte_t));
[f57ccb5]984 pthis->ptype = part->ptype.t.num;
[c02d098]985 pthis->first_lba = host2uint32_t_le(part->hdr_blocks);
986 pthis->length = host2uint32_t_le(part->nblocks);
987 }
988
989 /* 'Next' EBR entry */
990 if (pnext != NULL) {
[22747e8]991 next = mbr_log_part_next(part);
[c02d098]992
993 memset(pnext, 0, sizeof(mbr_pte_t));
994 if (next != NULL) {
995 /* Total size of EBR + partition */
996 totsize = next->hdr_blocks + next->nblocks;
997
998 pnext->ptype = mbr_pt_extended;
999 pnext->first_lba = host2uint32_t_le(next->block0 -
1000 next->hdr_blocks - ep_b0);
1001 pnext->length = host2uint32_t_le(totsize);
1002 }
1003 }
1004}
[3faa03d]1005
[99c23405]1006/** Update partition table entry at specified index.
1007 *
1008 * Replace partition entry at index @a index with the contents of
1009 * @a pte.
1010 */
[b7fd2a0]1011static errno_t mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
[99c23405]1012{
1013 mbr_br_block_t *br;
[b7fd2a0]1014 errno_t rc;
[99c23405]1015
1016 br = calloc(1, label->block_size);
1017 if (br == NULL)
1018 return ENOMEM;
1019
[deacc58d]1020 rc = label->bd.ops->read(label->bd.arg, mbr_ba, 1, br);
[99c23405]1021 if (rc != EOK) {
1022 rc = EIO;
1023 goto error;
1024 }
1025
1026 br->pte[index] = *pte;
1027
[deacc58d]1028 rc = label->bd.ops->write(label->bd.arg, mbr_ba, 1, br);
[99c23405]1029 if (rc != EOK) {
1030 rc = EIO;
1031 goto error;
1032 }
1033
1034 free(br);
1035 return EOK;
1036error:
1037 free(br);
1038 return rc;
1039}
1040
[c02d098]1041/** Insert logical partition into logical partition list. */
[b7fd2a0]1042static errno_t mbr_log_part_insert(label_t *label, label_part_t *part)
[c02d098]1043{
1044 label_part_t *cur;
1045
1046 cur = mbr_log_part_first(label);
1047 while (cur != NULL) {
1048 if (cur->block0 + cur->nblocks > part->block0)
1049 break;
1050 cur = mbr_log_part_next(part);
1051 }
1052
1053 if (cur != NULL)
1054 list_insert_before(&part->llog, &cur->llog);
1055 else
1056 list_append(&part->llog, &label->log_parts);
1057
1058 return EOK;
1059}
1060
[d8513177]1061/** Create EBR for partition.
1062 *
1063 * @param label Label
1064 * @param part Partition for which to create EBR or @c NULL to create
1065 * EBR for empty partition chain
1066 * @return EOK on success or non-zero error code
1067 */
[b7fd2a0]1068static errno_t mbr_ebr_create(label_t *label, label_part_t *part)
[c02d098]1069{
1070 mbr_br_block_t *br;
1071 uint64_t ba;
[b7fd2a0]1072 errno_t rc;
[c02d098]1073
1074 br = calloc(1, label->block_size);
1075 if (br == NULL)
1076 return ENOMEM;
1077
[d8513177]1078 if (part != NULL) {
1079 ba = part->block0 - part->hdr_blocks;
1080 mbr_log_part_to_ptes(part, &br->pte[mbr_ebr_pte_this],
1081 &br->pte[mbr_ebr_pte_next]);
1082 } else {
1083 ba = label->ext_part->block0;
1084 }
[c02d098]1085
[d8513177]1086 br->signature = host2uint16_t_le(mbr_br_signature);
[c02d098]1087
[deacc58d]1088 rc = label->bd.ops->write(label->bd.arg, ba, 1, br);
[c02d098]1089 if (rc != EOK) {
1090 rc = EIO;
1091 goto error;
1092 }
1093
1094 free(br);
1095 return EOK;
1096error:
1097 free(br);
1098 return rc;
1099}
1100
[b7fd2a0]1101static errno_t mbr_ebr_delete(label_t *label, label_part_t *part)
[c02d098]1102{
1103 mbr_br_block_t *br;
1104 uint64_t ba;
[b7fd2a0]1105 errno_t rc;
[c02d098]1106
1107 br = calloc(1, label->block_size);
1108 if (br == NULL)
1109 return ENOMEM;
1110
1111 ba = part->block0 - part->hdr_blocks;
1112
[deacc58d]1113 rc = label->bd.ops->write(label->bd.arg, ba, 1, br);
[c02d098]1114 if (rc != EOK) {
1115 rc = EIO;
1116 goto error;
1117 }
1118
1119 free(br);
1120 return EOK;
1121error:
1122 free(br);
1123 return rc;
1124}
1125
1126/** Update 'next' PTE in EBR of partition. */
[b7fd2a0]1127static errno_t mbr_ebr_update_next(label_t *label, label_part_t *part)
[c02d098]1128{
1129 mbr_br_block_t *br;
1130 uint64_t ba;
1131 uint16_t sgn;
[b7fd2a0]1132 errno_t rc;
[c02d098]1133
1134 ba = part->block0 - part->hdr_blocks;
1135
1136 br = calloc(1, label->block_size);
1137 if (br == NULL)
1138 return ENOMEM;
1139
[deacc58d]1140 rc = label->bd.ops->read(label->bd.arg, ba, 1, br);
[c02d098]1141 if (rc != EOK) {
1142 rc = EIO;
1143 goto error;
1144 }
1145
1146 /* Verify boot record signature */
1147 sgn = uint16_t_le2host(br->signature);
1148 if (sgn != mbr_br_signature) {
1149 rc = EIO;
1150 goto error;
1151 }
1152
1153 mbr_log_part_to_ptes(part, NULL, &br->pte[mbr_ebr_pte_next]);
1154
[deacc58d]1155 rc = label->bd.ops->write(label->bd.arg, ba, 1, br);
[c02d098]1156 if (rc != EOK) {
1157 rc = EIO;
1158 goto error;
1159 }
1160
1161 free(br);
1162 return EOK;
1163error:
1164 free(br);
1165 return rc;
1166}
1167
1168/** Update indices of logical partitions.
1169 *
1170 * Logical partition indices are unstable, i.e. they can change during
1171 * the lifetime of a logical partition. Since the index corresponds to the
1172 * position of the partition in order of block address, anytime a partition
1173 * is created or deleted, indices of all partitions at higher addresses
1174 * change.
1175 */
1176static void mbr_update_log_indices(label_t *label)
1177{
1178 label_part_t *part;
1179 int idx;
1180
1181 idx = mbr_nprimary + 1;
1182
1183 part = mbr_log_part_first(label);
1184 while (part != NULL) {
1185 part->index = idx++;
1186 part = mbr_log_part_next(part);
1187 }
1188}
1189
[3faa03d]1190/** @}
1191 */
Note: See TracBrowser for help on using the repository browser.