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