1/*	$OpenBSD: partition_map.c,v 1.99 2019/07/31 00:14:10 krw Exp $	*/
2
3/*
4 * partition_map.c - partition map routines
5 *
6 * Written by Eryk Vershen
7 */
8
9/*
10 * Copyright 1996,1997,1998 by Apple Computer, Inc.
11 *              All Rights Reserved
12 *
13 * Permission to use, copy, modify, and distribute this software and
14 * its documentation for any purpose and without fee is hereby granted,
15 * provided that the above copyright notice appears in all copies and
16 * that both the copyright notice and this permission notice appear in
17 * supporting documentation.
18 *
19 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE.
22 *
23 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
25 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
26 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
27 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 */
29
30#include <sys/queue.h>
31#include <sys/stdint.h>
32
33#include <err.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include "partition_map.h"
39#include "io.h"
40#include "file_media.h"
41
42#define APPLE_HFS_FLAGS_VALUE	0x4000037f
43
44const char     *kFreeType = "Apple_Free";
45const char     *kMapType = "Apple_partition_map";
46const char     *kUnixType = "OpenBSD";
47const char     *kHFSType = "Apple_HFS";
48
49void		combine_entry(struct entry *);
50struct entry   *create_entry(struct partition_map *, long, const char *,
51    const char *, uint32_t, uint32_t);
52void		delete_entry(struct entry *);
53void		insert_in_base_order(struct entry *);
54void		insert_in_disk_order(struct entry *);
55int		read_partition_map(struct partition_map *);
56void		remove_driver(struct entry *);
57void		renumber_disk_addresses(struct partition_map *);
58
59struct partition_map *
60open_partition_map(int fd, char *name, uint64_t mediasz, uint32_t sectorsz)
61{
62	struct partition_map *map;
63	int ok;
64
65	map = malloc(sizeof(struct partition_map));
66	if (map == NULL)
67		errx(1, "No memory to open partition map");
68
69	map->fd = fd;
70	map->name = name;
71
72	map->changed = 0;
73	LIST_INIT(&map->disk_order);
74	LIST_INIT(&map->base_order);
75	map->blocks_in_map = 0;
76	map->maximum_in_map = -1;
77
78	if (mediasz > UINT32_MAX)
79		map->media_size = UINT32_MAX;
80	else
81		map->media_size = mediasz;
82
83	if (read_block0(map->fd, map) == 0) {
84		warnx("Can't read block 0 from '%s'", name);
85		free_partition_map(map);
86		return NULL;
87	}
88	if (map->sbSig == BLOCK0_SIGNATURE &&
89	    map->sbBlkSize == sectorsz &&
90	    map->sbBlkCount <= mediasz) {
91		if (read_partition_map(map) == 0)
92			return map;
93	} else {
94		if (map->sbSig != BLOCK0_SIGNATURE)
95			warnx("Block 0 signature: Expected 0x%04x, "
96			    "got 0x%04x", BLOCK0_SIGNATURE,
97			    map->sbSig);
98		else if (map->sbBlkSize != sectorsz)
99			warnx("Block 0 sbBlkSize (%u) != sector size (%u)",
100			    map->sbBlkSize, sectorsz);
101		else if (map->sbBlkCount > mediasz)
102			warnx("Block 0 sbBlkCount (%u) > media size (%llu)",
103			    map->sbBlkCount,
104			    (unsigned long long)mediasz);
105	}
106
107	if (!lflag) {
108		my_ungetch('\n');
109		printf("No valid partition map found on '%s'.\n", name);
110		ok = get_okay("Create default map? [n/y]: ", 0);
111		flush_to_newline(0);
112		if (ok == 1) {
113			free_partition_map(map);
114			map = create_partition_map(fd, name, mediasz, sectorsz);
115			if (map)
116				return map;
117		}
118	}
119
120	free_partition_map(map);
121	return NULL;
122}
123
124
125void
126free_partition_map(struct partition_map *map)
127{
128	struct entry *entry;
129
130	if (map == NULL)
131		return;
132
133	while (!LIST_EMPTY(&map->disk_order)) {
134		entry = LIST_FIRST(&map->disk_order);
135		LIST_REMOVE(entry, disk_entry);
136		free(entry);
137	}
138
139	free(map);
140}
141
142int
143read_partition_map(struct partition_map *map)
144{
145	struct entry *cur, *nextcur;
146	struct entry *entry;
147	int ix;
148	uint32_t limit, base, next, nextbase;
149
150	limit = 1; /* There has to be at least one, which has the real limit. */
151	for (ix = 1; ix <= limit; ix++) {
152		entry = malloc(sizeof(struct entry));
153		if (entry == NULL)
154			errx(1, "No memory for partition entry");
155		if (read_dpme(map->fd, ix, entry) == 0) {
156			warnx("Can't read block %u from '%s'", ix, map->name);
157			free(entry);
158			return 1;
159		}
160		if (entry->dpme_signature != DPME_SIGNATURE) {
161			warnx("Invalid signature on block %d. Expected %x, "
162			    "got %x", ix, DPME_SIGNATURE,
163			    entry->dpme_signature);
164			free(entry);
165			return 1;
166		}
167		if (ix == 1) {
168			if (entry->dpme_map_entries > entry->dpme_pblocks) {
169				warnx("Map entry count (%u) > # of physical "
170				    "blocks (%u)", entry->dpme_map_entries,
171				    entry->dpme_pblocks);
172				free(entry);
173				return 1;
174			}
175			if (entry->dpme_map_entries == 0) {
176				warnx("Map entry count ==  0. Must be > 0");
177				free(entry);
178				return 1;
179			}
180			map->maximum_in_map = entry->dpme_pblocks;
181			limit = entry->dpme_map_entries;
182		}
183		if (limit != entry->dpme_map_entries) {
184			warnx("Invalid entry count on block %d. "
185			    "Expected %d, got %d", ix, limit,
186			    entry->dpme_map_entries);
187			free(entry);
188			return 1;
189		}
190		if (entry->dpme_lblock_start >= entry->dpme_pblocks) {
191			warnx("\tlogical start (%u) >= block count"
192			    "count (%u).", entry->dpme_lblock_start,
193			    entry->dpme_pblocks);
194			free(entry);
195			return 1;
196		}
197		if (entry->dpme_lblocks > entry->dpme_pblocks -
198			entry->dpme_lblock_start) {
199			warnx("\tlogical blocks (%u) > available blocks (%u).",
200			    entry->dpme_lblocks,
201			    entry->dpme_pblocks - entry->dpme_lblock_start);
202			free(entry);
203			return 1;
204		}
205		entry->the_map = map;
206		entry->disk_address = ix;
207		insert_in_disk_order(entry);
208		insert_in_base_order(entry);
209		map->blocks_in_map++;
210	}
211
212	/* Traverse base_order looking for
213	 *
214	 * 1) Overlapping partitions
215	 * 2) Unmapped space
216	 */
217	LIST_FOREACH(cur, &map->base_order, base_entry) {
218		base = cur->dpme_pblock_start;
219		next = base + cur->dpme_pblocks;
220		if (base >= map->media_size ||
221		    next < base ||
222		    next > map->media_size) {
223			warnx("Partition extends past end of disk: %u -> %u",
224			    base, next);
225		}
226		nextcur = LIST_NEXT(cur, base_entry);
227		if (nextcur)
228			nextbase = nextcur->dpme_pblock_start;
229		else
230			nextbase = map->media_size;
231		if (next != nextbase)
232			warnx("Unmapped pblocks: %u -> %u", next, nextbase);
233		if (next > nextbase)
234			warnx("Partition %ld overlaps next partition",
235			    cur->disk_address);
236	}
237
238	return 0;
239}
240
241
242void
243write_partition_map(struct partition_map *map)
244{
245	struct entry *entry;
246	int result;
247
248	result = write_block0(map->fd, map);
249	if (result == 0)
250		warn("Unable to write block zero");
251
252	LIST_FOREACH(entry, &map->disk_order, disk_entry) {
253		result = write_dpme(map->fd, entry->disk_address, entry);
254		if (result == 0)
255			warn("Unable to write block %ld", entry->disk_address);
256	}
257}
258
259
260struct partition_map *
261create_partition_map(int fd, char *name, u_int64_t mediasz, uint32_t sectorsz)
262{
263	struct partition_map *map;
264	struct entry *entry;
265
266	map = malloc(sizeof(struct partition_map));
267	if (map == NULL)
268		errx(1, "No memory to create partition map");
269
270	map->name = name;
271	map->fd = fd;
272	map->changed = 1;
273	LIST_INIT(&map->disk_order);
274	LIST_INIT(&map->base_order);
275
276	map->blocks_in_map = 0;
277	map->maximum_in_map = -1;
278	map->media_size = mediasz;
279
280	map->sbSig = BLOCK0_SIGNATURE;
281	map->sbBlkSize = sectorsz;
282	map->sbBlkCount = map->media_size;
283
284	entry = create_entry(map, 1, "", kFreeType, 1, mediasz - 1);
285	if (entry == NULL)
286		errx(1, "No memory for new dpme");
287
288	add_partition_to_map("Apple", kMapType, 1,
289	    (map->media_size <= 128 ? 2 : 63), map);
290
291	return map;
292}
293
294
295int
296add_partition_to_map(const char *name, const char *dptype, uint32_t base,
297    uint32_t length, struct partition_map *map)
298{
299	struct entry *cur;
300	int limit, new_entries;
301	uint32_t old_base, old_length, old_address;
302	uint32_t new_base, new_length;
303
304	if (map->maximum_in_map < 0)
305		limit = map->media_size;
306	else
307		limit = map->maximum_in_map;
308
309	/* find a block of free space that starts includes base and length */
310	LIST_FOREACH(cur, &map->base_order, base_entry) {
311		if (strncasecmp(cur->dpme_type, kFreeType, DPISTRLEN))
312		    continue;
313		if (cur->dpme_pblock_start <= base &&
314		    (base + length) <=
315		    (cur->dpme_pblock_start + cur->dpme_pblocks))
316			break;
317	}
318	if (cur == NULL) {
319		printf("requested base and length is not "
320		       "within an existing free partition\n");
321		return 0;
322	}
323	old_base = cur->dpme_pblock_start;
324	old_length = cur->dpme_pblocks;
325	old_address = cur->disk_address;
326
327	/* Check that there is enough room in the map for the new entries! */
328	if (base == old_base && length == old_length)
329		new_entries = 0;
330	else if (base == old_base)
331		new_entries = 1;
332	else if (base - old_base < old_length - length)
333		new_entries = 2;
334	else
335		new_entries = 1;
336	if (map->blocks_in_map + new_entries > limit) {
337		printf("the map is not big enough\n");
338		return 0;
339	}
340
341	/*
342	 * Delete old free entry from map and add back 1 to 3 new entries.
343	 *
344	 * 1) Empty space from base+len to old end.
345	 * 2) New entry from specified base for length.
346	 * 3) Empty space from old base to new base.
347	 *
348	 *  All with the same disk address, so they must be added in that
349	 *  order!
350	 */
351	delete_entry(cur);
352
353	new_base = base + length;
354	new_length = (old_base + old_length) - new_base;
355	if (new_length > 0) {
356		/* New free space entry *after* new partition. */
357		cur = create_entry(map, old_address, "", kFreeType, new_base,
358		    new_length);
359		if (cur == NULL)
360			errx(1, "No memory for new dpme");
361	}
362
363	cur = create_entry(map, old_address, name, dptype, base, length);
364	if (cur == NULL)
365		errx(1, "No memory for new entry");
366
367	new_length = base - old_base;
368	if (new_length > 0) {
369		/* New free space entry *before* new partition. */
370		cur = create_entry(map, old_address, "", kFreeType, old_base,
371		    new_length);
372		if (cur == NULL)
373			errx(1, "No memory for new entry");
374	}
375
376	renumber_disk_addresses(map);
377	map->changed = 1;
378	return 1;
379}
380
381
382struct entry*
383create_entry(struct partition_map *map, long ix, const char *name,
384    const char *dptype, uint32_t base, uint32_t length)
385{
386	struct entry *entry;
387
388	entry = calloc(1, sizeof(struct entry));
389	if (entry == NULL)
390		errx(1, "No memory for new entry");
391
392	entry->dpme_signature = DPME_SIGNATURE;
393	entry->dpme_map_entries = 1;
394	entry->dpme_pblock_start = base;
395	entry->dpme_pblocks = length;
396	strlcpy(entry->dpme_name, name, sizeof(entry->dpme_name));
397	strlcpy(entry->dpme_type, dptype, sizeof(entry->dpme_type));
398	if (strncasecmp(dptype, kFreeType, DPISTRLEN)) {
399		/* Only non-kFreeType entries get lblock info != 0. */
400		entry->dpme_lblocks = entry->dpme_pblocks;
401	}
402	dpme_init_flags(entry);
403
404	entry->disk_address = ix;
405	entry->the_map = map;
406
407	insert_in_disk_order(entry);
408	insert_in_base_order(entry);
409
410	map->blocks_in_map++;
411	if (map->maximum_in_map < 0) {
412		if (strncasecmp(entry->dpme_type, kMapType, DPISTRLEN) == 0)
413			map->maximum_in_map = entry->dpme_pblocks;
414	}
415
416	return entry;
417}
418
419void
420dpme_init_flags(struct entry *entry)
421{
422	if (strncasecmp(entry->dpme_type, kFreeType, DPISTRLEN) == 0)
423		entry->dpme_flags = 0;
424	else if (strncasecmp(entry->dpme_type, kMapType, DPISTRLEN) == 0)
425		entry->dpme_flags = DPME_VALID | DPME_ALLOCATED;
426	else if (strncasecmp(entry->dpme_type, kHFSType, DPISTRLEN) == 0)
427		entry->dpme_flags = APPLE_HFS_FLAGS_VALUE;
428	else
429		entry->dpme_flags = DPME_VALID | DPME_ALLOCATED |
430		    DPME_READABLE | DPME_WRITABLE;
431}
432
433void
434renumber_disk_addresses(struct partition_map *map)
435{
436	struct entry *cur;
437	long ix;
438
439	/* reset disk addresses */
440	ix = 1;
441	LIST_FOREACH(cur, &map->disk_order, disk_entry) {
442		cur->disk_address = ix++;
443		cur->dpme_map_entries = map->blocks_in_map;
444	}
445}
446
447void
448delete_partition_from_map(struct entry *entry)
449{
450	struct partition_map *map;
451	uint32_t base, length, address;
452
453	if (strncasecmp(entry->dpme_type, kMapType, DPISTRLEN) == 0) {
454		printf("Can't delete entry for the map itself\n");
455		return;
456	}
457	if (strncasecmp(entry->dpme_type, kFreeType, DPISTRLEN) == 0) {
458		printf("Can't delete entry for free space\n");
459		return;
460	}
461	if (contains_driver(entry)) {
462		printf("This program can't install drivers\n");
463		if (get_okay("are you sure you want to delete this driver? "
464		    "[n/y]: ", 0) != 1) {
465			return;
466		}
467		remove_driver(entry);	/* update block0 if necessary */
468	}
469
470	map = entry->the_map;
471	base = entry->dpme_pblock_start;
472	length = entry->dpme_pblocks;
473	address = entry->disk_address;
474
475	delete_entry(entry);
476	entry = create_entry(map, address, "" , kFreeType, base, length);
477	combine_entry(entry);
478	renumber_disk_addresses(entry->the_map);
479	entry->the_map->changed = 1;
480}
481
482
483int
484contains_driver(struct entry *entry)
485{
486	struct partition_map *map;
487	struct ddmap *m;
488	int i;
489	uint32_t start;
490
491	map = entry->the_map;
492	m = map->sbDDMap;
493	for (i = 0; i < map->sbDrvrCount; i++) {
494		start = m[i].ddBlock;
495		if (entry->dpme_pblock_start <= start &&
496		    (start + m[i].ddSize) <= (entry->dpme_pblock_start +
497		    entry->dpme_pblocks))
498			return 1;
499	}
500
501	return 0;
502}
503
504
505void
506combine_entry(struct entry *entry)
507{
508	struct entry *p;
509	uint32_t end;
510
511	if (entry == NULL ||
512	    strncasecmp(entry->dpme_type, kFreeType, DPISTRLEN) != 0)
513		return;
514
515	p = LIST_NEXT(entry, base_entry);
516	if (p != NULL) {
517		if (strncasecmp(p->dpme_type, kFreeType, DPISTRLEN) !=
518		    0) {
519			/* next is not free */
520		} else if (entry->dpme_pblock_start +
521		    entry->dpme_pblocks != p->dpme_pblock_start) {
522			/* next is not contiguous (XXX this is bad) */
523			printf("next entry is not contiguous\n");
524			/* start is already minimum */
525			/* new end is maximum of two ends */
526			end = p->dpme_pblock_start + p->dpme_pblocks;
527			if (end > entry->dpme_pblock_start +
528			    entry->dpme_pblocks) {
529				entry->dpme_pblocks = end -
530				    entry->dpme_pblock_start;
531			}
532			delete_entry(p);
533		} else {
534			entry->dpme_pblocks += p->dpme_pblocks;
535			delete_entry(p);
536		}
537	}
538
539	LIST_FOREACH(p, &entry->the_map->base_order, base_entry) {
540		if (LIST_NEXT(p, base_entry) == entry)
541			break;
542	}
543	if (p != NULL) {
544		if (strncasecmp(p->dpme_type, kFreeType, DPISTRLEN) != 0) {
545			/* previous is not free */
546		} else if (p->dpme_pblock_start + p->dpme_pblocks !=
547		    entry->dpme_pblock_start) {
548			/* previous is not contiguous (XXX this is bad) */
549			printf("previous entry is not contiguous\n");
550			/* new end is maximum of two ends */
551			end = p->dpme_pblock_start + p->dpme_pblocks;
552			if (end < entry->dpme_pblock_start +
553			    entry->dpme_pblocks) {
554				end = entry->dpme_pblock_start +
555				    entry->dpme_pblocks;
556			}
557			entry->dpme_pblocks = end - p->dpme_pblock_start;
558			entry->dpme_pblock_start = p->dpme_pblock_start;
559			delete_entry(p);
560		} else {
561			entry->dpme_pblock_start = p->dpme_pblock_start;
562			entry->dpme_pblocks += p->dpme_pblocks;
563			delete_entry(p);
564		}
565	}
566}
567
568
569void
570delete_entry(struct entry *entry)
571{
572	struct partition_map *map;
573
574	map = entry->the_map;
575	map->blocks_in_map--;
576
577	LIST_REMOVE(entry, disk_entry);
578	LIST_REMOVE(entry, base_entry);
579
580	free(entry);
581}
582
583
584struct entry *
585find_entry_by_disk_address(long ix, struct partition_map *map)
586{
587	struct entry *cur;
588
589	LIST_FOREACH(cur, &map->disk_order, disk_entry) {
590		if (cur->disk_address == ix)
591			break;
592	}
593	return cur;
594}
595
596
597struct entry *
598find_entry_by_type(const char *type_name, struct partition_map *map)
599{
600	struct entry *cur;
601
602	LIST_FOREACH(cur, &map->base_order, base_entry) {
603		if (strncasecmp(cur->dpme_type, type_name, DPISTRLEN) == 0)
604			break;
605	}
606	return cur;
607}
608
609struct entry *
610find_entry_by_base(uint32_t base, struct partition_map *map)
611{
612	struct entry *cur;
613
614	LIST_FOREACH(cur, &map->base_order, base_entry) {
615		if (cur->dpme_pblock_start == base)
616			break;
617	}
618	return cur;
619}
620
621
622void
623move_entry_in_map(long index1, long index2, struct partition_map *map)
624{
625	struct entry *p1, *p2;
626
627	if (index1 == index2)
628		return;
629
630	if (index1 == 1 || index2 == 1) {
631		printf("Partition #1 cannot be moved\n");
632		return;
633	}
634	p1 = find_entry_by_disk_address(index1, map);
635	if (p1 == NULL) {
636		printf("Partition #%ld not found\n", index1);
637		return;
638	}
639	p2 = find_entry_by_disk_address(index2, map);
640	if (p2 == NULL) {
641		printf("Partition #%ld not found\n", index2);
642		return;
643	}
644
645	LIST_REMOVE(p1, disk_entry);
646	LIST_REMOVE(p2, disk_entry);
647
648	p1->disk_address = index2;
649	p2->disk_address = index1;
650
651	insert_in_disk_order(p1);
652	insert_in_disk_order(p2);
653
654	renumber_disk_addresses(map);
655	map->changed = 1;
656}
657
658
659void
660insert_in_disk_order(struct entry *entry)
661{
662	struct partition_map *map;
663	struct entry *cur;
664
665	/* find position in disk list & insert */
666	map = entry->the_map;
667	if (LIST_EMPTY(&map->disk_order)) {
668		LIST_INSERT_HEAD(&map->disk_order, entry, disk_entry);
669		return;
670	}
671
672	LIST_FOREACH(cur, &map->disk_order, disk_entry) {
673		if (cur->disk_address >= entry->disk_address) {
674			LIST_INSERT_BEFORE(cur, entry, disk_entry);
675			return;
676		}
677		if (LIST_NEXT(cur, disk_entry) == NULL) {
678			LIST_INSERT_AFTER(cur, entry, disk_entry);
679			return;
680		}
681	}
682}
683
684
685void
686insert_in_base_order(struct entry *entry)
687{
688	struct partition_map *map;
689	struct entry *cur;
690	uint32_t start;
691
692	/* find position in base list & insert */
693	map = entry->the_map;
694	if (LIST_EMPTY(&map->base_order)) {
695		LIST_INSERT_HEAD(&map->base_order, entry, base_entry);
696		return;
697	}
698
699	start = entry->dpme_pblock_start;
700	LIST_FOREACH(cur, &map->base_order, base_entry) {
701		if (start <= cur->dpme_pblock_start) {
702			LIST_INSERT_BEFORE(cur, entry, base_entry);
703			return;
704		}
705		if (LIST_NEXT(cur, base_entry) == NULL) {
706			LIST_INSERT_AFTER(cur, entry, base_entry);
707			return;
708		}
709	}
710}
711
712
713void
714resize_map(long new_size, struct partition_map *map)
715{
716	struct entry *entry;
717	struct entry *next;
718	int incr;
719
720	entry = find_entry_by_type(kMapType, map);
721
722	if (entry == NULL) {
723		printf("Couldn't find entry for map!\n");
724		return;
725	}
726	if (new_size == entry->dpme_pblocks)
727		return;
728
729	next = LIST_NEXT(entry, base_entry);
730
731	if (new_size < entry->dpme_pblocks) {
732		/* make it smaller */
733		if (next == NULL ||
734		    strncasecmp(next->dpme_type, kFreeType, DPISTRLEN) != 0)
735			incr = 1;
736		else
737			incr = 0;
738		if (new_size < map->blocks_in_map + incr) {
739			printf("New size would be too small\n");
740			return;
741		}
742		goto doit;
743	}
744	/* make it larger */
745	if (next == NULL ||
746	    strncasecmp(next->dpme_type, kFreeType, DPISTRLEN) != 0) {
747		printf("No free space to expand into\n");
748		return;
749	}
750	if (entry->dpme_pblock_start + entry->dpme_pblocks
751	    != next->dpme_pblock_start) {
752		printf("No contiguous free space to expand into\n");
753		return;
754	}
755	if (new_size > entry->dpme_pblocks + next->dpme_pblocks) {
756		printf("No enough free space\n");
757		return;
758	}
759doit:
760	entry->dpme_type[0] = 0;
761	delete_partition_from_map(entry);
762	add_partition_to_map("Apple", kMapType, 1, new_size, map);
763	map->maximum_in_map = new_size;
764}
765
766
767void
768remove_driver(struct entry *entry)
769{
770	struct partition_map *map;
771	struct ddmap *m;
772	int i, j;
773	uint32_t start;
774
775	/*
776	 * compute the factor to convert the block numbers in block0
777	 * into partition map block numbers.
778	 */
779	map = entry->the_map;
780	m = map->sbDDMap;
781	for (i = 0; i < map->sbDrvrCount; i++) {
782		start = m[i].ddBlock;
783		/*
784		 * zap the driver if it is wholly contained in the
785		 * partition
786		 */
787		if (entry->dpme_pblock_start <= start && (start +
788		    m[i].ddSize) <= (entry->dpme_pblock_start +
789		    entry->dpme_pblocks)) {
790			/*
791			 * Delete this driver by copying down later ones and
792			 * zapping the last one.
793			 */
794			for (j = i + 1; j < map->sbDrvrCount; j++, i++) {
795				m[i].ddBlock = m[i].ddBlock;
796				m[i].ddSize = m[j].ddSize;
797				m[i].ddType = m[j].ddType;
798			}
799			m[i].ddBlock = 0;
800			m[i].ddSize = 0;
801			m[i].ddType = 0;
802			map->sbDrvrCount -= 1;
803			return;	/* XXX if we continue we will delete
804				 * other drivers? */
805		}
806	}
807}
808