1 // Iterators.h 2 // 3 // Copyright (c) 2003-2010, Ingo Weinhold (bonefish@cs.tu-berlin.de) 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 2 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // 19 // You can alternatively use *this file* under the terms of the the MIT 20 // license included in this package. 21 22 23 #include "Iterators.h" 24 25 #include "Block.h" 26 #include "BlockCache.h" 27 #include "Key.h" 28 #include "IndirectItem.h" 29 #include "StatItem.h" 30 #include "Tree.h" 31 32 33 // min and max 34 // We don't want to include <algobase.h> otherwise we also get <iostream.h> 35 // and other undesired things. 36 template<typename C> 37 static inline C min(const C &a, const C &b) { return (a < b ? a : b); } 38 template<typename C> 39 static inline C max(const C &a, const C &b) { return (a > b ? a : b); } 40 41 /*! 42 \class TreePath 43 \brief Represents a path in the tree. 44 45 It is composed of TreePath::Elements each one storing the block number 46 of a node and the index of a child node. 47 */ 48 49 // constructor 50 TreePath::TreePath(uint32 maxLength) 51 : fMaxLength(maxLength), 52 fLength(0), 53 fElements(NULL) 54 { 55 fElements = new(nothrow) Element[fMaxLength]; 56 } 57 58 // destructor 59 TreePath::~TreePath() 60 { 61 if (fElements) 62 delete[] fElements; 63 } 64 65 // InitCheck 66 status_t 67 TreePath::InitCheck() const 68 { 69 return (fElements ? B_OK : B_NO_MEMORY); 70 } 71 72 // GetMaxLength 73 uint32 74 TreePath::GetMaxLength() const 75 { 76 return fMaxLength; 77 } 78 79 // GetLength 80 uint32 81 TreePath::GetLength() const 82 { 83 return fLength; 84 } 85 86 // ElementAt 87 const TreePath::Element * 88 TreePath::ElementAt(int32 index) const 89 { 90 Element *element = NULL; 91 if (InitCheck() == B_OK && index >= 0 && (uint32)index < GetLength()) 92 element = fElements + index; 93 return element; 94 } 95 96 // GetTopElement 97 const TreePath::Element * 98 TreePath::GetTopElement() const 99 { 100 return ElementAt(GetLength() - 1); 101 } 102 103 // PushElement 104 status_t 105 TreePath::PushElement(uint64 blockNumber, int32 index) 106 { 107 status_t error = (fLength < fMaxLength ? InitCheck() : B_BAD_VALUE); 108 if (error == B_OK) { 109 error = fElements[fLength].SetTo(blockNumber, index); 110 if (error == B_OK) 111 fLength++; 112 } 113 return error; 114 } 115 116 // PopElement 117 status_t 118 TreePath::PopElement() 119 { 120 status_t error = InitCheck(); 121 if (error == B_OK) { 122 if (fLength > 0) 123 fLength--; 124 else 125 error = B_ERROR; 126 } 127 return error; 128 } 129 130 131 /*! 132 \class TreePath::Element 133 \brief Store information about one element in a tree path. 134 */ 135 136 // SetTo 137 status_t 138 TreePath::Element::SetTo(uint64 blockNumber, int32 index) 139 { 140 fBlockNumber = blockNumber; 141 fIndex = index; 142 return B_OK; 143 } 144 145 // GetBlockNumber 146 uint64 147 TreePath::Element::GetBlockNumber() const 148 { 149 return fBlockNumber; 150 } 151 152 // GetIndex 153 int32 154 TreePath::Element::GetIndex() const 155 { 156 return fIndex; 157 } 158 159 160 /*! 161 \class TreeIterator 162 \brief Class used to iterate and navigate in trees. 163 164 A TreeIterator is usually initialized to the root node of the tree 165 and can be used to navigate and search in the tree. 166 */ 167 168 // constructor 169 TreeIterator::TreeIterator(Tree *tree) 170 : fTree(NULL), 171 fCurrentNode(NULL), 172 fPath(NULL) 173 { 174 SetTo(tree); 175 } 176 177 // destructor 178 TreeIterator::~TreeIterator() 179 { 180 Unset(); 181 } 182 183 // SetTo 184 status_t 185 TreeIterator::SetTo(Tree *tree) 186 { 187 Unset(); 188 fTree = tree; 189 fCurrentNode = NULL; 190 fPath = NULL; 191 if (fTree) { 192 fCurrentNode = fTree->GetRootNode(); 193 if (fCurrentNode) 194 fCurrentNode->Get(); 195 fPath = new(nothrow) TreePath(tree->GetTreeHeight()); 196 } 197 return InitCheck(); 198 } 199 200 // Unset 201 void 202 TreeIterator::Unset() 203 { 204 if (fPath) { 205 delete fPath; 206 fPath = NULL; 207 } 208 if (fCurrentNode) { 209 fCurrentNode->Put(); 210 fCurrentNode = NULL; 211 } 212 } 213 214 // InitCheck 215 status_t 216 TreeIterator::InitCheck() const 217 { 218 return (fTree && fCurrentNode && fPath ? fPath->InitCheck() : B_NO_INIT); 219 } 220 221 // GetNode 222 Node * 223 TreeIterator::GetNode() const 224 { 225 return fCurrentNode; 226 } 227 228 // GetLevel 229 int32 230 TreeIterator::GetLevel() const 231 { 232 int32 level = 0; 233 if (fCurrentNode) 234 level = fCurrentNode->GetLevel(); 235 return level; 236 } 237 238 // GoTo 239 /*! \brief Goes into a given direction. 240 241 \a direction can be 242 - \c FORWARD: Forward/to the right. Goes to the next child node of the 243 current node. 244 - \c BACKWARDS: Forward/to the right. Goes to the previous child node of 245 the current node. 246 - \c UP: Up one level (in root direction). Goes to the parent node of 247 the current node. The current node is the child node, it is pointed 248 to afterward. 249 - \c DOWN: Down one level (in leaf direction). Goes to the child node of 250 the current node the iterator currently points at. Points afterwards to 251 the 0th child node of the new current node (unless it is a leaf node). 252 253 \c FORWARD and \c BACKWARDS do not change the current node! 254 255 \param direction \c FORWARD, \c BACKWARDS, \c UP or \c DOWN 256 \return \c B_OK, if everything went fine 257 */ 258 status_t 259 TreeIterator::GoTo(uint32 direction) 260 { 261 status_t error = InitCheck(); 262 if (error == B_OK) { 263 switch (direction) { 264 case FORWARD: 265 { 266 if (fCurrentNode->IsInternal() 267 && fIndex < fCurrentNode->CountItems()) { 268 fIndex++; 269 } else { 270 error = B_ENTRY_NOT_FOUND; 271 } 272 break; 273 } 274 case BACKWARDS: 275 { 276 if (fCurrentNode->IsInternal() && fIndex > 0) 277 fIndex--; 278 else 279 error = B_ENTRY_NOT_FOUND; 280 break; 281 } 282 case UP: 283 { 284 error = _PopTopNode(); 285 break; 286 } 287 case DOWN: 288 { 289 if (fCurrentNode->IsInternal()) { 290 InternalNode *internal = fCurrentNode->ToInternalNode(); 291 const DiskChild *child = internal->ChildAt(fIndex); 292 if (child) { 293 Node *node = NULL; 294 error = fTree->GetNode(child->GetBlockNumber(), &node); 295 if (error == B_OK) 296 error = _PushCurrentNode(node, 0); 297 } else 298 error = B_ENTRY_NOT_FOUND; 299 } else 300 error = B_ENTRY_NOT_FOUND; 301 break; 302 } 303 } 304 } 305 return error; 306 } 307 308 // GoToPreviousLeaf 309 /*! \brief Goes to the previous leaf node. 310 311 This method operates only at leaf node level. It finds the next leaf 312 node to the left. Fails, if the current node is no leaf node. 313 314 \param node Pointer to a pre-allocated LeafNode pointer that shall be set 315 to the found node. 316 \return \c B_OK, if everything went fine 317 */ 318 status_t 319 TreeIterator::GoToPreviousLeaf(LeafNode **node) 320 { 321 status_t error = InitCheck(); 322 if (error == B_OK) { 323 if (fCurrentNode->IsLeaf()) { 324 // find downmost branch on our path, that leads further left 325 bool found = false; 326 while (error == B_OK && !found) { 327 error = GoTo(UP); 328 if (error == B_OK) 329 found = (GoTo(BACKWARDS) == B_OK); 330 } 331 // descend the branch to the rightmost leaf 332 if (error == B_OK) { 333 // one level down 334 error = GoTo(DOWN); 335 // then keep right 336 while (error == B_OK && fCurrentNode->IsInternal()) { 337 fIndex = fCurrentNode->CountItems(); 338 error = GoTo(DOWN); 339 } 340 } 341 // set the result 342 if (error == B_OK && node) 343 *node = fCurrentNode->ToLeafNode(); 344 } else 345 error = B_ENTRY_NOT_FOUND; 346 } 347 return error; 348 } 349 350 // GoToNextLeaf 351 /*! \brief Goes to the next leaf node. 352 353 This method operates only at leaf node level. It finds the next leaf 354 node to the right. Fails, if the current node is no leaf node. 355 356 \param node Pointer to a pre-allocated LeafNode pointer that shall be set 357 to the found node. 358 \return \c B_OK, if everything went fine 359 */ 360 status_t 361 TreeIterator::GoToNextLeaf(LeafNode **node) 362 { 363 status_t error = InitCheck(); 364 if (error == B_OK) { 365 if (fCurrentNode->IsLeaf()) { 366 // find downmost branch on our path, that leads further right 367 bool found = false; 368 while (error == B_OK && !found) { 369 error = GoTo(UP); 370 if (error == B_OK) 371 found = (GoTo(FORWARD) == B_OK); 372 } 373 // descend the branch to the leftmost leaf 374 while (error == B_OK && fCurrentNode->IsInternal()) 375 error = GoTo(DOWN); 376 // set the result 377 if (error == B_OK && node) 378 *node = fCurrentNode->ToLeafNode(); 379 } else 380 error = B_ENTRY_NOT_FOUND; 381 } 382 return error; 383 } 384 385 // FindRightMostLeaf 386 /*! \brief Finds the rightmost leaf node that may contain the supplied key. 387 388 The method starts at the current node and only goes downwards. 389 In the spanned subtree it finds the rightmost leaf node whose left 390 delimiting key is not greater than the supplied key. 391 392 \param key The key to be found. 393 \param node Pointer to a pre-allocated LeafNode pointer that shall be set 394 to the found node. 395 \return \c B_OK, if everything went fine. 396 */ 397 status_t 398 TreeIterator::FindRightMostLeaf(const VKey *k, LeafNode **node) 399 { 400 //printf("TreeIterator::FindRightMostLeaf()\n"); 401 status_t error = (k ? InitCheck() : B_BAD_VALUE); 402 while (error == B_OK && fCurrentNode->IsInternal()) { 403 int32 index = 0; 404 error = _SearchRightMost(fCurrentNode->ToInternalNode(), k, &index); 405 if (error == B_OK) { 406 fIndex = index; 407 error = GoTo(DOWN); 408 } 409 } 410 //if (error == B_OK) 411 //printf("found node: index: %ld\n", fIndex); 412 // set the result 413 if (error == B_OK && node) 414 *node = fCurrentNode->ToLeafNode(); 415 //printf("TreeIterator::FindRightMostLeaf() done: %s\n", strerror(error)); 416 return error; 417 } 418 419 // Suspend 420 /*! \brief Suspends the iterator. 421 422 This means, the current node is Put() and its block number and child node 423 index pushed onto the tree path. This should be done, when the iteration 424 is not to be continued immediately (or for the foreseeable future) and 425 the node block shall not be locked in memory for that time. 426 427 Resume() is to be called, before the iteration can be continued. 428 429 \return \c B_OK, if everything went fine. 430 */ 431 status_t 432 TreeIterator::Suspend() 433 { 434 status_t error = InitCheck(); 435 if (error == B_OK) 436 error = _PushCurrentNode(); 437 if (error == B_OK) 438 fCurrentNode = NULL; 439 return error; 440 } 441 442 // Resume 443 /*! \brief Resumes the iteration. 444 445 To be called after a Suspend(), before the iteration can be continued. 446 447 \return \c B_OK, if everything went fine. 448 */ 449 status_t 450 TreeIterator::Resume() 451 { 452 status_t error 453 = (fTree && !fCurrentNode && fPath ? fPath->InitCheck() : B_NO_INIT); 454 if (error == B_OK) 455 error = _PopTopNode(); 456 return error; 457 } 458 459 // _PushCurrentNode 460 status_t 461 TreeIterator::_PushCurrentNode(Node *newTopNode, int32 newIndex) 462 { 463 status_t error = fPath->PushElement(fCurrentNode->GetNumber(), fIndex); 464 if (error == B_OK) { 465 fCurrentNode->Put(); 466 fCurrentNode = newTopNode; 467 fIndex = newIndex; 468 } 469 return error; 470 } 471 472 // _PopTopNode 473 status_t 474 TreeIterator::_PopTopNode() 475 { 476 status_t error = B_OK; 477 if (fPath->GetLength() > 0) { 478 const TreePath::Element *element = fPath->GetTopElement(); 479 Node *node = NULL; 480 error = fTree->GetNode(element->GetBlockNumber(), &node); 481 if (error == B_OK) { 482 if (fCurrentNode) 483 fCurrentNode->Put(); 484 fCurrentNode = node; 485 fIndex = element->GetIndex(); 486 fPath->PopElement(); 487 } 488 } else 489 error = B_BAD_VALUE; 490 return error; 491 } 492 493 // _SearchRightMost 494 status_t 495 TreeIterator::_SearchRightMost(InternalNode *node, const VKey *k, int32 *index) 496 { 497 //FUNCTION_START(); 498 // find the last node that may contain the key, i.e. the node with the 499 // greatest index whose left delimiting key is less or equal the given key 500 status_t error = (node && k && index ? B_OK : B_BAD_VALUE); 501 if (error == B_OK) { 502 //PRINT((" searching: ")); 503 //k->Dump(); 504 // binary search: lower and upper are node indices, mid is a key index 505 int32 lower = 0; 506 int32 upper = node->CountItems(); 507 while (lower < upper) { 508 int32 mid = (lower + upper) / 2; // lower <= mid < upper <= count 509 VKey midKey(node->KeyAt(mid)); 510 //PRINT((" mid: %3ld: ", mid)); 511 //midKey.Dump(); 512 if (*k < midKey) // => node index <= mid 513 upper = mid; // lower <= upper < count 514 else // => node index > mid 515 lower = mid + 1; // lower <= upper <= count 516 //PRINT((" lower: %ld, upper: %ld\n", lower, upper)); 517 } 518 if (error == B_OK) 519 *index = lower; 520 } 521 //RETURN_ERROR(error); 522 return error; 523 } 524 525 526 /*! 527 \class ItemIterator 528 \brief Class used to iterate through leaf node items. 529 530 A ItemIterator is usually initialized to the root node of the tree, 531 and before it can be used for iteration, FindRightMostClose() or 532 FindRightMost() must be invoked. They set the iterator to an item 533 and afterwards one can use GoToPrevious() and GoToNext() to get the 534 previous/next ones. 535 */ 536 537 // constructor 538 ItemIterator::ItemIterator(Tree *tree) 539 : fTreeIterator(tree), 540 fIndex(0) 541 { 542 } 543 544 // SetTo 545 status_t 546 ItemIterator::SetTo(Tree *tree) 547 { 548 status_t error = fTreeIterator.SetTo(tree); 549 fIndex = 0; 550 return error; 551 } 552 553 // InitCheck 554 status_t 555 ItemIterator::InitCheck() const 556 { 557 return fTreeIterator.InitCheck(); 558 } 559 560 // GetCurrent 561 status_t 562 ItemIterator::GetCurrent(Item *item) 563 { 564 LeafNode *node = NULL; 565 status_t error = (item ? _GetLeafNode(&node) : B_BAD_VALUE); 566 if (error == B_OK) { 567 if (fIndex >= 0 && fIndex < node->CountItems()) 568 error = item->SetTo(node, fIndex); 569 else 570 error = B_ENTRY_NOT_FOUND; 571 } 572 return error; 573 } 574 575 // GoToPrevious 576 status_t 577 ItemIterator::GoToPrevious(Item *item) 578 { 579 LeafNode *node = NULL; 580 status_t error = _GetLeafNode(&node); 581 if (error == B_OK) { 582 // get the leaf node on which the next item resides 583 int32 newIndex = fIndex - 1; 584 while (error == B_OK 585 && (newIndex < 0 || newIndex >= node->CountItems())) { 586 error = fTreeIterator.GoToPreviousLeaf(&node); 587 if (error == B_OK) 588 newIndex = node->CountItems() - 1; 589 } 590 // got the node, get the item 591 if (error == B_OK) { 592 fIndex = newIndex; 593 if (item) 594 error = item->SetTo(node, fIndex); 595 } 596 } 597 return error; 598 } 599 600 // GoToNext 601 status_t 602 ItemIterator::GoToNext(Item *item) 603 { 604 //PRINT(("ItemIterator::GoToNext()\n")); 605 LeafNode *node = NULL; 606 status_t error = _GetLeafNode(&node); 607 if (error == B_OK) { 608 //PRINT((" leaf node: %Ld\n", node->GetNumber())); 609 // get the leaf node on which the next item resides 610 int32 newIndex = fIndex + 1; 611 while (error == B_OK && newIndex >= node->CountItems()) { 612 error = fTreeIterator.GoToNextLeaf(&node); 613 newIndex = 0; 614 } 615 // got the node, get the item 616 if (error == B_OK) { 617 //PRINT((" leaf node now: %Ld\n", node->GetNumber())); 618 fIndex = newIndex; 619 //PRINT((" index now: %ld\n", fIndex)); 620 if (item) 621 error = item->SetTo(node, fIndex); 622 } 623 } 624 //PRINT(("ItemIterator::GoToNext() done: %s\n", strerror(error))); 625 return error; 626 } 627 628 // FindRightMostClose 629 /*! \brief Finds the rightmost item that may contain the supplied key. 630 631 The method finds the rightmost item whose left delimiting key is not 632 greater than the supplied key. 633 634 \param key The key to be found. 635 \param item Pointer to a pre-allocated Item that shall be set 636 to the found item. 637 \return \c B_OK, if everything went fine. 638 */ 639 status_t 640 ItemIterator::FindRightMostClose(const VKey *k, Item *item) 641 { 642 //printf("ItemIterator::FindRightMostClose()\n"); 643 status_t error = (k ? InitCheck() : B_BAD_VALUE); 644 // find rightmost leaf node with the given key 645 if (error == B_OK) 646 error = fTreeIterator.FindRightMostLeaf(k); 647 // search the node for the key 648 if (error == B_OK) { 649 LeafNode *node = fTreeIterator.GetNode()->ToLeafNode(); 650 error = _SearchRightMost(node, k, &fIndex); 651 if (error == B_OK && item) 652 { 653 error = item->SetTo(node, fIndex); 654 //VKey itemKey; 655 //printf(" found item: "); 656 //item->GetKey(&itemKey)->Dump(); 657 } 658 } 659 //printf("ItemIterator::FindRightMostClose() done: %s\n", strerror(error)); 660 return error; 661 } 662 663 // FindRightMost 664 /*! \brief Finds the rightmost item that starts with the supplied key. 665 666 The method finds the rightmost item whose left delimiting key is equal 667 to the supplied key. 668 669 \param key The key to be found. 670 \param item Pointer to a pre-allocated Item that shall be set 671 to the found item. 672 \return \c B_OK, if everything went fine. 673 */ 674 status_t 675 ItemIterator::FindRightMost(const VKey *k, Item *item) 676 { 677 //TFUNCTION_START(); 678 // find the first item with a greater or equal key, and check whether the 679 // key is equal 680 Item closeItem; 681 status_t error = FindRightMostClose(k, &closeItem); 682 //REPORT_ERROR(error); 683 if (error == B_OK) { 684 VKey itemKey; 685 closeItem.GetHeader()->GetKey(&itemKey); 686 if (*k == itemKey) { 687 if (item) 688 *item = closeItem; 689 } else 690 { 691 //PRINT(("keys not equal: dirID: %lu, objectID: %lu, offset: %Lu, type: %hu\n", 692 //itemKey.GetDirID(), itemKey.GetObjectID(), itemKey.GetOffset(), itemKey.GetType())); 693 error = B_ENTRY_NOT_FOUND; 694 } 695 } 696 //REPORT_ERROR(error); 697 return error; 698 } 699 700 // Suspend 701 /*! \brief Suspends the iterator. 702 \see TreeIterator::Suspend(). 703 \return \c B_OK, if everything went fine. 704 */ 705 status_t 706 ItemIterator::Suspend() 707 { 708 return fTreeIterator.Suspend(); 709 } 710 711 // Resume 712 /*! \brief Resumes the iteration. 713 \see TreeIterator::Resume(). 714 \return \c B_OK, if everything went fine. 715 */ 716 status_t 717 ItemIterator::Resume() 718 { 719 return fTreeIterator.Resume(); 720 } 721 722 // _GetLeafNode 723 status_t 724 ItemIterator::_GetLeafNode(LeafNode **leafNode) const 725 { 726 status_t error = InitCheck(); 727 if (error == B_OK) { 728 if (Node *node = fTreeIterator.GetNode()) { 729 if (node->IsLeaf()) 730 *leafNode = node->ToLeafNode(); 731 else 732 error = B_ENTRY_NOT_FOUND; 733 } else 734 error = B_ERROR; 735 } 736 return error; 737 } 738 739 // _SearchRightMost 740 status_t 741 ItemIterator::_SearchRightMost(LeafNode *node, const VKey *k, 742 int32 *index) const 743 { 744 //FUNCTION_START(); 745 status_t error = (node && k && index ? B_OK : B_BAD_VALUE); 746 // find the first item with a less or equal key 747 if (error == B_OK) { 748 //PRINT((" searching: ")); 749 //k->Dump(); 750 /* 751 // simple linear search backwards 752 int32 foundIndex = -1; 753 for (int32 i = node->CountItems() - 1; foundIndex < 0 && i >= 0; i--) { 754 VKey itemKey; 755 node->ItemHeaderAt(i)->GetKey(&itemKey); 756 if (itemKey <= *k) { 757 foundIndex = i; 758 error = B_OK; 759 break; 760 } 761 } 762 // check whether all item keys are greater 763 if (foundIndex < 0) 764 error = B_ENTRY_NOT_FOUND; 765 // set result 766 if (error == B_OK) 767 *index = foundIndex; 768 */ 769 // binary search 770 // check lower bound first 771 VKey lowerKey; 772 node->ItemHeaderAt(0)->GetKey(&lowerKey); 773 if (lowerKey <= *k) { 774 // pre-conditions hold 775 int32 lower = 0; 776 int32 upper = node->CountItems() - 1; 777 while (lower < upper) { 778 int32 mid = (lower + upper + 1) / 2; 779 VKey midKey; 780 node->ItemHeaderAt(mid)->GetKey(&midKey); 781 //PRINT((" mid: %3ld: ", mid)); 782 //midKey.Dump(); 783 if (midKey > *k) 784 upper = mid - 1; 785 else 786 lower = mid; 787 //PRINT((" lower: %ld, upper: %ld\n", lower, upper)); 788 } 789 *index = lower; 790 } else 791 error = B_ENTRY_NOT_FOUND; 792 } 793 //RETURN_ERROR(error); 794 return error; 795 } 796 797 798 /*! 799 \class ObjectItemIterator 800 \brief Class used to iterate through leaf node items. 801 802 This class basically wraps the ItemIterator class and provides a 803 more convenient interface for iteration through items of one given 804 object (directory, link or file). It finds only items of the object 805 identified by the dir and object ID specified on initialization. 806 */ 807 808 // constructor 809 /*! \brief Creates and initializes a ObjectItemIterator. 810 811 The iterator is initialized to find only items belonging to the object 812 identified by \a dirID and \a objectID. \a startOffset specifies the 813 offset (key offset) at which the iteration shall begin. 814 815 Note, that offsets don't need to be unique for an object, at least not 816 for files -- all indirect (and direct?) items have the same offset (1). 817 This has the ugly side effect, when iterating forward there may be items 818 with the same offset on previous nodes that will be skipped at the 819 beginning. The GetNext() does always find the item on the rightmost 820 possible node. Therefore searching forward starting with FIRST_ITEM_OFFSET 821 doesn't work for files! 822 823 \param tree The tree. 824 \param dirID The directory ID of the object. 825 \param objectID The object ID of the object. 826 \param startOffset The offset at which to begin the iteration. 827 */ 828 ObjectItemIterator::ObjectItemIterator(Tree *tree, uint32 dirID, 829 uint32 objectID, uint64 startOffset) 830 : fItemIterator(tree), 831 fDirID(dirID), 832 fObjectID(objectID), 833 fOffset(startOffset), 834 fFindFirst(true), 835 fDone(false) 836 { 837 } 838 839 // SetTo 840 /*! \brief Re-initializes a ObjectItemIterator. 841 842 The iterator is initialized to find only items belonging to the object 843 identified by \a dirID and \a objectID. \a startOffset specifies the 844 offset (key offset) at which the iteration shall begin. 845 846 \param tree The tree. 847 \param dirID The directory ID of the object. 848 \param objectID The object ID of the object. 849 \param startOffset The offset at which to begin the iteration. 850 \return \c B_OK, if everything went fine. 851 */ 852 status_t 853 ObjectItemIterator::SetTo(Tree *tree, uint32 dirID, uint32 objectID, 854 uint64 startOffset) 855 { 856 status_t error = fItemIterator.SetTo(tree); 857 fDirID = dirID; 858 fObjectID = objectID; 859 fOffset = startOffset; 860 fFindFirst = true; 861 fDone = false; 862 return error; 863 } 864 865 // InitCheck 866 status_t 867 ObjectItemIterator::InitCheck() const 868 { 869 return fItemIterator.InitCheck(); 870 } 871 872 // GetNext 873 /*! \brief Returns the next item belonging to the object. 874 875 Note, that offsets don't need to be unique for an object, at least not 876 for files -- all indirect (and direct?) items have the same offset (1). 877 This has the ugly side effect, when iterating forward there may be items 878 with the same offset on previous nodes that will be skipped at the 879 beginning. The GetNext() does always find the item on the rightmost 880 possible node. Therefore searching forward starting with FIRST_ITEM_OFFSET 881 doesn't work for files! 882 883 \param foundItem Pointer to a pre-allocated Item that shall be set 884 to the found item. 885 \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're 886 through. 887 */ 888 status_t 889 ObjectItemIterator::GetNext(Item *foundItem) 890 { 891 //PRINT(("ObjectItemIterator::GetNext(): fDirID: %lu, fObjectID: %lu\n", fDirID, fObjectID)); 892 status_t error = (foundItem ? InitCheck() : B_BAD_VALUE); 893 if (error == B_OK && fDone) 894 error = B_ENTRY_NOT_FOUND; 895 if (error == B_OK) { 896 // get the next item 897 Item item; 898 if (fFindFirst) { 899 // first invocation: find the item with the given IDs and offset 900 VKey k(fDirID, fObjectID, fOffset, 0, KEY_FORMAT_3_5); 901 error = fItemIterator.FindRightMostClose(&k, &item); 902 fFindFirst = false; 903 } else { 904 // item iterator positioned, get the next item 905 error = fItemIterator.GoToNext(&item); 906 //REPORT_ERROR(error); 907 } 908 // check whether the item belongs to our object 909 if (error == B_OK) { 910 VKey itemKey; 911 if (item.GetDirID() == fDirID && item.GetObjectID() == fObjectID) 912 *foundItem = item; 913 else 914 { 915 //PRINT((" found item for another object: (%lu, %lu)\n", item.GetDirID(), item.GetObjectID())); 916 error = B_ENTRY_NOT_FOUND; 917 } 918 } 919 if (error != B_OK) 920 fDone = true; 921 } 922 // return error; 923 RETURN_ERROR(error) 924 } 925 926 // GetNext 927 /*! \brief Returns the next item belonging to the object. 928 929 This version finds only items of the specified type. 930 931 \param foundItem Pointer to a pre-allocated Item that shall be set 932 to the found item. 933 \param type The type the found item must have. 934 \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're 935 through. 936 */ 937 status_t 938 ObjectItemIterator::GetNext(Item *foundItem, uint32 type) 939 { 940 status_t error = B_OK; 941 do { 942 error = GetNext(foundItem); 943 } while (error == B_OK && foundItem->GetType() != type); 944 return error; 945 } 946 947 // GetPrevious 948 /*! \brief Returns the previous item belonging to the object. 949 \param foundItem Pointer to a pre-allocated Item that shall be set 950 to the found item. 951 \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're 952 through. 953 */ 954 status_t 955 ObjectItemIterator::GetPrevious(Item *foundItem) 956 { 957 //PRINT(("ObjectItemIterator::GetPrevious()\n")); 958 status_t error = (foundItem ? InitCheck() : B_BAD_VALUE); 959 if (error == B_OK && fDone) 960 error = B_ENTRY_NOT_FOUND; 961 if (error == B_OK) { 962 // get the next item 963 Item item; 964 if (fFindFirst) { 965 // first invocation: find the rightmost item of the object 966 VKey k(fDirID, fObjectID, fOffset, 0xffffffffUL, KEY_FORMAT_3_5); 967 error = fItemIterator.FindRightMostClose(&k, &item); 968 fFindFirst = false; 969 } else { 970 // item iterator positioned, get the previous item 971 error = fItemIterator.GoToPrevious(&item); 972 } 973 // check whether the item belongs to our object 974 if (error == B_OK) { 975 VKey itemKey; 976 if (item.GetDirID() == fDirID && item.GetObjectID() == fObjectID) { 977 //PRINT((" found item: %lu, %lu, %Lu\n", fDirID, fObjectID, item.GetOffset())); 978 *foundItem = item; 979 } else 980 { 981 //PRINT((" item belongs to different object: (%lu, %lu)\n", item.GetDirID(), item.GetObjectID())); 982 error = B_ENTRY_NOT_FOUND; 983 } 984 } 985 if (error != B_OK) 986 fDone = true; 987 } 988 //PRINT(("ObjectItemIterator::GetPrevious() done: %s\n", strerror(error))); 989 return error; 990 } 991 992 // GetPrevious 993 /*! \brief Returns the previous item belonging to the object. 994 995 This version finds only items of the specified type. 996 997 \param foundItem Pointer to a pre-allocated Item that shall be set 998 to the found item. 999 \param type The type the found item must have. 1000 \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're 1001 through. 1002 */ 1003 status_t 1004 ObjectItemIterator::GetPrevious(Item *foundItem, uint32 type) 1005 { 1006 status_t error = B_OK; 1007 do { 1008 error = GetPrevious(foundItem); 1009 } while (error == B_OK && foundItem->GetType() != type); 1010 return error; 1011 } 1012 1013 // Suspend 1014 /*! \brief Suspends the iterator. 1015 \see ItemIterator::Suspend(). 1016 \return \c B_OK, if everything went fine. 1017 */ 1018 status_t 1019 ObjectItemIterator::Suspend() 1020 { 1021 return fItemIterator.Suspend(); 1022 } 1023 1024 // Resume 1025 /*! \brief Resumes the iteration. 1026 \see ItemIterator::Resume(). 1027 \return \c B_OK, if everything went fine. 1028 */ 1029 status_t 1030 ObjectItemIterator::Resume() 1031 { 1032 return fItemIterator.Resume(); 1033 } 1034 1035 1036 /*! 1037 \class DirEntryIterator 1038 \brief Class used to iterate through DirEntries. 1039 */ 1040 1041 // constructor 1042 /*! \brief Creates and initializes a DirEntryIterator. 1043 1044 The iterator is initialized to find only entries belonging to the directory 1045 identified by \a dirID and \a objectID. \a startOffset specifies the 1046 offset (key offset) at which the iteration shall begin. If \a fixedHash 1047 is \c true, only items that have the same hash value as \a startOffset 1048 are found. 1049 1050 \param tree The tree. 1051 \param dirID The directory ID of the object. 1052 \param objectID The object ID of the object. 1053 \param startOffset The offset at which to begin the iteration. 1054 \param fixedHash \c true to find only entries with the same hash as 1055 \a startOffset 1056 */ 1057 DirEntryIterator::DirEntryIterator(Tree *tree, uint32 dirID, uint32 objectID, 1058 uint64 startOffset, bool fixedHash) 1059 : fItemIterator(tree, dirID, objectID, startOffset), 1060 fDirItem(), 1061 fIndex(-1), 1062 fFixedHash(fixedHash), 1063 fDone(false) 1064 { 1065 } 1066 1067 // SetTo 1068 /*! \brief Re-initializes a DirEntryIterator. 1069 1070 The iterator is initialized to find only entries belonging to the directory 1071 identified by \a dirID and \a objectID. \a startOffset specifies the 1072 offset (key offset) at which the iteration shall begin. If \a fixedHash 1073 is \c true, only items that have the same hash value as \a startOffset 1074 are found. 1075 1076 \param tree The tree. 1077 \param dirID The directory ID of the object. 1078 \param objectID The object ID of the object. 1079 \param startOffset The offset at which to begin the iteration. 1080 \param fixedHash \c true to find only entries with the same hash as 1081 \a startOffset 1082 */ 1083 status_t 1084 DirEntryIterator::SetTo(Tree *tree, uint32 dirID, uint32 objectID, 1085 uint64 startOffset, bool fixedHash) 1086 { 1087 fDirItem.Unset(); 1088 status_t error = fItemIterator.SetTo(tree, dirID, objectID, startOffset); 1089 fIndex = -1; 1090 fFixedHash = fixedHash; 1091 fDone = false; 1092 return error; 1093 } 1094 1095 // InitCheck 1096 status_t 1097 DirEntryIterator::InitCheck() const 1098 { 1099 return fItemIterator.InitCheck(); 1100 } 1101 1102 // Rewind 1103 /*! \brief Rewinds the iterator. 1104 1105 Simply re-initializes the iterator to the parameters of the last 1106 initialization. 1107 1108 \return \c B_OK, if everything went fine. 1109 */ 1110 status_t 1111 DirEntryIterator::Rewind() 1112 { 1113 return SetTo(GetTree(), GetDirID(), GetObjectID(), GetOffset(), 1114 fFixedHash); 1115 } 1116 1117 // GetNext 1118 /*! \brief Returns the next entry belonging to the directory. 1119 \param foundItem Pointer to a pre-allocated Item that shall be set 1120 to the found item. 1121 \param entryIndex Pointer to a pre-allocated int32 that shall be set 1122 to the found entry index. 1123 \param _entry Pointer to a pre-allocated DirEntry pointer that shall be set 1124 to the found entry. May be \c NULL. 1125 \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're 1126 through. 1127 */ 1128 status_t 1129 DirEntryIterator::GetNext(DirItem *foundItem, int32 *entryIndex, 1130 DirEntry **_entry) 1131 { 1132 status_t error = (foundItem && entryIndex ? InitCheck() : B_BAD_VALUE); 1133 // get the next DirItem, if necessary 1134 // the loop skips empty DirItems gracefully 1135 while (error == B_OK 1136 && (fIndex < 0 || fIndex >= fDirItem.GetEntryCount())) { 1137 error = fItemIterator.GetNext(&fDirItem, TYPE_DIRENTRY); 1138 if (error == B_OK) { 1139 if (fDirItem.Check() == B_OK) 1140 fIndex = 0; 1141 else // bad data: skip the item 1142 fIndex = -1; 1143 } 1144 } 1145 // get the next entry and check whether it has the correct offset 1146 if (error == B_OK) { 1147 DirEntry *entry = fDirItem.EntryAt(fIndex); 1148 if (!fFixedHash 1149 || offset_hash_value(entry->GetOffset()) 1150 == offset_hash_value(GetOffset())) { 1151 *foundItem = fDirItem; 1152 *entryIndex = fIndex; 1153 if (_entry) 1154 *_entry = entry; 1155 fIndex++; 1156 } else 1157 error = B_ENTRY_NOT_FOUND; 1158 } 1159 return error; 1160 } 1161 1162 // GetPrevious 1163 /*! \brief Returns the previous entry belonging to the directory. 1164 \param foundItem Pointer to a pre-allocated Item that shall be set 1165 to the found item. 1166 \param entryIndex Pointer to a pre-allocated int32 that shall be set 1167 to the found entry index. 1168 \param _entry Pointer to a pre-allocated DirEntry pointer that shall be set 1169 to the found entry. May be \c NULL. 1170 \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're 1171 through. 1172 */ 1173 status_t 1174 DirEntryIterator::GetPrevious(DirItem *foundItem, int32 *entryIndex, 1175 DirEntry **_entry) 1176 { 1177 //printf("DirEntryIterator::GetPrevious()\n"); 1178 status_t error = (foundItem && entryIndex ? InitCheck() : B_BAD_VALUE); 1179 if (error == B_OK && fDone) 1180 error = B_ENTRY_NOT_FOUND; 1181 // get the next DirItem, if necessary 1182 // the loop skips empty DirItems gracefully 1183 while (error == B_OK 1184 && (fIndex < 0 || fIndex >= fDirItem.GetEntryCount())) { 1185 error = fItemIterator.GetPrevious(&fDirItem, TYPE_DIRENTRY); 1186 if (error == B_OK) { 1187 if (fDirItem.Check() == B_OK) 1188 fIndex = fDirItem.GetEntryCount() - 1; 1189 else // bad data: skip the item 1190 fIndex = -1; 1191 } 1192 } 1193 //printf(" found dir item: %s\n", strerror(error)); 1194 // skip entries with a greater offset 1195 while (error == B_OK && fIndex >= 0 1196 && fDirItem.EntryAt(fIndex)->GetOffset() > GetOffset()) { 1197 //printf(" skipping entry %ld: offset %lu\n", fIndex, fDirItem.EntryAt(fIndex)->GetOffset()); 1198 fIndex--; 1199 } 1200 // get the entry and check whether it has the correct offset 1201 if (error == B_OK) { 1202 //printf(" entries with greater offsets skipped: index: %ld\n", fIndex); 1203 if (fIndex >= 0 1204 //&& (printf(" entry index %ld: offset %lu\n", fIndex, fDirItem.EntryAt(fIndex)->GetOffset()), true) 1205 && (!fFixedHash 1206 || offset_hash_value(fDirItem.EntryAt(fIndex)->GetOffset()) 1207 == offset_hash_value(GetOffset()))) { 1208 //printf(" entry found\n"); 1209 DirEntry *entry = fDirItem.EntryAt(fIndex); 1210 *foundItem = fDirItem; 1211 *entryIndex = fIndex; 1212 fDone = (fFixedHash 1213 && offset_generation_number(entry->GetOffset()) == 0); 1214 if (_entry) 1215 *_entry = entry; 1216 fIndex--; 1217 } else 1218 error = B_ENTRY_NOT_FOUND; 1219 } 1220 //printf("DirEntryIterator::GetPrevious() done: %s\n", strerror(error)); 1221 return error; 1222 } 1223 1224 // Suspend 1225 /*! \brief Suspends the iterator. 1226 \see ObjectItemIterator::Suspend(). 1227 \return \c B_OK, if everything went fine. 1228 */ 1229 status_t 1230 DirEntryIterator::Suspend() 1231 { 1232 return fItemIterator.Suspend(); 1233 } 1234 1235 // Resume 1236 /*! \brief Resumes the iteration. 1237 \see ObjectItemIterator::Resume(). 1238 \return \c B_OK, if everything went fine. 1239 */ 1240 status_t 1241 DirEntryIterator::Resume() 1242 { 1243 return fItemIterator.Resume(); 1244 } 1245 1246 1247 /*! 1248 \class StreamReader 1249 \brief Class used to read object streams (files, links). 1250 */ 1251 1252 // constructor 1253 /*! \brief Creates and initializes a StreamReader. 1254 1255 The reader is initialized to read the stream of the object 1256 identified by \a dirID and \a objectID. 1257 1258 \param tree The tree. 1259 \param dirID The directory ID of the object. 1260 \param objectID The object ID of the object. 1261 */ 1262 StreamReader::StreamReader(Tree *tree, uint32 dirID, uint32 objectID) 1263 : fItemIterator(tree, dirID, objectID, SD_OFFSET), 1264 fItem(), 1265 fStreamSize(-1), 1266 fItemOffset(-1), 1267 fItemSize(0), 1268 fBlockSize(0) 1269 { 1270 fBlockSize = tree->GetBlockSize(); 1271 } 1272 1273 // SetTo 1274 /*! \brief Creates and initializes a StreamReader. 1275 1276 The reader is initialized to read the stream of the object 1277 identified by \a dirID and \a objectID. 1278 1279 \param tree The tree. 1280 \param dirID The directory ID of the object. 1281 \param objectID The object ID of the object. 1282 \return \c B_OK, if everything went fine. 1283 */ 1284 status_t 1285 StreamReader::SetTo(Tree *tree, uint32 dirID, uint32 objectID) 1286 { 1287 fItem.Unset(); 1288 status_t error = fItemIterator.SetTo(tree, dirID, objectID, SD_OFFSET); 1289 fStreamSize = -1; 1290 fItemOffset = -1; 1291 fItemSize = 0; 1292 fBlockSize = tree->GetBlockSize(); 1293 return error; 1294 } 1295 1296 // InitCheck 1297 status_t 1298 StreamReader::InitCheck() const 1299 { 1300 return fItemIterator.InitCheck(); 1301 } 1302 1303 // ReadAt 1304 /*! \brief Tries to read the specified number of bytes from the stream into 1305 the supplied buffer. 1306 \param position Stream position at which to start reading. 1307 \param buffer Pointer to a pre-allocated buffer into which the read data 1308 shall be written. 1309 \param bufferSize Number of bytes to be read. 1310 \param _bytesRead Pointer to a pre-allocated size_t which shall be set to 1311 the number of bytes actually read. 1312 \return \c B_OK, if everything went fine. 1313 */ 1314 status_t 1315 StreamReader::ReadAt(off_t position, void *buffer, size_t bufferSize, 1316 size_t *_bytesRead) 1317 { 1318 //PRINT(("StreamReader::ReadAt(%Ld, %p, %lu)\n", position, buffer, bufferSize)); 1319 status_t error = (position >= 0 && buffer && _bytesRead ? InitCheck() 1320 : B_BAD_VALUE); 1321 // get the size of the stream 1322 if (error == B_OK) 1323 error = _GetStreamSize(); 1324 // compute the number of bytes that acually have to be read 1325 if (error == B_OK) { 1326 if (position < fStreamSize) { 1327 if (position + bufferSize > fStreamSize) 1328 bufferSize = fStreamSize - position; 1329 } else 1330 bufferSize = 0; 1331 } 1332 // do the reading 1333 if (error == B_OK) { 1334 size_t bytesRead = 0; 1335 while (error == B_OK && bufferSize > 0 1336 && (error = _SeekTo(position)) == B_OK) { 1337 //PRINT((" seeked to %Ld: fItemOffset: %Ld, fItemSize: %Ld\n", position, 1338 //fItemOffset, fItemSize)); 1339 off_t inItemOffset = max_c(0LL, position - fItemOffset); 1340 off_t toRead = min_c(fItemSize - inItemOffset, (off_t)bufferSize); 1341 switch (fItem.GetType()) { 1342 case TYPE_INDIRECT: 1343 error = _ReadIndirectItem(inItemOffset, buffer, toRead); 1344 break; 1345 case TYPE_DIRECT: 1346 error = _ReadDirectItem(inItemOffset, buffer, toRead); 1347 break; 1348 case TYPE_STAT_DATA: 1349 case TYPE_DIRENTRY: 1350 case TYPE_ANY: 1351 default: 1352 FATAL(("Neither direct nor indirect item! type: %u\n", 1353 fItem.GetType())); 1354 error = B_IO_ERROR; 1355 break; 1356 } 1357 if (error == B_OK) { 1358 buffer = (uint8*)buffer + toRead; 1359 position += toRead; 1360 bufferSize -= toRead; 1361 bytesRead += toRead; 1362 } 1363 } 1364 *_bytesRead = bytesRead; 1365 } 1366 //if (error == B_OK) 1367 //PRINT(("StreamReader::ReadAt() done: read: %lu bytes\n", *_bytesRead)) 1368 //else 1369 //PRINT(("StreamReader::ReadAt() done: %s\n", strerror(error))) 1370 return error; 1371 } 1372 1373 // Suspend 1374 /*! \brief Suspends the reader. 1375 \see ObjectItemIterator::Suspend(). 1376 \return \c B_OK, if everything went fine. 1377 */ 1378 status_t 1379 StreamReader::Suspend() 1380 { 1381 return fItemIterator.Suspend(); 1382 } 1383 1384 // Resume 1385 /*! \brief Resumes the reader. 1386 \see ObjectItemIterator::Resume(). 1387 \return \c B_OK, if everything went fine. 1388 */ 1389 status_t 1390 StreamReader::Resume() 1391 { 1392 return fItemIterator.Resume(); 1393 } 1394 1395 // _GetStreamSize 1396 status_t 1397 StreamReader::_GetStreamSize() 1398 { 1399 status_t error = B_OK; 1400 if (fStreamSize < 0) { 1401 // get the stat item 1402 error = fItemIterator.GetNext(&fItem, TYPE_STAT_DATA); 1403 if (error == B_OK) { 1404 StatData statData; 1405 error = (static_cast<StatItem*>(&fItem))->GetStatData(&statData); 1406 if (error == B_OK) 1407 fStreamSize = statData.GetSize(); 1408 } 1409 } 1410 return error; 1411 } 1412 1413 // _SeekTo 1414 status_t 1415 StreamReader::_SeekTo(off_t position) 1416 { 1417 status_t error = _GetStreamSize(); 1418 if (error == B_OK && fItemOffset < 0) 1419 fItemOffset = 0; // prepare for the loop 1420 if (error == B_OK) { 1421 if (2 * position < fItemOffset) { 1422 // seek backwards 1423 // since the position is closer to the beginning of the file than 1424 // to the current position, we simply reinit the item iterator 1425 // and seek forward 1426 error = fItemIterator.SetTo(GetTree(), GetDirID(), GetObjectID(), 1427 SD_OFFSET); 1428 fStreamSize = -1; 1429 fItemOffset = -1; 1430 fItemSize = 0; 1431 if (error == B_OK) 1432 error = _SeekTo(position); 1433 } else if (position < fItemOffset) { 1434 // seek backwards 1435 // iterate through the items 1436 while (error == B_OK && position < fItemOffset 1437 && (error = fItemIterator.GetPrevious(&fItem)) == B_OK) { 1438 fItemSize = 0; 1439 switch (fItem.GetType()) { 1440 case TYPE_INDIRECT: 1441 { 1442 IndirectItem &indirect 1443 = *static_cast<IndirectItem*>(&fItem); 1444 // Note, that it is assumed, that the existence of a 1445 // next item implies, that all blocks are fully used. 1446 // This is safe, since otherwise we would have never 1447 // come to the next item. 1448 fItemSize = indirect.CountBlocks() * (off_t)fBlockSize; 1449 break; 1450 } 1451 case TYPE_DIRECT: 1452 // See the comment for indirect items. 1453 fItemSize = fItem.GetLen(); 1454 break; 1455 case TYPE_STAT_DATA: 1456 case TYPE_DIRENTRY: 1457 case TYPE_ANY: 1458 default: 1459 // simply skip items of other kinds 1460 break; 1461 } 1462 fItemOffset -= fItemSize; 1463 } 1464 } else if (position >= fItemOffset + fItemSize) { 1465 // seek forward 1466 // iterate through the items 1467 while (error == B_OK && position >= fItemOffset + fItemSize 1468 && (error = fItemIterator.GetNext(&fItem)) == B_OK) { 1469 fItemOffset += fItemSize; 1470 fItemSize = 0; 1471 switch (fItem.GetType()) { 1472 case TYPE_INDIRECT: 1473 { 1474 IndirectItem &indirect 1475 = *static_cast<IndirectItem*>(&fItem); 1476 fItemSize = min(indirect.CountBlocks() 1477 * (off_t)fBlockSize, 1478 fStreamSize - fItemOffset); 1479 break; 1480 } 1481 case TYPE_DIRECT: 1482 fItemSize = min((off_t)fItem.GetLen(), 1483 fStreamSize - fItemOffset); 1484 break; 1485 case TYPE_STAT_DATA: 1486 case TYPE_DIRENTRY: 1487 case TYPE_ANY: 1488 default: 1489 // simply skip items of other kinds 1490 break; 1491 } 1492 } 1493 } 1494 } 1495 // return error; 1496 RETURN_ERROR(error); 1497 } 1498 1499 // _ReadIndirectItem 1500 status_t 1501 StreamReader::_ReadIndirectItem(off_t offset, void *buffer, size_t bufferSize) 1502 { 1503 //PRINT(("StreamReader::_ReadIndirectItem(%Ld, %p, %lu)\n", offset, buffer, bufferSize)); 1504 status_t error = B_OK; 1505 IndirectItem &indirect = *static_cast<IndirectItem*>(&fItem); 1506 // skip items until the offset is reached 1507 uint32 skipItems = 0; 1508 if (offset > 0) { 1509 skipItems = uint32(offset / fBlockSize); 1510 skipItems = min(skipItems, indirect.CountBlocks()); // not necessary 1511 } 1512 //PRINT((" skipItems: %lu\n", skipItems)); 1513 for (uint32 i = skipItems; 1514 error == B_OK && bufferSize > 0 && i < indirect.CountBlocks(); 1515 i++) { 1516 //PRINT((" child %lu\n", i)); 1517 // get the block 1518 Block *block = NULL; 1519 error = GetTree()->GetBlock(indirect.BlockNumberAt(i), &block); 1520 if (error == B_OK) { 1521 // copy the data into the buffer 1522 off_t blockOffset = i * (off_t)fBlockSize; 1523 uint32 localOffset = max_c(0LL, offset - blockOffset); 1524 uint32 toRead = min_c(fBlockSize - localOffset, bufferSize); 1525 memcpy(buffer, 1526 reinterpret_cast<uint8*>(block->GetData()) + localOffset, 1527 toRead); 1528 1529 block->Put(); 1530 bufferSize -= toRead; 1531 buffer = (uint8*)buffer + toRead; 1532 } else { 1533 FATAL(("failed to get block %" B_PRIu64 "\n", 1534 indirect.BlockNumberAt(i))); 1535 error = B_IO_ERROR; 1536 } 1537 } 1538 //PRINT(("StreamReader::_ReadIndirectItem() done: %s\n", strerror(error))) 1539 return error; 1540 } 1541 1542 // _ReadDirectItem 1543 status_t 1544 StreamReader::_ReadDirectItem(off_t offset, void *buffer, size_t bufferSize) 1545 { 1546 //PRINT(("StreamReader::_ReadDirectItem(%Ld, %p, %lu)\n", offset, buffer, bufferSize)); 1547 // copy the data into the buffer 1548 memcpy(buffer, 1549 reinterpret_cast<uint8*>(fItem.GetData()) + offset, bufferSize); 1550 return B_OK; 1551 } 1552 1553