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 1552850062SAugustin Cavalier #include <algorithm> 1652850062SAugustin 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 128b568492fShyche if (type == BTREE_BACKWARD && comp < 0) 129b568492fShyche mid--; 130b568492fShyche else if (type == BTREE_FORWARD && comp > 0) 131b568492fShyche mid++; 1322ed88a48Shyche 133b568492fShyche if (type == BTREE_EXACT || mid < 0) 1342ed88a48Shyche return B_ENTRY_NOT_FOUND; 1352ed88a48Shyche 136b568492fShyche *slot = mid; 1370d726c5cShyche TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n", 1380d726c5cShyche *slot, comp); 1390d726c5cShyche return B_OK; 14091d7f850Shyche } 14191d7f850Shyche 14291d7f850Shyche 14327ffe058Shyche /* 14427ffe058Shyche * calculate used space except the header. 14527ffe058Shyche * type is only for leaf node 14627ffe058Shyche * type 1: only item space 14727ffe058Shyche * type 2: only item data space 14827ffe058Shyche * type 3: both type 1 and 2 14927ffe058Shyche */ 15027ffe058Shyche int 15127ffe058Shyche BTree::Node::_CalculateSpace(uint32 from, uint32 to, uint8 type) const 15227ffe058Shyche { 15327ffe058Shyche if (to < from || to >= ItemCount()) 15427ffe058Shyche return 0; 15527ffe058Shyche 15627ffe058Shyche if (Level() != 0) 15727ffe058Shyche return sizeof(btrfs_index) * (to - from + 1); 15827ffe058Shyche 15927ffe058Shyche uint32 result = 0; 16027ffe058Shyche if ((type & 1) == 1) { 16127ffe058Shyche result += sizeof(btrfs_entry) * (to - from + 1); 16227ffe058Shyche } 16327ffe058Shyche if ((type & 2) == 2) { 16427ffe058Shyche result += Item(from)->Offset() + Item(from)->Size() 16527ffe058Shyche - Item(to)->Offset(); 16627ffe058Shyche } 16727ffe058Shyche 16827ffe058Shyche return result; 16927ffe058Shyche } 17027ffe058Shyche 17127ffe058Shyche 17227ffe058Shyche int 17327ffe058Shyche BTree::Node::SpaceUsed() const 17427ffe058Shyche { 17527ffe058Shyche if (Level() == 0) 17627ffe058Shyche return _CalculateSpace(0, ItemCount() - 1, 3); 17727ffe058Shyche return _CalculateSpace(0, ItemCount() - 1, 0); 17827ffe058Shyche } 17927ffe058Shyche 18027ffe058Shyche 18127ffe058Shyche int 18227ffe058Shyche BTree::Node::SpaceLeft() const 18327ffe058Shyche { 18427ffe058Shyche return fVolume->BlockSize() - SpaceUsed() - sizeof(btrfs_header); 18527ffe058Shyche } 18627ffe058Shyche 18727ffe058Shyche 18889484dc0Shyche void 18989484dc0Shyche BTree::Node::_Copy(const Node* origin, uint32 at, uint32 from, uint32 to, 19089484dc0Shyche int length) const 19189484dc0Shyche { 19289484dc0Shyche TRACE("Node::_Copy() at: %d from: %d to: %d length: %d\n", 19389484dc0Shyche at, from, to, length); 19489484dc0Shyche 19589484dc0Shyche if (Level() == 0) { 19689484dc0Shyche memcpy(Item(at), origin->Item(from), origin->_CalculateSpace(from, to)); 19789484dc0Shyche // Item offset of copied node must be changed to get the 19889484dc0Shyche // item data offset correctly. length can be zero 19989484dc0Shyche // but let it there doesn't harm anything. 20089484dc0Shyche for (uint32 i = at; i - at <= to - from; ++i) 20189484dc0Shyche Item(i)->SetOffset(Item(i)->Offset() - length); 20289484dc0Shyche 20389484dc0Shyche memcpy(ItemData(at + to - from), origin->ItemData(to), 20489484dc0Shyche origin->_CalculateSpace(from, to, 2)); 20589484dc0Shyche } else { 20689484dc0Shyche memcpy(Index(at), origin->Index(from), 20789484dc0Shyche origin->_CalculateSpace(from, to)); 20889484dc0Shyche } 20989484dc0Shyche } 21089484dc0Shyche 21189484dc0Shyche 21227ffe058Shyche status_t 21327ffe058Shyche BTree::Node::_SpaceCheck(int length) const 21427ffe058Shyche { 21527ffe058Shyche // this is a little bit weird here because we can't find 21627ffe058Shyche // any suitable error code 21727ffe058Shyche if (length < 0 && std::abs(length) >= SpaceUsed()) 21827ffe058Shyche return B_DIRECTORY_NOT_EMPTY; // not enough data to delete 21927ffe058Shyche if (length > 0 && length >= SpaceLeft()) 22027ffe058Shyche return B_DEVICE_FULL; // no spare space 22127ffe058Shyche return B_OK; 22227ffe058Shyche } 22327ffe058Shyche 22427ffe058Shyche 22589484dc0Shyche /* 22689484dc0Shyche * copy node header, items and items data 22789484dc0Shyche * length is size to insert/remove 22889484dc0Shyche * if node is a internal node, length isnt used 22989484dc0Shyche * length = 0: Copy a whole 23089484dc0Shyche * length < 0: removing 23189484dc0Shyche * length > 0: inserting 23289484dc0Shyche */ 23389484dc0Shyche status_t 23489484dc0Shyche BTree::Node::Copy(const Node* origin, uint32 start, uint32 end, int length) 23589484dc0Shyche const 23689484dc0Shyche { 23789484dc0Shyche status_t status = origin->_SpaceCheck(length); 23889484dc0Shyche if (status != B_OK) 23989484dc0Shyche return status; 24089484dc0Shyche 24189484dc0Shyche memcpy(fNode, origin->fNode, sizeof(btrfs_header)); 24289484dc0Shyche if (length == 0) { 24389484dc0Shyche // like removing [0, start - 1] and keeping [start, end] 24489484dc0Shyche length = -origin->_CalculateSpace(0, start - 1, 2); 24589484dc0Shyche _Copy(origin, 0, start, end, length); 24689484dc0Shyche } else if (length < 0) { 24789484dc0Shyche //removing all items in [start, end] 24889484dc0Shyche if (start > 0) 24989484dc0Shyche _Copy(origin, 0, 0, start - 1, 0); // <-- [start,... 25089484dc0Shyche if (end + 1 < origin->ItemCount()) { 25189484dc0Shyche // ..., end] --> 25289484dc0Shyche // we only care data size 25389484dc0Shyche length += origin->_CalculateSpace(start, end); 25489484dc0Shyche _Copy(origin, start, end + 1, origin->ItemCount() - 1, length); 25589484dc0Shyche } 25689484dc0Shyche } else { 25789484dc0Shyche //inserting in [start, end] - make a hole for later 25889484dc0Shyche if (start > 0) 25989484dc0Shyche _Copy(origin, 0, 0, start - 1, 0); 26089484dc0Shyche if (start < origin->ItemCount()) { 26189484dc0Shyche length -= origin->_CalculateSpace(start, end); 26289484dc0Shyche _Copy(origin, end + 1, start, origin->ItemCount() - 1, length); 26389484dc0Shyche } 26489484dc0Shyche } 26589484dc0Shyche 26689484dc0Shyche return B_OK; 26789484dc0Shyche } 26889484dc0Shyche 26989484dc0Shyche 27089484dc0Shyche /* Like copy but here we use memmove on current node. 27189484dc0Shyche */ 27289484dc0Shyche status_t 27389484dc0Shyche BTree::Node::MoveEntries(uint32 start, uint32 end, int length) const 27489484dc0Shyche { 27589484dc0Shyche status_t status = _SpaceCheck(length); 27689484dc0Shyche if (status != B_OK || length == 0/*B_OK*/) 27789484dc0Shyche return status; 27889484dc0Shyche 27989484dc0Shyche int entrySize = sizeof(btrfs_entry); 28089484dc0Shyche if (Level() != 0) 28189484dc0Shyche entrySize = sizeof(btrfs_index); 28289484dc0Shyche 28389484dc0Shyche uint8* base = (uint8*)fNode + sizeof(btrfs_header); 28489484dc0Shyche end++; 28589484dc0Shyche if (length < 0) { 28689484dc0Shyche // removing [start, end] 28789484dc0Shyche TRACE("Node::MoveEntries() removing ... start %" B_PRIu32 " end %" 28889484dc0Shyche B_PRIu32 " length %i\n", start, end, length); 28989484dc0Shyche length += _CalculateSpace(start, end - 1); 29089484dc0Shyche } else { 29189484dc0Shyche // length > 0 29289484dc0Shyche // inserting into [start, end] - make room for later 29389484dc0Shyche TRACE("Node::MoveEntries() inserting ... start %" B_PRIu32 " end %" 29489484dc0Shyche B_PRIu32 " length %i\n", start, end, length); 29589484dc0Shyche length -= _CalculateSpace(start, end - 1); 29689484dc0Shyche std::swap(start, end); 29789484dc0Shyche } 29889484dc0Shyche 29989484dc0Shyche if (end >= ItemCount()) 30089484dc0Shyche return B_OK; 30189484dc0Shyche 30289484dc0Shyche int dataSize = _CalculateSpace(end, ItemCount() - 1, 2); 30389484dc0Shyche // moving items/block pointers 30489484dc0Shyche memmove(base + start * entrySize, base + end * entrySize, 30589484dc0Shyche _CalculateSpace(end, ItemCount() - 1)); 30689484dc0Shyche if (Level() == 0) { 30789484dc0Shyche // moving item data 30889484dc0Shyche int num = start - end; 30989484dc0Shyche for(uint32 i = start; i < ItemCount() + num; ++i) 31089484dc0Shyche Item(i)->SetOffset(Item(i)->Offset() - length); 31189484dc0Shyche 31289484dc0Shyche memmove(ItemData(ItemCount() - 1) - length, ItemData(ItemCount() - 1), 31389484dc0Shyche dataSize); 31489484dc0Shyche } 31589484dc0Shyche 31689484dc0Shyche return B_OK; 31789484dc0Shyche } 31889484dc0Shyche 31989484dc0Shyche 3203216460dShyche // #pragma mark - BTree::Path implementation 3213216460dShyche 3223216460dShyche 3233216460dShyche BTree::Path::Path(BTree* tree) 3243216460dShyche : 3253216460dShyche fTree(tree) 3263216460dShyche { 3273216460dShyche for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) { 3283216460dShyche fNodes[i] = NULL; 3293216460dShyche fSlots[i] = 0; 3303216460dShyche } 3313216460dShyche } 3323216460dShyche 3333216460dShyche 3343216460dShyche BTree::Path::~Path() 3353216460dShyche { 3363216460dShyche for (int i = 0; i < BTRFS_MAX_TREE_DEPTH; ++i) { 3373216460dShyche delete fNodes[i]; 3383216460dShyche fNodes[i] = NULL; 3393216460dShyche fSlots[i] = 0; 3403216460dShyche } 3413216460dShyche } 3423216460dShyche 3433216460dShyche 3443216460dShyche BTree::Node* 3453216460dShyche BTree::Path::GetNode(int level, int* _slot) const 3463216460dShyche { 3473216460dShyche if (_slot != NULL) 3483216460dShyche *_slot = fSlots[level]; 3493216460dShyche return fNodes[level]; 3503216460dShyche } 3513216460dShyche 3523216460dShyche 3533216460dShyche BTree::Node* 3543216460dShyche BTree::Path::SetNode(off_t block, int slot) 3553216460dShyche { 3563216460dShyche Node node(fTree->SystemVolume(), block); 3573216460dShyche return SetNode(&node, slot); 3583216460dShyche } 3593216460dShyche 3603216460dShyche 3613216460dShyche BTree::Node* 3623216460dShyche BTree::Path::SetNode(const Node* node, int slot) 3633216460dShyche { 3643216460dShyche uint8 level = node->Level(); 3653216460dShyche if (fNodes[level] == NULL) { 3663216460dShyche fNodes[level] = new Node(fTree->SystemVolume(), node->BlockNum()); 3673216460dShyche if (fNodes[level] == NULL) 3683216460dShyche return NULL; 3693216460dShyche } else 3703216460dShyche fNodes[level]->SetTo(node->BlockNum()); 3713216460dShyche 3723216460dShyche if (slot == -1) 3733216460dShyche fSlots[level] = fNodes[level]->ItemCount() - 1; 3743216460dShyche else 3753216460dShyche fSlots[level] = slot; 3763216460dShyche return fNodes[level]; 3773216460dShyche } 3783216460dShyche 3793216460dShyche 3803216460dShyche int 3813216460dShyche BTree::Path::Move(int level, int step) 3823216460dShyche { 3833216460dShyche fSlots[level] += step; 3843216460dShyche if (fSlots[level] < 0) 3853216460dShyche return -1; 3863216460dShyche if (fSlots[level] >= fNodes[level]->ItemCount()) 3873216460dShyche return 1; 3883216460dShyche return 0; 3893216460dShyche } 3903216460dShyche 3913216460dShyche 3923216460dShyche status_t 3933216460dShyche BTree::Path::GetEntry(int slot, btrfs_key* _key, void** _value, uint32* _size, 3943216460dShyche uint32* _offset) 3953216460dShyche { 3963216460dShyche BTree::Node* leaf = fNodes[0]; 3973216460dShyche if (slot < 0 || slot >= leaf->ItemCount()) 3983216460dShyche return B_ENTRY_NOT_FOUND; 3993216460dShyche 4003216460dShyche if (_key != NULL) 4013216460dShyche *_key = leaf->Item(slot)->key; 4023216460dShyche 4033216460dShyche uint32 itemSize = leaf->Item(slot)->Size(); 4043216460dShyche if (_value != NULL) { 4053216460dShyche *_value = malloc(itemSize); 4063216460dShyche if (*_value == NULL) 4073216460dShyche return B_NO_MEMORY; 4083216460dShyche 4093216460dShyche memcpy(*_value, leaf->ItemData(slot), itemSize); 4103216460dShyche } 4113216460dShyche 4123216460dShyche if (_size != NULL) 4133216460dShyche *_size = itemSize; 4143216460dShyche 4153216460dShyche if (_offset != NULL) 4163216460dShyche *_offset = leaf->Item(slot)->Offset(); 4173216460dShyche 4183216460dShyche return B_OK; 4193216460dShyche } 4203216460dShyche 4213216460dShyche 42284bc447cShyche status_t 42384bc447cShyche BTree::Path::SetEntry(int slot, const btrfs_entry& entry, void* value) 42484bc447cShyche { 42584bc447cShyche if (slot < 0) 42684bc447cShyche return B_ENTRY_NOT_FOUND; 42784bc447cShyche 42884bc447cShyche memcpy(fNodes[0]->Item(slot), &entry, sizeof(btrfs_entry)); 42984bc447cShyche memcpy(fNodes[0]->ItemData(slot), value, entry.Size()); 43084bc447cShyche return B_OK; 43184bc447cShyche } 43284bc447cShyche 43384bc447cShyche 434883b9bf2Shyche /* 435883b9bf2Shyche * Allocate and copy block and do all the changes that it can. 436883b9bf2Shyche * for now, we only copy-on-write tree block, 437883b9bf2Shyche * file data is "nocow" by default. 438883b9bf2Shyche * 439883b9bf2Shyche * o parent o 440883b9bf2Shyche * | ===> \ 441883b9bf2Shyche * o x o 442883b9bf2Shyche */ 443883b9bf2Shyche status_t 444883b9bf2Shyche BTree::Path::CopyOnWrite(Transaction& transaction, int level, uint32 start, 445883b9bf2Shyche int num, int length) 446883b9bf2Shyche { 447883b9bf2Shyche Node* node = fNodes[level]; 448883b9bf2Shyche if (node == NULL) 449883b9bf2Shyche return B_BAD_VALUE; 450883b9bf2Shyche 451883b9bf2Shyche status_t status; 452883b9bf2Shyche if (transaction.HasBlock(node->BlockNum())) { 453883b9bf2Shyche // cow-ed block can not be cow-ed again 454883b9bf2Shyche status = node->MoveEntries(start, start + num - 1, length); 455883b9bf2Shyche if (status != B_OK) 456883b9bf2Shyche return status; 457883b9bf2Shyche 458883b9bf2Shyche node->SetGeneration(transaction.SystemID()); 459883b9bf2Shyche if (length < 0) 460883b9bf2Shyche node->SetItemCount(node->ItemCount() - num); 461883b9bf2Shyche else if (length > 0) 462883b9bf2Shyche node->SetItemCount(node->ItemCount() + num); 463883b9bf2Shyche 464883b9bf2Shyche return B_OK; 465883b9bf2Shyche } 466883b9bf2Shyche 467883b9bf2Shyche uint64 address; 468883b9bf2Shyche fsblock_t block; 469883b9bf2Shyche status = fTree->SystemVolume()->GetNewBlock(address, block); 470883b9bf2Shyche if (status != B_OK) 471883b9bf2Shyche return status; 472883b9bf2Shyche 473883b9bf2Shyche fNodes[level] = new(std::nothrow) BTree::Node(fTree->SystemVolume()); 474883b9bf2Shyche if (fNodes[level] == NULL) 475883b9bf2Shyche return B_NO_MEMORY; 476883b9bf2Shyche 477883b9bf2Shyche fNodes[level]->SetToWritable(block, transaction.ID(), true); 478883b9bf2Shyche 479883b9bf2Shyche status = fNodes[level]->Copy(node, start, start + num - 1, length); 480883b9bf2Shyche if (status != B_OK) 481883b9bf2Shyche return status; 482883b9bf2Shyche 483883b9bf2Shyche fNodes[level]->SetGeneration(transaction.SystemID()); 484883b9bf2Shyche fNodes[level]->SetLogicalAddress(address); 485883b9bf2Shyche if (length < 0) 486883b9bf2Shyche fNodes[level]->SetItemCount(node->ItemCount() - num); 487883b9bf2Shyche else if (length > 0) 488883b9bf2Shyche fNodes[level]->SetItemCount(node->ItemCount() + num); 489883b9bf2Shyche else 490883b9bf2Shyche fNodes[level]->SetItemCount(num); 491883b9bf2Shyche 492883b9bf2Shyche // change pointer of this node in parent 493883b9bf2Shyche int parentSlot; 494883b9bf2Shyche Node* parentNode = GetNode(level + 1, &parentSlot); 495883b9bf2Shyche if (parentNode != NULL) 496883b9bf2Shyche parentNode->Index(parentSlot)->SetLogicalAddress(address); 497883b9bf2Shyche 498883b9bf2Shyche if (level == fTree->RootLevel()) 499883b9bf2Shyche fTree->SetRoot(fNodes[level]); 500883b9bf2Shyche 501883b9bf2Shyche delete node; 502883b9bf2Shyche return B_OK; 503883b9bf2Shyche } 504883b9bf2Shyche 505883b9bf2Shyche 506883b9bf2Shyche /* Copy-On-Write all internal nodes start from a specific level. 507883b9bf2Shyche * level > 0: to root 508883b9bf2Shyche * level <= 0: to leaf 509883b9bf2Shyche * 510883b9bf2Shyche * path cow-path path cow-path 511883b9bf2Shyche * ================================================= 512883b9bf2Shyche * root cow-root root level < 0 513883b9bf2Shyche * | | | 514883b9bf2Shyche * n1 cow-n1 ...______ 515883b9bf2Shyche * | | | \ 516883b9bf2Shyche * n2 cow-n2 n1 cow-n1 517883b9bf2Shyche * | / | | 518883b9bf2Shyche * ...____/ n2 cow-n2 519883b9bf2Shyche * | | | 520883b9bf2Shyche * leaf level > 0 leaf cow-leaf 521883b9bf2Shyche */ 522883b9bf2Shyche status_t 523883b9bf2Shyche BTree::Path::InternalCopy(Transaction& transaction, int level) 524883b9bf2Shyche { 525883b9bf2Shyche if (std::abs(level) >= fTree->RootLevel()) 526883b9bf2Shyche return B_OK; 527883b9bf2Shyche 528883b9bf2Shyche TRACE("Path::InternalCopy() level %i\n", level); 529883b9bf2Shyche int from, to; 530883b9bf2Shyche if (level > 0) { 531883b9bf2Shyche from = level; 532883b9bf2Shyche to = fTree->RootLevel(); 533883b9bf2Shyche } else { 534883b9bf2Shyche from = 0; 535883b9bf2Shyche to = std::abs(level); 536883b9bf2Shyche } 537883b9bf2Shyche 538883b9bf2Shyche Node* node = NULL; 539883b9bf2Shyche status_t status; 540883b9bf2Shyche while (from <= to) { 541883b9bf2Shyche node = fNodes[from]; 542883b9bf2Shyche status = CopyOnWrite(transaction, from, 0, node->ItemCount(), 0); 543883b9bf2Shyche from++; 544883b9bf2Shyche if (status != B_OK) 545883b9bf2Shyche return status; 546883b9bf2Shyche } 547883b9bf2Shyche 548883b9bf2Shyche return B_OK; 549883b9bf2Shyche } 550883b9bf2Shyche 551883b9bf2Shyche 5523216460dShyche // #pragma mark - BTree implementation 5531481c49cShyche 5541481c49cShyche 555fc4a1e78Shyche BTree::BTree(Volume* volume) 556fc4a1e78Shyche : 557fc4a1e78Shyche fRootBlock(0), 558883b9bf2Shyche fRootLevel(0), 559fc4a1e78Shyche fVolume(volume) 560fc4a1e78Shyche { 561fc4a1e78Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 562fc4a1e78Shyche } 563fc4a1e78Shyche 564fc4a1e78Shyche 565299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream) 566299aba38Shyche : 567299aba38Shyche fRootBlock(0), 568883b9bf2Shyche fRootLevel(0), 569299aba38Shyche fVolume(volume) 570299aba38Shyche { 571299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 572299aba38Shyche } 573299aba38Shyche 574299aba38Shyche 575299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock) 576299aba38Shyche : 577299aba38Shyche fRootBlock(rootBlock), 578299aba38Shyche fVolume(volume) 579299aba38Shyche { 580299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 581299aba38Shyche } 582299aba38Shyche 583299aba38Shyche 584299aba38Shyche BTree::~BTree() 585299aba38Shyche { 586299aba38Shyche // if there are any TreeIterators left, we need to stop them 587299aba38Shyche // (can happen when the tree's inode gets deleted while 588299aba38Shyche // traversing the tree - a TreeIterator doesn't lock the inode) 589299aba38Shyche mutex_lock(&fIteratorLock); 590299aba38Shyche 591299aba38Shyche SinglyLinkedList<TreeIterator>::Iterator iterator 592299aba38Shyche = fIterators.GetIterator(); 593299aba38Shyche while (iterator.HasNext()) 594299aba38Shyche iterator.Next()->Stop(); 595299aba38Shyche mutex_destroy(&fIteratorLock); 596299aba38Shyche } 597299aba38Shyche 598299aba38Shyche 599299aba38Shyche int32 600875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const 601299aba38Shyche { 602875a0552Shyche if (ObjectID() > key.ObjectID()) 603299aba38Shyche return 1; 604875a0552Shyche if (ObjectID() < key.ObjectID()) 605299aba38Shyche return -1; 606875a0552Shyche if (Type() > key.Type()) 607299aba38Shyche return 1; 608875a0552Shyche if (Type() < key.Type()) 609299aba38Shyche return -1; 610875a0552Shyche if (Offset() > key.Offset()) 611299aba38Shyche return 1; 612875a0552Shyche if (Offset() < key.Offset()) 613299aba38Shyche return -1; 614299aba38Shyche return 0; 615299aba38Shyche } 616299aba38Shyche 617299aba38Shyche 6183216460dShyche /* Traverse from root to fill in the path along way its finding. 6193216460dShyche * Return current slot at leaf if successful. 6203216460dShyche */ 6213216460dShyche status_t 6223216460dShyche BTree::Traverse(btree_traversing type, Path* path, const btrfs_key& key) 6233216460dShyche const 6243216460dShyche { 6253216460dShyche TRACE("BTree::Traverse() objectid %" B_PRId64 " type %d offset %" 6263216460dShyche B_PRId64 " \n", key.ObjectID(), key.Type(), key.Offset()); 6273216460dShyche fsblock_t physicalBlock = fRootBlock; 6283216460dShyche Node node(fVolume, physicalBlock); 6293216460dShyche int slot; 6303216460dShyche status_t status = B_OK; 6313216460dShyche 6323216460dShyche while (node.Level() != 0) { 6333216460dShyche TRACE("BTree::Traverse() level %d count %d\n", node.Level(), 6343216460dShyche node.ItemCount()); 6353216460dShyche status = node.SearchSlot(key, &slot, BTREE_BACKWARD); 6363216460dShyche if (status != B_OK) 6373216460dShyche return status; 6383216460dShyche if (path->SetNode(&node, slot) == NULL) 6393216460dShyche return B_NO_MEMORY; 6403216460dShyche 6413216460dShyche TRACE("BTree::Traverse() getting index %" B_PRIu32 "\n", slot); 6423216460dShyche 6433216460dShyche status = fVolume->FindBlock(node.Index(slot)->LogicalAddress(), 6443216460dShyche physicalBlock); 6453216460dShyche if (status != B_OK) { 6463216460dShyche ERROR("BTree::Traverse() unmapped block %" B_PRId64 "\n", 6473216460dShyche node.Index(slot)->LogicalAddress()); 6483216460dShyche return status; 6493216460dShyche } 6503216460dShyche node.SetTo(physicalBlock); 6513216460dShyche } 6523216460dShyche 6533216460dShyche TRACE("BTree::Traverse() dump count %" B_PRId32 "\n", node.ItemCount()); 6543216460dShyche status = node.SearchSlot(key, &slot, type); 6553216460dShyche if (status != B_OK) 6563216460dShyche return status; 6573216460dShyche if (path->SetNode(&node, slot) == NULL) 6583216460dShyche return B_NO_MEMORY; 6593216460dShyche 6603216460dShyche TRACE("BTree::Traverse() found %" B_PRIu32 " %" B_PRIu32 "\n", 6613216460dShyche node.Item(slot)->Offset(), node.Item(slot)->Size()); 6623216460dShyche return slot; 6633216460dShyche } 6643216460dShyche 6653216460dShyche 666299aba38Shyche /*! Searches the key in the tree, and stores the allocated found item in 667299aba38Shyche _value, if successful. 668299aba38Shyche Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not. 669299aba38Shyche It can also return other errors to indicate that something went wrong. 670299aba38Shyche */ 671299aba38Shyche status_t 6723216460dShyche BTree::_Find(Path* path, btrfs_key& wanted, void** _value, uint32* _size, 6733216460dShyche uint32* _offset, btree_traversing type) const 674299aba38Shyche { 6753216460dShyche status_t status = Traverse(type, path, wanted); 6763216460dShyche if (status < B_OK) 6773216460dShyche return status; 678299aba38Shyche 6793216460dShyche btrfs_key found; 6803216460dShyche status = path->GetCurrentEntry(&found, _value, _size, _offset); 6813216460dShyche if (status != B_OK) 6823216460dShyche return status; 683299aba38Shyche 684*690d16c6Shyche if (found.Type() != wanted.Type() && wanted.Type() != BTRFS_KEY_TYPE_ANY) { 685*690d16c6Shyche ERROR("Find() not found wanted: %" B_PRIu64 " %" B_PRIu8 " %" 686*690d16c6Shyche B_PRIu64 " found: %" B_PRIu64 " %" B_PRIu8 " %" B_PRIu64 "\n", 687*690d16c6Shyche wanted.ObjectID(), wanted.Type(), wanted.Offset(), found.ObjectID(), 688*690d16c6Shyche found.Type(), found.Offset()); 68946eba5c0Shyche return B_ENTRY_NOT_FOUND; 690*690d16c6Shyche } 691299aba38Shyche 6923216460dShyche wanted = found; 693299aba38Shyche return B_OK; 694299aba38Shyche } 695299aba38Shyche 696299aba38Shyche 69746eba5c0Shyche status_t 6983216460dShyche BTree::FindNext(Path* path, btrfs_key& key, void** _value, uint32* _size, 6993216460dShyche uint32* _offset) const 70046eba5c0Shyche { 7013216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_FORWARD); 702299aba38Shyche } 703299aba38Shyche 704299aba38Shyche 705299aba38Shyche status_t 7063216460dShyche BTree::FindPrevious(Path* path, btrfs_key& key, void** _value, uint32* _size, 7073216460dShyche uint32* _offset) const 708299aba38Shyche { 7093216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_BACKWARD); 710299aba38Shyche } 711299aba38Shyche 712299aba38Shyche 713299aba38Shyche status_t 7143216460dShyche BTree::FindExact(Path* path, btrfs_key& key, void** _value, uint32* _size, 7153216460dShyche uint32* _offset) const 716299aba38Shyche { 7173216460dShyche return _Find(path, key, _value, _size, _offset, BTREE_EXACT); 7183216460dShyche } 7193216460dShyche 7203216460dShyche 72184bc447cShyche /* 72284bc447cShyche * Insert "num" of consecutive empty entries start with slot of "startKey" 72384bc447cShyche * if successful return the starting slot, otherwise return error code. 72484bc447cShyche */ 72584bc447cShyche status_t 72684bc447cShyche BTree::MakeEntries(Transaction& transaction, Path* path, 72784bc447cShyche const btrfs_key& startKey, int num, int length) 72884bc447cShyche { 72984bc447cShyche TRACE("BTree::MakeEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %" 73084bc447cShyche B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(), 73184bc447cShyche startKey.Offset()); 73284bc447cShyche 73384bc447cShyche status_t status = Traverse(BTREE_FORWARD, path, startKey); 73484bc447cShyche if (status < B_OK) 73584bc447cShyche return status; 73684bc447cShyche 73784bc447cShyche int slot = status; 73884bc447cShyche status = path->InternalCopy(transaction, 1); 73984bc447cShyche if (status != B_OK) 74084bc447cShyche return status; 74184bc447cShyche 74284bc447cShyche status = path->CopyOnWrite(transaction, 0, slot, num, length); 74384bc447cShyche if (status == B_DEVICE_FULL) { 74484bc447cShyche // TODO: push data or split node 74584bc447cShyche return status; 74684bc447cShyche } 74784bc447cShyche 74884bc447cShyche if (status != B_OK) 74984bc447cShyche return status; 75084bc447cShyche return slot; 75184bc447cShyche } 75284bc447cShyche 75384bc447cShyche 75484bc447cShyche /* MakeEntries and then fill in them. 75584bc447cShyche */ 75684bc447cShyche status_t 75784bc447cShyche BTree::InsertEntries(Transaction& transaction, Path* path, 75884bc447cShyche btrfs_entry* entries, void** data, int num) 75984bc447cShyche { 76084bc447cShyche int totalLength = sizeof(btrfs_entry) * num; 76184bc447cShyche for (int i = 0; i < num; i++) 76284bc447cShyche totalLength += entries[i].Size(); 76384bc447cShyche 76484bc447cShyche status_t slot = MakeEntries(transaction, path, entries[0].key, num, 76584bc447cShyche totalLength); 76684bc447cShyche if (slot < B_OK) 76784bc447cShyche return slot; 76884bc447cShyche 76984bc447cShyche uint32 upperLimit; 77084bc447cShyche if (slot > 0) { 77184bc447cShyche path->GetEntry(slot - 1, NULL, NULL, NULL, &upperLimit); 77284bc447cShyche } else 77384bc447cShyche upperLimit = fVolume->BlockSize() - sizeof(btrfs_header); 77484bc447cShyche 77584bc447cShyche TRACE("BTree::InsertEntries() num: %i upper limit %" B_PRIu32 "\n", num, 77684bc447cShyche upperLimit); 77784bc447cShyche for (int i = 0; i < num; i++) { 77884bc447cShyche upperLimit -= entries[i].Size(); 77984bc447cShyche entries[i].SetOffset(upperLimit); 78084bc447cShyche path->SetEntry(slot + i, entries[i], data[i]); 78184bc447cShyche } 78284bc447cShyche 78384bc447cShyche return B_OK; 78484bc447cShyche } 78584bc447cShyche 78684bc447cShyche 78720185bb9Shyche /* Like MakeEntries, but here we remove entries instead. 78820185bb9Shyche * Removed data stored in _data 78920185bb9Shyche * May merge those functions into one. 79020185bb9Shyche */ 79120185bb9Shyche status_t 79220185bb9Shyche BTree::RemoveEntries(Transaction& transaction, Path* path, 79320185bb9Shyche const btrfs_key& startKey, void** _data, int num) 79420185bb9Shyche { 79520185bb9Shyche TRACE("BTree::RemoveEntries() num %i key (% " B_PRIu64 " %" B_PRIu8 " %" 79620185bb9Shyche B_PRIu64 ")\n", num, startKey.ObjectID(), startKey.Type(), 79720185bb9Shyche startKey.Offset()); 79820185bb9Shyche 79920185bb9Shyche status_t status = Traverse(BTREE_EXACT, path, startKey); 80020185bb9Shyche if (status < B_OK) 80120185bb9Shyche return status; 80220185bb9Shyche 80320185bb9Shyche int slot = status; 80420185bb9Shyche int length = -sizeof(btrfs_entry) * num; 80520185bb9Shyche for (int i = 0; i < num; i++) { 80620185bb9Shyche uint32 itemSize; 80720185bb9Shyche path->GetEntry(slot + i, NULL, &_data[i], &itemSize); 80820185bb9Shyche length -= itemSize; 80920185bb9Shyche } 81020185bb9Shyche 81120185bb9Shyche status = path->InternalCopy(transaction, 1); 81220185bb9Shyche if (status != B_OK) 81320185bb9Shyche return status; 81420185bb9Shyche 81520185bb9Shyche status = path->CopyOnWrite(transaction, 0, slot, num, length); 81620185bb9Shyche if (status == B_DIRECTORY_NOT_EMPTY) { 81720185bb9Shyche // TODO: merge node or push data 81820185bb9Shyche } 81920185bb9Shyche 82020185bb9Shyche return status; 82120185bb9Shyche } 82220185bb9Shyche 82320185bb9Shyche 8243216460dShyche status_t 8253216460dShyche BTree::PreviousLeaf(Path* path) const 8263216460dShyche { 8273216460dShyche // TODO: use Traverse() ??? 8283216460dShyche int level = 0; 8293216460dShyche int slot; 8303216460dShyche Node* node = NULL; 8313216460dShyche // iterate to the root until satisfy the condition 8323216460dShyche while (true) { 8333216460dShyche node = path->GetNode(level, &slot); 8343216460dShyche if (node == NULL || slot != 0) 8353216460dShyche break; 8363216460dShyche level++; 8373216460dShyche } 8383216460dShyche 8393216460dShyche // the current leaf is already the left most leaf or 8403216460dShyche // path was not initialized 8413216460dShyche if (node == NULL) 8423216460dShyche return B_ENTRY_NOT_FOUND; 8433216460dShyche 8443216460dShyche path->Move(level, BTREE_BACKWARD); 8453216460dShyche fsblock_t physicalBlock; 8463216460dShyche // change all nodes below this level and slot to the ending 8473216460dShyche do { 8483216460dShyche status_t status = fVolume->FindBlock( 8493216460dShyche node->Index(slot)->LogicalAddress(), physicalBlock); 8503216460dShyche if (status != B_OK) 8513216460dShyche return status; 8523216460dShyche 8533216460dShyche node = path->SetNode(physicalBlock, -1); 8543216460dShyche if (node == NULL) 8553216460dShyche return B_NO_MEMORY; 8563216460dShyche slot = node->ItemCount() - 1; 8573216460dShyche level--; 8583216460dShyche } while(level != 0); 8593216460dShyche 8603216460dShyche return B_OK; 8613216460dShyche } 8623216460dShyche 8633216460dShyche 8643216460dShyche status_t 8653216460dShyche BTree::NextLeaf(Path* path) const 8663216460dShyche { 8673216460dShyche int level = 0; 8683216460dShyche int slot; 8693216460dShyche Node* node = NULL; 8703216460dShyche // iterate to the root until satisfy the condition 8713216460dShyche while (true) { 8723216460dShyche node = path->GetNode(level, &slot); 8733216460dShyche if (node == NULL || slot < node->ItemCount() - 1) 8743216460dShyche break; 8753216460dShyche level++; 8763216460dShyche } 8773216460dShyche 8783216460dShyche // the current leaf is already the right most leaf or 8793216460dShyche // path was not initialized 8803216460dShyche if (node == NULL) 8813216460dShyche return B_ENTRY_NOT_FOUND; 8823216460dShyche 8833216460dShyche path->Move(level, BTREE_FORWARD); 8843216460dShyche fsblock_t physicalBlock; 8853216460dShyche // change all nodes below this level and slot to the beginning 8863216460dShyche do { 8873216460dShyche status_t status = fVolume->FindBlock( 8883216460dShyche node->Index(slot)->LogicalAddress(), physicalBlock); 8893216460dShyche if (status != B_OK) 8903216460dShyche return status; 8913216460dShyche 8923216460dShyche node = path->SetNode(physicalBlock, 0); 8933216460dShyche if (node == NULL) 8943216460dShyche return B_NO_MEMORY; 8953216460dShyche slot = 0; 8963216460dShyche level--; 8973216460dShyche } while(level != 0); 8983216460dShyche 8993216460dShyche return B_OK; 900299aba38Shyche } 901299aba38Shyche 902299aba38Shyche 903883b9bf2Shyche /* Set root infomation, to use this function root must be valid and 904883b9bf2Shyche * exists on disk. 905883b9bf2Shyche */ 906fc4a1e78Shyche status_t 907fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block) 908fc4a1e78Shyche { 909fc4a1e78Shyche if (block != NULL) { 910fc4a1e78Shyche fRootBlock = *block; 911fc4a1e78Shyche } else { 912fc4a1e78Shyche if (fVolume->FindBlock(logical, fRootBlock) != B_OK) { 913ce029df2Shyche ERROR("SetRoot() unmapped block %" B_PRId64 " %" B_PRId64 "\n", 914ce029df2Shyche logical, fRootBlock); 915fc4a1e78Shyche return B_ERROR; 916fc4a1e78Shyche } 917fc4a1e78Shyche } 918883b9bf2Shyche 919883b9bf2Shyche btrfs_header header; 920883b9bf2Shyche read_pos(fVolume->Device(), fRootBlock * fVolume->BlockSize(), &header, 921883b9bf2Shyche sizeof(btrfs_header)); 922883b9bf2Shyche fRootLevel = header.Level(); 923883b9bf2Shyche fLogicalRoot = header.LogicalAddress(); 924fc4a1e78Shyche return B_OK; 925fc4a1e78Shyche } 926fc4a1e78Shyche 927fc4a1e78Shyche 928299aba38Shyche void 929883b9bf2Shyche BTree::SetRoot(Node* root) 930883b9bf2Shyche { 931883b9bf2Shyche fRootBlock = root->BlockNum(); 932883b9bf2Shyche fLogicalRoot = root->LogicalAddress(); 933883b9bf2Shyche fRootLevel = root->Level(); 934883b9bf2Shyche } 935883b9bf2Shyche 936883b9bf2Shyche 937883b9bf2Shyche void 938299aba38Shyche BTree::_AddIterator(TreeIterator* iterator) 939299aba38Shyche { 940299aba38Shyche MutexLocker _(fIteratorLock); 941299aba38Shyche fIterators.Add(iterator); 942299aba38Shyche } 943299aba38Shyche 944299aba38Shyche 945299aba38Shyche void 946299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator) 947299aba38Shyche { 948299aba38Shyche MutexLocker _(fIteratorLock); 949299aba38Shyche fIterators.Remove(iterator); 950299aba38Shyche } 951299aba38Shyche 952299aba38Shyche 953299aba38Shyche // #pragma mark - 954299aba38Shyche 955299aba38Shyche 956bfd7a4fbShyche TreeIterator::TreeIterator(BTree* tree, const btrfs_key& key) 957299aba38Shyche : 958299aba38Shyche fTree(tree), 959bfd7a4fbShyche fKey(key), 960bfd7a4fbShyche fIteratorStatus(B_NO_INIT) 961299aba38Shyche { 962299aba38Shyche tree->_AddIterator(this); 963bfd7a4fbShyche fPath = new(std::nothrow) BTree::Path(tree); 964bfd7a4fbShyche if (fPath == NULL) 965bfd7a4fbShyche fIteratorStatus = B_NO_MEMORY; 966299aba38Shyche } 967299aba38Shyche 968299aba38Shyche 969299aba38Shyche TreeIterator::~TreeIterator() 970299aba38Shyche { 971299aba38Shyche if (fTree) 972299aba38Shyche fTree->_RemoveIterator(this); 973bfd7a4fbShyche 974bfd7a4fbShyche delete fPath; 975bfd7a4fbShyche fPath = NULL; 976bfd7a4fbShyche } 977bfd7a4fbShyche 978bfd7a4fbShyche 979bfd7a4fbShyche void 980bfd7a4fbShyche TreeIterator::Rewind(bool inverse) 981bfd7a4fbShyche { 982bfd7a4fbShyche if (inverse) 983bfd7a4fbShyche fKey.SetOffset(BTREE_END); 984bfd7a4fbShyche else 985bfd7a4fbShyche fKey.SetOffset(BTREE_BEGIN); 986bfd7a4fbShyche fIteratorStatus = B_NO_INIT; 987299aba38Shyche } 988299aba38Shyche 989299aba38Shyche 990299aba38Shyche /*! Iterates through the tree in the specified direction. 991299aba38Shyche */ 992299aba38Shyche status_t 993bfd7a4fbShyche TreeIterator::_Traverse(btree_traversing direction) 994299aba38Shyche { 995bfd7a4fbShyche status_t status = fTree->Traverse(direction, fPath, fKey); 996bfd7a4fbShyche if (status < B_OK) { 997bfd7a4fbShyche ERROR("TreeIterator::Traverse() Find failed\n"); 998bfd7a4fbShyche return status; 999299aba38Shyche } 1000299aba38Shyche 1001bfd7a4fbShyche return (fIteratorStatus = B_OK); 1002bfd7a4fbShyche } 1003bfd7a4fbShyche 1004bfd7a4fbShyche 1005bfd7a4fbShyche // Like GetEntry in BTree::Path but here we check the type and moving. 1006bfd7a4fbShyche status_t 1007bfd7a4fbShyche TreeIterator::_GetEntry(btree_traversing type, void** _value, uint32* _size, 1008bfd7a4fbShyche uint32* _offset) 1009bfd7a4fbShyche { 10105686d4e1Shyche status_t status = B_OK; 1011bfd7a4fbShyche if (fIteratorStatus == B_NO_INIT) { 1012bfd7a4fbShyche status = _Traverse(type); 1013bfd7a4fbShyche if (status != B_OK) 1014bfd7a4fbShyche return status; 1015bfd7a4fbShyche type = BTREE_EXACT; 1016bfd7a4fbShyche } 1017bfd7a4fbShyche 1018bfd7a4fbShyche if (fIteratorStatus != B_OK) 1019bfd7a4fbShyche return fIteratorStatus; 1020bfd7a4fbShyche 1021bfd7a4fbShyche int move = fPath->Move(0, type); 1022bfd7a4fbShyche if (move > 0) 1023bfd7a4fbShyche status = fTree->NextLeaf(fPath); 1024bfd7a4fbShyche else if (move < 0) 1025bfd7a4fbShyche status = fTree->PreviousLeaf(fPath); 1026bfd7a4fbShyche if (status != B_OK) 1027bfd7a4fbShyche return status; 1028bfd7a4fbShyche 1029bfd7a4fbShyche btrfs_key found; 1030bfd7a4fbShyche status = fPath->GetCurrentEntry(&found, _value, _size, _offset); 1031bfd7a4fbShyche if (status != B_OK) 1032bfd7a4fbShyche return status; 1033bfd7a4fbShyche 1034bfd7a4fbShyche fKey.SetObjectID(found.ObjectID()); 1035bfd7a4fbShyche fKey.SetOffset(found.Offset()); 1036bfd7a4fbShyche if (fKey.Type() != found.Type() && fKey.Type() != BTRFS_KEY_TYPE_ANY) 1037bfd7a4fbShyche return B_ENTRY_NOT_FOUND; 1038bfd7a4fbShyche 1039299aba38Shyche return B_OK; 1040299aba38Shyche } 1041299aba38Shyche 1042299aba38Shyche 1043299aba38Shyche /*! just sets the current key in the iterator. 1044299aba38Shyche */ 1045299aba38Shyche status_t 1046bfd7a4fbShyche TreeIterator::Find(const btrfs_key& key) 1047299aba38Shyche { 1048bfd7a4fbShyche if (fIteratorStatus == B_INTERRUPTED) 1049bfd7a4fbShyche return fIteratorStatus; 1050bfd7a4fbShyche 1051bfd7a4fbShyche fKey = key; 1052bfd7a4fbShyche fIteratorStatus = B_NO_INIT; 1053299aba38Shyche return B_OK; 1054299aba38Shyche } 1055299aba38Shyche 1056299aba38Shyche 1057299aba38Shyche void 1058299aba38Shyche TreeIterator::Stop() 1059299aba38Shyche { 1060299aba38Shyche fTree = NULL; 1061bfd7a4fbShyche fIteratorStatus = B_INTERRUPTED; 1062299aba38Shyche } 1063