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