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,
|
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++) {
|
for (int i = 0; i < MAX_TREE_DEPTH; i++) {
|
||||||
fPathForLeaves[i].blockData = NULL;
|
fPathForLeaves[i].blockData = NULL;
|
||||||
@ -85,7 +85,7 @@ TreeDirectory::MaxRecordsPossibleRoot()
|
|||||||
lengthOfDataFork = fInode->ForkOffset() << 3;
|
lengthOfDataFork = fInode->ForkOffset() << 3;
|
||||||
if (fInode->ForkOffset() == 0) {
|
if (fInode->ForkOffset() == 0) {
|
||||||
lengthOfDataFork = fInode->GetVolume()->InodeSize()
|
lengthOfDataFork = fInode->GetVolume()->InodeSize()
|
||||||
- INODE_CORE_UNLINKED_SIZE;
|
- fInode->CoreInodeSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
lengthOfDataFork -= sizeof(BlockInDataFork);
|
lengthOfDataFork -= sizeof(BlockInDataFork);
|
||||||
@ -122,7 +122,8 @@ TreePointer*
|
|||||||
TreeDirectory::GetPtrFromRoot(int pos)
|
TreeDirectory::GetPtrFromRoot(int pos)
|
||||||
{
|
{
|
||||||
return (TreePointer*)
|
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)
|
TreeDirectory::GetKeyFromRoot(int pos)
|
||||||
{
|
{
|
||||||
off_t offset = (pos - 1) * KeySize();
|
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);
|
+ sizeof(BlockInDataFork);
|
||||||
return (TreeKey*) (base + offset);
|
return (TreeKey*) (base + offset);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ Extent::Init()
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
ASSERT(IsBlockType() == true);
|
ASSERT(IsBlockType() == true);
|
||||||
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer());
|
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize());
|
||||||
FillMapEntry(pointerToMap);
|
FillMapEntry(pointerToMap);
|
||||||
ASSERT(fMap->br_blockcount == 1);
|
ASSERT(fMap->br_blockcount == 1);
|
||||||
//TODO: This is always true for block directories
|
//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
|
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||||
* All rights reserved. Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@ -6,6 +7,7 @@
|
|||||||
|
|
||||||
#include "Inode.h"
|
#include "Inode.h"
|
||||||
#include "BPlusTree.h"
|
#include "BPlusTree.h"
|
||||||
|
#include "Checksum.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
xfs_inode_t::SwapEndian()
|
xfs_inode_t::SwapEndian()
|
||||||
@ -34,6 +36,13 @@ xfs_inode_t::SwapEndian()
|
|||||||
di_flags = B_BENDIAN_TO_HOST_INT16(di_flags);
|
di_flags = B_BENDIAN_TO_HOST_INT16(di_flags);
|
||||||
di_gen = B_BENDIAN_TO_HOST_INT32(di_gen);
|
di_gen = B_BENDIAN_TO_HOST_INT32(di_gen);
|
||||||
di_next_unlinked = B_BENDIAN_TO_HOST_INT32(di_next_unlinked);
|
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
|
uint32
|
||||||
xfs_inode_t::NLink() const
|
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
|
status_t
|
||||||
Inode::Init()
|
Inode::Init()
|
||||||
{
|
{
|
||||||
@ -162,7 +374,7 @@ Inode::Init()
|
|||||||
|
|
||||||
status_t status = GetFromDisk();
|
status_t status = GetFromDisk();
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
if (fNode->di_magic == INODE_MAGIC) {
|
if (VerifyInode()) {
|
||||||
TRACE("Init(): Inode successfully read.\n");
|
TRACE("Init(): Inode successfully read.\n");
|
||||||
status = B_OK;
|
status = B_OK;
|
||||||
} else {
|
} else {
|
||||||
@ -186,7 +398,11 @@ Inode::~Inode()
|
|||||||
bool
|
bool
|
||||||
Inode::HasFileTypeField() const
|
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()
|
Inode::ReadExtentsFromExtentBasedInode()
|
||||||
{
|
{
|
||||||
fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()];
|
fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()];
|
||||||
char* dataStart = (char*) DIR_DFORK_PTR(Buffer());
|
char* dataStart = (char*) DIR_DFORK_PTR(Buffer(), CoreInodeSize());
|
||||||
uint64 wrappedExtent[2];
|
uint64 wrappedExtent[2];
|
||||||
for (int i = 0; i < DataExtentsCount(); i++) {
|
for (int i = 0; i < DataExtentsCount(); i++) {
|
||||||
wrappedExtent[0] = *(uint64*)(dataStart);
|
wrappedExtent[0] = *(uint64*)(dataStart);
|
||||||
@ -239,7 +455,7 @@ Inode::MaxRecordsPossibleInTreeRoot()
|
|||||||
lengthOfDataFork = ForkOffset() << 3;
|
lengthOfDataFork = ForkOffset() << 3;
|
||||||
else if(ForkOffset() == 0) {
|
else if(ForkOffset() == 0) {
|
||||||
lengthOfDataFork = GetVolume()->InodeSize()
|
lengthOfDataFork = GetVolume()->InodeSize()
|
||||||
- INODE_CORE_UNLINKED_SIZE;
|
- CoreInodeSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
lengthOfDataFork -= sizeof(BlockInDataFork);
|
lengthOfDataFork -= sizeof(BlockInDataFork);
|
||||||
@ -260,7 +476,7 @@ TreePointer*
|
|||||||
Inode::GetPtrFromRoot(int pos)
|
Inode::GetPtrFromRoot(int pos)
|
||||||
{
|
{
|
||||||
return (TreePointer*)
|
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)
|
if (root == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
memcpy((void*)root,
|
memcpy((void*)root,
|
||||||
DIR_DFORK_PTR(Buffer()), sizeof(BlockInDataFork));
|
DIR_DFORK_PTR(Buffer(), CoreInodeSize()), sizeof(BlockInDataFork));
|
||||||
|
|
||||||
size_t maxRecords = MaxRecordsPossibleInTreeRoot();
|
size_t maxRecords = MaxRecordsPossibleInTreeRoot();
|
||||||
TRACE("Maxrecords: (%" B_PRIuSIZE ")\n", maxRecords);
|
TRACE("Maxrecords: (%" B_PRIuSIZE ")\n", maxRecords);
|
||||||
@ -550,7 +766,11 @@ Inode::GetFromDisk()
|
|||||||
return B_IO_ERROR;
|
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();
|
fNode->SwapEndian();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2022, Raghav Sharma, raghavself28@gmail.com
|
||||||
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
|
||||||
* All rights reserved. Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@ -11,38 +12,80 @@
|
|||||||
#include "xfs_types.h"
|
#include "xfs_types.h"
|
||||||
|
|
||||||
|
|
||||||
#define INODE_MAGIC 0x494e
|
#define INODE_MAGIC 0x494e
|
||||||
#define INODE_MINSIZE_LOG 8
|
#define INODE_MINSIZE_LOG 8
|
||||||
#define INODE_MAXSIZE_LOG 11
|
#define INODE_MAXSIZE_LOG 11
|
||||||
#define INODE_CORE_SIZE 96
|
#define INODE_MIN_SIZE (1 << INODE_MINSIZE_LOG)
|
||||||
#define INODE_CORE_UNLINKED_SIZE 100
|
#define INODE_MAX_SIZE (1 << INODE_MAXSIZE_LOG)
|
||||||
// Inode core but with unlinked pointer
|
#define INODE_CRC_OFF offsetof(struct xfs_inode_t, di_crc)
|
||||||
#define DATA_FORK_OFFSET 0x64
|
#define MAXAEXTNUM ((xfs_aextnum_t) 0x7fff)
|
||||||
// For v4 FS
|
#define MAXEXTNUM ((xfs_extnum_t) 0x7fffffff)
|
||||||
#define INO_MASK(x) ((1ULL << (x)) - 1)
|
|
||||||
|
// 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
|
// 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
|
// 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
|
// Gets the AG relative inode number
|
||||||
#define INO_TO_AGBLOCK(id, volume) \
|
#define INO_TO_AGBLOCK(id, volume) \
|
||||||
(id >> (volume->InodesPerBlkLog())) \
|
(id >> (volume->InodesPerBlkLog())) \
|
||||||
& (INO_MASK(volume->AgBlocksLog()))
|
& (INO_MASK(volume->AgBlocksLog()))
|
||||||
// Gets the AG relative block number that contains inode
|
// 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
|
// 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)
|
((char*) dir_ino_ptr + DATA_FORK_OFFSET)
|
||||||
#define DIR_AFORK_PTR(dir_ino_ptr, forkoff) \
|
#define DIR_AFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET, forkoff) \
|
||||||
(void*)((char*)DIR_DFORK_PTR(dir_ino_ptr) + \
|
(void*)((char*)DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) + \
|
||||||
(((uint32)forkoff)<<3))
|
(((uint32)forkoff)<<3))
|
||||||
#define DIR_AFORK_EXIST(dir_ino_ptr) dir_ino_ptr->di_forkoff!=0
|
|
||||||
#define MASK(n) ((1UL << n) - 1)
|
#define DIR_AFORK_EXIST(dir_ino_ptr) (dir_ino_ptr->di_forkoff != 0)
|
||||||
#define FSBLOCKS_TO_AGNO(n, volume) ((n) >> volume->AgBlocksLog())
|
|
||||||
#define FSBLOCKS_TO_AGBLOCKNO(n, volume) ((n) & MASK(volume->AgBlocksLog()))
|
#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) \
|
#define BLOCKNO_FROM_POSITION(n, volume) \
|
||||||
((n) >> (volume->BlockLog()))
|
((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
|
// xfs_bmdr_block
|
||||||
@ -102,6 +145,33 @@ enum xfs_dinode_fmt_t {
|
|||||||
// Not used
|
// 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
|
* 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.
|
* fork might be different and that is to be handled accordingly.
|
||||||
@ -114,6 +184,8 @@ struct xfs_inode_t {
|
|||||||
timestamp);
|
timestamp);
|
||||||
void GetChangeTime(struct timespec& timestamp);
|
void GetChangeTime(struct timespec& timestamp);
|
||||||
void GetAccessTime(struct timespec& timestamp);
|
void GetAccessTime(struct timespec& timestamp);
|
||||||
|
void GetCreationTime(struct timespec& timestamp);
|
||||||
|
|
||||||
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;
|
||||||
@ -160,17 +232,97 @@ struct xfs_inode_t {
|
|||||||
uint16 di_flags;
|
uint16 di_flags;
|
||||||
uint32 di_gen;
|
uint32 di_gen;
|
||||||
uint32 di_next_unlinked;
|
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 {
|
class Inode {
|
||||||
public:
|
public:
|
||||||
Inode(Volume* volume, xfs_ino_t id);
|
Inode(Volume* volume, xfs_ino_t id);
|
||||||
~Inode();
|
~Inode();
|
||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
xfs_ino_t ID() const { return fId; }
|
xfs_ino_t ID() const { return fId; }
|
||||||
|
|
||||||
|
bool VerifyInode() const;
|
||||||
|
|
||||||
|
bool VerifyForkoff() const;
|
||||||
|
|
||||||
|
bool VerifyFork(int WhichFork) const;
|
||||||
|
|
||||||
bool IsDirectory() const
|
bool IsDirectory() const
|
||||||
{ return S_ISDIR(Mode()); }
|
{ return S_ISDIR(Mode()); }
|
||||||
|
|
||||||
@ -209,6 +361,8 @@ public:
|
|||||||
uint32 BlockSize() const
|
uint32 BlockSize() const
|
||||||
{ return fVolume->BlockSize(); }
|
{ return fVolume->BlockSize(); }
|
||||||
|
|
||||||
|
uint32 CoreInodeSize() const;
|
||||||
|
|
||||||
void GetChangeTime(struct timespec& timestamp) const
|
void GetChangeTime(struct timespec& timestamp) const
|
||||||
{ fNode->GetChangeTime(timestamp); }
|
{ fNode->GetChangeTime(timestamp); }
|
||||||
|
|
||||||
@ -219,6 +373,10 @@ public:
|
|||||||
void GetAccessTime(struct timespec& timestamp) const
|
void GetAccessTime(struct timespec& timestamp) const
|
||||||
{ fNode->GetAccessTime(timestamp); }
|
{ fNode->GetAccessTime(timestamp); }
|
||||||
|
|
||||||
|
void GetCreationTime(struct timespec& timestamp) const
|
||||||
|
{ fNode->GetCreationTime(timestamp); }
|
||||||
|
|
||||||
|
unsigned char XfsModeToFtype() const;
|
||||||
status_t CheckPermissions(int accessMode) const;
|
status_t CheckPermissions(int accessMode) const;
|
||||||
uint32 UserId() const { return fNode->UserId(); }
|
uint32 UserId() const { return fNode->UserId(); }
|
||||||
uint32 GroupId() const { return fNode->GroupId(); }
|
uint32 GroupId() const { return fNode->GroupId(); }
|
||||||
|
@ -74,7 +74,7 @@ LeafDirectory::IsLeafType()
|
|||||||
void
|
void
|
||||||
LeafDirectory::FillMapEntry(int num, ExtentMapEntry* fMap)
|
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* pointerToMap = (uint64*)((char*)directoryFork + num * EXTENT_SIZE);
|
||||||
uint64 firstHalf = pointerToMap[0];
|
uint64 firstHalf = pointerToMap[0];
|
||||||
|
@ -62,7 +62,7 @@ NodeDirectory::IsNodeType()
|
|||||||
void
|
void
|
||||||
NodeDirectory::FillMapEntry(int num, ExtentMapEntry* fMap)
|
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);
|
void* pointerToMap = (void*)((char*)directoryFork + num * EXTENT_SIZE);
|
||||||
uint64 firstHalf = *((uint64*)pointerToMap);
|
uint64 firstHalf = *((uint64*)pointerToMap);
|
||||||
uint64 secondHalf = *((uint64*)pointerToMap + 1);
|
uint64 secondHalf = *((uint64*)pointerToMap + 1);
|
||||||
|
@ -12,8 +12,7 @@ ShortDirectory::ShortDirectory(Inode* inode)
|
|||||||
fInode(inode),
|
fInode(inode),
|
||||||
fTrack(0)
|
fTrack(0)
|
||||||
{
|
{
|
||||||
|
fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()));
|
||||||
fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,8 +71,8 @@ size_t
|
|||||||
ShortDirectory::EntrySize(int namelen)
|
ShortDirectory::EntrySize(int namelen)
|
||||||
{
|
{
|
||||||
return sizeof(ShortFormEntry) + namelen
|
return sizeof(ShortFormEntry) + namelen
|
||||||
+ (fInode->HasFileTypeField()? sizeof(uint8) : 0)
|
+ (fInode->HasFileTypeField() ? sizeof(uint8) : 0)
|
||||||
+ (fHeader->i8count? sizeof(uint64):sizeof(uint32));
|
+ (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';
|
name[entry->namelen] = '\0';
|
||||||
*length = entry->namelen + 1;
|
*length = entry->namelen + 1;
|
||||||
*ino = GetEntryIno(entry);
|
*ino = GetEntryIno(entry);
|
||||||
|
|
||||||
TRACE("Entry found. Name: (%s), Length: (%" B_PRIuSIZE "),ino: (%" B_PRIu64 ")\n",
|
TRACE("Entry found. Name: (%s), Length: (%" B_PRIuSIZE "),ino: (%" B_PRIu64 ")\n",
|
||||||
name,*length, *ino);
|
name,*length, *ino);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
@ -31,6 +31,8 @@ public:
|
|||||||
uint32 blockSize, uint32 sectorSize);
|
uint32 blockSize, uint32 sectorSize);
|
||||||
|
|
||||||
bool IsValidSuperBlock() const;
|
bool IsValidSuperBlock() const;
|
||||||
|
bool IsVersion5() const
|
||||||
|
{ return fSuperBlock.IsVersion5(); }
|
||||||
bool IsReadOnly() const
|
bool IsReadOnly() const
|
||||||
{ return
|
{ return
|
||||||
(fFlags & VOLUME_READ_ONLY) != 0; }
|
(fFlags & VOLUME_READ_ONLY) != 0; }
|
||||||
@ -85,6 +87,9 @@ public:
|
|||||||
uint32 SuperBlockFeatures2() const
|
uint32 SuperBlockFeatures2() const
|
||||||
{ return fSuperBlock.Features2(); }
|
{ return fSuperBlock.Features2(); }
|
||||||
|
|
||||||
|
bool XfsHasIncompatFeature() const
|
||||||
|
{ return fSuperBlock.XfsHasIncompatFeature(); }
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
off_t NumBlocks() const
|
off_t NumBlocks() const
|
||||||
{ return fSuperBlock.NumBlocks(); }
|
{ 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->GetModificationTime(stat->st_mtim);
|
||||||
inode->GetChangeTime(stat->st_ctim);
|
inode->GetChangeTime(stat->st_ctim);
|
||||||
|
|
||||||
/* TODO: Can we obtain the Creation Time in v4 system? */
|
// Only version 3 Inodes has creation time
|
||||||
inode->GetChangeTime(stat->st_crtim);
|
if(inode->Version() == 3)
|
||||||
|
inode->GetCreationTime(stat->st_crtim);
|
||||||
|
else
|
||||||
|
inode->GetChangeTime(stat->st_crtim);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ XfsSuperBlock::IsValidFeatureMask() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
XfsSuperBlock::IsValid() const
|
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
|
uint16
|
||||||
XfsSuperBlock::Version() const
|
XfsSuperBlock::Version() const
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,6 @@ extern fs_volume_ops gxfsVolumeOps;
|
|||||||
#define XFS_OPEN_MODE_USER_MASK 0x7fffffff
|
#define XFS_OPEN_MODE_USER_MASK 0x7fffffff
|
||||||
#define XFS_SB_VERSION_NUMBITS 0x000f
|
#define XFS_SB_VERSION_NUMBITS 0x000f
|
||||||
#define XFS_SB_VERSION_ALLFBITS 0xfff0
|
#define XFS_SB_VERSION_ALLFBITS 0xfff0
|
||||||
#define XFS_SB_VERSION_NUM(sb) ((sb)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Inode minimum and maximum sizes.
|
Inode minimum and maximum sizes.
|
||||||
@ -73,6 +72,8 @@ public:
|
|||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
bool IsValidVersion() const;
|
bool IsValidVersion() const;
|
||||||
bool IsValidFeatureMask() const;
|
bool IsValidFeatureMask() const;
|
||||||
|
bool IsVersion5() const;
|
||||||
|
bool XfsHasIncompatFeature() const;
|
||||||
const char* Name() const;
|
const char* Name() const;
|
||||||
uint32 BlockSize() const;
|
uint32 BlockSize() const;
|
||||||
uint8 BlockLog() const;
|
uint8 BlockLog() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user