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