xfs: B+Tree GetNext() works
The GetNext() works well for B+Trees and that wraps up the work needed for all kinds of GetNext(). Change-Id: Ie965d3da273364f8fdbdb8faee5cb3c214881130 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3124 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
parent
7766b5a136
commit
1dcb6c252c
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "BPlusTree.h"
|
#include "BPlusTree.h"
|
||||||
|
|
||||||
|
|
||||||
TreeDirectory::TreeDirectory(Inode* inode)
|
TreeDirectory::TreeDirectory(Inode* inode)
|
||||||
:
|
:
|
||||||
fInode(inode),
|
fInode(inode),
|
||||||
@ -14,7 +13,11 @@ TreeDirectory::TreeDirectory(Inode* inode)
|
|||||||
fRoot(NULL),
|
fRoot(NULL),
|
||||||
fExtents(NULL),
|
fExtents(NULL),
|
||||||
fSingleDirBlock(NULL),
|
fSingleDirBlock(NULL),
|
||||||
fCountOfFilledExtents(0)
|
fOffsetOfSingleDirBlock(-1),
|
||||||
|
fCountOfFilledExtents(0),
|
||||||
|
fCurMapIndex(0),
|
||||||
|
fOffset(0),
|
||||||
|
fCurBlockNumber(0)
|
||||||
{
|
{
|
||||||
fRoot = new(std::nothrow) BlockInDataFork;
|
fRoot = new(std::nothrow) BlockInDataFork;
|
||||||
if (fRoot == NULL) {
|
if (fRoot == NULL) {
|
||||||
@ -30,6 +33,12 @@ TreeDirectory::TreeDirectory(Inode* inode)
|
|||||||
|
|
||||||
memcpy((void*)fRoot,
|
memcpy((void*)fRoot,
|
||||||
DIR_DFORK_PTR(fInode->Buffer()), sizeof(BlockInDataFork));
|
DIR_DFORK_PTR(fInode->Buffer()), sizeof(BlockInDataFork));
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
|
||||||
|
fPathForLeaves[i].blockData = NULL;
|
||||||
|
fPathForData[i].blockData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -55,13 +64,6 @@ TreeDirectory::BlockLen()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TreeKey
|
|
||||||
TreeDirectory::GetKey(int pos)
|
|
||||||
{
|
|
||||||
return BlockLen() + (pos - 1) * XFS_KEY_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
TreeDirectory::KeySize()
|
TreeDirectory::KeySize()
|
||||||
{
|
{
|
||||||
@ -76,22 +78,198 @@ TreeDirectory::PtrSize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TreePointer*
|
size_t
|
||||||
TreeDirectory::GetPtr(int pos, LongBlock* curLongBlock)
|
TreeDirectory::MaxRecordsPossibleRoot()
|
||||||
{
|
{
|
||||||
size_t availableSpace = fInode->GetVolume()->BlockSize() - BlockLen();
|
size_t lengthOfDataFork;
|
||||||
size_t maxRecords = availableSpace / (KeySize() + PtrSize());
|
if (fInode->ForkOffset() != 0)
|
||||||
size_t offsetIntoNode =
|
lengthOfDataFork = fInode->ForkOffset() << 3;
|
||||||
BlockLen() + maxRecords * KeySize() + (pos - 1) * PtrSize();
|
if (fInode->ForkOffset() == 0) {
|
||||||
return (TreePointer*)((char*)curLongBlock + offsetIntoNode);
|
lengthOfDataFork = fInode->GetVolume()->InodeSize()
|
||||||
|
- INODE_CORE_UNLINKED_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lengthOfDataFork -= sizeof(BlockInDataFork);
|
||||||
|
return lengthOfDataFork / (KeySize() + PtrSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
TreeDirectory::MaxRecordsPossible(size_t len)
|
TreeDirectory::GetPtrOffsetIntoRoot(int pos)
|
||||||
{
|
{
|
||||||
len -= sizeof(BlockInDataFork);
|
size_t maxRecords = MaxRecordsPossibleRoot();
|
||||||
return len / (KeySize() + PtrSize());
|
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()) + 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())
|
||||||
|
+ sizeof(BlockInDataFork);
|
||||||
|
return (TreeKey*) (base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TreeDirectory::SearchOffsetInTreeNode(uint32 offset,
|
||||||
|
TreePointer** pointer, int pathIndex)
|
||||||
|
{
|
||||||
|
// This is O(MaxRecords). Next is to implement this using upper bound
|
||||||
|
// binary search and get O(log(MaxRecords))
|
||||||
|
*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;
|
||||||
|
// Go down the root of the tree first
|
||||||
|
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) {
|
||||||
|
//Corrupt tree
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now have gone down the root and save path if not saved.
|
||||||
|
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:(%d)\n", requiredBlock);
|
||||||
|
if (path[i].blockNumber == requiredBlock) {
|
||||||
|
// This block already has what we need
|
||||||
|
if (path[i].type == 2)
|
||||||
|
break;
|
||||||
|
status = SearchOffsetInTreeNode(offset, &ptrToNode, i);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We do not have the block we need
|
||||||
|
size_t len;
|
||||||
|
if (level == 0) {
|
||||||
|
// The size of buffer should be the directory block size
|
||||||
|
len = fInode->DirBlockSize();
|
||||||
|
TRACE("path node type:(%d)\n", path[i].type);
|
||||||
|
if (path[i].type != 2) {
|
||||||
|
// Size is not directory block size.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// The size of buffer should be the block size
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,26 +277,20 @@ status_t
|
|||||||
TreeDirectory::GetAllExtents()
|
TreeDirectory::GetAllExtents()
|
||||||
{
|
{
|
||||||
xfs_extnum_t noOfExtents = fInode->DataExtentsCount();
|
xfs_extnum_t noOfExtents = fInode->DataExtentsCount();
|
||||||
|
|
||||||
ExtentMapUnwrap* extentsWrapped
|
ExtentMapUnwrap* extentsWrapped
|
||||||
= new(std::nothrow) ExtentMapUnwrap[noOfExtents];
|
= new(std::nothrow) ExtentMapUnwrap[noOfExtents];
|
||||||
if (extentsWrapped == NULL)
|
if (extentsWrapped == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
ArrayDeleter<ExtentMapUnwrap> extentsWrappedDeleter(extentsWrapped);
|
||||||
|
|
||||||
Volume* volume = fInode->GetVolume();
|
Volume* volume = fInode->GetVolume();
|
||||||
uint16 levelsInTree = fRoot->Levels();
|
uint16 levelsInTree = fRoot->Levels();
|
||||||
|
|
||||||
size_t lengthOfDataFork;
|
size_t maxRecords = MaxRecordsPossibleRoot();
|
||||||
if (fInode->ForkOffset() != 0)
|
|
||||||
lengthOfDataFork = fInode->ForkOffset() << 3;
|
|
||||||
else
|
|
||||||
lengthOfDataFork = volume->InodeSize() - INODE_CORE_UNLINKED_SIZE;
|
|
||||||
|
|
||||||
TRACE("Length Of Data Fork: (%d)\n", lengthOfDataFork);
|
|
||||||
size_t maxRecords = MaxRecordsPossible(lengthOfDataFork);
|
|
||||||
TRACE("Maxrecords: (%d)\n", maxRecords);
|
TRACE("Maxrecords: (%d)\n", maxRecords);
|
||||||
TreePointer* ptrToNode = (TreePointer*)
|
TreePointer* ptrToNode = GetPtrFromRoot(1);
|
||||||
((char*)DIR_DFORK_PTR(fInode->Buffer())
|
|
||||||
+ sizeof(BlockInDataFork) + maxRecords*KeySize());
|
|
||||||
|
|
||||||
size_t len = volume->BlockSize();
|
size_t len = volume->BlockSize();
|
||||||
char node[len];
|
char node[len];
|
||||||
@ -136,14 +308,11 @@ TreeDirectory::GetAllExtents()
|
|||||||
readPos = fInode->FileSystemBlockToAddr(fileSystemBlockNo);
|
readPos = fInode->FileSystemBlockToAddr(fileSystemBlockNo);
|
||||||
if (read_pos(volume->Device(), readPos, node, len) != len) {
|
if (read_pos(volume->Device(), readPos, node, len) != len) {
|
||||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
ERROR("Extent::FillBlockBuffer(): IO Error");
|
||||||
|
|
||||||
delete[] extentsWrapped;
|
|
||||||
extentsWrapped = NULL;
|
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
LongBlock* curLongBlock = (LongBlock*)node;
|
LongBlock* curLongBlock = (LongBlock*)node;
|
||||||
ASSERT(curLongBlock->Magic() == XFS_BMAP_MAGIC);
|
ASSERT(curLongBlock->Magic() == XFS_BMAP_MAGIC);
|
||||||
ptrToNode = GetPtr(1, curLongBlock);
|
ptrToNode = GetPtrFromNode(1, (void*)curLongBlock);
|
||||||
// Get's the first pointer. This points to next node.
|
// Get's the first pointer. This points to next node.
|
||||||
levelsInTree--;
|
levelsInTree--;
|
||||||
}
|
}
|
||||||
@ -153,9 +322,6 @@ TreeDirectory::GetAllExtents()
|
|||||||
if (read_pos(volume->Device(), readPos, fSingleDirBlock, len)
|
if (read_pos(volume->Device(), readPos, fSingleDirBlock, len)
|
||||||
!= len) {
|
!= len) {
|
||||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
ERROR("Extent::FillBlockBuffer(): IO Error");
|
||||||
|
|
||||||
delete[] extentsWrapped;
|
|
||||||
extentsWrapped = NULL;
|
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
levelsInTree--;
|
levelsInTree--;
|
||||||
@ -187,9 +353,6 @@ TreeDirectory::GetAllExtents()
|
|||||||
if (read_pos(volume->Device(), readPos, fSingleDirBlock, len)
|
if (read_pos(volume->Device(), readPos, fSingleDirBlock, len)
|
||||||
!= len) {
|
!= len) {
|
||||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
ERROR("Extent::FillBlockBuffer(): IO Error");
|
||||||
|
|
||||||
delete[] extentsWrapped;
|
|
||||||
extentsWrapped = NULL;
|
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,13 +360,200 @@ TreeDirectory::GetAllExtents()
|
|||||||
|
|
||||||
status_t status = UnWrapExtents(extentsWrapped);
|
status_t status = UnWrapExtents(extentsWrapped);
|
||||||
|
|
||||||
delete[] extentsWrapped;
|
|
||||||
extentsWrapped = NULL;
|
|
||||||
|
|
||||||
return status;
|
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;
|
||||||
|
|
||||||
|
size_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*) fSingleDirBlock;
|
||||||
|
if (B_BENDIAN_TO_HOST_INT32(header->magic) == DATA_HEADER_MAGIC) {
|
||||||
|
TRACE("DATA BLOCK VALID\n");
|
||||||
|
} else {
|
||||||
|
TRACE("DATA BLOCK INVALID\n");
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetMap != NULL) {
|
||||||
|
fSingleDirBlock = blockBuffer;
|
||||||
|
ExtentLeafHeader* header = (ExtentLeafHeader*) fSingleDirBlock;
|
||||||
|
if (B_BENDIAN_TO_HOST_INT16(header->info.magic) == XFS_DA_NODE_MAGIC
|
||||||
|
|| B_BENDIAN_TO_HOST_INT16(header->info.magic)
|
||||||
|
== XFS_DIR2_LEAFN_MAGIC) {
|
||||||
|
TRACE("LEAF/NODE VALID\n");
|
||||||
|
} else {
|
||||||
|
TRACE("LEAF/NODE INVALID\n");
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
TreeDirectory::EntrySize(int len) const
|
||||||
|
{
|
||||||
|
int entrySize = sizeof(xfs_ino_t) + sizeof(uint8) + len + sizeof(uint16);
|
||||||
|
// uint16 is for the tag
|
||||||
|
if (fInode->HasFileTypeField())
|
||||||
|
entrySize += sizeof(uint8);
|
||||||
|
|
||||||
|
return ROUNDUP(entrySize, 8);
|
||||||
|
// rounding off to next greatest multiple of 8
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Throw in the desired block number and get the index of it
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
TreeDirectory::SearchMapInAllExtent(int 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)) {
|
||||||
|
// Map found
|
||||||
|
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 = (void*)((ExtentDataHeader*)fSingleDirBlock + 1);
|
||||||
|
// This could be an unused entry so we should check
|
||||||
|
|
||||||
|
uint32 blockNoFromAddress = BLOCKNO_FROM_ADDRESS(fOffset, volume);
|
||||||
|
if (fOffset != 0 && blockNoFromAddress == fCurBlockNumber) {
|
||||||
|
entry = (void*)(fSingleDirBlock
|
||||||
|
+ BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode));
|
||||||
|
// This gets us a little faster to the next entry
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 curDirectorySize = fInode->Size();
|
||||||
|
ExtentMapEntry& map = fExtents[fCurMapIndex];
|
||||||
|
while (fOffset != curDirectorySize) {
|
||||||
|
blockNoFromAddress = BLOCKNO_FROM_ADDRESS(fOffset, volume);
|
||||||
|
|
||||||
|
TRACE("fOffset:(%d), blockNoFromAddress:(%d)\n",
|
||||||
|
fOffset, blockNoFromAddress);
|
||||||
|
if (fCurBlockNumber != blockNoFromAddress
|
||||||
|
&& blockNoFromAddress > map.br_startoff
|
||||||
|
&& blockNoFromAddress
|
||||||
|
<= map.br_startoff + map.br_blockcount - 1) {
|
||||||
|
// When the block is mapped in the same data
|
||||||
|
// map entry but is not the first block
|
||||||
|
status = FillBuffer(fSingleDirBlock,
|
||||||
|
blockNoFromAddress - map.br_startoff);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
entry = (void*)((ExtentDataHeader*)fSingleDirBlock + 1);
|
||||||
|
fOffset = fOffset + sizeof(ExtentDataHeader);
|
||||||
|
fCurBlockNumber = blockNoFromAddress;
|
||||||
|
} else if (fCurBlockNumber != blockNoFromAddress) {
|
||||||
|
// When the block isn't mapped in the current data map entry
|
||||||
|
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*)((ExtentDataHeader*)fSingleDirBlock + 1);
|
||||||
|
fOffset = fOffset + sizeof(ExtentDataHeader);
|
||||||
|
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:(%d), currentOffset:(%d)\n",
|
||||||
|
BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode), currentOffset);
|
||||||
|
|
||||||
|
if (BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode) > currentOffset) {
|
||||||
|
entry = (void*)((char*)entry + EntrySize(dataEntry->namelen));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataEntry->namelen + 1 > *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: (%ld), ino: (%ld)\n", name,
|
||||||
|
*length, *ino);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TreeDirectory::UnWrapExtents(ExtentMapUnwrap* extentsWrapped)
|
TreeDirectory::UnWrapExtents(ExtentMapUnwrap* extentsWrapped)
|
||||||
{
|
{
|
||||||
@ -223,3 +573,253 @@ TreeDirectory::UnWrapExtents(ExtentMapUnwrap* extentsWrapped)
|
|||||||
|
|
||||||
return B_OK;
|
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);
|
||||||
|
//dividing the 128 bits into 2 parts.
|
||||||
|
|
||||||
|
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:(%ld), startblock:(%ld), blockcount:(%ld),"
|
||||||
|
"state:(%d)\n", (*fMap)->br_startoff, (*fMap)->br_startblock,
|
||||||
|
(*fMap)->br_blockcount, (*fMap)->br_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TreeDirectory::SearchForMapInDirectoryBlock(int blockNo,
|
||||||
|
int entries, ExtentMapEntry** map, int type, int pathIndex)
|
||||||
|
{
|
||||||
|
TRACE("SearchForMapInDirectoryBlock: blockNo:(%d)\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)) {
|
||||||
|
// Map found
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Map wasn't found. Some kind of corruption. This is checked by caller.
|
||||||
|
*map = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
TreeDirectory::SearchForHashInNodeBlock(uint32 hashVal)
|
||||||
|
{
|
||||||
|
NodeHeader* header = (NodeHeader*)(fSingleDirBlock);
|
||||||
|
NodeEntry* entry = (NodeEntry*)(fSingleDirBlock + sizeof(NodeHeader));
|
||||||
|
int count = B_BENDIAN_TO_HOST_INT16(header->count);
|
||||||
|
|
||||||
|
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:(%ld)\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());
|
||||||
|
|
||||||
|
// In node directories, the "node blocks" had a single level
|
||||||
|
// Here we could have multiple levels. With each iteration of
|
||||||
|
// the loop we go a level lower.
|
||||||
|
while (rightOffset != fOffsetOfSingleDirBlock && 1) {
|
||||||
|
status = SearchAndFillPath(rightOffset, LEAF);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// The path should now have the Tree Leaf at appropriate level
|
||||||
|
// Find the directory block in the path
|
||||||
|
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
|
||||||
|
if (fPathForLeaves[i].type == 2) {
|
||||||
|
pathIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pathIndex == -1) {
|
||||||
|
// corrupt tree
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the node block from directory block
|
||||||
|
// If level is non-zero, reiterate with new "rightOffset"
|
||||||
|
// Else, we are at leaf block, then break
|
||||||
|
LongBlock* curDirBlock
|
||||||
|
= (LongBlock*)fPathForLeaves[pathIndex].blockData;
|
||||||
|
|
||||||
|
if (curDirBlock->Magic() != XFS_BMAP_MAGIC)
|
||||||
|
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*)fSingleDirBlock;
|
||||||
|
if (B_BENDIAN_TO_HOST_INT16(dirBlock->info.magic)
|
||||||
|
== XFS_DIR2_LEAFN_MAGIC) {
|
||||||
|
// Got the potential leaf. Break.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (B_BENDIAN_TO_HOST_INT16(dirBlock->info.magic)
|
||||||
|
== XFS_DA_NODE_MAGIC) {
|
||||||
|
rightOffset = SearchForHashInNodeBlock(hashValueOfRequest);
|
||||||
|
if (rightOffset == 0)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We now have the leaf block that might contain the entry we need.
|
||||||
|
// Else go to the right subling if it might contain it. Else break.
|
||||||
|
while (1) {
|
||||||
|
ExtentLeafHeader* leafHeader
|
||||||
|
= (ExtentLeafHeader*)fSingleDirBlock;
|
||||||
|
ExtentLeafEntry* leafEntry
|
||||||
|
= (ExtentLeafEntry*)(fSingleDirBlock + sizeof(ExtentLeafHeader));
|
||||||
|
|
||||||
|
int numberOfLeafEntries = B_BENDIAN_TO_HOST_INT16(leafHeader->count);
|
||||||
|
TRACE("numberOfLeafEntries:(%d)\n", numberOfLeafEntries);
|
||||||
|
int left = 0;
|
||||||
|
int mid;
|
||||||
|
int right = numberOfLeafEntries - 1;
|
||||||
|
|
||||||
|
// Trying to find the lowerbound of hashValueOfRequest
|
||||||
|
// This is slightly different from bsearch(), as we want the first
|
||||||
|
// instance of hashValueOfRequest and not any instance.
|
||||||
|
while (left < right) {
|
||||||
|
mid = (left + right) / 2;
|
||||||
|
uint32 hashval = B_BENDIAN_TO_HOST_INT32(leafEntry[mid].hashval);
|
||||||
|
if (hashval >= hashValueOfRequest) {
|
||||||
|
right = mid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hashval < hashValueOfRequest) {
|
||||||
|
left = mid + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE("left:(%d), right:(%d)\n", left, right);
|
||||||
|
uint32 nextLeaf = B_BENDIAN_TO_HOST_INT32(leafHeader->info.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:(%d), offset:(%d)\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:(%d)\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:(%d)\n", *ino);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
if (lastHashVal == hashValueOfRequest && nextLeaf != -1) {
|
||||||
|
// Go to forward neighbor. We might find an entry there.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define XFS_KEY_SIZE sizeof(xfs_fileoff_t)
|
#define XFS_KEY_SIZE sizeof(xfs_fileoff_t)
|
||||||
#define XFS_PTR_SIZE sizeof(xfs_fsblock_t)
|
#define XFS_PTR_SIZE sizeof(xfs_fsblock_t)
|
||||||
#define XFS_BMAP_MAGIC 0x424d4150
|
#define XFS_BMAP_MAGIC 0x424d4150
|
||||||
|
#define MAX_TREE_DEPTH 5
|
||||||
|
|
||||||
|
|
||||||
typedef xfs_fileoff_t TreeKey;
|
typedef xfs_fileoff_t TreeKey;
|
||||||
@ -61,7 +62,7 @@ struct LongBlock {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//xfs_bmdr_block
|
// xfs_bmdr_block
|
||||||
struct BlockInDataFork {
|
struct BlockInDataFork {
|
||||||
uint16 Levels()
|
uint16 Levels()
|
||||||
{ return
|
{ return
|
||||||
@ -80,6 +81,22 @@ struct ExtentMapUnwrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using the structure to prevent re-reading of already read blocks during
|
||||||
|
* a traversal of tree.
|
||||||
|
*
|
||||||
|
* type:
|
||||||
|
* 0, if its an unused node, 1 if blockData size is a single block,
|
||||||
|
* 2 if blockData size is directory block size.
|
||||||
|
*/
|
||||||
|
struct PathNode {
|
||||||
|
int type;
|
||||||
|
char* blockData;
|
||||||
|
uint32 blockNumber;
|
||||||
|
// This is the file system block number
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class should handle B+Tree based directories
|
* This class should handle B+Tree based directories
|
||||||
*/
|
*/
|
||||||
@ -96,13 +113,29 @@ public:
|
|||||||
int BlockLen();
|
int BlockLen();
|
||||||
size_t PtrSize();
|
size_t PtrSize();
|
||||||
size_t KeySize();
|
size_t KeySize();
|
||||||
TreeKey GetKey(int pos);
|
TreeKey* GetKeyFromNode(int pos, void* buffer);
|
||||||
// get the pos'th key
|
TreePointer* GetPtrFromNode(int pos, void* buffer);
|
||||||
TreePointer* GetPtr(int pos, LongBlock* pointer);
|
TreeKey* GetKeyFromRoot(int pos);
|
||||||
// get the pos'th pointer
|
TreePointer* GetPtrFromRoot(int pos);
|
||||||
|
status_t SearchMapInAllExtent(int blockNo,
|
||||||
|
uint32& mapIndex);
|
||||||
status_t GetAllExtents();
|
status_t GetAllExtents();
|
||||||
size_t MaxRecordsPossible(size_t len);
|
size_t MaxRecordsPossibleRoot();
|
||||||
|
size_t MaxRecordsPossibleNode();
|
||||||
|
void FillMapEntry(int num, ExtentMapEntry** map,
|
||||||
|
int type, int pathIndex);
|
||||||
|
status_t FillBuffer(char* blockBuffer,
|
||||||
|
int howManyBlocksFurther,
|
||||||
|
ExtentMapEntry* targetMap = NULL);
|
||||||
|
size_t GetPtrOffsetIntoNode(int pos);
|
||||||
|
size_t GetPtrOffsetIntoRoot(int pos);
|
||||||
|
status_t SearchAndFillPath(uint32 offset, int type);
|
||||||
|
status_t SearchOffsetInTreeNode (uint32 offset,
|
||||||
|
TreePointer** pointer, int pathIndex);
|
||||||
|
void SearchForMapInDirectoryBlock (int blockNo,
|
||||||
|
int entries, ExtentMapEntry** map,
|
||||||
|
int type, int pathIndex);
|
||||||
|
uint32 SearchForHashInNodeBlock(uint32 hashVal);
|
||||||
private:
|
private:
|
||||||
inline status_t UnWrapExtents(ExtentMapUnwrap* extentsWrapped);
|
inline status_t UnWrapExtents(ExtentMapUnwrap* extentsWrapped);
|
||||||
|
|
||||||
@ -113,6 +146,12 @@ private:
|
|||||||
ExtentMapEntry* fExtents;
|
ExtentMapEntry* fExtents;
|
||||||
uint32 fCountOfFilledExtents;
|
uint32 fCountOfFilledExtents;
|
||||||
char* fSingleDirBlock;
|
char* fSingleDirBlock;
|
||||||
|
uint32 fOffsetOfSingleDirBlock;
|
||||||
|
uint32 fCurMapIndex;
|
||||||
|
uint64 fOffset;
|
||||||
|
uint32 fCurBlockNumber;
|
||||||
|
PathNode fPathForLeaves[MAX_TREE_DEPTH];
|
||||||
|
PathNode fPathForData[MAX_TREE_DEPTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,13 +34,14 @@ DirectoryIterator::Init()
|
|||||||
{
|
{
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_LOCAL)
|
if (fInode->Format() == XFS_DINODE_FMT_LOCAL)
|
||||||
{
|
{
|
||||||
|
TRACE("Iterator:Init: LOCAL");
|
||||||
fShortDir = new(std::nothrow) ShortDirectory(fInode);
|
fShortDir = new(std::nothrow) ShortDirectory(fInode);
|
||||||
if (fShortDir == NULL)
|
if (fShortDir == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
|
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
|
||||||
// TODO: Only working with Block directories, not leaf.
|
TRACE("Iterator:Init: EXTENTS");
|
||||||
fExtentDir = new(std::nothrow) Extent(fInode);
|
fExtentDir = new(std::nothrow) Extent(fInode);
|
||||||
if (fExtentDir == NULL)
|
if (fExtentDir == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@ -76,10 +77,8 @@ DirectoryIterator::Init()
|
|||||||
/* Return B_OK so even if the shortform directory has an extent directory
|
/* Return B_OK so even if the shortform directory has an extent directory
|
||||||
* we can atleast still list the shortform directory
|
* we can atleast still list the shortform directory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//TODO: Reading from B+Trees based directories
|
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
|
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
|
||||||
TRACE("Iterator:GetNext: B+TREE");
|
TRACE("Iterator:Init(): B+TREE");
|
||||||
fTreeDir = new(std::nothrow) TreeDirectory(fInode);
|
fTreeDir = new(std::nothrow) TreeDirectory(fInode);
|
||||||
if (fTreeDir == NULL)
|
if (fTreeDir == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@ -95,11 +94,11 @@ DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
|||||||
{
|
{
|
||||||
status_t status;
|
status_t status;
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
|
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
|
||||||
|
TRACE("Iterator:GetNext: LOCAL");
|
||||||
status = fShortDir->GetNext(name, length, ino);
|
status = fShortDir->GetNext(name, length, ino);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Reading from extent based directories
|
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
|
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
|
||||||
TRACE("Iterator:GetNext: EXTENTS");
|
TRACE("Iterator:GetNext: EXTENTS");
|
||||||
if (fExtentDir != NULL)
|
if (fExtentDir != NULL)
|
||||||
@ -111,9 +110,10 @@ DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Reading from B+Trees based directories
|
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
|
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
|
||||||
TRACE("Iterator:GetNext: B+TREE");
|
TRACE("Iterator:GetNext: B+TREE");
|
||||||
|
if (fTreeDir != NULL)
|
||||||
|
return status = fTreeDir->GetNext(name, length, ino);
|
||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,13 +127,14 @@ DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
|
|||||||
{
|
{
|
||||||
status_t status;
|
status_t status;
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
|
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
|
||||||
|
TRACE("Iterator:Lookup: LOCAL\n");
|
||||||
status = fShortDir->Lookup(name, length, ino);
|
status = fShortDir->Lookup(name, length, ino);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Reading from extent based dirs
|
//TODO: Reading from extent based dirs
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
|
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
|
||||||
TRACE("Iterator:Lookup: EXTENTS");
|
TRACE("Iterator:Lookup: EXTENTS\n");
|
||||||
if (fExtentDir != NULL)
|
if (fExtentDir != NULL)
|
||||||
status = fExtentDir->Lookup(name, length, ino);
|
status = fExtentDir->Lookup(name, length, ino);
|
||||||
else if (fLeafDir != NULL)
|
else if (fLeafDir != NULL)
|
||||||
@ -145,7 +146,9 @@ DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
|
|||||||
|
|
||||||
//TODO: Reading from B+Tree based dirs
|
//TODO: Reading from B+Tree based dirs
|
||||||
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
|
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
|
||||||
TRACE("Iterator:Lookup: B+TREE");
|
TRACE("Iterator:Lookup: B+TREE\n");
|
||||||
|
if (fTreeDir != NULL)
|
||||||
|
return fTreeDir->Lookup(name, length, ino);
|
||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +149,10 @@ Extent::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
|||||||
// This could be an unused entry so we should check
|
// This could be an unused entry so we should check
|
||||||
|
|
||||||
int numberOfEntries = B_BENDIAN_TO_HOST_INT32(BlockTail()->count);
|
int numberOfEntries = B_BENDIAN_TO_HOST_INT32(BlockTail()->count);
|
||||||
|
int numberOfStaleEntries = B_BENDIAN_TO_HOST_INT32(BlockTail()->stale);
|
||||||
|
|
||||||
|
// We don't read stale entries.
|
||||||
|
numberOfEntries -= numberOfStaleEntries;
|
||||||
TRACE("numberOfEntries:(%d)\n", numberOfEntries);
|
TRACE("numberOfEntries:(%d)\n", numberOfEntries);
|
||||||
uint16 currentOffset = (char*)entry - fBlockBuffer;
|
uint16 currentOffset = (char*)entry - fBlockBuffer;
|
||||||
|
|
||||||
@ -161,6 +165,7 @@ Extent::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
|||||||
currentOffset += B_BENDIAN_TO_HOST_INT16(unusedEntry->length);
|
currentOffset += B_BENDIAN_TO_HOST_INT16(unusedEntry->length);
|
||||||
entry = (void*)
|
entry = (void*)
|
||||||
((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length));
|
((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length));
|
||||||
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ExtentDataEntry* dataEntry = (ExtentDataEntry*) entry;
|
ExtentDataEntry* dataEntry = (ExtentDataEntry*) entry;
|
||||||
|
@ -120,14 +120,14 @@ LeafDirectory::FillBuffer(int type, char* blockBuffer, int howManyBlocksFurthur)
|
|||||||
|
|
||||||
if (read_pos(fInode->GetVolume()->Device(), readPos, blockBuffer, len)
|
if (read_pos(fInode->GetVolume()->Device(), readPos, blockBuffer, len)
|
||||||
!= len) {
|
!= len) {
|
||||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
ERROR("LeafDirectory::FillBlockBuffer(): IO Error");
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == DATA) {
|
if (type == DATA) {
|
||||||
fDataBuffer = blockBuffer;
|
fDataBuffer = blockBuffer;
|
||||||
ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer;
|
ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer;
|
||||||
if (B_BENDIAN_TO_HOST_INT32(header->magic) == HEADER_MAGIC)
|
if (B_BENDIAN_TO_HOST_INT32(header->magic) == DATA_HEADER_MAGIC)
|
||||||
TRACE("DATA BLOCK VALID\n");
|
TRACE("DATA BLOCK VALID\n");
|
||||||
else {
|
else {
|
||||||
TRACE("DATA BLOCK INVALID\n");
|
TRACE("DATA BLOCK INVALID\n");
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include "system_dependencies.h"
|
#include "system_dependencies.h"
|
||||||
|
|
||||||
|
|
||||||
#define HEADER_MAGIC 0x58443244
|
#define DATA_HEADER_MAGIC 0x58443244
|
||||||
|
|
||||||
|
|
||||||
enum ContentType { DATA, LEAF };
|
enum ContentType { DATA, LEAF };
|
||||||
|
@ -106,14 +106,14 @@ NodeDirectory::FillBuffer(int type, char* blockBuffer, int howManyBlocksFurthur)
|
|||||||
|
|
||||||
if (read_pos(fInode->GetVolume()->Device(), readPos, blockBuffer, len)
|
if (read_pos(fInode->GetVolume()->Device(), readPos, blockBuffer, len)
|
||||||
!= len) {
|
!= len) {
|
||||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
ERROR("NodeDirectory::FillBlockBuffer(): IO Error");
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == DATA) {
|
if (type == DATA) {
|
||||||
fDataBuffer = blockBuffer;
|
fDataBuffer = blockBuffer;
|
||||||
ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer;
|
ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer;
|
||||||
if (B_BENDIAN_TO_HOST_INT32(header->magic) == HEADER_MAGIC) {
|
if (B_BENDIAN_TO_HOST_INT32(header->magic) == DATA_HEADER_MAGIC) {
|
||||||
TRACE("DATA BLOCK VALID\n");
|
TRACE("DATA BLOCK VALID\n");
|
||||||
} else {
|
} else {
|
||||||
TRACE("DATA BLOCK INVALID\n");
|
TRACE("DATA BLOCK INVALID\n");
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
bool IsNodeType();
|
bool IsNodeType();
|
||||||
void FillMapEntry(int num, ExtentMapEntry* map);
|
void FillMapEntry(int num, ExtentMapEntry* map);
|
||||||
status_t FillBuffer(int type, char* buffer,
|
status_t FillBuffer(int type, char* buffer,
|
||||||
int howManyBlocksFurthur);
|
int howManyBlocksFurther);
|
||||||
void SearchAndFillDataMap(int blockNo);
|
void SearchAndFillDataMap(int blockNo);
|
||||||
uint32 FindHashInNode(uint32 hashVal);
|
uint32 FindHashInNode(uint32 hashVal);
|
||||||
uint32 GetOffsetFromAddress(uint32 address);
|
uint32 GetOffsetFromAddress(uint32 address);
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#include "fssh_api_wrapper.h"
|
#include "fssh_api_wrapper.h"
|
||||||
#include "fssh_auto_deleter.h"
|
#include "fssh_auto_deleter.h"
|
||||||
|
#include "fssh_kernel_priv.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -47,6 +47,7 @@ extern "C"
|
|||||||
#include <fs_volume.h>
|
#include <fs_volume.h>
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include <Drivers.h>
|
#include <Drivers.h>
|
||||||
|
#include <kernel.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <NodeMonitor.h>
|
#include <NodeMonitor.h>
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
Loading…
Reference in New Issue
Block a user