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
RevLine 
[d3a92c87]1/*
[5beb1ff]2 * Copyright (c) 2011, 2012, 2013 Dominik Taborsky
[d3a92c87]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
[271e24a]14 * - The LIBMBR_NAME of the author may not be used to endorse or promote products
[d3a92c87]15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /** @addtogroup libmbr
30 * @{
31 */
32/** @file MBR extraxtion library
33 */
34
35#include <async.h>
[8f6c7785]36#include <assert.h>
[d3a92c87]37#include <block.h>
[8f6c7785]38#include <byteorder.h>
[d3a92c87]39#include <errno.h>
[8f6c7785]40#include <ipc/bd.h>
41#include <mem.h>
42#include <stdio.h>
[d3a92c87]43#include <stdlib.h>
44
45#include "libmbr.h"
46
47static br_block_t * alloc_br(void);
[271e24a]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);
[8f6c7785]50static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr);
[d617050]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);
[d3a92c87]54
[8f6c7785]55static void debug_print(unsigned char * data, size_t bytes);
56
[d3a92c87]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 */
[271e24a]131mbr_partitions_t * mbr_read_partitions(mbr_t * mbr)
[d3a92c87]132{
[8f6c7785]133 int rc, i, rc_ext;
[271e24a]134 mbr_part_t * p;
135 mbr_part_t * ext = NULL;
136 mbr_partitions_t * parts;
[8f6c7785]137
[d3a92c87]138 if (mbr == NULL)
139 return NULL;
[8f6c7785]140
[d3a92c87]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;
[8f6c7785]150
151 //p = malloc(sizeof(mbr_part_t));
152 p = mbr_alloc_partition();
[d3a92c87]153 if (p == NULL) {
[271e24a]154 printf(LIBMBR_NAME ": Error on memory allocation.\n");
[d3a92c87]155 mbr_free_partitions(parts);
156 return NULL;
157 }
[30440ed]158 //list_append(&(p->link), &(parts->list));
[8f6c7785]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) {
[d3a92c87]169 ext = p;
[30440ed]170 parts->l_extended = list_last(&(parts->list));
171 }
[d3a92c87]172 }
[8f6c7785]173
[d3a92c87]174 // Fill in the primary partitions and generate logical ones, if any
175 rc = decode_logical(mbr, parts, ext);
176 if (rc != EOK) {
[271e24a]177 printf(LIBMBR_NAME ": Error occured during decoding the MBR.\n" \
178 LIBMBR_NAME ": Partition list may be incomplete.\n");
[d3a92c87]179 }
[8f6c7785]180
181 //DEBUG:
182 //debug_print((unsigned char *) list_get_instance(list_last(&(parts->list)), mbr_part_t, link)->ebr, 512);
[d3a92c87]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 */
[271e24a]193int mbr_write_partitions(mbr_partitions_t * parts, mbr_t * mbr, service_id_t dev_handle)
[d3a92c87]194{
[d617050]195 //bool logical = false;
[d3a92c87]196 int i = 0;
197 int rc;
[271e24a]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);
[8f6c7785]201
[d617050]202 //br_block_t * last_ebr = NULL;
203 //link_t * it;
[8f6c7785]204
[30440ed]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);
[8f6c7785]206
[d3a92c87]207 rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
208 if (rc != EOK) {
[30440ed]209 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
[d3a92c87]210 return rc;
211 }
[d617050]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 }*/
[8f6c7785]241
[d617050]242 link_t * l = parts->list.head.next;
[8f6c7785]243
[d617050]244 // Encoding primary partitions
245 for (i = 0; i < parts->n_primary; i++) {
246 p = list_get_instance(l, mbr_part_t, link);
[8f6c7785]247 encode_part(p, &(mbr->raw_data.pte[i]), 0, false);
[d617050]248 l = l->next;
249 }
[8f6c7785]250
[d617050]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 }
[8f6c7785]257
[d3a92c87]258 if (ext == NULL)
259 goto no_extended;
[8f6c7785]260
261 //DEBUG:
262 //debug_print((unsigned char *) list_get_instance(list_last(&(parts->list)), mbr_part_t, link)->ebr, 512);
[30440ed]263 uint32_t base = ext->start_addr;
[8f6c7785]264 //uint32_t addr = base;
265 //uint32_t prev_addr;
266 //mbr_part_t * tmp;
267 mbr_part_t * prev_p;
[d617050]268 // Encoding and writing first logical partition
269 if (l != &(parts->list.head)) {
270 p = list_get_instance(l, mbr_part_t, link);
[8f6c7785]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);
[d617050]283 }
[8f6c7785]284
[d617050]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;
[8f6c7785]289 }*/
290
[d617050]291 l = l->next;
[8f6c7785]292 } else
293 goto no_logical;
294
295 //prev_addr = base;
296 prev_p = p;
297
[d617050]298 // Encoding and writing logical partitions
299 while (l != &(parts->list.head)) {
300 p = list_get_instance(l, mbr_part_t, link);
[8f6c7785]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");
[d617050]313 }
[8f6c7785]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);
[d617050]321 else
[8f6c7785]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);
[d617050]326 if (rc != EOK) {
327 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
328 goto end;
329 }
[8f6c7785]330
331 prev_p = p;
[d617050]332 l = l->next;
333 }
[8f6c7785]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:
[d617050]343no_extended:
[8f6c7785]344
[d617050]345 /*if (ext == NULL)
346 goto no_extended;
347
348 uint32_t base = ext->start_addr;
349 uint32_t addr;// = base;
[30440ed]350 uint32_t prev_addr;
[271e24a]351 mbr_part_t * prev_part = NULL;
[d3a92c87]352
[30440ed]353 list_foreach(parts->list, iter) {
354 p = list_get_instance(iter, mbr_part_t, link);
[d3a92c87]355 if (mbr_get_flag(p, ST_LOGIC)) {
356 // writing logical partition
[d617050]357 logical = true;
358
[d3a92c87]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) {
[30440ed]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));
[d3a92c87]377 goto end;
[30440ed]378 }
379 } else {
380 // addr is the address of EBR
381 addr = base;
382 // base-1 means start_lba+1
[d617050]383 // Fixed: mbr_add_partition now performs checks!nevim
384 encode_part(p, &(p->ebr->pte[0]), base);
[d3a92c87]385 }
[d617050]386
[30440ed]387 //addr = p->start_addr;
388 prev_addr = addr;
[d3a92c87]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 }
[d617050]401 } //*/
[d3a92c87]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 */
[d617050]407 /*
[d3a92c87]408 last_ebr = prev_part->ebr;
[d617050]409
[d3a92c87]410 if (!logical)
411 {
412 last_ebr = alloc_br();
413 if (last_ebr == NULL) {
414 rc = ENOMEM;
415 goto end;
416 }
[d617050]417
[d3a92c87]418 last_ebr->pte[0].ptype = PT_UNUSED;
419 }
[d617050]420
421
[d3a92c87]422 encode_part(NULL, &(last_ebr->pte[1]), 0);
423 rc = block_write_direct(dev_handle, addr, 1, last_ebr);
[d617050]424
[d3a92c87]425 if (!logical)
426 {
427 free(last_ebr);
428 }
[d617050]429 */
430 /*
[30440ed]431 if (rc != EOK) {
432 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
[d3a92c87]433 goto end;
[30440ed]434 }
[d3a92c87]435
436 goto skip;
437
438no_extended:
[d617050]439 */
[30440ed]440 /*list_foreach(parts->list, it) {
[271e24a]441 p = list_get_instance(it, mbr_part_t, link);
[d3a92c87]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 }
[30440ed]454 }*/
[d617050]455 /*
[30440ed]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 }
[d617050]471
[30440ed]472 it = it->next;
473 } else {
474 encode_part(NULL, &(mbr->raw_data.pte[i]), 0);
475 }
[d3a92c87]476 }
[d617050]477
[d3a92c87]478
479skip:
480 rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
[30440ed]481 if (rc != EOK) {
482 DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
[d3a92c87]483 goto end;
[30440ed]484 }
[d617050]485 */
[d3a92c87]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
[271e24a]493 //p = list_get_instance(p->link.next, mbr_partitions_t, link);
[d3a92c87]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 }*/
[8f6c7785]546
[d3a92c87]547 rc = EOK;
[8f6c7785]548
[d3a92c87]549end:
550 block_fini(dev_handle);
[8f6c7785]551
[d3a92c87]552 return rc;
553}
554
[271e24a]555/** mbr_part_t constructor */
556mbr_part_t * mbr_alloc_partition(void)
[d3a92c87]557{
[271e24a]558 mbr_part_t * p = malloc(sizeof(mbr_part_t));
[d3a92c87]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;
[8f6c7785]568 p->ebr_addr = 0;
[d3a92c87]569
570 return p;
571}
572
[271e24a]573mbr_partitions_t * mbr_alloc_partitions(void)
[d3a92c87]574{
[271e24a]575 mbr_partitions_t * parts = malloc(sizeof(mbr_partitions_t));
[d3a92c87]576 if (parts == NULL) {
577 return NULL;
578 }
579
580 list_initialize(&(parts->list));
[d617050]581
[30440ed]582 parts->n_primary = 0;
583 parts->n_logical = 0;
584 parts->l_extended = NULL;
[d3a92c87]585
586 return parts;
587}
588
[d617050]589/** Add partition
590 * Performs checks, sorts the list.
591 */
[30440ed]592int mbr_add_partition(mbr_partitions_t * parts, mbr_part_t * p)
[d3a92c87]593{
[8f6c7785]594 if (mbr_get_flag(p, ST_LOGIC)) { // adding logical part
[d617050]595 if (parts->l_extended == NULL) {
596 return ERR_NO_EXTENDED;
597 }
[8f6c7785]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);
[d617050]602 return ERR_OUT_BOUNDS;
603 }
604
605 mbr_part_t * last = list_get_instance(list_last(&(parts->list)), mbr_part_t, link);
[8f6c7785]606 mbr_part_t * iter;
607 uint32_t ebr_space = 1;
[d617050]608 mbr_part_foreach(parts, iter) {
609 if (mbr_get_flag(iter, ST_LOGIC)) {
610 if (check_overlap(p, iter)) {
[8f6c7785]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);
[d617050]613 return ERR_OVERLAP;
614 }
[8f6c7785]615 if (check_preceeds(iter, p)) {
[d617050]616 last = iter;
[8f6c7785]617 ebr_space = p->start_addr - (last->start_addr + last->length);
618 } else
[d617050]619 break;
620 }
621 }
[8f6c7785]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);
[d617050]643 //list_prepend(&(p->link), &(parts->list));
[8f6c7785]644 list_insert_after(&(p->link), &(last->link));
[30440ed]645 parts->n_logical += 1;
646 } else {
[d617050]647 // adding primary
648 if (parts->n_primary == 4) {
649 return ERR_PRIMARY_FULL;
650 }
[8f6c7785]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
[d617050]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 {
[8f6c7785]664 mbr_part_t * iter;
[d617050]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 }
[8f6c7785]673 if (iter == list_get_instance(&(parts->list.head.prev), mbr_part_t, link)) {
674 list_append(&(p->link), &(parts->list));
675 }
676
[d617050]677 }
[8f6c7785]678 parts->n_primary += 1;
[30440ed]679 }
[d617050]680
681 return ERR_OK;
[d3a92c87]682}
683
684/** Remove partition */
[271e24a]685int mbr_remove_partition(mbr_partitions_t * parts, size_t idx)
[d3a92c87]686{
[d617050]687 DEBUG_PRINT_1(LIBMBR_NAME "Removing partition: %zu\n", idx);
[d3a92c87]688 link_t * l = list_nth(&(parts->list), idx);
[30440ed]689 if (l == parts->l_extended) {
690 DEBUG_PRINT_0(LIBMBR_NAME "Removing extended partition.\n");
691 parts->l_extended = NULL;
692 }
[d3a92c87]693 list_remove(l);
[271e24a]694 mbr_part_t * p = list_get_instance(l, mbr_part_t, link);
[30440ed]695 if (mbr_get_flag(p, ST_LOGIC)) {
696 parts->n_logical -= 1;
697 } else {
698 parts->n_primary -= 1;
699 }
[d617050]700
701
[d3a92c87]702 mbr_free_partition(p);
[d617050]703
[271e24a]704 return EOK;
[d3a92c87]705}
706
[271e24a]707/** mbr_part_t destructor */
708void mbr_free_partition(mbr_part_t * p)
[d3a92c87]709{
710 if (p->ebr != NULL)
711 free(p->ebr);
712 free(p);
713}
714
715/** Get flag bool value */
[271e24a]716int mbr_get_flag(mbr_part_t * p, MBR_FLAGS flag)
[d3a92c87]717{
718 return (p->status & (1 << flag)) ? 1 : 0;
719}
720
721/** Set a specifig status flag to a value */
[271e24a]722void mbr_set_flag(mbr_part_t * p, MBR_FLAGS flag, bool value)
[d3a92c87]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
[8f6c7785]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
[d3a92c87]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 */
[271e24a]751void mbr_free_partitions(mbr_partitions_t * parts)
[d3a92c87]752{
753 list_foreach_safe(parts->list, cur_link, next) {
[271e24a]754 mbr_part_t * p = list_get_instance(cur_link, mbr_part_t, link);
[d3a92c87]755 list_remove(cur_link);
756 mbr_free_partition(p);
757 }
[d617050]758
[30440ed]759 free(parts);
[d3a92c87]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;
[8f6c7785]769
770 memset(br, 0, 512);
[d3a92c87]771 br->media_id = 0;
772 br->pad0 = 0;
773 br->signature = host2uint16_t_le(BR_SIGNATURE);
[8f6c7785]774
[d3a92c87]775 return br;
776}
777
[30440ed]778/** Parse partition entry to mbr_part_t
779 * @return returns 1, if extended partition, 0 otherwise
780 * */
[271e24a]781static int decode_part(pt_entry_t * src, mbr_part_t * trgt, uint32_t base)
[d3a92c87]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
[30440ed]795/** Parse MBR contents to mbr_part_t list */
[271e24a]796static int decode_logical(mbr_t * mbr, mbr_partitions_t * parts, mbr_part_t * ext)
[d3a92c87]797{
798 int rc;
[271e24a]799 mbr_part_t * p;
[d3a92c87]800
801 if (mbr == NULL || parts == NULL)
802 return EINVAL;
803
804
805 if (ext == NULL)
806 return EOK;
807
808
[30440ed]809 uint32_t base = ext->start_addr;
810 uint32_t addr = base;
[d3a92c87]811 br_block_t * ebr;
[8f6c7785]812
[d3a92c87]813 rc = block_init(EXCHANGE_ATOMIC, mbr->device, 512);
814 if (rc != EOK)
815 return rc;
[8f6c7785]816
[30440ed]817 ebr = alloc_br();
818 if (ebr == NULL) {
819 rc = ENOMEM;
820 goto end;
821 }
[8f6c7785]822
[30440ed]823 rc = block_read_direct(mbr->device, addr, 1, ebr);
824 if (rc != EOK) {
825 goto free_ebr_end;
826 }
[8f6c7785]827
[30440ed]828 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
829 rc = EINVAL;
830 goto free_ebr_end;
831 }
[8f6c7785]832
[30440ed]833 if (ebr->pte[0].ptype == PT_UNUSED) {
834 rc = EOK;
835 goto free_ebr_end;
836 }
[8f6c7785]837
[30440ed]838 p = mbr_alloc_partition();
839 if (p == NULL) {
840 rc = ENOMEM;
841 goto free_ebr_end;
842 }
[8f6c7785]843
[30440ed]844 decode_part(&(ebr->pte[0]), p, base);
845 mbr_set_flag(p, ST_LOGIC, true);
846 p->ebr = ebr;
[8f6c7785]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
[30440ed]855 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
[8f6c7785]856 printf("DEBUG: b: %u, a: %u, start: %u\n", base, addr, ebr->pte[1].first_lba);
857
[30440ed]858 while (ebr->pte[1].ptype != PT_UNUSED) {
[d3a92c87]859 ebr = alloc_br();
860 if (ebr == NULL) {
[30440ed]861 rc = ENOMEM;
862 goto end;
[d3a92c87]863 }
[8f6c7785]864
[d3a92c87]865 rc = block_read_direct(mbr->device, addr, 1, ebr);
866 if (rc != EOK) {
[30440ed]867 goto free_ebr_end;
[d3a92c87]868 }
[8f6c7785]869
[d3a92c87]870 if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
[30440ed]871 rc = EINVAL;
872 goto free_ebr_end;
[d3a92c87]873 }
[8f6c7785]874
[d3a92c87]875 p = mbr_alloc_partition();
[30440ed]876 if (p == NULL) {
877 rc = ENOMEM;
878 goto free_ebr_end;
879 }
[8f6c7785]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);
[d3a92c87]883 mbr_set_flag(p, ST_LOGIC, true);
884 p->ebr = ebr;
[8f6c7785]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
[30440ed]893 addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
894 }
[8f6c7785]895
[30440ed]896 rc = EOK;
[8f6c7785]897 goto end;
898
[30440ed]899free_ebr_end:
900 free(ebr);
[8f6c7785]901
[30440ed]902end:
[d3a92c87]903 block_fini(mbr->device);
[8f6c7785]904
[30440ed]905 return rc;
[d3a92c87]906}
907
[271e24a]908/** Convert mbr_part_t to pt_entry_t */
[8f6c7785]909static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr)
[d3a92c87]910{
911 if (src != NULL) {
912 trgt->status = mbr_get_flag(src, ST_BOOT) ? B_ACTIVE : B_INACTIVE;
[8f6c7785]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 }
[d3a92c87]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
[d617050]936static int check_overlap(mbr_part_t * p1, mbr_part_t * p2)
937{
[8f6c7785]938 if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length < p2->start_addr) {
[d617050]939 return 0;
[8f6c7785]940 } else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length < p1->start_addr) {
[d617050]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
[8f6c7785]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
[d617050]986
987
Note: See TracBrowser for help on using the repository browser.