From 852d12ef4ce8c211ebb201900500f2c018634545 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 13 Jun 2003 22:01:51 +0000 Subject: [PATCH] Ported the intel partitioning system module to the new interface (disk device manager) and moved it to a nicer place. First tests look good, though my hard disk structure doesn't even have extended partitions. Going to install Linux now... git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3504 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/Jamfile | 2 +- .../kernel/partitioning_systems/Jamfile | 3 + .../kernel/partitioning_systems/intel/Jamfile | 15 + .../intel/PartitionMap.cpp | 476 ++++++++++ .../partitioning_systems/intel/PartitionMap.h | 169 ++++ .../partitioning_systems/intel/intel.cpp | 836 ++++++++++++++++++ 6 files changed, 1500 insertions(+), 1 deletion(-) create mode 100644 src/add-ons/kernel/partitioning_systems/Jamfile create mode 100644 src/add-ons/kernel/partitioning_systems/intel/Jamfile create mode 100644 src/add-ons/kernel/partitioning_systems/intel/PartitionMap.cpp create mode 100644 src/add-ons/kernel/partitioning_systems/intel/PartitionMap.h create mode 100644 src/add-ons/kernel/partitioning_systems/intel/intel.cpp diff --git a/src/add-ons/kernel/Jamfile b/src/add-ons/kernel/Jamfile index 67abf000b7..be451d3090 100644 --- a/src/add-ons/kernel/Jamfile +++ b/src/add-ons/kernel/Jamfile @@ -6,4 +6,4 @@ SubInclude OBOS_TOP src add-ons kernel drivers ; SubInclude OBOS_TOP src add-ons kernel file_systems ; SubInclude OBOS_TOP src add-ons kernel network ; SubInclude OBOS_TOP src add-ons kernel media ; - +SubInclude OBOS_TOP src add-ons kernel partitioning_systems ; diff --git a/src/add-ons/kernel/partitioning_systems/Jamfile b/src/add-ons/kernel/partitioning_systems/Jamfile new file mode 100644 index 0000000000..ba4834c3a6 --- /dev/null +++ b/src/add-ons/kernel/partitioning_systems/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP src add-ons kernel partitioning_systems ; + +SubInclude OBOS_TOP src add-ons kernel partitioning_systems intel ; diff --git a/src/add-ons/kernel/partitioning_systems/intel/Jamfile b/src/add-ons/kernel/partitioning_systems/intel/Jamfile new file mode 100644 index 0000000000..699f1fad92 --- /dev/null +++ b/src/add-ons/kernel/partitioning_systems/intel/Jamfile @@ -0,0 +1,15 @@ +SubDir OBOS_TOP src add-ons kernel partitioning_systems intel ; + +#UsePrivateHeaders $(DOT) ; +UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; + +# For now build a userland version only. +Addon intel : userland partitioning_systems : + intel.cpp + PartitionMap.cpp +; + +LinkSharedOSLibs intel : + libkernelland_emu.so + libdisk_device_manager.so +; diff --git a/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.cpp b/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.cpp new file mode 100644 index 0000000000..29e759a690 --- /dev/null +++ b/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.cpp @@ -0,0 +1,476 @@ +//---------------------------------------------------------------------- +// 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 +#include +#include +#include + +#include + +#include "PartitionMap.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 +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(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(o1); + off_t offset2 = *static_cast(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; +} + diff --git a/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.h b/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.h new file mode 100644 index 0000000000..0d441c04d6 --- /dev/null +++ b/src/add-ons/kernel/partitioning_systems/intel/PartitionMap.h @@ -0,0 +1,169 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file PartitionMap.h + \brief Definitions for "intel" style partitions and interface definitions + for related classes. +*/ + +#ifndef _INTEL_PARTITION_MAP_H +#define _INTEL_PARTITION_MAP_H + +#include + +// 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); +} + +void get_partition_type_string(uint8 type, char *buffer); + +// 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; } + void GetTypeString(char *buffer) const + { get_partition_type_string(fType, buffer); } + + 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 diff --git a/src/add-ons/kernel/partitioning_systems/intel/intel.cpp b/src/add-ons/kernel/partitioning_systems/intel/intel.cpp new file mode 100644 index 0000000000..4b54143751 --- /dev/null +++ b/src/add-ons/kernel/partitioning_systems/intel/intel.cpp @@ -0,0 +1,836 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file intel.cpp + \brief disk_scanner partition module for "intel" style partitions. +*/ + +// TODO: The implementation is very strict right now. It rejects a partition +// completely, if it finds an error in its partition tables. We should see, +// what error can be handled gracefully, e.g. by ignoring the partition +// descriptor or the whole partition table sector. + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "PartitionMap.h" + +//#define TRACE(x) ; +#define TRACE(x) dprintf x + +// module names +#define INTEL_PARTITION_MAP_MODULE_NAME "partitioning_systems/intel/map/v1" +#define INTEL_EXTENDED_PARTITION_MODULE_NAME \ + "partitioning_systems/intel/extended/v1" + +// partition module identifier +static const char *const kPartitionMapPrettyName = "Intel Partition Map"; +static const char *const kPrimaryPartitionPrettyName + = "Intel Primary Partition"; +static const char *const kExtendedPartitionPrettyName + = "Intel Extended Partition"; +static const char *const kLogicalPartitionPrettyName + = "Intel Logical Partition"; + +// Maximal number of logical partitions per extended partition we allow. +static const int32 kMaxLogicalPartitionCount = 128; + + +// AutoDeleter + +template +class AutoDeleter { +public: + AutoDeleter(C *object) : fObject(object) {} + ~AutoDeleter() { delete fObject; } + void SetObject(C *object) { fObject = object; } + +private: + C *fObject; +}; + + +// PartitionMapParser + +class PartitionMapParser { +public: + PartitionMapParser(int deviceFD, off_t sessionOffset, off_t sessionSize, + int32 blockSize); + ~PartitionMapParser(); + + status_t Parse(const uint8 *block, PartitionMap *map); + + int32 CountPartitions() const; + const Partition *PartitionAt(int32 index) const; + +private: + status_t _ParsePrimary(const partition_table_sector *pts); + status_t _ParseExtended(PrimaryPartition *primary, off_t offset); + status_t _ReadPTS(off_t offset, partition_table_sector *pts = NULL); + +private: + int fDeviceFD; + off_t fSessionOffset; + off_t fSessionSize; + int32 fBlockSize; + partition_table_sector *fPTS; // while parsing + PartitionMap *fMap; // +}; + +// constructor +PartitionMapParser::PartitionMapParser(int deviceFD, off_t sessionOffset, + off_t sessionSize, int32 blockSize) + : fDeviceFD(deviceFD), + fSessionOffset(sessionOffset), + fSessionSize(sessionSize), + fBlockSize(blockSize), + 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, fBlockSize)) + error = B_BAD_DATA; + fMap = NULL; + } + return error; +} + +// _ParsePrimary +status_t +PartitionMapParser::_ParsePrimary(const partition_table_sector *pts) +{ + status_t error = (pts ? B_OK : B_BAD_VALUE); + // check the signature + if (error == B_OK && pts->signature != kPartitionTableSectorSignature) { + TRACE(("intel: _ParsePrimary(): invalid PTS signature\n")); + error = B_BAD_DATA; + } + // examine the table + if (error == B_OK) { + for (int32 i = 0; i < 4; i++) { + const partition_descriptor *descriptor = &pts->table[i]; + PrimaryPartition *partition = fMap->PrimaryPartitionAt(i); + partition->SetTo(descriptor, 0, fBlockSize); + // fail, if location is bad + if (!partition->CheckLocation(fSessionSize, fBlockSize)) { + error = B_BAD_DATA; + break; + } + } + } + // allocate a PTS buffer + if (error == B_OK) { + fPTS = new(nothrow) partition_table_sector; + if (!fPTS) + error = B_NO_MEMORY; + } + // parse extended partitions + if (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 + if (fPTS) { + 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\n")); + 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 + LogicalPartition extended; + LogicalPartition nonExtended; + if (error == B_OK) { + for (int32 i = 0; error == B_OK && i < 4; i++) { + const partition_descriptor *descriptor = &fPTS->table[i]; + LogicalPartition *partition = NULL; + if (!descriptor->is_empty()) { + if (descriptor->is_extended()) { + if (extended.IsEmpty()) { + extended.SetTo(descriptor, offset, fBlockSize, + 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, fBlockSize, + primary); + partition = &nonExtended; + } else { + // only one non-extended partition allowed + error = B_BAD_DATA; + TRACE(("intel: _ParseExtended(): only one " + "non-extended partition allowed\n")); + } + } + // check the partition's location + if (partition && !partition->CheckLocation(fSessionSize, + fBlockSize)) { + error = B_BAD_DATA; + } + } + } + } + // 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 partition + 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) { + error = errno; + if (error == B_OK) + error = B_IO_ERROR; + TRACE(("intel: _ReadPTS(): reading the PTS failed: %s\n", + strerror(error))); + } + return error; +} + + +/* +// std_ops +static +status_t +std_ops(int32 op, ...) +{ + TRACE(("intel: std_ops(0x%lx)\n", op)); + switch(op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + } + return B_ERROR; +} + +// read_partition_map +static +bool +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 +static +bool +intel_identify(int deviceFD, const session_info *sessionInfo, + const uchar *block) +{ + TRACE(("intel: identify(%d, %lld, %lld, %p, %ld)\n", deviceFD, + sessionInfo->offset, sessionInfo->size, block, + sessionInfo->logical_block_size)); + PartitionMap map; + return read_partition_map(deviceFD, sessionInfo, block, &map); +} + +// intel_get_nth_info +static +status_t +intel_get_nth_info(int deviceFD, const session_info *sessionInfo, + const uchar *block, int32 index, + extended_partition_info *partitionInfo) +{ + status_t error = B_OK; + off_t sessionOffset = sessionInfo->offset; + TRACE(("intel: get_nth_info(%d, %lld, %lld, %p, %ld, %ld)\n", deviceFD, + sessionOffset, sessionInfo->size, block, + sessionInfo->logical_block_size, index)); + PartitionMap map; + if (read_partition_map(deviceFD, sessionInfo, block, &map)) { + if (Partition *partition = map.PartitionAt(index)) { + if (partition->IsEmpty()) { + // empty partition + partitionInfo->info.offset = sessionOffset; + partitionInfo->info.size = 0; + partitionInfo->flags + = 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; + } + partitionInfo->partition_name[0] = '\0'; + partition->GetTypeString(partitionInfo->partition_type); + } else + error = B_ENTRY_NOT_FOUND; + } else // couldn't read partition map -- we shouldn't be in get_nth_info() + error = B_BAD_DATA; + return error; +} + +// intel_get_partitioning_params +static +status_t +intel_get_partitioning_params(int deviceFD, + const struct session_info *sessionInfo, + char *buffer, size_t bufferSize, + size_t *actualSize) +{ + status_t error = B_OK; + 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 +static +status_t +intel_partition(int deviceFD, const struct session_info *sessionInfo, + const char *parameters) +{ + // not yet supported + return B_UNSUPPORTED; +} +*/ + + +// intel partition map module + +// module +static status_t pm_std_ops(int32 op, ...); + +// scanning +static float pm_identify_partition(int fd, partition_data *partition, + void **cookie); +static status_t pm_scan_partition(int fd, partition_data *partition, + void *cookie); +static void pm_free_identify_partition_cookie(partition_data *partition, + void *cookie); +static void pm_free_partition_cookie(partition_data *partition); +static void pm_free_partition_content_cookie(partition_data *partition); + +static partition_module_info intel_partition_map_module = { + { + INTEL_PARTITION_MAP_MODULE_NAME, + 0, + pm_std_ops + }, + kPartitionMapPrettyName, // pretty_name + + // scanning + pm_identify_partition, // identify_partition + pm_scan_partition, // scan_partition + pm_free_identify_partition_cookie, // free_identify_partition_cookie + pm_free_partition_cookie, // free_partition_cookie + pm_free_partition_content_cookie, // free_partition_content_cookie + + // querying + NULL, // supports_reparing_partition + NULL, // supports_resizing_partition + NULL, // supports_resizing_child_partition + NULL, // supports_moving_partition + NULL, // supports_moving_child_partition + NULL, // supports_parent_system + NULL, // supports_child_system + NULL, // validate_resize_partition + NULL, // validate_move_partition + NULL, // validate_resize_child_partition + NULL, // validate_move_child_partition + NULL, // validate_create_child_partition + NULL, // validate_initialize_partition + NULL, // validate_set_partition_parameters + NULL, + // validate_set_partition_content_parameters + NULL, // get_partitionable_spaces; + + // writing + NULL, // repair_partition + NULL, // resize_partition + NULL, // resize_child_partition + NULL, // move_partition + NULL, // move_child_partition + NULL, // create_child_partition + NULL, // delete_child_partition + NULL, // initialize_partition + NULL, // set_parameters_partition + NULL, // set_partition_content_parameters +}; + + +// intel extended partition module + +// module +static status_t ep_std_ops(int32 op, ...); + +// scanning +static float ep_identify_partition(int fd, partition_data *partition, + void **cookie); +static status_t ep_scan_partition(int fd, partition_data *partition, + void *cookie); +static void ep_free_identify_partition_cookie(partition_data *partition, + void *cookie); +static void ep_free_partition_cookie(partition_data *partition); +static void ep_free_partition_content_cookie(partition_data *partition); + +static partition_module_info intel_extended_partition_module = { + { + INTEL_EXTENDED_PARTITION_MODULE_NAME, + 0, + ep_std_ops + }, + kExtendedPartitionPrettyName, // pretty_name + + // scanning + ep_identify_partition, // identify_partition + ep_scan_partition, // scan_partition + ep_free_identify_partition_cookie, // free_identify_partition_cookie + ep_free_partition_cookie, // free_partition_cookie + ep_free_partition_content_cookie, // free_partition_content_cookie + + // querying + NULL, // supports_reparing_partition + NULL, // supports_resizing_partition + NULL, // supports_resizing_child_partition + NULL, // supports_moving_partition + NULL, // supports_moving_child_partition + NULL, // supports_parent_system + NULL, // supports_child_system + NULL, // validate_resize_partition + NULL, // validate_move_partition + NULL, // validate_resize_child_partition + NULL, // validate_move_child_partition + NULL, // validate_create_child_partition + NULL, // validate_initialize_partition + NULL, // validate_set_partition_parameters + NULL, + // validate_set_partition_content_parameters + NULL, // get_partitionable_spaces; + + // writing + NULL, // repair_partition + NULL, // resize_partition + NULL, // resize_child_partition + NULL, // move_partition + NULL, // move_child_partition + NULL, // create_child_partition + NULL, // delete_child_partition + NULL, // initialize_partition + NULL, // set_parameters_partition + NULL, // set_partition_content_parameters +}; + + +extern "C" partition_module_info *modules[]; +_EXPORT partition_module_info *modules[] = +{ + &intel_partition_map_module, + &intel_extended_partition_module, + NULL +}; + + +// intel partition map module + +// pm_std_ops +static +status_t +pm_std_ops(int32 op, ...) +{ + TRACE(("intel: pm_std_ops(0x%lx)\n", op)); + switch(op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + } + return B_ERROR; +} + +// pm_identify_partition +static +float +pm_identify_partition(int fd, partition_data *partition, void **cookie) +{ + // check parameters + if (fd < 0 || !partition || !cookie) + return -1; + TRACE(("intel: pm_identify_partition(%d, %ld: %lld, %lld, %ld)\n", fd, + partition->id, partition->offset, partition->size, + partition->block_size)); + // check block size + uint32 blockSize = partition->block_size; + if (blockSize < sizeof(partition_table_sector)) { + TRACE(("intel: read_partition_map: bad block size: %ld, should be " + ">= %ld\n", blockSize, sizeof(partition_table_sector))); + return -1; + } + // allocate a PartitionMap + PartitionMap *map = new(nothrow) PartitionMap; + if (!map) + return -1; + // read the partition structure + PartitionMapParser parser(fd, 0, partition->size, blockSize); + status_t error = parser.Parse(NULL, map); + if (error == B_OK) { + *cookie = map; + return 0.5; + } + // cleanup, if not detected + delete map; + return -1; +} + +// pm_scan_partition +static +status_t +pm_scan_partition(int fd, partition_data *partition, void *cookie) +{ + AutoDeleter deleter((PartitionMap*)cookie); + // check parameters + if (fd < 0 || !partition || !cookie) + return B_ERROR; + TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd, + partition->id, partition->offset, partition->size, + partition->block_size)); + PartitionMap *map = (PartitionMap*)cookie; + // fill in the partition_data structure + // (no content_name and content_parameters) + partition->content_type = strdup(kPartitionMapPrettyName); + if (!partition->content_type) + return B_NO_MEMORY; + partition->content_cookie = map; + // children + status_t error = B_OK; + int32 index = 0; + for (int32 i = 0; i < 4; i++) { + PrimaryPartition *primary = map->PrimaryPartitionAt(i); + if (!primary->IsEmpty()) { + partition_data *child = create_child_partition(partition->id, + index, -1); + index++; + if (!child) { +TRACE(("Creating child at index %ld failed\n", index - 1)); + // something went wrong + error = B_ERROR; + break; + } + child->offset = partition->offset + primary->Offset(); + child->size = primary->Size(); + child->block_size = partition->block_size; + // (no name) + child->type = strdup(primary->IsExtended() + ? kExtendedPartitionPrettyName : kPrimaryPartitionPrettyName); + // parameters + char buffer[128]; + sprintf(buffer, "type = %u ; active = %d\n", primary->Type(), + primary->Active()); + child->parameters = strdup(buffer); + child->cookie = primary; + // check for allocation problems + if (!child->type || !child->parameters) { + error = B_NO_MEMORY; + break; + } + } + } + // keep map on success or cleanup on error + if (error == B_OK) { + deleter.SetObject(NULL); + } else { + partition->content_cookie = NULL; + for (int32 i = 0; i < partition->child_count; i++) { + if (partition_data *child = get_child_partition(partition->id, i)) + child->cookie = NULL; + } + } + return error; +} + +// pm_free_identify_partition_cookie +static +void +pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie) +{ + if (cookie) + delete (PartitionMap*)cookie; +} + +// pm_free_partition_cookie +static +void +pm_free_partition_cookie(partition_data *partition) +{ + // called for the primary partitions: the PrimaryPartition is allocated + // by the partition containing the partition map + if (partition) + partition->cookie = NULL; +} + +// pm_free_partition_content_cookie +static +void +pm_free_partition_content_cookie(partition_data *partition) +{ + if (partition && partition->content_cookie) { + delete (PartitionMap*)partition->content_cookie; + partition->content_cookie = NULL; + } +} + + +// intel extended partition module + +// ep_std_ops +static +status_t +ep_std_ops(int32 op, ...) +{ + TRACE(("intel: ep_std_ops(0x%lx)\n", op)); + switch(op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + } + return B_ERROR; +} + +// ep_identify_partition +static +float +ep_identify_partition(int fd, partition_data *partition, void **cookie) +{ + // check parameters + if (fd < 0 || !partition || !cookie || !partition->cookie) + return -1; + TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd, + partition->offset, partition->size, partition->block_size)); + // our parent must be a intel partition map partition and we must have + // extended partition type + if (!partition->type + || strcmp(partition->type, kExtendedPartitionPrettyName)) { + return -1; + } + partition_data *parent = get_parent_partition(partition->id); + if (!parent || !parent->content_type + || strcmp(parent->content_type, kPartitionMapPrettyName)) { + return -1; + } + // things seem to be in order + return 0.5; +} + +// ep_scan_partition +static +status_t +ep_scan_partition(int fd, partition_data *partition, void *cookie) +{ + // check parameters + if (fd < 0 || !partition || !cookie || !partition->cookie) + return B_ERROR; + partition_data *parent = get_parent_partition(partition->id); + if (!parent) + return B_ERROR; + PrimaryPartition *primary = (PrimaryPartition*)partition->cookie; + // fill in the partition_data structure + // (no content_name and content_parameters) + partition->content_type = strdup(kExtendedPartitionPrettyName); + if (!partition->content_type) + return B_NO_MEMORY; + partition->content_cookie = primary; + // children + status_t error = B_OK; + int32 index = 0; + for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { + LogicalPartition *logical = primary->LogicalPartitionAt(i); + partition_data *child = create_child_partition(partition->id, + index, -1); + if (!child) { + // something went wrong + error = B_ERROR; + break; + } + child->offset = parent->offset + logical->Offset(); + child->size = logical->Size(); + child->block_size = partition->block_size; + // (no name) + child->type = strdup(kLogicalPartitionPrettyName); + // parameters + char buffer[128]; + sprintf(buffer, "type = %u ; active = %d\n", primary->Type(), + primary->Active()); + child->parameters = strdup(buffer); + child->cookie = logical; + // check for allocation problems + if (!child->type || !child->parameters) { + error = B_NO_MEMORY; + break; + } + } + // cleanup on error + if (error != B_OK) { + partition->content_cookie = NULL; + for (int32 i = 0; i < partition->child_count; i++) { + if (partition_data *child = get_child_partition(partition->id, i)) + child->cookie = NULL; + } + } + return error; +} + +// ep_free_identify_partition_cookie +static +void +ep_free_identify_partition_cookie(partition_data *partition, void *cookie) +{ + // nothing to do +} + +// ep_free_partition_cookie +static +void +ep_free_partition_cookie(partition_data *partition) +{ + // the logical partition's cookie belongs to the partition map partition + if (partition) + partition->cookie = NULL; +} + +// ep_free_partition_content_cookie +static +void +ep_free_partition_content_cookie(partition_data *partition) +{ + // the extended partition's cookie belongs to the partition map partition + if (partition) + partition->content_cookie = NULL; +} +