int32 DirEntryBlock::FindInsertionIndex(const char* name, size_t nameLength, bool& _exactMatch) const { int32 entryCount = EntryCount(); if (entryCount == 0) { _exactMatch = false; return 0; } const char* entryNames = (char*)(fBlock->nameEnds + entryCount); uint32 nameOffset = 0; int32 index = 0; int cmp = -1; // TODO: Binary search! for (; index < entryCount; index++) { const char* entryName = entryNames + nameOffset; size_t entryNameLength = fBlock->nameEnds[index] - nameOffset; cmp = compare_names(entryName, entryNameLength, name, nameLength); if (cmp >= 0) break; nameOffset += entryNameLength; } _exactMatch = cmp == 0; return index; }
void DirEntryBlock::RemoveEntry(int32 index) { ASSERT(index >= 0 && index < EntryCount()); int32 entryCount = EntryCount(); if (entryCount == 1) { // simple case -- removing the last entry fBlock->entryCount = 0; return; } uint64* blockIndices = (uint64*)((uint8*)fBlock + fBlockSize) - 1; char* entryNames = (char*)(fBlock->nameEnds + entryCount); uint32 nameOffset = index == 0 ? 0 : fBlock->nameEnds[index - 1]; uint32 nameEnd = fBlock->nameEnds[index]; uint32 lastNameEnd = entryCount == 0 ? 0 : fBlock->nameEnds[entryCount - 1]; if (index < entryCount - 1) { uint32 nameLength = nameEnd - nameOffset; // remove the element from the block indices array memmove(&blockIndices[-entryCount + 2], &blockIndices[-entryCount + 1], 8 * (entryCount - index - 1)); // move and update the nameEnds entries > index for (int32 i = index + 1; i < entryCount; i++) fBlock->nameEnds[i - 1] = fBlock->nameEnds[i] - nameLength; // move the names < index by 2 bytes if (index > 0) memmove(entryNames - 2, entryNames, nameOffset); // move the names > index memmove(entryNames - 2 + nameOffset, entryNames + nameEnd, lastNameEnd - nameEnd); } else { // the nameEnds array shrinks -- move all names memmove(entryNames - 2, entryNames, nameOffset); } // we have removed the entry fBlock->entryCount--; ASSERT(Check()); }
/*! Moves all entries beyond \a splitIndex (inclusively) to the empty block \a other. */ void DirEntryBlock::SplitBlock(int32 splitIndex, DirEntryBlock& other) { ASSERT(other.EntryCount() == 0); ASSERT(splitIndex <= EntryCount()); int32 entryCount = EntryCount(); if (splitIndex == entryCount) return; int32 otherEntryCount = entryCount - splitIndex; // copy block indices uint64* blockIndices = (uint64*)((uint8*)fBlock + fBlockSize); uint64* otherBlockIndices = (uint64*)((uint8*)other.fBlock + other.fBlockSize); // note: both point after the last entry, unlike in other methods memcpy(otherBlockIndices - otherEntryCount, blockIndices - entryCount, 8 * otherEntryCount); // copy the name end offsets uint32 namesOffset = splitIndex > 0 ? fBlock->nameEnds[splitIndex - 1] : 0; for (int32 i = splitIndex; i < entryCount; i++) { other.fBlock->nameEnds[i - splitIndex] = fBlock->nameEnds[i] - namesOffset; } // copy the names char* entryNames = (char*)(fBlock->nameEnds + entryCount); char* otherEntryNames = (char*)(other.fBlock->nameEnds + otherEntryCount); memcpy(otherEntryNames, entryNames + namesOffset, fBlock->nameEnds[entryCount - 1] - namesOffset); // the name ends array shrinks -- move the names if (splitIndex > 0) { char* newEntryNames = (char*)(fBlock->nameEnds + splitIndex); memmove(newEntryNames, entryNames, namesOffset); } // update the entry counts fBlock->entryCount = splitIndex; other.fBlock->entryCount = otherEntryCount; ASSERT(Check()); ASSERT(other.Check()); }
Generator * Model :: FindGen( const std::string & name ) const { for ( unsigned int i = 0; i < EntryCount() ; i++ ) { Generator * gp = GenAt( i ); if ( gp && gp->Name() == name ) { return gp; } } return 0; }
const char* DirEntryBlock::NameAt(int32 index, size_t& _nameLength) const { int32 entryCount = EntryCount(); if (index < 0 || index >= entryCount) return NULL; uint32 nameOffset = index > 0 ? fBlock->nameEnds[index - 1] : 0; _nameLength = fBlock->nameEnds[index] - nameOffset; return (const char*)(fBlock->nameEnds + entryCount) + nameOffset; }
/*! Finds a good split index for an insertion of \a bytesNeeded bytes at index \a index. */ int32 DirEntryBlock::FindSplitIndex(int32 index, size_t bytesNeeded) const { size_t splitSize = (BytesUsed() + bytesNeeded) / 2; int32 entryCount = EntryCount(); for (int32 i = 0; i < entryCount; i++) { size_t bytesUsed = BytesUsedFor(i + 1); if (i == index) bytesUsed += bytesNeeded; if (bytesUsed > splitSize) return i; } // This should never happen. return entryCount; }
void Header::_DumpPartitions() { for (uint32 i = 0; i < EntryCount(); i++) { const efi_partition_entry &entry = EntryAt(i); if (entry.partition_type == kEmptyGUID) continue; dprintf("[%3" B_PRIu32 "] partition type: %s\n", i, _PrintGUID(entry.partition_type)); dprintf(" unique id: %s\n", _PrintGUID(entry.unique_guid)); dprintf(" start block: %" B_PRIu64 "\n", entry.StartBlock()); dprintf(" end block: %" B_PRIu64 "\n", entry.EndBlock()); dprintf(" size: %g MB\n", (entry.EndBlock() - entry.StartBlock()) * 512 / 1024.0 / 1024.0); dprintf(" attributes: %" B_PRIx64 "\n", entry.Attributes()); char name[64]; to_utf8(entry.name, EFI_PARTITION_NAME_LENGTH, name, sizeof(name)); dprintf(" name: %s\n", name); } }
bool DirEntryBlock::Check() const { int32 entryCount = EntryCount(); if (entryCount == 0) return true; // Check size: Both name ends and block index arrays must fit and we need // at least one byte per name. size_t size = sizeof(*fBlock) + entryCount * 10; if (size + entryCount > fBlockSize) { ERROR("Invalid dir entry block: entry count %d requires minimum size " "of %" B_PRIuSIZE " + %d bytes, but block size is %" B_PRIuSIZE "\n", (int)entryCount, size, (int)entryCount, fBlockSize); return false; } // check the name ends and block indices arrays and the names const char* entryNames = (char*)(fBlock->nameEnds + entryCount); const uint64* blockIndices = (uint64*)((uint8*)fBlock + fBlockSize) - 1; const char* previousName = NULL; uint16 previousNameLength = 0; uint16 previousEnd = 0; for (int32 i = 0; i < entryCount; i++) { // check name end uint16 nameEnd = fBlock->nameEnds[i]; if (nameEnd <= previousEnd || nameEnd > fBlockSize - size) { ERROR("Invalid dir entry block: name end offset of entry %" B_PRId32 ": %u, previous: %u\n", i, nameEnd, previousEnd); return false; } // check name length uint16 nameLength = nameEnd - previousEnd; if (nameLength > kCheckSumFSNameLength) { ERROR("Invalid dir entry block: name of entry %" B_PRId32 " too " "long: %u\n", i, nameLength); return false; } // verify that the name doesn't contain a null char const char* name = entryNames + previousEnd; if (strnlen(name, nameLength) != nameLength) { ERROR("Invalid dir entry block: name of entry %" B_PRId32 " contains a null char\n", i); return false; } // compare the name with the previous name if (i > 0) { int cmp = compare_names(previousName, previousNameLength, name, nameLength); if (cmp == 0) { ERROR("Invalid dir entry block: entries %" B_PRId32 "/%" B_PRId32 " have the same name: \"%.*s\"\n", i - 1, i, (int)nameLength, name); return false; } else if (cmp > 0) { ERROR("Invalid dir entry block: entries %" B_PRId32 "/%" B_PRId32 " out of order: \"%.*s\" > \"%.*s\"\n", i - 1, i, (int)previousNameLength, previousName, (int)nameLength, name); return false; } } // check the block index if (blockIndices[-i] < kCheckSumFSSuperBlockOffset / B_PAGE_SIZE) { ERROR("Invalid dir entry block: entry %" B_PRId32 " has invalid block index: %" B_PRIu64, i, blockIndices[-i]); return false; } previousName = name; previousNameLength = nameLength; previousEnd = nameEnd; } return true; }
size_t DirEntryBlock::BytesUsed() const { return BytesUsedFor(EntryCount()); }
void Model :: Generate() { for ( unsigned int i = 0; i < EntryCount(); i++ ) { EntryAt( i )->Generate( this ); EntryAt( i )->Discard(); } }