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

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

logical write functional

  • Property mode set to 100644
File size: 23.8 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 * src, mbr_part_t * trgt, uint32_t base);
49static int decode_logical(mbr_t * mbr, mbr_partitions_t * p, mbr_part_t * ext);
50static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr);
51static int check_overlap(mbr_part_t * p1, mbr_part_t * p2);
52static int check_encaps(mbr_part_t * inner, mbr_part_t * outer);
53static int check_preceeds(mbr_part_t * preceeder, mbr_part_t * precedee);
54
55static void debug_print(unsigned char * data, size_t bytes);
56
57/** Read MBR from specific device
58 * @param dev_handle device to read MBR from
59 *
60 * @return mbr record on success, NULL on error
61 */
62mbr_t * mbr_read_mbr(service_id_t dev_handle)
63{
64 int rc;
65
66 mbr_t * mbr = malloc(sizeof(mbr_t));
67 if (mbr == NULL) {
68 return NULL;
69 }
70
71 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
72 if (rc != EOK) {
73 return NULL;
74 }
75
76 rc = block_read_direct(dev_handle, 0, 1, &(mbr->raw_data));
77 if (rc != EOK) {
78 block_fini(dev_handle);
79 return NULL;
80 }
81
82 block_fini(dev_handle);
83
84 mbr->device = dev_handle;
85 //mbr->partitions = NULL;
86
87 return mbr;
88}
89
90/** Write mbr to disk
91 * @param mbr MBR to be written
92 * @param dev_handle device handle to write MBR to (may be different
93 * from the device in 'mbr')
94 *
95 * @return 0 on success, -1 on block_init error, -2 on write error
96 */
97int mbr_write_mbr(mbr_t * mbr, service_id_t dev_handle)
98{
99 int rc;
100
101 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
102 if (rc != EOK) {
103 return rc;
104 }
105
106 rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
107 block_fini(dev_handle);
108 if (rc != EOK) {
109 return rc;
110 }
111
112 return 0;
113}
114
115/** Decide whether this is an actual MBR or a Protective MBR from GPT
116 *
117 * @param mbr the actual MBR to decide upon
118 *
119 * @return 1 if MBR, 0 if GPT
120 */
121int mbr_is_mbr(mbr_t * mbr)
122{
123 return (mbr->raw_data.pte[0].ptype != PT_GPT) ? 1 : 0;
124}
125
126/** Parse partitions from MBR
127 * @param mbr MBR to be parsed
128 *
129 * @return linked list of partitions or NULL on error
130 */
131mbr_partitions_t * mbr_read_partitions(mbr_t * mbr)
132{
133 int rc, i, rc_ext;
134 mbr_part_t * p;
135 mbr_part_t * ext = NULL;
136 mbr_partitions_t * parts;
137
138 if (mbr == NULL)
139 return NULL;
140
141 parts = mbr_alloc_partitions();
142 if (parts == NULL) {
143 return NULL;
144 }
145
146 // Generate the primary partitions
147 for (i = 0; i < N_PRIMARY; ++i) {
148 if (mbr->raw_data.pte[i].ptype == PT_UNUSED)
149 continue;
150
151 //p = malloc(sizeof(mbr_part_t));
152 p = mbr_alloc_partition();
153 if (p == NULL) {
154 printf(LIBMBR_NAME ": Error on memory allocation.\n");
155 mbr_free_partitions(parts);
156 return NULL;
157 }
158 //list_append(&(p->link), &(parts->list));
159 rc_ext = decode_part(&(mbr->raw_data.pte[i]), p, 0);
160 mbr_set_flag(p, ST_LOGIC, false);
161 rc = mbr_add_partition(parts, p);
162 if (rc != ERR_OK) {
163 printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
164 LIBMBR_NAME ": Partition list may be incomplete.\n", rc);
165 return NULL;
166 }
167
168 if (rc_ext) {
169 ext = p;
170 parts->l_extended = list_last(&(parts->list));
171 }
172 }
173
174 // Fill in the primary partitions and generate logical ones, if any
175 rc = decode_logical(mbr, parts, ext);
176 if (rc != EOK) {
177 printf(LIBMBR_NAME ": Error occured during decoding the MBR.\n" \
178 LIBMBR_NAME ": Partition list may be incomplete.\n");
179 }
180
181 //DEBUG:
182 //debug_print((unsigned char *) list_get_instance(list_last(&(parts->list)), mbr_part_t, link)->ebr, 512);
183 return parts;
184}
185
186/** Write MBR and partitions to device
187 * @param parts partition list to be written
188 * @param mbr MBR to be written with 'parts' partitions
189 * @param dev_handle device to write the data to
190 *
191 * @return returns EOK on succes, specific error code otherwise
192 */
193int mbr_write_partitions(mbr_partitions_t * parts, mbr_t * mbr, service_id_t dev_handle)
194{
195 //bool logical = false;
196 int i = 0;
197 int rc;
198 mbr_part_t * p;
199 mbr_part_t * ext = (parts->l_extended == NULL) ? NULL
200 : list_get_instance(parts->l_extended, mbr_part_t, link);
201
202 //br_block_t * last_ebr = NULL;
203 //link_t * it;
204
205 DEBUG_PRINT_3(LIBMBR_NAME "Writing partitions: n_primary: %u, n_logical:%u, l_extended:%p", parts->n_primary, parts->n_logical, parts->l_extended);
206
207 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
208 if (rc != EOK) {
209 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
210 return rc;
211 }
212 /*
213 // Encoding primary partitions
214 for (i = 0; i < parts->n_primary; i++) {
215 encode_part(p, &(mbr->raw_data.pte[i]), 0);
216 }
217
218 // Writing MBR
219 rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
220 if (rc != EOK) {
221 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
222 goto end;
223 }
224
225 uint32_t base = ext->start_addr;
226 uint32_t addr = base;
227
228 // Encoding and writing logical partitions
229 mbr_part_foreach(parts, p) {
230 if (p->ebr == NULL) {
231 p->ebr = alloc_br();
232 if (p->ebr == NULL)
233 {
234 rc = ENOMEM;
235 goto end;
236 }
237 }
238
239
240 }*/
241
242 link_t * l = parts->list.head.next;
243
244 // Encoding primary partitions
245 for (i = 0; i < parts->n_primary; i++) {
246 p = list_get_instance(l, mbr_part_t, link);
247 encode_part(p, &(mbr->raw_data.pte[i]), 0, false);
248 l = l->next;
249 }
250
251 // Writing MBR
252 rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
253 if (rc != EOK) {
254 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
255 goto end;
256 }
257
258 if (ext == NULL)
259 goto no_extended;
260
261 //DEBUG:
262 //debug_print((unsigned char *) list_get_instance(list_last(&(parts->list)), mbr_part_t, link)->ebr, 512);
263 uint32_t base = ext->start_addr;
264 //uint32_t addr = base;
265 //uint32_t prev_addr;
266 //mbr_part_t * tmp;
267 mbr_part_t * prev_p;
268 // Encoding and writing first logical partition
269 if (l != &(parts->list.head)) {
270 p = list_get_instance(l, mbr_part_t, link);
271 p->ebr_addr = base;
272 encode_part(p, &(p->ebr->pte[0]), base, false);
273
274 /*if (l->next == &(parts->list.head))
275 encode_part(NULL, &(p->ebr->pte[1]), base, false);
276 else {
277 tmp = list_get_instance(l->next, mbr_part_t, link);
278 //debug_print((unsigned char*) p->ebr, 512);
279 printf("DEBUG: base: %u, tmp: start: %u, end: %u\n", base, tmp->start_addr, tmp->start_addr + tmp->length);
280 //encode_part(tmp, &(p->ebr->pte[1]), base);
281 encode_part(tmp, &(p->ebr->pte[1]), base, true);
282 debug_print(((unsigned char*) p->ebr) + 446, 32);
283 }
284
285 rc = block_write_direct(dev_handle, base, 1, p->ebr);
286 if (rc != EOK) {
287 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
288 goto end;
289 }*/
290
291 l = l->next;
292 } else
293 goto no_logical;
294
295 //prev_addr = base;
296 prev_p = p;
297
298 // Encoding and writing logical partitions
299 while (l != &(parts->list.head)) {
300 p = list_get_instance(l, mbr_part_t, link);
301
302 /* Checking whether EBR address makes sense. If not, we take a guess.
303 * So far this is simple, we just take the first preceeding sector.
304 * Fdisk always reserves at least 2048 sectors (1MiB), so it can have
305 * the EBR aligned as well as the partition itself. Parted reserves
306 * minimum one sector, like we do.
307 *
308 * Note that we know there is at least one sector free from previous checks.
309 * Also note that the user can set ebr_addr to their liking (if it's valid). */
310 if (p->ebr_addr >= p->start_addr || p->ebr_addr <= (prev_p->start_addr + prev_p->length)) {
311 p->ebr_addr = p->start_addr - 1;
312 DEBUG_PRINT_0(LIBMBR_NAME ": Warning: invalid EBR address.\n");
313 }
314
315 encode_part(p, &(p->ebr->pte[0]), p->ebr_addr, false);
316 debug_print(((unsigned char*) p->ebr) + 446, 32);
317 encode_part(p, &(prev_p->ebr->pte[1]), base, true);
318 debug_print(((unsigned char*) prev_p->ebr) + 446, 32);
319 /*if (l->next == &(parts->list.head))
320 encode_part(NULL, &(p->ebr->pte[1]), base, false);
321 else
322 encode_part(list_get_instance(l->next, mbr_part_t, link), &(p->ebr->pte[1]), base, true);
323 */
324
325 rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
326 if (rc != EOK) {
327 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
328 goto end;
329 }
330
331 prev_p = p;
332 l = l->next;
333 }
334
335 encode_part(NULL, &(prev_p->ebr->pte[1]), 0, false);
336 rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
337 if (rc != EOK) {
338 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
339 goto end;
340 }
341
342no_logical:
343no_extended:
344
345 /*if (ext == NULL)
346 goto no_extended;
347
348 uint32_t base = ext->start_addr;
349 uint32_t addr;// = base;
350 uint32_t prev_addr;
351 mbr_part_t * prev_part = NULL;
352
353 list_foreach(parts->list, iter) {
354 p = list_get_instance(iter, mbr_part_t, link);
355 if (mbr_get_flag(p, ST_LOGIC)) {
356 // writing logical partition
357 logical = true;
358
359 if (p->ebr == NULL) {
360 p->ebr = alloc_br();
361 if (p->ebr == NULL)
362 {
363 rc = ENOMEM;
364 goto end;
365 }
366 }
367
368 if (prev_part != NULL) {
369 // addr is the address of EBR
370 addr = p->start_addr - base;
371 // base-1 means start_lba+1
372 encode_part(p, &(p->ebr->pte[0]), addr - 1);
373 encode_part(p, &(prev_part->ebr->pte[1]), base);
374 rc = block_write_direct(dev_handle, prev_addr, 1, prev_part->ebr);
375 if (rc != EOK) {
376 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
377 goto end;
378 }
379 } else {
380 // addr is the address of EBR
381 addr = base;
382 // base-1 means start_lba+1
383 // Fixed: mbr_add_partition now performs checks!nevim
384 encode_part(p, &(p->ebr->pte[0]), base);
385 }
386
387 //addr = p->start_addr;
388 prev_addr = addr;
389 prev_part = p;
390 } else {
391 // writing primary partition
392 if (i >= 4) {
393 rc = EINVAL;
394 goto end;
395 }
396
397 encode_part(p, &(mbr->raw_data.pte[i]), 0);
398
399 ++i;
400 }
401 } //*/
402
403 /* If there was an extended but no logical, we should overwrite
404 * the space where the first logical's EBR would have been. There
405 * might be some garbage from the past.
406 */
407 /*
408 last_ebr = prev_part->ebr;
409
410 if (!logical)
411 {
412 last_ebr = alloc_br();
413 if (last_ebr == NULL) {
414 rc = ENOMEM;
415 goto end;
416 }
417
418 last_ebr->pte[0].ptype = PT_UNUSED;
419 }
420
421
422 encode_part(NULL, &(last_ebr->pte[1]), 0);
423 rc = block_write_direct(dev_handle, addr, 1, last_ebr);
424
425 if (!logical)
426 {
427 free(last_ebr);
428 }
429 */
430 /*
431 if (rc != EOK) {
432 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
433 goto end;
434 }
435
436 goto skip;
437
438no_extended:
439 */
440 /*list_foreach(parts->list, it) {
441 p = list_get_instance(it, mbr_part_t, link);
442 if (mbr_get_flag(p, ST_LOGIC)) {
443 // extended does not exist, fail
444 return EINVAL;
445 } else {
446 // writing primary partition
447 if (i >= 4)
448 return EINVAL;
449
450 encode_part(p, &(mbr->raw_data.pte[i]), 0);
451
452 ++i;
453 }
454 }*/
455 /*
456 it = parts->list.head.next;
457 for (i = 0; i < N_PRIMARY; i++) {
458 if (it != &parts->list.head) {
459 p = list_get_instance(it, mbr_part_t, link);
460 if (mbr_get_flag(p, ST_LOGIC)) {
461 // extended does not exist, fail
462 return EINVAL;
463 } else {
464 // writing primary partition
465 if (i >= 4)
466 return EINVAL;
467
468 encode_part(p, &(mbr->raw_data.pte[i]), 0);
469
470 }
471
472 it = it->next;
473 } else {
474 encode_part(NULL, &(mbr->raw_data.pte[i]), 0);
475 }
476 }
477
478
479skip:
480 rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
481 if (rc != EOK) {
482 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
483 goto end;
484 }
485 */
486
487 /*
488 for (i = 0; i < N_PRIMARY; ++i) {
489 encode_part(&(p->partition), &(mbr->raw_data.pte[i]), 0);
490 if (p->type == PT_EXTENDED)
491 ext = p;
492
493 //p = list_get_instance(p->link.next, mbr_partitions_t, link);
494 p = p->next;
495 }
496
497 rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
498 if (rc != EOK) {
499 block_fini(dev_handle);
500 return rc;
501 }
502
503 //writing logical partitions
504
505 if (p == NULL && ext != NULL) {
506 //we need an empty EBR to rewrite the old EBR on disk, if we need to delete it
507 br_block_t * temp_ebr = alloc_br();
508 if (temp_ebr == NULL) {
509 block_fini(dev_handle);
510 return ENOMEM;
511 }
512
513 temp_ebr->pte[0].ptype = PT_UNUSED;
514 encode_part(NULL, &(temp_ebr->pte[1]), 0);
515 rc = block_write_direct(dev_handle, ext->start_addr, 1, temp_ebr);
516 free(temp_ebr);
517 block_fini(dev_handle);
518 return rc;
519 }
520
521 if (p != NULL && ext == NULL) {
522 block_fini(dev_handle);
523 //no extended but one or more logical? EINVAL to the rescue!
524 return EINVAL;
525 }
526
527 aoff64_t addr = ext->start_addr;
528
529 while (p != NULL) {
530 if (p->type == PT_UNUSED) {
531 p = p->next;
532 continue;
533 }
534 //encode_part(p, &(p->ebr->pte[0]), p->start_addr - 63 * 512);
535 encode_part(p, &(p->ebr->pte[0]), addr);
536 encode_part(p->next, &(p->ebr->pte[1]), ext->start_addr);
537
538 rc = block_write_direct(dev_handle, p->start_addr, 1, p->ebr);
539 if (rc != EOK) {
540 block_fini(dev_handle);
541 return rc;
542 }
543 addr = p->start_addr;
544 p = p->next;
545 }*/
546
547 rc = EOK;
548
549end:
550 block_fini(dev_handle);
551
552 return rc;
553}
554
555/** mbr_part_t constructor */
556mbr_part_t * mbr_alloc_partition(void)
557{
558 mbr_part_t * p = malloc(sizeof(mbr_part_t));
559 if (p == NULL) {
560 return NULL;
561 }
562 link_initialize(&(p->link));
563 p->ebr = NULL;
564 p->type = 0;
565 p->status = 0;
566 p->start_addr = 0;
567 p->length = 0;
568 p->ebr_addr = 0;
569
570 return p;
571}
572
573mbr_partitions_t * mbr_alloc_partitions(void)
574{
575 mbr_partitions_t * parts = malloc(sizeof(mbr_partitions_t));
576 if (parts == NULL) {
577 return NULL;
578 }
579
580 list_initialize(&(parts->list));
581
582 parts->n_primary = 0;
583 parts->n_logical = 0;
584 parts->l_extended = NULL;
585
586 return parts;
587}
588
589/** Add partition
590 * Performs checks, sorts the list.
591 */
592int mbr_add_partition(mbr_partitions_t * parts, mbr_part_t * p)
593{
594 if (mbr_get_flag(p, ST_LOGIC)) { // adding logical part
595 if (parts->l_extended == NULL) {
596 return ERR_NO_EXTENDED;
597 }
598 mbr_part_t * ext = list_get_instance(parts->l_extended, mbr_part_t, link);
599 if (!check_encaps(p, ext)) {
600 //printf("DEBUG: OOB: start: %u, end: %u\n", h->start_addr, h->start_addr + h->length);
601 //printf("DEBUG: OOB: start: %u, end: %u\n", p->start_addr, p->start_addr + p->length);
602 return ERR_OUT_BOUNDS;
603 }
604
605 mbr_part_t * last = list_get_instance(list_last(&(parts->list)), mbr_part_t, link);
606 mbr_part_t * iter;
607 uint32_t ebr_space = 1;
608 mbr_part_foreach(parts, iter) {
609 if (mbr_get_flag(iter, ST_LOGIC)) {
610 if (check_overlap(p, iter)) {
611 //printf("DEBUG: overlap: start: %u, end: %u\n", iter->start_addr, iter->start_addr + iter->length);
612 //printf("DEBUG: overlap: start: %u, end: %u\n", p->start_addr, p->start_addr + p->length);
613 return ERR_OVERLAP;
614 }
615 if (check_preceeds(iter, p)) {
616 last = iter;
617 ebr_space = p->start_addr - (last->start_addr + last->length);
618 } else
619 break;
620 }
621 }
622
623 // checking if there's at least one sector of space preceeding
624
625 if (ebr_space < 1)
626 return ERR_NO_EBR;
627
628 // checking if there's at least one sector of space following (for following partitions's EBR)
629 if (last->link.next != &(parts->list.head)) {
630 if (list_get_instance(&(last->link.next), mbr_part_t, link)->start_addr <= p->start_addr + p->length + 1) {
631 return ERR_NO_EBR;
632 }
633 }
634
635 if (p->ebr == NULL) {
636 p->ebr = alloc_br();
637 if (p->ebr == NULL) {
638 return ERR_NOMEM;
639 }
640 }
641
642 //printf("DEBUG: last: start: %u\n", last->start_addr);
643 //list_prepend(&(p->link), &(parts->list));
644 list_insert_after(&(p->link), &(last->link));
645 parts->n_logical += 1;
646 } else {
647 // adding primary
648 if (parts->n_primary == 4) {
649 return ERR_PRIMARY_FULL;
650 }
651
652 // should we check if it's inside the drive's upper boundary?
653 if (p->start_addr == 0) {
654 return ERR_OUT_BOUNDS;
655 }
656
657 if (p->type == PT_EXTENDED && parts->l_extended != NULL) {
658 return ERR_EXTENDED_PRESENT;
659 }
660
661 if (list_empty(&(parts->list))) {
662 list_append(&(p->link), &(parts->list));
663 } else {
664 mbr_part_t * iter;
665 mbr_part_foreach(parts, iter) {
666 if (mbr_get_flag(iter, ST_LOGIC)) {
667 list_insert_before(&(p->link), &(iter->link));
668 break;
669 } else if (check_overlap(p, iter)) {
670 return ERR_OVERLAP;
671 }
672 }
673 if (iter == list_get_instance(&(parts->list.head.prev), mbr_part_t, link)) {
674 list_append(&(p->link), &(parts->list));
675 }
676
677 }
678 parts->n_primary += 1;
679 }
680
681 return ERR_OK;
682}
683
684/** Remove partition */
685int mbr_remove_partition(mbr_partitions_t * parts, size_t idx)
686{
687 DEBUG_PRINT_1(LIBMBR_NAME "Removing partition: %zu\n", idx);
688 link_t * l = list_nth(&(parts->list), idx);
689 if (l == parts->l_extended) {
690 DEBUG_PRINT_0(LIBMBR_NAME "Removing extended partition.\n");
691 parts->l_extended = NULL;
692 }
693 list_remove(l);
694 mbr_part_t * p = list_get_instance(l, mbr_part_t, link);
695 if (mbr_get_flag(p, ST_LOGIC)) {
696 parts->n_logical -= 1;
697 } else {
698 parts->n_primary -= 1;
699 }
700
701
702 mbr_free_partition(p);
703
704 return EOK;
705}
706
707/** mbr_part_t destructor */
708void mbr_free_partition(mbr_part_t * p)
709{
710 if (p->ebr != NULL)
711 free(p->ebr);
712 free(p);
713}
714
715/** Get flag bool value */
716int mbr_get_flag(mbr_part_t * p, MBR_FLAGS flag)
717{
718 return (p->status & (1 << flag)) ? 1 : 0;
719}
720
721/** Set a specifig status flag to a value */
722void mbr_set_flag(mbr_part_t * p, MBR_FLAGS flag, bool value)
723{
724 uint8_t status = p->status;
725
726 if (value)
727 status = status | (1 << flag);
728 else
729 status = status ^ (status & (1 << flag));
730
731 p->status = status;
732}
733
734/** Get next aligned address (in sectors!) */
735uint32_t mbr_get_next_aligned(uint32_t addr, unsigned int alignment)
736{
737 uint32_t div = addr / alignment;
738 return (div + 1) * alignment;
739}
740
741/** Just a wrapper for free() */
742void mbr_free_mbr(mbr_t * mbr)
743{
744 free(mbr);
745}
746
747/** Free partition list
748 *
749 * @param parts partition list to be freed
750 */
751void mbr_free_partitions(mbr_partitions_t * parts)
752{
753 list_foreach_safe(parts->list, cur_link, next) {
754 mbr_part_t * p = list_get_instance(cur_link, mbr_part_t, link);
755 list_remove(cur_link);
756 mbr_free_partition(p);
757 }
758
759 free(parts);
760}
761
762// Internal functions follow //
763
764static br_block_t * alloc_br()
765{
766 br_block_t * br = malloc(sizeof(br_block_t));
767 if (br == NULL)
768 return NULL;
769
770 memset(br, 0, 512);
771 br->media_id = 0;
772 br->pad0 = 0;
773 br->signature = host2uint16_t_le(BR_SIGNATURE);
774
775 return br;
776}
777
778/** Parse partition entry to mbr_part_t
779 * @return returns 1, if extended partition, 0 otherwise
780 * */
781static int decode_part(pt_entry_t * src, mbr_part_t * trgt, uint32_t base)
782{
783 trgt->type = src->ptype;
784
785 /* Checking only 0x80; otherwise writing will fix to 0x00 */
786 //trgt->bootable = (src->status == B_ACTIVE) ? true : false;
787 mbr_set_flag(trgt, ST_BOOT, (src->status == B_ACTIVE) ? true : false);
788
789 trgt->start_addr = uint32_t_le2host(src->first_lba) + base;
790 trgt->length = uint32_t_le2host(src->length);
791
792 return (src->ptype == PT_EXTENDED) ? 1 : 0;
793}
794
795/** Parse MBR contents to mbr_part_t list */
796static int decode_logical(mbr_t * mbr, mbr_partitions_t * parts, mbr_part_t * ext)
797{
798 int rc;
799 mbr_part_t * p;
800
801 if (mbr == NULL || parts == NULL)
802 return EINVAL;
803
804
805 if (ext == NULL)
806 return EOK;
807
808
809 uint32_t base = ext->start_addr;
810 uint32_t addr = base;
811 br_block_t * ebr;
812
813 rc = block_init(EXCHANGE_ATOMIC, mbr->device, 512);
814 if (rc != EOK)
815 return rc;
816
817 ebr = alloc_br();
818 if (ebr == NULL) {
819 rc = ENOMEM;
820 goto end;
821 }
822
823 rc = block_read_direct(mbr->device, addr, 1, ebr);
824 if (rc != EOK) {
825 goto free_ebr_end;
826 }
827
828 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
829 rc = EINVAL;
830 goto free_ebr_end;
831 }
832
833 if (ebr->pte[0].ptype == PT_UNUSED) {
834 rc = EOK;
835 goto free_ebr_end;
836 }
837
838 p = mbr_alloc_partition();
839 if (p == NULL) {
840 rc = ENOMEM;
841 goto free_ebr_end;
842 }
843
844 decode_part(&(ebr->pte[0]), p, base);
845 mbr_set_flag(p, ST_LOGIC, true);
846 p->ebr = ebr;
847 p->ebr_addr = addr;
848 rc = mbr_add_partition(parts, p);
849 if (rc != ERR_OK) {
850 printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
851 LIBMBR_NAME ": Partition list may be incomplete.\n", rc);
852 return EINVAL;
853 }
854
855 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
856 printf("DEBUG: b: %u, a: %u, start: %u\n", base, addr, ebr->pte[1].first_lba);
857
858 while (ebr->pte[1].ptype != PT_UNUSED) {
859 ebr = alloc_br();
860 if (ebr == NULL) {
861 rc = ENOMEM;
862 goto end;
863 }
864
865 rc = block_read_direct(mbr->device, addr, 1, ebr);
866 if (rc != EOK) {
867 goto free_ebr_end;
868 }
869
870 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
871 rc = EINVAL;
872 goto free_ebr_end;
873 }
874
875 p = mbr_alloc_partition();
876 if (p == NULL) {
877 rc = ENOMEM;
878 goto free_ebr_end;
879 }
880
881 //printf("DEBUG: b: %u, a: %u, start: %u\n", base, addr, ebr->pte[0].first_lba);
882 decode_part(&(ebr->pte[0]), p, addr);
883 mbr_set_flag(p, ST_LOGIC, true);
884 p->ebr = ebr;
885 p->ebr_addr = addr;
886 rc = mbr_add_partition(parts, p);
887 if (rc != ERR_OK) {
888 printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
889 LIBMBR_NAME ": Partition list may be incomplete.\n", rc);
890 return EINVAL;
891 }
892
893 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
894 }
895
896 rc = EOK;
897 goto end;
898
899free_ebr_end:
900 free(ebr);
901
902end:
903 block_fini(mbr->device);
904
905 return rc;
906}
907
908/** Convert mbr_part_t to pt_entry_t */
909static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr)
910{
911 if (src != NULL) {
912 trgt->status = mbr_get_flag(src, ST_BOOT) ? B_ACTIVE : B_INACTIVE;
913 if (ebr) { // encoding reference to EBR
914 trgt->ptype = PT_EXTENDED_LBA;
915 trgt->first_lba = host2uint32_t_le(src->ebr_addr - base);
916 trgt->length = host2uint32_t_le(src->length + src->start_addr - src->ebr_addr);
917 } else { // encoding reference to partition
918 trgt->ptype = src->type;
919 trgt->first_lba = host2uint32_t_le(src->start_addr - base);
920 trgt->length = host2uint32_t_le(src->length);
921 }
922 } else {
923 trgt->status = 0;
924 trgt->first_chs[0] = 0;
925 trgt->first_chs[1] = 0;
926 trgt->first_chs[2] = 0;
927 trgt->ptype = 0;
928 trgt->last_chs[0] = 0;
929 trgt->last_chs[1] = 0;
930 trgt->last_chs[2] = 0;
931 trgt->first_lba = 0;
932 trgt->length = 0;
933 }
934}
935
936static int check_overlap(mbr_part_t * p1, mbr_part_t * p2)
937{
938 if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length < p2->start_addr) {
939 return 0;
940 } else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length < p1->start_addr) {
941 return 0;
942 }
943
944 return 1;
945}
946
947static int check_encaps(mbr_part_t * inner, mbr_part_t * outer)
948{
949 if (inner->start_addr <= outer->start_addr || outer->start_addr + outer->length <= inner->start_addr) {
950 return 0;
951 } else if (outer->start_addr + outer->length < inner->start_addr + inner->length) {
952 return 0;
953 }
954
955 return 1;
956}
957
958static int check_preceeds(mbr_part_t * preceeder, mbr_part_t * precedee)
959{
960 return preceeder->start_addr < precedee->start_addr;
961}
962
963static void debug_print(unsigned char * data, size_t bytes)
964{
965 size_t addr = 0;
966 int i;
967
968 while (bytes >= 16) {
969 printf("%8x ", addr);
970 for (i = 0; i < 8; i++) {
971 printf(" %2hhx", data[addr + i]);
972 }
973 printf(" ");
974 for (i = 0; i < 8; i++) {
975 printf(" %2hhx", data[addr + i + 8]);
976 }
977 printf("\n");
978
979 bytes -= 16;
980 addr += 16;
981 }
982
983
984}
985
986
987
Note: See TracBrowser for help on using the repository browser.