xref: /haiku/src/add-ons/kernel/file_systems/btrfs/BTree.cpp (revision 52850062104effde4152bb4551a4d89d99695e7f)
1299aba38Shyche /*
299768086Shyche  * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com.
3299aba38Shyche  * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
4299aba38Shyche  * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
5299aba38Shyche  * This file may be used under the terms of the MIT License.
6299aba38Shyche  */
7299aba38Shyche 
8299aba38Shyche 
9299aba38Shyche //! BTree implementation
10299aba38Shyche 
11299aba38Shyche 
12299aba38Shyche #include "BTree.h"
13883b9bf2Shyche #include "Journal.h"
14299aba38Shyche 
15*52850062SAugustin Cavalier #include <algorithm>
16*52850062SAugustin Cavalier 
17299aba38Shyche 
18299aba38Shyche //#define TRACE_BTRFS
19299aba38Shyche #ifdef TRACE_BTRFS
20299aba38Shyche #	define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
21299aba38Shyche #else
22299aba38Shyche #	define TRACE(x...) ;
23299aba38Shyche #endif
24299aba38Shyche #	define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
25299aba38Shyche 
26299aba38Shyche 
278160f31fShyche BTree::Node::Node(Volume* volume)
281481c49cShyche 	:
291481c49cShyche 	fNode(NULL),
308160f31fShyche 	fVolume(volume),
311481c49cShyche 	fBlockNumber(0),
321481c49cShyche 	fWritable(false)
331481c49cShyche {
341481c49cShyche }
351481c49cShyche 
361481c49cShyche 
378160f31fShyche BTree::Node::Node(Volume* volume, off_t block)
381481c49cShyche 	:
391481c49cShyche 	fNode(NULL),
408160f31fShyche 	fVolume(volume),
411481c49cShyche 	fBlockNumber(0),
421481c49cShyche 	fWritable(false)
431481c49cShyche {
441481c49cShyche 	SetTo(block);
451481c49cShyche }
461481c49cShyche 
471481c49cShyche 
48548a0d80Shyche BTree::Node::~Node()
491481c49cShyche {
501481c49cShyche 	Unset();
511481c49cShyche }
521481c49cShyche 
531481c49cShyche 
541481c49cShyche void
55548a0d80Shyche BTree::Node::Keep()
561481c49cShyche {
571481c49cShyche 	fNode = NULL;
581481c49cShyche }
591481c49cShyche 
601481c49cShyche void
61548a0d80Shyche BTree::Node::Unset()
621481c49cShyche {
631481c49cShyche 	if (fNode != NULL) {
648160f31fShyche 		block_cache_put(fVolume->BlockCache(), fBlockNumber);
651481c49cShyche 		fNode = NULL;
661481c49cShyche 	}
671481c49cShyche }
681481c49cShyche 
691481c49cShyche 
701481c49cShyche void
71548a0d80Shyche BTree::Node::SetTo(off_t block)
721481c49cShyche {
731481c49cShyche 	Unset();
741481c49cShyche 	fBlockNumber = block;
758160f31fShyche 	fNode = (btrfs_stream*)block_cache_get(fVolume->BlockCache(), block);
761481c49cShyche }
771481c49cShyche 
781481c49cShyche 
791481c49cShyche void
80548a0d80Shyche BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty)
811481c49cShyche {
821481c49cShyche 	Unset();
831481c49cShyche 	fBlockNumber = block;
841481c49cShyche 	fWritable = true;
851481c49cShyche 	if (empty) {
868160f31fShyche 		fNode = (btrfs_stream*)block_cache_get_empty(fVolume->BlockCache(),
878160f31fShyche 			block, transactionId);
881481c49cShyche 	} else {
898160f31fShyche 		fNode = (btrfs_stream*)block_cache_get_writable(fVolume->BlockCache(),
908160f31fShyche 			block, transactionId);
911481c49cShyche 	}
921481c49cShyche }
931481c49cShyche 
941481c49cShyche 
952ed88a48Shyche status_t
962ed88a48Shyche BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type)
972ed88a48Shyche 	const
9891d7f850Shyche {
9991d7f850Shyche 	//binary search for item slot in a node
10091d7f850Shyche 	int entrySize = sizeof(btrfs_entry);
10191d7f850Shyche 	if (Level() != 0) {
10291d7f850Shyche 		// internal node
10391d7f850Shyche 		entrySize = sizeof(btrfs_index);
10491d7f850Shyche 	}
10591d7f850Shyche 
10691d7f850Shyche 	int high = ItemCount();
1072ed88a48Shyche 	int low = 0, mid = 0, comp = 0;
1082ed88a48Shyche 	uint8* base = (uint8*)fNode + sizeof(btrfs_header);
10991d7f850Shyche 	const btrfs_key* other;
11091d7f850Shyche 	while (low < high) {
11191d7f850Shyche 		mid = (low + high) / 2;
1122ed88a48Shyche 		other = (const btrfs_key*)(base + mid * entrySize);
1130d726c5cShyche 		comp = key.Compare(*other);
11491d7f850Shyche 		if (comp < 0)
11591d7f850Shyche 			high = mid;
11691d7f850Shyche 		else if (comp > 0)
11791d7f850Shyche 			low = mid + 1;
11891d7f850Shyche 		else {
11991d7f850Shyche 			*slot = mid;
1200d726c5cShyche 			return B_OK; 		//if key is in node
12191d7f850Shyche 		}
12291d7f850Shyche 	}
1230d726c5cShyche 
1242ed88a48Shyche 	// |--item1--|--item2--|--item3--|--etc--|
1252ed88a48Shyche 	//     m-1        m        m+1
1262ed88a48Shyche 	//           k          		: comp < 0
1272ed88a48Shyche 	//                     k		: comp > 0
1282ed88a48Shyche 	if (type == BTREE_BACKWARD) {
1292ed88a48Shyche 		*slot = mid - 1;
1302ed88a48Shyche 		if (comp > 0)
1312ed88a48Shyche 			*slot = mid;
1322ed88a48Shyche 	} else if (type == BTREE_FORWARD) {
1332ed88a48Shyche 		*slot = mid;
1342ed88a48Shyche 		if (comp > 0)
1352ed88a48Shyche 			*slot = mid + 1;
1362ed88a48Shyche 	}
1372ed88a48Shyche 
1382ed88a48Shyche 	if (type == BTREE_EXACT || *slot < 0)
1392ed88a48Shyche 		return B_ENTRY_NOT_FOUND;
1402ed88a48Shyche 
1410d726c5cShyche 	TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n",
1420d726c5cShyche 		*slot, comp);
1430d726c5cShyche 	return B_OK;
14491d7f850Shyche }
14591d7f850Shyche 
14691d7f850Shyche 
14727ffe058Shyche /*
14827ffe058Shyche  * calculate used space except the header.
14927ffe058Shyche  * type is only for leaf node
15027ffe058Shyche  * type 1: only item space
15127ffe058Shyche  * type 2: only item data space
15227ffe058Shyche  * type 3: both type 1 and 2
15327ffe058Shyche  */
15427ffe058Shyche int
15527ffe058Shyche BTree::Node::_CalculateSpace(uint32 from, uint32 to, uint8 type) const
15627ffe058Shyche {
15727ffe058Shyche 	if (to < from || to >= ItemCount())
15827ffe058Shyche 		return 0;
15927ffe058Shyche 
16027ffe058Shyche 	if (Level() != 0)
16127ffe058Shyche 		return sizeof(btrfs_index) * (to - from + 1);
16227ffe058Shyche 
16327ffe058Shyche 	uint32 result = 0;
16427ffe058Shyche 	if ((type & 1) == 1) {
16527ffe058Shyche 		result += sizeof(btrfs_entry) * (to - from + 1);
16627ffe058Shyche 	}
16727ffe058Shyche 	if ((type & 2) == 2) {
16827ffe058Shyche 		result += Item(from)->Offset() + Item(from)->Size()
16927ffe058Shyche 			- Item(to)->Offset();
17027ffe058Shyche 	}
17127ffe058Shyche 
17227ffe058Shyche 	return result;
17327ffe058Shyche }
17427ffe058Shyche 
17527ffe058Shyche 
17627ffe058Shyche int
17727ffe058Shyche BTree::Node::SpaceUsed() const
17827ffe058Shyche {
17927ffe058Shyche 	if (Level() == 0)
18027ffe058Shyche 		return _CalculateSpace(0, ItemCount() - 1, 3);
18127ffe058Shyche 	return _CalculateSpace(0, ItemCount() - 1, 0);
18227ffe058Shyche }
18327ffe058Shyche 
18427ffe058Shyche 
18527ffe058Shyche int
18627ffe058Shyche BTree::Node::SpaceLeft() const
18727ffe058Shyche {
18827ffe058Shyche 	return fVolume->BlockSize() - SpaceUsed() - sizeof(btrfs_header);
18927ffe058Shyche }
19027ffe058Shyche 
19127ffe058Shyche 
19289484dc0Shyche void
19389484dc0Shyche BTree::Node::_Copy(const Node* origin, uint32 at, uint32 from, uint32 to,
19489484dc0Shyche 	int length) const
19589484dc0Shyche {
19689484dc0Shyche 	TRACE("Node::_Copy() at: %d from: %d to: %d length: %d\n",
19789484dc0Shyche 		at, from, to, length);
19889484dc0Shyche 
19989484dc0Shyche 	if (Level() == 0) {
20089484dc0Shyche 		memcpy(Item(at), origin->Item(from), origin->_CalculateSpace(from, to));
20189484dc0Shyche 		// Item offset of copied node must be changed to get the
20289484dc0Shyche 		// item data offset correctly. length can be zero
20389484dc0Shyche 		// but let it there doesn't harm anything.
20489484dc0Shyche 		for (uint32 i = at; i - at <= to - from; ++i)
20589484dc0Shyche 			Item(i)->SetOffset(Item(i)->Offset() - length);
20689484dc0Shyche 
20789484dc0Shyche 		memcpy(ItemData(at + to - from), origin->ItemData(to),
20889484dc0Shyche 			origin->_CalculateSpace(from, to, 2));
20989484dc0Shyche 	} else {
21089484dc0Shyche 		memcpy(Index(at), origin->Index(from),
21189484dc0Shyche 			origin->_CalculateSpace(from, to));
21289484dc0Shyche 	}
21389484dc0Shyche }
21489484dc0Shyche 
21589484dc0Shyche 
21627ffe058Shyche status_t
21727ffe058Shyche BTree::Node::_SpaceCheck(int length) const
21827ffe058Shyche {
21927ffe058Shyche 	// this is a little bit weird here because we can't find
22027ffe058Shyche 	// any suitable error code
22127ffe058Shyche 	if (length < 0 && std::abs(length) >= SpaceUsed())
22227ffe058Shyche 		return B_DIRECTORY_NOT_EMPTY;	// not enough data to delete
22327ffe058Shyche 	if (length > 0 && length >= SpaceLeft())
22427ffe058Shyche 		return B_DEVICE_FULL;			// no spare space
22527ffe058Shyche 	return B_OK;
22627ffe058Shyche }
22727ffe058Shyche 
22827ffe058Shyche 
22989484dc0Shyche /*
23089484dc0Shyche  * copy node header, items and items data
23189484dc0Shyche  * length is size to insert/remove
23289484dc0Shyche  * if node is a internal node, length isnt used
23389484dc0Shyche  * length = 0: Copy a whole
23489484dc0Shyche  * length < 0: removing
23589484dc0Shyche  * length > 0: inserting
23689484dc0Shyche  */
23789484dc0Shyche status_t
23889484dc0Shyche BTree::Node::Copy(const Node* origin, uint32 start, uint32 end, int length)
23989484dc0Shyche 	const
24089484dc0Shyche {
24189484dc0Shyche 	status_t status = origin->_SpaceCheck(length);
24289484dc0Shyche 	if (status != B_OK)
24389484dc0Shyche 		return status;
24489484dc0Shyche 
24589484dc0Shyche 	memcpy(fNode, origin->fNode, sizeof(btrfs_header));
24689484dc0Shyche 	if (length == 0) {
24789484dc0Shyche 		// like removing [0, start - 1] and keeping [start, end]
24889484dc0Shyche 		length = -origin->_CalculateSpace(0, start - 1, 2);
24989484dc0Shyche 		_Copy(origin, 0, start, end, length);
25089484dc0Shyche 	} else if (length < 0) {
25189484dc0Shyche 		//removing all items in [start, end]
25289484dc0Shyche 		if (start > 0)
25389484dc0Shyche 			_Copy(origin, 0, 0, start - 1, 0);	// <-- [start,...
25489484dc0Shyche 		if (end + 1 < origin->ItemCount()) {
25589484dc0Shyche 			// ..., end] -->
25689484dc0Shyche 			// we only care data size
25789484dc0Shyche 			length += origin->_CalculateSpace(start, end);
25889484dc0Shyche 			_Copy(origin, start, end + 1, origin->ItemCount() - 1, length);
25989484dc0Shyche 		}
26089484dc0Shyche 	} else {
26189484dc0Shyche 		//inserting in [start, end] - make a hole for later
26289484dc0Shyche 		if (start > 0)
26389484dc0Shyche 			_Copy(origin, 0, 0, start - 1, 0);
26489484dc0Shyche 		if (start < origin->ItemCount()) {
26589484dc0Shyche 			length -= origin->_CalculateSpace(start, end);
26689484dc0Shyche 			_Copy(origin, end + 1, start, origin->ItemCount() - 1, length);
26789484dc0Shyche 		}
26889484dc0Shyche 	}
26989484dc0Shyche 
27089484dc0Shyche 	return B_OK;
27189484dc0Shyche }
27289484dc0Shyche 
27389484dc0Shyche 
27489484dc0Shyche /* Like copy but here we use memmove on current node.
27589484dc0Shyche  */
27689484dc0Shyche status_t
27789484dc0Shyche BTree::Node::MoveEntries(uint32 start, uint32 end, int length) const
27889484dc0Shyche {
27989484dc0Shyche 	status_t status = _SpaceCheck(length);
28089484dc0Shyche 	if (status != B_OK || length == 0/*B_OK*/)
28189484dc0Shyche 		return status;
28289484dc0Shyche 
28389484dc0Shyche 	int entrySize = sizeof(btrfs_entry);
28489484dc0Shyche 	if (Level() != 0)
28589484dc0Shyche 		entrySize = sizeof(btrfs_index);
28689484dc0Shyche 
28789484dc0Shyche 	uint8* base = (uint8*)fNode + sizeof(btrfs_header);
28889484dc0Shyche 	end++;
28989484dc0Shyche 	if (length < 0) {
29089484dc0Shyche 		// removing [start, end]
29189484dc0Shyche 		TRACE("Node::MoveEntries() removing ... start %" B_PRIu32 " end %"
29289484dc0Shyche 			B_PRIu32 " length %i\n", start, end, length);
29389484dc0Shyche 		length += _CalculateSpace(start, end - 1);
29489484dc0Shyche 	} else {
29589484dc0Shyche 		// length > 0
29689484dc0Shyche 		// inserting into [start, end] - make room for later
29789484dc0Shyche 		TRACE("Node::MoveEntries() inserting ... start %" B_PRIu32 " end %"
29889484dc0Shyche 			B_PRIu32 " length %i\n", start, end, length);
29989484dc0Shyche 		length -= _CalculateSpace(start, end - 1);
30089484dc0Shyche 		std::swap(start, end);
30189484dc0Shyche 	}
30289484dc0Shyche 
30389484dc0Shyche 	if (end >= ItemCount())
30489484dc0Shyche 		return B_OK;
30589484dc0Shyche 
30689484dc0Shyche 	int dataSize = _CalculateSpace(end, ItemCount() - 1, 2);
30789484dc0Shyche 	// moving items/block pointers
30889484dc0Shyche 	memmove(base + start * entrySize, base + end * entrySize,
30989484dc0Shyche 		_CalculateSpace(end, ItemCount() - 1));
31089484dc0Shyche 	if (Level() == 0) {
31189484dc0Shyche 		// moving item data
31289484dc0Shyche 		int num = start - end;
31389484dc0Shyche 		for(uint32 i = start; i < ItemCount() + num; ++i)
31489484dc0Shyche 			Item(i)->SetOffset(Item(i)->Offset() - length);
31589484dc0Shyche 
31689484dc0Shyche 		memmove(ItemData(ItemCount() - 1) - length, ItemData(ItemCount() - 1),
31789484dc0Shyche 			dataSize);
31889484dc0Shyche 	}
31989484dc0Shyche 
32089484dc0Shyche 	return B_OK;
32189484dc0Shyche }
32289484dc0Shyche 
32389484dc0Shyche 
3243216460dShyche //	#pragma mark - BTree::Path implementation
3253216460dShyche 
3263216460dShyche 
3273216460dShyche BTree::Path::Path(BTree* tree)
3283216460dShyche 	:
3293216460dShyche 	fTree(tree)
3303216460dShyche {
3313216460dShyche 	for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
3323216460dShyche 		fNodes[i] = NULL;
3333216460dShyche 		fSlots[i] = 0;
3343216460dShyche 	}
3353216460dShyche }
3363216460dShyche 
3373216460dShyche 
3383216460dShyche BTree::Path::~Path()
3393216460dShyche {
3403216460dShyche 	for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) {
3413216460dShyche 		delete fNodes[i];
3423216460dShyche 		fNodes[i] = NULL;
3433216460dShyche 		fSlots[i] = 0;
3443216460dShyche 	}
3453216460dShyche }
3463216460dShyche 
3473216460dShyche 
3483216460dShyche BTree::Node*
3493216460dShyche BTree::Path::GetNode(int level, int* _slot) const
3503216460dShyche {
3513216460dShyche 	if (_slot != NULL)
3523216460dShyche 		*_slot = fSlots[level];
3533216460dShyche 	return fNodes[level];
3543216460dShyche }
3553216460dShyche 
3563216460dShyche 
3573216460dShyche BTree::Node*
3583216460dShyche BTree::Path::SetNode(off_t block, int slot)
3593216460dShyche {
3603216460dShyche 	Node node(fTree->SystemVolume(), block);
3613216460dShyche 	return SetNode(&node, slot);
3623216460dShyche }
3633216460dShyche 
3643216460dShyche 
3653216460dShyche BTree::Node*
3663216460dShyche BTree::Path::SetNode(const Node* node, int slot)
3673216460dShyche {
3683216460dShyche 	uint8 level = node->Level();
3693216460dShyche 	if (fNodes[level] == NULL) {
3703216460dShyche 		fNodes[level] = new Node(fTree->SystemVolume(), node->BlockNum());
3713216460dShyche 		if (fNodes[level] == NULL)
3723216460dShyche 			return NULL;
3733216460dShyche 	} else
3743216460dShyche 		fNodes[level]->SetTo(node->BlockNum());
3753216460dShyche 
3763216460dShyche 	if (slot == -1)
3773216460dShyche 		fSlots[level] = fNodes[level]->ItemCount() - 1;
3783216460dShyche 	else
3793216460dShyche 		fSlots[level] = slot;
3803216460dShyche 	return fNodes[level];
3813216460dShyche }
3823216460dShyche 
3833216460dShyche 
3843216460dShyche int
3853216460dShyche BTree::Path::Move(int level, int step)
3863216460dShyche {
3873216460dShyche 	fSlots[level] += step;
3883216460dShyche 	if (fSlots[level] < 0)
3893216460dShyche 		return -1;
3903216460dShyche 	if (fSlots[level] >= fNodes[level]->ItemCount())
3913216460dShyche 		return 1;
3923216460dShyche 	return 0;
3933216460dShyche }
3943216460dShyche 
3953216460dShyche 
3963216460dShyche status_t
3973216460dShyche BTree::Path::GetEntry(int slot, btrfs_key* _key, void** _value, uint32* _size,
3983216460dShyche 	uint32* _offset)
3993216460dShyche {
4003216460dShyche 	BTree::Node* leaf = fNodes[0];
4013216460dShyche 	if (slot < 0 || slot >= leaf->ItemCount())
4023216460dShyche 		return B_ENTRY_NOT_FOUND;
4033216460dShyche 
4043216460dShyche 	if (_key != NULL)
4053216460dShyche 		*_key = leaf->Item(slot)->key;
4063216460dShyche 
4073216460dShyche 	uint32 itemSize = leaf->Item(slot)->Size();
4083216460dShyche 	if (_value != NULL) {
4093216460dShyche 		*_value = malloc(itemSize);
4103216460dShyche 		if (*_value == NULL)
4113216460dShyche 			return B_NO_MEMORY;
4123216460dShyche 
4133216460dShyche 		memcpy(*_value, leaf->ItemData(slot), itemSize);
4143216460dShyche 	}
4153216460dShyche 
4163216460dShyche 	if (_size != NULL)
4173216460dShyche 		*_size = itemSize;
4183216460dShyche 
4193216460dShyche 	if (_offset != NULL)
4203216460dShyche 		*_offset = leaf->Item(slot)->Offset();
4213216460dShyche 
4223216460dShyche 	return B_OK;
4233216460dShyche }
4243216460dShyche 
4253216460dShyche 
42684bc447cShyche status_t
42784bc447cShyche BTree::Path::SetEntry(int slot, const btrfs_entry& entry, void* value)
42884bc447cShyche {
42984bc447cShyche 	if (slot < 0)
43084bc447cShyche 		return B_ENTRY_NOT_FOUND;
43184bc447cShyche 
43284bc447cShyche 	memcpy(fNodes[0]->Item(slot), &entry, sizeof(btrfs_entry));
43384bc447cShyche 	memcpy(fNodes[0]->ItemData(slot), value, entry.Size());
43484bc447cShyche 	return B_OK;
43584bc447cShyche }
43684bc447cShyche 
43784bc447cShyche 
438883b9bf2Shyche /*
439883b9bf2Shyche  * Allocate and copy block and do all the changes that it can.
440883b9bf2Shyche  * for now, we only copy-on-write tree block,
441883b9bf2Shyche  * file data is "nocow" by default.
442883b9bf2Shyche  *
443883b9bf2Shyche  * 	o	parent	o
444883b9bf2Shyche  * 	|	 ===> 	 \
445883b9bf2Shyche  * 	o	      	x o
446883b9bf2Shyche  */
447883b9bf2Shyche status_t
448883b9bf2Shyche BTree::Path::CopyOnWrite(Transaction& transaction, int level, uint32 start,
449883b9bf2Shyche 	int num, int length)
450883b9bf2Shyche {
451883b9bf2Shyche 	Node* node = fNodes[level];
452883b9bf2Shyche 	if (node == NULL)
453883b9bf2Shyche 		return B_BAD_VALUE;
454883b9bf2Shyche 
455883b9bf2Shyche 	status_t status;
456883b9bf2Shyche 	if (transaction.HasBlock(node->BlockNum())) {
457883b9bf2Shyche 		// cow-ed block can not be cow-ed again
458883b9bf2Shyche 		status = node->MoveEntries(start, start + num - 1, length);
459883b9bf2Shyche 		if (status != B_OK)
460883b9bf2Shyche 			return status;
461883b9bf2Shyche 
462883b9bf2Shyche 		node->SetGeneration(transaction.SystemID());
463883b9bf2Shyche 		if (length < 0)
464883b9bf2Shyche 			node->SetItemCount(node->ItemCount() - num);
465883b9bf2Shyche 		else if (length > 0)
466883b9bf2Shyche 			node->SetItemCount(node->ItemCount() + num);
467883b9bf2Shyche 
468883b9bf2Shyche 		return B_OK;
469883b9bf2Shyche 	}
470883b9bf2Shyche 
471883b9bf2Shyche 	uint64 address;
472883b9bf2Shyche 	fsblock_t block;
473883b9bf2Shyche 	status = fTree->SystemVolume()->GetNewBlock(address, block);
474883b9bf2Shyche 	if (status != B_OK)
475883b9bf2Shyche 		return status;
476883b9bf2Shyche 
477883b9bf2Shyche 	fNodes[level] = new(std::nothrow) BTree::Node(fTree->SystemVolume());
478883b9bf2Shyche 	if (fNodes[level] == NULL)
479883b9bf2Shyche 		return B_NO_MEMORY;
480883b9bf2Shyche 
481883b9bf2Shyche 	fNodes[level]->SetToWritable(block, transaction.ID(), true);
482883b9bf2Shyche 
483883b9bf2Shyche 	status = fNodes[level]->Copy(node, start, start + num - 1, length);
484883b9bf2Shyche 	if (status != B_OK)
485883b9bf2Shyche 		return status;
486883b9bf2Shyche 
487883b9bf2Shyche 	fNodes[level]->SetGeneration(transaction.SystemID());
488883b9bf2Shyche 	fNodes[level]->SetLogicalAddress(address);
489883b9bf2Shyche 	if (length < 0)
490883b9bf2Shyche 		fNodes[level]->SetItemCount(node->ItemCount() - num);
491883b9bf2Shyche 	else if (length > 0)
492883b9bf2Shyche 		fNodes[level]->SetItemCount(node->ItemCount() + num);
493883b9bf2Shyche 	else
494883b9bf2Shyche 		fNodes[level]->SetItemCount(num);
495883b9bf2Shyche 
496883b9bf2Shyche 	// change pointer of this node in parent
497883b9bf2Shyche 	int parentSlot;
498883b9bf2Shyche 	Node* parentNode = GetNode(level + 1, &parentSlot);
499883b9bf2Shyche 	if (parentNode != NULL)
500883b9bf2Shyche 		parentNode->Index(parentSlot)->SetLogicalAddress(address);
501883b9bf2Shyche 
502883b9bf2Shyche 	if (level == fTree->RootLevel())
503883b9bf2Shyche 		fTree->SetRoot(fNodes[level]);
504883b9bf2Shyche 
505883b9bf2Shyche 	delete node;
506883b9bf2Shyche 	return B_OK;
507883b9bf2Shyche }
508883b9bf2Shyche 
509883b9bf2Shyche 
510883b9bf2Shyche /* Copy-On-Write all internal nodes start from a specific level.
511883b9bf2Shyche  * level > 0: to root
512883b9bf2Shyche  * level <= 0: to leaf
513883b9bf2Shyche  *
514883b9bf2Shyche  *		path	cow-path       path    cow-path
515883b9bf2Shyche  *	=================================================
516883b9bf2Shyche  *		root	cow-root       root	level < 0
517883b9bf2Shyche  *		 |  	|               |
518883b9bf2Shyche  *		 n1 	cow-n1         ...______
519883b9bf2Shyche  *		 |  	|               |       \
520883b9bf2Shyche  *		 n2 	cow-n2          n1     cow-n1
521883b9bf2Shyche  *		 |  	/               |        |
522883b9bf2Shyche  *		...____/                n2     cow-n2
523883b9bf2Shyche  *		 |  	                |        |
524883b9bf2Shyche  *		leaf	level > 0      leaf    cow-leaf
525883b9bf2Shyche  */
526883b9bf2Shyche status_t
527883b9bf2Shyche BTree::Path::InternalCopy(Transaction& transaction, int level)
528883b9bf2Shyche {
529883b9bf2Shyche 	if (std::abs(level) >= fTree->RootLevel())
530883b9bf2Shyche 		return B_OK;
531883b9bf2Shyche 
532883b9bf2Shyche 	TRACE("Path::InternalCopy() level %i\n", level);
533883b9bf2Shyche 	int from, to;
534883b9bf2Shyche 	if (level > 0) {
535883b9bf2Shyche 		from = level;
536883b9bf2Shyche 		to = fTree->RootLevel();
537883b9bf2Shyche 	} else {
538883b9bf2Shyche 		from = 0;
539883b9bf2Shyche 		to = std::abs(level);
540883b9bf2Shyche 	}
541883b9bf2Shyche 
542883b9bf2Shyche 	Node* node = NULL;
543883b9bf2Shyche 	status_t status;
544883b9bf2Shyche 	while (from <= to) {
545883b9bf2Shyche 		node = fNodes[from];
546883b9bf2Shyche 		status = CopyOnWrite(transaction, from, 0, node->ItemCount(), 0);
547883b9bf2Shyche 		from++;
548883b9bf2Shyche 		if (status != B_OK)
549883b9bf2Shyche 			return status;
550883b9bf2Shyche 	}
551883b9bf2Shyche 
552883b9bf2Shyche 	return B_OK;
553883b9bf2Shyche }
554883b9bf2Shyche 
555883b9bf2Shyche 
5563216460dShyche //	#pragma mark - BTree implementation
5571481c49cShyche 
5581481c49cShyche 
559fc4a1e78Shyche BTree::BTree(Volume* volume)
560fc4a1e78Shyche 	:
561fc4a1e78Shyche 	fRootBlock(0),
562883b9bf2Shyche 	fRootLevel(0),
563fc4a1e78Shyche 	fVolume(volume)
564fc4a1e78Shyche {
565fc4a1e78Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
566fc4a1e78Shyche }
567fc4a1e78Shyche 
568fc4a1e78Shyche 
569299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream)
570299aba38Shyche 	:
571299aba38Shyche 	fRootBlock(0),
572883b9bf2Shyche 	fRootLevel(0),
573299aba38Shyche 	fVolume(volume)
574299aba38Shyche {
575299aba38Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
576299aba38Shyche }
577299aba38Shyche 
578299aba38Shyche 
579299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock)
580299aba38Shyche 	:
581299aba38Shyche 	fRootBlock(rootBlock),
582299aba38Shyche 	fVolume(volume)
583299aba38Shyche {
584299aba38Shyche 	mutex_init(&fIteratorLock, "btrfs b+tree iterator");
585299aba38Shyche }
586299aba38Shyche 
587299aba38Shyche 
588299aba38Shyche BTree::~BTree()
589299aba38Shyche {
590299aba38Shyche 	// if there are any TreeIterators left, we need to stop them
591299aba38Shyche 	// (can happen when the tree's inode gets deleted while
592299aba38Shyche 	// traversing the tree - a TreeIterator doesn't lock the inode)
593299aba38Shyche 	mutex_lock(&fIteratorLock);
594299aba38Shyche 
595299aba38Shyche 	SinglyLinkedList<TreeIterator>::Iterator iterator
596299aba38Shyche 		= fIterators.GetIterator();
597299aba38Shyche 	while (iterator.HasNext())
598299aba38Shyche 		iterator.Next()->Stop();
599299aba38Shyche 	mutex_destroy(&fIteratorLock);
600299aba38Shyche }
601299aba38Shyche 
602299aba38Shyche 
603299aba38Shyche int32
604875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const
605299aba38Shyche {
606875a0552Shyche 	if (ObjectID() > key.ObjectID())
607299aba38Shyche 		return 1;
608875a0552Shyche 	if (ObjectID() < key.ObjectID())
609299aba38Shyche 		return -1;
610875a0552Shyche 	if (Type() > key.Type())
611299aba38Shyche 		return 1;
612875a0552Shyche 	if (Type() < key.Type())
613299aba38Shyche 		return -1;
614875a0552Shyche 	if (Offset() > key.Offset())
615299aba38Shyche 		return 1;
616875a0552Shyche 	if (Offset() < key.Offset())
617299aba38Shyche 		return -1;
618299aba38Shyche 	return 0;
619299aba38Shyche }
620299aba38Shyche 
621299aba38Shyche 
6223216460dShyche /* Traverse from root to fill in the path along way its finding.
6233216460dShyche  * Return current slot at leaf if successful.
6243216460dShyche  */
6253216460dShyche status_t
6263216460dShyche BTree::Traverse(btree_traversing type, Path* path, const btrfs_key& key)
6273216460dShyche 	const
6283216460dShyche {
6293216460dShyche 	TRACE("BTree::Traverse() objectid %" B_PRId64 " type %d offset %"
6303216460dShyche 		B_PRId64 " \n", key.ObjectID(),	key.Type(), key.Offset());
6313216460dShyche 	fsblock_t physicalBlock = fRootBlock;
6323216460dShyche 	Node node(fVolume, physicalBlock);
6333216460dShyche 	int slot;
6343216460dShyche 	status_t status = B_OK;
6353216460dShyche 
6363216460dShyche 	while (node.Level() != 0) {
6373216460dShyche 		TRACE("BTree::Traverse() level %d count %d\n", node.Level(),
6383216460dShyche 			node.ItemCount());
6393216460dShyche 		status = node.SearchSlot(key, &slot, BTREE_BACKWARD);
6403216460dShyche 		if (status != B_OK)
6413216460dShyche 			return status;
6423216460dShyche 		if (path->SetNode(&node, slot) == NULL)
6433216460dShyche 			return B_NO_MEMORY;
6443216460dShyche 
6453216460dShyche 		TRACE("BTree::Traverse() getting index %" B_PRIu32 "\n", slot);
6463216460dShyche 
6473216460dShyche 		status = fVolume->FindBlock(node.Index(slot)->LogicalAddress(),
6483216460dShyche 				physicalBlock);
6493216460dShyche 		if (status != B_OK) {
6503216460dShyche 			ERROR("BTree::Traverse() unmapped block %" B_PRId64 "\n",
6513216460dShyche 				node.Index(slot)->LogicalAddress());
6523216460dShyche 			return status;
6533216460dShyche 		}
6543216460dShyche 		node.SetTo(physicalBlock);
6553216460dShyche 	}
6563216460dShyche 
6573216460dShyche 	TRACE("BTree::Traverse() dump count %" B_PRId32 "\n", node.ItemCount());
6583216460dShyche 	status = node.SearchSlot(key, &slot, type);
6593216460dShyche 	if (status != B_OK)
6603216460dShyche 		return status;
6613216460dShyche 	if (path->SetNode(&node, slot) == NULL)
6623216460dShyche 		return B_NO_MEMORY;
6633216460dShyche 
6643216460dShyche 	TRACE("BTree::Traverse() found %" B_PRIu32 " %" B_PRIu32 "\n",
6653216460dShyche 		node.Item(slot)->Offset(), node.Item(slot)->Size());
6663216460dShyche 	return slot;
6673216460dShyche }
6683216460dShyche 
6693216460dShyche 
670299aba38Shyche /*!	Searches the key in the tree, and stores the allocated found item in
671299aba38Shyche 	_value, if successful.
672299aba38Shyche 	Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
673299aba38Shyche 	It can also return other errors to indicate that something went wrong.
674299aba38Shyche */
675299aba38Shyche status_t
6763216460dShyche BTree::_Find(Path* path, btrfs_key& wanted, void** _value, uint32* _size,
6773216460dShyche 	uint32* _offset, btree_traversing type) const
678299aba38Shyche {
6793216460dShyche 	status_t status = Traverse(type, path, wanted);
6803216460dShyche 	if (status < B_OK)
6813216460dShyche 		return status;
682299aba38Shyche 
6833216460dShyche 	btrfs_key found;
6843216460dShyche 	status = path->GetCurrentEntry(&found, _value, _size, _offset);
6853216460dShyche 	if (status != B_OK)
6863216460dShyche 		return status;
687299aba38Shyche 
6883216460dShyche 	if (found.Type() != wanted.Type() && wanted.Type() != BTRFS_KEY_TYPE_ANY)
68946eba5c0Shyche 		return B_ENTRY_NOT_FOUND;
690299aba38Shyche 
6913216460dShyche 	wanted = found;
692299aba38Shyche 	return B_OK;
693299aba38Shyche }
694299aba38Shyche 
695299aba38Shyche 
69646eba5c0Shyche status_t
6973216460dShyche BTree::FindNext(Path* path, btrfs_key& key, void** _value, uint32* _size,
6983216460dShyche 	uint32* _offset) const
69946eba5c0Shyche {
7003216460dShyche 	return _Find(path, key, _value, _size, _offset, BTREE_FORWARD);
701299aba38Shyche }
702299aba38Shyche 
703299aba38Shyche 
704299aba38Shyche status_t
7053216460dShyche BTree::FindPrevious(Path* path, btrfs_key& key, void** _value, uint32* _size,
7063216460dShyche 	uint32* _offset) const
707299aba38Shyche {
7083216460dShyche 	return _Find(path, key, _value, _size, _offset, BTREE_BACKWARD);
709299aba38Shyche }
710299aba38Shyche 
711299aba38Shyche 
712299aba38Shyche status_t
7133216460dShyche BTree::FindExact(Path* path, btrfs_key& key, void** _value, uint32* _size,
7143216460dShyche 	uint32* _offset) const
715299aba38Shyche {
7163216460dShyche 	return _Find(path, key, _value, _size, _offset, BTREE_EXACT);
7173216460dShyche }
7183216460dShyche 
7193216460dShyche 
72084bc447cShyche /*
72184bc447cShyche  * Insert "num" of consecutive empty entries start with slot of "startKey"
72284bc447cShyche  * if successful return the starting slot, otherwise return error code.
72384bc447cShyche  */
72484bc447cShyche status_t
72584bc447cShyche BTree::MakeEntries(Transaction& transaction, Path* path,
72684bc447cShyche 	const btrfs_key& startKey, int num, int length)
72784bc447cShyche {
72884bc447cShyche 	TRACE("BTree::MakeEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %"
72984bc447cShyche 		B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(),
73084bc447cShyche 		startKey.Offset());
73184bc447cShyche 
73284bc447cShyche 	status_t status = Traverse(BTREE_FORWARD, path, startKey);
73384bc447cShyche 	if (status < B_OK)
73484bc447cShyche 		return status;
73584bc447cShyche 
73684bc447cShyche 	int slot = status;
73784bc447cShyche 	status = path->InternalCopy(transaction, 1);
73884bc447cShyche 	if (status != B_OK)
73984bc447cShyche 		return status;
74084bc447cShyche 
74184bc447cShyche 	status = path->CopyOnWrite(transaction, 0, slot, num, length);
74284bc447cShyche 	if (status == B_DEVICE_FULL) {
74384bc447cShyche 		// TODO: push data or split node
74484bc447cShyche 		return status;
74584bc447cShyche 	}
74684bc447cShyche 
74784bc447cShyche 	if (status != B_OK)
74884bc447cShyche 		return status;
74984bc447cShyche 	return slot;
75084bc447cShyche }
75184bc447cShyche 
75284bc447cShyche 
75384bc447cShyche /* MakeEntries and then fill in them.
75484bc447cShyche  */
75584bc447cShyche status_t
75684bc447cShyche BTree::InsertEntries(Transaction& transaction, Path* path,
75784bc447cShyche 	btrfs_entry* entries, void** data, int num)
75884bc447cShyche {
75984bc447cShyche 	int totalLength = sizeof(btrfs_entry) * num;
76084bc447cShyche 	for (int i = 0; i < num; i++)
76184bc447cShyche 		totalLength += entries[i].Size();
76284bc447cShyche 
76384bc447cShyche 	status_t slot = MakeEntries(transaction, path, entries[0].key, num,
76484bc447cShyche 		totalLength);
76584bc447cShyche 	if (slot < B_OK)
76684bc447cShyche 		return slot;
76784bc447cShyche 
76884bc447cShyche 	uint32 upperLimit;
76984bc447cShyche 	if (slot > 0) {
77084bc447cShyche 		path->GetEntry(slot - 1, NULL, NULL, NULL, &upperLimit);
77184bc447cShyche 	} else
77284bc447cShyche 		upperLimit = fVolume->BlockSize() - sizeof(btrfs_header);
77384bc447cShyche 
77484bc447cShyche 	TRACE("BTree::InsertEntries() num: %i upper limit %" B_PRIu32 "\n", num,
77584bc447cShyche 		upperLimit);
77684bc447cShyche 	for (int i = 0; i < num; i++) {
77784bc447cShyche 		upperLimit -= entries[i].Size();
77884bc447cShyche 		entries[i].SetOffset(upperLimit);
77984bc447cShyche 		path->SetEntry(slot + i, entries[i], data[i]);
78084bc447cShyche 	}
78184bc447cShyche 
78284bc447cShyche 	return B_OK;
78384bc447cShyche }
78484bc447cShyche 
78584bc447cShyche 
78620185bb9Shyche /* Like MakeEntries, but here we remove entries instead.
78720185bb9Shyche  * Removed data stored in _data
78820185bb9Shyche  * May merge those functions into one.
78920185bb9Shyche  */
79020185bb9Shyche status_t
79120185bb9Shyche BTree::RemoveEntries(Transaction& transaction, Path* path,
79220185bb9Shyche 	const btrfs_key& startKey, void** _data, int num)
79320185bb9Shyche {
79420185bb9Shyche 	TRACE("BTree::RemoveEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %"
79520185bb9Shyche 		B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(),
79620185bb9Shyche 		startKey.Offset());
79720185bb9Shyche 
79820185bb9Shyche 	status_t status = Traverse(BTREE_EXACT, path, startKey);
79920185bb9Shyche 	if (status < B_OK)
80020185bb9Shyche 		return status;
80120185bb9Shyche 
80220185bb9Shyche 	int slot = status;
80320185bb9Shyche 	int length = -sizeof(btrfs_entry) * num;
80420185bb9Shyche 	for (int i = 0; i < num; i++) {
80520185bb9Shyche 		uint32 itemSize;
80620185bb9Shyche 		path->GetEntry(slot + i, NULL, &_data[i], &itemSize);
80720185bb9Shyche 		length -= itemSize;
80820185bb9Shyche 	}
80920185bb9Shyche 
81020185bb9Shyche 	status = path->InternalCopy(transaction, 1);
81120185bb9Shyche 	if (status != B_OK)
81220185bb9Shyche 		return status;
81320185bb9Shyche 
81420185bb9Shyche 	status = path->CopyOnWrite(transaction, 0, slot, num, length);
81520185bb9Shyche 	if (status == B_DIRECTORY_NOT_EMPTY) {
81620185bb9Shyche 		// TODO: merge node or push data
81720185bb9Shyche 	}
81820185bb9Shyche 
81920185bb9Shyche 	return status;
82020185bb9Shyche }
82120185bb9Shyche 
82220185bb9Shyche 
8233216460dShyche status_t
8243216460dShyche BTree::PreviousLeaf(Path* path) const
8253216460dShyche {
8263216460dShyche 	// TODO: use Traverse() ???
8273216460dShyche 	int level = 0;
8283216460dShyche 	int slot;
8293216460dShyche 	Node* node = NULL;
8303216460dShyche 	// iterate to the root until satisfy the condition
8313216460dShyche 	while (true) {
8323216460dShyche 		node = path->GetNode(level, &slot);
8333216460dShyche 		if (node == NULL || slot != 0)
8343216460dShyche 			break;
8353216460dShyche 		level++;
8363216460dShyche 	}
8373216460dShyche 
8383216460dShyche 	// the current leaf is already the left most leaf or
8393216460dShyche 	// path was not initialized
8403216460dShyche 	if (node == NULL)
8413216460dShyche 		return B_ENTRY_NOT_FOUND;
8423216460dShyche 
8433216460dShyche 	path->Move(level, BTREE_BACKWARD);
8443216460dShyche 	fsblock_t physicalBlock;
8453216460dShyche 	// change all nodes below this level and slot to the ending
8463216460dShyche 	do {
8473216460dShyche 		status_t status = fVolume->FindBlock(
8483216460dShyche 			node->Index(slot)->LogicalAddress(), physicalBlock);
8493216460dShyche 		if (status != B_OK)
8503216460dShyche 			return status;
8513216460dShyche 
8523216460dShyche 		node = path->SetNode(physicalBlock, -1);
8533216460dShyche 		if (node == NULL)
8543216460dShyche 			return B_NO_MEMORY;
8553216460dShyche 		slot = node->ItemCount() - 1;
8563216460dShyche 		level--;
8573216460dShyche 	} while(level != 0);
8583216460dShyche 
8593216460dShyche 	return B_OK;
8603216460dShyche }
8613216460dShyche 
8623216460dShyche 
8633216460dShyche status_t
8643216460dShyche BTree::NextLeaf(Path* path) const
8653216460dShyche {
8663216460dShyche 	int level = 0;
8673216460dShyche 	int slot;
8683216460dShyche 	Node* node = NULL;
8693216460dShyche 	// iterate to the root until satisfy the condition
8703216460dShyche 	while (true) {
8713216460dShyche 		node = path->GetNode(level, &slot);
8723216460dShyche 		if (node == NULL || slot < node->ItemCount() - 1)
8733216460dShyche 			break;
8743216460dShyche 		level++;
8753216460dShyche 	}
8763216460dShyche 
8773216460dShyche 	// the current leaf is already the right most leaf or
8783216460dShyche 	// path was not initialized
8793216460dShyche 	if (node == NULL)
8803216460dShyche 		return B_ENTRY_NOT_FOUND;
8813216460dShyche 
8823216460dShyche 	path->Move(level, BTREE_FORWARD);
8833216460dShyche 	fsblock_t physicalBlock;
8843216460dShyche 	// change all nodes below this level and slot to the beginning
8853216460dShyche 	do {
8863216460dShyche 		status_t status = fVolume->FindBlock(
8873216460dShyche 			node->Index(slot)->LogicalAddress(), physicalBlock);
8883216460dShyche 		if (status != B_OK)
8893216460dShyche 			return status;
8903216460dShyche 
8913216460dShyche 		node = path->SetNode(physicalBlock, 0);
8923216460dShyche 		if (node == NULL)
8933216460dShyche 			return B_NO_MEMORY;
8943216460dShyche 		slot = 0;
8953216460dShyche 		level--;
8963216460dShyche 	} while(level != 0);
8973216460dShyche 
8983216460dShyche 	return B_OK;
899299aba38Shyche }
900299aba38Shyche 
901299aba38Shyche 
902883b9bf2Shyche /* Set root infomation, to use this function root must be valid and
903883b9bf2Shyche  * exists on disk.
904883b9bf2Shyche  */
905fc4a1e78Shyche status_t
906fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block)
907fc4a1e78Shyche {
908fc4a1e78Shyche 	if (block != NULL) {
909fc4a1e78Shyche 		fRootBlock = *block;
910fc4a1e78Shyche 	} else {
911fc4a1e78Shyche 		if (fVolume->FindBlock(logical, fRootBlock) != B_OK) {
912fc4a1e78Shyche 			ERROR("Find() unmapped block %" B_PRId64 "\n", fRootBlock);
913fc4a1e78Shyche 			return B_ERROR;
914fc4a1e78Shyche 		}
915fc4a1e78Shyche 	}
916883b9bf2Shyche 
917883b9bf2Shyche 	btrfs_header header;
918883b9bf2Shyche 	read_pos(fVolume->Device(), fRootBlock * fVolume->BlockSize(), &header,
919883b9bf2Shyche 		sizeof(btrfs_header));
920883b9bf2Shyche 	fRootLevel = header.Level();
921883b9bf2Shyche 	fLogicalRoot = header.LogicalAddress();
922fc4a1e78Shyche 	return B_OK;
923fc4a1e78Shyche }
924fc4a1e78Shyche 
925fc4a1e78Shyche 
926299aba38Shyche void
927883b9bf2Shyche BTree::SetRoot(Node* root)
928883b9bf2Shyche {
929883b9bf2Shyche 	fRootBlock = root->BlockNum();
930883b9bf2Shyche 	fLogicalRoot = root->LogicalAddress();
931883b9bf2Shyche 	fRootLevel = root->Level();
932883b9bf2Shyche }
933883b9bf2Shyche 
934883b9bf2Shyche 
935883b9bf2Shyche void
936299aba38Shyche BTree::_AddIterator(TreeIterator* iterator)
937299aba38Shyche {
938299aba38Shyche 	MutexLocker _(fIteratorLock);
939299aba38Shyche 	fIterators.Add(iterator);
940299aba38Shyche }
941299aba38Shyche 
942299aba38Shyche 
943299aba38Shyche void
944299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator)
945299aba38Shyche {
946299aba38Shyche 	MutexLocker _(fIteratorLock);
947299aba38Shyche 	fIterators.Remove(iterator);
948299aba38Shyche }
949299aba38Shyche 
950299aba38Shyche 
951299aba38Shyche //	#pragma mark -
952299aba38Shyche 
953299aba38Shyche 
954bfd7a4fbShyche TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key)
955299aba38Shyche 	:
956299aba38Shyche 	fTree(tree),
957bfd7a4fbShyche 	fKey(key),
958bfd7a4fbShyche 	fIteratorStatus(B_NO_INIT)
959299aba38Shyche {
960299aba38Shyche 	tree->_AddIterator(this);
961bfd7a4fbShyche 	fPath = new(std::nothrow) BTree::Path(tree);
962bfd7a4fbShyche 	if (fPath == NULL)
963bfd7a4fbShyche 		fIteratorStatus = B_NO_MEMORY;
964299aba38Shyche }
965299aba38Shyche 
966299aba38Shyche 
967299aba38Shyche TreeIterator::~TreeIterator()
968299aba38Shyche {
969299aba38Shyche 	if (fTree)
970299aba38Shyche 		fTree->_RemoveIterator(this);
971bfd7a4fbShyche 
972bfd7a4fbShyche 	delete fPath;
973bfd7a4fbShyche 	fPath = NULL;
974bfd7a4fbShyche }
975bfd7a4fbShyche 
976bfd7a4fbShyche 
977bfd7a4fbShyche void
978bfd7a4fbShyche TreeIterator::Rewind(bool inverse)
979bfd7a4fbShyche {
980bfd7a4fbShyche 	if (inverse)
981bfd7a4fbShyche 		fKey.SetOffset(BTREE_END);
982bfd7a4fbShyche 	else
983bfd7a4fbShyche 		fKey.SetOffset(BTREE_BEGIN);
984bfd7a4fbShyche 	fIteratorStatus = B_NO_INIT;
985299aba38Shyche }
986299aba38Shyche 
987299aba38Shyche 
988299aba38Shyche /*!	Iterates through the tree in the specified direction.
989299aba38Shyche */
990299aba38Shyche status_t
991bfd7a4fbShyche TreeIterator::_Traverse(btree_traversing direction)
992299aba38Shyche {
993bfd7a4fbShyche 	status_t status = fTree->Traverse(direction, fPath, fKey);
994bfd7a4fbShyche 	if (status < B_OK) {
995bfd7a4fbShyche 		ERROR("TreeIterator::Traverse() Find failed\n");
996bfd7a4fbShyche 		return status;
997299aba38Shyche 	}
998299aba38Shyche 
999bfd7a4fbShyche 	return (fIteratorStatus = B_OK);
1000bfd7a4fbShyche }
1001bfd7a4fbShyche 
1002bfd7a4fbShyche 
1003bfd7a4fbShyche // Like GetEntry in BTree::Path but here we check the type and moving.
1004bfd7a4fbShyche status_t
1005bfd7a4fbShyche TreeIterator::_GetEntry(btree_traversing type, void** _value, uint32* _size,
1006bfd7a4fbShyche 	uint32* _offset)
1007bfd7a4fbShyche {
1008bfd7a4fbShyche 	status_t status;
1009bfd7a4fbShyche 	if (fIteratorStatus == B_NO_INIT) {
1010bfd7a4fbShyche 		status = _Traverse(type);
1011bfd7a4fbShyche 		if (status != B_OK)
1012bfd7a4fbShyche 			return status;
1013bfd7a4fbShyche 		type = BTREE_EXACT;
1014bfd7a4fbShyche 	}
1015bfd7a4fbShyche 
1016bfd7a4fbShyche 	if (fIteratorStatus != B_OK)
1017bfd7a4fbShyche 		return fIteratorStatus;
1018bfd7a4fbShyche 
1019bfd7a4fbShyche 	int move = fPath->Move(0, type);
1020bfd7a4fbShyche 	if (move > 0)
1021bfd7a4fbShyche 		status = fTree->NextLeaf(fPath);
1022bfd7a4fbShyche 	else if (move < 0)
1023bfd7a4fbShyche 		status = fTree->PreviousLeaf(fPath);
1024bfd7a4fbShyche 	if (status != B_OK)
1025bfd7a4fbShyche 		return status;
1026bfd7a4fbShyche 
1027bfd7a4fbShyche 	btrfs_key found;
1028bfd7a4fbShyche 	status = fPath->GetCurrentEntry(&found, _value, _size, _offset);
1029bfd7a4fbShyche 	if (status != B_OK)
1030bfd7a4fbShyche 		return status;
1031bfd7a4fbShyche 
1032bfd7a4fbShyche 	fKey.SetObjectID(found.ObjectID());
1033bfd7a4fbShyche 	fKey.SetOffset(found.Offset());
1034bfd7a4fbShyche 	if (fKey.Type() != found.Type() && fKey.Type() != BTRFS_KEY_TYPE_ANY)
1035bfd7a4fbShyche 		return B_ENTRY_NOT_FOUND;
1036bfd7a4fbShyche 
1037299aba38Shyche 	return B_OK;
1038299aba38Shyche }
1039299aba38Shyche 
1040299aba38Shyche 
1041299aba38Shyche /*!	just sets the current key in the iterator.
1042299aba38Shyche */
1043299aba38Shyche status_t
1044bfd7a4fbShyche TreeIterator::Find(const btrfs_key& key)
1045299aba38Shyche {
1046bfd7a4fbShyche 	if (fIteratorStatus == B_INTERRUPTED)
1047bfd7a4fbShyche 		return fIteratorStatus;
1048bfd7a4fbShyche 
1049bfd7a4fbShyche 	fKey = key;
1050bfd7a4fbShyche 	fIteratorStatus = B_NO_INIT;
1051299aba38Shyche 	return B_OK;
1052299aba38Shyche }
1053299aba38Shyche 
1054299aba38Shyche 
1055299aba38Shyche void
1056299aba38Shyche TreeIterator::Stop()
1057299aba38Shyche {
1058299aba38Shyche 	fTree = NULL;
1059bfd7a4fbShyche 	fIteratorStatus = B_INTERRUPTED;
1060299aba38Shyche }
1061