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