From 066d69dad4d972cd6dcacc556992f7487399cc1d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 28 Jan 2003 23:22:54 +0000 Subject: [PATCH] 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 --- .../kernel/disk_scanner/partition/intel.cpp | 731 +++--------------- .../partition/intel_parameters.cpp | 390 ++++++++++ .../disk_scanner/partition/intel_parameters.h | 110 +++ .../partition/intel_partition_map.cpp | 459 +++++++++++ .../partition/intel_partition_map.h | 168 ++++ 5 files changed, 1233 insertions(+), 625 deletions(-) create mode 100644 src/add-ons/kernel/disk_scanner/partition/intel_parameters.cpp create mode 100644 src/add-ons/kernel/disk_scanner/partition/intel_parameters.h create mode 100644 src/add-ons/kernel/disk_scanner/partition/intel_partition_map.cpp create mode 100644 src/add-ons/kernel/disk_scanner/partition/intel_partition_map.h diff --git a/src/add-ons/kernel/disk_scanner/partition/intel.cpp b/src/add-ons/kernel/disk_scanner/partition/intel.cpp index 0b277c84af..a26aaa0b85 100644 --- a/src/add-ons/kernel/disk_scanner/partition/intel.cpp +++ b/src/add-ons/kernel/disk_scanner/partition/intel.cpp @@ -4,7 +4,7 @@ //--------------------------------------------------------------------- /*! \file intel.cpp - disk_scanner partition module for "intel" style partitions + \brief disk_scanner partition module for "intel" style partitions. */ #include @@ -17,6 +17,9 @@ #include #include +#include "intel_parameters.h" +#include "intel_partition_map.h" + #define TRACE(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. 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(this)->PartitionAt(index); -} - -// cmp_partition_offset -static -int -cmp_partition_offset(const void *p1, const void *p2) -{ - const Partition *partition1 = *static_cast(p1); - const Partition *partition2 = *static_cast(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() 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 @@ -595,7 +48,7 @@ public: private: status_t _ParsePrimary(const partition_table_sector *pts); 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: int fDeviceFD; @@ -631,10 +84,17 @@ PartitionMapParser::Parse(const uint8 *block, PartitionMap *map) if (error == B_OK) { fMap = map; fMap->Unset(); - const partition_table_sector *pts - = (const partition_table_sector*)block; - error = _ParsePrimary(pts); - if (error == B_OK && !fMap->Check()) + 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; } @@ -658,7 +118,7 @@ PartitionMapParser::_ParsePrimary(const partition_table_sector *pts) PrimaryPartition *partition = fMap->PrimaryPartitionAt(i); partition->SetTo(descriptor, 0, fBlockSize); // fail, if location is bad - if (!partition->CheckLocation(fSessionSize)) { + if (!partition->CheckLocation(fSessionSize, fBlockSize)) { error = B_BAD_DATA; break; } @@ -738,8 +198,10 @@ PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset) } } // check the partition's location - if (partition && !partition->CheckLocation(fSessionSize)) + if (partition && !partition->CheckLocation(fSessionSize, + fBlockSize)) { error = B_BAD_DATA; + } } } } @@ -763,16 +225,18 @@ PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset) // _ReadPTS status_t -PartitionMapParser::_ReadPTS(off_t offset) +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, fPTS, toRead) + } else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead) != toRead) { error = errno; if (error == B_OK) @@ -798,34 +262,43 @@ std_ops(int32 op, ...) 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 static bool intel_identify(int deviceFD, const session_info *sessionInfo, const uchar *block) { - bool result = true; - int32 blockSize = sessionInfo->logical_block_size; - 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; + PartitionMap map; + return read_partition_map(deviceFD, sessionInfo, block, &map); } // intel_get_nth_info @@ -835,50 +308,38 @@ intel_get_nth_info(int deviceFD, const session_info *sessionInfo, const uchar *block, int32 index, extended_partition_info *partitionInfo) { - status_t error = B_ENTRY_NOT_FOUND; + status_t error = B_OK; 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, - sessionOffset, sessionSize, block, blockSize, index)); - if (intel_identify(deviceFD, sessionInfo, block)) { - if (index >= 0) { - // parse the partition map - PartitionMapParser parser(deviceFD, sessionOffset, sessionSize, - blockSize); - PartitionMap map; - error = parser.Parse(block, &map); - if (error == B_OK) { - if (map.CountPartitions() == 0) - error = B_BAD_DATA; + 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; } - if (error == B_OK) { - 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'; - strcpy(partitionInfo->partition_type, - partition->TypeString()); - partitionInfo->partition_code = partition->Type(); - } else - error = B_ENTRY_NOT_FOUND; - } - } - } + partitionInfo->partition_name[0] = '\0'; + strcpy(partitionInfo->partition_type, + partition->TypeString()); + partitionInfo->partition_code = 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; } @@ -890,8 +351,28 @@ intel_get_partitioning_params(int deviceFD, char *buffer, size_t bufferSize, size_t *actualSize) { - // not yet supported - return B_UNSUPPORTED; + 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 diff --git a/src/add-ons/kernel/disk_scanner/partition/intel_parameters.cpp b/src/add-ons/kernel/disk_scanner/partition/intel_parameters.cpp new file mode 100644 index 0000000000..8347126ccc --- /dev/null +++ b/src/add-ons/kernel/disk_scanner/partition/intel_parameters.cpp @@ -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 +#include +#include +#include +#include + +#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; +} +*/ diff --git a/src/add-ons/kernel/disk_scanner/partition/intel_parameters.h b/src/add-ons/kernel/disk_scanner/partition/intel_parameters.h new file mode 100644 index 0000000000..04128ecbfd --- /dev/null +++ b/src/add-ons/kernel/disk_scanner/partition/intel_parameters.h @@ -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 + +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 diff --git a/src/add-ons/kernel/disk_scanner/partition/intel_partition_map.cpp b/src/add-ons/kernel/disk_scanner/partition/intel_partition_map.cpp new file mode 100644 index 0000000000..62e85b75d7 --- /dev/null +++ b/src/add-ons/kernel/disk_scanner/partition/intel_partition_map.cpp @@ -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 +#include +#include + +#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(this)->PartitionAt(index); +} + +// cmp_partition_offset +static +int +cmp_partition_offset(const void *p1, const void *p2) +{ + const Partition *partition1 = *static_cast(p1); + const Partition *partition2 = *static_cast(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/disk_scanner/partition/intel_partition_map.h b/src/add-ons/kernel/disk_scanner/partition/intel_partition_map.h new file mode 100644 index 0000000000..34c6280eb5 --- /dev/null +++ b/src/add-ons/kernel/disk_scanner/partition/intel_partition_map.h @@ -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 + +// 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