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 7 8 #include "Inode.h" 9 10 #include "BPlusTree.h" 11 #include "VerifyHeader.h" 12 13 14 void 15 Inode::SwapEndian() 16 { 17 fNode->di_magic = B_BENDIAN_TO_HOST_INT16(fNode->di_magic); 18 fNode->di_mode = B_BENDIAN_TO_HOST_INT16(fNode->di_mode); 19 fNode->di_onlink = B_BENDIAN_TO_HOST_INT16(fNode->di_onlink); 20 fNode->di_uid = B_BENDIAN_TO_HOST_INT32(fNode->di_uid); 21 fNode->di_gid = B_BENDIAN_TO_HOST_INT32(fNode->di_gid); 22 fNode->di_nlink = B_BENDIAN_TO_HOST_INT32(fNode->di_nlink); 23 fNode->di_projid = B_BENDIAN_TO_HOST_INT16(fNode->di_projid); 24 fNode->di_flushiter = B_BENDIAN_TO_HOST_INT16(fNode->di_flushiter); 25 fNode->di_atime.t_sec = B_BENDIAN_TO_HOST_INT32(fNode->di_atime.t_sec); 26 fNode->di_atime.t_nsec = B_BENDIAN_TO_HOST_INT32(fNode->di_atime.t_nsec); 27 fNode->di_mtime.t_sec = B_BENDIAN_TO_HOST_INT32(fNode->di_mtime.t_sec); 28 fNode->di_mtime.t_nsec = B_BENDIAN_TO_HOST_INT32(fNode->di_mtime.t_nsec); 29 fNode->di_ctime.t_sec = B_BENDIAN_TO_HOST_INT32(fNode->di_ctime.t_sec); 30 fNode->di_ctime.t_nsec = B_BENDIAN_TO_HOST_INT32(fNode->di_ctime.t_nsec); 31 fNode->di_size = B_BENDIAN_TO_HOST_INT64(fNode->di_size); 32 fNode->di_nblocks = B_BENDIAN_TO_HOST_INT64(fNode->di_nblocks); 33 fNode->di_extsize = B_BENDIAN_TO_HOST_INT32(fNode->di_extsize); 34 fNode->di_nextents = B_BENDIAN_TO_HOST_INT32(fNode->di_nextents); 35 fNode->di_naextents = B_BENDIAN_TO_HOST_INT16(fNode->di_naextents); 36 fNode->di_dmevmask = B_BENDIAN_TO_HOST_INT32(fNode->di_dmevmask); 37 fNode->di_dmstate = B_BENDIAN_TO_HOST_INT16(fNode->di_dmstate); 38 fNode->di_flags = B_BENDIAN_TO_HOST_INT16(fNode->di_flags); 39 fNode->di_gen = B_BENDIAN_TO_HOST_INT32(fNode->di_gen); 40 fNode->di_next_unlinked = B_BENDIAN_TO_HOST_INT32(fNode->di_next_unlinked); 41 fNode->di_changecount = B_BENDIAN_TO_HOST_INT64(fNode->di_changecount); 42 fNode->di_lsn = B_BENDIAN_TO_HOST_INT64(fNode->di_lsn); 43 fNode->di_flags2 = B_BENDIAN_TO_HOST_INT64(fNode->di_flags2); 44 fNode->di_cowextsize = B_BENDIAN_TO_HOST_INT64(fNode->di_cowextsize); 45 fNode->di_crtime.t_sec = B_BENDIAN_TO_HOST_INT32(fNode->di_crtime.t_sec); 46 fNode->di_crtime.t_nsec = B_BENDIAN_TO_HOST_INT32(fNode->di_crtime.t_nsec); 47 fNode->di_ino = B_BENDIAN_TO_HOST_INT64(fNode->di_ino); 48 } 49 50 51 void 52 Inode::GetModificationTime(struct timespec& stamp) const 53 { 54 stamp.tv_sec = fNode->di_mtime.t_sec; 55 stamp.tv_nsec = fNode->di_mtime.t_nsec; 56 } 57 58 59 void 60 Inode::GetAccessTime(struct timespec& stamp) const 61 { 62 stamp.tv_sec = fNode->di_atime.t_sec; 63 stamp.tv_nsec = fNode->di_atime.t_nsec; 64 } 65 66 67 void 68 Inode::GetChangeTime(struct timespec& stamp) const 69 { 70 stamp.tv_sec = fNode->di_ctime.t_sec; 71 stamp.tv_nsec = fNode->di_ctime.t_nsec; 72 } 73 74 75 void 76 Inode::GetCreationTime(struct timespec& stamp) const 77 { 78 stamp.tv_sec = fNode->di_crtime.t_sec; 79 stamp.tv_nsec = fNode->di_crtime.t_nsec; 80 } 81 82 83 Inode::Inode(Volume* volume, xfs_ino_t id) 84 : 85 fId(id), 86 fVolume(volume), 87 fBuffer(NULL), 88 fExtents(NULL) 89 { 90 } 91 92 93 //Convert inode mode to directory entry filetype 94 unsigned char 95 Inode::XfsModeToFtype() const 96 { 97 switch (Mode() & S_IFMT) { 98 case S_IFREG: 99 return XFS_DIR3_FT_REG_FILE; 100 case S_IFDIR: 101 return XFS_DIR3_FT_DIR; 102 case S_IFCHR: 103 return XFS_DIR3_FT_CHRDEV; 104 case S_IFBLK: 105 return XFS_DIR3_FT_BLKDEV; 106 case S_IFIFO: 107 return XFS_DIR3_FT_FIFO; 108 case S_IFSOCK: 109 return XFS_DIR3_FT_SOCK; 110 case S_IFLNK: 111 return XFS_DIR3_FT_SYMLINK; 112 default: 113 return XFS_DIR3_FT_UNKNOWN; 114 } 115 } 116 117 118 bool 119 Inode::VerifyFork(int whichFork) const 120 { 121 uint32 di_nextents = XFS_DFORK_NEXTENTS(fNode, whichFork); 122 123 switch (XFS_DFORK_FORMAT(fNode, whichFork)) { 124 case XFS_DINODE_FMT_LOCAL: 125 if (whichFork == XFS_DATA_FORK) { 126 if (S_ISREG(Mode())) 127 return false; 128 if (Size() > (xfs_fsize_t) DFORK_SIZE(fNode, fVolume, whichFork)) 129 return false; 130 } 131 if (di_nextents) 132 return false; 133 break; 134 case XFS_DINODE_FMT_EXTENTS: 135 if (di_nextents > DFORK_MAXEXT(fNode, fVolume, whichFork)) 136 return false; 137 break; 138 case XFS_DINODE_FMT_BTREE: 139 if (whichFork == XFS_ATTR_FORK) { 140 if (di_nextents > MAXAEXTNUM) 141 return false; 142 } else if (di_nextents > MAXEXTNUM) { 143 return false; 144 } 145 break; 146 default: 147 return false; 148 } 149 150 return true; 151 } 152 153 154 bool 155 Inode::VerifyForkoff() const 156 { 157 switch(Format()) { 158 case XFS_DINODE_FMT_DEV: 159 if (fNode->di_forkoff != (ROUNDUP(sizeof(uint32), 8) >> 3)) 160 return false; 161 break; 162 case XFS_DINODE_FMT_LOCAL: 163 case XFS_DINODE_FMT_EXTENTS: 164 case XFS_DINODE_FMT_BTREE: 165 if (fNode->di_forkoff >= (LITINO(fVolume) >> 3)) 166 return false; 167 break; 168 default: 169 return false; 170 } 171 172 return true; 173 } 174 175 176 bool 177 Inode::VerifyInode() const 178 { 179 if(fNode->di_magic != INODE_MAGIC) { 180 ERROR("Bad inode magic number"); 181 return false; 182 } 183 184 // check if inode version is valid 185 if (Version() < 1 || Version() > 3) { 186 ERROR("Bad inode version"); 187 return false; 188 } 189 190 // verify version 3 inodes first 191 if (Version() == 3) { 192 193 if(!HAS_V3INODES(fVolume)) { 194 ERROR("xfs v4 doesn't have v3 inodes"); 195 return false; 196 } 197 198 if(!xfs_verify_cksum(fBuffer, fVolume->InodeSize(), INODE_CRC_OFF)) { 199 ERROR("Inode is corrupted"); 200 return false; 201 } 202 203 if(fNode->di_ino != fId) { 204 ERROR("Incorrect inode number"); 205 return false; 206 } 207 208 if(!fVolume->UuidEquals(fNode->di_uuid)) { 209 ERROR("UUID is incorrect"); 210 return false; 211 } 212 } 213 214 if(fNode->di_size & (1ULL << 63)) { 215 ERROR("Invalid EOF of inode"); 216 return false; 217 } 218 219 if (Mode() && XfsModeToFtype() == XFS_DIR3_FT_UNKNOWN) { 220 ERROR("Entry points to an unknown inode type"); 221 return false; 222 } 223 224 if(!VerifyForkoff()) { 225 ERROR("Invalid inode fork offset"); 226 return false; 227 } 228 229 // Check for appropriate data fork formats for the mode 230 switch (Mode() & S_IFMT) { 231 case S_IFIFO: 232 case S_IFCHR: 233 case S_IFBLK: 234 case S_IFSOCK: 235 if (fNode->di_format != XFS_DINODE_FMT_DEV) 236 return false; 237 break; 238 case S_IFREG: 239 case S_IFLNK: 240 case S_IFDIR: 241 if (!VerifyFork(XFS_DATA_FORK)) { 242 ERROR("Invalid data fork in inode"); 243 return false; 244 } 245 break; 246 case 0: 247 // Uninitialized inode is fine 248 break; 249 default: 250 return false; 251 } 252 253 if (fNode->di_forkoff) { 254 if (!VerifyFork(XFS_ATTR_FORK)) { 255 ERROR("Invalid attribute fork in inode"); 256 return false; 257 } 258 } else { 259 /* 260 If there is no fork offset, this may be a freshly-made inode 261 in a new disk cluster, in which case di_aformat is zeroed. 262 Otherwise, such an inode must be in EXTENTS format; this goes 263 for freed inodes as well. 264 */ 265 switch (fNode->di_aformat) { 266 case 0: 267 case XFS_DINODE_FMT_EXTENTS: 268 break; 269 default: 270 return false; 271 } 272 273 if (fNode->di_naextents) 274 return false; 275 } 276 277 // TODO : Add reflink and big-timestamps check using di_flags2 278 279 return true; 280 } 281 282 283 uint32 284 Inode::CoreInodeSize() const 285 { 286 if (Version() == 3) 287 return sizeof(Dinode); 288 289 return offsetof(Dinode, di_crc); 290 } 291 292 293 status_t 294 Inode::Init() 295 { 296 fNode = new(std::nothrow) Dinode; 297 if (fNode == NULL) 298 return B_NO_MEMORY; 299 300 uint16 inodeSize = fVolume->InodeSize(); 301 fBuffer = new(std::nothrow) char[inodeSize]; 302 if (fBuffer == NULL) 303 return B_NO_MEMORY; 304 305 status_t status = GetFromDisk(); 306 if (status == B_OK) { 307 if (VerifyInode()) { 308 TRACE("Init(): Inode successfully read.\n"); 309 status = B_OK; 310 } else { 311 TRACE("Init(): Inode wasn't read successfully!\n"); 312 status = B_BAD_VALUE; 313 } 314 } 315 316 return status; 317 } 318 319 320 Inode::~Inode() 321 { 322 delete fNode; 323 delete[] fBuffer; 324 delete[] fExtents; 325 } 326 327 328 bool 329 Inode::HasFileTypeField() const 330 { 331 if ((Version() == 3 && fVolume->XfsHasIncompatFeature()) 332 || (fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE)) { 333 return true; 334 } 335 return false; 336 } 337 338 339 status_t 340 Inode::CheckPermissions(int accessMode) const 341 { 342 // you never have write access to a read-only volume 343 if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly()) 344 return B_READ_ONLY_DEVICE; 345 346 return check_access_permissions(accessMode, Mode(), (uint32)GroupId(), (uint32)UserId()); 347 } 348 349 350 uint32 351 Inode::SizeOfLongBlock() 352 { 353 if (Version() == 3) 354 return sizeof(LongBlock); 355 else 356 return LongBlock::Offset_v5(); 357 } 358 359 360 void 361 Inode::UnWrapExtentFromWrappedEntry(uint64 wrappedExtent[2], 362 ExtentMapEntry* entry) 363 { 364 uint64 first = B_BENDIAN_TO_HOST_INT64(wrappedExtent[0]); 365 uint64 second = B_BENDIAN_TO_HOST_INT64(wrappedExtent[1]); 366 entry->br_state = first >> 63; 367 entry->br_startoff = (first & MASK(63)) >> 9; 368 entry->br_startblock = ((first & MASK(9)) << 43) | (second >> 21); 369 entry->br_blockcount = second & MASK(21); 370 } 371 372 373 status_t 374 Inode::ReadExtentsFromExtentBasedInode() 375 { 376 fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()]; 377 char* dataStart = (char*) DIR_DFORK_PTR(Buffer(), CoreInodeSize()); 378 uint64 wrappedExtent[2]; 379 for (int i = 0; i < DataExtentsCount(); i++) { 380 wrappedExtent[0] = *(uint64*)(dataStart); 381 wrappedExtent[1] = *(uint64*)(dataStart + sizeof(uint64)); 382 dataStart += 2 * sizeof(uint64); 383 UnWrapExtentFromWrappedEntry(wrappedExtent, &fExtents[i]); 384 } 385 return B_OK; 386 } 387 388 389 size_t 390 Inode::MaxRecordsPossibleInTreeRoot() 391 { 392 size_t lengthOfDataFork; 393 if (ForkOffset() != 0) 394 lengthOfDataFork = ForkOffset() << 3; 395 else if(ForkOffset() == 0) { 396 lengthOfDataFork = GetVolume()->InodeSize() 397 - CoreInodeSize(); 398 } 399 400 lengthOfDataFork -= sizeof(BlockInDataFork); 401 return lengthOfDataFork / (XFS_KEY_SIZE + XFS_PTR_SIZE); 402 } 403 404 405 size_t 406 Inode::GetPtrOffsetIntoRoot(int pos) 407 { 408 size_t maxRecords = MaxRecordsPossibleInTreeRoot(); 409 return (sizeof(BlockInDataFork) 410 + maxRecords * XFS_KEY_SIZE + (pos - 1) * XFS_PTR_SIZE); 411 } 412 413 414 TreePointer* 415 Inode::GetPtrFromRoot(int pos) 416 { 417 return (TreePointer*) 418 ((char*)DIR_DFORK_PTR(Buffer(), CoreInodeSize()) + GetPtrOffsetIntoRoot(pos)); 419 } 420 421 422 size_t 423 Inode::MaxRecordsPossibleNode() 424 { 425 size_t availableSpace = GetVolume()->BlockSize(); 426 return availableSpace / (XFS_KEY_SIZE + XFS_PTR_SIZE); 427 } 428 429 430 size_t 431 Inode::GetPtrOffsetIntoNode(int pos) 432 { 433 size_t maxRecords = MaxRecordsPossibleNode(); 434 435 return SizeOfLongBlock() + maxRecords * XFS_KEY_SIZE 436 + (pos - 1) * XFS_PTR_SIZE; 437 } 438 439 440 TreePointer* 441 Inode::GetPtrFromNode(int pos, void* buffer) 442 { 443 size_t offsetIntoNode = GetPtrOffsetIntoNode(pos); 444 return (TreePointer*)((char*)buffer + offsetIntoNode); 445 } 446 447 448 status_t 449 Inode::GetNodefromTree(uint16& levelsInTree, Volume* volume, 450 ssize_t& len, size_t DirBlockSize, char* block) { 451 452 char* node = new(std::nothrow) char[len]; 453 if (node == NULL) 454 return B_NO_MEMORY; 455 // This isn't for a directory block but for one of the tree nodes 456 457 ArrayDeleter<char> nodeDeleter(node); 458 459 TRACE("levels:(%" B_PRIu16 ")\n", levelsInTree); 460 461 TreePointer* ptrToNode = GetPtrFromRoot(1); 462 uint64 fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode); 463 uint64 readPos = FileSystemBlockToAddr(fileSystemBlockNo); 464 // Go down the tree by taking the leftmost pointer to the first leaf 465 while (levelsInTree != 1) { 466 fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode); 467 // The fs block that contains node at next lower level. Now read. 468 readPos = FileSystemBlockToAddr(fileSystemBlockNo); 469 if (read_pos(volume->Device(), readPos, node, len) != len) { 470 ERROR("Extent::FillBlockBuffer(): IO Error"); 471 return B_IO_ERROR; 472 } 473 LongBlock* curLongBlock = (LongBlock*)node; 474 if (!VerifyHeader<LongBlock>(curLongBlock, node, this, 475 0, NULL, XFS_BTREE)) { 476 TRACE("Invalid Long Block"); 477 return B_BAD_VALUE; 478 } 479 ptrToNode = GetPtrFromNode(1, (void*)curLongBlock); 480 // Get's the first pointer. This points to next node. 481 levelsInTree--; 482 } 483 // Next level wil contain leaf nodes. Now Read Directory Buffer 484 len = DirBlockSize; 485 if (read_pos(volume->Device(), readPos, block, len) 486 != len) { 487 ERROR("Extent::FillBlockBuffer(): IO Error"); 488 return B_IO_ERROR; 489 } 490 levelsInTree--; 491 if (levelsInTree != 0) 492 return B_BAD_VALUE; 493 return B_OK; 494 } 495 496 497 status_t 498 Inode::ReadExtentsFromTreeInode() 499 { 500 fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()]; 501 BlockInDataFork* root = new(std::nothrow) BlockInDataFork; 502 if (root == NULL) 503 return B_NO_MEMORY; 504 memcpy((void*)root, 505 DIR_DFORK_PTR(Buffer(), CoreInodeSize()), sizeof(BlockInDataFork)); 506 507 uint16 levelsInTree = root->Levels(); 508 delete root; 509 510 Volume* volume = GetVolume(); 511 ssize_t len = volume->BlockSize(); 512 513 len = DirBlockSize(); 514 char* block = new(std::nothrow) char[len]; 515 if (block == NULL) 516 return B_NO_MEMORY; 517 518 ArrayDeleter<char> blockDeleter(block); 519 520 GetNodefromTree(levelsInTree, volume, len, DirBlockSize(), block); 521 522 uint64 fileSystemBlockNo; 523 uint64 wrappedExtent[2]; 524 int indexIntoExtents = 0; 525 // We should be at the left most leaf node. 526 // This could be a multilevel node type directory 527 while (1) { 528 // Run till you have leaf blocks to checkout 529 char* leafBuffer = block; 530 if (!VerifyHeader<LongBlock>((LongBlock*)leafBuffer, leafBuffer, this, 531 0, NULL, XFS_BTREE)) { 532 TRACE("Invalid Long Block"); 533 return B_BAD_VALUE; 534 } 535 536 uint32 offset = SizeOfLongBlock(); 537 int numRecs = ((LongBlock*)leafBuffer)->NumRecs(); 538 539 for (int i = 0; i < numRecs; i++) { 540 wrappedExtent[0] = *(uint64*)(leafBuffer + offset); 541 wrappedExtent[1] 542 = *(uint64*)(leafBuffer + offset + sizeof(uint64)); 543 offset += sizeof(ExtentMapUnwrap); 544 UnWrapExtentFromWrappedEntry(wrappedExtent, 545 &fExtents[indexIntoExtents]); 546 indexIntoExtents++; 547 } 548 549 fileSystemBlockNo = ((LongBlock*)leafBuffer)->Right(); 550 TRACE("Next leaf is at: (%" B_PRIu64 ")\n", fileSystemBlockNo); 551 if (fileSystemBlockNo == (uint64) -1) 552 break; 553 uint64 readPos = FileSystemBlockToAddr(fileSystemBlockNo); 554 if (read_pos(volume->Device(), readPos, block, len) 555 != len) { 556 ERROR("Extent::FillBlockBuffer(): IO Error"); 557 return B_IO_ERROR; 558 } 559 } 560 TRACE("Total covered: (%" B_PRId32 ")\n", indexIntoExtents); 561 return B_OK; 562 } 563 564 565 status_t 566 Inode::ReadExtents() 567 { 568 if (fExtents != NULL) 569 return B_OK; 570 if (Format() == XFS_DINODE_FMT_BTREE) 571 return ReadExtentsFromTreeInode(); 572 if (Format() == XFS_DINODE_FMT_EXTENTS) 573 return ReadExtentsFromExtentBasedInode(); 574 return B_BAD_VALUE; 575 } 576 577 578 int 579 Inode::SearchMapInAllExtent(uint64 blockNo) 580 { 581 for (int i = 0; i < DataExtentsCount(); i++) { 582 if (fExtents[i].br_startoff <= blockNo 583 && (blockNo <= fExtents[i].br_startoff 584 + fExtents[i].br_blockcount - 1)) { 585 // Map found 586 return i; 587 } 588 } 589 return -1; 590 } 591 592 593 status_t 594 Inode::ReadAt(off_t pos, uint8* buffer, size_t* length) 595 { 596 TRACE("Inode::ReadAt: pos:(%" B_PRIdOFF "), *length:(%" B_PRIuSIZE ")\n", pos, *length); 597 status_t status; 598 if (fExtents == NULL) { 599 status = ReadExtents(); 600 if (status != B_OK) 601 return status; 602 } 603 604 // set/check boundaries for pos/length 605 if (pos < 0) { 606 ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF 607 ", length %lu)\n", ID(), pos, *length); 608 return B_BAD_VALUE; 609 } 610 611 if (pos >= Size() || length == 0) { 612 TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %" B_PRIdOFF 613 ", length %" B_PRIuSIZE ")\n", ID(), pos, *length); 614 *length = 0; 615 return B_NO_ERROR; 616 } 617 618 uint32 blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume()); 619 uint32 offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this); 620 621 ssize_t lengthOfBlock = BlockSize(); 622 char* block = new(std::nothrow) char[lengthOfBlock]; 623 if (block == NULL) 624 return B_NO_MEMORY; 625 626 ArrayDeleter<char> blockDeleter(block); 627 628 size_t lengthRead = 0; 629 size_t lengthLeftInFile; 630 size_t lengthLeftInBlock; 631 size_t lengthToRead; 632 TRACE("What is blockLen:(%" B_PRId64 ")\n", lengthOfBlock); 633 while (*length > 0) { 634 TRACE("Inode::ReadAt: pos:(%" B_PRIdOFF "), *length:(%" B_PRIuSIZE ")\n", pos, *length); 635 // As long as you can read full blocks, read. 636 lengthLeftInFile = Size() - pos; 637 lengthLeftInBlock = lengthOfBlock - offsetIntoBlock; 638 639 /* 640 We will read file in blocks of size 4096 bytes, if that 641 is not possible we will read file of remaining bytes. 642 This meathod will change when we will add file cache for xfs. 643 */ 644 if(lengthLeftInFile >= 4096) { 645 *length = 4096; 646 } else { 647 *length = lengthLeftInFile; 648 } 649 650 // We could be almost at the end of the file 651 if (lengthLeftInFile <= lengthLeftInBlock) 652 lengthToRead = lengthLeftInFile; 653 else lengthToRead = lengthLeftInBlock; 654 655 // But we might not be able to read all of the 656 // data because of less buffer length 657 if (lengthToRead > *length) 658 lengthToRead = *length; 659 660 int indexForMap = SearchMapInAllExtent(blockNo); 661 if (indexForMap == -1) 662 return B_BAD_VALUE; 663 664 xfs_daddr_t readPos 665 = FileSystemBlockToAddr(fExtents[indexForMap].br_startblock 666 + blockNo - fExtents[indexForMap].br_startoff); 667 668 if (read_pos(GetVolume()->Device(), readPos, block, lengthOfBlock) 669 != lengthOfBlock) { 670 ERROR("TreeDirectory::FillBlockBuffer(): IO Error"); 671 return B_IO_ERROR; 672 } 673 674 675 memcpy((void*) (buffer + lengthRead), 676 (void*)(block + offsetIntoBlock), lengthToRead); 677 678 pos += lengthToRead; 679 *length -= lengthToRead; 680 lengthRead += lengthToRead; 681 blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume()); 682 offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this); 683 } 684 685 TRACE("lengthRead:(%" B_PRIuSIZE ")\n", lengthRead); 686 *length = lengthRead; 687 return B_OK; 688 } 689 690 691 status_t 692 Inode::GetFromDisk() 693 { 694 xfs_agnumber_t agNo = INO_TO_AGNO(fId, fVolume); 695 // Get the AG number from the inode 696 uint32 agRelativeInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits()); 697 // AG relative ino # 698 xfs_agblock_t agBlock = INO_TO_AGBLOCK(agRelativeInodeNo, fVolume); 699 // AG relative block number 700 xfs_off_t offset = INO_TO_BLOCKOFFSET(fId, fVolume); 701 // Offset into the block1 702 uint32 len = fVolume->InodeSize(); 703 // Inode len to read (size of inode) 704 705 TRACE("AgNumber: (%" B_PRIu32 "), AgRelativeIno: (%" B_PRIu32 ")," 706 "AgRelativeBlockNum: (%" B_PRIu32 "),Offset: (%" B_PRId64 ")," 707 "len: (%" B_PRIu32 ")\n", agNo,agRelativeInodeNo, agBlock, offset, len); 708 709 if (agNo > fVolume->AgCount()) { 710 ERROR("Inode::GetFromDisk : AG Number more than number of AGs"); 711 return B_ENTRY_NOT_FOUND; 712 } 713 714 xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks(); 715 716 xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(), 717 ((uint64)(agNo * numberOfBlocksInAg) + agBlock)); 718 719 xfs_daddr_t readPos = blockToRead * XFS_MIN_BLOCKSIZE + offset * len; 720 721 if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) { 722 ERROR("Inode::Inode(): IO Error"); 723 return B_IO_ERROR; 724 } 725 726 if(fVolume->IsVersion5()) 727 memcpy(fNode, fBuffer, sizeof(Inode::Dinode)); 728 else 729 memcpy(fNode, fBuffer, INODE_CRC_OFF); 730 731 SwapEndian(); 732 733 return B_OK; 734 } 735 736 737 uint64 738 Inode::FileSystemBlockToAddr(uint64 block) 739 { 740 xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks(); 741 742 uint64 agNo = FSBLOCKS_TO_AGNO(block, fVolume); 743 uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(block, fVolume); 744 745 xfs_fsblock_t actualBlockToRead = 746 FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(), 747 ((uint64)(agNo * numberOfBlocksInAg) + agBlockNo)); 748 TRACE("blockToRead:(%" B_PRIu64 ")\n", actualBlockToRead); 749 750 uint64 readPos = actualBlockToRead * (XFS_MIN_BLOCKSIZE); 751 return readPos; 752 } 753 754 755 /* 756 * Basically take 4 characters at a time as long as you can, and xor with 757 * previous hashVal after rotating 4 bits of hashVal. Likewise, continue 758 * xor and rotating. This is quite a generic hash function. 759 */ 760 uint32 761 hashfunction(const char* name, int length) 762 { 763 uint32 hashVal = 0; 764 int lengthCovered = 0; 765 int index = 0; 766 if (length >= 4) { 767 for (; index < length && (length - index) >= 4; index += 4) 768 { 769 lengthCovered += 4; 770 hashVal = (name[index] << 21) ^ (name[index + 1] << 14) 771 ^ (name[index + 2] << 7) ^ (name[index + 3] << 0) 772 ^ ((hashVal << 28) | (hashVal >> 4)); 773 } 774 } 775 776 int leftToCover = length - lengthCovered; 777 if (leftToCover == 3) { 778 hashVal = (name[index] << 14) ^ (name[index + 1] << 7) 779 ^ (name[index + 2] << 0) ^ ((hashVal << 21) | (hashVal >> 11)); 780 } 781 if (leftToCover == 2) { 782 hashVal = (name[index] << 7) ^ (name[index + 1] << 0) 783 ^ ((hashVal << 14) | (hashVal >> (32 - 14))); 784 } 785 if (leftToCover == 1) { 786 hashVal = (name[index] << 0) 787 ^ ((hashVal << 7) | (hashVal >> (32 - 7))); 788 } 789 790 return hashVal; 791 } 792