xfs: version 3 Inodes and shortform directory
- Implemented xfs v5 inodes (known as v3 inodes) and necessary metadata integrity checks - Implemented correct data fork pointer which handles both xfs v4 and v5 directories - We can now read inodes and shortform directories for both xfs versions completely fine Change-Id: I8a75ec1dc663d567d3bf6db64be4a27b55d709b3 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5396 Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
e511f0c1cb
commit
6c478b54f6
@ -32,7 +32,7 @@ TreeDirectory::TreeDirectory(Inode* inode)
|
||||
}
|
||||
|
||||
memcpy((void*)fRoot,
|
||||
DIR_DFORK_PTR(fInode->Buffer()), sizeof(BlockInDataFork));
|
||||
DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()), sizeof(BlockInDataFork));
|
||||
|
||||
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
|
||||
fPathForLeaves[i].blockData = NULL;
|
||||
@ -85,7 +85,7 @@ TreeDirectory::MaxRecordsPossibleRoot()
|
||||
lengthOfDataFork = fInode->ForkOffset() << 3;
|
||||
if (fInode->ForkOffset() == 0) {
|
||||
lengthOfDataFork = fInode->GetVolume()->InodeSize()
|
||||
- INODE_CORE_UNLINKED_SIZE;
|
||||
- fInode->CoreInodeSize();
|
||||
}
|
||||
|
||||
lengthOfDataFork -= sizeof(BlockInDataFork);
|
||||
@ -122,7 +122,8 @@ TreePointer*
|
||||
TreeDirectory::GetPtrFromRoot(int pos)
|
||||
{
|
||||
return (TreePointer*)
|
||||
((char*)DIR_DFORK_PTR(fInode->Buffer()) + GetPtrOffsetIntoRoot(pos));
|
||||
((char*)DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize())
|
||||
+ GetPtrOffsetIntoRoot(pos));
|
||||
}
|
||||
|
||||
|
||||
@ -146,7 +147,7 @@ TreeKey*
|
||||
TreeDirectory::GetKeyFromRoot(int pos)
|
||||
{
|
||||
off_t offset = (pos - 1) * KeySize();
|
||||
char* base = (char*)DIR_DFORK_PTR(fInode->Buffer())
|
||||
char* base = (char*)DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize())
|
||||
+ sizeof(BlockInDataFork);
|
||||
return (TreeKey*) (base + offset);
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ Extent::Init()
|
||||
return B_NO_MEMORY;
|
||||
|
||||
ASSERT(IsBlockType() == true);
|
||||
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer());
|
||||
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize());
|
||||
FillMapEntry(pointerToMap);
|
||||
ASSERT(fMap->br_blockcount == 1);
|
||||
//TODO: This is always true for block directories
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022, Raghav Sharma, raghavself28@gmail.com
|
||||
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@ -6,6 +7,7 @@
|
||||
|
||||
#include "Inode.h"
|
||||
#include "BPlusTree.h"
|
||||
#include "Checksum.h"
|
||||
|
||||
void
|
||||
xfs_inode_t::SwapEndian()
|
||||
@ -34,6 +36,13 @@ xfs_inode_t::SwapEndian()
|
||||
di_flags = B_BENDIAN_TO_HOST_INT16(di_flags);
|
||||
di_gen = B_BENDIAN_TO_HOST_INT32(di_gen);
|
||||
di_next_unlinked = B_BENDIAN_TO_HOST_INT32(di_next_unlinked);
|
||||
di_changecount = B_BENDIAN_TO_HOST_INT64(di_changecount);
|
||||
di_lsn = B_BENDIAN_TO_HOST_INT64(di_lsn);
|
||||
di_flags2 = B_BENDIAN_TO_HOST_INT64(di_flags2);
|
||||
di_cowextsize = B_BENDIAN_TO_HOST_INT64(di_cowextsize);
|
||||
di_crtime.t_sec = B_BENDIAN_TO_HOST_INT32(di_crtime.t_sec);
|
||||
di_crtime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_crtime.t_nsec);
|
||||
di_ino = B_BENDIAN_TO_HOST_INT64(di_ino);
|
||||
}
|
||||
|
||||
|
||||
@ -103,6 +112,14 @@ xfs_inode_t::GetChangeTime(struct timespec& stamp)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xfs_inode_t::GetCreationTime(struct timespec& stamp)
|
||||
{
|
||||
stamp.tv_sec = di_crtime.t_sec;
|
||||
stamp.tv_nsec = di_crtime.t_nsec;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
xfs_inode_t::NLink() const
|
||||
{
|
||||
@ -148,6 +165,201 @@ Inode::Inode(Volume* volume, xfs_ino_t id)
|
||||
}
|
||||
|
||||
|
||||
//Convert inode mode to directory entry filetype
|
||||
unsigned char
|
||||
Inode::XfsModeToFtype() const
|
||||
{
|
||||
switch (Mode() & S_IFMT) {
|
||||
case S_IFREG:
|
||||
return XFS_DIR3_FT_REG_FILE;
|
||||
case S_IFDIR:
|
||||
return XFS_DIR3_FT_DIR;
|
||||
case S_IFCHR:
|
||||
return XFS_DIR3_FT_CHRDEV;
|
||||
case S_IFBLK:
|
||||
return XFS_DIR3_FT_BLKDEV;
|
||||
case S_IFIFO:
|
||||
return XFS_DIR3_FT_FIFO;
|
||||
case S_IFSOCK:
|
||||
return XFS_DIR3_FT_SOCK;
|
||||
case S_IFLNK:
|
||||
return XFS_DIR3_FT_SYMLINK;
|
||||
default:
|
||||
return XFS_DIR3_FT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Inode::VerifyFork(int whichFork) const
|
||||
{
|
||||
uint32 di_nextents = XFS_DFORK_NEXTENTS(fNode, whichFork);
|
||||
|
||||
switch (XFS_DFORK_FORMAT(fNode, whichFork)) {
|
||||
case XFS_DINODE_FMT_LOCAL:
|
||||
if (whichFork == XFS_DATA_FORK) {
|
||||
if (S_ISREG(Mode()))
|
||||
return false;
|
||||
if (Size() > (xfs_fsize_t) DFORK_SIZE(fNode, fVolume, whichFork))
|
||||
return false;
|
||||
}
|
||||
if (di_nextents)
|
||||
return false;
|
||||
break;
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
if (di_nextents > DFORK_MAXEXT(fNode, fVolume, whichFork))
|
||||
return false;
|
||||
break;
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
if (whichFork == XFS_ATTR_FORK) {
|
||||
if (di_nextents > MAXAEXTNUM)
|
||||
return false;
|
||||
} else if (di_nextents > MAXEXTNUM) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Inode::VerifyForkoff() const
|
||||
{
|
||||
switch(Format()) {
|
||||
case XFS_DINODE_FMT_DEV:
|
||||
if (fNode->di_forkoff != (ROUNDUP(sizeof(uint32), 8) >> 3))
|
||||
return false;
|
||||
break;
|
||||
case XFS_DINODE_FMT_LOCAL:
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
if (fNode->di_forkoff >= (LITINO(fVolume) >> 3))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Inode::VerifyInode() const
|
||||
{
|
||||
if(fNode->di_magic != INODE_MAGIC) {
|
||||
ERROR("Bad inode magic number");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if inode version is valid
|
||||
if(fNode->Version() < 1 || fNode->Version() > 3) {
|
||||
ERROR("Bad inode version");
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify version 3 inodes first
|
||||
if(fNode->Version() == 3) {
|
||||
|
||||
if(!HAS_V3INODES(fVolume)) {
|
||||
ERROR("xfs v4 doesn't have v3 inodes");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!xfs_verify_cksum(fBuffer, fVolume->InodeSize(), INODE_CRC_OFF)) {
|
||||
ERROR("Inode is corrupted");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fNode->di_ino != fId) {
|
||||
ERROR("Incorrect inode number");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO : uuid verification
|
||||
}
|
||||
|
||||
if(fNode->di_size & (1ULL << 63)) {
|
||||
ERROR("Invalid EOF of inode");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Mode() && XfsModeToFtype() == XFS_DIR3_FT_UNKNOWN) {
|
||||
ERROR("Entry points to an unknown inode type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!VerifyForkoff()) {
|
||||
ERROR("Invalid inode fork offset");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for appropriate data fork formats for the mode
|
||||
switch (Mode() & S_IFMT) {
|
||||
case S_IFIFO:
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
case S_IFSOCK:
|
||||
if (fNode->di_format != XFS_DINODE_FMT_DEV)
|
||||
return false;
|
||||
break;
|
||||
case S_IFREG:
|
||||
case S_IFLNK:
|
||||
case S_IFDIR:
|
||||
if (!VerifyFork(XFS_DATA_FORK)) {
|
||||
ERROR("Invalid data fork in inode");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
// Uninitialized inode is fine
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fNode->di_forkoff) {
|
||||
if (!VerifyFork(XFS_ATTR_FORK)) {
|
||||
ERROR("Invalid attribute fork in inode");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
If there is no fork offset, this may be a freshly-made inode
|
||||
in a new disk cluster, in which case di_aformat is zeroed.
|
||||
Otherwise, such an inode must be in EXTENTS format; this goes
|
||||
for freed inodes as well.
|
||||
*/
|
||||
switch (fNode->di_aformat) {
|
||||
case 0:
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fNode->di_anextents)
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO : Add reflink and big-timestamps check using di_flags2
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
Inode::CoreInodeSize() const
|
||||
{
|
||||
if (Version() == 3)
|
||||
return sizeof(struct xfs_inode_t);
|
||||
|
||||
return offsetof(struct xfs_inode_t, di_crc);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Init()
|
||||
{
|
||||
@ -162,7 +374,7 @@ Inode::Init()
|
||||
|
||||
status_t status = GetFromDisk();
|
||||
if (status == B_OK) {
|
||||
if (fNode->di_magic == INODE_MAGIC) {
|
||||
if (VerifyInode()) {
|
||||
TRACE("Init(): Inode successfully read.\n");
|
||||
status = B_OK;
|
||||
} else {
|
||||
@ -186,7 +398,11 @@ Inode::~Inode()
|
||||
bool
|
||||
Inode::HasFileTypeField() const
|
||||
{
|
||||
return fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE;
|
||||
if((fNode->Version() == 3 && fVolume->XfsHasIncompatFeature())
|
||||
|| (fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -219,7 +435,7 @@ status_t
|
||||
Inode::ReadExtentsFromExtentBasedInode()
|
||||
{
|
||||
fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()];
|
||||
char* dataStart = (char*) DIR_DFORK_PTR(Buffer());
|
||||
char* dataStart = (char*) DIR_DFORK_PTR(Buffer(), CoreInodeSize());
|
||||
uint64 wrappedExtent[2];
|
||||
for (int i = 0; i < DataExtentsCount(); i++) {
|
||||
wrappedExtent[0] = *(uint64*)(dataStart);
|
||||
@ -239,7 +455,7 @@ Inode::MaxRecordsPossibleInTreeRoot()
|
||||
lengthOfDataFork = ForkOffset() << 3;
|
||||
else if(ForkOffset() == 0) {
|
||||
lengthOfDataFork = GetVolume()->InodeSize()
|
||||
- INODE_CORE_UNLINKED_SIZE;
|
||||
- CoreInodeSize();
|
||||
}
|
||||
|
||||
lengthOfDataFork -= sizeof(BlockInDataFork);
|
||||
@ -260,7 +476,7 @@ TreePointer*
|
||||
Inode::GetPtrFromRoot(int pos)
|
||||
{
|
||||
return (TreePointer*)
|
||||
((char*)DIR_DFORK_PTR(Buffer()) + GetPtrOffsetIntoRoot(pos));
|
||||
((char*)DIR_DFORK_PTR(Buffer(), CoreInodeSize()) + GetPtrOffsetIntoRoot(pos));
|
||||
}
|
||||
|
||||
|
||||
@ -342,7 +558,7 @@ Inode::ReadExtentsFromTreeInode()
|
||||
if (root == NULL)
|
||||
return B_NO_MEMORY;
|
||||
memcpy((void*)root,
|
||||
DIR_DFORK_PTR(Buffer()), sizeof(BlockInDataFork));
|
||||
DIR_DFORK_PTR(Buffer(), CoreInodeSize()), sizeof(BlockInDataFork));
|
||||
|
||||
size_t maxRecords = MaxRecordsPossibleInTreeRoot();
|
||||
TRACE("Maxrecords: (%" B_PRIuSIZE ")\n", maxRecords);
|
||||
@ -550,7 +766,11 @@ Inode::GetFromDisk()
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
memcpy(fNode, fBuffer, INODE_CORE_UNLINKED_SIZE);
|
||||
if(fVolume->IsVersion5())
|
||||
memcpy(fNode, fBuffer, sizeof(xfs_inode_t));
|
||||
else
|
||||
memcpy(fNode, fBuffer, INODE_CRC_OFF);
|
||||
|
||||
fNode->SwapEndian();
|
||||
|
||||
return B_OK;
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022, Raghav Sharma, raghavself28@gmail.com
|
||||
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@ -11,38 +12,80 @@
|
||||
#include "xfs_types.h"
|
||||
|
||||
|
||||
#define INODE_MAGIC 0x494e
|
||||
#define INODE_MINSIZE_LOG 8
|
||||
#define INODE_MAXSIZE_LOG 11
|
||||
#define INODE_CORE_SIZE 96
|
||||
#define INODE_CORE_UNLINKED_SIZE 100
|
||||
// Inode core but with unlinked pointer
|
||||
#define DATA_FORK_OFFSET 0x64
|
||||
// For v4 FS
|
||||
#define INO_MASK(x) ((1ULL << (x)) - 1)
|
||||
#define INODE_MAGIC 0x494e
|
||||
#define INODE_MINSIZE_LOG 8
|
||||
#define INODE_MAXSIZE_LOG 11
|
||||
#define INODE_MIN_SIZE (1 << INODE_MINSIZE_LOG)
|
||||
#define INODE_MAX_SIZE (1 << INODE_MAXSIZE_LOG)
|
||||
#define INODE_CRC_OFF offsetof(struct xfs_inode_t, di_crc)
|
||||
#define MAXAEXTNUM ((xfs_aextnum_t) 0x7fff)
|
||||
#define MAXEXTNUM ((xfs_extnum_t) 0x7fffffff)
|
||||
|
||||
// Does fs volume has v3 inodes?
|
||||
#define HAS_V3INODES(volume) (volume->IsVersion5() ? 1 : 0 )
|
||||
|
||||
// Inode size for given fs
|
||||
#define DINODE_SIZE(volume) \
|
||||
(HAS_V3INODES(volume) ? \
|
||||
sizeof(struct xfs_inode_t) : offsetof(struct xfs_inode_t, di_crc))
|
||||
#define LITINO(volume) \
|
||||
((volume)->InodeSize() - DINODE_SIZE(volume))
|
||||
|
||||
// inode data and attribute fork sizes
|
||||
#define DFORK_BOFF(ino) ((int)((ino)->di_forkoff << 3))
|
||||
|
||||
#define DFORK_DSIZE(ino, volume) \
|
||||
((ino)->di_forkoff ? DFORK_BOFF(ino) : LITINO(volume))
|
||||
#define DFORK_ASIZE(ino, volume) \
|
||||
((ino)->di_forkoff ? LITINO(volume) - DFORK_BOFF(ino) : 0)
|
||||
#define DFORK_SIZE(ino, volume, w) \
|
||||
((w) == XFS_DATA_FORK ? \
|
||||
DFORK_DSIZE(ino, volume) : DFORK_ASIZE(ino, volume))
|
||||
|
||||
|
||||
#define INO_MASK(x) ((1ULL << (x)) - 1)
|
||||
// Gets 2^x - 1
|
||||
#define INO_TO_AGNO(id, volume) (xfs_agnumber_t)id >> (volume->AgInodeBits())
|
||||
#define INO_TO_AGNO(id, volume) ((xfs_agnumber_t)id >> (volume->AgInodeBits()))
|
||||
// Gets AG number from inode number
|
||||
#define INO_TO_AGINO(id, bits) (uint32) id & INO_MASK(bits);
|
||||
#define INO_TO_AGINO(id, bits) ((uint32) id & INO_MASK(bits))
|
||||
// Gets the AG relative inode number
|
||||
#define INO_TO_AGBLOCK(id, volume) \
|
||||
(id >> (volume->InodesPerBlkLog())) \
|
||||
& (INO_MASK(volume->AgBlocksLog()))
|
||||
// Gets the AG relative block number that contains inode
|
||||
#define INO_TO_BLOCKOFFSET(id, volume) (id & INO_MASK(volume->InodesPerBlkLog()))
|
||||
#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) (void*) \
|
||||
|
||||
// Data and attribute fork pointers
|
||||
#define DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) (void*) \
|
||||
((char*) dir_ino_ptr + DATA_FORK_OFFSET)
|
||||
#define DIR_AFORK_PTR(dir_ino_ptr, forkoff) \
|
||||
(void*)((char*)DIR_DFORK_PTR(dir_ino_ptr) + \
|
||||
#define DIR_AFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET, forkoff) \
|
||||
(void*)((char*)DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) + \
|
||||
(((uint32)forkoff)<<3))
|
||||
#define DIR_AFORK_EXIST(dir_ino_ptr) dir_ino_ptr->di_forkoff!=0
|
||||
#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 DIR_AFORK_EXIST(dir_ino_ptr) (dir_ino_ptr->di_forkoff != 0)
|
||||
|
||||
#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 BLOCKNO_FROM_POSITION(n, volume) \
|
||||
((n) >> (volume->BlockLog()))
|
||||
#define BLOCKOFFSET_FROM_POSITION(n, inode) ((n) & (inode->BlockSize() - 1))
|
||||
#define BLOCKOFFSET_FROM_POSITION(n, inode) ((n) & (inode->BlockSize() - 1))
|
||||
|
||||
#define MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL))
|
||||
|
||||
// Inode fork identifiers
|
||||
#define XFS_DATA_FORK 0
|
||||
#define XFS_ATTR_FORK 1
|
||||
|
||||
#define XFS_DFORK_FORMAT(ino, w) \
|
||||
((w) == XFS_DATA_FORK ? (ino)->di_format : (ino)->di_aformat)
|
||||
|
||||
#define XFS_DFORK_NEXTENTS(ino, w) \
|
||||
((w) == XFS_DATA_FORK ? (ino)->di_nextents : (ino)->di_anextents)
|
||||
|
||||
#define DFORK_MAXEXT(ino, volume, w) \
|
||||
(DFORK_SIZE(ino, volume, w) / (2 * sizeof(uint64)))
|
||||
|
||||
|
||||
// xfs_bmdr_block
|
||||
@ -102,6 +145,33 @@ enum xfs_dinode_fmt_t {
|
||||
// Not used
|
||||
};
|
||||
|
||||
|
||||
#define XFS_INODE_FORMAT_STR \
|
||||
{ XFS_DINODE_FMT_DEV, "dev" }, \
|
||||
{ XFS_DINODE_FMT_LOCAL, "local" }, \
|
||||
{ XFS_DINODE_FMT_EXTENTS, "extent" }, \
|
||||
{ XFS_DINODE_FMT_BTREE, "btree" }, \
|
||||
{ XFS_DINODE_FMT_UUID, "uuid" }
|
||||
|
||||
|
||||
/*
|
||||
Dirents in version 3 directories have a file type field. Additions to this
|
||||
list are an on-disk format change, requiring feature bits. Valid values
|
||||
are as follows:
|
||||
*/
|
||||
#define XFS_DIR3_FT_UNKNOWN 0
|
||||
#define XFS_DIR3_FT_REG_FILE 1
|
||||
#define XFS_DIR3_FT_DIR 2
|
||||
#define XFS_DIR3_FT_CHRDEV 3
|
||||
#define XFS_DIR3_FT_BLKDEV 4
|
||||
#define XFS_DIR3_FT_FIFO 5
|
||||
#define XFS_DIR3_FT_SOCK 6
|
||||
#define XFS_DIR3_FT_SYMLINK 7
|
||||
#define XFS_DIR3_FT_WHT 8
|
||||
|
||||
#define XFS_DIR3_FT_MAX 9
|
||||
|
||||
|
||||
/*
|
||||
* The xfs_ino_t is the same for all types of inodes, the data and attribute
|
||||
* fork might be different and that is to be handled accordingly.
|
||||
@ -114,6 +184,8 @@ struct xfs_inode_t {
|
||||
timestamp);
|
||||
void GetChangeTime(struct timespec& timestamp);
|
||||
void GetAccessTime(struct timespec& timestamp);
|
||||
void GetCreationTime(struct timespec& timestamp);
|
||||
|
||||
int8 Format() const;
|
||||
// The format of the inode
|
||||
xfs_fsize_t Size() const;
|
||||
@ -160,17 +232,97 @@ struct xfs_inode_t {
|
||||
uint16 di_flags;
|
||||
uint32 di_gen;
|
||||
uint32 di_next_unlinked;
|
||||
|
||||
// XFS Version 5
|
||||
|
||||
uint32 di_crc;
|
||||
uint64 di_changecount;
|
||||
uint64 di_lsn;
|
||||
uint64 di_flags2;
|
||||
uint32 di_cowextsize;
|
||||
uint8 di_pad2[12];
|
||||
|
||||
// fields only written to during inode creation
|
||||
|
||||
xfs_timestamp_t di_crtime;
|
||||
uint64 di_ino;
|
||||
uuid_t di_uuid;
|
||||
};
|
||||
|
||||
|
||||
// Values for di_flags
|
||||
#define XFS_DIFLAG_REALTIME_BIT 0 // file's blocks come from rt area
|
||||
#define XFS_DIFLAG_PREALLOC_BIT 1 // file space has been preallocated
|
||||
#define XFS_DIFLAG_NEWRTBM_BIT 2 // for rtbitmap inode, new format
|
||||
#define XFS_DIFLAG_IMMUTABLE_BIT 3 // inode is immutable
|
||||
#define XFS_DIFLAG_APPEND_BIT 4 // inode is append-only
|
||||
#define XFS_DIFLAG_SYNC_BIT 5 // inode is written synchronously
|
||||
#define XFS_DIFLAG_NOATIME_BIT 6 // do not update atime
|
||||
#define XFS_DIFLAG_NODUMP_BIT 7 // do not dump
|
||||
#define XFS_DIFLAG_RTINHERIT_BIT 8 // create with realtime bit set
|
||||
#define XFS_DIFLAG_PROJINHERIT_BIT 9 // create with parents projid
|
||||
#define XFS_DIFLAG_NOSYMLINKS_BIT 10 // disallow symlink creation
|
||||
#define XFS_DIFLAG_EXTSIZE_BIT 11 // inode extent size allocator hint
|
||||
#define XFS_DIFLAG_EXTSZINHERIT_BIT 12 // inherit inode extent size
|
||||
#define XFS_DIFLAG_NODEFRAG_BIT 13 // do not reorganize/defragment
|
||||
#define XFS_DIFLAG_FILESTREAM_BIT 14 // use filestream allocator
|
||||
|
||||
#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT)
|
||||
#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT)
|
||||
#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT)
|
||||
#define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT)
|
||||
#define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT)
|
||||
#define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT)
|
||||
#define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT)
|
||||
#define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT)
|
||||
#define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT)
|
||||
#define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT)
|
||||
#define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
|
||||
#define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT)
|
||||
#define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
|
||||
#define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT)
|
||||
#define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT)
|
||||
|
||||
#define XFS_DIFLAG_ANY \
|
||||
(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
|
||||
XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
|
||||
XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
|
||||
XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
|
||||
XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)
|
||||
|
||||
/*
|
||||
Values for di_flags2 These start by being exposed to userspace in the upper
|
||||
16 bits of the XFS_XFLAG_S range.
|
||||
*/
|
||||
#define XFS_DIFLAG2_DAX_BIT 0 // use DAX for this inode
|
||||
#define XFS_DIFLAG2_REFLINK_BIT 1 // file's blocks may be shared
|
||||
#define XFS_DIFLAG2_COWEXTSIZE_BIT 2 // copy on write extent size hint
|
||||
#define XFS_DIFLAG2_BIGTIME_BIT 3 // big timestamps
|
||||
|
||||
#define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT)
|
||||
#define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT)
|
||||
#define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
|
||||
#define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT)
|
||||
|
||||
#define XFS_DIFLAG2_ANY \
|
||||
(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
|
||||
XFS_DIFLAG2_BIGTIME)
|
||||
|
||||
class Inode {
|
||||
public:
|
||||
Inode(Volume* volume, xfs_ino_t id);
|
||||
~Inode();
|
||||
|
||||
status_t Init();
|
||||
|
||||
xfs_ino_t ID() const { return fId; }
|
||||
|
||||
bool VerifyInode() const;
|
||||
|
||||
bool VerifyForkoff() const;
|
||||
|
||||
bool VerifyFork(int WhichFork) const;
|
||||
|
||||
bool IsDirectory() const
|
||||
{ return S_ISDIR(Mode()); }
|
||||
|
||||
@ -209,6 +361,8 @@ public:
|
||||
uint32 BlockSize() const
|
||||
{ return fVolume->BlockSize(); }
|
||||
|
||||
uint32 CoreInodeSize() const;
|
||||
|
||||
void GetChangeTime(struct timespec& timestamp) const
|
||||
{ fNode->GetChangeTime(timestamp); }
|
||||
|
||||
@ -219,6 +373,10 @@ public:
|
||||
void GetAccessTime(struct timespec& timestamp) const
|
||||
{ fNode->GetAccessTime(timestamp); }
|
||||
|
||||
void GetCreationTime(struct timespec& timestamp) const
|
||||
{ fNode->GetCreationTime(timestamp); }
|
||||
|
||||
unsigned char XfsModeToFtype() const;
|
||||
status_t CheckPermissions(int accessMode) const;
|
||||
uint32 UserId() const { return fNode->UserId(); }
|
||||
uint32 GroupId() const { return fNode->GroupId(); }
|
||||
|
@ -74,7 +74,7 @@ LeafDirectory::IsLeafType()
|
||||
void
|
||||
LeafDirectory::FillMapEntry(int num, ExtentMapEntry* fMap)
|
||||
{
|
||||
void* directoryFork = DIR_DFORK_PTR(fInode->Buffer());
|
||||
void* directoryFork = DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize());
|
||||
|
||||
uint64* pointerToMap = (uint64*)((char*)directoryFork + num * EXTENT_SIZE);
|
||||
uint64 firstHalf = pointerToMap[0];
|
||||
|
@ -62,7 +62,7 @@ NodeDirectory::IsNodeType()
|
||||
void
|
||||
NodeDirectory::FillMapEntry(int num, ExtentMapEntry* fMap)
|
||||
{
|
||||
void* directoryFork = DIR_DFORK_PTR(fInode->Buffer());
|
||||
void* directoryFork = DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize());
|
||||
void* pointerToMap = (void*)((char*)directoryFork + num * EXTENT_SIZE);
|
||||
uint64 firstHalf = *((uint64*)pointerToMap);
|
||||
uint64 secondHalf = *((uint64*)pointerToMap + 1);
|
||||
|
@ -12,8 +12,7 @@ ShortDirectory::ShortDirectory(Inode* inode)
|
||||
fInode(inode),
|
||||
fTrack(0)
|
||||
{
|
||||
|
||||
fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer()));
|
||||
fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()));
|
||||
}
|
||||
|
||||
|
||||
@ -72,8 +71,8 @@ size_t
|
||||
ShortDirectory::EntrySize(int namelen)
|
||||
{
|
||||
return sizeof(ShortFormEntry) + namelen
|
||||
+ (fInode->HasFileTypeField()? sizeof(uint8) : 0)
|
||||
+ (fHeader->i8count? sizeof(uint64):sizeof(uint32));
|
||||
+ (fInode->HasFileTypeField() ? sizeof(uint8) : 0)
|
||||
+ (fHeader->i8count ? sizeof(uint64) : sizeof(uint32));
|
||||
}
|
||||
|
||||
|
||||
@ -155,7 +154,6 @@ ShortDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
|
||||
name[entry->namelen] = '\0';
|
||||
*length = entry->namelen + 1;
|
||||
*ino = GetEntryIno(entry);
|
||||
|
||||
TRACE("Entry found. Name: (%s), Length: (%" B_PRIuSIZE "),ino: (%" B_PRIu64 ")\n",
|
||||
name,*length, *ino);
|
||||
return B_OK;
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
uint32 blockSize, uint32 sectorSize);
|
||||
|
||||
bool IsValidSuperBlock() const;
|
||||
bool IsVersion5() const
|
||||
{ return fSuperBlock.IsVersion5(); }
|
||||
bool IsReadOnly() const
|
||||
{ return
|
||||
(fFlags & VOLUME_READ_ONLY) != 0; }
|
||||
@ -85,6 +87,9 @@ public:
|
||||
uint32 SuperBlockFeatures2() const
|
||||
{ return fSuperBlock.Features2(); }
|
||||
|
||||
bool XfsHasIncompatFeature() const
|
||||
{ return fSuperBlock.XfsHasIncompatFeature(); }
|
||||
|
||||
#if 0
|
||||
off_t NumBlocks() const
|
||||
{ return fSuperBlock.NumBlocks(); }
|
||||
|
@ -251,11 +251,13 @@ xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
|
||||
inode->GetModificationTime(stat->st_mtim);
|
||||
inode->GetChangeTime(stat->st_ctim);
|
||||
|
||||
/* TODO: Can we obtain the Creation Time in v4 system? */
|
||||
inode->GetChangeTime(stat->st_crtim);
|
||||
// Only version 3 Inodes has creation time
|
||||
if(inode->Version() == 3)
|
||||
inode->GetCreationTime(stat->st_crtim);
|
||||
else
|
||||
inode->GetChangeTime(stat->st_crtim);
|
||||
|
||||
return B_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,6 +74,7 @@ XfsSuperBlock::IsValidFeatureMask() const
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
XfsSuperBlock::IsValid() const
|
||||
{
|
||||
@ -154,6 +155,20 @@ XfsSuperBlock::IsValid() const
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
XfsSuperBlock::IsVersion5() const
|
||||
{
|
||||
return (Version() & XFS_SB_VERSION_NUMBITS) == 5;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
XfsSuperBlock::XfsHasIncompatFeature() const
|
||||
{
|
||||
return (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) != 0;
|
||||
}
|
||||
|
||||
|
||||
uint16
|
||||
XfsSuperBlock::Version() const
|
||||
{
|
||||
|
@ -39,7 +39,6 @@ extern fs_volume_ops gxfsVolumeOps;
|
||||
#define XFS_OPEN_MODE_USER_MASK 0x7fffffff
|
||||
#define XFS_SB_VERSION_NUMBITS 0x000f
|
||||
#define XFS_SB_VERSION_ALLFBITS 0xfff0
|
||||
#define XFS_SB_VERSION_NUM(sb) ((sb)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
|
||||
|
||||
/*
|
||||
Inode minimum and maximum sizes.
|
||||
@ -73,6 +72,8 @@ public:
|
||||
bool IsValid() const;
|
||||
bool IsValidVersion() const;
|
||||
bool IsValidFeatureMask() const;
|
||||
bool IsVersion5() const;
|
||||
bool XfsHasIncompatFeature() const;
|
||||
const char* Name() const;
|
||||
uint32 BlockSize() const;
|
||||
uint8 BlockLog() const;
|
||||
|
Loading…
Reference in New Issue
Block a user