[haiku-commits] haiku: hrev56219 - src/add-ons/kernel/file_systems/xfs

  • From: Adrien Destugues <pulkomandy@xxxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 27 Jun 2022 15:00:33 +0000 (UTC)

hrev56219 adds 1 changeset to branch 'master'
old head: e511f0c1cb7fea2809d57e7eb79577248f2687e9
new head: 6c478b54f65d618f528b9b8b747c5e80d4d2bc95
overview: 
https://git.haiku-os.org/haiku/log/?qt=range&q=6c478b54f65d+%5Ee511f0c1cb7f

----------------------------------------------------------------------------

6c478b54f65d: 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@xxxxxxxxxxxxx>
  Tested-by: Commit checker robot <no-reply+buildbot@xxxxxxxxxxxx>

                                      [ Mashijams <raghavself28@xxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev56219
Commit:      6c478b54f65d618f528b9b8b747c5e80d4d2bc95
URL:         https://git.haiku-os.org/haiku/commit/?id=6c478b54f65d
Author:      Mashijams <raghavself28@xxxxxxxxx>
Date:        Fri Jun 24 09:19:37 2022 UTC
Committer:   Adrien Destugues <pulkomandy@xxxxxxxxxxxxx>
Commit-Date: Mon Jun 27 15:00:30 2022 UTC

----------------------------------------------------------------------------

11 files changed, 443 insertions(+), 43 deletions(-)
.../kernel/file_systems/xfs/BPlusTree.cpp        |   9 +-
src/add-ons/kernel/file_systems/xfs/Extent.cpp   |   2 +-
src/add-ons/kernel/file_systems/xfs/Inode.cpp    | 234 ++++++++++++++++++-
src/add-ons/kernel/file_systems/xfs/Inode.h      | 198 ++++++++++++++--
.../kernel/file_systems/xfs/LeafDirectory.cpp    |   2 +-
src/add-ons/kernel/file_systems/xfs/Node.cpp     |   2 +-
.../kernel/file_systems/xfs/ShortDirectory.cpp   |   8 +-
src/add-ons/kernel/file_systems/xfs/Volume.h     |   5 +
.../kernel/file_systems/xfs/kernel_interface.cpp |   8 +-
src/add-ons/kernel/file_systems/xfs/xfs.cpp      |  15 ++
src/add-ons/kernel/file_systems/xfs/xfs.h        |   3 +-

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp 
b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
index 819e50f633..77321583bb 100644
--- a/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/BPlusTree.cpp
@@ -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);
 }
diff --git a/src/add-ons/kernel/file_systems/xfs/Extent.cpp 
b/src/add-ons/kernel/file_systems/xfs/Extent.cpp
index dbe4023b8d..7bc3ab1440 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 @@ 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
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp 
b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
index a99d89ae1b..6ec3bfc30e 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 @@ 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;
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.h 
b/src/add-ons/kernel/file_systems/xfs/Inode.h
index 052a8afe5f..a04d7e8460 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.
  */
@@ -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(); }
diff --git a/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp 
b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp
index 7359a93d77..7c8b1c32ac 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 @@ 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];
diff --git a/src/add-ons/kernel/file_systems/xfs/Node.cpp 
b/src/add-ons/kernel/file_systems/xfs/Node.cpp
index c2f983d876..ed854d368e 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 @@ 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);
diff --git a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp 
b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
index 50b8e113ed..dab97f5be5 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 @@ 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;
diff --git a/src/add-ons/kernel/file_systems/xfs/Volume.h 
b/src/add-ons/kernel/file_systems/xfs/Volume.h
index a213451ff0..d5a7fb2cea 100644
--- a/src/add-ons/kernel/file_systems/xfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/xfs/Volume.h
@@ -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(); }
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 9aec919404..0d200f57a2 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 @@ 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;
-
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.cpp 
b/src/add-ons/kernel/file_systems/xfs/xfs.cpp
index 2f43f882c8..ced32b76d5 100644
--- a/src/add-ons/kernel/file_systems/xfs/xfs.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/xfs.cpp
@@ -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
 {
diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.h 
b/src/add-ons/kernel/file_systems/xfs/xfs.h
index e132fe65e4..4f9134bd6e 100644
--- a/src/add-ons/kernel/file_systems/xfs/xfs.h
+++ b/src/add-ons/kernel/file_systems/xfs/xfs.h
@@ -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;


Other related posts:

  • » [haiku-commits] haiku: hrev56219 - src/add-ons/kernel/file_systems/xfs - Adrien Destugues