source: mainline/uspace/lib/mbr/libmbr.c@ 1c8bfe8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1c8bfe8 was 1c8bfe8, checked in by Dominik Taborsky (AT DOT) <brembyseznamcz>, 12 years ago

GPT updates

  • Property mode set to 100644
File size: 21.6 KB
RevLine 
[d3a92c87]1/*
[5beb1ff]2 * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
[d3a92c87]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.
[271e24a]14 * - The LIBMBR_NAME of the author may not be used to endorse or promote products
[d3a92c87]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 libmbr
30 * @{
31 */
32/** @file MBR extraxtion library
33 */
34
35#include <async.h>
[8f6c7785]36#include <assert.h>
[d3a92c87]37#include <block.h>
[8f6c7785]38#include <byteorder.h>
[d3a92c87]39#include <errno.h>
[8f6c7785]40#include <ipc/bd.h>
41#include <mem.h>
42#include <stdio.h>
[d3a92c87]43#include <stdlib.h>
44
45#include "libmbr.h"
46
47static br_block_t * alloc_br(void);
[a2aa81cb]48static int decode_part(pt_entry_t *, mbr_part_t *, uint32_t);
49static int decode_logical(mbr_label_t *, mbr_part_t *);
50static void encode_part(mbr_part_t *, pt_entry_t *, uint32_t, bool);
51static int check_overlap(mbr_part_t *, mbr_part_t *);
52static int check_encaps(mbr_part_t *, mbr_part_t *);
53static int check_preceeds(mbr_part_t *, mbr_part_t *);
[6e8e4e19]54static mbr_err_val mbr_add_primary(mbr_label_t *label, mbr_part_t *p);
55static mbr_err_val mbr_add_logical(mbr_label_t *label, mbr_part_t *p);
[a2aa81cb]56
57/** Allocate and initialize mbr_label_t structure */
58mbr_label_t * mbr_alloc_label(void)
59{
60 mbr_label_t *label = malloc(sizeof(mbr_label_t));
61 if (label == NULL)
62 return NULL;
63
64 label->mbr = NULL;
65 label->parts = NULL;
66 label->device = 0;
67
68 return label;
69}
70
71/** Free mbr_label_t structure */
72void mbr_free_label(mbr_label_t *label)
73{
74 if (label->mbr != NULL)
75 mbr_free_mbr(label->mbr);
76
77 if (label->parts != NULL)
78 mbr_free_partitions(label->parts);
79
80 free(label);
81}
[d3a92c87]82
[700f89e]83/** Allocate memory for mbr_t */
[9bda5d90]84mbr_t * mbr_alloc_mbr(void)
[700f89e]85{
[9bda5d90]86 return malloc(sizeof(mbr_t));
[700f89e]87}
[8f6c7785]88
[d3a92c87]89/** Read MBR from specific device
[a2aa81cb]90 * @param label label to write data to
91 * @param dev_handle device to read MBR from
[d3a92c87]92 *
[a2aa81cb]93 * @return EOK on success, error code on error
[d3a92c87]94 */
[a2aa81cb]95int mbr_read_mbr(mbr_label_t *label, service_id_t dev_handle)
[44c4886]96{
[d3a92c87]97 int rc;
[a2aa81cb]98
99 if (label->mbr == NULL) {
100 label->mbr = mbr_alloc_mbr();
101 if (label->mbr == NULL) {
102 return ENOMEM;
103 }
[d3a92c87]104 }
105
106 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
[a2aa81cb]107 if (rc != EOK)
108 return rc;
[d3a92c87]109
[a2aa81cb]110 rc = block_read_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
[d3a92c87]111 block_fini(dev_handle);
[a2aa81cb]112 if (rc != EOK)
113 return rc;
[d3a92c87]114
[a2aa81cb]115 label->device = dev_handle;
[d3a92c87]116
[a2aa81cb]117 return EOK;
[d3a92c87]118}
119
120/** Write mbr to disk
[a2aa81cb]121 * @param label MBR to be written
[d3a92c87]122 * @param dev_handle device handle to write MBR to (may be different
123 * from the device in 'mbr')
124 *
[700f89e]125 * @return 0 on success, otherwise libblock error code
[d3a92c87]126 */
[a2aa81cb]127int mbr_write_mbr(mbr_label_t *label, service_id_t dev_handle)
[d3a92c87]128{
129 int rc;
130
131 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
132 if (rc != EOK) {
133 return rc;
134 }
135
[a2aa81cb]136 rc = block_write_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
[d3a92c87]137 block_fini(dev_handle);
138 if (rc != EOK) {
139 return rc;
140 }
141
[a2aa81cb]142 return EOK;
[d3a92c87]143}
144
145/** Decide whether this is an actual MBR or a Protective MBR from GPT
146 *
147 * @param mbr the actual MBR to decide upon
148 *
149 * @return 1 if MBR, 0 if GPT
150 */
[a2aa81cb]151int mbr_is_mbr(mbr_label_t *label)
[d3a92c87]152{
[a2aa81cb]153 return (label->mbr->raw_data.pte[0].ptype != PT_GPT) ? 1 : 0;
[d3a92c87]154}
155
[a2aa81cb]156/** Parse partitions from MBR, freeing previous partitions if any
157 * NOTE: it is assumed mbr_read_mbr(label) was called before.
158 * @param label MBR to be parsed
[d3a92c87]159 *
[a2aa81cb]160 * @return linked list of partitions or NULL on error
[d3a92c87]161 */
[a2aa81cb]162int mbr_read_partitions(mbr_label_t *label)
[d3a92c87]163{
[a2aa81cb]164 if (label == NULL || label->mbr == NULL)
165 return EINVAL;
[8f6c7785]166
[a2aa81cb]167 int rc, rc_ext;
168 unsigned int i;
169 mbr_part_t *p;
170 mbr_part_t *ext = NULL;
171 //mbr_partitions_t *parts;
[6e8e4e19]172
[a2aa81cb]173 if (label->parts != NULL)
174 mbr_free_partitions(label->parts);
[6e8e4e19]175
[a2aa81cb]176 label->parts = mbr_alloc_partitions();
177 if (label->parts == NULL) {
178 return ENOMEM;
[d3a92c87]179 }
[6e8e4e19]180
[a2aa81cb]181 /* Generate the primary partitions */
[d3a92c87]182 for (i = 0; i < N_PRIMARY; ++i) {
[a2aa81cb]183 if (label->mbr->raw_data.pte[i].ptype == PT_UNUSED)
[d3a92c87]184 continue;
[6e8e4e19]185
[8f6c7785]186 p = mbr_alloc_partition();
[d3a92c87]187 if (p == NULL) {
[271e24a]188 printf(LIBMBR_NAME ": Error on memory allocation.\n");
[a2aa81cb]189 mbr_free_partitions(label->parts);
190 return ENOMEM;
[d3a92c87]191 }
[6e8e4e19]192
[a2aa81cb]193 rc_ext = decode_part(&(label->mbr->raw_data.pte[i]), p, 0);
[8f6c7785]194 mbr_set_flag(p, ST_LOGIC, false);
[a2aa81cb]195 rc = mbr_add_partition(label, p);
[8f6c7785]196 if (rc != ERR_OK) {
197 printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
[a2aa81cb]198 LIBMBR_NAME ": MBR is invalid.\n", rc);
199 mbr_free_partitions(label->parts);
200 return EINVAL;
[8f6c7785]201 }
[6e8e4e19]202
[8f6c7785]203 if (rc_ext) {
[d3a92c87]204 ext = p;
[6e8e4e19]205 label->parts->l_extended = &p->link;
[30440ed]206 }
[d3a92c87]207 }
[6e8e4e19]208
[a2aa81cb]209 /* Fill in the primary partitions and generate logical ones, if any */
210 rc = decode_logical(label, ext);
[d3a92c87]211 if (rc != EOK) {
[6e8e4e19]212 printf(LIBMBR_NAME ": Error during decoding logical partitions: %d - %s.\n" \
213 LIBMBR_NAME ": Partition list may be incomplete.\n", rc, str_error(rc));
[a2aa81cb]214 return rc;
[d3a92c87]215 }
[6e8e4e19]216
[a2aa81cb]217 return EOK;
[d3a92c87]218}
219
220/** Write MBR and partitions to device
[a2aa81cb]221 * @param label label to write
222 * @param dev_handle device to write the data to
[d3a92c87]223 *
[a2aa81cb]224 * @return returns EOK on succes, specific error code otherwise
[d3a92c87]225 */
[a2aa81cb]226int mbr_write_partitions(mbr_label_t *label, service_id_t dev_handle)
[d3a92c87]227{
[1c8bfe8]228 if (label->parts == NULL)
229 return EOK;
230
231 if (label->mbr == NULL)
232 label->mbr = mbr_alloc_mbr();
233
[d3a92c87]234 int i = 0;
235 int rc;
[a2aa81cb]236 mbr_part_t *p;
237 mbr_part_t *ext = (label->parts->l_extended == NULL) ? NULL
238 : list_get_instance(label->parts->l_extended, mbr_part_t, link);
[8f6c7785]239
[d3a92c87]240 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
241 if (rc != EOK) {
[700f89e]242 printf(LIBMBR_NAME ": Error while initializing libblock: %d - %s.\n", rc, str_error(rc));
[d3a92c87]243 return rc;
244 }
[8f6c7785]245
[a2aa81cb]246 link_t *l = label->parts->list.head.next;
[8f6c7785]247
[a2aa81cb]248 /* Encoding primary partitions */
[6e8e4e19]249 for (i = 0; i < N_PRIMARY; i++) {
[a2aa81cb]250 p = list_get_instance(l, mbr_part_t, link);
251 encode_part(p, &(label->mbr->raw_data.pte[i]), 0, false);
[d617050]252 l = l->next;
253 }
[8f6c7785]254
[a2aa81cb]255 /* Writing MBR */
256 rc = block_write_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
[d617050]257 if (rc != EOK) {
[700f89e]258 printf(LIBMBR_NAME ": Error while writing MBR : %d - %s.\n", rc, str_error(rc));
[d617050]259 goto end;
260 }
[8f6c7785]261
[6e8e4e19]262 if (ext == NULL) {
263 rc = EOK;
[700f89e]264 goto end;
[6e8e4e19]265 }
[8f6c7785]266
[30440ed]267 uint32_t base = ext->start_addr;
[6e8e4e19]268 mbr_part_t *prev_p;
[700f89e]269
270 /* Note for future changes: Some thought has been put into design
271 * and implementation. If you don't have to change it, don't. Other
272 * designs have been tried, this came out as the least horror with
273 * as much power over it as you can get. Thanks. */
274
[a2aa81cb]275 /* Encoding and writing first logical partition */
276 if (l != &(label->parts->list.head)) {
[d617050]277 p = list_get_instance(l, mbr_part_t, link);
[8f6c7785]278 p->ebr_addr = base;
279 encode_part(p, &(p->ebr->pte[0]), base, false);
[700f89e]280 l = l->next;
281 } else {
282 /* If there was an extended but no logical, we should overwrite
283 * the space where the first logical's EBR would have been. There
284 * might be some garbage from the past. */
285 br_block_t * tmp = alloc_br();
286 rc = block_write_direct(dev_handle, base, 1, tmp);
[d617050]287 if (rc != EOK) {
[700f89e]288 printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
[d617050]289 goto end;
[700f89e]290 }
291 free(tmp);
[6e8e4e19]292 rc = EOK;
[700f89e]293 goto end;
294 }
[8f6c7785]295
296 prev_p = p;
297
[6e8e4e19]298 /* Check EBR addresses
299 * This piece of code saves previous EBR placements from other
300 * software. But if our user modifies the logical partition chain,
301 * we have to fix those placements if needed.*/
302 link_t *l_ebr = l;
303 link_t *l_iter;
304 mbr_part_t *tmp = mbr_alloc_partition();
305 tmp->length = 1;
306 while (l_ebr != &(label->parts->list.head)) {
307 p = list_get_instance(l_ebr, mbr_part_t, link);
308 tmp->start_addr = p->ebr_addr;
309
310 l_iter = l;
311 while (l_iter != &(label->parts->list.head)) {
312 /* Checking whether EBR address makes sense. If not, we take a guess.
313 * So far this is simple, we just take the first preceeding sector.
314 * Fdisk always reserves at least 2048 sectors (1MiB), so it can have
315 * the EBR aligned as well as the partition itself. Parted reserves
316 * minimum one sector, like we do.
317 *
318 * Note that we know there is at least one sector free from previous checks.
319 * Also note that the user can set ebr_addr to their liking (if it's valid). */
320 if (p->ebr_addr < base || p->ebr_addr >= base + ext->length ||
321 check_overlap(tmp, list_get_instance(l_iter, mbr_part_t, link))) {
322 p->ebr_addr = p->start_addr - 1;
323 break;
324 }
325
326 l_iter = l_iter->next;
327 }
328
329 l_ebr = l_ebr->next;
330 }
331 mbr_free_partition(tmp);
332
[a2aa81cb]333 /* Encoding and writing logical partitions */
334 while (l != &(label->parts->list.head)) {
[d617050]335 p = list_get_instance(l, mbr_part_t, link);
[8f6c7785]336
337
338 encode_part(p, &(p->ebr->pte[0]), p->ebr_addr, false);
339 encode_part(p, &(prev_p->ebr->pte[1]), base, true);
340
341 rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
[d617050]342 if (rc != EOK) {
[700f89e]343 printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
[d617050]344 goto end;
345 }
[8f6c7785]346
347 prev_p = p;
[d617050]348 l = l->next;
349 }
[8f6c7785]350
[a2aa81cb]351 /* write the last EBR */
[8f6c7785]352 encode_part(NULL, &(prev_p->ebr->pte[1]), 0, false);
353 rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
354 if (rc != EOK) {
[700f89e]355 printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
[8f6c7785]356 goto end;
357 }
358
[d3a92c87]359 rc = EOK;
[8f6c7785]360
[d3a92c87]361end:
362 block_fini(dev_handle);
[8f6c7785]363
[d3a92c87]364 return rc;
365}
366
[271e24a]367/** mbr_part_t constructor */
368mbr_part_t * mbr_alloc_partition(void)
[d3a92c87]369{
[a2aa81cb]370 mbr_part_t *p = malloc(sizeof(mbr_part_t));
[d3a92c87]371 if (p == NULL) {
372 return NULL;
373 }
[700f89e]374
[d3a92c87]375 link_initialize(&(p->link));
376 p->ebr = NULL;
[a2aa81cb]377 p->type = PT_UNUSED;
[d3a92c87]378 p->status = 0;
379 p->start_addr = 0;
380 p->length = 0;
[8f6c7785]381 p->ebr_addr = 0;
[a2aa81cb]382
[d3a92c87]383 return p;
384}
385
[700f89e]386/** mbr_partitions_t constructor */
[271e24a]387mbr_partitions_t * mbr_alloc_partitions(void)
[d3a92c87]388{
[a2aa81cb]389 mbr_partitions_t *parts = malloc(sizeof(mbr_partitions_t));
[d3a92c87]390 if (parts == NULL) {
391 return NULL;
392 }
[a2aa81cb]393
[d3a92c87]394 list_initialize(&(parts->list));
[30440ed]395 parts->n_primary = 0;
396 parts->n_logical = 0;
397 parts->l_extended = NULL;
[a2aa81cb]398
399 /* add blank primary partitions */
400 int i;
401 mbr_part_t *p;
402 for (i = 0; i < N_PRIMARY; ++i) {
403 p = mbr_alloc_partition();
404 if (p == NULL) {
405 mbr_free_partitions(parts);
406 return NULL;
407 }
408 list_append(&(p->link), &(parts->list));
409 }
410
[d3a92c87]411
412 return parts;
413}
414
[d617050]415/** Add partition
416 * Performs checks, sorts the list.
[700f89e]417 *
[a2aa81cb]418 * @param label label to add to
[700f89e]419 * @param p partition to add
420 *
421 * @return ERR_OK (0) on success, other MBR_ERR_VAL otherwise
[d617050]422 */
[a2aa81cb]423mbr_err_val mbr_add_partition(mbr_label_t *label, mbr_part_t *p)
[d3a92c87]424{
[6e8e4e19]425 int rc1, rc2;
[a2aa81cb]426 aoff64_t nblocks;
[6e8e4e19]427
428 rc1 = block_init(EXCHANGE_ATOMIC, label->device, 512);
429 if (rc1 != EOK && rc1 != EEXIST) {
430 printf(LIBMBR_NAME ": Error during libblock init: %d - %s.\n", rc1, str_error(rc1));
[a2aa81cb]431 return ERR_LIBBLOCK;
432 }
[6e8e4e19]433
434 rc2 = block_get_nblocks(label->device, &nblocks);
435
436 if (rc1 != EEXIST)
437 block_fini(label->device);
438
439 if (rc2 != EOK) {
440 printf(LIBMBR_NAME ": Error while getting number of blocks: %d - %s.\n", rc2, str_error(rc2));
[a2aa81cb]441 return ERR_LIBBLOCK;
442 }
[6e8e4e19]443
444 if ((aoff64_t) p->start_addr + p->length > nblocks)
445 return ERR_OUT_BOUNDS;
446
447 if (label->parts == NULL) {
448 label->parts = mbr_alloc_partitions();
449 if (label->parts == NULL)
450 return ENOMEM; //FIXME! merge mbr_err_val into errno.h
451 }
452
453 if (mbr_get_flag(p, ST_LOGIC))
[a2aa81cb]454 /* adding logical partition */
[6e8e4e19]455 return mbr_add_logical(label, p);
456 else
[a2aa81cb]457 /* adding primary */
[6e8e4e19]458 return mbr_add_primary(label, p);
[d3a92c87]459}
460
[700f89e]461/** Remove partition
462 * Removes partition by index, indexed from zero. When removing extended
[a2aa81cb]463 * partition, all logical partitions get removed as well.
[700f89e]464 *
[a2aa81cb]465 * @param label label to remove from
[700f89e]466 * @param idx index of the partition to remove
467 *
468 * @return EOK on success, EINVAL if idx invalid
469 */
[a2aa81cb]470int mbr_remove_partition(mbr_label_t *label, size_t idx)
[d3a92c87]471{
[a2aa81cb]472 link_t *l = list_nth(&(label->parts->list), idx);
[700f89e]473 if (l == NULL)
474 return EINVAL;
475
[a2aa81cb]476 mbr_part_t *p;
[700f89e]477
[a2aa81cb]478 /* If we're removing an extended partition, remove all logical as well */
479 if (l == label->parts->l_extended) {
480 label->parts->l_extended = NULL;
[700f89e]481
[a2aa81cb]482 link_t *it = l->next;
483 link_t *next_it;
484 while (it != &(label->parts->list.head)) {
[700f89e]485 next_it = it->next;
486
487 p = list_get_instance(it, mbr_part_t, link);
488 if (mbr_get_flag(p, ST_LOGIC)) {
489 list_remove(it);
[a2aa81cb]490 label->parts->n_logical -= 1;
[700f89e]491 mbr_free_partition(p);
492 }
493
494 it = next_it;
495 }
496
[30440ed]497 }
[700f89e]498
[a2aa81cb]499 /* Remove the partition itself */
[700f89e]500 p = list_get_instance(l, mbr_part_t, link);
[a2aa81cb]501 if (mbr_get_flag(p, ST_LOGIC)) {
502 label->parts->n_logical -= 1;
503 list_remove(l);
504 mbr_free_partition(p);
505 } else {
506 /* Cannot remove primary - it would break ordering, just zero it */
507 label->parts->n_primary -= 1;
508 p->type = 0;
509 p->status = 0;
510 p->start_addr = 0;
511 p->length = 0;
512 p->ebr_addr = 0;
513 }
[700f89e]514
[271e24a]515 return EOK;
[d3a92c87]516}
517
[271e24a]518/** mbr_part_t destructor */
[a2aa81cb]519void mbr_free_partition(mbr_part_t *p)
[d3a92c87]520{
521 if (p->ebr != NULL)
522 free(p->ebr);
523 free(p);
524}
525
526/** Get flag bool value */
[a2aa81cb]527int mbr_get_flag(mbr_part_t *p, MBR_FLAGS flag)
[d3a92c87]528{
529 return (p->status & (1 << flag)) ? 1 : 0;
530}
531
532/** Set a specifig status flag to a value */
[a2aa81cb]533void mbr_set_flag(mbr_part_t *p, MBR_FLAGS flag, bool value)
[d3a92c87]534{
[6e8e4e19]535 uint16_t status = p->status;
[d3a92c87]536
537 if (value)
538 status = status | (1 << flag);
539 else
540 status = status ^ (status & (1 << flag));
541
542 p->status = status;
543}
544
[6e8e4e19]545/** Get next aligned address */
[8f6c7785]546uint32_t mbr_get_next_aligned(uint32_t addr, unsigned int alignment)
547{
548 uint32_t div = addr / alignment;
549 return (div + 1) * alignment;
550}
551
[6e8e4e19]552list_t * mbr_get_list(mbr_label_t *label)
553{
554 if (label->parts != NULL)
555 return &(label->parts->list);
556 else
557 return NULL;
558}
559
560mbr_part_t * mbr_get_first_partition(mbr_label_t *label)
561{
562 list_t *list = mbr_get_list(label);
563 if (list != NULL && !list_empty(list))
564 return list_get_instance(list->head.next, mbr_part_t, link);
565 else
566 return NULL;
567}
568
569mbr_part_t * mbr_get_next_partition(mbr_label_t *label, mbr_part_t *p)
570{
571 list_t *list = mbr_get_list(label);
572 if (list != NULL && &(p->link) != list_last(list))
573 return list_get_instance(p->link.next, mbr_part_t, link);
574 else
575 return NULL;
576}
577
[d3a92c87]578/** Just a wrapper for free() */
[a2aa81cb]579void mbr_free_mbr(mbr_t *mbr)
[d3a92c87]580{
581 free(mbr);
582}
583
584/** Free partition list
585 *
586 * @param parts partition list to be freed
587 */
[a2aa81cb]588void mbr_free_partitions(mbr_partitions_t *parts)
[d3a92c87]589{
590 list_foreach_safe(parts->list, cur_link, next) {
[a2aa81cb]591 mbr_part_t *p = list_get_instance(cur_link, mbr_part_t, link);
[d3a92c87]592 mbr_free_partition(p);
593 }
[d617050]594
[30440ed]595 free(parts);
[d3a92c87]596}
597
598// Internal functions follow //
599
[a2aa81cb]600static br_block_t *alloc_br()
[d3a92c87]601{
[a2aa81cb]602 br_block_t *br = malloc(sizeof(br_block_t));
[d3a92c87]603 if (br == NULL)
604 return NULL;
[8f6c7785]605
606 memset(br, 0, 512);
[d3a92c87]607 br->signature = host2uint16_t_le(BR_SIGNATURE);
[8f6c7785]608
[d3a92c87]609 return br;
610}
611
[30440ed]612/** Parse partition entry to mbr_part_t
613 * @return returns 1, if extended partition, 0 otherwise
614 * */
[a2aa81cb]615static int decode_part(pt_entry_t *src, mbr_part_t *trgt, uint32_t base)
[d3a92c87]616{
617 trgt->type = src->ptype;
618
[6e8e4e19]619 trgt->status = (trgt->status & 0xFF00) | (uint16_t) src->status;
[d3a92c87]620
621 trgt->start_addr = uint32_t_le2host(src->first_lba) + base;
622 trgt->length = uint32_t_le2host(src->length);
623
624 return (src->ptype == PT_EXTENDED) ? 1 : 0;
625}
626
[30440ed]627/** Parse MBR contents to mbr_part_t list */
[a2aa81cb]628static int decode_logical(mbr_label_t *label, mbr_part_t * ext)
[d3a92c87]629{
630 int rc;
[a2aa81cb]631 mbr_part_t *p;
[d3a92c87]632
633 if (ext == NULL)
634 return EOK;
635
[30440ed]636 uint32_t base = ext->start_addr;
637 uint32_t addr = base;
[a2aa81cb]638 br_block_t *ebr;
[8f6c7785]639
[a2aa81cb]640 rc = block_init(EXCHANGE_ATOMIC, label->device, 512);
[d3a92c87]641 if (rc != EOK)
642 return rc;
[8f6c7785]643
[30440ed]644 ebr = alloc_br();
645 if (ebr == NULL) {
646 rc = ENOMEM;
647 goto end;
648 }
[8f6c7785]649
[a2aa81cb]650 rc = block_read_direct(label->device, addr, 1, ebr);
[30440ed]651 if (rc != EOK) {
652 goto free_ebr_end;
653 }
[8f6c7785]654
[30440ed]655 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
656 rc = EINVAL;
657 goto free_ebr_end;
658 }
[8f6c7785]659
[30440ed]660 if (ebr->pte[0].ptype == PT_UNUSED) {
661 rc = EOK;
662 goto free_ebr_end;
663 }
[8f6c7785]664
[30440ed]665 p = mbr_alloc_partition();
666 if (p == NULL) {
667 rc = ENOMEM;
668 goto free_ebr_end;
669 }
[8f6c7785]670
[30440ed]671 decode_part(&(ebr->pte[0]), p, base);
672 mbr_set_flag(p, ST_LOGIC, true);
673 p->ebr = ebr;
[8f6c7785]674 p->ebr_addr = addr;
[a2aa81cb]675 rc = mbr_add_partition(label, p);
[700f89e]676 if (rc != ERR_OK)
[8f6c7785]677 return EINVAL;
678
[30440ed]679 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
[8f6c7785]680
[30440ed]681 while (ebr->pte[1].ptype != PT_UNUSED) {
[6e8e4e19]682
[d3a92c87]683 ebr = alloc_br();
684 if (ebr == NULL) {
[30440ed]685 rc = ENOMEM;
686 goto end;
[d3a92c87]687 }
[8f6c7785]688
[a2aa81cb]689 rc = block_read_direct(label->device, addr, 1, ebr);
[d3a92c87]690 if (rc != EOK) {
[30440ed]691 goto free_ebr_end;
[d3a92c87]692 }
[8f6c7785]693
[d3a92c87]694 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
[30440ed]695 rc = EINVAL;
696 goto free_ebr_end;
[d3a92c87]697 }
[8f6c7785]698
[d3a92c87]699 p = mbr_alloc_partition();
[30440ed]700 if (p == NULL) {
701 rc = ENOMEM;
702 goto free_ebr_end;
703 }
[8f6c7785]704
705 decode_part(&(ebr->pte[0]), p, addr);
[d3a92c87]706 mbr_set_flag(p, ST_LOGIC, true);
707 p->ebr = ebr;
[8f6c7785]708 p->ebr_addr = addr;
[a2aa81cb]709 rc = mbr_add_partition(label, p);
[700f89e]710 if (rc != ERR_OK)
[8f6c7785]711 return EINVAL;
712
[30440ed]713 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
714 }
[8f6c7785]715
[30440ed]716 rc = EOK;
[8f6c7785]717 goto end;
718
[30440ed]719free_ebr_end:
720 free(ebr);
[8f6c7785]721
[30440ed]722end:
[a2aa81cb]723 block_fini(label->device);
[8f6c7785]724
[30440ed]725 return rc;
[d3a92c87]726}
727
[271e24a]728/** Convert mbr_part_t to pt_entry_t */
[8f6c7785]729static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr)
[d3a92c87]730{
731 if (src != NULL) {
[a2aa81cb]732 //trgt->status = mbr_get_flag(src, ST_BOOT) ? B_ACTIVE : B_INACTIVE;
733 trgt->status = (uint8_t) (src->status & 0xFF);
734 /* ingoring CHS */
735 trgt->first_chs[0] = 0xFE;
736 trgt->first_chs[1] = 0xFF;
737 trgt->first_chs[2] = 0xFF;
738 trgt->last_chs[0] = 0xFE;
739 trgt->last_chs[1] = 0xFF;
740 trgt->last_chs[2] = 0xFF;
[8f6c7785]741 if (ebr) { // encoding reference to EBR
742 trgt->ptype = PT_EXTENDED_LBA;
743 trgt->first_lba = host2uint32_t_le(src->ebr_addr - base);
744 trgt->length = host2uint32_t_le(src->length + src->start_addr - src->ebr_addr);
745 } else { // encoding reference to partition
746 trgt->ptype = src->type;
747 trgt->first_lba = host2uint32_t_le(src->start_addr - base);
748 trgt->length = host2uint32_t_le(src->length);
749 }
[6e8e4e19]750
751 if (trgt->ptype == PT_UNUSED)
752 memset(trgt, 0, sizeof(pt_entry_t));
[d3a92c87]753 } else {
[6e8e4e19]754 memset(trgt, 0, sizeof(pt_entry_t));
[d3a92c87]755 }
756}
757
[700f89e]758/** Check whether two partitions overlap
759 *
760 * @return 1 for yes, 0 for no
761 */
[d617050]762static int check_overlap(mbr_part_t * p1, mbr_part_t * p2)
763{
[6e8e4e19]764 if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length <= p2->start_addr) {
[d617050]765 return 0;
[6e8e4e19]766 } else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length <= p1->start_addr) {
[d617050]767 return 0;
768 }
769
770 return 1;
771}
772
[700f89e]773/** Check whether one partition encapsulates the other
774 *
775 * @return 1 for yes, 0 for no
776 */
[d617050]777static int check_encaps(mbr_part_t * inner, mbr_part_t * outer)
778{
779 if (inner->start_addr <= outer->start_addr || outer->start_addr + outer->length <= inner->start_addr) {
780 return 0;
781 } else if (outer->start_addr + outer->length < inner->start_addr + inner->length) {
782 return 0;
783 }
784
785 return 1;
786}
787
[700f89e]788/** Check whether one partition preceeds the other
789 *
790 * @return 1 for yes, 0 for no
791 */
[d617050]792static int check_preceeds(mbr_part_t * preceeder, mbr_part_t * precedee)
793{
794 return preceeder->start_addr < precedee->start_addr;
795}
796
[6e8e4e19]797mbr_err_val mbr_add_primary(mbr_label_t *label, mbr_part_t *p)
798{
799 if (label->parts->n_primary == 4) {
800 return ERR_PRIMARY_FULL;
801 }
802
803 /* Check if partition makes space for MBR itself. */
804 if (p->start_addr == 0) {
805 return ERR_OUT_BOUNDS;
806 }
807
808 /* if it's extended, is there any other one? */
809 if ((p->type == PT_EXTENDED || p->type == PT_EXTENDED_LBA) && label->parts->l_extended != NULL) {
810 return ERR_EXTENDED_PRESENT;
811 }
812
813 /* find a place and add it */
814 mbr_part_t *iter;
815 mbr_part_t *empty = NULL;
816 mbr_part_foreach(label, iter) {
817 if (iter->type == PT_UNUSED) {
818 if (empty == NULL)
819 empty = iter;
820 } else if (check_overlap(p, iter))
821 return ERR_OVERLAP;
822 }
823
824 list_insert_after(&(p->link), &(empty->link));
825 list_remove(&(empty->link));
826 free(empty);
827
828 label->parts->n_primary += 1;
829
830 if (p->type == PT_EXTENDED || p->type == PT_EXTENDED_LBA)
831 label->parts->l_extended = &(p->link);
832
833 return EOK;
834}
835
836mbr_err_val mbr_add_logical(mbr_label_t *label, mbr_part_t *p)
837{
838 /* is there any extended partition? */
839 if (label->parts->l_extended == NULL)
840 return ERR_NO_EXTENDED;
841
842 /* is the logical partition inside the extended one? */
843 mbr_part_t *ext = list_get_instance(label->parts->l_extended, mbr_part_t, link);
844 if (!check_encaps(p, ext))
845 return ERR_OUT_BOUNDS;
846
847 /* find a place for the new partition in a sorted linked list */
848 bool first_logical = true;
849 mbr_part_t *iter;
850 mbr_part_foreach(label, iter) {
851 if (mbr_get_flag(iter, ST_LOGIC)) {
852 if (check_overlap(p, iter))
853 return ERR_OVERLAP;
854 if (check_preceeds(iter, p)) {
855 /* checking if there's at least one sector of space preceeding */
856 if ((iter->start_addr + iter->length) >= p->start_addr - 1)
857 return ERR_NO_EBR;
858 } else if (first_logical){
859 /* First logical partition's EBR is before every other
860 * logical partition. Thus we don't check if this partition
861 * leaves enough space for it. */
862 first_logical = false;
863 } else {
864 /* checking if there's at least one sector of space following (for following partitions's EBR) */
865 if ((p->start_addr + p->length) >= iter->start_addr - 1)
866 return ERR_NO_EBR;
867 }
868 }
869 }
870
871 /* alloc EBR if it's not already there */
872 if (p->ebr == NULL) {
873 p->ebr = alloc_br();
874 if (p->ebr == NULL) {
875 return ERR_NOMEM;
876 }
877 }
878
879 /* add it */
880 list_append(&(p->link), &(label->parts->list));
881 label->parts->n_logical += 1;
882
883 return EOK;
884}
[8f6c7785]885
[d617050]886
887
Note: See TracBrowser for help on using the repository browser.