1 // 2 // partition_map.c - partition map routines 3 // 4 // Written by Eryk Vershen 5 // 6 7 /* 8 * Copyright 1996,1997,1998 by Apple Computer, Inc. 9 * All Rights Reserved 10 * 11 * Permission to use, copy, modify, and distribute this software and 12 * its documentation for any purpose and without fee is hereby granted, 13 * provided that the above copyright notice appears in all copies and 14 * that both the copyright notice and this permission notice appear in 15 * supporting documentation. 16 * 17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE. 20 * 21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 */ 27 28 // for *printf() 29 #include <stdio.h> 30 31 // for malloc(), calloc() & free() 32 #include <stdlib.h> 33 34 // for strncpy() & strcmp() 35 #include <string.h> 36 // for O_RDONLY & O_RDWR 37 #include <fcntl.h> 38 // for errno 39 #include <errno.h> 40 41 #include "partition_map.h" 42 #include "pathname.h" 43 #include "hfs_misc.h" 44 #include "deblock_media.h" 45 #include "io.h" 46 #include "convert.h" 47 #include "util.h" 48 #include "errors.h" 49 50 51 // 52 // Defines 53 // 54 #define APPLE_HFS_FLAGS_VALUE 0x4000037f 55 #define get_align_long(x) (*(x)) 56 #define put_align_long(y, x) ((*(x)) = (y)) 57 // #define TEST_COMPUTE 58 59 60 // 61 // Types 62 // 63 64 65 // 66 // Global Constants 67 // 68 const char * kFreeType = "Apple_Free"; 69 const char * kMapType = "Apple_partition_map"; 70 const char * kUnixType = "OpenBSD"; 71 const char * kHFSType = "Apple_HFS"; 72 const char * kPatchType = "Apple_Patches"; 73 74 const char * kFreeName = "Extra"; 75 76 enum add_action { 77 kReplace = 0, 78 kAdd = 1, 79 kSplit = 2 80 }; 81 82 // 83 // Global Variables 84 // 85 extern int cflag; 86 87 88 // 89 // Forward declarations 90 // 91 int add_data_to_map(struct dpme *, long, partition_map_header *); 92 int coerce_block0(partition_map_header *map); 93 int contains_driver(partition_map *entry); 94 void combine_entry(partition_map *entry); 95 long compute_device_size(partition_map_header *map, partition_map_header *oldmap); 96 DPME* create_data(const char *name, const char *dptype, u32 base, u32 length); 97 void delete_entry(partition_map *entry); 98 char *get_HFS_name(partition_map *entry, int *kind); 99 void insert_in_base_order(partition_map *entry); 100 void insert_in_disk_order(partition_map *entry); 101 int read_block(partition_map_header *map, unsigned long num, char *buf); 102 int read_partition_map(partition_map_header *map); 103 void remove_driver(partition_map *entry); 104 void remove_from_disk_order(partition_map *entry); 105 void renumber_disk_addresses(partition_map_header *map); 106 void sync_device_size(partition_map_header *map); 107 int write_block(partition_map_header *map, unsigned long num, char *buf); 108 109 110 // 111 // Routines 112 // 113 partition_map_header * 114 open_partition_map(char *name, int *valid_file, int ask_logical_size) 115 { 116 MEDIA m; 117 partition_map_header * map; 118 int writable; 119 long size; 120 121 m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR); 122 if (m == 0) { 123 m = open_pathname_as_media(name, O_RDONLY); 124 if (m == 0) { 125 error(errno, "can't open file '%s'", name); 126 *valid_file = 0; 127 return NULL; 128 } else { 129 writable = 0; 130 } 131 } else { 132 writable = 1; 133 } 134 *valid_file = 1; 135 136 map = (partition_map_header *) malloc(sizeof(partition_map_header)); 137 if (map == NULL) { 138 error(errno, "can't allocate memory for open partition map"); 139 close_media(m); 140 return NULL; 141 } 142 map->name = name; 143 map->writable = (rflag)?0:writable; 144 map->changed = 0; 145 map->written = 0; 146 map->disk_order = NULL; 147 map->base_order = NULL; 148 149 map->physical_block = media_granularity(m); /* preflight */ 150 m = open_deblock_media(PBLOCK_SIZE, m); 151 map->m = m; 152 map->misc = (Block0 *) malloc(PBLOCK_SIZE); 153 if (map->misc == NULL) { 154 error(errno, "can't allocate memory for block zero buffer"); 155 close_media(map->m); 156 free(map); 157 return NULL; 158 } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0 159 || convert_block0(map->misc, 1) 160 || coerce_block0(map)) { 161 // if I can't read block 0 I might as well give up 162 error(-1, "Can't read block 0 from '%s'", name); 163 close_partition_map(map); 164 return NULL; 165 } 166 map->physical_block = map->misc->sbBlkSize; 167 //printf("physical block size is %d\n", map->physical_block); 168 169 if (ask_logical_size && interactive) { 170 size = PBLOCK_SIZE; 171 printf("A logical block is %ld bytes: ", size); 172 flush_to_newline(0); 173 get_number_argument("what should be the logical block size? ", 174 &size, size); 175 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE; 176 if (size < PBLOCK_SIZE) { 177 size = PBLOCK_SIZE; 178 } 179 map->logical_block = size; 180 } else { 181 map->logical_block = PBLOCK_SIZE; 182 } 183 if (map->logical_block > MAXIOSIZE) { 184 map->logical_block = MAXIOSIZE; 185 } 186 if (map->logical_block > map->physical_block) { 187 map->physical_block = map->logical_block; 188 } 189 map->blocks_in_map = 0; 190 map->maximum_in_map = -1; 191 map->media_size = compute_device_size(map, map); 192 sync_device_size(map); 193 194 if (read_partition_map(map) < 0) { 195 // some sort of failure reading the map 196 } else { 197 // got it! 198 ; 199 return map; 200 } 201 close_partition_map(map); 202 return NULL; 203 } 204 205 206 void 207 close_partition_map(partition_map_header *map) 208 { 209 partition_map * entry; 210 partition_map * next; 211 212 if (map == NULL) { 213 return; 214 } 215 216 free(map->misc); 217 218 for (entry = map->disk_order; entry != NULL; entry = next) { 219 next = entry->next_on_disk; 220 free(entry->data); 221 free(entry->HFS_name); 222 free(entry); 223 } 224 close_media(map->m); 225 free(map); 226 } 227 228 229 int 230 read_partition_map(partition_map_header *map) 231 { 232 DPME *data; 233 u32 limit; 234 int ix; 235 int old_logical; 236 double d; 237 238 //printf("called read_partition_map\n"); 239 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block); 240 data = (DPME *) malloc(PBLOCK_SIZE); 241 if (data == NULL) { 242 error(errno, "can't allocate memory for disk buffers"); 243 return -1; 244 } 245 246 if (read_block(map, 1, (char *)data) == 0) { 247 error(-1, "Can't read block 1 from '%s'", map->name); 248 free(data); 249 return -1; 250 } else if (convert_dpme(data, 1) 251 || data->dpme_signature != DPME_SIGNATURE) { 252 old_logical = map->logical_block; 253 map->logical_block = 512; 254 while (map->logical_block <= map->physical_block) { 255 if (read_block(map, 1, (char *)data) == 0) { 256 error(-1, "Can't read block 1 from '%s'", map->name); 257 free(data); 258 return -1; 259 } else if (convert_dpme(data, 1) == 0 260 && data->dpme_signature == DPME_SIGNATURE) { 261 d = map->media_size; 262 map->media_size = (d * old_logical) / map->logical_block; 263 break; 264 } 265 map->logical_block *= 2; 266 } 267 if (map->logical_block > map->physical_block) { 268 error(-1, "No valid block 1 on '%s'", map->name); 269 free(data); 270 return -1; 271 } 272 } 273 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block); 274 275 limit = data->dpme_map_entries; 276 ix = 1; 277 while (1) { 278 if (add_data_to_map(data, ix, map) == 0) { 279 free(data); 280 return -1; 281 } 282 283 if (ix >= limit) { 284 break; 285 } else { 286 ix++; 287 } 288 289 data = (DPME *) malloc(PBLOCK_SIZE); 290 if (data == NULL) { 291 error(errno, "can't allocate memory for disk buffers"); 292 return -1; 293 } 294 295 if (read_block(map, ix, (char *)data) == 0) { 296 error(-1, "Can't read block %u from '%s'", ix, map->name); 297 free(data); 298 return -1; 299 } else if (convert_dpme(data, 1) 300 || (data->dpme_signature != DPME_SIGNATURE && dflag == 0) 301 || (data->dpme_map_entries != limit && dflag == 0)) { 302 error(-1, "Bad data in block %u from '%s'", ix, map->name); 303 free(data); 304 return -1; 305 } 306 } 307 return 0; 308 } 309 310 311 void 312 write_partition_map(partition_map_header *map) 313 { 314 MEDIA m; 315 char *block; 316 partition_map * entry; 317 int i = 0; 318 int result = 0; 319 320 m = map->m; 321 if (map->misc != NULL) { 322 convert_block0(map->misc, 0); 323 result = write_block(map, 0, (char *)map->misc); 324 convert_block0(map->misc, 1); 325 } else { 326 block = (char *) calloc(1, PBLOCK_SIZE); 327 if (block != NULL) { 328 result = write_block(map, 0, block); 329 free(block); 330 } 331 } 332 if (result == 0) { 333 error(errno, "Unable to write block zero"); 334 } 335 for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { 336 convert_dpme(entry->data, 0); 337 result = write_block(map, entry->disk_address, (char *)entry->data); 338 convert_dpme(entry->data, 1); 339 i = entry->disk_address; 340 if (result == 0) { 341 error(errno, "Unable to write block %d", i); 342 } 343 } 344 345 if (interactive) 346 printf("The partition table has been altered!\n\n"); 347 348 os_reload_media(map->m); 349 } 350 351 352 int 353 add_data_to_map(struct dpme *data, long ix, partition_map_header *map) 354 { 355 partition_map *entry; 356 357 //printf("add data %d to map\n", ix); 358 entry = (partition_map *) malloc(sizeof(partition_map)); 359 if (entry == NULL) { 360 error(errno, "can't allocate memory for map entries"); 361 return 0; 362 } 363 entry->next_on_disk = NULL; 364 entry->prev_on_disk = NULL; 365 entry->next_by_base = NULL; 366 entry->prev_by_base = NULL; 367 entry->disk_address = ix; 368 entry->the_map = map; 369 entry->data = data; 370 entry->contains_driver = contains_driver(entry); 371 entry->HFS_name = get_HFS_name(entry, &entry->HFS_kind); 372 373 insert_in_disk_order(entry); 374 insert_in_base_order(entry); 375 376 map->blocks_in_map++; 377 if (map->maximum_in_map < 0) { 378 if (istrncmp(data->dpme_type, kMapType, DPISTRLEN) == 0) { 379 map->maximum_in_map = data->dpme_pblocks; 380 } 381 } 382 383 return 1; 384 } 385 386 387 partition_map_header * 388 init_partition_map(char *name, partition_map_header* oldmap) 389 { 390 partition_map_header *map; 391 392 if (oldmap != NULL) { 393 printf("map already exists\n"); 394 if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) { 395 return oldmap; 396 } 397 } 398 399 map = create_partition_map(name, oldmap); 400 if (map == NULL) { 401 return oldmap; 402 } 403 close_partition_map(oldmap); 404 405 add_partition_to_map("Apple", kMapType, 406 1, (map->media_size <= 128? 2: 63), map); 407 return map; 408 } 409 410 411 partition_map_header * 412 create_partition_map(char *name, partition_map_header *oldmap) 413 { 414 MEDIA m; 415 partition_map_header * map; 416 DPME *data; 417 unsigned long default_number; 418 unsigned long number; 419 long size; 420 unsigned long multiple; 421 422 m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR); 423 if (m == 0) { 424 error(errno, "can't open file '%s' for %sing", name, 425 (rflag)?"read":"writ"); 426 return NULL; 427 } 428 429 map = (partition_map_header *) malloc(sizeof(partition_map_header)); 430 if (map == NULL) { 431 error(errno, "can't allocate memory for open partition map"); 432 close_media(m); 433 return NULL; 434 } 435 map->name = name; 436 map->writable = (rflag)?0:1; 437 map->changed = 1; 438 map->disk_order = NULL; 439 map->base_order = NULL; 440 441 if (oldmap != NULL) { 442 size = oldmap->physical_block; 443 } else { 444 size = media_granularity(m); 445 } 446 m = open_deblock_media(PBLOCK_SIZE, m); 447 map->m = m; 448 if (interactive) { 449 printf("A physical block is %ld bytes: ", size); 450 flush_to_newline(0); 451 get_number_argument("what should be the physical block size? ", 452 &size, size); 453 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE; 454 if (size < PBLOCK_SIZE) { 455 size = PBLOCK_SIZE; 456 } 457 } 458 if (map->physical_block > MAXIOSIZE) { 459 map->physical_block = MAXIOSIZE; 460 } 461 map->physical_block = size; 462 // printf("block size is %d\n", map->physical_block); 463 464 if (oldmap != NULL) { 465 size = oldmap->logical_block; 466 } else { 467 size = PBLOCK_SIZE; 468 } 469 if (interactive) { 470 printf("A logical block is %ld bytes: ", size); 471 flush_to_newline(0); 472 get_number_argument("what should be the logical block size? ", 473 &size, size); 474 size = (size / PBLOCK_SIZE) * PBLOCK_SIZE; 475 if (size < PBLOCK_SIZE) { 476 size = PBLOCK_SIZE; 477 } 478 } 479 #if 0 480 if (size > map->physical_block) { 481 size = map->physical_block; 482 } 483 #endif 484 map->logical_block = size; 485 486 map->blocks_in_map = 0; 487 map->maximum_in_map = -1; 488 489 number = compute_device_size(map, oldmap); 490 if (interactive) { 491 printf("size of 'device' is %lu blocks (%d byte blocks): ", 492 number, map->logical_block); 493 default_number = number; 494 flush_to_newline(0); 495 do { 496 if (get_number_argument("what should be the size? ", 497 (long *)&number, default_number) == 0) { 498 printf("Not a number\n"); 499 flush_to_newline(1); 500 number = 0; 501 } else { 502 multiple = get_multiplier(map->logical_block); 503 if (multiple == 0) { 504 printf("Bad multiplier\n"); 505 number = 0; 506 } else if (multiple != 1) { 507 if (0xFFFFFFFF/multiple < number) { 508 printf("Number too large\n"); 509 number = 0; 510 } else { 511 number *= multiple; 512 } 513 } 514 } 515 default_number = kDefault; 516 } while (number == 0); 517 518 if (number < 4) { 519 number = 4; 520 } 521 printf("new size of 'device' is %lu blocks (%d byte blocks)\n", 522 number, map->logical_block); 523 } 524 map->media_size = number; 525 526 map->misc = (Block0 *) calloc(1, PBLOCK_SIZE); 527 if (map->misc == NULL) { 528 error(errno, "can't allocate memory for block zero buffer"); 529 } else { 530 // got it! 531 coerce_block0(map); 532 sync_device_size(map); 533 534 data = (DPME *) calloc(1, PBLOCK_SIZE); 535 if (data == NULL) { 536 error(errno, "can't allocate memory for disk buffers"); 537 } else { 538 // set data into entry 539 data->dpme_signature = DPME_SIGNATURE; 540 data->dpme_map_entries = 1; 541 data->dpme_pblock_start = 1; 542 data->dpme_pblocks = map->media_size - 1; 543 strncpy(data->dpme_name, kFreeName, DPISTRLEN); 544 strncpy(data->dpme_type, kFreeType, DPISTRLEN); 545 data->dpme_lblock_start = 0; 546 data->dpme_lblocks = data->dpme_pblocks; 547 dpme_writable_set(data, 1); 548 dpme_readable_set(data, 1); 549 dpme_bootable_set(data, 0); 550 dpme_in_use_set(data, 0); 551 dpme_allocated_set(data, 0); 552 dpme_valid_set(data, 1); 553 554 if (add_data_to_map(data, 1, map) == 0) { 555 free(data); 556 } else { 557 return map; 558 } 559 } 560 } 561 close_partition_map(map); 562 return NULL; 563 } 564 565 566 int 567 coerce_block0(partition_map_header *map) 568 { 569 Block0 *p; 570 571 p = map->misc; 572 if (p == NULL) { 573 return 1; 574 } 575 if (p->sbSig != BLOCK0_SIGNATURE) { 576 p->sbSig = BLOCK0_SIGNATURE; 577 if (map->physical_block == 1) { 578 p->sbBlkSize = PBLOCK_SIZE; 579 } else { 580 p->sbBlkSize = map->physical_block; 581 } 582 p->sbBlkCount = 0; 583 p->sbDevType = 0; 584 p->sbDevId = 0; 585 p->sbData = 0; 586 p->sbDrvrCount = 0; 587 } 588 return 0; // we do this simply to make it easier to call this function 589 } 590 591 592 int 593 add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length, 594 partition_map_header *map) 595 { 596 partition_map * cur; 597 DPME *data; 598 enum add_action act; 599 int limit; 600 u32 adjusted_base = 0; 601 u32 adjusted_length = 0; 602 u32 new_base = 0; 603 u32 new_length = 0; 604 605 // find a block that starts includes base and length 606 cur = map->base_order; 607 while (cur != NULL) { 608 if (cur->data->dpme_pblock_start <= base 609 && (base + length) <= 610 (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) { 611 break; 612 } else { 613 // check if request is past end of existing partitions, but on disk 614 if ((cur->next_by_base == NULL) && 615 (base + length <= map->media_size)) { 616 // Expand final free partition 617 if ((istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) == 0) && 618 base >= cur->data->dpme_pblock_start) { 619 cur->data->dpme_pblocks = 620 map->media_size - cur->data->dpme_pblock_start; 621 break; 622 } 623 // create an extra free partition 624 if (base >= cur->data->dpme_pblock_start + cur->data->dpme_pblocks) { 625 if (map->maximum_in_map < 0) { 626 limit = map->media_size; 627 } else { 628 limit = map->maximum_in_map; 629 } 630 if (map->blocks_in_map + 1 > limit) { 631 printf("the map is not big enough\n"); 632 return 0; 633 } 634 data = create_data(kFreeName, kFreeType, 635 cur->data->dpme_pblock_start + cur->data->dpme_pblocks, 636 map->media_size - (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)); 637 if (data != NULL) { 638 if (add_data_to_map(data, cur->disk_address, map) == 0) { 639 free(data); 640 } 641 } 642 } 643 } 644 cur = cur->next_by_base; 645 } 646 } 647 // if it is not Extra then punt 648 if (cur == NULL 649 || istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) { 650 printf("requested base and length is not " 651 "within an existing free partition\n"); 652 return 0; 653 } 654 // figure out what to do and sizes 655 data = cur->data; 656 if (data->dpme_pblock_start == base) { 657 // replace or add 658 if (data->dpme_pblocks == length) { 659 act = kReplace; 660 } else { 661 act = kAdd; 662 adjusted_base = base + length; 663 adjusted_length = data->dpme_pblocks - length; 664 } 665 } else { 666 // split or add 667 if (data->dpme_pblock_start + data->dpme_pblocks == base + length) { 668 act = kAdd; 669 adjusted_base = data->dpme_pblock_start; 670 adjusted_length = base - adjusted_base; 671 } else { 672 act = kSplit; 673 new_base = data->dpme_pblock_start; 674 new_length = base - new_base; 675 adjusted_base = base + length; 676 adjusted_length = data->dpme_pblocks - (length + new_length); 677 } 678 } 679 // if the map will overflow then punt 680 if (map->maximum_in_map < 0) { 681 limit = map->media_size; 682 } else { 683 limit = map->maximum_in_map; 684 } 685 if (map->blocks_in_map + act > limit) { 686 printf("the map is not big enough\n"); 687 return 0; 688 } 689 690 data = create_data(name, dptype, base, length); 691 if (data == NULL) { 692 return 0; 693 } 694 if (act == kReplace) { 695 free(cur->data); 696 cur->data = data; 697 } else { 698 // adjust this block's size 699 cur->data->dpme_pblock_start = adjusted_base; 700 cur->data->dpme_pblocks = adjusted_length; 701 cur->data->dpme_lblocks = adjusted_length; 702 // insert new with block address equal to this one 703 if (add_data_to_map(data, cur->disk_address, map) == 0) { 704 free(data); 705 } else if (act == kSplit) { 706 data = create_data(kFreeName, kFreeType, new_base, new_length); 707 if (data != NULL) { 708 // insert new with block address equal to this one 709 if (add_data_to_map(data, cur->disk_address, map) == 0) { 710 free(data); 711 } 712 } 713 } 714 } 715 // renumber disk addresses 716 renumber_disk_addresses(map); 717 // mark changed 718 map->changed = 1; 719 return 1; 720 } 721 722 723 DPME * 724 create_data(const char *name, const char *dptype, u32 base, u32 length) 725 { 726 DPME *data; 727 728 data = (DPME *) calloc(1, PBLOCK_SIZE); 729 if (data == NULL) { 730 error(errno, "can't allocate memory for disk buffers"); 731 } else { 732 // set data into entry 733 data->dpme_signature = DPME_SIGNATURE; 734 data->dpme_map_entries = 1; 735 data->dpme_pblock_start = base; 736 data->dpme_pblocks = length; 737 strncpy(data->dpme_name, name, DPISTRLEN); 738 strncpy(data->dpme_type, dptype, DPISTRLEN); 739 data->dpme_lblock_start = 0; 740 data->dpme_lblocks = data->dpme_pblocks; 741 dpme_init_flags(data); 742 } 743 return data; 744 } 745 746 void 747 dpme_init_flags(DPME *data) 748 { 749 if (istrncmp(data->dpme_type, kHFSType, DPISTRLEN) == 0) { /* XXX this is gross, fix it! */ 750 data->dpme_flags = APPLE_HFS_FLAGS_VALUE; 751 } 752 else { 753 dpme_writable_set(data, 1); 754 dpme_readable_set(data, 1); 755 dpme_bootable_set(data, 0); 756 dpme_in_use_set(data, 0); 757 dpme_allocated_set(data, 1); 758 dpme_valid_set(data, 1); 759 } 760 } 761 762 /* These bits are appropriate for Apple_UNIX_SVR2 partitions 763 * used by OpenBSD. They may be ok for A/UX, but have not been 764 * tested. 765 */ 766 void 767 bzb_init_slice(BZB *bp, int slice) 768 { 769 memset(bp,0,sizeof(BZB)); 770 if ((slice >= 'A') && (slice <= 'Z')) { 771 slice += 'a' - 'A'; 772 } 773 if ((slice != 0) && ((slice < 'a') || (slice > 'z'))) { 774 error(-1,"Bad bzb slice"); 775 slice = 0; 776 } 777 switch (slice) { 778 case 0: 779 case 'c': 780 return; 781 case 'a': 782 bp->bzb_type = FST; 783 strlcpy(bp->bzb_mount_point, "/", sizeof(bp->bzb_mount_point)); 784 bp->bzb_inode = 1; 785 bzb_root_set(bp,1); 786 bzb_usr_set(bp,1); 787 break; 788 case 'b': 789 bp->bzb_type = FSTSFS; 790 strlcpy(bp->bzb_mount_point, "(swap)", sizeof(bp->bzb_mount_point)); 791 break; 792 case 'g': 793 strlcpy(bp->bzb_mount_point, "/usr", sizeof(bp->bzb_mount_point)); 794 /* Fall through */ 795 default: 796 bp->bzb_type = FST; 797 bp->bzb_inode = 1; 798 bzb_usr_set(bp,1); 799 break; 800 } 801 bzb_slice_set(bp,0); // XXX OpenBSD disksubr.c ignores slice 802 // bzb_slice_set(bp,slice-'a'+1); 803 bp->bzb_magic = BZBMAGIC; 804 } 805 806 void 807 renumber_disk_addresses(partition_map_header *map) 808 { 809 partition_map * cur; 810 long ix; 811 812 // reset disk addresses 813 cur = map->disk_order; 814 ix = 1; 815 while (cur != NULL) { 816 cur->disk_address = ix++; 817 cur->data->dpme_map_entries = map->blocks_in_map; 818 cur = cur->next_on_disk; 819 } 820 } 821 822 823 long 824 compute_device_size(partition_map_header *map, partition_map_header *oldmap) 825 { 826 #ifdef TEST_COMPUTE 827 unsigned long length; 828 struct hd_geometry geometry; 829 struct stat info; 830 loff_t pos; 831 #endif 832 char* data; 833 unsigned long l, r, x = 0; 834 long long size; 835 int valid = 0; 836 #ifdef TEST_COMPUTE 837 int fd; 838 839 fd = map->fd->fd; 840 printf("\n"); 841 if (fstat(fd, &info) < 0) { 842 printf("stat of device failed\n"); 843 } else { 844 printf("stat: mode = 0%o, type=%s\n", info.st_mode, 845 (S_ISREG(info.st_mode)? "Regular": 846 (S_ISBLK(info.st_mode)?"Block":"Other"))); 847 printf("size = %d, blocks = %d\n", 848 info.st_size, info.st_size/map->logical_block); 849 } 850 851 if (ioctl(fd, BLKGETSIZE, &length) < 0) { 852 printf("get device size failed\n"); 853 } else { 854 printf("BLKGETSIZE:size in blocks = %u\n", length); 855 } 856 857 if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) { 858 printf("get device geometry failed\n"); 859 } else { 860 printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d, total=%d\n", 861 geometry.heads, geometry.sectors, 862 geometry.cylinders, geometry.start, 863 geometry.heads*geometry.sectors*geometry.cylinders); 864 } 865 866 if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) { 867 printf("llseek to end of device failed\n"); 868 } else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) { 869 printf("llseek to end of device failed on second try\n"); 870 } else { 871 printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block); 872 } 873 #endif 874 875 if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) { 876 return (oldmap->misc->sbBlkCount 877 * (oldmap->physical_block / map->logical_block)); 878 } 879 880 size = media_total_size(map->m); 881 if (size != 0) { 882 return (long)(size / map->logical_block); 883 } 884 885 // else case 886 887 data = (char *) malloc(PBLOCK_SIZE); 888 if (data == NULL) { 889 error(errno, "can't allocate memory for try buffer"); 890 x = 0; 891 } else { 892 // double till off end 893 l = 0; 894 r = 1024; 895 while (read_block(map, r, data) != 0) { 896 l = r; 897 if (r <= 1024) { 898 r = r * 1024; 899 } else { 900 r = r * 2; 901 } 902 if (r >= 0x80000000) { 903 r = 0xFFFFFFFE; 904 break; 905 } 906 } 907 // binary search for end 908 while (l <= r) { 909 x = (r - l) / 2 + l; 910 if ((valid = read_block(map, x, data)) != 0) { 911 l = x + 1; 912 } else { 913 if (x > 0) { 914 r = x - 1; 915 } else { 916 break; 917 } 918 } 919 } 920 if (valid != 0) { 921 x = x + 1; 922 } 923 // printf("size in blocks = %d\n", x); 924 free(data); 925 } 926 927 return x; 928 } 929 930 931 void 932 sync_device_size(partition_map_header *map) 933 { 934 Block0 *p; 935 unsigned long size; 936 double d; 937 938 p = map->misc; 939 if (p == NULL) { 940 return; 941 } 942 d = map->media_size; 943 size = (d * map->logical_block) / p->sbBlkSize; 944 if (p->sbBlkCount != size) { 945 p->sbBlkCount = size; 946 } 947 } 948 949 950 void 951 delete_partition_from_map(partition_map *entry) 952 { 953 partition_map_header *map; 954 DPME *data; 955 956 if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) { 957 printf("Can't delete entry for the map itself\n"); 958 return; 959 } 960 if (entry->contains_driver) { 961 printf("This program can't install drivers\n"); 962 if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) { 963 return; 964 } 965 } 966 // if past end of disk, delete it completely 967 if (entry->next_by_base == NULL && 968 entry->data->dpme_pblock_start >= entry->the_map->media_size) { 969 if (entry->contains_driver) { 970 remove_driver(entry); // update block0 if necessary 971 } 972 delete_entry(entry); 973 return; 974 } 975 // If at end of disk, incorporate extra disk space to partition 976 if (entry->next_by_base == NULL) { 977 entry->data->dpme_pblocks = 978 entry->the_map->media_size - entry->data->dpme_pblock_start; 979 } 980 data = create_data(kFreeName, kFreeType, 981 entry->data->dpme_pblock_start, entry->data->dpme_pblocks); 982 if (data == NULL) { 983 return; 984 } 985 if (entry->contains_driver) { 986 remove_driver(entry); // update block0 if necessary 987 } 988 free(entry->data); 989 free(entry->HFS_name); 990 entry->HFS_kind = kHFS_not; 991 entry->HFS_name = 0; 992 entry->data = data; 993 combine_entry(entry); 994 map = entry->the_map; 995 renumber_disk_addresses(map); 996 map->changed = 1; 997 } 998 999 1000 int 1001 contains_driver(partition_map *entry) 1002 { 1003 partition_map_header *map; 1004 Block0 *p; 1005 DDMap *m; 1006 int i; 1007 int f; 1008 u32 start; 1009 1010 map = entry->the_map; 1011 p = map->misc; 1012 if (p == NULL) { 1013 return 0; 1014 } 1015 if (p->sbSig != BLOCK0_SIGNATURE) { 1016 return 0; 1017 } 1018 if (map->logical_block > p->sbBlkSize) { 1019 return 0; 1020 } else { 1021 f = p->sbBlkSize / map->logical_block; 1022 } 1023 if (p->sbDrvrCount > 0) { 1024 m = (DDMap *) p->sbMap; 1025 for (i = 0; i < p->sbDrvrCount; i++) { 1026 start = get_align_long(&m[i].ddBlock); 1027 if (entry->data->dpme_pblock_start <= f*start 1028 && f*(start + m[i].ddSize) 1029 <= (entry->data->dpme_pblock_start 1030 + entry->data->dpme_pblocks)) { 1031 return 1; 1032 } 1033 } 1034 } 1035 return 0; 1036 } 1037 1038 1039 void 1040 combine_entry(partition_map *entry) 1041 { 1042 partition_map *p; 1043 u32 end; 1044 1045 if (entry == NULL 1046 || istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) { 1047 return; 1048 } 1049 if (entry->next_by_base != NULL) { 1050 p = entry->next_by_base; 1051 if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) { 1052 // next is not free 1053 } else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks 1054 != p->data->dpme_pblock_start) { 1055 // next is not contiguous (XXX this is bad) 1056 printf("next entry is not contiguous\n"); 1057 // start is already minimum 1058 // new end is maximum of two ends 1059 end = p->data->dpme_pblock_start + p->data->dpme_pblocks; 1060 if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) { 1061 entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start; 1062 } 1063 entry->data->dpme_lblocks = entry->data->dpme_pblocks; 1064 delete_entry(p); 1065 } else { 1066 entry->data->dpme_pblocks += p->data->dpme_pblocks; 1067 entry->data->dpme_lblocks = entry->data->dpme_pblocks; 1068 delete_entry(p); 1069 } 1070 } 1071 if (entry->prev_by_base != NULL) { 1072 p = entry->prev_by_base; 1073 if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) { 1074 // previous is not free 1075 } else if (p->data->dpme_pblock_start + p->data->dpme_pblocks 1076 != entry->data->dpme_pblock_start) { 1077 // previous is not contiguous (XXX this is bad) 1078 printf("previous entry is not contiguous\n"); 1079 // new end is maximum of two ends 1080 end = p->data->dpme_pblock_start + p->data->dpme_pblocks; 1081 if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) { 1082 end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks; 1083 } 1084 entry->data->dpme_pblocks = end - p->data->dpme_pblock_start; 1085 // new start is previous entry's start 1086 entry->data->dpme_pblock_start = p->data->dpme_pblock_start; 1087 entry->data->dpme_lblocks = entry->data->dpme_pblocks; 1088 delete_entry(p); 1089 } else { 1090 entry->data->dpme_pblock_start = p->data->dpme_pblock_start; 1091 entry->data->dpme_pblocks += p->data->dpme_pblocks; 1092 entry->data->dpme_lblocks = entry->data->dpme_pblocks; 1093 delete_entry(p); 1094 } 1095 } 1096 entry->contains_driver = contains_driver(entry); 1097 } 1098 1099 1100 void 1101 delete_entry(partition_map *entry) 1102 { 1103 partition_map_header *map; 1104 partition_map *p; 1105 1106 map = entry->the_map; 1107 map->blocks_in_map--; 1108 1109 remove_from_disk_order(entry); 1110 1111 p = entry->next_by_base; 1112 if (map->base_order == entry) { 1113 map->base_order = p; 1114 } 1115 if (p != NULL) { 1116 p->prev_by_base = entry->prev_by_base; 1117 } 1118 if (entry->prev_by_base != NULL) { 1119 entry->prev_by_base->next_by_base = p; 1120 } 1121 1122 free(entry->data); 1123 free(entry->HFS_name); 1124 free(entry); 1125 } 1126 1127 1128 partition_map * 1129 find_entry_by_disk_address(long ix, partition_map_header *map) 1130 { 1131 partition_map * cur; 1132 1133 cur = map->disk_order; 1134 while (cur != NULL) { 1135 if (cur->disk_address == ix) { 1136 break; 1137 } 1138 cur = cur->next_on_disk; 1139 } 1140 return cur; 1141 } 1142 1143 1144 partition_map * 1145 find_entry_by_type(const char *type_name, partition_map_header *map) 1146 { 1147 partition_map * cur; 1148 1149 cur = map->base_order; 1150 while (cur != NULL) { 1151 if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) { 1152 break; 1153 } 1154 cur = cur->next_by_base; 1155 } 1156 return cur; 1157 } 1158 1159 partition_map * 1160 find_entry_by_base(u32 base, partition_map_header *map) 1161 { 1162 partition_map * cur; 1163 1164 cur = map->base_order; 1165 while (cur != NULL) { 1166 if (cur->data->dpme_pblock_start == base) { 1167 break; 1168 } 1169 cur = cur->next_by_base; 1170 } 1171 return cur; 1172 } 1173 1174 1175 void 1176 move_entry_in_map(long old_index, long ix, partition_map_header *map) 1177 { 1178 partition_map * cur; 1179 1180 cur = find_entry_by_disk_address(old_index, map); 1181 if (cur == NULL) { 1182 printf("No such partition\n"); 1183 } else { 1184 remove_from_disk_order(cur); 1185 cur->disk_address = ix; 1186 insert_in_disk_order(cur); 1187 renumber_disk_addresses(map); 1188 map->changed = 1; 1189 } 1190 } 1191 1192 1193 void 1194 remove_from_disk_order(partition_map *entry) 1195 { 1196 partition_map_header *map; 1197 partition_map *p; 1198 1199 map = entry->the_map; 1200 p = entry->next_on_disk; 1201 if (map->disk_order == entry) { 1202 map->disk_order = p; 1203 } 1204 if (p != NULL) { 1205 p->prev_on_disk = entry->prev_on_disk; 1206 } 1207 if (entry->prev_on_disk != NULL) { 1208 entry->prev_on_disk->next_on_disk = p; 1209 } 1210 entry->next_on_disk = NULL; 1211 entry->prev_on_disk = NULL; 1212 } 1213 1214 1215 void 1216 insert_in_disk_order(partition_map *entry) 1217 { 1218 partition_map_header *map; 1219 partition_map * cur; 1220 1221 // find position in disk list & insert 1222 map = entry->the_map; 1223 cur = map->disk_order; 1224 if (cur == NULL || entry->disk_address <= cur->disk_address) { 1225 map->disk_order = entry; 1226 entry->next_on_disk = cur; 1227 if (cur != NULL) { 1228 cur->prev_on_disk = entry; 1229 } 1230 entry->prev_on_disk = NULL; 1231 } else { 1232 for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) { 1233 if (cur->disk_address <= entry->disk_address 1234 && (cur->next_on_disk == NULL 1235 || entry->disk_address <= cur->next_on_disk->disk_address)) { 1236 entry->next_on_disk = cur->next_on_disk; 1237 cur->next_on_disk = entry; 1238 entry->prev_on_disk = cur; 1239 if (entry->next_on_disk != NULL) { 1240 entry->next_on_disk->prev_on_disk = entry; 1241 } 1242 break; 1243 } 1244 } 1245 } 1246 } 1247 1248 1249 void 1250 insert_in_base_order(partition_map *entry) 1251 { 1252 partition_map_header *map; 1253 partition_map * cur; 1254 1255 // find position in base list & insert 1256 map = entry->the_map; 1257 cur = map->base_order; 1258 if (cur == NULL 1259 || entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) { 1260 map->base_order = entry; 1261 entry->next_by_base = cur; 1262 if (cur != NULL) { 1263 cur->prev_by_base = entry; 1264 } 1265 entry->prev_by_base = NULL; 1266 } else { 1267 for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) { 1268 if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start 1269 && (cur->next_by_base == NULL 1270 || entry->data->dpme_pblock_start 1271 <= cur->next_by_base->data->dpme_pblock_start)) { 1272 entry->next_by_base = cur->next_by_base; 1273 cur->next_by_base = entry; 1274 entry->prev_by_base = cur; 1275 if (entry->next_by_base != NULL) { 1276 entry->next_by_base->prev_by_base = entry; 1277 } 1278 break; 1279 } 1280 } 1281 } 1282 } 1283 1284 1285 void 1286 resize_map(long new_size, partition_map_header *map) 1287 { 1288 partition_map * entry; 1289 partition_map * next; 1290 int incr; 1291 1292 // find map entry 1293 entry = find_entry_by_type(kMapType, map); 1294 1295 if (entry == NULL) { 1296 printf("Couldn't find entry for map!\n"); 1297 return; 1298 } 1299 next = entry->next_by_base; 1300 1301 // same size 1302 if (new_size == entry->data->dpme_pblocks) { 1303 // do nothing 1304 return; 1305 } 1306 1307 // make it smaller 1308 if (new_size < entry->data->dpme_pblocks) { 1309 if (next == NULL 1310 || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) { 1311 incr = 1; 1312 } else { 1313 incr = 0; 1314 } 1315 if (new_size < map->blocks_in_map + incr) { 1316 printf("New size would be too small\n"); 1317 return; 1318 } 1319 goto doit; 1320 } 1321 1322 // make it larger 1323 if (next == NULL 1324 || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) { 1325 printf("No free space to expand into\n"); 1326 return; 1327 } 1328 if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks 1329 != next->data->dpme_pblock_start) { 1330 printf("No contiguous free space to expand into\n"); 1331 return; 1332 } 1333 if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) { 1334 printf("No enough free space\n"); 1335 return; 1336 } 1337 doit: 1338 entry->data->dpme_type[0] = 0; 1339 delete_partition_from_map(entry); 1340 add_partition_to_map("Apple", kMapType, 1, new_size, map); 1341 map->maximum_in_map = new_size; 1342 } 1343 1344 1345 void 1346 remove_driver(partition_map *entry) 1347 { 1348 partition_map_header *map; 1349 Block0 *p; 1350 DDMap *m; 1351 int i; 1352 int j; 1353 int f; 1354 u32 start; 1355 1356 map = entry->the_map; 1357 p = map->misc; 1358 if (p == NULL) { 1359 return; 1360 } 1361 if (p->sbSig != BLOCK0_SIGNATURE) { 1362 return; 1363 } 1364 if (map->logical_block > p->sbBlkSize) { 1365 /* this is not supposed to happen, but let's just ignore it. */ 1366 return; 1367 } else { 1368 /* 1369 * compute the factor to convert the block numbers in block0 1370 * into partition map block numbers. 1371 */ 1372 f = p->sbBlkSize / map->logical_block; 1373 } 1374 if (p->sbDrvrCount > 0) { 1375 m = (DDMap *) p->sbMap; 1376 for (i = 0; i < p->sbDrvrCount; i++) { 1377 start = get_align_long(&m[i].ddBlock); 1378 1379 /* zap the driver if it is wholly contained in the partition */ 1380 if (entry->data->dpme_pblock_start <= f*start 1381 && f*(start + m[i].ddSize) 1382 <= (entry->data->dpme_pblock_start 1383 + entry->data->dpme_pblocks)) { 1384 // delete this driver 1385 // by copying down later ones and zapping the last 1386 for (j = i+1; j < p->sbDrvrCount; j++, i++) { 1387 put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock); 1388 m[i].ddSize = m[j].ddSize; 1389 m[i].ddType = m[j].ddType; 1390 } 1391 put_align_long(0, &m[i].ddBlock); 1392 m[i].ddSize = 0; 1393 m[i].ddType = 0; 1394 p->sbDrvrCount -= 1; 1395 return; /* XXX if we continue we will delete other drivers? */ 1396 } 1397 } 1398 } 1399 } 1400 1401 int 1402 read_block(partition_map_header *map, unsigned long num, char *buf) 1403 { 1404 //printf("read block %d\n", num); 1405 return read_media(map->m, ((long long) num) * map->logical_block, 1406 PBLOCK_SIZE, (void *)buf); 1407 } 1408 1409 1410 int 1411 write_block(partition_map_header *map, unsigned long num, char *buf) 1412 { 1413 return write_media(map->m, ((long long) num) * map->logical_block, 1414 PBLOCK_SIZE, (void *)buf); 1415 } 1416