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