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
Line 
1/*
2 * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
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 LIBMBR_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 libmbr
30 * @{
31 */
32/** @file MBR extraxtion library
33 */
34
35#include <async.h>
36#include <assert.h>
37#include <block.h>
38#include <byteorder.h>
39#include <errno.h>
40#include <ipc/bd.h>
41#include <mem.h>
42#include <stdio.h>
43#include <stdlib.h>
44
45#include "libmbr.h"
46
47static br_block_t * alloc_br(void);
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 *);
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);
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}
82
83/** Allocate memory for mbr_t */
84mbr_t * mbr_alloc_mbr(void)
85{
86 return malloc(sizeof(mbr_t));
87}
88
89/** Read MBR from specific device
90 * @param label label to write data to
91 * @param dev_handle device to read MBR from
92 *
93 * @return EOK on success, error code on error
94 */
95int mbr_read_mbr(mbr_label_t *label, service_id_t dev_handle)
96{
97 int rc;
98
99 if (label->mbr == NULL) {
100 label->mbr = mbr_alloc_mbr();
101 if (label->mbr == NULL) {
102 return ENOMEM;
103 }
104 }
105
106 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
107 if (rc != EOK)
108 return rc;
109
110 rc = block_read_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
111 block_fini(dev_handle);
112 if (rc != EOK)
113 return rc;
114
115 label->device = dev_handle;
116
117 return EOK;
118}
119
120/** Write mbr to disk
121 * @param label MBR to be written
122 * @param dev_handle device handle to write MBR to (may be different
123 * from the device in 'mbr')
124 *
125 * @return 0 on success, otherwise libblock error code
126 */
127int mbr_write_mbr(mbr_label_t *label, service_id_t dev_handle)
128{
129 int rc;
130
131 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
132 if (rc != EOK) {
133 return rc;
134 }
135
136 rc = block_write_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
137 block_fini(dev_handle);
138 if (rc != EOK) {
139 return rc;
140 }
141
142 return EOK;
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 */
151int mbr_is_mbr(mbr_label_t *label)
152{
153 return (label->mbr->raw_data.pte[0].ptype != PT_GPT) ? 1 : 0;
154}
155
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
159 *
160 * @return linked list of partitions or NULL on error
161 */
162int mbr_read_partitions(mbr_label_t *label)
163{
164 if (label == NULL || label->mbr == NULL)
165 return EINVAL;
166
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;
172
173 if (label->parts != NULL)
174 mbr_free_partitions(label->parts);
175
176 label->parts = mbr_alloc_partitions();
177 if (label->parts == NULL) {
178 return ENOMEM;
179 }
180
181 /* Generate the primary partitions */
182 for (i = 0; i < N_PRIMARY; ++i) {
183 if (label->mbr->raw_data.pte[i].ptype == PT_UNUSED)
184 continue;
185
186 p = mbr_alloc_partition();
187 if (p == NULL) {
188 printf(LIBMBR_NAME ": Error on memory allocation.\n");
189 mbr_free_partitions(label->parts);
190 return ENOMEM;
191 }
192
193 rc_ext = decode_part(&(label->mbr->raw_data.pte[i]), p, 0);
194 mbr_set_flag(p, ST_LOGIC, false);
195 rc = mbr_add_partition(label, p);
196 if (rc != ERR_OK) {
197 printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
198 LIBMBR_NAME ": MBR is invalid.\n", rc);
199 mbr_free_partitions(label->parts);
200 return EINVAL;
201 }
202
203 if (rc_ext) {
204 ext = p;
205 label->parts->l_extended = &p->link;
206 }
207 }
208
209 /* Fill in the primary partitions and generate logical ones, if any */
210 rc = decode_logical(label, ext);
211 if (rc != EOK) {
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));
214 return rc;
215 }
216
217 return EOK;
218}
219
220/** Write MBR and partitions to device
221 * @param label label to write
222 * @param dev_handle device to write the data to
223 *
224 * @return returns EOK on succes, specific error code otherwise
225 */
226int mbr_write_partitions(mbr_label_t *label, service_id_t dev_handle)
227{
228 if (label->parts == NULL)
229 return EOK;
230
231 if (label->mbr == NULL)
232 label->mbr = mbr_alloc_mbr();
233
234 int i = 0;
235 int rc;
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);
239
240 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
241 if (rc != EOK) {
242 printf(LIBMBR_NAME ": Error while initializing libblock: %d - %s.\n", rc, str_error(rc));
243 return rc;
244 }
245
246 link_t *l = label->parts->list.head.next;
247
248 /* Encoding primary partitions */
249 for (i = 0; i < N_PRIMARY; i++) {
250 p = list_get_instance(l, mbr_part_t, link);
251 encode_part(p, &(label->mbr->raw_data.pte[i]), 0, false);
252 l = l->next;
253 }
254
255 /* Writing MBR */
256 rc = block_write_direct(dev_handle, 0, 1, &(label->mbr->raw_data));
257 if (rc != EOK) {
258 printf(LIBMBR_NAME ": Error while writing MBR : %d - %s.\n", rc, str_error(rc));
259 goto end;
260 }
261
262 if (ext == NULL) {
263 rc = EOK;
264 goto end;
265 }
266
267 uint32_t base = ext->start_addr;
268 mbr_part_t *prev_p;
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
275 /* Encoding and writing first logical partition */
276 if (l != &(label->parts->list.head)) {
277 p = list_get_instance(l, mbr_part_t, link);
278 p->ebr_addr = base;
279 encode_part(p, &(p->ebr->pte[0]), base, false);
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);
287 if (rc != EOK) {
288 printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
289 goto end;
290 }
291 free(tmp);
292 rc = EOK;
293 goto end;
294 }
295
296 prev_p = p;
297
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
333 /* Encoding and writing logical partitions */
334 while (l != &(label->parts->list.head)) {
335 p = list_get_instance(l, mbr_part_t, link);
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);
342 if (rc != EOK) {
343 printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
344 goto end;
345 }
346
347 prev_p = p;
348 l = l->next;
349 }
350
351 /* write the last EBR */
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) {
355 printf(LIBMBR_NAME ": Error while writing EBR: %d - %s.\n", rc, str_error(rc));
356 goto end;
357 }
358
359 rc = EOK;
360
361end:
362 block_fini(dev_handle);
363
364 return rc;
365}
366
367/** mbr_part_t constructor */
368mbr_part_t * mbr_alloc_partition(void)
369{
370 mbr_part_t *p = malloc(sizeof(mbr_part_t));
371 if (p == NULL) {
372 return NULL;
373 }
374
375 link_initialize(&(p->link));
376 p->ebr = NULL;
377 p->type = PT_UNUSED;
378 p->status = 0;
379 p->start_addr = 0;
380 p->length = 0;
381 p->ebr_addr = 0;
382
383 return p;
384}
385
386/** mbr_partitions_t constructor */
387mbr_partitions_t * mbr_alloc_partitions(void)
388{
389 mbr_partitions_t *parts = malloc(sizeof(mbr_partitions_t));
390 if (parts == NULL) {
391 return NULL;
392 }
393
394 list_initialize(&(parts->list));
395 parts->n_primary = 0;
396 parts->n_logical = 0;
397 parts->l_extended = NULL;
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
411
412 return parts;
413}
414
415/** Add partition
416 * Performs checks, sorts the list.
417 *
418 * @param label label to add to
419 * @param p partition to add
420 *
421 * @return ERR_OK (0) on success, other MBR_ERR_VAL otherwise
422 */
423mbr_err_val mbr_add_partition(mbr_label_t *label, mbr_part_t *p)
424{
425 int rc1, rc2;
426 aoff64_t nblocks;
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));
431 return ERR_LIBBLOCK;
432 }
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));
441 return ERR_LIBBLOCK;
442 }
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))
454 /* adding logical partition */
455 return mbr_add_logical(label, p);
456 else
457 /* adding primary */
458 return mbr_add_primary(label, p);
459}
460
461/** Remove partition
462 * Removes partition by index, indexed from zero. When removing extended
463 * partition, all logical partitions get removed as well.
464 *
465 * @param label label to remove from
466 * @param idx index of the partition to remove
467 *
468 * @return EOK on success, EINVAL if idx invalid
469 */
470int mbr_remove_partition(mbr_label_t *label, size_t idx)
471{
472 link_t *l = list_nth(&(label->parts->list), idx);
473 if (l == NULL)
474 return EINVAL;
475
476 mbr_part_t *p;
477
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;
481
482 link_t *it = l->next;
483 link_t *next_it;
484 while (it != &(label->parts->list.head)) {
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);
490 label->parts->n_logical -= 1;
491 mbr_free_partition(p);
492 }
493
494 it = next_it;
495 }
496
497 }
498
499 /* Remove the partition itself */
500 p = list_get_instance(l, mbr_part_t, link);
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 }
514
515 return EOK;
516}
517
518/** mbr_part_t destructor */
519void mbr_free_partition(mbr_part_t *p)
520{
521 if (p->ebr != NULL)
522 free(p->ebr);
523 free(p);
524}
525
526/** Get flag bool value */
527int mbr_get_flag(mbr_part_t *p, MBR_FLAGS flag)
528{
529 return (p->status & (1 << flag)) ? 1 : 0;
530}
531
532/** Set a specifig status flag to a value */
533void mbr_set_flag(mbr_part_t *p, MBR_FLAGS flag, bool value)
534{
535 uint16_t status = p->status;
536
537 if (value)
538 status = status | (1 << flag);
539 else
540 status = status ^ (status & (1 << flag));
541
542 p->status = status;
543}
544
545/** Get next aligned address */
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
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
578/** Just a wrapper for free() */
579void mbr_free_mbr(mbr_t *mbr)
580{
581 free(mbr);
582}
583
584/** Free partition list
585 *
586 * @param parts partition list to be freed
587 */
588void mbr_free_partitions(mbr_partitions_t *parts)
589{
590 list_foreach_safe(parts->list, cur_link, next) {
591 mbr_part_t *p = list_get_instance(cur_link, mbr_part_t, link);
592 mbr_free_partition(p);
593 }
594
595 free(parts);
596}
597
598// Internal functions follow //
599
600static br_block_t *alloc_br()
601{
602 br_block_t *br = malloc(sizeof(br_block_t));
603 if (br == NULL)
604 return NULL;
605
606 memset(br, 0, 512);
607 br->signature = host2uint16_t_le(BR_SIGNATURE);
608
609 return br;
610}
611
612/** Parse partition entry to mbr_part_t
613 * @return returns 1, if extended partition, 0 otherwise
614 * */
615static int decode_part(pt_entry_t *src, mbr_part_t *trgt, uint32_t base)
616{
617 trgt->type = src->ptype;
618
619 trgt->status = (trgt->status & 0xFF00) | (uint16_t) src->status;
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
627/** Parse MBR contents to mbr_part_t list */
628static int decode_logical(mbr_label_t *label, mbr_part_t * ext)
629{
630 int rc;
631 mbr_part_t *p;
632
633 if (ext == NULL)
634 return EOK;
635
636 uint32_t base = ext->start_addr;
637 uint32_t addr = base;
638 br_block_t *ebr;
639
640 rc = block_init(EXCHANGE_ATOMIC, label->device, 512);
641 if (rc != EOK)
642 return rc;
643
644 ebr = alloc_br();
645 if (ebr == NULL) {
646 rc = ENOMEM;
647 goto end;
648 }
649
650 rc = block_read_direct(label->device, addr, 1, ebr);
651 if (rc != EOK) {
652 goto free_ebr_end;
653 }
654
655 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
656 rc = EINVAL;
657 goto free_ebr_end;
658 }
659
660 if (ebr->pte[0].ptype == PT_UNUSED) {
661 rc = EOK;
662 goto free_ebr_end;
663 }
664
665 p = mbr_alloc_partition();
666 if (p == NULL) {
667 rc = ENOMEM;
668 goto free_ebr_end;
669 }
670
671 decode_part(&(ebr->pte[0]), p, base);
672 mbr_set_flag(p, ST_LOGIC, true);
673 p->ebr = ebr;
674 p->ebr_addr = addr;
675 rc = mbr_add_partition(label, p);
676 if (rc != ERR_OK)
677 return EINVAL;
678
679 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
680
681 while (ebr->pte[1].ptype != PT_UNUSED) {
682
683 ebr = alloc_br();
684 if (ebr == NULL) {
685 rc = ENOMEM;
686 goto end;
687 }
688
689 rc = block_read_direct(label->device, addr, 1, ebr);
690 if (rc != EOK) {
691 goto free_ebr_end;
692 }
693
694 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
695 rc = EINVAL;
696 goto free_ebr_end;
697 }
698
699 p = mbr_alloc_partition();
700 if (p == NULL) {
701 rc = ENOMEM;
702 goto free_ebr_end;
703 }
704
705 decode_part(&(ebr->pte[0]), p, addr);
706 mbr_set_flag(p, ST_LOGIC, true);
707 p->ebr = ebr;
708 p->ebr_addr = addr;
709 rc = mbr_add_partition(label, p);
710 if (rc != ERR_OK)
711 return EINVAL;
712
713 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
714 }
715
716 rc = EOK;
717 goto end;
718
719free_ebr_end:
720 free(ebr);
721
722end:
723 block_fini(label->device);
724
725 return rc;
726}
727
728/** Convert mbr_part_t to pt_entry_t */
729static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr)
730{
731 if (src != NULL) {
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;
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 }
750
751 if (trgt->ptype == PT_UNUSED)
752 memset(trgt, 0, sizeof(pt_entry_t));
753 } else {
754 memset(trgt, 0, sizeof(pt_entry_t));
755 }
756}
757
758/** Check whether two partitions overlap
759 *
760 * @return 1 for yes, 0 for no
761 */
762static int check_overlap(mbr_part_t * p1, mbr_part_t * p2)
763{
764 if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length <= p2->start_addr) {
765 return 0;
766 } else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length <= p1->start_addr) {
767 return 0;
768 }
769
770 return 1;
771}
772
773/** Check whether one partition encapsulates the other
774 *
775 * @return 1 for yes, 0 for no
776 */
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
788/** Check whether one partition preceeds the other
789 *
790 * @return 1 for yes, 0 for no
791 */
792static int check_preceeds(mbr_part_t * preceeder, mbr_part_t * precedee)
793{
794 return preceeder->start_addr < precedee->start_addr;
795}
796
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}
885
886
887
Note: See TracBrowser for help on using the repository browser.