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