The beginning of partitioning support:

* Added functionality to convert a PartitionMap to a string and vice versa.
* get_partitioning_parameters() implemented, but not tested.
* The code also needed by the GUI add-on now lives in separate files.
* Some cleanup.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2591 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-01-28 23:22:54 +00:00
parent 59ec2bb9e7
commit 066d69dad4
5 changed files with 1233 additions and 625 deletions

View File

@ -4,7 +4,7 @@
//--------------------------------------------------------------------- //---------------------------------------------------------------------
/*! /*!
\file intel.cpp \file intel.cpp
disk_scanner partition module for "intel" style partitions \brief disk_scanner partition module for "intel" style partitions.
*/ */
#include <errno.h> #include <errno.h>
@ -17,6 +17,9 @@
#include <KernelExport.h> #include <KernelExport.h>
#include <disk_scanner/partition.h> #include <disk_scanner/partition.h>
#include "intel_parameters.h"
#include "intel_partition_map.h"
#define TRACE(x) ; #define TRACE(x) ;
//#define TRACE(x) dprintf x //#define TRACE(x) dprintf x
@ -28,556 +31,6 @@ static const char *const kShortModuleName = "intel";
// Maximal number of logical partitions per extended partition we allow. // Maximal number of logical partitions per extended partition we allow.
static const int32 kMaxLogicalPartitionCount = 128; static const int32 kMaxLogicalPartitionCount = 128;
struct partition_type {
uint8 type;
char *name;
};
static const struct partition_type gPartitionTypes[] = {
// these entries must be sorted by type (currently not)
{ 0x00, "empty" },
{ 0x01, "FAT 12-bit" },
{ 0x02, "Xenix root" },
{ 0x03, "Xenix user" },
{ 0x04, "FAT 16-bit (dos 3.0)" },
{ 0x05, "Extended Partition" },
{ 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" },
{ 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" },
{ 0xa5, "FreeBSD" },
{ 0xa6, "OpenBSD" },
{ 0xa7, "NextSTEP" },
{ 0xa8, "MacOS X" },
{ 0xa9, "NetBSD" },
{ 0xab, "MacOS X boot" },
{ 0xbe, "Solaris 8 boot" },
{ 0xeb, "BeOS" },
{ 0, NULL }
};
// is_empty_type
static inline
bool
is_empty_type(uint8 type)
{
return (type == 0x00);
}
// is_extended_type
static inline
bool
is_extended_type(uint8 type)
{
return (type == 0x05 || type == 0x0f || type == 0x85);
}
// chs
struct chs {
uint8 cylinder;
uint16 head_sector; // head[15:10], sector[9:0]
} _PACKED;
// partition_descriptor
struct partition_descriptor {
uint8 active;
chs begin;
uint8 type;
chs end;
uint32 start;
uint32 size;
bool is_empty() const { return is_empty_type(type); }
bool is_extended() const { return is_extended_type(type); }
} _PACKED;
// partition_table_sector
struct partition_table_sector {
char pad1[446];
partition_descriptor table[4];
uint16 signature;
} _PACKED;
static const uint16 kPartitionTableSectorSignature = 0xaa55;
// partition_type_string
static
const char *
partition_type_string(uint8 type)
{
int32 i;
for (i = 0; gPartitionTypes[i].name ; i++)
{
if (type == gPartitionTypes[i].type)
return gPartitionTypes[i].name;
}
return "unknown";
}
// Partition
class Partition {
public:
Partition();
Partition(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize);
void Unset();
bool IsEmpty() const { return is_empty_type(fType); }
bool IsExtended() const { return is_extended_type(fType); }
off_t PTSOffset() const { return fPTSOffset; }
off_t Offset() const { return fOffset; }
off_t Size() const { return fSize; }
uint8 Type() const { return fType; }
const char *TypeString() const { return partition_type_string(fType); }
bool CheckLocation(off_t sessionSize) const;
private:
off_t fPTSOffset;
off_t fOffset; // relative to the start of the session
off_t fSize;
uint8 fType;
};
// constructor
Partition::Partition()
: fPTSOffset(0),
fOffset(0),
fSize(0),
fType(0)
{
}
// constructor
Partition::Partition(const partition_descriptor *descriptor,off_t ptsOffset,
off_t baseOffset, int32 blockSize)
: fPTSOffset(0),
fOffset(0),
fSize(0),
fType(0)
{
SetTo(descriptor, ptsOffset, baseOffset, blockSize);
}
// SetTo
void
Partition::SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize)
{
fPTSOffset = ptsOffset;
fOffset = baseOffset + (off_t)descriptor->start * blockSize;
fSize = (off_t)descriptor->size * blockSize;
fType = descriptor->type;
if (fSize == 0)
Unset();
}
// Unset
void
Partition::Unset()
{
fPTSOffset = 0;
fOffset = 0;
fSize = 0;
fType = 0;
}
// CheckLocation
bool
Partition::CheckLocation(off_t sessionSize) const
{
return (fOffset >= 0 && fOffset + fSize <= sessionSize);
}
class LogicalPartition;
// PrimaryPartition
class PrimaryPartition : public Partition {
public:
PrimaryPartition();
PrimaryPartition(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize);
void Unset();
// only if extended
int32 CountLogicalPartitions() const { return fLogicalPartitionCount; }
LogicalPartition *LogicalPartitionAt(int32 index) const;
void AddLogicalPartition(LogicalPartition *partition);
private:
LogicalPartition *fHead;
LogicalPartition *fTail;
int32 fLogicalPartitionCount;
};
// LogicalPartition
class LogicalPartition : public Partition {
public:
LogicalPartition();
LogicalPartition(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize, PrimaryPartition *primary);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize, PrimaryPartition *primary);
void Unset();
PrimaryPartition *GetPrimaryPartition() const { return fPrimary; }
void SetNext(LogicalPartition *next) { fNext = next; }
LogicalPartition *Next() const { return fNext; }
private:
PrimaryPartition *fPrimary;
LogicalPartition *fNext;
};
// 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) {
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
class PartitionMap {
public:
PartitionMap();
~PartitionMap();
void Unset();
PrimaryPartition *PrimaryPartitionAt(int32 index);
int32 CountPartitions() const;
Partition *PartitionAt(int32 index);
const Partition *PartitionAt(int32 index) const;
bool Check() const;
private:
PrimaryPartition fPrimaries[4];
};
// 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;
}
// 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 = *static_cast<const Partition **>(p1);
const Partition *partition2 = *static_cast<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() const
{
bool result = true;
int32 partitionCount = CountPartitions();
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;
}
// PartitionMapParser // PartitionMapParser
@ -595,7 +48,7 @@ public:
private: private:
status_t _ParsePrimary(const partition_table_sector *pts); status_t _ParsePrimary(const partition_table_sector *pts);
status_t _ParseExtended(PrimaryPartition *primary, off_t offset); status_t _ParseExtended(PrimaryPartition *primary, off_t offset);
status_t _ReadPTS(off_t offset); status_t _ReadPTS(off_t offset, partition_table_sector *pts = NULL);
private: private:
int fDeviceFD; int fDeviceFD;
@ -631,10 +84,17 @@ PartitionMapParser::Parse(const uint8 *block, PartitionMap *map)
if (error == B_OK) { if (error == B_OK) {
fMap = map; fMap = map;
fMap->Unset(); fMap->Unset();
const partition_table_sector *pts if (block) {
= (const partition_table_sector*)block; const partition_table_sector *pts
error = _ParsePrimary(pts); = (const partition_table_sector*)block;
if (error == B_OK && !fMap->Check()) error = _ParsePrimary(pts);
} else {
partition_table_sector pts;
error = _ReadPTS(0, &pts);
if (error == B_OK)
error = _ParsePrimary(&pts);
}
if (error == B_OK && !fMap->Check(fSessionSize, fBlockSize))
error = B_BAD_DATA; error = B_BAD_DATA;
fMap = NULL; fMap = NULL;
} }
@ -658,7 +118,7 @@ PartitionMapParser::_ParsePrimary(const partition_table_sector *pts)
PrimaryPartition *partition = fMap->PrimaryPartitionAt(i); PrimaryPartition *partition = fMap->PrimaryPartitionAt(i);
partition->SetTo(descriptor, 0, fBlockSize); partition->SetTo(descriptor, 0, fBlockSize);
// fail, if location is bad // fail, if location is bad
if (!partition->CheckLocation(fSessionSize)) { if (!partition->CheckLocation(fSessionSize, fBlockSize)) {
error = B_BAD_DATA; error = B_BAD_DATA;
break; break;
} }
@ -738,8 +198,10 @@ PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset)
} }
} }
// check the partition's location // check the partition's location
if (partition && !partition->CheckLocation(fSessionSize)) if (partition && !partition->CheckLocation(fSessionSize,
fBlockSize)) {
error = B_BAD_DATA; error = B_BAD_DATA;
}
} }
} }
} }
@ -763,16 +225,18 @@ PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset)
// _ReadPTS // _ReadPTS
status_t status_t
PartitionMapParser::_ReadPTS(off_t offset) PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts)
{ {
status_t error = B_OK; status_t error = B_OK;
if (!pts)
pts = fPTS;
int32 toRead = sizeof(partition_table_sector); int32 toRead = sizeof(partition_table_sector);
// check the offset // check the offset
if (offset < 0 || offset + toRead > fSessionSize) { if (offset < 0 || offset + toRead > fSessionSize) {
error = B_BAD_VALUE; error = B_BAD_VALUE;
TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset)); TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset));
// read // read
} else if (read_pos(fDeviceFD, fSessionOffset + offset, fPTS, toRead) } else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead)
!= toRead) { != toRead) {
error = errno; error = errno;
if (error == B_OK) if (error == B_OK)
@ -798,34 +262,43 @@ std_ops(int32 op, ...)
return B_ERROR; return B_ERROR;
} }
// read_partition_map
static
status_t
read_partition_map(int deviceFD, const session_info *sessionInfo,
const uchar *block, PartitionMap *map)
{
bool result = true;
off_t sessionOffset = sessionInfo->offset;
off_t sessionSize = sessionInfo->size;
int32 blockSize = sessionInfo->logical_block_size;
TRACE(("intel: read_partition_map(%d, %lld, %lld, %p, %ld)\n", deviceFD,
sessionOffset, sessionSize, block, blockSize));
// check block size
if (result) {
result = ((uint32)blockSize >= sizeof(partition_table_sector));
if (!result) {
TRACE(("intel: read_partition_map: bad block size: %ld, should be "
">= %ld\n", blockSize, sizeof(partition_table_sector)));
}
}
// read the partition structure
if (result) {
PartitionMapParser parser(deviceFD, sessionOffset, sessionSize,
blockSize);
result = (parser.Parse(block, map) == B_OK);
}
return result;
}
// intel_identify // intel_identify
static static
bool bool
intel_identify(int deviceFD, const session_info *sessionInfo, intel_identify(int deviceFD, const session_info *sessionInfo,
const uchar *block) const uchar *block)
{ {
bool result = true; PartitionMap map;
int32 blockSize = sessionInfo->logical_block_size; return read_partition_map(deviceFD, sessionInfo, block, &map);
TRACE(("intel: identify(%d, %lld, %lld, %p, %ld)\n", deviceFD,
sessionInfo->offset, sessionInfo->size, block, blockSize));
// check block size
if (result) {
result = ((uint32)blockSize >= sizeof(partition_table_sector));
if (!result) {
TRACE(("intel: identify: bad block size: %ld, should be >= %ld\n",
blockSize, sizeof(partition_table_sector)));
}
}
// read the partition structure
if (result) {
PartitionMapParser parser(deviceFD, sessionInfo->offset,
sessionInfo->size, blockSize);
PartitionMap map;
result = (parser.Parse(block, &map) == B_OK
&& map.CountPartitions() > 0);
}
return result;
} }
// intel_get_nth_info // intel_get_nth_info
@ -835,50 +308,38 @@ intel_get_nth_info(int deviceFD, const session_info *sessionInfo,
const uchar *block, int32 index, const uchar *block, int32 index,
extended_partition_info *partitionInfo) extended_partition_info *partitionInfo)
{ {
status_t error = B_ENTRY_NOT_FOUND; status_t error = B_OK;
off_t sessionOffset = sessionInfo->offset; off_t sessionOffset = sessionInfo->offset;
off_t sessionSize = sessionInfo->size;
int32 blockSize = sessionInfo->logical_block_size;
TRACE(("intel: get_nth_info(%d, %lld, %lld, %p, %ld, %ld)\n", deviceFD, TRACE(("intel: get_nth_info(%d, %lld, %lld, %p, %ld, %ld)\n", deviceFD,
sessionOffset, sessionSize, block, blockSize, index)); sessionOffset, sessionInfo->size, block,
if (intel_identify(deviceFD, sessionInfo, block)) { sessionInfo->logical_block_size, index));
if (index >= 0) { PartitionMap map;
// parse the partition map if (read_partition_map(deviceFD, sessionInfo, block, &map)) {
PartitionMapParser parser(deviceFD, sessionOffset, sessionSize, if (Partition *partition = map.PartitionAt(index)) {
blockSize); if (partition->IsEmpty()) {
PartitionMap map; // empty partition
error = parser.Parse(block, &map); partitionInfo->info.offset = sessionOffset;
if (error == B_OK) { partitionInfo->info.size = 0;
if (map.CountPartitions() == 0) partitionInfo->flags
error = B_BAD_DATA; = B_HIDDEN_PARTITION | B_EMPTY_PARTITION;
} else {
// non-empty partition
partitionInfo->info.offset
= partition->Offset() + sessionOffset;
partitionInfo->info.size = partition->Size();
if (partition->IsExtended())
partitionInfo->flags = B_HIDDEN_PARTITION;
else
partitionInfo->flags = 0;
} }
if (error == B_OK) { partitionInfo->partition_name[0] = '\0';
if (Partition *partition = map.PartitionAt(index)) { strcpy(partitionInfo->partition_type,
if (partition->IsEmpty()) { partition->TypeString());
// empty partition partitionInfo->partition_code = partition->Type();
partitionInfo->info.offset = sessionOffset; } else
partitionInfo->info.size = 0; error = B_ENTRY_NOT_FOUND;
partitionInfo->flags } else // couldn't read partition map -- we shouldn't be in get_nth_info()
= B_HIDDEN_PARTITION | B_EMPTY_PARTITION; error = B_BAD_DATA;
} else {
// non-empty partition
partitionInfo->info.offset
= partition->Offset() + sessionOffset;
partitionInfo->info.size = partition->Size();
if (partition->IsExtended())
partitionInfo->flags = B_HIDDEN_PARTITION;
else
partitionInfo->flags = 0;
}
partitionInfo->partition_name[0] = '\0';
strcpy(partitionInfo->partition_type,
partition->TypeString());
partitionInfo->partition_code = partition->Type();
} else
error = B_ENTRY_NOT_FOUND;
}
}
}
return error; return error;
} }
@ -890,8 +351,28 @@ intel_get_partitioning_params(int deviceFD,
char *buffer, size_t bufferSize, char *buffer, size_t bufferSize,
size_t *actualSize) size_t *actualSize)
{ {
// not yet supported status_t error = B_OK;
return B_UNSUPPORTED; PartitionMap map;
if (!read_partition_map(deviceFD, sessionInfo, NULL, &map)) {
// couldn't read partition map, set up a default one:
// four empty primary partitions
map.Unset();
}
// get the parameter length
size_t length = 0;
if (error == B_OK) {
ParameterUnparser unparser;
error = unparser.GetParameterLength(&map, &length);
}
// write the parameters
if (error == B_OK && length <= bufferSize) {
ParameterUnparser unparser;
error = unparser.Unparse(&map, buffer, bufferSize);
}
// set the results
if (error == B_OK)
*actualSize = length;
return error;
} }
// intel_partition // intel_partition

View File

@ -0,0 +1,390 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_parameters.cpp
\brief Class implementations for "intel" style partitioning
parameter support.
*/
#include <ctype.h>
#include <new.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intel_parameters.h"
#include "intel_partition_map.h"
// Grammar for parameters:
//
// partition ::= "{" ptsoffset "," offset "," size "," type ","
// active "}"
// primary ::= "{" partition+ "}"
// partition_map ::= primary primary primary primary
// longest token (including terminating null)
const int32 kMaxTokenLen = 256;
// Tokenizer
// constructor
Tokenizer::Tokenizer()
: fInput(NULL),
fPosition(0),
fLastPosition(0)
{
}
// constructor
Tokenizer::Tokenizer(const char *input)
: fInput(input),
fPosition(0),
fLastPosition(0)
{
}
// SetTo
void
Tokenizer::SetTo(const char *input)
{
fInput = input;
fPosition = 0;
fLastPosition = 0;
}
// GetNextToken
int32
Tokenizer::GetNextToken(char *buffer)
{
int32 kind = TOKEN_ERROR;
fLastPosition = fPosition;
// skip WS
_SkipWhiteSpace();
switch (fInput[fPosition]) {
case '{':
case '}':
case ',':
kind = fInput[fPosition];
fPosition++;
break;
case '\0':
kind = TOKEN_EOF;
break;
default:
{
if (isdigit(fInput[fPosition])) {
int32 startPos = fPosition;
while (isdigit(fInput[fPosition]))
fPosition++;
int32 len = fPosition - startPos;
if (len < kMaxTokenLen) {
if (buffer) {
memcpy(buffer, fInput + startPos, len);
buffer[len] = '\0';
}
kind = TOKEN_NUMBER;
} else {
printf("token too long at: %ld\n", startPos);
kind = TOKEN_ERROR;
}
}
break;
}
}
return kind;
}
// ExpectToken
bool
Tokenizer::ExpectToken(int32 kind, char *buffer)
{
bool result = (GetNextToken(buffer) == kind);
if (!result)
PutLastToken();
return result;
}
// ReadNumber
bool
Tokenizer::ReadNumber(int64 &number)
{
char buffer[kMaxTokenLen];
bool result = ExpectToken(TOKEN_NUMBER, buffer);
if (result)
number = atoll(buffer);
return result;
}
// _SkipWhiteSpace
void
Tokenizer::_SkipWhiteSpace()
{
while (fInput[fPosition] != '\0' && isspace(fInput[fPosition]))
fPosition++;
}
// ParameterParser
// constructor
ParameterParser::ParameterParser()
: fTokenizer(),
fParseError(B_OK),
fMap(NULL)
{
}
// Parse
status_t
ParameterParser::Parse(const char *parameters, PartitionMap *map)
{
status_t error = (parameters && map ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// init parser
fParseError = B_OK;
fTokenizer.SetTo(parameters);
fMap = map;
// partition_map ::= primary primary primary primary
if (_ParsePrimaryPartition(fMap->PrimaryPartitionAt(0))
&& _ParsePrimaryPartition(fMap->PrimaryPartitionAt(1))
&& _ParsePrimaryPartition(fMap->PrimaryPartitionAt(2))
&& _ParsePrimaryPartition(fMap->PrimaryPartitionAt(3))
&& fTokenizer.ReadEOF()) {
// successfully parsed
} else
_ErrorOccurred();
// cleanup / set results
fMap = NULL;
error = fParseError;
}
return error;
}
// _ParsePrimaryPartition
bool
ParameterParser::_ParsePrimaryPartition(PrimaryPartition *primary)
{
// primary ::= "{" partition+ "}"
if (fTokenizer.ReadOpen()
&& _ParsePartition(primary)) {
while (_NoError() && !fTokenizer.ReadClose()) {
LogicalPartition *partition = new(nothrow) LogicalPartition;
if (partition) {
if (_ParsePartition(partition))
primary->AddLogicalPartition(partition);
else
delete partition;
} else
_ErrorOccurred(B_NO_MEMORY);
}
} else
_ErrorOccurred();
return _NoError();
}
// _ParsePartition
bool
ParameterParser::_ParsePartition(Partition *partition)
{
// partition ::= "{" ptsoffset "," offset "," size "," type ","
// active "}"
int64 ptsOffset, offset, size, type, active;
if (fTokenizer.ReadOpen()
&& fTokenizer.ReadNumber(ptsOffset)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(offset)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(size)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(type)
&& fTokenizer.ReadComma()
&& fTokenizer.ReadNumber(active)
&& fTokenizer.ReadClose()) {
if (ptsOffset >= 0 && offset >= 0 && size >= 0
&& type >= 0 && type < 256) {
partition->SetPTSOffset(ptsOffset);
partition->SetOffset(offset);
partition->SetSize(size);
partition->SetType((uint8)type);
partition->SetActive(active);
} else
_ErrorOccurred(B_BAD_VALUE);
} else
_ErrorOccurred();
return _NoError();
}
// _ErrorOccurred
void
ParameterParser::_ErrorOccurred(status_t error)
{
if (fParseError == B_OK)
fParseError = error;
}
// ParameterUnparser
// constructor
ParameterUnparser::ParameterUnparser()
: fMap(NULL),
fParameters(NULL),
fPosition(0),
fSize(0),
fDryRun(false),
fUnparseError(B_OK)
{
}
// GetParameterLength
status_t
ParameterUnparser::GetParameterLength(const PartitionMap *map, size_t *length)
{
status_t error = (map && length ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// init unparser for a dry run
fUnparseError = B_OK;
fMap = map;
char buffer[kMaxTokenLen];
fParameters = buffer;
fPosition = 0;
fSize = 0;
fDryRun = true;
// dry run -- get the parameter size
if (_UnparsePartitionMap())
*length = fPosition + 1;
// cleanup / set results
fMap = NULL;
error = fUnparseError;
}
return error;
}
// Unparse
status_t
ParameterUnparser::Unparse(const PartitionMap *map, char *parameters,
size_t size)
{
status_t error = (map && parameters ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
// init unparser
fUnparseError = B_OK;
fMap = map;
fParameters = parameters;
fPosition = 0;
fSize = size;
fDryRun = false;
// unparse the partition map
_UnparsePartitionMap();
// cleanup / set results
fMap = NULL;
error = fUnparseError;
}
return error;
}
// _UnparsePartitionMap
bool
ParameterUnparser::_UnparsePartitionMap()
{
if (_UnparsePrimaryPartition(fMap->PrimaryPartitionAt(0))
&& _UnparsePrimaryPartition(fMap->PrimaryPartitionAt(1))
&& _UnparsePrimaryPartition(fMap->PrimaryPartitionAt(2))
&& _UnparsePrimaryPartition(fMap->PrimaryPartitionAt(3))) {
// successfully unparsed
}
return _NoError();
}
// _UnparsePrimaryPartition
bool
ParameterUnparser::_UnparsePrimaryPartition(const PrimaryPartition *primary)
{
// primary ::= "{" partition+ "}"
if (_WriteOpen() && _UnparsePartition(primary)) {
for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) {
const LogicalPartition *partition = primary->LogicalPartitionAt(i);
if (!_UnparsePartition(partition))
break;
}
if (_NoError())
_WriteClose();
}
return _NoError();
}
// _UnparsePartition
bool
ParameterUnparser::_UnparsePartition(const Partition *partition)
{
// partition ::= "{" ptsoffset "," offset "," size "," type ","
// active "}"
if (_WriteOpen()
&& _WriteNumber(partition->PTSOffset())
&& _WriteComma()
&& _WriteNumber(partition->Offset())
&& _WriteComma()
&& _WriteNumber(partition->Size())
&& _WriteComma()
&& _WriteNumber(partition->Type())
&& _WriteComma()
&& _WriteNumber(partition->Active() ? 1 : 0)
&& _WriteClose()) {
// success
}
return _NoError();
}
// _Write
bool
ParameterUnparser::_Write(const char *str)
{
size_t len = strlen(str);
if (!fDryRun) {
if (fSize > fPosition + len)
strcpy(fParameters + fPosition, str);
else
_ErrorOccurred(B_BAD_VALUE);
}
fPosition += len;
return _NoError();
}
// _WriteNumber
bool
ParameterUnparser::_WriteNumber(int64 number)
{
char buffer[kMaxTokenLen];
sprintf(buffer, "%lld", number);
return _Write(buffer);
}
// _ErrorOccurred
void
ParameterUnparser::_ErrorOccurred(status_t error)
{
if (fUnparseError == B_OK)
fUnparseError = error;
}
/*
// main
int
main()
{
const char *parameters = "{{ 0, 10, 1, 0}{ 0, 3, 1, 0}}"
"{{10, 13, 1, 1}}"
"{{23, 7, 1, 0}}"
"{{30, 9, 1, 0}}";
ParameterParser parser;
status_t error = parser.Parse(parameters);
if (error != B_OK)
printf("error while parsing: %s\n", strerror(error));
return 0;
}
*/

View File

@ -0,0 +1,110 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_parameters.h
\brief Class interface definitions for "intel" style partitioning
parameter support.
*/
#ifndef _INTEL_PARAMETERS_H
#define _INTEL_PARAMETERS_H
#include <SupportDefs.h>
class Partition;
class PartitionMap;
class PrimaryPartition;
// tokens
enum {
TOKEN_ERROR = -1,
TOKEN_EOF = '\0',
TOKEN_OPEN = '{',
TOKEN_CLOSE = '}',
TOKEN_COMMA = ',',
TOKEN_NUMBER = '0',
};
// Tokenizer
class Tokenizer {
public:
Tokenizer();
Tokenizer(const char *input);
void SetTo(const char *input);
int32 GetNextToken(char *buffer = NULL);
void PutLastToken() { fPosition = fLastPosition; }
bool ExpectToken(int32 kind, char *buffer = NULL);
bool ReadOpen() { return (ExpectToken(TOKEN_OPEN)); }
bool ReadClose() { return (ExpectToken(TOKEN_CLOSE)); }
bool ReadComma() { return (ExpectToken(TOKEN_COMMA)); }
bool ReadEOF() { return (ExpectToken(TOKEN_EOF)); }
bool ReadNumber(int64 &number);
private:
void _SkipWhiteSpace();
private:
const char *fInput;
int32 fPosition;
int32 fLastPosition;
};
// ParameterParser
class ParameterParser {
public:
ParameterParser();
~ParameterParser() {}
status_t Parse(const char *parameters, PartitionMap *map);
private:
bool _ParsePrimaryPartition(PrimaryPartition *primary);
bool _ParsePartition(Partition *partition);
void _ErrorOccurred(status_t error = B_ERROR);
bool _NoError() const { return (fParseError == B_OK); }
private:
Tokenizer fTokenizer;
status_t fParseError;
PartitionMap *fMap;
};
// ParameterUnparser
class ParameterUnparser {
public:
ParameterUnparser();
~ParameterUnparser() {}
status_t GetParameterLength(const PartitionMap *map, size_t *length);
status_t Unparse(const PartitionMap *map, char *parameters, size_t length);
private:
bool _UnparsePartitionMap();
bool _UnparsePrimaryPartition(const PrimaryPartition *primary);
bool _UnparsePartition(const Partition *partition);
bool _Write(const char *str);
bool _WriteOpen() { return _Write("{"); }
bool _WriteClose() { return _Write("}"); }
bool _WriteComma() { return _Write(","); }
bool _WriteNumber(int64 number);
void _ErrorOccurred(status_t error = B_ERROR);
bool _NoError() const { return (fUnparseError == B_OK); }
private:
const PartitionMap *fMap;
char *fParameters;
size_t fPosition;
size_t fSize;
bool fDryRun;
status_t fUnparseError;
};
#endif // _INTEL_PARAMETERS_H

View File

@ -0,0 +1,459 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_partition_map.cpp
\brief Definitions for "intel" style partitions and implementation
of related classes.
*/
#include <new.h>
#include <stdlib.h>
#include <string.h>
#include "intel_partition_map.h"
#define TRACE(x) ;
//#define TRACE(x) dprintf x
// partition_type
struct partition_type {
uint8 type;
char *name;
};
static const struct partition_type kPartitionTypes[] = {
// these entries must be sorted by type (currently not)
{ 0x00, "empty" },
{ 0x01, "FAT 12-bit" },
{ 0x02, "Xenix root" },
{ 0x03, "Xenix user" },
{ 0x04, "FAT 16-bit (dos 3.0)" },
{ 0x05, "Extended Partition" },
{ 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" },
{ 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" },
{ 0xa5, "FreeBSD" },
{ 0xa6, "OpenBSD" },
{ 0xa7, "NextSTEP" },
{ 0xa8, "MacOS X" },
{ 0xa9, "NetBSD" },
{ 0xab, "MacOS X boot" },
{ 0xbe, "Solaris 8 boot" },
{ 0xeb, "BeOS" },
{ 0, NULL }
};
// partition_type_string
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 "unknown";
}
// 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)
{
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 = *static_cast<const Partition **>(p1);
const Partition *partition2 = *static_cast<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;
}

View File

@ -0,0 +1,168 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//---------------------------------------------------------------------
/*!
\file intel_partition_map.h
\brief Definitions for "intel" style partitions and interface definitions
for related classes.
*/
#ifndef _INTEL_PARTITION_MAP_H
#define _INTEL_PARTITION_MAP_H
#include <SupportDefs.h>
// is_empty_type
static inline
bool
is_empty_type(uint8 type)
{
return (type == 0x00);
}
// is_extended_type
static inline
bool
is_extended_type(uint8 type)
{
return (type == 0x05 || type == 0x0f || type == 0x85);
}
const char *partition_type_string(uint8 type);
// chs
struct chs {
uint8 cylinder;
uint16 head_sector; // head[15:10], sector[9:0]
} _PACKED;
// partition_descriptor
struct partition_descriptor {
uint8 active;
chs begin;
uint8 type;
chs end;
uint32 start;
uint32 size;
bool is_empty() const { return is_empty_type(type); }
bool is_extended() const { return is_extended_type(type); }
} _PACKED;
// partition_table_sector
struct partition_table_sector {
char pad1[446];
partition_descriptor table[4];
uint16 signature;
} _PACKED;
static const uint16 kPartitionTableSectorSignature = 0xaa55;
class Partition;
class PrimaryPartition;
class LogicalPartition;
// Partition
class Partition {
public:
Partition();
Partition(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
off_t baseOffset, int32 blockSize);
void Unset();
bool IsEmpty() const { return is_empty_type(fType); }
bool IsExtended() const { return is_extended_type(fType); }
off_t PTSOffset() const { return fPTSOffset; }
off_t Offset() const { return fOffset; }
off_t Size() const { return fSize; }
uint8 Type() const { return fType; }
bool Active() const { return fActive; }
const char *TypeString() const { return partition_type_string(fType); }
void SetPTSOffset(off_t offset) { fPTSOffset = offset; }
void SetOffset(off_t offset) { fOffset = offset; }
void SetSize(off_t size) { fSize = size; }
void SetType(uint8 type) { fType = type; }
void SetActive(bool active) { fActive = active; }
bool CheckLocation(off_t sessionSize, int32 blockSize) const;
private:
off_t fPTSOffset;
off_t fOffset; // relative to the start of the session
off_t fSize;
uint8 fType;
bool fActive;
};
// PrimaryPartition
class PrimaryPartition : public Partition {
public:
PrimaryPartition();
PrimaryPartition(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize);
void Unset();
// only if extended
int32 CountLogicalPartitions() const { return fLogicalPartitionCount; }
LogicalPartition *LogicalPartitionAt(int32 index) const;
void AddLogicalPartition(LogicalPartition *partition);
private:
LogicalPartition *fHead;
LogicalPartition *fTail;
int32 fLogicalPartitionCount;
};
// LogicalPartition
class LogicalPartition : public Partition {
public:
LogicalPartition();
LogicalPartition(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize, PrimaryPartition *primary);
void SetTo(const partition_descriptor *descriptor, off_t ptsOffset,
int32 blockSize, PrimaryPartition *primary);
void Unset();
void SetPrimaryPartition(PrimaryPartition *primary) { fPrimary = primary; }
PrimaryPartition *GetPrimaryPartition() const { return fPrimary; }
void SetNext(LogicalPartition *next) { fNext = next; }
LogicalPartition *Next() const { return fNext; }
private:
PrimaryPartition *fPrimary;
LogicalPartition *fNext;
};
// PartitionMap
class PartitionMap {
public:
PartitionMap();
~PartitionMap();
void Unset();
PrimaryPartition *PrimaryPartitionAt(int32 index);
const PrimaryPartition *PrimaryPartitionAt(int32 index) const;
int32 CountPartitions() const;
Partition *PartitionAt(int32 index);
const Partition *PartitionAt(int32 index) const;
bool Check(off_t sessionSize, int32 blockSize) const;
private:
PrimaryPartition fPrimaries[4];
};
#endif // _INTEL_PARTITION_MAP_H