xfs: Reading Node Directories
Node directories can now be read. With this, extent directories are complete. Change-Id: Ic42c8464e810137cff4946e8c975edc121daaa4f Reviewed-on: https://review.haiku-os.org/c/haiku/+/3045 Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
3376ed1a72
commit
19488d5c68
@@ -12,7 +12,8 @@ DirectoryIterator::DirectoryIterator(Inode* inode)
|
||||
fInode(inode),
|
||||
fShortDir(NULL),
|
||||
fExtentDir(NULL),
|
||||
fLeafDir(NULL)
|
||||
fLeafDir(NULL),
|
||||
fNodeDir(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,6 +23,7 @@ DirectoryIterator::~DirectoryIterator()
|
||||
delete fShortDir;
|
||||
delete fLeafDir;
|
||||
delete fExtentDir;
|
||||
delete fNodeDir;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +54,21 @@ DirectoryIterator::Init()
|
||||
status_t status = fLeafDir->Init();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
if (fLeafDir->IsLeafType() == false) {
|
||||
delete fLeafDir;
|
||||
fLeafDir = NULL;
|
||||
}
|
||||
if (fLeafDir->IsLeafType())
|
||||
return B_OK;
|
||||
delete fLeafDir;
|
||||
fLeafDir = NULL;
|
||||
|
||||
fNodeDir = new(std::nothrow) NodeDirectory(fInode);
|
||||
if (fNodeDir == NULL)
|
||||
return B_NO_MEMORY;
|
||||
status = fNodeDir->Init();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
if (fNodeDir->IsNodeType())
|
||||
return B_OK;
|
||||
delete fNodeDir;
|
||||
fNodeDir = NULL;
|
||||
}
|
||||
|
||||
/* Return B_OK so even if the shortform directory has an extent directory
|
||||
@@ -95,7 +108,7 @@ DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||
else if (fLeafDir != NULL)
|
||||
status = fLeafDir->GetNext(name, length, ino);
|
||||
else
|
||||
return B_BAD_VALUE;
|
||||
status = fNodeDir->GetNext(name, length, ino);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -127,7 +140,7 @@ DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
|
||||
else if (fLeafDir != NULL)
|
||||
status = fLeafDir->Lookup(name, length, ino);
|
||||
else
|
||||
return B_BAD_VALUE;
|
||||
status = fNodeDir->Lookup(name, length, ino);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Extent.h"
|
||||
#include "Inode.h"
|
||||
#include "LeafDirectory.h"
|
||||
#include "Node.h"
|
||||
#include "ShortDirectory.h"
|
||||
|
||||
|
||||
@@ -36,6 +37,7 @@ private:
|
||||
// TODO: Rename all to block type
|
||||
LeafDirectory* fLeafDir;
|
||||
// Extent based leaf directory
|
||||
NodeDirectory* fNodeDir;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -33,12 +33,8 @@ Extent::FillMapEntry(void* pointerToMap)
|
||||
fMap->br_startblock = ((firstHalf & MASK(9)) << 43) | (secondHalf >> 21);
|
||||
fMap->br_blockcount = (secondHalf & MASK(21));
|
||||
TRACE("Extent::Init: startoff:(%ld), startblock:(%ld), blockcount:(%ld),"
|
||||
"state:(%d)\n",
|
||||
fMap->br_startoff,
|
||||
fMap->br_startblock,
|
||||
fMap->br_blockcount,
|
||||
fMap->br_state
|
||||
);
|
||||
"state:(%d)\n", fMap->br_startoff, fMap->br_startblock,
|
||||
fMap->br_blockcount, fMap->br_state);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +180,7 @@ Extent::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataEntry->namelen > *length)
|
||||
if (dataEntry->namelen + 1 > *length)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
fOffset = currentOffset;
|
||||
|
||||
@@ -16,9 +16,13 @@
|
||||
#define XFS_DIR2_DATA_FD_COUNT 3
|
||||
#define EXTENT_REC_SIZE 128
|
||||
#define MASK(n) ((1UL << n) - 1)
|
||||
#define FSBLOCKS_TO_AGNO(n, volume) (n >> volume->AgBlocksLog())
|
||||
#define FSBLOCKS_TO_AGBLOCKNO(n, volume) (n & MASK(volume->AgBlocksLog()))
|
||||
|
||||
#define FSBLOCKS_TO_AGNO(n, volume) ((n) >> volume->AgBlocksLog())
|
||||
#define FSBLOCKS_TO_AGBLOCKNO(n, volume) ((n) & MASK(volume->AgBlocksLog()))
|
||||
#define EXTENT_SIZE 16
|
||||
#define BLOCKNO_FROM_ADDRESS(n, volume) \
|
||||
((n) >> (volume->BlockLog() + volume->DirBlockLog()))
|
||||
#define BLOCKOFFSET_FROM_ADDRESS(n, inode) ((n) & (inode->DirBlockSize() - 1))
|
||||
#define LEAF_STARTOFFSET(n) 1UL << (35 - (n))
|
||||
|
||||
|
||||
// xfs_exntst_t
|
||||
|
||||
@@ -38,6 +38,15 @@
|
||||
#define DIR_AFORK_EXIST(dir_ino_ptr) dir_ino_ptr->di_forkoff!=0
|
||||
|
||||
|
||||
// xfs_da_blkinfo_t
|
||||
struct BlockInfo {
|
||||
uint32 forw;
|
||||
uint32 back;
|
||||
uint16 magic;
|
||||
uint16 pad;
|
||||
};
|
||||
|
||||
|
||||
uint32
|
||||
hashfunction(const char* name, int length);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ local xfsSources =
|
||||
kernel_cpp.cpp
|
||||
kernel_interface.cpp
|
||||
LeafDirectory.cpp
|
||||
Node.cpp
|
||||
ShortDirectory.cpp
|
||||
Volume.cpp
|
||||
xfs.cpp
|
||||
|
||||
@@ -75,6 +75,7 @@ void
|
||||
LeafDirectory::FillMapEntry(int num, ExtentMapEntry* fMap)
|
||||
{
|
||||
void* directoryFork = DIR_DFORK_PTR(fInode->Buffer());
|
||||
|
||||
uint64* pointerToMap = (uint64*)((char*)directoryFork + num * EXTENT_SIZE);
|
||||
uint64 firstHalf = pointerToMap[0];
|
||||
uint64 secondHalf = pointerToMap[1];
|
||||
@@ -99,9 +100,10 @@ LeafDirectory::FillBuffer(int type, char* blockBuffer, int howManyBlocksFurthur)
|
||||
ExtentMapEntry* map;
|
||||
if (type == DATA)
|
||||
map = fDataMap;
|
||||
|
||||
if (type == LEAF)
|
||||
else if (type == LEAF)
|
||||
map = fLeafMap;
|
||||
else
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (map->br_state !=0)
|
||||
return B_BAD_VALUE;
|
||||
@@ -132,18 +134,8 @@ LeafDirectory::FillBuffer(int type, char* blockBuffer, int howManyBlocksFurthur)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
if (type == DATA)
|
||||
fDataBuffer = blockBuffer;
|
||||
|
||||
if (type == LEAF)
|
||||
fLeafBuffer = blockBuffer;
|
||||
|
||||
if (type == LEAF) {
|
||||
ExtentLeafHeader* header = (ExtentLeafHeader*) fLeafBuffer;
|
||||
TRACE("NumberOfEntries in leaf: (%d)\n",
|
||||
B_BENDIAN_TO_HOST_INT16(header->count));
|
||||
}
|
||||
if (type == DATA) {
|
||||
fDataBuffer = blockBuffer;
|
||||
ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer;
|
||||
if (B_BENDIAN_TO_HOST_INT32(header->magic) == HEADER_MAGIC)
|
||||
TRACE("DATA BLOCK VALID\n");
|
||||
@@ -151,6 +143,10 @@ LeafDirectory::FillBuffer(int type, char* blockBuffer, int howManyBlocksFurthur)
|
||||
TRACE("DATA BLOCK INVALID\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
} else if (type == LEAF) {
|
||||
fLeafBuffer = blockBuffer;
|
||||
ExtentLeafHeader* header = (ExtentLeafHeader*) fLeafBuffer;
|
||||
TRACE("NumberOfEntries in leaf: (%d)\n", B_BENDIAN_TO_HOST_INT16(header->count));
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
@@ -281,7 +277,7 @@ LeafDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataEntry->namelen > *length)
|
||||
if (dataEntry->namelen + 1 > *length)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
fOffset = fOffset + EntrySize(dataEntry->namelen);
|
||||
|
||||
@@ -11,25 +11,12 @@
|
||||
#include "system_dependencies.h"
|
||||
|
||||
|
||||
#define EXTENT_SIZE 16
|
||||
#define BLOCKNO_FROM_ADDRESS(n, volume) \
|
||||
(n >> (volume->BlockLog() + volume->DirBlockLog()))
|
||||
#define BLOCKOFFSET_FROM_ADDRESS(n, inode) (n & (inode->DirBlockSize() - 1))
|
||||
#define HEADER_MAGIC 0x58443244
|
||||
#define LEAF_STARTOFFSET(n) 1UL << (35 - n)
|
||||
|
||||
|
||||
enum ContentType { DATA, LEAF };
|
||||
|
||||
|
||||
// xfs_da_blkinfo_t
|
||||
struct BlockInfo {
|
||||
uint32 forw;
|
||||
uint32 back;
|
||||
uint16 magic;
|
||||
uint16 pad;
|
||||
};
|
||||
|
||||
|
||||
//xfs_dir2_leaf_hdr_t
|
||||
struct ExtentLeafHeader {
|
||||
BlockInfo info;
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
|
||||
NodeDirectory::NodeDirectory(Inode* inode)
|
||||
:
|
||||
fInode(inode),
|
||||
fOffset(0),
|
||||
fDataBuffer(NULL),
|
||||
fLeafBuffer(NULL),
|
||||
fLeafMap(NULL),
|
||||
fDataMap(NULL),
|
||||
fCurBlockNumber(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NodeDirectory::~NodeDirectory()
|
||||
{
|
||||
delete fDataMap;
|
||||
delete fLeafMap;
|
||||
delete fDataBuffer;
|
||||
delete fLeafBuffer;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NodeDirectory::Init()
|
||||
{
|
||||
fLeafMap = new(std::nothrow) ExtentMapEntry;
|
||||
if (fLeafMap == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fDataMap = new(std::nothrow) ExtentMapEntry;
|
||||
if (fDataMap == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
FillMapEntry(fInode->DataExtentsCount()-3, fLeafMap);
|
||||
fCurLeafMapNumber = 1;
|
||||
FillMapEntry(0, fDataMap);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NodeDirectory::IsNodeType()
|
||||
{
|
||||
if (fCurLeafMapNumber != 1) {
|
||||
FillMapEntry(fInode->DataExtentsCount() - 3, fLeafMap);
|
||||
fCurLeafMapNumber = 1;
|
||||
}
|
||||
return fLeafMap->br_startoff == LEAF_STARTOFFSET(fInode->GetVolume()->BlockLog());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NodeDirectory::FillMapEntry(int num, ExtentMapEntry* fMap)
|
||||
{
|
||||
void* directoryFork = DIR_DFORK_PTR(fInode->Buffer());
|
||||
void* pointerToMap = (void*)((char*)directoryFork + num * EXTENT_SIZE);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NodeDirectory::FillBuffer(int type, char* blockBuffer, int howManyBlocksFurthur)
|
||||
{
|
||||
TRACE("FILLBUFFER\n");
|
||||
ExtentMapEntry* map;
|
||||
if (type == DATA)
|
||||
map = fDataMap;
|
||||
else if (type == LEAF)
|
||||
map = fLeafMap;
|
||||
else
|
||||
return B_BAD_VALUE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Volume* volume = fInode->GetVolume();
|
||||
xfs_agblock_t numberOfBlocksInAg = volume->AgBlocks();
|
||||
|
||||
uint64 agNo
|
||||
= FSBLOCKS_TO_AGNO(map->br_startblock + howManyBlocksFurthur, volume);
|
||||
uint64 agBlockNo
|
||||
= FSBLOCKS_TO_AGBLOCKNO(map->br_startblock + howManyBlocksFurthur, volume);
|
||||
|
||||
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(),
|
||||
((uint64)(agNo * numberOfBlocksInAg) + agBlockNo));
|
||||
|
||||
xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE);
|
||||
|
||||
TRACE("blockToRead: (%ld), readPos: (%ld)\n", blockToRead, readPos);
|
||||
if (read_pos(volume->Device(), readPos, blockBuffer, len) != len) {
|
||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
if (type == DATA) {
|
||||
fDataBuffer = blockBuffer;
|
||||
ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer;
|
||||
if (B_BENDIAN_TO_HOST_INT32(header->magic) == HEADER_MAGIC) {
|
||||
TRACE("DATA BLOCK VALID\n");
|
||||
} else {
|
||||
TRACE("DATA BLOCK INVALID\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
} else if (type == LEAF) {
|
||||
fLeafBuffer = blockBuffer;
|
||||
ExtentLeafHeader* header = (ExtentLeafHeader*) fLeafBuffer;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
NodeDirectory::GetOffsetFromAddress(uint32 address)
|
||||
{
|
||||
address = address * 8;
|
||||
// block offset in eight bytes, hence multiple with 8
|
||||
return address & (fInode->DirBlockSize() - 1);
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
NodeDirectory::FindHashInNode(uint32 hashVal)
|
||||
{
|
||||
NodeHeader* header = (NodeHeader*)(void*)(fLeafBuffer);
|
||||
NodeEntry* entry = (NodeEntry*)(void*)(fLeafBuffer + sizeof(NodeHeader));
|
||||
int count = B_BENDIAN_TO_HOST_INT16(header->count);
|
||||
if ((NodeEntry*)(void*)fLeafBuffer + fInode->DirBlockSize()
|
||||
< &entry[count]) {
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
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 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
NodeDirectory::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 (entrySize + 7) & -8;
|
||||
// rounding off to closest multiple of 8
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NodeDirectory::SearchAndFillDataMap(int blockNo)
|
||||
{
|
||||
int len = fInode->DataExtentsCount();
|
||||
|
||||
for (int i = 0; i < len - 3; i++) {
|
||||
FillMapEntry(i, fDataMap);
|
||||
if (fDataMap->br_startoff <= blockNo
|
||||
&& (blockNo <= fDataMap->br_startoff + fDataMap->br_blockcount - 1))
|
||||
// Map found
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NodeDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||
{
|
||||
TRACE("NodeDirectory::GetNext\n");
|
||||
status_t status;
|
||||
|
||||
if (fDataBuffer == NULL) {
|
||||
status = FillBuffer(DATA, fDataBuffer, 0);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
Volume* volume = fInode->GetVolume();
|
||||
void* entry = (void*)((ExtentDataHeader*)fDataBuffer + 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*)(fDataBuffer + BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode));
|
||||
// This gets us a little faster to the next entry
|
||||
|
||||
uint32 curDirectorySize = fInode->Size();
|
||||
|
||||
while (fOffset != curDirectorySize) {
|
||||
blockNoFromAddress = BLOCKNO_FROM_ADDRESS(fOffset, volume);
|
||||
|
||||
TRACE("fOffset:(%d), blockNoFromAddress:(%d)\n",
|
||||
fOffset, blockNoFromAddress);
|
||||
if (fCurBlockNumber != blockNoFromAddress
|
||||
&& blockNoFromAddress > fDataMap->br_startoff
|
||||
&& blockNoFromAddress
|
||||
<= fDataMap->br_startoff + fDataMap->br_blockcount - 1) {
|
||||
// When the block is mapped in the same data
|
||||
// map entry but is not the first block
|
||||
status = FillBuffer(DATA, fDataBuffer,
|
||||
blockNoFromAddress - fDataMap->br_startoff);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
entry = (void*)((ExtentDataHeader*)fDataBuffer + 1);
|
||||
fOffset = fOffset + sizeof(ExtentDataHeader);
|
||||
fCurBlockNumber = blockNoFromAddress;
|
||||
} else if (fCurBlockNumber != blockNoFromAddress) {
|
||||
// When the block isn't mapped in the current data map entry
|
||||
SearchAndFillDataMap(blockNoFromAddress);
|
||||
status = FillBuffer(DATA, fDataBuffer,
|
||||
blockNoFromAddress - fDataMap->br_startoff);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
entry = (void*)((ExtentDataHeader*)fDataBuffer + 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 - fDataBuffer;
|
||||
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
|
||||
NodeDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
|
||||
{
|
||||
TRACE("NodeDirectory: Lookup\n");
|
||||
TRACE("Name: %s\n", name);
|
||||
uint32 hashValueOfRequest = hashfunction(name, length);
|
||||
TRACE("Hashval:(%ld)\n", hashValueOfRequest);
|
||||
|
||||
status_t status;
|
||||
if (fCurLeafBufferNumber != 1) {
|
||||
if (fCurLeafMapNumber != 1) {
|
||||
FillMapEntry(fInode->DataExtentsCount() - 3, fLeafMap);
|
||||
fCurLeafMapNumber = 1;
|
||||
}
|
||||
status = FillBuffer(LEAF, fLeafBuffer, 0);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
fCurLeafBufferNumber = 1;
|
||||
}
|
||||
/* Leaf now has the nodes. */
|
||||
uint32 rightMapOffset = FindHashInNode(hashValueOfRequest);
|
||||
if (rightMapOffset == 1){
|
||||
TRACE("Not in this directory.\n");
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
TRACE("rightMapOffset:(%d)\n", rightMapOffset);
|
||||
|
||||
FillMapEntry(fInode->DataExtentsCount() - 2, fLeafMap);
|
||||
fCurLeafMapNumber = 2;
|
||||
status = FillBuffer(LEAF, fLeafBuffer, rightMapOffset - fLeafMap->br_startoff);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
fCurLeafBufferNumber = 2;
|
||||
|
||||
ExtentLeafHeader* leafHeader = (ExtentLeafHeader*)(void*)fLeafBuffer;
|
||||
ExtentLeafEntry* leafEntry =
|
||||
(ExtentLeafEntry*)(void*)(fLeafBuffer + sizeof(ExtentLeafHeader));
|
||||
if (leafEntry == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
int numberOfLeafEntries = B_BENDIAN_TO_HOST_INT16(leafHeader->count);
|
||||
TRACE("numberOfLeafEntries:(%d)\n", numberOfLeafEntries);
|
||||
int left = 0;
|
||||
int mid;
|
||||
int right = numberOfLeafEntries - 1;
|
||||
Volume* volume = fInode->GetVolume();
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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("DataBlockNumber:(%d), offset:(%d)\n", dataBlockNumber, offset);
|
||||
if (dataBlockNumber != fCurBlockNumber) {
|
||||
fCurBlockNumber = dataBlockNumber;
|
||||
SearchAndFillDataMap(dataBlockNumber);
|
||||
status = FillBuffer(DATA, fDataBuffer,
|
||||
dataBlockNumber - fDataMap->br_startoff);
|
||||
if (status != B_OK)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
TRACE("offset:(%d)\n", offset);
|
||||
ExtentDataEntry* entry = (ExtentDataEntry*)(fDataBuffer + 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++;
|
||||
}
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NODE_H_
|
||||
#define _NODE_H_
|
||||
|
||||
|
||||
#include "Extent.h"
|
||||
#include "LeafDirectory.h"
|
||||
|
||||
|
||||
#define XFS_DIR2_LEAFN_MAGIC (0xd2ff)
|
||||
#define XFS_DA_NODE_MAGIC (0xfebe)
|
||||
|
||||
|
||||
//xfs_da_node_hdr
|
||||
struct NodeHeader {
|
||||
BlockInfo info;
|
||||
uint16 count;
|
||||
uint16 level;
|
||||
};
|
||||
|
||||
|
||||
//xfs_da_node_entry
|
||||
struct NodeEntry {
|
||||
uint32 hashval;
|
||||
uint32 before;
|
||||
};
|
||||
|
||||
|
||||
class NodeDirectory {
|
||||
public:
|
||||
NodeDirectory(Inode* inode);
|
||||
~NodeDirectory();
|
||||
status_t Init();
|
||||
bool IsNodeType();
|
||||
void FillMapEntry(int num, ExtentMapEntry* map);
|
||||
status_t FillBuffer(int type, char* buffer,
|
||||
int howManyBlocksFurthur);
|
||||
void SearchAndFillDataMap(int blockNo);
|
||||
uint32 FindHashInNode(uint32 hashVal);
|
||||
uint32 GetOffsetFromAddress(uint32 address);
|
||||
int EntrySize(int len) const;
|
||||
status_t GetNext(char* name, size_t* length,
|
||||
xfs_ino_t* ino);
|
||||
status_t Lookup(const char* name, size_t length,
|
||||
xfs_ino_t* id);
|
||||
private:
|
||||
Inode* fInode;
|
||||
ExtentMapEntry* fDataMap;
|
||||
ExtentMapEntry* fLeafMap;
|
||||
uint32 fOffset;
|
||||
char* fDataBuffer;
|
||||
// This isn't inode data. It holds the directory block.
|
||||
char* fLeafBuffer;
|
||||
uint32 fCurBlockNumber;
|
||||
uint8 fCurLeafMapNumber;
|
||||
uint8 fCurLeafBufferNumber;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -147,7 +147,7 @@ ShortDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||
uint16 curOffset = B_BENDIAN_TO_HOST_INT16(entry->offset.i);
|
||||
if (curOffset > fLastEntryOffset) {
|
||||
|
||||
if (entry->namelen > *length)
|
||||
if (entry->namelen + 1 > *length)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
fLastEntryOffset = curOffset;
|
||||
|
||||
@@ -45,6 +45,7 @@ local xfsSource =
|
||||
Inode.cpp
|
||||
kernel_interface.cpp
|
||||
LeafDirectory.cpp
|
||||
Node.cpp
|
||||
ShortDirectory.cpp
|
||||
Volume.cpp
|
||||
xfs.cpp
|
||||
|
||||
Reference in New Issue
Block a user