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 DIR_AFORK_EXIST(dir_ino_ptr) (dir_ino_ptr->di_forkoff != 0) 67 68 #define MASK(n) ((1UL << n) - 1) 69 #define FSBLOCKS_TO_AGNO(n, volume) ((n) >> volume->AgBlocksLog()) 70 #define FSBLOCKS_TO_AGBLOCKNO(n, volume) ((n) & MASK(volume->AgBlocksLog())) 71 #define BLOCKNO_FROM_POSITION(n, volume) \ 72 ((n) >> (volume->BlockLog())) 73 #define BLOCKOFFSET_FROM_POSITION(n, inode) ((n) & (inode->BlockSize() - 1)) 74 75 #define MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) 76 77 // Inode fork identifiers 78 #define XFS_DATA_FORK 0 79 #define XFS_ATTR_FORK 1 80 81 #define XFS_DFORK_FORMAT(ino, w) \ 82 ((w) == XFS_DATA_FORK ? (ino)->di_format : (ino)->di_aformat) 83 84 #define XFS_DFORK_NEXTENTS(ino, w) \ 85 ((w) == XFS_DATA_FORK ? (ino)->di_nextents : (ino)->di_naextents) 86 87 #define DFORK_MAXEXT(ino, volume, w) \ 88 (DFORK_SIZE(ino, volume, w) / (2 * sizeof(uint64))) 89 90 91 struct LongBlock; // Forward declaration to remove cyclic dependency 92 93 94 // xfs_bmdr_block 95 struct BlockInDataFork { 96 uint16 Levels() 97 { return 98 B_BENDIAN_TO_HOST_INT16(bb_level); } 99 uint16 NumRecords() 100 { return 101 B_BENDIAN_TO_HOST_INT16(bb_numrecs); } 102 uint16 bb_level; 103 uint16 bb_numrecs; 104 }; 105 106 107 //xfs_da_blkinfo_t 108 struct BlockInfo { 109 uint32 forw; 110 uint32 back; 111 uint16 magic; 112 uint16 pad; 113 }; 114 115 116 // xfs_da3_blkinfo_t 117 struct BlockInfoV5 { 118 uint32 forw; 119 uint32 back; 120 uint16 magic; 121 uint16 pad; 122 123 // version 5 124 125 uint32 crc; 126 uint64 blkno; 127 uint64 lsn; 128 uuid_t uuid; 129 uint64 owner; 130 }; 131 132 #define XFS_BLOCK_CRC_OFF offsetof(struct BlockInfo, crc) 133 134 135 struct ExtentMapEntry { 136 xfs_fileoff_t br_startoff; 137 // logical file block offset 138 xfs_fsblock_t br_startblock; 139 // absolute block number 140 xfs_filblks_t br_blockcount; 141 // # of blocks 142 uint8 br_state; 143 // state of the extent 144 }; 145 146 147 struct xfs_timestamp_t { 148 int32 t_sec; 149 int32 t_nsec; 150 }; 151 152 153 enum xfs_dinode_fmt_t { 154 XFS_DINODE_FMT_DEV, 155 // For devices 156 XFS_DINODE_FMT_LOCAL, 157 // For Directories and links 158 XFS_DINODE_FMT_EXTENTS, 159 // For large number of extents 160 XFS_DINODE_FMT_BTREE, 161 // Extents and Directories 162 XFS_DINODE_FMT_UUID, 163 // Not used 164 }; 165 166 167 #define XFS_INODE_FORMAT_STR \ 168 { XFS_DINODE_FMT_DEV, "dev" }, \ 169 { XFS_DINODE_FMT_LOCAL, "local" }, \ 170 { XFS_DINODE_FMT_EXTENTS, "extent" }, \ 171 { XFS_DINODE_FMT_BTREE, "btree" }, \ 172 { XFS_DINODE_FMT_UUID, "uuid" } 173 174 175 /* 176 Dirents in version 3 directories have a file type field. Additions to this 177 list are an on-disk format change, requiring feature bits. Valid values 178 are as follows: 179 */ 180 #define XFS_DIR3_FT_UNKNOWN 0 181 #define XFS_DIR3_FT_REG_FILE 1 182 #define XFS_DIR3_FT_DIR 2 183 #define XFS_DIR3_FT_CHRDEV 3 184 #define XFS_DIR3_FT_BLKDEV 4 185 #define XFS_DIR3_FT_FIFO 5 186 #define XFS_DIR3_FT_SOCK 6 187 #define XFS_DIR3_FT_SYMLINK 7 188 #define XFS_DIR3_FT_WHT 8 189 190 #define XFS_DIR3_FT_MAX 9 191 192 193 /* 194 * The xfs_ino_t is the same for all types of inodes, the data and attribute 195 * fork might be different and that is to be handled accordingly. 196 */ 197 struct xfs_inode_t { 198 void SwapEndian(); 199 int8 Version() const; 200 mode_t Mode() const; 201 void GetModificationTime(struct timespec& 202 timestamp); 203 void GetChangeTime(struct timespec& timestamp); 204 void GetAccessTime(struct timespec& timestamp); 205 void GetCreationTime(struct timespec& timestamp); 206 207 int8 Format() const; 208 // The format of the inode 209 int8 AttrFormat() const; 210 xfs_fsize_t Size() const; 211 xfs_rfsblock_t BlockCount() const; 212 uint32 NLink() const; 213 uint16 Flags() const; 214 uint32 UserId() const; 215 uint32 GroupId() const; 216 xfs_extnum_t DataExtentsCount() const; 217 xfs_extnum_t AttrExtentsCount() const; 218 uint8 ForkOffset() const; 219 uint16 di_magic; 220 uint16 di_mode; 221 // uses standard S_Ixxx 222 int8 di_version; 223 //This either would be 1 or 2 224 int8 di_format; 225 uint16 di_onlink; 226 uint32 di_uid; 227 uint32 di_gid; 228 uint32 di_nlink; 229 uint16 di_projid; 230 uint8 di_pad[8]; 231 uint16 di_flushiter; 232 xfs_timestamp_t di_atime; 233 xfs_timestamp_t di_mtime; 234 xfs_timestamp_t di_ctime; 235 xfs_fsize_t di_size; 236 // size in bytes or length if link 237 xfs_rfsblock_t di_nblocks; 238 // blocks used including metadata 239 // extended attributes not included 240 xfs_extlen_t di_extsize; 241 // extent size 242 xfs_extnum_t di_nextents; 243 // number of data extents 244 xfs_aextnum_t di_naextents; 245 // number of EA extents 246 uint8 di_forkoff; 247 // decides where di_a starts 248 int8 di_aformat; 249 // similar to di_format 250 uint32 di_dmevmask; 251 uint16 di_dmstate; 252 uint16 di_flags; 253 uint32 di_gen; 254 uint32 di_next_unlinked; 255 256 // XFS Version 5 257 258 uint32 di_crc; 259 uint64 di_changecount; 260 uint64 di_lsn; 261 uint64 di_flags2; 262 uint32 di_cowextsize; 263 uint8 di_pad2[12]; 264 265 // fields only written to during inode creation 266 267 xfs_timestamp_t di_crtime; 268 uint64 di_ino; 269 uuid_t di_uuid; 270 }; 271 272 273 // Values for di_flags 274 #define XFS_DIFLAG_REALTIME_BIT 0 // file's blocks come from rt area 275 #define XFS_DIFLAG_PREALLOC_BIT 1 // file space has been preallocated 276 #define XFS_DIFLAG_NEWRTBM_BIT 2 // for rtbitmap inode, new format 277 #define XFS_DIFLAG_IMMUTABLE_BIT 3 // inode is immutable 278 #define XFS_DIFLAG_APPEND_BIT 4 // inode is append-only 279 #define XFS_DIFLAG_SYNC_BIT 5 // inode is written synchronously 280 #define XFS_DIFLAG_NOATIME_BIT 6 // do not update atime 281 #define XFS_DIFLAG_NODUMP_BIT 7 // do not dump 282 #define XFS_DIFLAG_RTINHERIT_BIT 8 // create with realtime bit set 283 #define XFS_DIFLAG_PROJINHERIT_BIT 9 // create with parents projid 284 #define XFS_DIFLAG_NOSYMLINKS_BIT 10 // disallow symlink creation 285 #define XFS_DIFLAG_EXTSIZE_BIT 11 // inode extent size allocator hint 286 #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 // inherit inode extent size 287 #define XFS_DIFLAG_NODEFRAG_BIT 13 // do not reorganize/defragment 288 #define XFS_DIFLAG_FILESTREAM_BIT 14 // use filestream allocator 289 290 #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) 291 #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) 292 #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) 293 #define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT) 294 #define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT) 295 #define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) 296 #define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) 297 #define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) 298 #define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT) 299 #define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT) 300 #define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) 301 #define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) 302 #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) 303 #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) 304 #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) 305 306 #define XFS_DIFLAG_ANY \ 307 (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ 308 XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ 309 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ 310 XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ 311 XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) 312 313 /* 314 Values for di_flags2 These start by being exposed to userspace in the upper 315 16 bits of the XFS_XFLAG_S range. 316 */ 317 #define XFS_DIFLAG2_DAX_BIT 0 // use DAX for this inode 318 #define XFS_DIFLAG2_REFLINK_BIT 1 // file's blocks may be shared 319 #define XFS_DIFLAG2_COWEXTSIZE_BIT 2 // copy on write extent size hint 320 #define XFS_DIFLAG2_BIGTIME_BIT 3 // big timestamps 321 322 #define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT) 323 #define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT) 324 #define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT) 325 #define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) 326 327 #define XFS_DIFLAG2_ANY \ 328 (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \ 329 XFS_DIFLAG2_BIGTIME) 330 331 class Inode { 332 public: 333 Inode(Volume* volume, xfs_ino_t id); 334 ~Inode(); 335 336 status_t Init(); 337 338 xfs_ino_t ID() const { return fId; } 339 340 bool VerifyInode() const; 341 342 bool VerifyForkoff() const; 343 344 bool VerifyFork(int WhichFork) const; 345 346 bool IsDirectory() const 347 { return S_ISDIR(Mode()); } 348 349 bool IsFile() const 350 { return S_ISREG(Mode()); } 351 352 bool IsSymLink() const 353 { return S_ISLNK(Mode()); } 354 355 mode_t Mode() const { return fNode->Mode(); } 356 357 Volume* GetVolume() { return fVolume;} 358 359 int8 Format() const { return fNode->Format(); } 360 361 int8 AttrFormat() const { return fNode->AttrFormat(); } 362 363 bool IsLocal() const 364 { return 365 Format() == XFS_DINODE_FMT_LOCAL; } 366 367 uint32 NLink() const { return fNode->NLink(); } 368 369 int8 Version() const { return fNode->Version(); } 370 371 xfs_rfsblock_t BlockCount() const 372 { return fNode->BlockCount(); } 373 374 char* Buffer() { return fBuffer; } 375 376 int16 Flags() const { return fNode->Flags(); } 377 378 xfs_fsize_t Size() const { return fNode->Size(); } 379 380 uint32 DirBlockSize() const 381 { return fVolume->DirBlockSize(); } 382 383 uint32 BlockSize() const 384 { return fVolume->BlockSize(); } 385 386 uint32 CoreInodeSize() const; 387 388 void GetChangeTime(struct timespec& timestamp) const 389 { fNode->GetChangeTime(timestamp); } 390 391 void GetModificationTime(struct timespec& timestamp) 392 const 393 { fNode->GetModificationTime(timestamp); } 394 395 void GetAccessTime(struct timespec& timestamp) const 396 { fNode->GetAccessTime(timestamp); } 397 398 void GetCreationTime(struct timespec& timestamp) const 399 { fNode->GetCreationTime(timestamp); } 400 401 unsigned char XfsModeToFtype() const; 402 status_t CheckPermissions(int accessMode) const; 403 uint32 UserId() const { return fNode->UserId(); } 404 uint32 GroupId() const { return fNode->GroupId(); } 405 bool HasFileTypeField() const; 406 xfs_extnum_t DataExtentsCount() const 407 { return fNode->DataExtentsCount(); } 408 xfs_extnum_t AttrExtentsCount() const 409 { return fNode->AttrExtentsCount(); } 410 uint64 FileSystemBlockToAddr(uint64 block); 411 uint8 ForkOffset() const 412 { return fNode->ForkOffset(); } 413 status_t ReadExtents(); 414 status_t ReadAt(off_t pos, uint8* buffer, size_t* length); 415 status_t GetNodefromTree(uint16& levelsInTree, 416 Volume* volume, ssize_t& len, 417 size_t DirBlockSize, char* block); 418 int SearchMapInAllExtent(uint64 blockNo); 419 void UnWrapExtentFromWrappedEntry( 420 uint64 wrappedExtent[2], 421 ExtentMapEntry* entry); 422 status_t ReadExtentsFromExtentBasedInode(); 423 status_t ReadExtentsFromTreeInode(); 424 size_t MaxRecordsPossibleInTreeRoot(); 425 size_t MaxRecordsPossibleNode(); 426 TreePointer* GetPtrFromRoot(int pos); 427 TreePointer* GetPtrFromNode(int pos, void* buffer); 428 size_t GetPtrOffsetIntoRoot(int pos); 429 size_t GetPtrOffsetIntoNode(int pos); 430 uint32 SizeOfLongBlock(); 431 private: 432 status_t GetFromDisk(); 433 xfs_inode_t* fNode; 434 xfs_ino_t fId; 435 Volume* fVolume; 436 char* fBuffer; 437 // Contains the disk inode in BE format 438 ExtentMapEntry* fExtents; 439 }; 440 441 442 uint32 hashfunction(const char* name, int length); 443 444 445 // A common function to return given hash lowerbound 446 template<class T> void 447 hashLowerBound(T* entry, int& left, int& right, uint32 hashValueOfRequest) 448 { 449 int mid; 450 451 /* 452 * Trying to find the lowerbound of hashValueOfRequest 453 * This is slightly different from bsearch(), as we want the first 454 * instance of hashValueOfRequest and not any instance. 455 */ 456 while (left < right) { 457 mid = (left + right) / 2; 458 uint32 hashval = B_BENDIAN_TO_HOST_INT32(entry[mid].hashval); 459 if (hashval >= hashValueOfRequest) { 460 right = mid; 461 continue; 462 } 463 if (hashval < hashValueOfRequest) 464 left = mid+1; 465 } 466 TRACE("left:(%" B_PRId32 "), right:(%" B_PRId32 ")\n", left, right); 467 } 468 469 #endif 470