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