xfs: An attempt to read block directories

Map entries can be read, most structures are in place. Next is to
actually work with the directory block.

Change-Id: I700ee2e003bdef97838b1f06a95e53a5e4293658
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2981
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
CruxBox
2020-07-08 06:23:24 +00:00
committed by Adrien Destugues
parent a060fa968e
commit 9593c05ac5
11 changed files with 263 additions and 9 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
// #define TRACE_XFS
#define TRACE_XFS
#ifdef TRACE_XFS
#define TRACE(x...) dprintf("\n\33[34mxfs:\33[0m " x)
#define ASSERT(x) \
@@ -30,6 +30,14 @@ DirectoryIterator::Init()
return B_NO_MEMORY;
return B_OK;
}
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
// TODO: Only working with Block directories, not leaf.
fExtentDir = new(std::nothrow) Extent(fInode);
if (fExtentDir == NULL)
return B_NO_MEMORY;
status_t status = fExtentDir->Init();
return status;
}
/* Return B_OK so even if the shortform directory has an extent directory
* we can atleast still list the shortform directory
@@ -87,6 +95,10 @@ DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
//TODO: Reading from extent based dirs
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
TRACE("Iterator:Lookup: EXTENTS");
#if 0
status_t status = fExtentDir->Lookup(name, length, ino);
return status;
#endif
return B_NOT_SUPPORTED;
}
@@ -6,6 +6,7 @@
#define _DIRECTORY_H_
#include "Extent.h"
#include "Inode.h"
#include "ShortDirectory.h"
@@ -29,6 +30,8 @@ private:
Inode* fInode;
ShortDirectory* fShortDir;
// Short form Directory type
Extent* fExtentDir;
// Extent form Directory type
};
@@ -0,0 +1,79 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Extent.h"
Extent::Extent(Inode* inode)
:
fInode(inode)
{
}
void
Extent::FillMapEntry(void* pointerToMap)
{
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("Extent::Init: startoff:(%ld), startblock:(%ld), blockcount:(%ld),"
"state:(%d)\n",
fMap->br_startoff,
fMap->br_startblock,
fMap->br_blockcount,
fMap->br_state
);
}
status_t
Extent::Init()
{
fMap = new(std::nothrow) ExtentMapEntry;
if (fMap == NULL)
return B_NO_MEMORY;
ASSERT(BlockType() == true);
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer());
FillMapEntry(pointerToMap);
return B_NOT_SUPPORTED;
}
ExtentBlockTail*
Extent::BlockTail(ExtentDataHeader* header)
{
return (ExtentBlockTail*)
((char*)header + fInode->DirBlockSize() - sizeof(ExtentBlockTail));
}
ExtentLeafEntry*
Extent::BlockFirstLeaf(ExtentBlockTail* tail)
{
return (ExtentLeafEntry*)tail - B_BENDIAN_TO_HOST_INT32(tail->count);
}
bool
Extent::BlockType()
{
bool status = true;
if (fInode->NoOfBlocks() != 1)
status = false;
if (fInode->Size() != fInode->DirBlockSize())
status = false;
return status;
}
@@ -0,0 +1,116 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _EXTENT_H_
#define _EXTENT_H_
#include "Inode.h"
#include "system_dependencies.h"
#define DIR2_BLOCK_HEADER_MAGIC 0x58443242
// for v4 system
#define XFS_DIR2_DATA_FD_COUNT 3
#define EXTENT_REC_SIZE 128
#define MASK(n) ((1UL << n) - 1)
// xfs_exntst_t
enum ExtentState {
XFS_EXT_NORM,
XFS_EXT_UNWRITTEN,
XFS_EXT_INVALID
};
// xfs_dir2_data_free_t
struct FreeRegion {
uint16 offset;
uint16 length;
};
// xfs_dir2_data_hdr_t
struct ExtentDataHeader {
uint32 magic;
FreeRegion bestfree[XFS_DIR2_DATA_FD_COUNT];
};
// xfs_dir2_data_entry_t
struct ExtentDataEntry {
xfs_ino_t inumber;
uint8 namelen;
uint8 name[];
// Followed by a file type (8bit) if applicable and a 16bit tag
// tag is the offset from start of the block
};
// xfs_dir2_data_unused_t
struct ExtentUnusedEntry {
uint16 freetag;
// takes the value 0xffff
uint16 length;
// freetag+length overrides the inumber of an entry
uint16 tag;
};
// xfs_dir2_leaf_entry_t
struct ExtentLeafEntry {
uint32 hashval;
uint32 address;
// offset into block after >> 3
};
// xfs_dir2_block_tail_t
struct ExtentBlockTail {
uint32 count;
// # of entries in leaf
uint32 stale;
// # of free leaf entries
};
struct ExtentMapEntry {
xfs_fileoff_t br_startoff;
// logical file block offset
xfs_fsblock_t br_startblock;
// absolute block number
xfs_filblks_t br_blockcount;
// # of blocks
uint8 br_state;
// state of the extent
};
class Extent
{
public:
Extent(Inode* inode);
~Extent();
status_t Init();
bool BlockType();
void FillMapEntry(void* pointerToMap);
ExtentDataHeader* BlockHeader();
ExtentBlockTail* BlockTail(ExtentDataHeader* header);
ExtentLeafEntry* BlockFirstLeaf(ExtentBlockTail* tail);
xfs_ino_t GetIno();
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* fMap;
char* fBlockBuffer;
// This isn't inode data. It holds the directory block.
};
#endif
+37 -1
View File
@@ -175,7 +175,8 @@ Inode::GetFromDisk()
// Inode len to read (size of inode)
TRACE("AgNumber: (%d), AgRelativeIno: (%d), AgRelativeBlockNum: (%d),"
"Offset: (%d), len: (%d)\n", agNo, agInodeNo, agBlock, offset, len);
"Offset: (%d), len: (%d)\n", agNo,
agRelativeInodeNo, agBlock, offset, len);
if (agNo > fVolume->AgCount()) {
ERROR("Inode::GetFromDisk : AG Number more than number of AGs");
@@ -206,3 +207,38 @@ Inode::~Inode()
delete fBuffer;
delete fNode;
}
uint32
hashfunction(const char* name, int length)
{
uint32 hashVal = 0;
int lengthCovered = 0;
int index = 0;
if (length >= 4) {
for (; index <= length; index+=4)
{
lengthCovered = index;
hashVal = (name[index] << 21) ^ (name[index+1] << 14)
^ (name[index+2] << 7) ^ (name[index+3] << 0)
^ ((hashVal << 28) | (hashVal >> (4)));
}
}
int leftToCover = length - lengthCovered;
if (leftToCover == 3) {
hashVal = (name[index] << 14) ^ (name[index+1] << 7)
^ (name[index+2] << 0) ^ ((hashVal << 21) | (hashVal >> (11)));
}
if (leftToCover == 2) {
hashVal = (name[index] << 7) ^ (name[index+1] << 0)
^ ((hashVal << 14) | (hashVal >> (32 - 14)));
}
if (leftToCover == 1) {
hashVal = (name[index] << 0)
^ ((hashVal << 7) | (hashVal >> (32 - 7)));
}
return hashVal;
}
@@ -38,6 +38,10 @@
#define DIR_AFORK_EXIST(dir_ino_ptr) dir_ino_ptr->di_forkoff!=0
uint32
hashfunction(const char* name, int length);
struct xfs_timestamp_t {
int32 t_sec;
int32 t_nsec;
@@ -159,6 +163,9 @@ public:
xfs_fsize_t Size() const { return fNode->Size(); }
uint32 DirBlockSize() const
{ return fVolume->DirBlockSize(); }
void GetChangeTime(struct timespec& timestamp) const
{ fNode->GetChangeTime(timestamp); }
+2 -1
View File
@@ -22,6 +22,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) src libs uuid ] : true ;
local xfsSources =
DeviceOpener.cpp
Directory.cpp
Extent.cpp
Inode.cpp
kernel_cpp.cpp
kernel_interface.cpp
@@ -42,4 +43,4 @@ SEARCH on [ FGristFiles DeviceOpener.cpp ]
= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;
SEARCH on [ FGristFiles kernel_cpp.cpp ]
= [ FDirName $(HAIKU_TOP) src system kernel util ] ;
= [ FDirName $(HAIKU_TOP) src system kernel util ] ;
@@ -152,7 +152,7 @@ xfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
_node->ops = &gxfsVnodeOps;
*_type = inode->Mode();
*_flags = 0;
TRACE("(%d)\n", inode->ID());
TRACE("(%ld)\n", inode->ID());
return B_OK;
}
@@ -230,7 +230,7 @@ xfs_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name,
return status;
}
TRACE("XFS_LOOKUP: ID: (%d)\n", *_vnodeID);
TRACE("XFS_LOOKUP: ID: (%ld)\n", *_vnodeID);
status = get_vnode(volume->FSVolume(), *_vnodeID, NULL);
TRACE("get_vnode status: (%d)\n", status);
return status;
@@ -249,7 +249,7 @@ static status_t
xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
{
Inode* inode = (Inode*)_node->private_node;
TRACE("XFS_READ_STAT: id: (%d)\n", inode->ID());
TRACE("XFS_READ_STAT: id: (%ld)\n", inode->ID());
stat->st_dev = inode->GetVolume()->ID();
stat->st_ino = inode->ID();
stat->st_nlink = 1;
@@ -351,7 +351,7 @@ static status_t
xfs_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie)
{
Inode* inode = (Inode*)_node->private_node;
TRACE("XFS_OPEN_DIR: (%d)\n", inode->ID());
TRACE("XFS_OPEN_DIR: (%ld)\n", inode->ID());
if (!inode->IsDirectory())
return B_NOT_A_DIRECTORY;
@@ -29,10 +29,9 @@ typedef uint32 xfs_dablk_t; // block number for directories
typedef uint32 xfs_dahash_t; // hash of a directory file name
// or extended attribute name
typedef uint64 xfs_fsblock_t; // filesystem block number combining AG number
// and block offset into the AG
typedef uint64 xfs_rfsblock_t; // raw filesystem block number
typedef uint64 xfs_rtblock_t; // extent number in the real-time sub-volume
typedef uint64 xfs_filoff_t; // block offset into a file
typedef uint64 xfs_fileoff_t; // block offset into a file
typedef uint64 xfs_filblks_t; // block count for a file
typedef int64 xfs_fsize_t; // byte size of a file
@@ -41,6 +41,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) src tools fs_shell ] ;
local xfsSource =
DeviceOpener.cpp
Directory.cpp
Extent.cpp
Inode.cpp
kernel_interface.cpp
ShortDirectory.cpp