xfs: Read Short Form Directories

We can now read short form directories.
Change-Id: I23eb6ef52e8bb07643213e603ed0185f536c649f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2952
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
CruxBox 2020-06-25 17:43:07 +05:30 committed by Adrien Destugues
parent 4639c4e898
commit a060fa968e
10 changed files with 187 additions and 60 deletions

View File

@ -1,6 +1,10 @@
/*
* Copyright 2017, Chế Gia Hy, cvghy116@gmail.com.
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008-2014, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de.
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
* All rights reserved. Distributed under the terms of the MIT License.
* This file may be used under the terms of the MIT License.
*/
#ifndef _DEBUG_H_
#define _DEBUG_H_
@ -8,8 +12,11 @@
// #define TRACE_XFS
#ifdef TRACE_XFS
#define TRACE(x...) dprintf("\n\33[34mxfs:\33[0m " x)
#define ASSERT(x) \
{ if (!(x)) kernel_debugger("xfs: assert failed: " #x "\n"); }
#else
#define TRACE(x...) ;
#define ASSERT(x) ;
#endif
#define ERROR(x...) dprintf("\n\33[34mxfs:\33[0m " x)

View File

@ -50,6 +50,7 @@ DirectoryIterator::Init()
return B_BAD_VALUE;
}
status_t
DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
{

View File

@ -174,6 +174,9 @@ Inode::GetFromDisk()
uint32 len = fVolume->InodeSize();
// Inode len to read (size of inode)
TRACE("AgNumber: (%d), AgRelativeIno: (%d), AgRelativeBlockNum: (%d),"
"Offset: (%d), len: (%d)\n", agNo, agInodeNo, agBlock, offset, len);
if (agNo > fVolume->AgCount()) {
ERROR("Inode::GetFromDisk : AG Number more than number of AGs");
return B_ENTRY_NOT_FOUND;
@ -184,7 +187,7 @@ Inode::GetFromDisk()
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
((uint64)(agNo * numberOfBlocksInAg) + agBlock));
xfs_daddr_t readPos = blockToRead*(BASICBLOCKSIZE) + offset;
xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE) + offset * len;
if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
ERROR("Inode::Inode(): IO Error");

View File

@ -30,9 +30,10 @@
// Gets the AG relative block number that contains inode
#define INO_TO_BLOCKOFFSET(id, volume) (id & INO_MASK(volume->InodesPerBlkLog()))
// Gets the offset into the block from the inode number
#define DIR_DFORK_PTR(dir_ino_ptr) (char*) dir_ino_ptr + DATA_FORK_OFFSET
#define DIR_DFORK_PTR(dir_ino_ptr) (void*) \
((char*) dir_ino_ptr + DATA_FORK_OFFSET)
#define DIR_AFORK_PTR(dir_ino_ptr) \
(XFS_DFORK_PTR + \
(void*)((char*)XFS_DFORK_PTR + \
((uint32)dir_ino_ptr->di_forkoff<<3))
#define DIR_AFORK_EXIST(dir_ino_ptr) dir_ino_ptr->di_forkoff!=0

View File

@ -12,8 +12,8 @@ ShortDirectory::ShortDirectory(Inode* inode)
fInode(inode),
fTrack(0)
{
memcpy(&fHeader,
DIR_DFORK_PTR(fInode->Buffer()), sizeof(xfs_dir2_sf_hdr_t));
fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer()));
}
@ -22,20 +22,76 @@ ShortDirectory::~ShortDirectory()
}
xfs_ino_t
ShortDirectory::GetParentIno()
bool
ShortDirectory::HasFileTypeField()
{
TRACE("GetParentIno: \n");
if (fHeader.i8count > 0)
return B_BENDIAN_TO_HOST_INT64(fHeader.parent.i8);
if (fInode->GetVolume()->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE)
return true;
else
return B_BENDIAN_TO_HOST_INT32(fHeader.parent.i4);
return false;
}
uint8
ShortDirectory::GetFileType(ShortFormEntry* entry)
{
ASSERT(HasFileTypeField() == true);
return entry->name[entry->namelen];
}
ShortFormEntry*
ShortDirectory::FirstEntry()
{
return (ShortFormEntry*) ((char*) fHeader + HeaderSize());
}
size_t
ShortDirectory::HeaderSize()
{
if (fHeader->i8count)
return sizeof(ShortFormHeader);
else
return sizeof(ShortFormHeader) - sizeof(uint32);
}
xfs_ino_t
ShortDirectory::GetIno(ShortFormInodeUnion* inum)
{
if (fHeader->i8count)
return B_BENDIAN_TO_HOST_INT64(inum->i8);
else
return B_BENDIAN_TO_HOST_INT32(inum->i4);
}
xfs_ino_t
ShortDirectory::GetEntryIno(ShortFormEntry* entry)
{
if (HasFileTypeField())
return GetIno((ShortFormInodeUnion*)(entry->name
+ entry->namelen + sizeof(uint8)));
else
return GetIno((ShortFormInodeUnion*)(entry->name + entry->namelen));
}
size_t
ShortDirectory::EntrySize(int namelen)
{
return sizeof(ShortFormEntry) + namelen
+ (HasFileTypeField()? sizeof(uint8) : 0)
+ (fHeader->i8count? sizeof(uint64):sizeof(uint32));
}
status_t
ShortDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
{
TRACE("ShortDirectory::Lookup\n");
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
xfs_ino_t rootIno = fInode->GetVolume()->Root();
if (strcmp(name, ".") == 0 || (rootIno == fInode->ID())) {
@ -43,13 +99,27 @@ ShortDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
TRACE("ShortDirectory:Lookup: name: \".\" ino: (%d)\n", *ino);
return B_OK;
}
*ino = GetParentIno();
*ino = GetIno(&fHeader->parent);
TRACE("Parent: (%d)\n", *ino);
return B_OK;
}
//TODO: Other entries
return B_NOT_SUPPORTED;
ShortFormEntry* entry = FirstEntry();
TRACE("Length of first entry: (%d),offset of first entry:"
"(%d)\n", entry->namelen, B_BENDIAN_TO_HOST_INT16(entry->offset.i));
int status;
for (int i = 0; i < fHeader->count; i++) {
status = strncmp(name, (char*)entry->name, entry->namelen);
if (status == 0) {
*ino = GetEntryIno(entry);
return B_OK;
}
entry = (ShortFormEntry*)
((char*) entry + EntrySize(entry->namelen));
}
return B_ENTRY_NOT_FOUND;
}
@ -73,12 +143,35 @@ ShortDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
return B_BUFFER_OVERFLOW;
*length = 3;
strlcpy(name, "..", *length + 1);
*ino = GetParentIno();
*ino = GetIno(&fHeader->parent);
fTrack = 2;
TRACE("ShortDirectory:GetNext: name: \"..\" ino: (%d)\n", *ino);
return B_OK;
}
// TODO: Now iterate through sf entries
return B_NOT_SUPPORTED;
ShortFormEntry* entry = FirstEntry();
TRACE("Length of first entry: (%d), offset of first entry:"
"(%d)\n", entry->namelen, B_BENDIAN_TO_HOST_INT16(entry->offset.i));
for (int i = 0; i < fHeader->count; i++) {
uint16 curOffset = B_BENDIAN_TO_HOST_INT16(entry->offset.i);
if (curOffset > fLastEntryOffset) {
if (entry->namelen > *length)
return B_BUFFER_OVERFLOW;
fLastEntryOffset = curOffset;
memcpy(name, entry->name, entry->namelen);
name[entry->namelen] = '\0';
*length = entry->namelen + 1;
*ino = GetEntryIno(entry);
TRACE("Entry found. Name: (%s), Length: (%ld),ino: (%ld)\n", name,
*length, *ino);
return B_OK;
}
entry = (ShortFormEntry*)((char*)entry + EntrySize(entry->namelen));
}
return B_ENTRY_NOT_FOUND;
}

View File

@ -5,52 +5,49 @@
#ifndef __SHORT_DIR_H__
#define __SHORT_DIR_H__
#include "Inode.h"
struct xfs_dir2_sf_off_t { uint8 i[2]; };
//offset into the literal area
/*
* offset into the literal area
* xfs_dir2_sf_off_t
*/
struct ShortFormOffset {
uint16 i;
} __attribute__((packed));
union xfs_dir2_inou_t {
//xfs_dir2_inou_t
union ShortFormInodeUnion {
uint64 i8;
uint32 i4;
};
} __attribute__((packed));
// Short form directory header
struct xfs_dir2_sf_hdr_t {
// xfs_dir2_sf_hdr_t
struct ShortFormHeader {
uint8 count;
// number of entries
uint8 i8count;
// # of 64bit inode entries
xfs_dir2_inou_t parent;
ShortFormInodeUnion parent;
// absolute inode # of parent
};
} __attribute__((packed));
/*
*The xfs_dir2_sf_entry is split into
* two parts because the entries size is variable
*/
struct xfs_dir2_sf_entry_t {
//xfs_dir2_sf_entry_t
struct ShortFormEntry {
uint8 namelen;
// length of the name, in bytes
xfs_dir2_sf_off_t offset;
ShortFormOffset offset;
// offset tag, for directory iteration
uint8 name[];
// name of directory entry
};
union xfs_dir2_sf_entry_inum_t {
struct xfs_ftype_inum{
uint8 ftype;
xfs_dir2_inou_t inumber;
};
struct xfs_inum{
xfs_dir2_inou_t inumber;
};
};
/*
* Following will be a single byte file type variable
* and inode number (64bits or 32 bits)
*/
} __attribute__((packed));
class ShortDirectory
@ -58,21 +55,24 @@ class ShortDirectory
public:
ShortDirectory(Inode* inode);
~ShortDirectory();
size_t HeaderSize();
bool HasFileTypeField();
uint8 GetFileType(ShortFormEntry* entry);
ShortFormEntry* FirstEntry();
xfs_ino_t GetIno(ShortFormInodeUnion* inum);
xfs_ino_t GetEntryIno(ShortFormEntry* entry);
size_t EntrySize(int namelen);
status_t GetNext(char* name, size_t* length,
xfs_ino_t* ino);
xfs_ino_t GetParentIno();
status_t Lookup(const char* name, size_t length,
xfs_ino_t* id);
private:
Inode* fInode;
xfs_dir2_sf_hdr_t fHeader;
xfs_dir2_sf_off_t fLastEntryOffset;
// offset into the literal area
ShortFormHeader* fHeader;
uint16 fLastEntryOffset;
// offset into the literal area
uint8 fTrack;
// Takes the values 0, 1 or 2 only
// Takes the values 0, 1 or 2
};
#endif
#endif

View File

@ -79,6 +79,9 @@ public:
uint8 SuperBlockFlags() const
{ return fSuperBlock.Flags(); }
uint32 SuperBlockFeatures2() const
{ return fSuperBlock.Features2(); }
#if 0
off_t NumBlocks() const
{ return fSuperBlock.NumBlocks(); }

View File

@ -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: root_id: (%d)\n", inode->ID());
TRACE("XFS_READ_STAT: id: (%d)\n", inode->ID());
stat->st_dev = inode->GetVolume()->ID();
stat->st_ino = inode->ID();
stat->st_nlink = 1;

View File

@ -24,10 +24,27 @@ XfsSuperBlock::IsValid() const
return false;
}
// Checking version 4 file system
ASSERT((Version() & 0x000f) == 4)
return true;
}
uint16
XfsSuperBlock::Version() const
{
return sb_versionnum;
}
uint32
XfsSuperBlock::Features2() const
{
return sb_features2;
}
uint32
XfsSuperBlock::BlockSize() const
{

View File

@ -55,6 +55,8 @@ public:
xfs_agnumber_t AgCount() const;
xfs_agblock_t AgBlocks() const;
uint8 Flags() const;
uint16 Version() const;
uint32 Features2() const;
private:
uint32 sb_magicnum;
@ -151,13 +153,13 @@ Superblock quota flags - sb_qflags
Extended v4 Superblock flags - sb_features2
*/
#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x0001
#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000001
// update global free space and inode on clean unmount
#define XFS_SB_VERSION2_ATTR2BIT 0x0002
#define XFS_SB_VERSION2_ATTR2BIT 0x00000002
// optimises the inode layout of ext-attr
#define XFS_SB_VERSION2_PARENTBIT 0x0004 /* Parent pointers */
#define XFS_SB_VERSION2_PROJID32BIT 0x0008 /* 32-bit project id */
#define XFS_SB_VERSION2_CRCBIT 0x0010 /* Metadata checksumming */
#define XFS_SB_VERSION2_FTYPE 0x0020
#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* Parent pointers */
#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32-bit project id */
#define XFS_SB_VERSION2_CRCBIT 0x00000100 /* Metadata checksumming */
#define XFS_SB_VERSION2_FTYPE 0x00000200
#endif