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