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