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