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