source: mainline/uspace/lib/mbr/libmbr.c@ f9d9184

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f9d9184 was 6453e306, checked in by Martin Decky <martin@…>, 12 years ago

basic code review and coding style cleanup

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