/* * 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 _EXTENT_H_ #define _EXTENT_H_ #include "Directory.h" #include "Inode.h" #include "system_dependencies.h" #define DIR2_BLOCK_HEADER_MAGIC 0x58443242 // for v4 system #define DIR3_BLOCK_HEADER_MAGIC 0x58444233 // for v5 system #define DIR2_FREE_TAG 0xffff #define XFS_DIR2_DATA_FD_COUNT 3 #define EXTENT_SIZE 16 #define BLOCKNO_FROM_ADDRESS(n, volume) \ ((n) >> (volume->BlockLog() + volume->DirBlockLog())) #define BLOCKOFFSET_FROM_ADDRESS(n, inode) ((n) & (inode->DirBlockSize() - 1)) #define LEAF_STARTOFFSET(n) 1UL << (35 - (n)) // Enum values to check which directory we are reading enum DirectoryType { XFS_BLOCK, XFS_LEAF, XFS_NODE, XFS_BTREE, }; // xfs_dir2_data_free_t struct FreeRegion { uint16 offset; uint16 length; }; // This class will act as interface for V4 and V5 data header class ExtentDataHeader { public: virtual ~ExtentDataHeader() = 0; virtual uint32 Magic() = 0; virtual uint64 Blockno() = 0; virtual uint64 Lsn() = 0; virtual uint64 Owner() = 0; virtual const uuid_t& Uuid() = 0; static uint32 ExpectedMagic(int8 WhichDirectory, Inode* inode); static uint32 CRCOffset(); static ExtentDataHeader* Create(Inode* inode, const char* buffer); static uint32 Size(Inode* inode); }; // xfs_dir_data_hdr_t class ExtentDataHeaderV4 : public ExtentDataHeader { public : struct OnDiskData { public: uint32 magic; FreeRegion bestfree[XFS_DIR2_DATA_FD_COUNT]; }; ExtentDataHeaderV4(const char* buffer); ~ExtentDataHeaderV4(); uint32 Magic(); uint64 Blockno(); uint64 Lsn(); uint64 Owner(); const uuid_t& Uuid(); private: void _SwapEndian(); private: OnDiskData fData; }; // xfs_dir3_data_hdr_t class ExtentDataHeaderV5 : public ExtentDataHeader { public: struct OnDiskData { public: uint32 magic; uint32 crc; uint64 blkno; uint64 lsn; uuid_t uuid; uint64 owner; FreeRegion bestfree[XFS_DIR2_DATA_FD_COUNT]; uint32 pad; }; ExtentDataHeaderV5(const char* buffer); ~ExtentDataHeaderV5(); uint32 Magic(); uint64 Blockno(); uint64 Lsn(); uint64 Owner(); const uuid_t& Uuid(); private: void _SwapEndian(); private: OnDiskData fData; }; // xfs_dir2_data_entry_t struct ExtentDataEntry { xfs_ino_t inumber; uint8 namelen; uint8 name[]; // Followed by a file type (8bit) if applicable and a 16bit tag // tag is the offset from start of the block }; // xfs_dir2_data_unused_t struct ExtentUnusedEntry { uint16 freetag; // takes the value 0xffff uint16 length; // freetag + length overrides the inumber of an entry uint16 tag; }; // xfs_dir2_leaf_entry_t struct ExtentLeafEntry { uint32 hashval; uint32 address; // offset into block after >> 3 }; // xfs_dir2_block_tail_t struct ExtentBlockTail { uint32 count; // # of entries in leaf uint32 stale; // # of free leaf entries }; class Extent : public DirectoryIterator { public: Extent(Inode* inode); ~Extent(); status_t Init(); bool IsBlockType(); void FillMapEntry(void* pointerToMap); status_t FillBlockBuffer(); ExtentBlockTail* BlockTail(); ExtentLeafEntry* BlockFirstLeaf(ExtentBlockTail* tail); xfs_ino_t GetIno(); uint32 GetOffsetFromAddress(uint32 address); int EntrySize(int len) const; status_t GetNext(char* name, size_t* length, xfs_ino_t* ino); status_t Lookup(const char* name, size_t length, xfs_ino_t* id); private: Inode* fInode; ExtentMapEntry* fMap; uint32 fOffset; char* fBlockBuffer; // This isn't inode data. It holds the directory block. }; #endif