source: mainline/uspace/lib/mbr/libmbr.c@ 8c95dff

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

various bugfixes

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