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_anextents) 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 uint32 148 hashfunction(const char* name, int length); 149 150 151 struct xfs_timestamp_t { 152 int32 t_sec; 153 int32 t_nsec; 154 }; 155 156 157 enum xfs_dinode_fmt_t { 158 XFS_DINODE_FMT_DEV, 159 // For devices 160 XFS_DINODE_FMT_LOCAL, 161 // For Directories and links 162 XFS_DINODE_FMT_EXTENTS, 163 // For large number of extents 164 XFS_DINODE_FMT_BTREE, 165 // Extents and Directories 166 XFS_DINODE_FMT_UUID, 167 // Not used 168 }; 169 170 171 #define XFS_INODE_FORMAT_STR \ 172 { XFS_DINODE_FMT_DEV, "dev" }, \ 173 { XFS_DINODE_FMT_LOCAL, "local" }, \ 174 { XFS_DINODE_FMT_EXTENTS, "extent" }, \ 175 { XFS_DINODE_FMT_BTREE, "btree" }, \ 176 { XFS_DINODE_FMT_UUID, "uuid" } 177 178 179 /* 180 Dirents in version 3 directories have a file type field. Additions to this 181 list are an on-disk format change, requiring feature bits. Valid values 182 are as follows: 183 */ 184 #define XFS_DIR3_FT_UNKNOWN 0 185 #define XFS_DIR3_FT_REG_FILE 1 186 #define XFS_DIR3_FT_DIR 2 187 #define XFS_DIR3_FT_CHRDEV 3 188 #define XFS_DIR3_FT_BLKDEV 4 189 #define XFS_DIR3_FT_FIFO 5 190 #define XFS_DIR3_FT_SOCK 6 191 #define XFS_DIR3_FT_SYMLINK 7 192 #define XFS_DIR3_FT_WHT 8 193 194 #define XFS_DIR3_FT_MAX 9 195 196 197 /* 198 * The xfs_ino_t is the same for all types of inodes, the data and attribute 199 * fork might be different and that is to be handled accordingly. 200 */ 201 struct xfs_inode_t { 202 void SwapEndian(); 203 int8 Version() const; 204 mode_t Mode() const; 205 void GetModificationTime(struct timespec& 206 timestamp); 207 void GetChangeTime(struct timespec& timestamp); 208 void GetAccessTime(struct timespec& timestamp); 209 void GetCreationTime(struct timespec& timestamp); 210 211 int8 Format() const; 212 // The format of the inode 213 int8 AttrFormat() const; 214 xfs_fsize_t Size() const; 215 xfs_rfsblock_t BlockCount() const; 216 uint32 NLink() const; 217 uint16 Flags() const; 218 uint32 UserId() const; 219 uint32 GroupId() const; 220 xfs_extnum_t DataExtentsCount() const; 221 uint8 ForkOffset() const; 222 uint16 di_magic; 223 uint16 di_mode; 224 // uses standard S_Ixxx 225 int8 di_version; 226 //This either would be 1 or 2 227 int8 di_format; 228 uint16 di_onlink; 229 uint32 di_uid; 230 uint32 di_gid; 231 uint32 di_nlink; 232 uint16 di_projid; 233 uint8 di_pad[8]; 234 uint16 di_flushiter; 235 xfs_timestamp_t di_atime; 236 xfs_timestamp_t di_mtime; 237 xfs_timestamp_t di_ctime; 238 xfs_fsize_t di_size; 239 // size in bytes or length if link 240 xfs_rfsblock_t di_nblocks; 241 // blocks used including metadata 242 // extended attributes not included 243 xfs_extlen_t di_extsize; 244 // extent size 245 xfs_extnum_t di_nextents; 246 // number of data extents 247 xfs_aextnum_t di_anextents; 248 // number of EA extents 249 uint8 di_forkoff; 250 // decides where di_a starts 251 int8 di_aformat; 252 // similar to di_format 253 uint32 di_dmevmask; 254 uint16 di_dmstate; 255 uint16 di_flags; 256 uint32 di_gen; 257 uint32 di_next_unlinked; 258 259 // XFS Version 5 260 261 uint32 di_crc; 262 uint64 di_changecount; 263 uint64 di_lsn; 264 uint64 di_flags2; 265 uint32 di_cowextsize; 266 uint8 di_pad2[12]; 267 268 // fields only written to during inode creation 269 270 xfs_timestamp_t di_crtime; 271 uint64 di_ino; 272 uuid_t di_uuid; 273 }; 274 275 276 // Values for di_flags 277 #define XFS_DIFLAG_REALTIME_BIT 0 // file's blocks come from rt area 278 #define XFS_DIFLAG_PREALLOC_BIT 1 // file space has been preallocated 279 #define XFS_DIFLAG_NEWRTBM_BIT 2 // for rtbitmap inode, new format 280 #define XFS_DIFLAG_IMMUTABLE_BIT 3 // inode is immutable 281 #define XFS_DIFLAG_APPEND_BIT 4 // inode is append-only 282 #define XFS_DIFLAG_SYNC_BIT 5 // inode is written synchronously 283 #define XFS_DIFLAG_NOATIME_BIT 6 // do not update atime 284 #define XFS_DIFLAG_NODUMP_BIT 7 // do not dump 285 #define XFS_DIFLAG_RTINHERIT_BIT 8 // create with realtime bit set 286 #define XFS_DIFLAG_PROJINHERIT_BIT 9 // create with parents projid 287 #define XFS_DIFLAG_NOSYMLINKS_BIT 10 // disallow symlink creation 288 #define XFS_DIFLAG_EXTSIZE_BIT 11 // inode extent size allocator hint 289 #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 // inherit inode extent size 290 #define XFS_DIFLAG_NODEFRAG_BIT 13 // do not reorganize/defragment 291 #define XFS_DIFLAG_FILESTREAM_BIT 14 // use filestream allocator 292 293 #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) 294 #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) 295 #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) 296 #define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT) 297 #define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT) 298 #define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) 299 #define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) 300 #define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) 301 #define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT) 302 #define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT) 303 #define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) 304 #define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) 305 #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) 306 #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) 307 #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) 308 309 #define XFS_DIFLAG_ANY \ 310 (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ 311 XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ 312 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ 313 XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ 314 XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) 315 316 /* 317 Values for di_flags2 These start by being exposed to userspace in the upper 318 16 bits of the XFS_XFLAG_S range. 319 */ 320 #define XFS_DIFLAG2_DAX_BIT 0 // use DAX for this inode 321 #define XFS_DIFLAG2_REFLINK_BIT 1 // file's blocks may be shared 322 #define XFS_DIFLAG2_COWEXTSIZE_BIT 2 // copy on write extent size hint 323 #define XFS_DIFLAG2_BIGTIME_BIT 3 // big timestamps 324 325 #define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT) 326 #define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT) 327 #define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT) 328 #define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) 329 330 #define XFS_DIFLAG2_ANY \ 331 (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \ 332 XFS_DIFLAG2_BIGTIME) 333 334 class Inode { 335 public: 336 Inode(Volume* volume, xfs_ino_t id); 337 ~Inode(); 338 339 status_t Init(); 340 341 xfs_ino_t ID() const { return fId; } 342 343 bool VerifyInode() const; 344 345 bool VerifyForkoff() const; 346 347 bool VerifyFork(int WhichFork) const; 348 349 bool IsDirectory() const 350 { return S_ISDIR(Mode()); } 351 352 bool IsFile() const 353 { return S_ISREG(Mode()); } 354 355 bool IsSymLink() const 356 { return S_ISLNK(Mode()); } 357 358 mode_t Mode() const { return fNode->Mode(); } 359 360 Volume* GetVolume() { return fVolume;} 361 362 int8 Format() const { return fNode->Format(); } 363 364 int8 AttrFormat() const { return fNode->AttrFormat(); } 365 366 bool IsLocal() const 367 { return 368 Format() == XFS_DINODE_FMT_LOCAL; } 369 370 uint32 NLink() const { return fNode->NLink(); } 371 372 int8 Version() const { return fNode->Version(); } 373 374 xfs_rfsblock_t BlockCount() const 375 { return fNode->BlockCount(); } 376 377 char* Buffer() { return fBuffer; } 378 379 int16 Flags() const { return fNode->Flags(); } 380 381 xfs_fsize_t Size() const { return fNode->Size(); } 382 383 uint32 DirBlockSize() const 384 { return fVolume->DirBlockSize(); } 385 386 uint32 BlockSize() const 387 { return fVolume->BlockSize(); } 388 389 uint32 CoreInodeSize() const; 390 391 void GetChangeTime(struct timespec& timestamp) const 392 { fNode->GetChangeTime(timestamp); } 393 394 void GetModificationTime(struct timespec& timestamp) 395 const 396 { fNode->GetModificationTime(timestamp); } 397 398 void GetAccessTime(struct timespec& timestamp) const 399 { fNode->GetAccessTime(timestamp); } 400 401 void GetCreationTime(struct timespec& timestamp) const 402 { fNode->GetCreationTime(timestamp); } 403 404 unsigned char XfsModeToFtype() const; 405 status_t CheckPermissions(int accessMode) const; 406 uint32 UserId() const { return fNode->UserId(); } 407 uint32 GroupId() const { return fNode->GroupId(); } 408 bool HasFileTypeField() const; 409 xfs_extnum_t DataExtentsCount() const 410 { return fNode->DataExtentsCount(); } 411 uint64 FileSystemBlockToAddr(uint64 block); 412 uint8 ForkOffset() const 413 { return fNode->ForkOffset(); } 414 status_t ReadExtents(); 415 status_t ReadAt(off_t pos, uint8* buffer, size_t* length); 416 status_t GetNodefromTree(uint16& levelsInTree, 417 Volume* volume, ssize_t& len, 418 size_t DirBlockSize, char* block); 419 int SearchMapInAllExtent(uint64 blockNo); 420 void UnWrapExtentFromWrappedEntry( 421 uint64 wrappedExtent[2], 422 ExtentMapEntry* entry); 423 status_t ReadExtentsFromExtentBasedInode(); 424 status_t ReadExtentsFromTreeInode(); 425 size_t MaxRecordsPossibleInTreeRoot(); 426 size_t MaxRecordsPossibleNode(); 427 TreePointer* GetPtrFromRoot(int pos); 428 TreePointer* GetPtrFromNode(int pos, void* buffer); 429 size_t GetPtrOffsetIntoRoot(int pos); 430 size_t GetPtrOffsetIntoNode(int pos); 431 uint32 SizeOfLongBlock(); 432 private: 433 status_t GetFromDisk(); 434 xfs_inode_t* fNode; 435 xfs_ino_t fId; 436 Volume* fVolume; 437 char* fBuffer; 438 // Contains the disk inode in BE format 439 ExtentMapEntry* fExtents; 440 }; 441 442 #endif 443