Home | History | Annotate | Line # | Download | only in dist
      1 //
      2 // partition_map.c - partition map routines
      3 //
      4 // Written by Eryk Vershen
      5 //
      6 
      7 /*
      8  * Copyright 1996,1997,1998 by Apple Computer, Inc.
      9  *              All Rights Reserved
     10  *
     11  * Permission to use, copy, modify, and distribute this software and
     12  * its documentation for any purpose and without fee is hereby granted,
     13  * provided that the above copyright notice appears in all copies and
     14  * that both the copyright notice and this permission notice appear in
     15  * supporting documentation.
     16  *
     17  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
     18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     19  * FOR A PARTICULAR PURPOSE.
     20  *
     21  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
     22  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     23  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
     24  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
     25  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     26  */
     27 
     28 // for *printf()
     29 #include <stdio.h>
     30 
     31 // for malloc(), calloc() & free()
     32 #ifndef __linux__
     33 #include <stdlib.h>
     34 #else
     35 #include <malloc.h>
     36 #endif
     37 
     38 // for strncpy() & strcmp()
     39 #include <string.h>
     40 // for O_RDONLY & O_RDWR
     41 #include <fcntl.h>
     42 // for errno
     43 #include <errno.h>
     44 
     45 #include <inttypes.h>
     46 
     47 #include "partition_map.h"
     48 #include "pathname.h"
     49 #include "hfs_misc.h"
     50 #include "deblock_media.h"
     51 #include "io.h"
     52 #include "convert.h"
     53 #include "util.h"
     54 #include "errors.h"
     55 
     56 
     57 //
     58 // Defines
     59 //
     60 #define APPLE_HFS_FLAGS_VALUE	0x4000037f
     61 #define get_align_long(x)	(*(x))
     62 #define put_align_long(y, x)	((*(x)) = (y))
     63 // #define TEST_COMPUTE
     64 
     65 
     66 //
     67 // Types
     68 //
     69 
     70 
     71 //
     72 // Global Constants
     73 //
     74 const char * kFreeType	= "Apple_Free";
     75 const char * kMapType	= "Apple_partition_map";
     76 const char * kUnixType	= "Apple_UNIX_SVR2";
     77 const char * kHFSType	= "Apple_HFS";
     78 const char * kPatchType	= "Apple_Patches";
     79 
     80 const char * kFreeName	= "Extra";
     81 
     82 enum add_action {
     83     kReplace = 0,
     84     kAdd = 1,
     85     kSplit = 2
     86 };
     87 
     88 //
     89 // Global Variables
     90 //
     91 extern int cflag;
     92 
     93 
     94 //
     95 // Forward declarations
     96 //
     97 int add_data_to_map(struct dpme *, long, partition_map_header *);
     98 int coerce_block0(partition_map_header *map);
     99 int contains_driver(partition_map *entry);
    100 void combine_entry(partition_map *entry);
    101 long compute_device_size(partition_map_header *map, partition_map_header *oldmap);
    102 DPME* create_data(const char *name, const char *dptype, uint32_t base, uint32_t length);
    103 void delete_entry(partition_map *entry);
    104 char *get_HFS_name(partition_map *entry, int *kind);
    105 void insert_in_base_order(partition_map *entry);
    106 void insert_in_disk_order(partition_map *entry);
    107 int read_block(partition_map_header *map, uint32_t num, char *buf);
    108 int read_partition_map(partition_map_header *map);
    109 void remove_driver(partition_map *entry);
    110 void remove_from_disk_order(partition_map *entry);
    111 void renumber_disk_addresses(partition_map_header *map);
    112 void sync_device_size(partition_map_header *map);
    113 int write_block(partition_map_header *map, uint32_t num, char *buf);
    114 
    115 
    116 //
    117 // Routines
    118 //
    119 partition_map_header *
    120 open_partition_map(char *name, int *valid_file, int ask_logical_size)
    121 {
    122     MEDIA m;
    123     partition_map_header * map;
    124     int writable;
    125     long size;
    126 
    127     m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
    128     if (m == 0) {
    129 	m = open_pathname_as_media(name, O_RDONLY);
    130 	if (m == 0) {
    131 	    error(errno, "can't open file '%s'", name);
    132 	    *valid_file = 0;
    133 	    return NULL;
    134 	} else {
    135 	    writable = 0;
    136 	}
    137     } else {
    138 	writable = 1;
    139     }
    140     *valid_file = 1;
    141 
    142     map = (partition_map_header *) malloc(sizeof(partition_map_header));
    143     if (map == NULL) {
    144 	error(errno, "can't allocate memory for open partition map");
    145 	close_media(m);
    146 	return NULL;
    147     }
    148     map->name = name;
    149     map->writable = (rflag)?0:writable;
    150     map->changed = 0;
    151     map->written = 0;
    152     map->disk_order = NULL;
    153     map->base_order = NULL;
    154 
    155     map->physical_block = media_granularity(m);	/* preflight */
    156     m = open_deblock_media(PBLOCK_SIZE, m);
    157     map->m = m;
    158     map->misc = (Block0 *) malloc(PBLOCK_SIZE);
    159     if (map->misc == NULL) {
    160 	error(errno, "can't allocate memory for block zero buffer");
    161 	close_media(map->m);
    162 	free(map);
    163 	return NULL;
    164     } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0
    165 	    || convert_block0(map->misc, 1)
    166 	    || coerce_block0(map)) {
    167 	// if I can't read block 0 I might as well give up
    168 	error(-1, "Can't read block 0 from '%s'", name);
    169 	close_partition_map(map);
    170 	return NULL;
    171     }
    172     map->physical_block = map->misc->sbBlkSize;
    173     //printf("physical block size is %d\n", map->physical_block);
    174 
    175     if (ask_logical_size && interactive) {
    176 	size = PBLOCK_SIZE;
    177 	printf("A logical block is %ld bytes: ", size);
    178 	flush_to_newline(0);
    179 	get_number_argument("what should be the logical block size? ",
    180 		&size, size);
    181 	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
    182 	if (size < PBLOCK_SIZE) {
    183 	    size = PBLOCK_SIZE;
    184 	}
    185 	map->logical_block = size;
    186     } else {
    187 	map->logical_block = PBLOCK_SIZE;
    188     }
    189     if (map->logical_block > MAXIOSIZE) {
    190 	map->logical_block = MAXIOSIZE;
    191     }
    192     if (map->logical_block > map->physical_block) {
    193 	map->physical_block = map->logical_block;
    194     }
    195     map->blocks_in_map = 0;
    196     map->maximum_in_map = -1;
    197     map->media_size = compute_device_size(map, map);
    198     sync_device_size(map);
    199 
    200     if (read_partition_map(map) < 0) {
    201 	// some sort of failure reading the map
    202     } else {
    203 	// got it!
    204 	;
    205 	return map;
    206     }
    207     close_partition_map(map);
    208     return NULL;
    209 }
    210 
    211 
    212 void
    213 close_partition_map(partition_map_header *map)
    214 {
    215     partition_map * entry;
    216     partition_map * next;
    217 
    218     if (map == NULL) {
    219 	return;
    220     }
    221 
    222     free(map->misc);
    223 
    224     for (entry = map->disk_order; entry != NULL; entry = next) {
    225 	next = entry->next_on_disk;
    226 	free(entry->data);
    227 	free(entry->HFS_name);
    228 	free(entry);
    229     }
    230     close_media(map->m);
    231     free(map);
    232 }
    233 
    234 
    235 int
    236 read_partition_map(partition_map_header *map)
    237 {
    238     DPME *data;
    239     uint32_t limit;
    240     uint32_t ix;
    241     int old_logical;
    242     double d;
    243 
    244 //printf("called read_partition_map\n");
    245 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
    246     data = (DPME *) malloc(PBLOCK_SIZE);
    247     if (data == NULL) {
    248 	error(errno, "can't allocate memory for disk buffers");
    249 	return -1;
    250     }
    251 
    252     if (read_block(map, 1, (char *)data) == 0) {
    253 	error(-1, "Can't read block 1 from '%s'", map->name);
    254 	free(data);
    255 	return -1;
    256     } else if (convert_dpme(data, 1)
    257 	    || data->dpme_signature != DPME_SIGNATURE) {
    258 	old_logical = map->logical_block;
    259 	map->logical_block = 512;
    260 	while (map->logical_block <= map->physical_block) {
    261 	    if (read_block(map, 1, (char *)data) == 0) {
    262 		error(-1, "Can't read block 1 from '%s'", map->name);
    263 		free(data);
    264 		return -1;
    265 	    } else if (convert_dpme(data, 1) == 0
    266 		    && data->dpme_signature == DPME_SIGNATURE) {
    267 		d = map->media_size;
    268 		map->media_size =  (d * old_logical) / map->logical_block;
    269 		break;
    270 	    }
    271 	    map->logical_block *= 2;
    272 	}
    273 	if (map->logical_block > map->physical_block) {
    274 	    error(-1, "No valid block 1 on '%s'", map->name);
    275 	    free(data);
    276 	    return -1;
    277 	}
    278     }
    279 //printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
    280 
    281     limit = data->dpme_map_entries;
    282     ix = 1;
    283     while (1) {
    284 	if (add_data_to_map(data, ix, map) == 0) {
    285 	    free(data);
    286 	    return -1;
    287 	}
    288 
    289 	if (ix >= limit) {
    290 	    break;
    291 	} else {
    292 	    ix++;
    293 	}
    294 
    295 	data = (DPME *) malloc(PBLOCK_SIZE);
    296 	if (data == NULL) {
    297 	    error(errno, "can't allocate memory for disk buffers");
    298 	    return -1;
    299 	}
    300 
    301 	if (read_block(map, ix, (char *)data) == 0) {
    302 	    error(-1, "Can't read block %u from '%s'", ix, map->name);
    303 	    free(data);
    304 	    return -1;
    305 	} else if (convert_dpme(data, 1)
    306 		|| (data->dpme_signature != DPME_SIGNATURE && dflag == 0)
    307 		|| (data->dpme_map_entries != limit && dflag == 0)) {
    308 	    error(-1, "Bad data in block %u from '%s'", ix, map->name);
    309 	    free(data);
    310 	    return -1;
    311 	}
    312     }
    313     return 0;
    314 }
    315 
    316 
    317 void
    318 write_partition_map(partition_map_header *map)
    319 {
    320     char *block;
    321     partition_map * entry;
    322     int i = 0;
    323     int result = 0;
    324 
    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 
    371 int
    372 add_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 
    406 partition_map_header *
    407 init_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 
    430 partition_map_header *
    431 create_partition_map(char *name, partition_map_header *oldmap)
    432 {
    433     MEDIA m;
    434     partition_map_header * map;
    435     DPME *data;
    436     uint32_t default_number;
    437     uint32_t number;
    438     long size;
    439     uint32_t 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 %"PRIu32" 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 %"PRIu32" 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 
    587 int
    588 coerce_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 
    613 int
    614 add_partition_to_map(const char *name, const char *dptype, uint32_t base, uint32_t length,
    615 	partition_map_header *map)
    616 {
    617     partition_map * cur;
    618     DPME *data;
    619     enum add_action act;
    620     int limit;
    621     uint32_t adjusted_base = 0;
    622     uint32_t adjusted_length = 0;
    623     uint32_t new_base = 0;
    624     uint32_t 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 
    744 DPME *
    745 create_data(const char *name, const char *dptype, uint32_t base, uint32_t 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 
    767 void
    768 dpme_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  */
    787 void
    788 bzb_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 
    827 void
    828 renumber_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 
    844 long
    845 compute_device_size(partition_map_header *map, partition_map_header *oldmap)
    846 {
    847 #ifdef TEST_COMPUTE
    848     uint32_t length;
    849     struct hd_geometry geometry;
    850     struct stat info;
    851     loff_t pos;
    852 #endif
    853     char* data;
    854     uint32_t 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 
    952 void
    953 sync_device_size(partition_map_header *map)
    954 {
    955     Block0 *p;
    956     uint32_t 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 
    971 void
    972 delete_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 
   1021 int
   1022 contains_driver(partition_map *entry)
   1023 {
   1024     partition_map_header *map;
   1025     Block0 *p;
   1026     DDMap *m;
   1027     int i;
   1028     int f;
   1029     uint32_t 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 
   1060 void
   1061 combine_entry(partition_map *entry)
   1062 {
   1063     partition_map *p;
   1064     uint32_t 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 
   1121 void
   1122 delete_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 
   1149 partition_map *
   1150 find_entry_by_disk_address(int32_t 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 
   1165 partition_map *
   1166 find_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 
   1180 partition_map *
   1181 find_entry_by_base(uint32_t 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 
   1196 void
   1197 move_entry_in_map(int32_t old_index, int32_t 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 
   1214 void
   1215 remove_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 
   1236 void
   1237 insert_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 
   1270 void
   1271 insert_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 
   1306 void
   1307 resize_map(uint32_t new_size, partition_map_header *map)
   1308 {
   1309     partition_map * entry;
   1310     partition_map * next;
   1311     uint32_t 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     }
   1358 doit:
   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 
   1366 void
   1367 remove_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     uint32_t 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 
   1422 int
   1423 read_block(partition_map_header *map, uint32_t 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 
   1431 int
   1432 write_block(partition_map_header *map, uint32_t num, char *buf)
   1433 {
   1434     return write_media(map->m, ((long long) num) * map->logical_block,
   1435     		PBLOCK_SIZE, (void *)buf);
   1436 }
   1437