Files
haiku-beta6/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.cpp
T
Axel Dörfler b132797ec3 Made the module working in the boot loader.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4552 a95241bf-73f2-0310-859d-f6bbb57e9c96
2003-09-08 02:41:05 +00:00

483 lines
11 KiB
C++

//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file PartitionMap.cpp
\brief Definitions for "intel" style partitions and implementation
of related classes.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util/kernel_cpp.h>
#ifndef _BOOT_MODE
# include <DiskDeviceTypes.h>
#else
# include <boot/partitions.h>
#endif
#include <KernelExport.h>
#include "PartitionMap.h"
#define TRACE(x) ;
//#define TRACE(x) dprintf x
// partition_type
struct partition_type {
uint8 type;
const char *name;
};
static const struct partition_type kPartitionTypes[] = {
// these entries must be sorted by type (currently not)
// TODO: Standardize naming.
{ 0x00, "empty" },
{ 0x01, "FAT 12-bit" },
{ 0x02, "Xenix root" },
{ 0x03, "Xenix user" },
{ 0x04, "FAT 16-bit (dos 3.0)" },
{ 0x05, /*"Extended Partition"*/kPartitionTypeIntelExtended },
{ 0x06, "FAT 16-bit (dos 3.31)" },
{ 0x07, "OS/2 IFS, Windows NT, Advanced Unix" },
{ 0x0b, "FAT 32-bit" },
{ 0x0c, "FAT 32-bit, LBA-mapped" },
{ 0x0d, "FAT 16-bit, LBA-mapped" },
{ 0x0f, /*"Extended Partition, LBA-mapped"*/kPartitionTypeIntelExtended },
{ 0x42, "Windows 2000 marker (switches to a proprietary partition table)" },
{ 0x4d, "QNX 4" },
{ 0x4e, "QNX 4 2nd part" },
{ 0x4f, "QNX 4 3rd part" },
{ 0x78, "XOSL boot loader" },
{ 0x82, "Linux swapfile" },
{ 0x83, "Linux native" },
{ 0x85, /*"Linux extendend partition"*/kPartitionTypeIntelExtended },
{ 0xa5, "FreeBSD" },
{ 0xa6, "OpenBSD" },
{ 0xa7, "NextSTEP" },
{ 0xa8, "MacOS X" },
{ 0xa9, "NetBSD" },
{ 0xab, "MacOS X boot" },
{ 0xbe, "Solaris 8 boot" },
{ 0xeb, /*"BeOS"*/ kPartitionTypeBFS },
{ 0, NULL }
};
// partition_type_string
static
const char *
partition_type_string(uint8 type)
{
int32 i;
for (i = 0; kPartitionTypes[i].name ; i++)
{
if (type == kPartitionTypes[i].type)
return kPartitionTypes[i].name;
}
return NULL;
}
// get_partition_type_string
void
get_partition_type_string(uint8 type, char *buffer)
{
if (buffer) {
if (const char *str = partition_type_string(type))
strcpy(buffer, str);
else
sprintf(buffer, "Unrecognized Type 0x%x", type);
}
}
// Partition
// constructor
Partition::Partition()
: fPTSOffset(0),
fOffset(0),
fSize(0),
fType(0),
fActive(false)
{
}
// constructor
Partition::Partition(const partition_descriptor *descriptor,off_t ptsOffset,
off_t baseOffset, int32 blockSize)
: fPTSOffset(0),
fOffset(0),
fSize(0),
fType(0),
fActive(false)
{
SetTo(descriptor, ptsOffset, baseOffset, blockSize);
}
// SetTo
void
Partition::SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize)
{
TRACE(("Partition::SetTo(): active: %x\n", descriptor->active));
fPTSOffset = ptsOffset;
fOffset = baseOffset + (off_t)descriptor->start * blockSize;
fSize = (off_t)descriptor->size * blockSize;
fType = descriptor->type;
fActive = descriptor->active;
if (fSize == 0)
Unset();
}
// Unset
void
Partition::Unset()
{
fPTSOffset = 0;
fOffset = 0;
fSize = 0;
fType = 0;
fActive = false;
}
// CheckLocation
bool
Partition::CheckLocation(off_t sessionSize, int32 blockSize) const
{
// offsets and size must be block aligned, PTS and partition must lie
// within the session
return (fPTSOffset % blockSize == 0
&& fOffset % blockSize == 0
&& fSize % blockSize == 0
&& fPTSOffset >= 0 && fPTSOffset < sessionSize
&& fOffset >= 0 && fOffset + fSize <= sessionSize);
}
// PrimaryPartition
// constructor
PrimaryPartition::PrimaryPartition()
: Partition(),
fHead(NULL),
fTail(NULL),
fLogicalPartitionCount(0)
{
}
// constructor
PrimaryPartition::PrimaryPartition(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize)
: Partition(),
fHead(NULL),
fTail(NULL),
fLogicalPartitionCount(0)
{
SetTo(descriptor, ptsOffset, blockSize);
}
// SetTo
void
PrimaryPartition::SetTo(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize)
{
Unset();
Partition::SetTo(descriptor, ptsOffset, 0, blockSize);
}
// Unset
void
PrimaryPartition::Unset()
{
while (LogicalPartition *partition = fHead) {
fHead = partition->Next();
delete partition;
}
fHead = NULL;
fTail = NULL;
fLogicalPartitionCount = 0;
Partition::Unset();
}
// LogicalPartitionAt
LogicalPartition *
PrimaryPartition::LogicalPartitionAt(int32 index) const
{
LogicalPartition *partition = NULL;
if (index >= 0 && index < fLogicalPartitionCount) {
for (partition = fHead; index > 0; index--)
partition = partition->Next();
}
return partition;
}
// AddLogicalPartition
void
PrimaryPartition::AddLogicalPartition(LogicalPartition *partition)
{
if (partition) {
partition->SetPrimaryPartition(this);
if (fTail) {
fTail->SetNext(partition);
fTail = partition;
} else
fHead = fTail = partition;
partition->SetNext(NULL);
fLogicalPartitionCount++;
}
}
// LogicalPartition
// constructor
LogicalPartition::LogicalPartition()
: Partition(),
fPrimary(NULL),
fNext(NULL)
{
}
// constructor
LogicalPartition::LogicalPartition(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize,
PrimaryPartition *primary)
: Partition(),
fPrimary(NULL),
fNext(NULL)
{
SetTo(descriptor, ptsOffset, blockSize, primary);
}
// SetTo
void
LogicalPartition::SetTo(const partition_descriptor *descriptor,
off_t ptsOffset, int32 blockSize,
PrimaryPartition *primary)
{
Unset();
if (descriptor && primary) {
off_t baseOffset = (descriptor->is_extended() ? primary->Offset()
: ptsOffset);
Partition::SetTo(descriptor, ptsOffset, baseOffset, blockSize);
fPrimary = primary;
}
}
// Unset
void
LogicalPartition::Unset()
{
fPrimary = NULL;
fNext = NULL;
Partition::Unset();
}
// PartitionMap
// constructor
PartitionMap::PartitionMap()
{
}
// destructor
PartitionMap::~PartitionMap()
{
}
// Unset
void
PartitionMap::Unset()
{
for (int32 i = 0; i < 4; i++)
fPrimaries[i].Unset();
}
// PrimaryPartitionAt
PrimaryPartition *
PartitionMap::PrimaryPartitionAt(int32 index)
{
PrimaryPartition *partition = NULL;
if (index >= 0 && index < 4)
partition = fPrimaries + index;
return partition;
}
// PrimaryPartitionAt
const PrimaryPartition *
PartitionMap::PrimaryPartitionAt(int32 index) const
{
const PrimaryPartition *partition = NULL;
if (index >= 0 && index < 4)
partition = fPrimaries + index;
return partition;
}
// CountPartitions
int32
PartitionMap::CountPartitions() const
{
int32 count = 4;
for (int32 i = 0; i < 4; i++)
count += fPrimaries[i].CountLogicalPartitions();
return count;
}
// PartitionAt
Partition *
PartitionMap::PartitionAt(int32 index)
{
Partition *partition = NULL;
int32 count = CountPartitions();
if (index >= 0 && index < count) {
if (index < 4)
partition = fPrimaries + index;
else {
index -= 4;
int32 primary = 0;
while (index >= fPrimaries[primary].CountLogicalPartitions()) {
index -= fPrimaries[primary].CountLogicalPartitions();
primary++;
}
partition = fPrimaries[primary].LogicalPartitionAt(index);
}
}
return partition;
}
// PartitionAt
const Partition *
PartitionMap::PartitionAt(int32 index) const
{
return const_cast<PartitionMap*>(this)->PartitionAt(index);
}
// cmp_partition_offset
static
int
cmp_partition_offset(const void *p1, const void *p2)
{
const Partition *partition1 = *(const Partition**)p1;
const Partition *partition2 = *(const Partition**)p2;
if (partition1->Offset() < partition2->Offset())
return -1;
else if (partition1->Offset() > partition2->Offset())
return 1;
return 0;
}
// cmp_offset
static
int
cmp_offset(const void *o1, const void *o2)
{
off_t offset1 = *static_cast<const off_t*>(o1);
off_t offset2 = *static_cast<const off_t*>(o2);
if (offset1 < offset2)
return -1;
else if (offset1 > offset2)
return 1;
return 0;
}
// is_inside_partitions
static
bool
is_inside_partitions(off_t location, const Partition **partitions, int32 count)
{
bool result = false;
if (count > 0) {
// binary search
int32 lower = 0;
int32 upper = count - 1;
while (lower < upper) {
int32 mid = (lower + upper) / 2;
const Partition *midPartition = partitions[mid];
if (location >= midPartition->Offset() + midPartition->Size())
lower = mid + 1;
else
upper = mid;
}
const Partition *partition = partitions[lower];
result = (location >= partition->Offset() &&
location < partition->Offset() + partition->Size());
}
return result;
}
// Check
bool
PartitionMap::Check(off_t sessionSize, int32 blockSize) const
{
int32 partitionCount = CountPartitions();
// 1. check partition locations
for (int32 i = 0; i < partitionCount; i++) {
if (!PartitionAt(i)->CheckLocation(sessionSize, blockSize))
return false;
}
// 2. check overlapping of partitions and location of PTSs
bool result = true;
const Partition **byOffset = new(nothrow) const Partition*[partitionCount];
off_t *ptsOffsets = new(nothrow) off_t[partitionCount - 3];
if (byOffset && ptsOffsets) {
// fill the arrays
int32 byOffsetCount = 0;
int32 ptsOffsetCount = 1; // primary PTS
ptsOffsets[0] = 0; //
for (int32 i = 0; i < partitionCount; i++) {
const Partition *partition = PartitionAt(i);
if (!partition->IsExtended())
byOffset[byOffsetCount++] = partition;
// add only logical partition PTS locations
if (i >= 4)
ptsOffsets[ptsOffsetCount++] = partition->PTSOffset();
}
// sort the arrays
qsort(byOffset, byOffsetCount, sizeof(const Partition*),
cmp_partition_offset);
qsort(ptsOffsets, ptsOffsetCount, sizeof(off_t), cmp_offset);
// check for overlappings
off_t nextOffset = 0;
for (int32 i = 0; i < byOffsetCount; i++) {
const Partition *partition = byOffset[i];
if (partition->Offset() < nextOffset) {
TRACE(("intel: PartitionMap::Check(): overlapping partitions!"
"\n"));
result = false;
break;
}
nextOffset = partition->Offset() + partition->Size();
}
// check uniqueness of PTS offsets and whether they lie outside of the
// non-extended partitions
if (result) {
for (int32 i = 0; i < ptsOffsetCount; i++) {
if (i > 0 && ptsOffsets[i] == ptsOffsets[i - 1]) {
TRACE(("intel: PartitionMap::Check(): same PTS for "
"different extended partitions!\n"));
result = false;
break;
} else if (is_inside_partitions(ptsOffsets[i], byOffset,
byOffsetCount)) {
TRACE(("intel: PartitionMap::Check(): a PTS lies "
"inside a non-extended partition!\n"));
result = false;
break;
}
}
}
} else
result = false; // no memory: assume failure
// cleanup
if (byOffset)
delete[] byOffset;
if (ptsOffsets)
delete[] ptsOffsets;
return result;
}