iBoot/lib/partition/partition.c

149 lines
3.5 KiB
C

/*
* Copyright (C) 2007, 2009-2011, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <compiler.h>
#include <lib/mib.h>
#include <lib/partition.h>
#include <lib/blockdev.h>
#include "partition_private.h"
static bool
partition_overlap_check(struct partition_entry *part, int num_entries)
{
int i, j;
bool overlap;
overlap = false;
for (i=0; i < num_entries; i++) {
off_t ioff = part[i].offset;
off_t iend = part[i].offset + part[i].len;
for (j=0; j < num_entries; j++) {
if (i == j)
continue;
off_t joff = part[j].offset;
off_t jend = part[j].offset + part[j].len;
/* is j's starting offset within i's range */
if ((joff >= ioff) && (joff < iend))
overlap = true;
/* is j's end within i's range */
if ((jend <= iend) && (jend > ioff))
overlap = true;
/* does j completely cover i */
if ((joff <= ioff) && (jend >= iend))
overlap = true;
}
}
if (overlap)
dprintf(DEBUG_INFO, "partition_scan: some partitions overlap, probably garbage partition data\n");
return overlap;
}
static bool
partition_extents_check(struct partition_entry *part, int num_entries, struct blockdev *dev)
{
int i;
bool toobig;
toobig = false;
for (i=0; i < num_entries; i++) {
if (part[i].offset + part[i].len > dev->total_len) {
dprintf(DEBUG_INFO, "partition %i overshoots size of device\n", i);
toobig = true;
}
}
return toobig;
}
static int
partition_scan(struct blockdev *dev, struct partition_entry *entry_list, size_t num_entries)
{
int scanned_entries;
int err;
struct mbr_partition *part;
int mbr_bytes;
scanned_entries = 0;
part = NULL;
mbr_bytes = MBR_PARTITIONS * sizeof(struct mbr_partition);
/* read what we expect to be an MBR from the beginning of the blockdev */
part = memalign(mbr_bytes, mib_get_size(kMIBPlatformCacheLineSize));
/* read *just* the partition table */
err = blockdev_read(dev, part, MBR_ADDRESS, mbr_bytes);
if (err != mbr_bytes) {
dprintf(DEBUG_INFO, "mbr: read error\n");
goto out;
}
/* scan it as an mbr */
scanned_entries = mbr_scan(part, dev, entry_list);
/* does it look like it might be GPT? */
if ((scanned_entries == 1) && (entry_list[0].id == 0xee))
scanned_entries = gpt_scan(dev, entry_list);
/* do an overlap check to make sure this is a sort of reasonable layout */
if (partition_overlap_check(entry_list, scanned_entries)) {
scanned_entries = 0;
goto out;
}
out:
if (NULL != part)
free(part);
return scanned_entries;
}
int partition_scan_and_publish_subdevices(const char *dev_name)
{
struct partition_entry entries[MAX_PARTITIONS];
int found;
int i;
struct blockdev *dev;
dev = lookup_blockdev(dev_name);
if (!dev)
return -1;
/* scan for LwVM partitions */
found = lwvm_scan(dev);
if (found > 0)
return found;
/* scan for regular partitions */
found = partition_scan(dev, entries, MAX_PARTITIONS);
for (i=0; i < found; i++) {
/* publish subdevices */
struct blockdev *subdev;
char subdev_name[32];
snprintf(subdev_name, 32, "%s%c", dev_name, 'a' + i);
// make sure it doesn't already exist
if (lookup_blockdev(subdev_name))
continue;
subdev = create_subdev_blockdev(subdev_name, dev, entries[i].offset, entries[i].len, dev->block_size);
if (subdev)
register_blockdev(subdev);
}
return found;
}