From Raghav Sharma <raghavself28@xxxxxxxxx>:
Raghav Sharma has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/5396 ;)
Change subject: xfs : version 3 Inodes and shortform directory
......................................................................
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
---
M src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
M src/add-ons/kernel/file_systems/xfs/Extent.cpp
M src/add-ons/kernel/file_systems/xfs/Inode.cpp
M src/add-ons/kernel/file_systems/xfs/Inode.h
M src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp
M src/add-ons/kernel/file_systems/xfs/Node.cpp
M src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
M src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
M src/add-ons/kernel/file_systems/xfs/Volume.h
M src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
M src/add-ons/kernel/file_systems/xfs/xfs.cpp
M src/add-ons/kernel/file_systems/xfs/xfs.h
12 files changed, 428 insertions(+), 31 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/96/5396/1
diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
index 819e50f..8d23ff7 100644
--- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
@@ -32,7 +32,8 @@
}
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 +86,7 @@
lengthOfDataFork = fInode->ForkOffset() << 3;
if (fInode->ForkOffset() == 0) {
lengthOfDataFork = fInode->GetVolume()->InodeSize()
- - INODE_CORE_UNLINKED_SIZE;
+ - fInode->CoreInodeSize();
}
lengthOfDataFork -= sizeof(BlockInDataFork);
@@ -122,7 +123,8 @@
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 +148,7 @@
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);
}
diff --git a/src/add-ons/kernel/file_systems/xfs/Extent.cpp
b/src/add-ons/kernel/file_systems/xfs/Extent.cpp
index dbe4023..96c9ce2 100644
--- a/src/add-ons/kernel/file_systems/xfs/Extent.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Extent.cpp
@@ -70,7 +70,7 @@
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
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp
b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
index a99d89a..99564f7 100644
--- a/src/add-ons/kernel/file_systems/xfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright 2022, Raghav Sharma, raghavself28@xxxxxxxxx
* Copyright 2020, Shubham Bhagat, shubhambhagat111@xxxxxxxxx
* 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 @@
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 @@
}
+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 @@
}
+//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() > 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() > 3 || fNode->Version() < 1) {
+ 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 @@
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 @@
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 @@
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 @@
lengthOfDataFork = ForkOffset() << 3;
else if(ForkOffset() == 0) {
lengthOfDataFork = GetVolume()->InodeSize()
- - INODE_CORE_UNLINKED_SIZE;
+ - CoreInodeSize();
}
lengthOfDataFork -= sizeof(BlockInDataFork);
@@ -260,7 +476,7 @@
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 @@
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,8 @@
return B_IO_ERROR;
}
- memcpy(fNode, fBuffer, INODE_CORE_UNLINKED_SIZE);
+ memcpy(fNode, fBuffer, 176);
+
fNode->SwapEndian();
return B_OK;
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.h
b/src/add-ons/kernel/file_systems/xfs/Inode.h
index 052a8af..1902ca7 100644
--- a/src/add-ons/kernel/file_systems/xfs/Inode.h
+++ b/src/add-ons/kernel/file_systems/xfs/Inode.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2022, Raghav Sharma, raghavself28@xxxxxxxxx
* Copyright 2020, Shubham Bhagat, shubhambhagat111@xxxxxxxxx
* All rights reserved. Distributed under the terms of the MIT License.
*/
@@ -14,11 +15,38 @@
#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 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) \
+ (XFS_SB_VERSION_NUM(volume->SuperBlock()) == 5 ? \
+ 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())
@@ -31,12 +59,16 @@
// 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) (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()))
@@ -44,6 +76,25 @@
((n) >> (volume->BlockLog()))
#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
struct BlockInDataFork {
@@ -102,6 +153,33 @@
// 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 +192,8 @@
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 +240,97 @@
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 +369,8 @@
uint32 BlockSize() const
{
return fVolume->BlockSize(); }
+ uint32 CoreInodeSize() const;
+
void GetChangeTime(struct
timespec& timestamp) const
{
fNode->GetChangeTime(timestamp); }
@@ -219,6 +381,10 @@
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(); }
diff --git a/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp
b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp
index 7359a93..7c8b1c3 100644
--- a/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp
@@ -74,7 +74,7 @@
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];
diff --git a/src/add-ons/kernel/file_systems/xfs/Node.cpp
b/src/add-ons/kernel/file_systems/xfs/Node.cpp
index c2f983d..77cf1ef 100644
--- a/src/add-ons/kernel/file_systems/xfs/Node.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Node.cpp
@@ -62,7 +62,7 @@
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);
diff --git a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
index 50b8e11..4224636 100644
--- a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
@@ -12,8 +12,7 @@
fInode(inode),
fTrack(0)
{
-
- fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer()));
+ fHeader =
(ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer(),fInode->CoreInodeSize()));
}
@@ -72,8 +71,8 @@
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 @@
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;
diff --git a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
index 316a3bd..bf95e98 100644
--- a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
+++ b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
@@ -43,6 +43,7 @@
// offset tag, for directory iteration
uint8 name[];
// name of directory entry
+
/*
* Following will be a single byte file type variable
* and inode number (64bits or 32 bits)
diff --git a/src/add-ons/kernel/file_systems/xfs/Volume.h
b/src/add-ons/kernel/file_systems/xfs/Volume.h
index a213451..8baf31f 100644
--- a/src/add-ons/kernel/file_systems/xfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/xfs/Volume.h
@@ -85,6 +85,9 @@
uint32 SuperBlockFeatures2()
const
{
return fSuperBlock.Features2(); }
+ bool XfsHasIncompatFeature()
const
+ {
return fSuperBlock.XfsHasIncompatFeature(); }
+
#if 0
off_t NumBlocks() const
{
return fSuperBlock.NumBlocks(); }
diff --git a/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
b/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
index 9aec919..0d200f5 100644
--- a/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
@@ -251,11 +251,13 @@
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;
-
}
diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.cpp
b/src/add-ons/kernel/file_systems/xfs/xfs.cpp
index 2f43f88..2eb631c 100644
--- a/src/add-ons/kernel/file_systems/xfs/xfs.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/xfs.cpp
@@ -154,6 +154,13 @@
}
+bool
+XfsSuperBlock::XfsHasIncompatFeature() const
+{
+ return sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE != 0;
+}
+
+
uint16
XfsSuperBlock::Version() const
{
diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.h
b/src/add-ons/kernel/file_systems/xfs/xfs.h
index e132fe6..813213f 100644
--- a/src/add-ons/kernel/file_systems/xfs/xfs.h
+++ b/src/add-ons/kernel/file_systems/xfs/xfs.h
@@ -39,7 +39,7 @@
#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)
+#define XFS_SB_VERSION_NUM(sb) ((sb).Version() &
XFS_SB_VERSION_NUMBITS)
/*
Inode minimum and maximum sizes.
@@ -73,6 +73,7 @@
bool IsValid() const;
bool IsValidVersion() const;
bool IsValidFeatureMask()
const;
+ bool XfsHasIncompatFeature()
const;
const char* Name() const;
uint32 BlockSize() const;
uint8 BlockLog() const;
--
To view, visit https://review.haiku-os.org/c/haiku/+/5396
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I8a75ec1dc663d567d3bf6db64be4a27b55d709b3
Gerrit-Change-Number: 5396
Gerrit-PatchSet: 1
Gerrit-Owner: Raghav Sharma <raghavself28@xxxxxxxxx>
Gerrit-MessageType: newchange