3ce67e6c14
When deleting the final partition, truncate it to match media size. Also handle creating new partitions beyond the existing partitions if it is still within the media size.
1435 lines
35 KiB
C
1435 lines
35 KiB
C
//
|
|
// partition_map.c - partition map routines
|
|
//
|
|
// Written by Eryk Vershen
|
|
//
|
|
|
|
/*
|
|
* Copyright 1996,1997,1998 by Apple Computer, Inc.
|
|
* All Rights Reserved
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and
|
|
* its documentation for any purpose and without fee is hereby granted,
|
|
* provided that the above copyright notice appears in all copies and
|
|
* that both the copyright notice and this permission notice appear in
|
|
* supporting documentation.
|
|
*
|
|
* APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
|
|
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
// for *printf()
|
|
#include <stdio.h>
|
|
|
|
// for malloc(), calloc() & free()
|
|
#ifndef __linux__
|
|
#include <stdlib.h>
|
|
#else
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
// for strncpy() & strcmp()
|
|
#include <string.h>
|
|
// for O_RDONLY & O_RDWR
|
|
#include <fcntl.h>
|
|
// for errno
|
|
#include <errno.h>
|
|
|
|
#include "partition_map.h"
|
|
#include "pathname.h"
|
|
#include "hfs_misc.h"
|
|
#include "deblock_media.h"
|
|
#include "io.h"
|
|
#include "convert.h"
|
|
#include "util.h"
|
|
#include "errors.h"
|
|
|
|
|
|
//
|
|
// Defines
|
|
//
|
|
#define APPLE_HFS_FLAGS_VALUE 0x4000037f
|
|
#define get_align_long(x) (*(x))
|
|
#define put_align_long(y, x) ((*(x)) = (y))
|
|
// #define TEST_COMPUTE
|
|
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
|
|
//
|
|
// Global Constants
|
|
//
|
|
const char * kFreeType = "Apple_Free";
|
|
const char * kMapType = "Apple_partition_map";
|
|
const char * kUnixType = "Apple_UNIX_SVR2";
|
|
const char * kHFSType = "Apple_HFS";
|
|
const char * kPatchType = "Apple_Patches";
|
|
|
|
const char * kFreeName = "Extra";
|
|
|
|
enum add_action {
|
|
kReplace = 0,
|
|
kAdd = 1,
|
|
kSplit = 2
|
|
};
|
|
|
|
//
|
|
// Global Variables
|
|
//
|
|
extern int cflag;
|
|
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
int add_data_to_map(struct dpme *data, long index, partition_map_header *map);
|
|
int coerce_block0(partition_map_header *map);
|
|
int contains_driver(partition_map *entry);
|
|
void combine_entry(partition_map *entry);
|
|
long compute_device_size(partition_map_header *map, partition_map_header *oldmap);
|
|
DPME* create_data(const char *name, const char *dptype, u32 base, u32 length);
|
|
void delete_entry(partition_map *entry);
|
|
char *get_HFS_name(partition_map *entry, int *kind);
|
|
void insert_in_base_order(partition_map *entry);
|
|
void insert_in_disk_order(partition_map *entry);
|
|
int read_block(partition_map_header *map, unsigned long num, char *buf);
|
|
int read_partition_map(partition_map_header *map);
|
|
void remove_driver(partition_map *entry);
|
|
void remove_from_disk_order(partition_map *entry);
|
|
void renumber_disk_addresses(partition_map_header *map);
|
|
void sync_device_size(partition_map_header *map);
|
|
int write_block(partition_map_header *map, unsigned long num, char *buf);
|
|
|
|
|
|
//
|
|
// Routines
|
|
//
|
|
partition_map_header *
|
|
open_partition_map(char *name, int *valid_file, int ask_logical_size)
|
|
{
|
|
MEDIA m;
|
|
partition_map_header * map;
|
|
int writable;
|
|
int size;
|
|
|
|
m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
|
|
if (m == 0) {
|
|
m = open_pathname_as_media(name, O_RDONLY);
|
|
if (m == 0) {
|
|
error(errno, "can't open file '%s'", name);
|
|
*valid_file = 0;
|
|
return NULL;
|
|
} else {
|
|
writable = 0;
|
|
}
|
|
} else {
|
|
writable = 1;
|
|
}
|
|
*valid_file = 1;
|
|
|
|
map = (partition_map_header *) malloc(sizeof(partition_map_header));
|
|
if (map == NULL) {
|
|
error(errno, "can't allocate memory for open partition map");
|
|
close_media(m);
|
|
return NULL;
|
|
}
|
|
map->name = name;
|
|
map->writable = (rflag)?0:writable;
|
|
map->changed = 0;
|
|
map->written = 0;
|
|
map->disk_order = NULL;
|
|
map->base_order = NULL;
|
|
|
|
map->physical_block = media_granularity(m); /* preflight */
|
|
m = open_deblock_media(PBLOCK_SIZE, m);
|
|
map->m = m;
|
|
map->misc = (Block0 *) malloc(PBLOCK_SIZE);
|
|
if (map->misc == NULL) {
|
|
error(errno, "can't allocate memory for block zero buffer");
|
|
close_media(map->m);
|
|
free(map);
|
|
return NULL;
|
|
} else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0
|
|
|| convert_block0(map->misc, 1)
|
|
|| coerce_block0(map)) {
|
|
// if I can't read block 0 I might as well give up
|
|
error(-1, "Can't read block 0 from '%s'", name);
|
|
close_partition_map(map);
|
|
return NULL;
|
|
}
|
|
map->physical_block = map->misc->sbBlkSize;
|
|
//printf("physical block size is %d\n", map->physical_block);
|
|
|
|
if (ask_logical_size && interactive) {
|
|
size = PBLOCK_SIZE;
|
|
printf("A logical block is %d bytes: ", size);
|
|
flush_to_newline(0);
|
|
get_number_argument("what should be the logical block size? ",
|
|
(long *)&size, size);
|
|
size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
|
|
if (size < PBLOCK_SIZE) {
|
|
size = PBLOCK_SIZE;
|
|
}
|
|
map->logical_block = size;
|
|
} else {
|
|
map->logical_block = PBLOCK_SIZE;
|
|
}
|
|
if (map->logical_block > MAXIOSIZE) {
|
|
map->logical_block = MAXIOSIZE;
|
|
}
|
|
if (map->logical_block > map->physical_block) {
|
|
map->physical_block = map->logical_block;
|
|
}
|
|
map->blocks_in_map = 0;
|
|
map->maximum_in_map = -1;
|
|
map->media_size = compute_device_size(map, map);
|
|
sync_device_size(map);
|
|
|
|
if (read_partition_map(map) < 0) {
|
|
// some sort of failure reading the map
|
|
} else {
|
|
// got it!
|
|
;
|
|
return map;
|
|
}
|
|
close_partition_map(map);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void
|
|
close_partition_map(partition_map_header *map)
|
|
{
|
|
partition_map * entry;
|
|
partition_map * next;
|
|
|
|
if (map == NULL) {
|
|
return;
|
|
}
|
|
|
|
free(map->misc);
|
|
|
|
for (entry = map->disk_order; entry != NULL; entry = next) {
|
|
next = entry->next_on_disk;
|
|
free(entry->data);
|
|
free(entry->HFS_name);
|
|
free(entry);
|
|
}
|
|
close_media(map->m);
|
|
free(map);
|
|
}
|
|
|
|
|
|
int
|
|
read_partition_map(partition_map_header *map)
|
|
{
|
|
DPME *data;
|
|
u32 limit;
|
|
int index;
|
|
int old_logical;
|
|
double d;
|
|
|
|
//printf("called read_partition_map\n");
|
|
//printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
|
|
data = (DPME *) malloc(PBLOCK_SIZE);
|
|
if (data == NULL) {
|
|
error(errno, "can't allocate memory for disk buffers");
|
|
return -1;
|
|
}
|
|
|
|
if (read_block(map, 1, (char *)data) == 0) {
|
|
error(-1, "Can't read block 1 from '%s'", map->name);
|
|
free(data);
|
|
return -1;
|
|
} else if (convert_dpme(data, 1)
|
|
|| data->dpme_signature != DPME_SIGNATURE) {
|
|
old_logical = map->logical_block;
|
|
map->logical_block = 512;
|
|
while (map->logical_block <= map->physical_block) {
|
|
if (read_block(map, 1, (char *)data) == 0) {
|
|
error(-1, "Can't read block 1 from '%s'", map->name);
|
|
free(data);
|
|
return -1;
|
|
} else if (convert_dpme(data, 1) == 0
|
|
&& data->dpme_signature == DPME_SIGNATURE) {
|
|
d = map->media_size;
|
|
map->media_size = (d * old_logical) / map->logical_block;
|
|
break;
|
|
}
|
|
map->logical_block *= 2;
|
|
}
|
|
if (map->logical_block > map->physical_block) {
|
|
error(-1, "No valid block 1 on '%s'", map->name);
|
|
free(data);
|
|
return -1;
|
|
}
|
|
}
|
|
//printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
|
|
|
|
limit = data->dpme_map_entries;
|
|
index = 1;
|
|
while (1) {
|
|
if (add_data_to_map(data, index, map) == 0) {
|
|
free(data);
|
|
return -1;
|
|
}
|
|
|
|
if (index >= limit) {
|
|
break;
|
|
} else {
|
|
index++;
|
|
}
|
|
|
|
data = (DPME *) malloc(PBLOCK_SIZE);
|
|
if (data == NULL) {
|
|
error(errno, "can't allocate memory for disk buffers");
|
|
return -1;
|
|
}
|
|
|
|
if (read_block(map, index, (char *)data) == 0) {
|
|
error(-1, "Can't read block %u from '%s'", index, map->name);
|
|
free(data);
|
|
return -1;
|
|
} else if (convert_dpme(data, 1)
|
|
|| (data->dpme_signature != DPME_SIGNATURE && dflag == 0)
|
|
|| (data->dpme_map_entries != limit && dflag == 0)) {
|
|
error(-1, "Bad data in block %u from '%s'", index, map->name);
|
|
free(data);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
write_partition_map(partition_map_header *map)
|
|
{
|
|
MEDIA m;
|
|
char *block;
|
|
partition_map * entry;
|
|
int i = 0;
|
|
int result = 0;
|
|
|
|
m = map->m;
|
|
if (map->misc != NULL) {
|
|
convert_block0(map->misc, 0);
|
|
result = write_block(map, 0, (char *)map->misc);
|
|
convert_block0(map->misc, 1);
|
|
} else {
|
|
block = (char *) calloc(1, PBLOCK_SIZE);
|
|
if (block != NULL) {
|
|
result = write_block(map, 0, block);
|
|
free(block);
|
|
}
|
|
}
|
|
if (result == 0) {
|
|
error(errno, "Unable to write block zero");
|
|
}
|
|
for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
|
|
convert_dpme(entry->data, 0);
|
|
result = write_block(map, entry->disk_address, (char *)entry->data);
|
|
convert_dpme(entry->data, 1);
|
|
i = entry->disk_address;
|
|
if (result == 0) {
|
|
error(errno, "Unable to write block %d", i);
|
|
}
|
|
}
|
|
|
|
#ifdef __linux__
|
|
// zap the block after the map (if possible) to get around a bug.
|
|
if (map->maximum_in_map > 0 && i < map->maximum_in_map) {
|
|
i += 1;
|
|
block = (char *) malloc(PBLOCK_SIZE);
|
|
if (block != NULL) {
|
|
if (read_block(map, i, block)) {
|
|
block[0] = 0;
|
|
write_block(map, i, block);
|
|
}
|
|
free(block);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (interactive)
|
|
printf("The partition table has been altered!\n\n");
|
|
|
|
os_reload_media(map->m);
|
|
}
|
|
|
|
|
|
int
|
|
add_data_to_map(struct dpme *data, long index, partition_map_header *map)
|
|
{
|
|
partition_map *entry;
|
|
|
|
//printf("add data %d to map\n", index);
|
|
entry = (partition_map *) malloc(sizeof(partition_map));
|
|
if (entry == NULL) {
|
|
error(errno, "can't allocate memory for map entries");
|
|
return 0;
|
|
}
|
|
entry->next_on_disk = NULL;
|
|
entry->prev_on_disk = NULL;
|
|
entry->next_by_base = NULL;
|
|
entry->prev_by_base = NULL;
|
|
entry->disk_address = index;
|
|
entry->the_map = map;
|
|
entry->data = data;
|
|
entry->contains_driver = contains_driver(entry);
|
|
entry->HFS_name = get_HFS_name(entry, &entry->HFS_kind);
|
|
|
|
insert_in_disk_order(entry);
|
|
insert_in_base_order(entry);
|
|
|
|
map->blocks_in_map++;
|
|
if (map->maximum_in_map < 0) {
|
|
if (istrncmp(data->dpme_type, kMapType, DPISTRLEN) == 0) {
|
|
map->maximum_in_map = data->dpme_pblocks;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
partition_map_header *
|
|
init_partition_map(char *name, partition_map_header* oldmap)
|
|
{
|
|
partition_map_header *map;
|
|
|
|
if (oldmap != NULL) {
|
|
printf("map already exists\n");
|
|
if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) {
|
|
return oldmap;
|
|
}
|
|
}
|
|
|
|
map = create_partition_map(name, oldmap);
|
|
if (map == NULL) {
|
|
return oldmap;
|
|
}
|
|
close_partition_map(oldmap);
|
|
|
|
add_partition_to_map("Apple", kMapType,
|
|
1, (map->media_size <= 128? 2: 63), map);
|
|
return map;
|
|
}
|
|
|
|
|
|
partition_map_header *
|
|
create_partition_map(char *name, partition_map_header *oldmap)
|
|
{
|
|
MEDIA m;
|
|
partition_map_header * map;
|
|
DPME *data;
|
|
unsigned long default_number;
|
|
unsigned long number;
|
|
int size;
|
|
unsigned long multiple;
|
|
|
|
m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
|
|
if (m == 0) {
|
|
error(errno, "can't open file '%s' for %sing", name,
|
|
(rflag)?"read":"writ");
|
|
return NULL;
|
|
}
|
|
|
|
map = (partition_map_header *) malloc(sizeof(partition_map_header));
|
|
if (map == NULL) {
|
|
error(errno, "can't allocate memory for open partition map");
|
|
close_media(m);
|
|
return NULL;
|
|
}
|
|
map->name = name;
|
|
map->writable = (rflag)?0:1;
|
|
map->changed = 1;
|
|
map->disk_order = NULL;
|
|
map->base_order = NULL;
|
|
|
|
if (oldmap != NULL) {
|
|
size = oldmap->physical_block;
|
|
} else {
|
|
size = media_granularity(m);
|
|
}
|
|
m = open_deblock_media(PBLOCK_SIZE, m);
|
|
map->m = m;
|
|
if (interactive) {
|
|
printf("A physical block is %d bytes: ", size);
|
|
flush_to_newline(0);
|
|
get_number_argument("what should be the physical block size? ",
|
|
(long *)&size, size);
|
|
size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
|
|
if (size < PBLOCK_SIZE) {
|
|
size = PBLOCK_SIZE;
|
|
}
|
|
}
|
|
if (map->physical_block > MAXIOSIZE) {
|
|
map->physical_block = MAXIOSIZE;
|
|
}
|
|
map->physical_block = size;
|
|
// printf("block size is %d\n", map->physical_block);
|
|
|
|
if (oldmap != NULL) {
|
|
size = oldmap->logical_block;
|
|
} else {
|
|
size = PBLOCK_SIZE;
|
|
}
|
|
if (interactive) {
|
|
printf("A logical block is %d bytes: ", size);
|
|
flush_to_newline(0);
|
|
get_number_argument("what should be the logical block size? ",
|
|
(long *)&size, size);
|
|
size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
|
|
if (size < PBLOCK_SIZE) {
|
|
size = PBLOCK_SIZE;
|
|
}
|
|
}
|
|
#if 0
|
|
if (size > map->physical_block) {
|
|
size = map->physical_block;
|
|
}
|
|
#endif
|
|
map->logical_block = size;
|
|
|
|
map->blocks_in_map = 0;
|
|
map->maximum_in_map = -1;
|
|
|
|
number = compute_device_size(map, oldmap);
|
|
if (interactive) {
|
|
printf("size of 'device' is %lu blocks (%d byte blocks): ",
|
|
number, map->logical_block);
|
|
default_number = number;
|
|
flush_to_newline(0);
|
|
do {
|
|
if (get_number_argument("what should be the size? ",
|
|
(long *)&number, default_number) == 0) {
|
|
printf("Not a number\n");
|
|
flush_to_newline(1);
|
|
number = 0;
|
|
} else {
|
|
multiple = get_multiplier(map->logical_block);
|
|
if (multiple == 0) {
|
|
printf("Bad multiplier\n");
|
|
number = 0;
|
|
} else if (multiple != 1) {
|
|
if (0xFFFFFFFF/multiple < number) {
|
|
printf("Number too large\n");
|
|
number = 0;
|
|
} else {
|
|
number *= multiple;
|
|
}
|
|
}
|
|
}
|
|
default_number = kDefault;
|
|
} while (number == 0);
|
|
|
|
if (number < 4) {
|
|
number = 4;
|
|
}
|
|
printf("new size of 'device' is %lu blocks (%d byte blocks)\n",
|
|
number, map->logical_block);
|
|
}
|
|
map->media_size = number;
|
|
|
|
map->misc = (Block0 *) calloc(1, PBLOCK_SIZE);
|
|
if (map->misc == NULL) {
|
|
error(errno, "can't allocate memory for block zero buffer");
|
|
} else {
|
|
// got it!
|
|
coerce_block0(map);
|
|
sync_device_size(map);
|
|
|
|
data = (DPME *) calloc(1, PBLOCK_SIZE);
|
|
if (data == NULL) {
|
|
error(errno, "can't allocate memory for disk buffers");
|
|
} else {
|
|
// set data into entry
|
|
data->dpme_signature = DPME_SIGNATURE;
|
|
data->dpme_map_entries = 1;
|
|
data->dpme_pblock_start = 1;
|
|
data->dpme_pblocks = map->media_size - 1;
|
|
strncpy(data->dpme_name, kFreeName, DPISTRLEN);
|
|
strncpy(data->dpme_type, kFreeType, DPISTRLEN);
|
|
data->dpme_lblock_start = 0;
|
|
data->dpme_lblocks = data->dpme_pblocks;
|
|
dpme_writable_set(data, 1);
|
|
dpme_readable_set(data, 1);
|
|
dpme_bootable_set(data, 0);
|
|
dpme_in_use_set(data, 0);
|
|
dpme_allocated_set(data, 0);
|
|
dpme_valid_set(data, 1);
|
|
|
|
if (add_data_to_map(data, 1, map) == 0) {
|
|
free(data);
|
|
} else {
|
|
return map;
|
|
}
|
|
}
|
|
}
|
|
close_partition_map(map);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int
|
|
coerce_block0(partition_map_header *map)
|
|
{
|
|
Block0 *p;
|
|
|
|
p = map->misc;
|
|
if (p == NULL) {
|
|
return 1;
|
|
}
|
|
if (p->sbSig != BLOCK0_SIGNATURE) {
|
|
p->sbSig = BLOCK0_SIGNATURE;
|
|
if (map->physical_block == 1) {
|
|
p->sbBlkSize = PBLOCK_SIZE;
|
|
} else {
|
|
p->sbBlkSize = map->physical_block;
|
|
}
|
|
p->sbBlkCount = 0;
|
|
p->sbDevType = 0;
|
|
p->sbDevId = 0;
|
|
p->sbData = 0;
|
|
p->sbDrvrCount = 0;
|
|
}
|
|
return 0; // we do this simply to make it easier to call this function
|
|
}
|
|
|
|
|
|
int
|
|
add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length,
|
|
partition_map_header *map)
|
|
{
|
|
partition_map * cur;
|
|
DPME *data;
|
|
enum add_action act;
|
|
int limit;
|
|
u32 adjusted_base = 0;
|
|
u32 adjusted_length = 0;
|
|
u32 new_base = 0;
|
|
u32 new_length = 0;
|
|
|
|
// find a block that starts includes base and length
|
|
cur = map->base_order;
|
|
while (cur != NULL) {
|
|
if (cur->data->dpme_pblock_start <= base
|
|
&& (base + length) <=
|
|
(cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) {
|
|
break;
|
|
} else {
|
|
// check if request is past end of existing partitions, but on disk
|
|
if ((cur->next_by_base == NULL) &&
|
|
(base + length <= map->media_size)) {
|
|
// Expand final free partition
|
|
if ((istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) == 0) &&
|
|
base >= cur->data->dpme_pblock_start) {
|
|
cur->data->dpme_pblocks =
|
|
map->media_size - cur->data->dpme_pblock_start;
|
|
break;
|
|
}
|
|
// create an extra free partition
|
|
if (base >= cur->data->dpme_pblock_start + cur->data->dpme_pblocks) {
|
|
if (map->maximum_in_map < 0) {
|
|
limit = map->media_size;
|
|
} else {
|
|
limit = map->maximum_in_map;
|
|
}
|
|
if (map->blocks_in_map + 1 > limit) {
|
|
printf("the map is not big enough\n");
|
|
return 0;
|
|
}
|
|
data = create_data(kFreeName, kFreeType,
|
|
cur->data->dpme_pblock_start + cur->data->dpme_pblocks,
|
|
map->media_size - (cur->data->dpme_pblock_start + cur->data->dpme_pblocks));
|
|
if (data != NULL) {
|
|
if (add_data_to_map(data, cur->disk_address, map) == 0) {
|
|
free(data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cur = cur->next_by_base;
|
|
}
|
|
}
|
|
// if it is not Extra then punt
|
|
if (cur == NULL
|
|
|| istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
|
|
printf("requested base and length is not "
|
|
"within an existing free partition\n");
|
|
return 0;
|
|
}
|
|
// figure out what to do and sizes
|
|
data = cur->data;
|
|
if (data->dpme_pblock_start == base) {
|
|
// replace or add
|
|
if (data->dpme_pblocks == length) {
|
|
act = kReplace;
|
|
} else {
|
|
act = kAdd;
|
|
adjusted_base = base + length;
|
|
adjusted_length = data->dpme_pblocks - length;
|
|
}
|
|
} else {
|
|
// split or add
|
|
if (data->dpme_pblock_start + data->dpme_pblocks == base + length) {
|
|
act = kAdd;
|
|
adjusted_base = data->dpme_pblock_start;
|
|
adjusted_length = base - adjusted_base;
|
|
} else {
|
|
act = kSplit;
|
|
new_base = data->dpme_pblock_start;
|
|
new_length = base - new_base;
|
|
adjusted_base = base + length;
|
|
adjusted_length = data->dpme_pblocks - (length + new_length);
|
|
}
|
|
}
|
|
// if the map will overflow then punt
|
|
if (map->maximum_in_map < 0) {
|
|
limit = map->media_size;
|
|
} else {
|
|
limit = map->maximum_in_map;
|
|
}
|
|
if (map->blocks_in_map + act > limit) {
|
|
printf("the map is not big enough\n");
|
|
return 0;
|
|
}
|
|
|
|
data = create_data(name, dptype, base, length);
|
|
if (data == NULL) {
|
|
return 0;
|
|
}
|
|
if (act == kReplace) {
|
|
free(cur->data);
|
|
cur->data = data;
|
|
} else {
|
|
// adjust this block's size
|
|
cur->data->dpme_pblock_start = adjusted_base;
|
|
cur->data->dpme_pblocks = adjusted_length;
|
|
cur->data->dpme_lblocks = adjusted_length;
|
|
// insert new with block address equal to this one
|
|
if (add_data_to_map(data, cur->disk_address, map) == 0) {
|
|
free(data);
|
|
} else if (act == kSplit) {
|
|
data = create_data(kFreeName, kFreeType, new_base, new_length);
|
|
if (data != NULL) {
|
|
// insert new with block address equal to this one
|
|
if (add_data_to_map(data, cur->disk_address, map) == 0) {
|
|
free(data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// renumber disk addresses
|
|
renumber_disk_addresses(map);
|
|
// mark changed
|
|
map->changed = 1;
|
|
return 1;
|
|
}
|
|
|
|
|
|
DPME *
|
|
create_data(const char *name, const char *dptype, u32 base, u32 length)
|
|
{
|
|
DPME *data;
|
|
|
|
data = (DPME *) calloc(1, PBLOCK_SIZE);
|
|
if (data == NULL) {
|
|
error(errno, "can't allocate memory for disk buffers");
|
|
} else {
|
|
// set data into entry
|
|
data->dpme_signature = DPME_SIGNATURE;
|
|
data->dpme_map_entries = 1;
|
|
data->dpme_pblock_start = base;
|
|
data->dpme_pblocks = length;
|
|
strncpy(data->dpme_name, name, DPISTRLEN);
|
|
strncpy(data->dpme_type, dptype, DPISTRLEN);
|
|
data->dpme_lblock_start = 0;
|
|
data->dpme_lblocks = data->dpme_pblocks;
|
|
dpme_init_flags(data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void
|
|
dpme_init_flags(DPME *data)
|
|
{
|
|
if (istrncmp(data->dpme_type, kHFSType, DPISTRLEN) == 0) { /* XXX this is gross, fix it! */
|
|
data->dpme_flags = APPLE_HFS_FLAGS_VALUE;
|
|
}
|
|
else {
|
|
dpme_writable_set(data, 1);
|
|
dpme_readable_set(data, 1);
|
|
dpme_bootable_set(data, 0);
|
|
dpme_in_use_set(data, 0);
|
|
dpme_allocated_set(data, 1);
|
|
dpme_valid_set(data, 1);
|
|
}
|
|
}
|
|
|
|
/* These bits are appropriate for Apple_UNIX_SVR2 partitions
|
|
* used by NetBSD. They may be ok for A/UX, but have not been
|
|
* tested.
|
|
*/
|
|
void
|
|
bzb_init_slice(BZB *bp, int slice)
|
|
{
|
|
memset(bp,0,sizeof(BZB));
|
|
if ((slice >= 'A') && (slice <= 'Z')) {
|
|
slice += 'a' - 'A';
|
|
}
|
|
if ((slice != 0) && ((slice < 'a') || (slice > 'z'))) {
|
|
error(-1,"Bad bzb slice");
|
|
slice = 0;
|
|
}
|
|
switch (slice) {
|
|
case 0:
|
|
case 'c':
|
|
return;
|
|
case 'a':
|
|
bp->bzb_type = FST;
|
|
strlcpy(bp->bzb_mount_point, "/", sizeof(bp->bzb_mount_point));
|
|
bp->bzb_inode = 1;
|
|
bzb_root_set(bp,1);
|
|
bzb_usr_set(bp,1);
|
|
break;
|
|
case 'b':
|
|
bp->bzb_type = FSTSFS;
|
|
strlcpy(bp->bzb_mount_point, "(swap)", sizeof(bp->bzb_mount_point));
|
|
break;
|
|
case 'g':
|
|
strlcpy(bp->bzb_mount_point, "/usr", sizeof(bp->bzb_mount_point));
|
|
/* Fall through */
|
|
default:
|
|
bp->bzb_type = FST;
|
|
bp->bzb_inode = 1;
|
|
bzb_usr_set(bp,1);
|
|
break;
|
|
}
|
|
bzb_slice_set(bp,0); // XXX NetBSD disksubr.c ignores slice
|
|
// bzb_slice_set(bp,slice-'a'+1);
|
|
bp->bzb_magic = BZBMAGIC;
|
|
}
|
|
|
|
void
|
|
renumber_disk_addresses(partition_map_header *map)
|
|
{
|
|
partition_map * cur;
|
|
long index;
|
|
|
|
// reset disk addresses
|
|
cur = map->disk_order;
|
|
index = 1;
|
|
while (cur != NULL) {
|
|
cur->disk_address = index++;
|
|
cur->data->dpme_map_entries = map->blocks_in_map;
|
|
cur = cur->next_on_disk;
|
|
}
|
|
}
|
|
|
|
|
|
long
|
|
compute_device_size(partition_map_header *map, partition_map_header *oldmap)
|
|
{
|
|
#ifdef TEST_COMPUTE
|
|
unsigned long length;
|
|
struct hd_geometry geometry;
|
|
struct stat info;
|
|
loff_t pos;
|
|
#endif
|
|
char* data;
|
|
unsigned long l, r, x = 0;
|
|
long long size;
|
|
int valid = 0;
|
|
#ifdef TEST_COMPUTE
|
|
int fd;
|
|
|
|
fd = map->fd->fd;
|
|
printf("\n");
|
|
if (fstat(fd, &info) < 0) {
|
|
printf("stat of device failed\n");
|
|
} else {
|
|
printf("stat: mode = 0%o, type=%s\n", info.st_mode,
|
|
(S_ISREG(info.st_mode)? "Regular":
|
|
(S_ISBLK(info.st_mode)?"Block":"Other")));
|
|
printf("size = %d, blocks = %d\n",
|
|
info.st_size, info.st_size/map->logical_block);
|
|
}
|
|
|
|
if (ioctl(fd, BLKGETSIZE, &length) < 0) {
|
|
printf("get device size failed\n");
|
|
} else {
|
|
printf("BLKGETSIZE:size in blocks = %u\n", length);
|
|
}
|
|
|
|
if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) {
|
|
printf("get device geometry failed\n");
|
|
} else {
|
|
printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d, total=%d\n",
|
|
geometry.heads, geometry.sectors,
|
|
geometry.cylinders, geometry.start,
|
|
geometry.heads*geometry.sectors*geometry.cylinders);
|
|
}
|
|
|
|
if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) {
|
|
printf("llseek to end of device failed\n");
|
|
} else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) {
|
|
printf("llseek to end of device failed on second try\n");
|
|
} else {
|
|
printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block);
|
|
}
|
|
#endif
|
|
|
|
if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) {
|
|
return (oldmap->misc->sbBlkCount
|
|
* (oldmap->physical_block / map->logical_block));
|
|
}
|
|
|
|
size = media_total_size(map->m);
|
|
if (size != 0) {
|
|
return (long)(size / map->logical_block);
|
|
}
|
|
|
|
// else case
|
|
|
|
data = (char *) malloc(PBLOCK_SIZE);
|
|
if (data == NULL) {
|
|
error(errno, "can't allocate memory for try buffer");
|
|
x = 0;
|
|
} else {
|
|
// double till off end
|
|
l = 0;
|
|
r = 1024;
|
|
while (read_block(map, r, data) != 0) {
|
|
l = r;
|
|
if (r <= 1024) {
|
|
r = r * 1024;
|
|
} else {
|
|
r = r * 2;
|
|
}
|
|
if (r >= 0x80000000) {
|
|
r = 0xFFFFFFFE;
|
|
break;
|
|
}
|
|
}
|
|
// binary search for end
|
|
while (l <= r) {
|
|
x = (r - l) / 2 + l;
|
|
if ((valid = read_block(map, x, data)) != 0) {
|
|
l = x + 1;
|
|
} else {
|
|
if (x > 0) {
|
|
r = x - 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (valid != 0) {
|
|
x = x + 1;
|
|
}
|
|
// printf("size in blocks = %d\n", x);
|
|
free(data);
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
void
|
|
sync_device_size(partition_map_header *map)
|
|
{
|
|
Block0 *p;
|
|
unsigned long size;
|
|
double d;
|
|
|
|
p = map->misc;
|
|
if (p == NULL) {
|
|
return;
|
|
}
|
|
d = map->media_size;
|
|
size = (d * map->logical_block) / p->sbBlkSize;
|
|
if (p->sbBlkCount != size) {
|
|
p->sbBlkCount = size;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
delete_partition_from_map(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
DPME *data;
|
|
|
|
if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) {
|
|
printf("Can't delete entry for the map itself\n");
|
|
return;
|
|
}
|
|
if (entry->contains_driver) {
|
|
printf("This program can't install drivers\n");
|
|
if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) {
|
|
return;
|
|
}
|
|
}
|
|
// if past end of disk, delete it completely
|
|
if (entry->next_by_base == NULL &&
|
|
entry->data->dpme_pblock_start >= entry->the_map->media_size) {
|
|
if (entry->contains_driver) {
|
|
remove_driver(entry); // update block0 if necessary
|
|
}
|
|
delete_entry(entry);
|
|
return;
|
|
}
|
|
// If at end of disk, incorporate extra disk space to partition
|
|
if (entry->next_by_base == NULL) {
|
|
entry->data->dpme_pblocks =
|
|
entry->the_map->media_size - entry->data->dpme_pblock_start;
|
|
}
|
|
data = create_data(kFreeName, kFreeType,
|
|
entry->data->dpme_pblock_start, entry->data->dpme_pblocks);
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
if (entry->contains_driver) {
|
|
remove_driver(entry); // update block0 if necessary
|
|
}
|
|
free(entry->data);
|
|
free(entry->HFS_name);
|
|
entry->HFS_kind = kHFS_not;
|
|
entry->HFS_name = 0;
|
|
entry->data = data;
|
|
combine_entry(entry);
|
|
map = entry->the_map;
|
|
renumber_disk_addresses(map);
|
|
map->changed = 1;
|
|
}
|
|
|
|
|
|
int
|
|
contains_driver(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
Block0 *p;
|
|
DDMap *m;
|
|
int i;
|
|
int f;
|
|
u32 start;
|
|
|
|
map = entry->the_map;
|
|
p = map->misc;
|
|
if (p == NULL) {
|
|
return 0;
|
|
}
|
|
if (p->sbSig != BLOCK0_SIGNATURE) {
|
|
return 0;
|
|
}
|
|
if (map->logical_block > p->sbBlkSize) {
|
|
return 0;
|
|
} else {
|
|
f = p->sbBlkSize / map->logical_block;
|
|
}
|
|
if (p->sbDrvrCount > 0) {
|
|
m = (DDMap *) p->sbMap;
|
|
for (i = 0; i < p->sbDrvrCount; i++) {
|
|
start = get_align_long(&m[i].ddBlock);
|
|
if (entry->data->dpme_pblock_start <= f*start
|
|
&& f*(start + m[i].ddSize)
|
|
<= (entry->data->dpme_pblock_start
|
|
+ entry->data->dpme_pblocks)) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
combine_entry(partition_map *entry)
|
|
{
|
|
partition_map *p;
|
|
u32 end;
|
|
|
|
if (entry == NULL
|
|
|| istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
|
|
return;
|
|
}
|
|
if (entry->next_by_base != NULL) {
|
|
p = entry->next_by_base;
|
|
if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
|
|
// next is not free
|
|
} else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
|
|
!= p->data->dpme_pblock_start) {
|
|
// next is not contiguous (XXX this is bad)
|
|
printf("next entry is not contiguous\n");
|
|
// start is already minimum
|
|
// new end is maximum of two ends
|
|
end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
|
|
if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
|
|
entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start;
|
|
}
|
|
entry->data->dpme_lblocks = entry->data->dpme_pblocks;
|
|
delete_entry(p);
|
|
} else {
|
|
entry->data->dpme_pblocks += p->data->dpme_pblocks;
|
|
entry->data->dpme_lblocks = entry->data->dpme_pblocks;
|
|
delete_entry(p);
|
|
}
|
|
}
|
|
if (entry->prev_by_base != NULL) {
|
|
p = entry->prev_by_base;
|
|
if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
|
|
// previous is not free
|
|
} else if (p->data->dpme_pblock_start + p->data->dpme_pblocks
|
|
!= entry->data->dpme_pblock_start) {
|
|
// previous is not contiguous (XXX this is bad)
|
|
printf("previous entry is not contiguous\n");
|
|
// new end is maximum of two ends
|
|
end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
|
|
if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
|
|
end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks;
|
|
}
|
|
entry->data->dpme_pblocks = end - p->data->dpme_pblock_start;
|
|
// new start is previous entry's start
|
|
entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
|
|
entry->data->dpme_lblocks = entry->data->dpme_pblocks;
|
|
delete_entry(p);
|
|
} else {
|
|
entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
|
|
entry->data->dpme_pblocks += p->data->dpme_pblocks;
|
|
entry->data->dpme_lblocks = entry->data->dpme_pblocks;
|
|
delete_entry(p);
|
|
}
|
|
}
|
|
entry->contains_driver = contains_driver(entry);
|
|
}
|
|
|
|
|
|
void
|
|
delete_entry(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
partition_map *p;
|
|
|
|
map = entry->the_map;
|
|
map->blocks_in_map--;
|
|
|
|
remove_from_disk_order(entry);
|
|
|
|
p = entry->next_by_base;
|
|
if (map->base_order == entry) {
|
|
map->base_order = p;
|
|
}
|
|
if (p != NULL) {
|
|
p->prev_by_base = entry->prev_by_base;
|
|
}
|
|
if (entry->prev_by_base != NULL) {
|
|
entry->prev_by_base->next_by_base = p;
|
|
}
|
|
|
|
free(entry->data);
|
|
free(entry->HFS_name);
|
|
free(entry);
|
|
}
|
|
|
|
|
|
partition_map *
|
|
find_entry_by_disk_address(long index, partition_map_header *map)
|
|
{
|
|
partition_map * cur;
|
|
|
|
cur = map->disk_order;
|
|
while (cur != NULL) {
|
|
if (cur->disk_address == index) {
|
|
break;
|
|
}
|
|
cur = cur->next_on_disk;
|
|
}
|
|
return cur;
|
|
}
|
|
|
|
|
|
partition_map *
|
|
find_entry_by_type(const char *type_name, partition_map_header *map)
|
|
{
|
|
partition_map * cur;
|
|
|
|
cur = map->base_order;
|
|
while (cur != NULL) {
|
|
if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) {
|
|
break;
|
|
}
|
|
cur = cur->next_by_base;
|
|
}
|
|
return cur;
|
|
}
|
|
|
|
partition_map *
|
|
find_entry_by_base(u32 base, partition_map_header *map)
|
|
{
|
|
partition_map * cur;
|
|
|
|
cur = map->base_order;
|
|
while (cur != NULL) {
|
|
if (cur->data->dpme_pblock_start == base) {
|
|
break;
|
|
}
|
|
cur = cur->next_by_base;
|
|
}
|
|
return cur;
|
|
}
|
|
|
|
|
|
void
|
|
move_entry_in_map(long old_index, long index, partition_map_header *map)
|
|
{
|
|
partition_map * cur;
|
|
|
|
cur = find_entry_by_disk_address(old_index, map);
|
|
if (cur == NULL) {
|
|
printf("No such partition\n");
|
|
} else {
|
|
remove_from_disk_order(cur);
|
|
cur->disk_address = index;
|
|
insert_in_disk_order(cur);
|
|
renumber_disk_addresses(map);
|
|
map->changed = 1;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
remove_from_disk_order(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
partition_map *p;
|
|
|
|
map = entry->the_map;
|
|
p = entry->next_on_disk;
|
|
if (map->disk_order == entry) {
|
|
map->disk_order = p;
|
|
}
|
|
if (p != NULL) {
|
|
p->prev_on_disk = entry->prev_on_disk;
|
|
}
|
|
if (entry->prev_on_disk != NULL) {
|
|
entry->prev_on_disk->next_on_disk = p;
|
|
}
|
|
entry->next_on_disk = NULL;
|
|
entry->prev_on_disk = NULL;
|
|
}
|
|
|
|
|
|
void
|
|
insert_in_disk_order(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
partition_map * cur;
|
|
|
|
// find position in disk list & insert
|
|
map = entry->the_map;
|
|
cur = map->disk_order;
|
|
if (cur == NULL || entry->disk_address <= cur->disk_address) {
|
|
map->disk_order = entry;
|
|
entry->next_on_disk = cur;
|
|
if (cur != NULL) {
|
|
cur->prev_on_disk = entry;
|
|
}
|
|
entry->prev_on_disk = NULL;
|
|
} else {
|
|
for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) {
|
|
if (cur->disk_address <= entry->disk_address
|
|
&& (cur->next_on_disk == NULL
|
|
|| entry->disk_address <= cur->next_on_disk->disk_address)) {
|
|
entry->next_on_disk = cur->next_on_disk;
|
|
cur->next_on_disk = entry;
|
|
entry->prev_on_disk = cur;
|
|
if (entry->next_on_disk != NULL) {
|
|
entry->next_on_disk->prev_on_disk = entry;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
insert_in_base_order(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
partition_map * cur;
|
|
|
|
// find position in base list & insert
|
|
map = entry->the_map;
|
|
cur = map->base_order;
|
|
if (cur == NULL
|
|
|| entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) {
|
|
map->base_order = entry;
|
|
entry->next_by_base = cur;
|
|
if (cur != NULL) {
|
|
cur->prev_by_base = entry;
|
|
}
|
|
entry->prev_by_base = NULL;
|
|
} else {
|
|
for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) {
|
|
if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start
|
|
&& (cur->next_by_base == NULL
|
|
|| entry->data->dpme_pblock_start
|
|
<= cur->next_by_base->data->dpme_pblock_start)) {
|
|
entry->next_by_base = cur->next_by_base;
|
|
cur->next_by_base = entry;
|
|
entry->prev_by_base = cur;
|
|
if (entry->next_by_base != NULL) {
|
|
entry->next_by_base->prev_by_base = entry;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
resize_map(long new_size, partition_map_header *map)
|
|
{
|
|
partition_map * entry;
|
|
partition_map * next;
|
|
int incr;
|
|
|
|
// find map entry
|
|
entry = find_entry_by_type(kMapType, map);
|
|
|
|
if (entry == NULL) {
|
|
printf("Couldn't find entry for map!\n");
|
|
return;
|
|
}
|
|
next = entry->next_by_base;
|
|
|
|
// same size
|
|
if (new_size == entry->data->dpme_pblocks) {
|
|
// do nothing
|
|
return;
|
|
}
|
|
|
|
// make it smaller
|
|
if (new_size < entry->data->dpme_pblocks) {
|
|
if (next == NULL
|
|
|| istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
|
|
incr = 1;
|
|
} else {
|
|
incr = 0;
|
|
}
|
|
if (new_size < map->blocks_in_map + incr) {
|
|
printf("New size would be too small\n");
|
|
return;
|
|
}
|
|
goto doit;
|
|
}
|
|
|
|
// make it larger
|
|
if (next == NULL
|
|
|| istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
|
|
printf("No free space to expand into\n");
|
|
return;
|
|
}
|
|
if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
|
|
!= next->data->dpme_pblock_start) {
|
|
printf("No contiguous free space to expand into\n");
|
|
return;
|
|
}
|
|
if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) {
|
|
printf("No enough free space\n");
|
|
return;
|
|
}
|
|
doit:
|
|
entry->data->dpme_type[0] = 0;
|
|
delete_partition_from_map(entry);
|
|
add_partition_to_map("Apple", kMapType, 1, new_size, map);
|
|
map->maximum_in_map = new_size;
|
|
}
|
|
|
|
|
|
void
|
|
remove_driver(partition_map *entry)
|
|
{
|
|
partition_map_header *map;
|
|
Block0 *p;
|
|
DDMap *m;
|
|
int i;
|
|
int j;
|
|
int f;
|
|
u32 start;
|
|
|
|
map = entry->the_map;
|
|
p = map->misc;
|
|
if (p == NULL) {
|
|
return;
|
|
}
|
|
if (p->sbSig != BLOCK0_SIGNATURE) {
|
|
return;
|
|
}
|
|
if (map->logical_block > p->sbBlkSize) {
|
|
/* this is not supposed to happen, but let's just ignore it. */
|
|
return;
|
|
} else {
|
|
/*
|
|
* compute the factor to convert the block numbers in block0
|
|
* into partition map block numbers.
|
|
*/
|
|
f = p->sbBlkSize / map->logical_block;
|
|
}
|
|
if (p->sbDrvrCount > 0) {
|
|
m = (DDMap *) p->sbMap;
|
|
for (i = 0; i < p->sbDrvrCount; i++) {
|
|
start = get_align_long(&m[i].ddBlock);
|
|
|
|
/* zap the driver if it is wholly contained in the partition */
|
|
if (entry->data->dpme_pblock_start <= f*start
|
|
&& f*(start + m[i].ddSize)
|
|
<= (entry->data->dpme_pblock_start
|
|
+ entry->data->dpme_pblocks)) {
|
|
// delete this driver
|
|
// by copying down later ones and zapping the last
|
|
for (j = i+1; j < p->sbDrvrCount; j++, i++) {
|
|
put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock);
|
|
m[i].ddSize = m[j].ddSize;
|
|
m[i].ddType = m[j].ddType;
|
|
}
|
|
put_align_long(0, &m[i].ddBlock);
|
|
m[i].ddSize = 0;
|
|
m[i].ddType = 0;
|
|
p->sbDrvrCount -= 1;
|
|
return; /* XXX if we continue we will delete other drivers? */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
read_block(partition_map_header *map, unsigned long num, char *buf)
|
|
{
|
|
//printf("read block %d\n", num);
|
|
return read_media(map->m, ((long long) num) * map->logical_block,
|
|
PBLOCK_SIZE, (void *)buf);
|
|
}
|
|
|
|
|
|
int
|
|
write_block(partition_map_header *map, unsigned long num, char *buf)
|
|
{
|
|
return write_media(map->m, ((long long) num) * map->logical_block,
|
|
PBLOCK_SIZE, (void *)buf);
|
|
}
|