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