xfs: Attempt at reading Leaf Directories
We can read leaf directories now but I've only checked for a single block working right now. I might make a few more changes in an upcoming patch. Change-Id: I325de8a6fad4ef9298e7810256cba47a87c45187 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3027 Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
a20b880907
commit
bd0708fd41
@@ -15,8 +15,8 @@
|
|||||||
#define ASSERT(x) \
|
#define ASSERT(x) \
|
||||||
{ if (!(x)) kernel_debugger("xfs: assert failed: " #x "\n"); }
|
{ if (!(x)) kernel_debugger("xfs: assert failed: " #x "\n"); }
|
||||||
#else
|
#else
|
||||||
#define TRACE(x...) ;
|
#define TRACE(x...)
|
||||||
#define ASSERT(x) ;
|
#define ASSERT(x)
|
||||||
#endif
|
#endif
|
||||||
#define ERROR(x...) dprintf("\n\33[34mxfs:\33[0m " x)
|
#define ERROR(x...) dprintf("\n\33[34mxfs:\33[0m " x)
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,20 @@
|
|||||||
|
|
||||||
|
|
||||||
DirectoryIterator::DirectoryIterator(Inode* inode)
|
DirectoryIterator::DirectoryIterator(Inode* inode)
|
||||||
|
:
|
||||||
|
fInode(inode),
|
||||||
|
fShortDir(NULL),
|
||||||
|
fExtentDir(NULL),
|
||||||
|
fLeafDir(NULL)
|
||||||
{
|
{
|
||||||
fInode = inode;
|
|
||||||
fShortDir = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DirectoryIterator::~DirectoryIterator()
|
DirectoryIterator::~DirectoryIterator()
|
||||||
{
|
{
|
||||||
delete fShortDir;
|
delete fShortDir;
|
||||||
|
delete fLeafDir;
|
||||||
|
delete fExtentDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -35,8 +40,22 @@ DirectoryIterator::Init()
|
|||||||
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;
|
||||||
status_t status = fExtentDir->Init();
|
if (fExtentDir->IsBlockType())
|
||||||
|
return fExtentDir->Init();
|
||||||
|
|
||||||
|
delete fExtentDir;
|
||||||
|
fExtentDir = NULL;
|
||||||
|
|
||||||
|
fLeafDir = new(std::nothrow) LeafDirectory(fInode);
|
||||||
|
if (fLeafDir == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
status_t status = fLeafDir->Init();
|
||||||
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
if (fLeafDir->IsLeafType() == false) {
|
||||||
|
delete fLeafDir;
|
||||||
|
fLeafDir = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
||||||
@@ -71,7 +90,12 @@ DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
|||||||
//TODO: Reading from extent based directories
|
//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)
|
||||||
status = fExtentDir->GetNext(name, length, ino);
|
status = fExtentDir->GetNext(name, length, ino);
|
||||||
|
else if (fLeafDir != NULL)
|
||||||
|
status = fLeafDir->GetNext(name, length, ino);
|
||||||
|
else
|
||||||
|
return B_BAD_VALUE;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +122,12 @@ DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
|
|||||||
//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");
|
||||||
|
if (fExtentDir != NULL)
|
||||||
status = fExtentDir->Lookup(name, length, ino);
|
status = fExtentDir->Lookup(name, length, ino);
|
||||||
|
else if (fLeafDir != NULL)
|
||||||
|
status = fLeafDir->Lookup(name, length, ino);
|
||||||
|
else
|
||||||
|
return B_BAD_VALUE;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "Extent.h"
|
#include "Extent.h"
|
||||||
#include "Inode.h"
|
#include "Inode.h"
|
||||||
|
#include "LeafDirectory.h"
|
||||||
#include "ShortDirectory.h"
|
#include "ShortDirectory.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +33,9 @@ private:
|
|||||||
// Short form Directory type
|
// Short form Directory type
|
||||||
Extent* fExtentDir;
|
Extent* fExtentDir;
|
||||||
// Extent form Directory type
|
// Extent form Directory type
|
||||||
|
// TODO: Rename all to block type
|
||||||
|
LeafDirectory* fLeafDir;
|
||||||
|
// Extent based leaf directory
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ Extent::Extent(Inode* inode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Extent::~Extent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Extent::FillMapEntry(void* pointerToMap)
|
Extent::FillMapEntry(void* pointerToMap)
|
||||||
{
|
{
|
||||||
@@ -56,7 +61,7 @@ Extent::FillBlockBuffer()
|
|||||||
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(),
|
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(),
|
||||||
((uint64)(agNo * numberOfBlocksInAg) + agBlockNo));
|
((uint64)(agNo * numberOfBlocksInAg) + agBlockNo));
|
||||||
|
|
||||||
xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE) + fMap->br_startoff;
|
xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE;
|
||||||
|
|
||||||
TRACE("blockToRead: (%ld), readPos: (%ld)\n", blockToRead, readPos);
|
TRACE("blockToRead: (%ld), readPos: (%ld)\n", blockToRead, readPos);
|
||||||
if (read_pos(volume->Device(), readPos, fBlockBuffer, len) != len) {
|
if (read_pos(volume->Device(), readPos, fBlockBuffer, len) != len) {
|
||||||
@@ -75,7 +80,7 @@ Extent::Init()
|
|||||||
if (fMap == NULL)
|
if (fMap == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
ASSERT(BlockType() == true);
|
ASSERT(IsBlockType() == true);
|
||||||
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer());
|
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer());
|
||||||
FillMapEntry(pointerToMap);
|
FillMapEntry(pointerToMap);
|
||||||
ASSERT(fMap->br_blockcount == 1);
|
ASSERT(fMap->br_blockcount == 1);
|
||||||
@@ -121,10 +126,10 @@ Extent::BlockFirstLeaf(ExtentBlockTail* tail)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Extent::BlockType()
|
Extent::IsBlockType()
|
||||||
{
|
{
|
||||||
bool status = true;
|
bool status = true;
|
||||||
if (fInode->NoOfBlocks() != 1)
|
if (fInode->BlockCount() != 1)
|
||||||
status = false;
|
status = false;
|
||||||
if (fInode->Size() != fInode->DirBlockSize())
|
if (fInode->Size() != fInode->DirBlockSize())
|
||||||
status = false;
|
status = false;
|
||||||
@@ -158,11 +163,12 @@ Extent::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
|||||||
TRACE("numberOfEntries:(%d)\n", numberOfEntries);
|
TRACE("numberOfEntries:(%d)\n", numberOfEntries);
|
||||||
|
|
||||||
for (int i = 0; i < numberOfEntries; i++) {
|
for (int i = 0; i < numberOfEntries; i++) {
|
||||||
TRACE("i:(%d)\n", i);
|
TRACE("EntryNumber:(%d)\n", i);
|
||||||
ExtentUnusedEntry* unusedEntry = (ExtentUnusedEntry*)entry;
|
ExtentUnusedEntry* unusedEntry = (ExtentUnusedEntry*)entry;
|
||||||
|
|
||||||
if (B_BENDIAN_TO_HOST_INT16(unusedEntry->freetag) == DIR2_FREE_TAG) {
|
if (B_BENDIAN_TO_HOST_INT16(unusedEntry->freetag) == DIR2_FREE_TAG) {
|
||||||
TRACE("Unused entry found\n");
|
TRACE("Unused entry found\n");
|
||||||
|
i--;
|
||||||
entry = (void*)
|
entry = (void*)
|
||||||
((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length));
|
((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length));
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public:
|
|||||||
Extent(Inode* inode);
|
Extent(Inode* inode);
|
||||||
~Extent();
|
~Extent();
|
||||||
status_t Init();
|
status_t Init();
|
||||||
bool BlockType();
|
bool IsBlockType();
|
||||||
void FillMapEntry(void* pointerToMap);
|
void FillMapEntry(void* pointerToMap);
|
||||||
status_t FillBlockBuffer();
|
status_t FillBlockBuffer();
|
||||||
ExtentBlockTail* BlockTail();
|
ExtentBlockTail* BlockTail();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ xfs_inode_t::SwapEndian()
|
|||||||
|
|
||||||
|
|
||||||
xfs_rfsblock_t
|
xfs_rfsblock_t
|
||||||
xfs_inode_t::NoOfBlocks() const
|
xfs_inode_t::BlockCount() const
|
||||||
{
|
{
|
||||||
return di_nblocks;
|
return di_nblocks;
|
||||||
}
|
}
|
||||||
@@ -124,6 +124,13 @@ xfs_inode_t::Format() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xfs_extnum_t
|
||||||
|
xfs_inode_t::DataExtentsCount() const
|
||||||
|
{
|
||||||
|
return di_nextents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Inode::Inode(Volume* volume, xfs_ino_t id)
|
Inode::Inode(Volume* volume, xfs_ino_t id)
|
||||||
:
|
:
|
||||||
fVolume(volume),
|
fVolume(volume),
|
||||||
@@ -195,7 +202,7 @@ Inode::GetFromDisk()
|
|||||||
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
|
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
|
||||||
((uint64)(agNo * numberOfBlocksInAg) + agBlock));
|
((uint64)(agNo * numberOfBlocksInAg) + agBlock));
|
||||||
|
|
||||||
xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE) + offset * len;
|
xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE + offset * len;
|
||||||
|
|
||||||
if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
|
if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
|
||||||
ERROR("Inode::Inode(): IO Error");
|
ERROR("Inode::Inode(): IO Error");
|
||||||
|
|||||||
@@ -77,11 +77,12 @@ struct xfs_inode_t {
|
|||||||
int8 Format() const;
|
int8 Format() const;
|
||||||
// The format of the inode
|
// The format of the inode
|
||||||
xfs_fsize_t Size() const;
|
xfs_fsize_t Size() const;
|
||||||
xfs_rfsblock_t NoOfBlocks() const;
|
xfs_rfsblock_t BlockCount() const;
|
||||||
uint32 NLink() const;
|
uint32 NLink() const;
|
||||||
uint16 Flags() const;
|
uint16 Flags() const;
|
||||||
uint32 UserId() const;
|
uint32 UserId() const;
|
||||||
uint32 GroupId() const;
|
uint32 GroupId() const;
|
||||||
|
xfs_extnum_t DataExtentsCount() const;
|
||||||
|
|
||||||
uint16 di_magic;
|
uint16 di_magic;
|
||||||
uint16 di_mode;
|
uint16 di_mode;
|
||||||
@@ -154,8 +155,8 @@ public:
|
|||||||
|
|
||||||
int8 Version() const { return fNode->Version(); }
|
int8 Version() const { return fNode->Version(); }
|
||||||
|
|
||||||
xfs_rfsblock_t NoOfBlocks() const
|
xfs_rfsblock_t BlockCount() const
|
||||||
{ return fNode->NoOfBlocks(); }
|
{ return fNode->BlockCount(); }
|
||||||
|
|
||||||
char* Buffer() { return fBuffer; }
|
char* Buffer() { return fBuffer; }
|
||||||
|
|
||||||
@@ -179,6 +180,8 @@ public:
|
|||||||
uint32 UserId() const { return fNode->UserId(); }
|
uint32 UserId() const { return fNode->UserId(); }
|
||||||
uint32 GroupId() const { return fNode->GroupId(); }
|
uint32 GroupId() const { return fNode->GroupId(); }
|
||||||
bool HasFileTypeField() const;
|
bool HasFileTypeField() const;
|
||||||
|
xfs_extnum_t DataExtentsCount() const
|
||||||
|
{ return fNode->DataExtentsCount(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t GetFromDisk();
|
status_t GetFromDisk();
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ local xfsSources =
|
|||||||
Inode.cpp
|
Inode.cpp
|
||||||
kernel_cpp.cpp
|
kernel_cpp.cpp
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
|
LeafDirectory.cpp
|
||||||
ShortDirectory.cpp
|
ShortDirectory.cpp
|
||||||
Volume.cpp
|
Volume.cpp
|
||||||
xfs.cpp
|
xfs.cpp
|
||||||
|
|||||||
@@ -0,0 +1,345 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "LeafDirectory.h"
|
||||||
|
|
||||||
|
|
||||||
|
LeafDirectory::LeafDirectory(Inode* inode)
|
||||||
|
:
|
||||||
|
fInode(inode),
|
||||||
|
fOffset(0),
|
||||||
|
fDataBuffer(NULL),
|
||||||
|
fLeafBuffer(NULL),
|
||||||
|
fLeafMap(NULL),
|
||||||
|
fDataMap(NULL),
|
||||||
|
fCurBlockNumber(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LeafDirectory::~LeafDirectory()
|
||||||
|
{
|
||||||
|
delete fDataMap;
|
||||||
|
delete fLeafMap;
|
||||||
|
delete fDataBuffer;
|
||||||
|
delete fLeafBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LeafDirectory::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()-1, fLeafMap);
|
||||||
|
FillMapEntry(0, fDataMap);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LeafDirectory::IsLeafType()
|
||||||
|
{
|
||||||
|
bool status = true;
|
||||||
|
if (fInode->BlockCount() == 1
|
||||||
|
|| fInode->DataExtentsCount() == 1
|
||||||
|
|| fInode->Size() !=
|
||||||
|
(fInode->BlockCount() - 1) * fInode->DirBlockSize())
|
||||||
|
status = false;
|
||||||
|
|
||||||
|
if (status == false)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
FillMapEntry(fInode->DataExtentsCount() - 1, fLeafMap);
|
||||||
|
TRACE("leaf_Startoffset:(%ld)\n",
|
||||||
|
LEAF_STARTOFFSET(fInode->GetVolume()->BlockLog()));
|
||||||
|
|
||||||
|
if (fLeafMap->br_startoff
|
||||||
|
!= LEAF_STARTOFFSET(fInode->GetVolume()->BlockLog()))
|
||||||
|
status = false;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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];
|
||||||
|
//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
|
||||||
|
LeafDirectory::FillBuffer(int type, char* blockBuffer)
|
||||||
|
{
|
||||||
|
TRACE("FILLBUFFER\n");
|
||||||
|
ExtentMapEntry* map;
|
||||||
|
if (type == DATA)
|
||||||
|
map = fDataMap;
|
||||||
|
|
||||||
|
if (type == LEAF)
|
||||||
|
map = fLeafMap;
|
||||||
|
|
||||||
|
if (map->br_state !=0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
int 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, volume);
|
||||||
|
uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(map->br_startblock, volume);
|
||||||
|
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(),
|
||||||
|
(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;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
LeafDirectory::GetOffsetFromAddress(uint32 address)
|
||||||
|
{
|
||||||
|
address = address * 8;
|
||||||
|
// block offset in eight bytes, hence multiply with 8
|
||||||
|
return address & (fInode->DirBlockSize() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ExtentLeafEntry*
|
||||||
|
LeafDirectory::FirstLeaf()
|
||||||
|
{
|
||||||
|
TRACE("LeafDirectory: FirstLeaf\n");
|
||||||
|
if (fLeafBuffer == NULL) {
|
||||||
|
ASSERT(fLeafMap != NULL);
|
||||||
|
status_t status = FillBuffer(LEAF, fLeafBuffer);
|
||||||
|
if (status != B_OK)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return (ExtentLeafEntry*)((char*)fLeafBuffer + sizeof(ExtentLeafHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
LeafDirectory::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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LeafDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||||
|
{
|
||||||
|
TRACE("LeafDirectory::GetNext\n");
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
if (fDataBuffer == NULL) {
|
||||||
|
status = FillBuffer(DATA, fDataBuffer);
|
||||||
|
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
|
||||||
|
|
||||||
|
if (BLOCKNO_FROM_ADDRESS(fOffset, volume) == fCurBlockNumber
|
||||||
|
&& fOffset != 0)
|
||||||
|
entry = (void*)(fDataBuffer
|
||||||
|
+ BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode));
|
||||||
|
// This gets us a little faster to the next entry
|
||||||
|
|
||||||
|
ExtentLeafHeader* leafHeader = (ExtentLeafHeader*)(void*)fLeafBuffer;
|
||||||
|
uint32 curDirectorySize = fInode->Size();
|
||||||
|
|
||||||
|
while (fOffset != curDirectorySize) {
|
||||||
|
TRACE("fOffset:(%d)\n", fOffset);
|
||||||
|
if (fCurBlockNumber != BLOCKNO_FROM_ADDRESS(fOffset, volume)) {
|
||||||
|
fCurBlockNumber = BLOCKNO_FROM_ADDRESS(fOffset, volume);
|
||||||
|
FillMapEntry(fCurBlockNumber, fDataMap);
|
||||||
|
status = FillBuffer(DATA, fDataBuffer);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
entry = (void*)((ExtentDataHeader*)fDataBuffer + 1);
|
||||||
|
fOffset = fOffset + sizeof(ExtentDataHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 > *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
|
||||||
|
LeafDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
|
||||||
|
{
|
||||||
|
TRACE("LeafDirectory: Lookup\n");
|
||||||
|
TRACE("Name: %s\n", name);
|
||||||
|
uint32 hashValueOfRequest = hashfunction(name, length);
|
||||||
|
TRACE("Hashval:(%ld)\n", hashValueOfRequest);
|
||||||
|
|
||||||
|
status_t status;
|
||||||
|
if (fLeafBuffer == NULL)
|
||||||
|
status = FillBuffer(LEAF, fLeafBuffer);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
ExtentLeafHeader* leafHeader = (ExtentLeafHeader*)(void*)fLeafBuffer;
|
||||||
|
ExtentLeafEntry* leafEntry = FirstLeaf();
|
||||||
|
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;
|
||||||
|
FillMapEntry(dataBlockNumber, fDataMap);
|
||||||
|
status = FillBuffer(DATA, fDataBuffer);
|
||||||
|
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,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _LEAFDIRECTORY_H_
|
||||||
|
#define _LEAFDIRECTORY_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include "Extent.h"
|
||||||
|
#include "Inode.h"
|
||||||
|
#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;
|
||||||
|
uint16 count;
|
||||||
|
uint16 stale;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// xfs_dir2_leaf_tail_t
|
||||||
|
struct ExtentLeafTail {
|
||||||
|
uint32 bestcount;
|
||||||
|
// # of best free entries
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LeafDirectory {
|
||||||
|
public:
|
||||||
|
LeafDirectory(Inode* inode);
|
||||||
|
~LeafDirectory();
|
||||||
|
status_t Init();
|
||||||
|
bool IsLeafType();
|
||||||
|
void FillMapEntry(int num, ExtentMapEntry* map);
|
||||||
|
status_t FillBuffer(int type, char* buffer);
|
||||||
|
ExtentLeafEntry* FirstLeaf();
|
||||||
|
xfs_ino_t GetIno();
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -56,6 +56,9 @@ public:
|
|||||||
uint32 DirBlockSize() const
|
uint32 DirBlockSize() const
|
||||||
{ return fSuperBlock.DirBlockSize(); }
|
{ return fSuperBlock.DirBlockSize(); }
|
||||||
|
|
||||||
|
uint32 DirBlockLog() const
|
||||||
|
{ return fSuperBlock.DirBlockLog(); }
|
||||||
|
|
||||||
uint8 AgInodeBits() const
|
uint8 AgInodeBits() const
|
||||||
{ return fSuperBlock.AgInodeBits(); }
|
{ return fSuperBlock.AgInodeBits(); }
|
||||||
|
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
|
|||||||
stat->st_type = 0; // TODO
|
stat->st_type = 0; // TODO
|
||||||
|
|
||||||
stat->st_size = inode->Size();
|
stat->st_size = inode->Size();
|
||||||
stat->st_blocks = inode->NoOfBlocks();
|
stat->st_blocks = inode->BlockCount();
|
||||||
|
|
||||||
inode->GetAccessTime(stat->st_atim);
|
inode->GetAccessTime(stat->st_atim);
|
||||||
inode->GetModificationTime(stat->st_mtim);
|
inode->GetModificationTime(stat->st_mtim);
|
||||||
|
|||||||
@@ -52,6 +52,13 @@ XfsSuperBlock::BlockSize() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
XfsSuperBlock::DirBlockLog() const
|
||||||
|
{
|
||||||
|
return sb_dirblklog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8
|
uint8
|
||||||
XfsSuperBlock::BlockLog() const
|
XfsSuperBlock::BlockLog() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ extern fs_volume_ops gxfsVolumeOps;
|
|||||||
#define XFS_SB_MAXSIZE 512
|
#define XFS_SB_MAXSIZE 512
|
||||||
#define BASICBLOCKLOG 9
|
#define BASICBLOCKLOG 9
|
||||||
// Log of block size should be 9
|
// Log of block size should be 9
|
||||||
#define BASICBLOCKSIZE 1 << BASICBLOCKLOG
|
#define BASICBLOCKSIZE (1 << BASICBLOCKLOG)
|
||||||
// The size of a basic block should be 512
|
// The size of a basic block should be 512
|
||||||
|
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ public:
|
|||||||
uint8 BlockLog() const;
|
uint8 BlockLog() const;
|
||||||
uint32 DirBlockSize() const;
|
uint32 DirBlockSize() const;
|
||||||
// maximum 65536
|
// maximum 65536
|
||||||
|
uint32 DirBlockLog() const;
|
||||||
uint8 AgInodeBits() const;
|
uint8 AgInodeBits() const;
|
||||||
uint8 InodesPerBlkLog() const;
|
uint8 InodesPerBlkLog() const;
|
||||||
uint8 AgBlocksLog() const;
|
uint8 AgBlocksLog() const;
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ local xfsSource =
|
|||||||
Extent.cpp
|
Extent.cpp
|
||||||
Inode.cpp
|
Inode.cpp
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
|
LeafDirectory.cpp
|
||||||
ShortDirectory.cpp
|
ShortDirectory.cpp
|
||||||
Volume.cpp
|
Volume.cpp
|
||||||
xfs.cpp
|
xfs.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user