me confused were perfectly correct. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27626 a95241bf-73f2-0310-859d-f6bbb57e9c96
270 lines
6.5 KiB
C++
270 lines
6.5 KiB
C++
/*
|
|
* Copyright 2003-2008, Haiku, Inc. All Rights Reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Ingo Weinhold, [email protected]
|
|
*/
|
|
|
|
|
|
#ifndef _USER_MODE
|
|
# include <KernelExport.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <new>
|
|
|
|
#include "PartitionMap.h"
|
|
#include "PartitionMapParser.h"
|
|
|
|
|
|
//#define TRACE_ENABLED
|
|
#ifdef TRACE_ENABLED
|
|
# ifdef _USER_MODE
|
|
# define TRACE(x) printf x
|
|
# else
|
|
# define TRACE(x) dprintf x
|
|
# endif
|
|
#else
|
|
# define TRACE(x) ;
|
|
#endif
|
|
|
|
using std::nothrow;
|
|
|
|
// Maximal number of logical partitions per extended partition we allow.
|
|
static const int32 kMaxLogicalPartitionCount = 128;
|
|
|
|
// constructor
|
|
PartitionMapParser::PartitionMapParser(int deviceFD, off_t sessionOffset,
|
|
off_t sessionSize)
|
|
: fDeviceFD(deviceFD),
|
|
fSessionOffset(sessionOffset),
|
|
fSessionSize(sessionSize),
|
|
fPTS(NULL),
|
|
fMap(NULL)
|
|
{
|
|
}
|
|
|
|
// destructor
|
|
PartitionMapParser::~PartitionMapParser()
|
|
{
|
|
}
|
|
|
|
// Parse
|
|
status_t
|
|
PartitionMapParser::Parse(const uint8 *block, PartitionMap *map)
|
|
{
|
|
status_t error = (map ? B_OK : B_BAD_VALUE);
|
|
if (error == B_OK) {
|
|
fMap = map;
|
|
fMap->Unset();
|
|
if (block) {
|
|
const partition_table_sector *pts
|
|
= (const partition_table_sector*)block;
|
|
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))
|
|
error = B_BAD_DATA;
|
|
|
|
fMap = NULL;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
// _ParsePrimary
|
|
status_t
|
|
PartitionMapParser::_ParsePrimary(const partition_table_sector *pts)
|
|
{
|
|
if (pts == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
// check the signature
|
|
if (pts->signature != kPartitionTableSectorSignature) {
|
|
TRACE(("intel: _ParsePrimary(): invalid PTS signature: %lx\n",
|
|
(uint32)pts->signature));
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
// examine the table
|
|
for (int32 i = 0; i < 4; i++) {
|
|
const partition_descriptor *descriptor = &pts->table[i];
|
|
PrimaryPartition *partition = fMap->PrimaryPartitionAt(i);
|
|
partition->SetTo(descriptor, 0);
|
|
|
|
#ifdef _BOOT_MODE
|
|
// work-around potential BIOS problems
|
|
partition->AdjustSize(fSessionSize);
|
|
#endif
|
|
// ignore, if location is bad
|
|
if (!partition->CheckLocation(fSessionSize)) {
|
|
TRACE(("intel: _ParsePrimary(): partition %ld: bad location, "
|
|
"ignoring\n", i));
|
|
partition->Unset();
|
|
}
|
|
}
|
|
|
|
// allocate a PTS buffer
|
|
fPTS = new(nothrow) partition_table_sector;
|
|
if (fPTS == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
// parse extended partitions
|
|
status_t error = B_OK;
|
|
for (int32 i = 0; error == B_OK && i < 4; i++) {
|
|
PrimaryPartition *primary = fMap->PrimaryPartitionAt(i);
|
|
if (primary->IsExtended())
|
|
error = _ParseExtended(primary, primary->Offset());
|
|
}
|
|
|
|
// cleanup
|
|
delete fPTS;
|
|
fPTS = NULL;
|
|
|
|
return error;
|
|
}
|
|
|
|
// _ParseExtended
|
|
status_t
|
|
PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset)
|
|
{
|
|
status_t error = B_OK;
|
|
int32 partitionCount = 0;
|
|
while (error == B_OK) {
|
|
// check for cycles
|
|
if (++partitionCount > kMaxLogicalPartitionCount) {
|
|
TRACE(("intel: _ParseExtended(): Maximal number of logical "
|
|
"partitions for extended partition reached. Cycle?\n"));
|
|
error = B_BAD_DATA;
|
|
}
|
|
|
|
// read the PTS
|
|
if (error == B_OK)
|
|
error = _ReadPTS(offset);
|
|
|
|
// check the signature
|
|
if (error == B_OK
|
|
&& fPTS->signature != kPartitionTableSectorSignature) {
|
|
TRACE(("intel: _ParseExtended(): invalid PTS signature: %lx\n",
|
|
(uint32)fPTS->signature));
|
|
error = B_BAD_DATA;
|
|
}
|
|
|
|
// ignore the PTS, if any error occured till now
|
|
if (error != B_OK) {
|
|
TRACE(("intel: _ParseExtended(): ignoring this PTS\n"));
|
|
error = B_OK;
|
|
break;
|
|
}
|
|
|
|
// Examine the table, there is exactly one extended and one
|
|
// non-extended logical partition. All four table entries are
|
|
// examined though. If there is no inner extended partition,
|
|
// the end of the linked list is reached.
|
|
// The first PTS describing both an "inner extended" parition and a
|
|
// "data" partition (non extended and not empty) is the start sector
|
|
// of the primary extended partition. The next PTS in the linked list
|
|
// is the start sector of the inner extended partition described in
|
|
// this PTS.
|
|
LogicalPartition extended;
|
|
LogicalPartition nonExtended;
|
|
for (int32 i = 0; error == B_OK && i < 4; i++) {
|
|
const partition_descriptor *descriptor = &fPTS->table[i];
|
|
if (descriptor->is_empty())
|
|
continue;
|
|
|
|
LogicalPartition *partition = NULL;
|
|
if (descriptor->is_extended()) {
|
|
if (extended.IsEmpty()) {
|
|
extended.SetTo(descriptor, offset, primary);
|
|
partition = &extended;
|
|
} else {
|
|
// only one extended partition allowed
|
|
error = B_BAD_DATA;
|
|
TRACE(("intel: _ParseExtended(): "
|
|
"only one extended partition allowed\n"));
|
|
}
|
|
} else {
|
|
if (nonExtended.IsEmpty()) {
|
|
nonExtended.SetTo(descriptor, offset, primary);
|
|
partition = &nonExtended;
|
|
} else {
|
|
// only one non-extended partition allowed
|
|
error = B_BAD_DATA;
|
|
TRACE(("intel: _ParseExtended(): only one "
|
|
"non-extended partition allowed\n"));
|
|
}
|
|
}
|
|
if (partition == NULL)
|
|
break;
|
|
#ifdef _BOOT_MODE
|
|
// work-around potential BIOS problems
|
|
partition->AdjustSize(fSessionSize);
|
|
#endif
|
|
// check the partition's location
|
|
if (!partition->CheckLocation(fSessionSize)) {
|
|
error = B_BAD_DATA;
|
|
TRACE(("intel: _ParseExtended(): Invalid partition "
|
|
"location: pts: %lld, offset: %lld, size: %lld\n",
|
|
partition->PTSOffset(), partition->Offset(),
|
|
partition->Size()));
|
|
}
|
|
}
|
|
|
|
// add non-extended partition to list
|
|
if (error == B_OK && !nonExtended.IsEmpty()) {
|
|
LogicalPartition *partition
|
|
= new(nothrow) LogicalPartition(nonExtended);
|
|
if (partition)
|
|
primary->AddLogicalPartition(partition);
|
|
else
|
|
error = B_NO_MEMORY;
|
|
}
|
|
|
|
// prepare to parse next extended/non-extended partition pair
|
|
if (error == B_OK && !extended.IsEmpty())
|
|
offset = extended.Offset();
|
|
else
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
// _ReadPTS
|
|
status_t
|
|
PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts)
|
|
{
|
|
status_t error = B_OK;
|
|
if (!pts)
|
|
pts = fPTS;
|
|
int32 toRead = sizeof(partition_table_sector);
|
|
// check the offset
|
|
if (offset < 0 || offset + toRead > fSessionSize) {
|
|
error = B_BAD_VALUE;
|
|
TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset));
|
|
// read
|
|
} else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead)
|
|
!= toRead) {
|
|
#ifndef _BOOT_MODE
|
|
error = errno;
|
|
if (error == B_OK)
|
|
error = B_IO_ERROR;
|
|
#else
|
|
error = B_IO_ERROR;
|
|
#endif
|
|
TRACE(("intel: _ReadPTS(): reading the PTS failed: %lx\n", error));
|
|
}
|
|
return error;
|
|
}
|
|
|