* Copyright 2022, Raghav Sharma, raghavself28@gmail.com
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _INODE_H_
#define _INODE_H_
#include "system_dependencies.h"
#include "Volume.h"
#include "xfs_types.h"
#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(Inode::Dinode, di_crc)
#define MAXAEXTNUM ((xfs_aextnum_t) 0x7fff)
#define MAXEXTNUM ((xfs_extnum_t) 0x7fffffff)
#define HAS_V3INODES(volume) (volume->IsVersion5() ? 1 : 0 )
#define DINODE_SIZE(volume) \
(HAS_V3INODES(volume) ? sizeof(Inode::Dinode) : offsetof(Inode::Dinode, di_crc))
#define LITINO(volume) \
((volume)->InodeSize() - DINODE_SIZE(volume))
#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)
#define INO_TO_AGNO(id, volume) ((xfs_agnumber_t)id >> (volume->AgInodeBits()))
#define INO_TO_AGINO(id, bits) ((uint32) id & INO_MASK(bits))
#define INO_TO_AGBLOCK(id, volume) \
(id >> (volume->InodesPerBlkLog())) \
& (INO_MASK(volume->AgBlocksLog()))
#define INO_TO_BLOCKOFFSET(id, volume) (id & INO_MASK(volume->InodesPerBlkLog()))
#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, DATA_FORK_OFFSET, forkoff) \
(void*)((char*)DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) + \
(((uint32)forkoff)<<3))
#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 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_naextents)
#define DFORK_MAXEXT(ino, volume, w) \
(DFORK_SIZE(ino, volume, w) / (2 * sizeof(uint64)))
struct LongBlock;
struct BlockInDataFork {
uint16 Levels()
{ return
B_BENDIAN_TO_HOST_INT16(bb_level); }
uint16 NumRecords()
{ return
B_BENDIAN_TO_HOST_INT16(bb_numrecs); }
uint16 bb_level;
uint16 bb_numrecs;
};
struct BlockInfo {
uint32 forw;
uint32 back;
uint16 magic;
uint16 pad;
};
struct BlockInfoV5 {
uint32 forw;
uint32 back;
uint16 magic;
uint16 pad;
uint32 crc;
uint64 blkno;
uint64 lsn;
uuid_t uuid;
uint64 owner;
};
#define XFS_BLOCK_CRC_OFF offsetof(struct BlockInfoV5, crc)
struct ExtentMapEntry {
xfs_fileoff_t br_startoff;
xfs_fsblock_t br_startblock;
xfs_filblks_t br_blockcount;
uint8 br_state;
};
struct xfs_timestamp_t {
int32 t_sec;
int32 t_nsec;
};
enum xfs_dinode_fmt_t {
XFS_DINODE_FMT_DEV,
XFS_DINODE_FMT_LOCAL,
XFS_DINODE_FMT_EXTENTS,
XFS_DINODE_FMT_BTREE,
XFS_DINODE_FMT_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 dinode is the same for all types of inodes, the data and attribute
* fork might be different and that is to be handled accordingly.
*/
class Inode {
public:
typedef struct Dinode{
public:
uint16 di_magic;
uint16 di_mode;
int8 di_version;
int8 di_format;
uint16 di_onlink;
uint32 di_uid;
uint32 di_gid;
uint32 di_nlink;
uint16 di_projid;
uint8 di_pad[8];
uint16 di_flushiter;
xfs_timestamp_t di_atime;
xfs_timestamp_t di_mtime;
xfs_timestamp_t di_ctime;
xfs_fsize_t di_size;
xfs_rfsblock_t di_nblocks;
xfs_extlen_t di_extsize;
xfs_extnum_t di_nextents;
xfs_aextnum_t di_naextents;
uint8 di_forkoff;
int8 di_aformat;
uint32 di_dmevmask;
uint16 di_dmstate;
uint16 di_flags;
uint32 di_gen;
uint32 di_next_unlinked;
uint32 di_crc;
uint64 di_changecount;
uint64 di_lsn;
uint64 di_flags2;
uint32 di_cowextsize;
uint8 di_pad2[12];
xfs_timestamp_t di_crtime;
uint64 di_ino;
uuid_t di_uuid;
};
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()); }
bool IsFile() const
{ return S_ISREG(Mode()); }
bool IsSymLink() const
{ return S_ISLNK(Mode()); }
mode_t Mode() const { return fNode->di_mode; }
Volume* GetVolume() { return fVolume;}
int8 Format() const { return fNode->di_format; }
int8 AttrFormat() const { return fNode->di_aformat; }
bool IsLocal() const
{ return Format() == XFS_DINODE_FMT_LOCAL; }
uint32 NLink() const { return fNode->di_nlink; }
int8 Version() const { return fNode->di_version; }
xfs_rfsblock_t BlockCount() const
{ return fNode->di_nblocks; }
char* Buffer() { return fBuffer; }
int16 Flags() const { return fNode->di_flags; }
xfs_fsize_t Size() const { return fNode->di_size; }
uint32 DirBlockSize() const
{ return fVolume->DirBlockSize(); }
uint32 BlockSize() const
{ return fVolume->BlockSize(); }
uint32 CoreInodeSize() const;
void GetChangeTime(struct timespec& timestamp) const;
void GetModificationTime(struct timespec& timestamp) const;
void GetAccessTime(struct timespec& timestamp) const;
void GetCreationTime(struct timespec& timestamp) const;
unsigned char XfsModeToFtype() const;
status_t CheckPermissions(int accessMode) const;
uint32 UserId() const { return fNode->di_uid; }
uint32 GroupId() const { return fNode->di_gid; }
bool HasFileTypeField() const;
xfs_extnum_t DataExtentsCount() const
{ return fNode->di_nextents; }
xfs_extnum_t AttrExtentsCount() const
{ return fNode->di_naextents; }
uint64 FileSystemBlockToAddr(uint64 block);
uint8 ForkOffset() const
{ return fNode->di_forkoff; }
status_t ReadExtents();
status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
status_t GetNodefromTree(uint16& levelsInTree,
Volume* volume, ssize_t& len,
size_t DirBlockSize, char* block);
int SearchMapInAllExtent(uint64 blockNo);
void UnWrapExtentFromWrappedEntry(
uint64 wrappedExtent[2],
ExtentMapEntry* entry);
status_t ReadExtentsFromExtentBasedInode();
status_t ReadExtentsFromTreeInode();
size_t MaxRecordsPossibleInTreeRoot();
size_t MaxRecordsPossibleNode();
TreePointer* GetPtrFromRoot(int pos);
TreePointer* GetPtrFromNode(int pos, void* buffer);
size_t GetPtrOffsetIntoRoot(int pos);
size_t GetPtrOffsetIntoNode(int pos);
uint32 SizeOfLongBlock();
private:
void SwapEndian();
private:
status_t GetFromDisk();
Dinode* fNode;
xfs_ino_t fId;
Volume* fVolume;
char* fBuffer;
ExtentMapEntry* fExtents;
};
uint32 hashfunction(const char* name, int length);
template<class T> void
hashLowerBound(T* entry, int& left, int& right, uint32 hashValueOfRequest)
{
int mid;
* Trying to find the lowerbound of hashValueOfRequest
* This is slightly different from bsearch(), as we want the first
* instance of hashValueOfRequest and not any instance.
*/
while (left < right) {
mid = (left + right) / 2;
uint32 hashval = B_BENDIAN_TO_HOST_INT32(entry[mid].hashval);
if (hashval >= hashValueOfRequest) {
right = mid;
continue;
}
if (hashval < hashValueOfRequest)
left = mid+1;
}
TRACE("left:(%" B_PRId32 "), right:(%" B_PRId32 ")\n", left, right);
}
#endif