* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "BPlusTree.h"
#include "VerifyHeader.h"
TreeDirectory::TreeDirectory(Inode* inode)
:
fInode(inode),
fInitStatus(B_OK),
fRoot(NULL),
fExtents(NULL),
fCountOfFilledExtents(0),
fSingleDirBlock(NULL),
fOffsetOfSingleDirBlock(-1),
fCurMapIndex(0),
fOffset(0),
fCurBlockNumber(0)
{
fRoot = new(std::nothrow) BlockInDataFork;
if (fRoot == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fSingleDirBlock = new(std::nothrow) char[fInode->DirBlockSize()];
if (fSingleDirBlock == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
memcpy((void*)fRoot,
DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()), sizeof(BlockInDataFork));
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
fPathForLeaves[i].blockData = NULL;
fPathForData[i].blockData = NULL;
}
}
TreeDirectory::~TreeDirectory()
{
delete fRoot;
delete[] fExtents;
delete[] fSingleDirBlock;
}
status_t
TreeDirectory::InitCheck()
{
return fInitStatus;
}
uint32
TreeDirectory::BlockLen()
{
return fInode->SizeOfLongBlock();
}
size_t
TreeDirectory::KeySize()
{
return XFS_KEY_SIZE;
}
size_t
TreeDirectory::PtrSize()
{
return XFS_PTR_SIZE;
}
size_t
TreeDirectory::MaxRecordsPossibleRoot()
{
size_t lengthOfDataFork = 0;
if (fInode->ForkOffset() != 0)
lengthOfDataFork = fInode->ForkOffset() << 3;
if (fInode->ForkOffset() == 0) {
lengthOfDataFork = fInode->GetVolume()->InodeSize()
- fInode->CoreInodeSize();
}
lengthOfDataFork -= sizeof(BlockInDataFork);
return lengthOfDataFork / (KeySize() + PtrSize());
}
size_t
TreeDirectory::GetPtrOffsetIntoRoot(int pos)
{
size_t maxRecords = MaxRecordsPossibleRoot();
return sizeof(BlockInDataFork) + maxRecords * KeySize()
+ (pos - 1) * PtrSize();
}
size_t
TreeDirectory::MaxRecordsPossibleNode()
{
size_t availableSpace = fInode->GetVolume()->BlockSize() - BlockLen();
return availableSpace / (KeySize() + PtrSize());
}
size_t
TreeDirectory::GetPtrOffsetIntoNode(int pos)
{
size_t maxRecords = MaxRecordsPossibleNode();
return BlockLen() + maxRecords * KeySize() + (pos - 1) * PtrSize();
}
TreePointer*
TreeDirectory::GetPtrFromRoot(int pos)
{
return (TreePointer*)
((char*)DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize())
+ GetPtrOffsetIntoRoot(pos));
}
TreePointer*
TreeDirectory::GetPtrFromNode(int pos, void* buffer)
{
size_t offsetIntoNode = GetPtrOffsetIntoNode(pos);
return (TreePointer*)((char*)buffer + offsetIntoNode);
}
TreeKey*
TreeDirectory::GetKeyFromNode(int pos, void* buffer)
{
return (TreeKey*)
((char*)buffer + BlockLen() + (pos - 1) * KeySize());
}
TreeKey*
TreeDirectory::GetKeyFromRoot(int pos)
{
off_t offset = (pos - 1) * KeySize();
char* base = (char*)DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize())
+ sizeof(BlockInDataFork);
return (TreeKey*) (base + offset);
}
status_t
TreeDirectory::SearchOffsetInTreeNode(uint32 offset,
TreePointer** pointer, int pathIndex)
{
*pointer = NULL;
TreeKey* offsetKey = NULL;
size_t maxRecords = MaxRecordsPossibleNode();
for (int i = maxRecords - 1; i >= 0; i--) {
offsetKey
= GetKeyFromNode(i + 1, (void*)fPathForLeaves[pathIndex].blockData);
if (B_BENDIAN_TO_HOST_INT64(*offsetKey) <= offset) {
*pointer = GetPtrFromNode(i + 1, (void*)
fPathForLeaves[pathIndex].blockData);
break;
}
}
if (offsetKey == NULL || *pointer == NULL)
return B_BAD_VALUE;
return B_OK;
}
status_t
TreeDirectory::SearchAndFillPath(uint32 offset, int type)
{
TRACE("SearchAndFillPath:\n");
PathNode* path;
if (type == DATA)
path = fPathForData;
else if (type == LEAF)
path = fPathForLeaves;
else
return B_BAD_VALUE;
TreePointer* ptrToNode = NULL;
TreeKey* offsetKey = NULL;
for (int i = fRoot->NumRecords() - 1; i >= 0; i--) {
offsetKey = GetKeyFromRoot(i + 1);
if (B_BENDIAN_TO_HOST_INT64(*offsetKey) <= offset) {
ptrToNode = GetPtrFromRoot(i + 1);
break;
}
}
if (ptrToNode == NULL || offsetKey == NULL) {
return B_BAD_VALUE;
}
int level = fRoot->Levels() - 1;
Volume* volume = fInode->GetVolume();
status_t status;
for (int i = 0; i < MAX_TREE_DEPTH && level >= 0; i++, level--) {
uint64 requiredBlock = B_BENDIAN_TO_HOST_INT64(*ptrToNode);
TRACE("requiredBlock:(%" B_PRIu64 ")\n", requiredBlock);
if (path[i].blockNumber == requiredBlock) {
if (path[i].type == 2)
break;
status = SearchOffsetInTreeNode(offset, &ptrToNode, i);
if (status != B_OK)
return status;
continue;
}
ssize_t len;
if (level == 0) {
len = fInode->DirBlockSize();
TRACE("path node type:(%" B_PRId32 ")\n", path[i].type);
if (path[i].type != 2) {
delete path[i].blockData;
path[i].type = 0;
path[i].blockData = new(std::nothrow) char[len];
if (path[i].blockData == NULL)
return B_NO_MEMORY;
path[i].type = 2;
}
uint64 readPos = fInode->FileSystemBlockToAddr(requiredBlock);
if (read_pos(volume->Device(), readPos, path[i].blockData, len)
!= len) {
ERROR("FillPath::FillBlockBuffer(): IO Error");
return B_IO_ERROR;
}
path[i].blockNumber = requiredBlock;
break;
}
len = volume->BlockSize();
if (path[i].type != 1) {
delete path[i].blockData;
path[i].type = 0;
path[i].blockData = new(std::nothrow) char[len];
if (path[i].blockData == NULL)
return B_NO_MEMORY;
path[i].type = 1;
}
uint64 readPos = fInode->FileSystemBlockToAddr(requiredBlock);
if (read_pos(volume->Device(), readPos, path[i].blockData, len)
!= len) {
ERROR("FillPath::FillBlockBuffer(): IO Error");
return B_IO_ERROR;
}
path[i].blockNumber = requiredBlock;
status = SearchOffsetInTreeNode(offset, &ptrToNode, i);
if (status != B_OK)
return status;
}
return B_OK;
}
status_t
TreeDirectory::GetAllExtents()
{
xfs_extnum_t noOfExtents = fInode->DataExtentsCount();
ExtentMapUnwrap* extentsWrapped
= new(std::nothrow) ExtentMapUnwrap[noOfExtents];
if (extentsWrapped == NULL)
return B_NO_MEMORY;
ArrayDeleter<ExtentMapUnwrap> extentsWrappedDeleter(extentsWrapped);
Volume* volume = fInode->GetVolume();
ssize_t len = volume->BlockSize();
uint16 levelsInTree = fRoot->Levels();
status_t status = fInode->GetNodefromTree(levelsInTree, volume, len,
fInode->DirBlockSize(), fSingleDirBlock);
if (status != B_OK)
return status;
uint64 fileSystemBlockNo;
while (1) {
char* leafBuffer = fSingleDirBlock;
if (!VerifyHeader<LongBlock>((LongBlock*)leafBuffer, leafBuffer, fInode,
0, NULL, XFS_BTREE)) {
TRACE("Invalid Long Block");
return B_BAD_VALUE;
}
uint32 offset = fInode->SizeOfLongBlock();
int numRecs = ((LongBlock*)leafBuffer)->NumRecs();
for (int i = 0; i < numRecs; i++) {
extentsWrapped[fCountOfFilledExtents].first =
*(uint64*)(leafBuffer + offset);
extentsWrapped[fCountOfFilledExtents].second =
*(uint64*)(leafBuffer + offset + sizeof(uint64));
offset += sizeof(ExtentMapUnwrap);
fCountOfFilledExtents++;
}
fileSystemBlockNo = ((LongBlock*)leafBuffer)->Right();
TRACE("Next leaf is at: (%" B_PRIu64 ")\n", fileSystemBlockNo);
if (fileSystemBlockNo == (uint64) -1)
break;
uint64 readPos = fInode->FileSystemBlockToAddr(fileSystemBlockNo);
if (read_pos(volume->Device(), readPos, fSingleDirBlock, len)
!= len) {
ERROR("Extent::FillBlockBuffer(): IO Error");
return B_IO_ERROR;
}
}
TRACE("Total covered: (%" B_PRIu32 ")\n", fCountOfFilledExtents);
status = UnWrapExtents(extentsWrapped);
return status;
}
status_t
TreeDirectory::FillBuffer(char* blockBuffer, int howManyBlocksFurther,
ExtentMapEntry* targetMap)
{
TRACE("FILLBUFFER\n");
ExtentMapEntry map;
if (targetMap == NULL)
map = fExtents[fCurMapIndex];
if (targetMap != NULL)
map = *targetMap;
if (map.br_state != 0)
return B_BAD_VALUE;
ssize_t len = fInode->DirBlockSize();
if (blockBuffer == NULL) {
blockBuffer = new(std::nothrow) char[len];
if (blockBuffer == NULL)
return B_NO_MEMORY;
}
xfs_daddr_t readPos = fInode->FileSystemBlockToAddr(
map.br_startblock + howManyBlocksFurther);
if (read_pos(fInode->GetVolume()->Device(), readPos, blockBuffer, len)
!= len) {
ERROR("TreeDirectory::FillBlockBuffer(): IO Error");
return B_IO_ERROR;
}
if (targetMap == NULL) {
fSingleDirBlock = blockBuffer;
ExtentDataHeader* header = ExtentDataHeader::Create(fInode, fSingleDirBlock);
if (header == NULL)
return B_NO_MEMORY;
if (!VerifyHeader<ExtentDataHeader>(header, fSingleDirBlock, fInode,
howManyBlocksFurther, &map, XFS_BTREE)) {
ERROR("Invalid Data block");
delete header;
return B_BAD_VALUE;
}
delete header;
}
if (targetMap != NULL) {
fSingleDirBlock = blockBuffer;
This could be leaf or node block perform check for both
based on magic number found.
*/
ExtentLeafHeader* leaf = ExtentLeafHeader::Create(fInode, fSingleDirBlock);
if (leaf == NULL)
return B_NO_MEMORY;
if ((leaf->Magic() == XFS_DIR2_LEAFN_MAGIC
|| leaf->Magic() == XFS_DIR3_LEAFN_MAGIC)
&& !VerifyHeader<ExtentLeafHeader>(leaf, fSingleDirBlock, fInode,
howManyBlocksFurther, &map, XFS_BTREE)) {
TRACE("Leaf block invalid");
delete leaf;
return B_BAD_VALUE;
}
delete leaf;
leaf = NULL;
NodeHeader* node = NodeHeader::Create(fInode, fSingleDirBlock);
if (node == NULL)
return B_NO_MEMORY;
if ((node->Magic() == XFS_DA_NODE_MAGIC
|| node->Magic() == XFS_DA3_NODE_MAGIC)
&& !VerifyHeader<NodeHeader>(node, fSingleDirBlock, fInode,
howManyBlocksFurther, &map, XFS_BTREE)) {
TRACE("Node block invalid");
delete node;
return B_BAD_VALUE;
}
delete node;
}
return B_OK;
}
int
TreeDirectory::EntrySize(int len) const
{
int entrySize = sizeof(xfs_ino_t) + sizeof(uint8) + len + sizeof(uint16);
if (fInode->HasFileTypeField())
entrySize += sizeof(uint8);
return ROUNDUP(entrySize, 8);
}
* Throw in the desired block number and get the index of it
*/
status_t
TreeDirectory::SearchMapInAllExtent(uint64 blockNo, uint32& mapIndex)
{
ExtentMapEntry map;
for (uint32 i = 0; i < fCountOfFilledExtents; i++) {
map = fExtents[i];
if (map.br_startoff <= blockNo
&& (blockNo <= map.br_startoff + map.br_blockcount - 1)) {
mapIndex = i;
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
status_t
TreeDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
{
TRACE("TreeDirectory::GetNext\n");
status_t status;
if (fExtents == NULL) {
status = GetAllExtents();
if (status != B_OK)
return status;
}
status = FillBuffer(fSingleDirBlock, 0);
if (status != B_OK)
return status;
Volume* volume = fInode->GetVolume();
void* entry;
entry = (void*)(fSingleDirBlock + ExtentDataHeader::Size(fInode));
uint32 blockNoFromAddress = BLOCKNO_FROM_ADDRESS(fOffset, volume);
if (fOffset != 0 && blockNoFromAddress == fCurBlockNumber) {
entry = (void*)(fSingleDirBlock
+ BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode));
}
uint32 curDirectorySize = fInode->Size();
ExtentMapEntry& map = fExtents[fCurMapIndex];
while (fOffset != curDirectorySize) {
blockNoFromAddress = BLOCKNO_FROM_ADDRESS(fOffset, volume);
TRACE("fOffset:(%" B_PRIu64 "), blockNoFromAddress:(%" B_PRIu32 ")\n",
fOffset, blockNoFromAddress);
if (fCurBlockNumber != blockNoFromAddress
&& blockNoFromAddress > map.br_startoff
&& blockNoFromAddress
<= map.br_startoff + map.br_blockcount - 1) {
status = FillBuffer(fSingleDirBlock,
blockNoFromAddress - map.br_startoff);
if (status != B_OK)
return status;
entry = (void*)(fSingleDirBlock + ExtentDataHeader::Size(fInode));
fOffset = fOffset + ExtentDataHeader::Size(fInode);
fCurBlockNumber = blockNoFromAddress;
} else if (fCurBlockNumber != blockNoFromAddress) {
uint32 curMapIndex;
status = SearchMapInAllExtent(blockNoFromAddress, curMapIndex);
if (status != B_OK)
return status;
fCurMapIndex = curMapIndex;
map = fExtents[fCurMapIndex];
status = FillBuffer(fSingleDirBlock,
blockNoFromAddress - map.br_startoff);
if (status != B_OK)
return status;
entry = (void*)(fSingleDirBlock + ExtentDataHeader::Size(fInode));
fOffset = fOffset + ExtentDataHeader::Size(fInode);
fCurBlockNumber = blockNoFromAddress;
}
ExtentUnusedEntry* unusedEntry = (ExtentUnusedEntry*)entry;
if (B_BENDIAN_TO_HOST_INT16(unusedEntry->freetag) == DIR2_FREE_TAG) {
TRACE("Unused entry found\n");
fOffset = fOffset + B_BENDIAN_TO_HOST_INT16(unusedEntry->length);
entry = (void*)
((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length));
continue;
}
ExtentDataEntry* dataEntry = (ExtentDataEntry*) entry;
uint16 currentOffset = (char*)dataEntry - fSingleDirBlock;
TRACE("GetNext: fOffset:(%" B_PRIu64 "), currentOffset:(%" B_PRIu16 ")\n",
BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode), currentOffset);
if (BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode) > currentOffset) {
entry = (void*)((char*)entry + EntrySize(dataEntry->namelen));
continue;
}
if ((size_t)(dataEntry->namelen) >= *length)
return B_BUFFER_OVERFLOW;
fOffset = fOffset + EntrySize(dataEntry->namelen);
memcpy(name, dataEntry->name, dataEntry->namelen);
name[dataEntry->namelen] = '\0';
*length = dataEntry->namelen + 1;
*ino = B_BENDIAN_TO_HOST_INT64(dataEntry->inumber);
TRACE("Entry found. Name: (%s), Length: (%" B_PRIuSIZE "), ino: (%" B_PRIu64 ")\n", name,
*length, *ino);
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
status_t
TreeDirectory::UnWrapExtents(ExtentMapUnwrap* extentsWrapped)
{
fExtents = new(std::nothrow) ExtentMapEntry[fCountOfFilledExtents];
if (fExtents == NULL)
return B_NO_MEMORY;
uint64 first, second;
for (uint32 i = 0; i < fCountOfFilledExtents; i++) {
first = B_BENDIAN_TO_HOST_INT64(extentsWrapped[i].first);
second = B_BENDIAN_TO_HOST_INT64(extentsWrapped[i].second);
fExtents[i].br_state = first >> 63;
fExtents[i].br_startoff = (first & MASK(63)) >> 9;
fExtents[i].br_startblock = ((first & MASK(9)) << 43) | (second >> 21);
fExtents[i].br_blockcount = second & MASK(21);
}
return B_OK;
}
void
TreeDirectory::FillMapEntry(int num, ExtentMapEntry** fMap,
int type, int pathIndex)
{
void* pointerToMap;
if (type == DATA) {
char* base = fPathForData[pathIndex].blockData + BlockLen();
off_t offset = num * EXTENT_SIZE;
pointerToMap = (void*)(base + offset);
} else {
char* base = fPathForLeaves[pathIndex].blockData + BlockLen();
off_t offset = num * EXTENT_SIZE;
pointerToMap = (void*)(base + offset);
}
uint64 firstHalf = *((uint64*)pointerToMap);
uint64 secondHalf = *((uint64*)pointerToMap + 1);
firstHalf = B_BENDIAN_TO_HOST_INT64(firstHalf);
secondHalf = B_BENDIAN_TO_HOST_INT64(secondHalf);
(*fMap)->br_state = firstHalf >> 63;
(*fMap)->br_startoff = (firstHalf & MASK(63)) >> 9;
(*fMap)->br_startblock = ((firstHalf & MASK(9)) << 43) | (secondHalf >> 21);
(*fMap)->br_blockcount = secondHalf & MASK(21);
TRACE("FillMapEntry: startoff:(%" B_PRIu64 "), startblock:(%" B_PRIu64 "),"
"blockcount:(%" B_PRIu64 "),state:(%" B_PRIu8 ")\n", (*fMap)->br_startoff,
(*fMap)->br_startblock,(*fMap)->br_blockcount, (*fMap)->br_state);
}
void
TreeDirectory::SearchForMapInDirectoryBlock(uint64 blockNo,
int entries, ExtentMapEntry** map, int type, int pathIndex)
{
TRACE("SearchForMapInDirectoryBlock: blockNo:(%" B_PRIu64 ")\n", blockNo);
for (int i = 0; i < entries; i++) {
FillMapEntry(i, map, type, pathIndex);
if ((*map)->br_startoff <= blockNo
&& (blockNo <= (*map)->br_startoff + (*map)->br_blockcount - 1)) {
return;
}
}
*map = NULL;
}
uint32
TreeDirectory::SearchForHashInNodeBlock(uint32 hashVal)
{
NodeHeader* header = NodeHeader::Create(fInode, fSingleDirBlock);
if (header == NULL)
return B_NO_MEMORY;
NodeEntry* entry = (NodeEntry*)(fSingleDirBlock + NodeHeader::Size(fInode));
int count = header->Count();
delete header;
for (int i = 0; i < count; i++) {
if (hashVal <= B_BENDIAN_TO_HOST_INT32(entry[i].hashval))
return B_BENDIAN_TO_HOST_INT32(entry[i].before);
}
return 0;
}
status_t
TreeDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
{
TRACE("TreeDirectory: Lookup\n");
TRACE("Name: %s\n", name);
uint32 hashValueOfRequest = hashfunction(name, length);
TRACE("Hashval:(%" B_PRIu32 ")\n", hashValueOfRequest);
Volume* volume = fInode->GetVolume();
status_t status;
ExtentMapEntry* targetMap = new(std::nothrow) ExtentMapEntry;
if (targetMap == NULL)
return B_NO_MEMORY;
int pathIndex = -1;
uint32 rightOffset = LEAF_STARTOFFSET(volume->BlockLog());
while (rightOffset != fOffsetOfSingleDirBlock && 1) {
status = SearchAndFillPath(rightOffset, LEAF);
if (status != B_OK)
return status;
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
if (fPathForLeaves[i].type == 2) {
pathIndex = i;
break;
}
}
if (pathIndex == -1) {
return B_BAD_VALUE;
}
LongBlock* curDirBlock
= (LongBlock*)fPathForLeaves[pathIndex].blockData;
if (!VerifyHeader<LongBlock>(curDirBlock, fPathForLeaves[pathIndex].blockData, fInode,
0, NULL, XFS_BTREE)) {
TRACE("Invalid Long Block");
return B_BAD_VALUE;
}
SearchForMapInDirectoryBlock(rightOffset, curDirBlock->NumRecs(),
&targetMap, LEAF, pathIndex);
if (targetMap == NULL)
return B_BAD_VALUE;
FillBuffer(fSingleDirBlock, rightOffset - targetMap->br_startoff,
targetMap);
fOffsetOfSingleDirBlock = rightOffset;
ExtentLeafHeader* dirBlock = ExtentLeafHeader::Create(fInode, fSingleDirBlock);
if (dirBlock == NULL)
return B_NO_MEMORY;
if (dirBlock->Magic() == XFS_DIR2_LEAFN_MAGIC
|| dirBlock->Magic() == XFS_DIR3_LEAFN_MAGIC) {
delete dirBlock;
break;
}
if (dirBlock->Magic() == XFS_DA_NODE_MAGIC
|| dirBlock->Magic() == XFS_DA3_NODE_MAGIC) {
rightOffset = SearchForHashInNodeBlock(hashValueOfRequest);
if (rightOffset == 0)
return B_ENTRY_NOT_FOUND;
delete dirBlock;
continue;
}
}
while (1) {
ExtentLeafHeader* leafHeader
= ExtentLeafHeader::Create(fInode, fSingleDirBlock);
if (leafHeader == NULL)
return B_NO_MEMORY;
ExtentLeafEntry* leafEntry
= (ExtentLeafEntry*)(fSingleDirBlock + ExtentLeafHeader::Size(fInode));
int numberOfLeafEntries = leafHeader->Count();
TRACE("numberOfLeafEntries:(%" B_PRId32 ")\n", numberOfLeafEntries);
int left = 0;
int right = numberOfLeafEntries - 1;
hashLowerBound<ExtentLeafEntry>(leafEntry, left, right, hashValueOfRequest);
uint32 nextLeaf = leafHeader->Forw();
uint32 lastHashVal = B_BENDIAN_TO_HOST_INT32(
leafEntry[numberOfLeafEntries - 1].hashval);
while (B_BENDIAN_TO_HOST_INT32(leafEntry[left].hashval)
== hashValueOfRequest) {
uint32 address = B_BENDIAN_TO_HOST_INT32(leafEntry[left].address);
if (address == 0) {
left++;
continue;
}
uint32 dataBlockNumber = BLOCKNO_FROM_ADDRESS(address * 8, volume);
uint32 offset = BLOCKOFFSET_FROM_ADDRESS(address * 8, fInode);
TRACE("BlockNumber:(%" B_PRIu32 "), offset:(%" B_PRIu32 ")\n", dataBlockNumber, offset);
status = SearchAndFillPath(dataBlockNumber, DATA);
int pathIndex = -1;
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
if (fPathForData[i].type == 2) {
pathIndex = i;
break;
}
}
if (pathIndex == -1)
return B_BAD_VALUE;
LongBlock* curDirBlock
= (LongBlock*)fPathForData[pathIndex].blockData;
SearchForMapInDirectoryBlock(dataBlockNumber,
curDirBlock->NumRecs(), &targetMap, DATA, pathIndex);
if (targetMap == NULL)
return B_BAD_VALUE;
FillBuffer(fSingleDirBlock,
dataBlockNumber - targetMap->br_startoff, targetMap);
fOffsetOfSingleDirBlock = dataBlockNumber;
TRACE("offset:(%" B_PRIu32 ")\n", offset);
ExtentDataEntry* entry
= (ExtentDataEntry*)(fSingleDirBlock + offset);
int retVal = strncmp(name, (char*)entry->name, entry->namelen);
if (retVal == 0) {
*ino = B_BENDIAN_TO_HOST_INT64(entry->inumber);
TRACE("ino:(%" B_PRIu64 ")\n", *ino);
return B_OK;
}
left++;
}
if (lastHashVal == hashValueOfRequest && nextLeaf != (uint32) -1) {
status = SearchAndFillPath(nextLeaf, LEAF);
if (status != B_OK)
return status;
pathIndex = -1;
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
if (fPathForLeaves[i].type == 2) {
pathIndex = i;
break;
}
}
if (pathIndex == -1)
return B_BAD_VALUE;
LongBlock* curDirBlock
= (LongBlock*)fPathForLeaves[pathIndex].blockData;
SearchForMapInDirectoryBlock(nextLeaf, curDirBlock->NumRecs(),
&targetMap, LEAF, pathIndex);
if (targetMap == NULL)
return B_BAD_VALUE;
FillBuffer(fSingleDirBlock,
nextLeaf - targetMap->br_startoff, targetMap);
fOffsetOfSingleDirBlock = nextLeaf;
continue;
} else {
break;
}
delete leafHeader;
}
return B_ENTRY_NOT_FOUND;
}
uint32
LongBlock::ExpectedMagic(int8 WhichDirectory, Inode* inode)
{
if(inode->Version() == 3)
return XFS_BMAP_CRC_MAGIC;
else
return XFS_BMAP_MAGIC;
}
uint32
LongBlock::CRCOffset()
{
return offsetof(LongBlock, bb_crc);
}