xref: /haiku/src/add-ons/kernel/file_systems/reiserfs/Iterators.cpp (revision 95c9effd68127df2dce202d5e254a7c86560010a)
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(0LL, position - fItemOffset);
1340 			off_t toRead = min(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(0LL, offset - blockOffset);
1524 			uint32 toRead = min(fBlockSize - localOffset, bufferSize);
1525 			memcpy(buffer, (uint8*)block->GetData() + localOffset, toRead);
1526 			block->Put();
1527 			bufferSize -= toRead;
1528 			buffer = (uint8*)buffer + toRead;
1529 		} else {
1530 			FATAL(("failed to get block %Lu\n", indirect.BlockNumberAt(i)));
1531 			error = B_IO_ERROR;
1532 		}
1533 	}
1534 //PRINT(("StreamReader::_ReadIndirectItem() done: %s\n", strerror(error)))
1535 	return error;
1536 }
1537 
1538 // _ReadDirectItem
1539 status_t
1540 StreamReader::_ReadDirectItem(off_t offset, void *buffer, size_t bufferSize)
1541 {
1542 //PRINT(("StreamReader::_ReadDirectItem(%Ld, %p, %lu)\n", offset, buffer, bufferSize));
1543 	// copy the data into the buffer
1544 	memcpy(buffer, (uint8*)fItem.GetData() + offset, bufferSize);
1545 	return B_OK;
1546 }
1547 
1548