1 /* 2 * Copyright 2022, Raghav Sharma, raghavself28@gmail.com 3 * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 #ifndef _INODE_H_ 7 #define _INODE_H_ 8 9 10 #include "system_dependencies.h" 11 #include "Volume.h" 12 #include "xfs_types.h" 13 14 15 #define INODE_MAGIC 0x494e 16 #define INODE_MINSIZE_LOG 8 17 #define INODE_MAXSIZE_LOG 11 18 #define INODE_MIN_SIZE (1 << INODE_MINSIZE_LOG) 19 #define INODE_MAX_SIZE (1 << INODE_MAXSIZE_LOG) 20 #define INODE_CRC_OFF offsetof(Inode::Dinode, di_crc) 21 #define MAXAEXTNUM ((xfs_aextnum_t) 0x7fff) 22 #define MAXEXTNUM ((xfs_extnum_t) 0x7fffffff) 23 24 // Does fs volume has v3 inodes? 25 #define HAS_V3INODES(volume) (volume->IsVersion5() ? 1 : 0 ) 26 27 // Inode size for given fs 28 #define DINODE_SIZE(volume) \ 29 (HAS_V3INODES(volume) ? sizeof(Inode::Dinode) : offsetof(Inode::Dinode, di_crc)) 30 #define LITINO(volume) \ 31 ((volume)->InodeSize() - DINODE_SIZE(volume)) 32 33 // inode data and attribute fork sizes 34 #define DFORK_BOFF(ino) ((int)((ino)->di_forkoff << 3)) 35 36 #define DFORK_DSIZE(ino, volume) \ 37 ((ino)->di_forkoff ? DFORK_BOFF(ino) : LITINO(volume)) 38 #define DFORK_ASIZE(ino, volume) \ 39 ((ino)->di_forkoff ? LITINO(volume) - DFORK_BOFF(ino) : 0) 40 #define DFORK_SIZE(ino, volume, w) \ 41 ((w) == XFS_DATA_FORK ? \ 42 DFORK_DSIZE(ino, volume) : DFORK_ASIZE(ino, volume)) 43 44 45 #define INO_MASK(x) ((1ULL << (x)) - 1) 46 // Gets 2^x - 1 47 #define INO_TO_AGNO(id, volume) ((xfs_agnumber_t)id >> (volume->AgInodeBits())) 48 // Gets AG number from inode number 49 #define INO_TO_AGINO(id, bits) ((uint32) id & INO_MASK(bits)) 50 // Gets the AG relative inode number 51 #define INO_TO_AGBLOCK(id, volume) \ 52 (id >> (volume->InodesPerBlkLog())) \ 53 & (INO_MASK(volume->AgBlocksLog())) 54 // Gets the AG relative block number that contains inode 55 #define INO_TO_BLOCKOFFSET(id, volume) (id & INO_MASK(volume->InodesPerBlkLog())) 56 // Gets the offset into the block from the inode number 57 58 // Data and attribute fork pointers 59 #define DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) (void*) \ 60 ((char*) dir_ino_ptr + DATA_FORK_OFFSET) 61 #define DIR_AFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET, forkoff) \ 62 (void*)((char*)DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) + \ 63 (((uint32)forkoff)<<3)) 64 65 #define MASK(n) ((1UL << n) - 1) 66 #define FSBLOCKS_TO_AGNO(n, volume) ((n) >> volume->AgBlocksLog()) 67 #define FSBLOCKS_TO_AGBLOCKNO(n, volume) ((n) & MASK(volume->AgBlocksLog())) 68 #define BLOCKNO_FROM_POSITION(n, volume) \ 69 ((n) >> (volume->BlockLog())) 70 #define BLOCKOFFSET_FROM_POSITION(n, inode) ((n) & (inode->BlockSize() - 1)) 71 72 73 // Inode fork identifiers 74 #define XFS_DATA_FORK 0 75 #define XFS_ATTR_FORK 1 76 77 #define XFS_DFORK_FORMAT(ino, w) \ 78 ((w) == XFS_DATA_FORK ? (ino)->di_format : (ino)->di_aformat) 79 80 #define XFS_DFORK_NEXTENTS(ino, w) \ 81 ((w) == XFS_DATA_FORK ? (ino)->di_nextents : (ino)->di_naextents) 82 83 #define DFORK_MAXEXT(ino, volume, w) \ 84 (DFORK_SIZE(ino, volume, w) / (2 * sizeof(uint64))) 85 86 87 struct LongBlock; // Forward declaration to remove cyclic dependency 88 89 90 // xfs_bmdr_block 91 struct BlockInDataFork { 92 uint16 Levels() 93 { return 94 B_BENDIAN_TO_HOST_INT16(bb_level); } 95 uint16 NumRecords() 96 { return 97 B_BENDIAN_TO_HOST_INT16(bb_numrecs); } 98 uint16 bb_level; 99 uint16 bb_numrecs; 100 }; 101 102 103 //xfs_da_blkinfo_t 104 struct BlockInfo { 105 uint32 forw; 106 uint32 back; 107 uint16 magic; 108 uint16 pad; 109 }; 110 111 112 // xfs_da3_blkinfo_t 113 struct BlockInfoV5 { 114 uint32 forw; 115 uint32 back; 116 uint16 magic; 117 uint16 pad; 118 119 // version 5 120 121 uint32 crc; 122 uint64 blkno; 123 uint64 lsn; 124 uuid_t uuid; 125 uint64 owner; 126 }; 127 128 #define XFS_BLOCK_CRC_OFF offsetof(struct BlockInfoV5, crc) 129 130 131 struct ExtentMapEntry { 132 xfs_fileoff_t br_startoff; 133 // logical file block offset 134 xfs_fsblock_t br_startblock; 135 // absolute block number 136 xfs_filblks_t br_blockcount; 137 // # of blocks 138 uint8 br_state; 139 // state of the extent 140 }; 141 142 143 struct xfs_timestamp_t { 144 int32 t_sec; 145 int32 t_nsec; 146 }; 147 148 149 enum xfs_dinode_fmt_t { 150 XFS_DINODE_FMT_DEV, 151 // For devices 152 XFS_DINODE_FMT_LOCAL, 153 // For Directories and links 154 XFS_DINODE_FMT_EXTENTS, 155 // For large number of extents 156 XFS_DINODE_FMT_BTREE, 157 // Extents and Directories 158 XFS_DINODE_FMT_UUID, 159 // Not used 160 }; 161 162 163 /* 164 Dirents in version 3 directories have a file type field. Additions to this 165 list are an on-disk format change, requiring feature bits. Valid values 166 are as follows: 167 */ 168 #define XFS_DIR3_FT_UNKNOWN 0 169 #define XFS_DIR3_FT_REG_FILE 1 170 #define XFS_DIR3_FT_DIR 2 171 #define XFS_DIR3_FT_CHRDEV 3 172 #define XFS_DIR3_FT_BLKDEV 4 173 #define XFS_DIR3_FT_FIFO 5 174 #define XFS_DIR3_FT_SOCK 6 175 #define XFS_DIR3_FT_SYMLINK 7 176 #define XFS_DIR3_FT_WHT 8 177 178 #define XFS_DIR3_FT_MAX 9 179 180 181 /* 182 * The dinode is the same for all types of inodes, the data and attribute 183 * fork might be different and that is to be handled accordingly. 184 */ 185 class Inode { 186 public: 187 typedef struct Dinode{ 188 public: 189 uint16 di_magic; 190 uint16 di_mode; 191 // uses standard S_Ixxx 192 int8 di_version; 193 //This either would be 1 or 2 194 int8 di_format; 195 uint16 di_onlink; 196 uint32 di_uid; 197 uint32 di_gid; 198 uint32 di_nlink; 199 uint16 di_projid; 200 uint8 di_pad[8]; 201 uint16 di_flushiter; 202 xfs_timestamp_t di_atime; 203 xfs_timestamp_t di_mtime; 204 xfs_timestamp_t di_ctime; 205 xfs_fsize_t di_size; 206 // size in bytes or length if link 207 xfs_rfsblock_t di_nblocks; 208 // blocks used including metadata 209 // extended attributes not included 210 xfs_extlen_t di_extsize; 211 // extent size 212 xfs_extnum_t di_nextents; 213 // number of data extents 214 xfs_aextnum_t di_naextents; 215 // number of EA extents 216 uint8 di_forkoff; 217 // decides where di_a starts 218 int8 di_aformat; 219 // similar to di_format 220 uint32 di_dmevmask; 221 uint16 di_dmstate; 222 uint16 di_flags; 223 uint32 di_gen; 224 uint32 di_next_unlinked; 225 226 // XFS Version 5 227 228 uint32 di_crc; 229 uint64 di_changecount; 230 uint64 di_lsn; 231 uint64 di_flags2; 232 uint32 di_cowextsize; 233 uint8 di_pad2[12]; 234 235 // fields only written to during inode creation 236 237 xfs_timestamp_t di_crtime; 238 uint64 di_ino; 239 uuid_t di_uuid; 240 }; 241 242 Inode(Volume* volume, xfs_ino_t id); 243 ~Inode(); 244 245 status_t Init(); 246 247 xfs_ino_t ID() const { return fId; } 248 249 bool VerifyInode() const; 250 251 bool VerifyForkoff() const; 252 253 bool VerifyFork(int WhichFork) const; 254 255 bool IsDirectory() const 256 { return S_ISDIR(Mode()); } 257 258 bool IsFile() const 259 { return S_ISREG(Mode()); } 260 261 bool IsSymLink() const 262 { return S_ISLNK(Mode()); } 263 264 mode_t Mode() const { return fNode->di_mode; } 265 266 Volume* GetVolume() { return fVolume;} 267 268 int8 Format() const { return fNode->di_format; } 269 270 int8 AttrFormat() const { return fNode->di_aformat; } 271 272 bool IsLocal() const 273 { return Format() == XFS_DINODE_FMT_LOCAL; } 274 275 uint32 NLink() const { return fNode->di_nlink; } 276 277 int8 Version() const { return fNode->di_version; } 278 279 xfs_rfsblock_t BlockCount() const 280 { return fNode->di_nblocks; } 281 282 char* Buffer() { return fBuffer; } 283 284 int16 Flags() const { return fNode->di_flags; } 285 286 xfs_fsize_t Size() const { return fNode->di_size; } 287 288 uint32 DirBlockSize() const 289 { return fVolume->DirBlockSize(); } 290 291 uint32 BlockSize() const 292 { return fVolume->BlockSize(); } 293 294 uint32 CoreInodeSize() const; 295 296 void GetChangeTime(struct timespec& timestamp) const; 297 298 void GetModificationTime(struct timespec& timestamp) const; 299 300 void GetAccessTime(struct timespec& timestamp) const; 301 302 void GetCreationTime(struct timespec& timestamp) const; 303 304 unsigned char XfsModeToFtype() const; 305 status_t CheckPermissions(int accessMode) const; 306 uint32 UserId() const { return fNode->di_uid; } 307 uint32 GroupId() const { return fNode->di_gid; } 308 bool HasFileTypeField() const; 309 xfs_extnum_t DataExtentsCount() const 310 { return fNode->di_nextents; } 311 xfs_extnum_t AttrExtentsCount() const 312 { return fNode->di_naextents; } 313 uint64 FileSystemBlockToAddr(uint64 block); 314 uint8 ForkOffset() const 315 { return fNode->di_forkoff; } 316 status_t ReadExtents(); 317 status_t ReadAt(off_t pos, uint8* buffer, size_t* length); 318 status_t GetNodefromTree(uint16& levelsInTree, 319 Volume* volume, ssize_t& len, 320 size_t DirBlockSize, char* block); 321 int SearchMapInAllExtent(uint64 blockNo); 322 void UnWrapExtentFromWrappedEntry( 323 uint64 wrappedExtent[2], 324 ExtentMapEntry* entry); 325 status_t ReadExtentsFromExtentBasedInode(); 326 status_t ReadExtentsFromTreeInode(); 327 size_t MaxRecordsPossibleInTreeRoot(); 328 size_t MaxRecordsPossibleNode(); 329 TreePointer* GetPtrFromRoot(int pos); 330 TreePointer* GetPtrFromNode(int pos, void* buffer); 331 size_t GetPtrOffsetIntoRoot(int pos); 332 size_t GetPtrOffsetIntoNode(int pos); 333 uint32 SizeOfLongBlock(); 334 private: 335 void SwapEndian(); 336 private: 337 status_t GetFromDisk(); 338 Dinode* fNode; 339 xfs_ino_t fId; 340 Volume* fVolume; 341 char* fBuffer; 342 // Contains the disk inode in BE format 343 ExtentMapEntry* fExtents; 344 }; 345 346 347 uint32 hashfunction(const char* name, int length); 348 349 350 // A common function to return given hash lowerbound 351 template<class T> void 352 hashLowerBound(T* entry, int& left, int& right, uint32 hashValueOfRequest) 353 { 354 int mid; 355 356 /* 357 * Trying to find the lowerbound of hashValueOfRequest 358 * This is slightly different from bsearch(), as we want the first 359 * instance of hashValueOfRequest and not any instance. 360 */ 361 while (left < right) { 362 mid = (left + right) / 2; 363 uint32 hashval = B_BENDIAN_TO_HOST_INT32(entry[mid].hashval); 364 if (hashval >= hashValueOfRequest) { 365 right = mid; 366 continue; 367 } 368 if (hashval < hashValueOfRequest) 369 left = mid+1; 370 } 371 TRACE("left:(%" B_PRId32 "), right:(%" B_PRId32 ")\n", left, right); 372 } 373 374 #endif 375