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