xref: /haiku/src/add-ons/kernel/file_systems/reiserfs/Iterators.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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