diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp index 9e43ad808d..6b3c17c563 100644 --- a/src/add-ons/kernel/file_systems/btrfs/BTree.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/BTree.cpp @@ -185,6 +185,30 @@ BTree::Node::SpaceLeft() const } +void +BTree::Node::_Copy(const Node* origin, uint32 at, uint32 from, uint32 to, + int length) const +{ + TRACE("Node::_Copy() at: %d from: %d to: %d length: %d\n", + at, from, to, length); + + if (Level() == 0) { + memcpy(Item(at), origin->Item(from), origin->_CalculateSpace(from, to)); + // Item offset of copied node must be changed to get the + // item data offset correctly. length can be zero + // but let it there doesn't harm anything. + for (uint32 i = at; i - at <= to - from; ++i) + Item(i)->SetOffset(Item(i)->Offset() - length); + + memcpy(ItemData(at + to - from), origin->ItemData(to), + origin->_CalculateSpace(from, to, 2)); + } else { + memcpy(Index(at), origin->Index(from), + origin->_CalculateSpace(from, to)); + } +} + + status_t BTree::Node::_SpaceCheck(int length) const { @@ -198,6 +222,101 @@ BTree::Node::_SpaceCheck(int length) const } +/* + * copy node header, items and items data + * length is size to insert/remove + * if node is a internal node, length isnt used + * length = 0: Copy a whole + * length < 0: removing + * length > 0: inserting + */ +status_t +BTree::Node::Copy(const Node* origin, uint32 start, uint32 end, int length) + const +{ + status_t status = origin->_SpaceCheck(length); + if (status != B_OK) + return status; + + memcpy(fNode, origin->fNode, sizeof(btrfs_header)); + if (length == 0) { + // like removing [0, start - 1] and keeping [start, end] + length = -origin->_CalculateSpace(0, start - 1, 2); + _Copy(origin, 0, start, end, length); + } else if (length < 0) { + //removing all items in [start, end] + if (start > 0) + _Copy(origin, 0, 0, start - 1, 0); // <-- [start,... + if (end + 1 < origin->ItemCount()) { + // ..., end] --> + // we only care data size + length += origin->_CalculateSpace(start, end); + _Copy(origin, start, end + 1, origin->ItemCount() - 1, length); + } + } else { + //inserting in [start, end] - make a hole for later + if (start > 0) + _Copy(origin, 0, 0, start - 1, 0); + if (start < origin->ItemCount()) { + length -= origin->_CalculateSpace(start, end); + _Copy(origin, end + 1, start, origin->ItemCount() - 1, length); + } + } + + return B_OK; +} + + +/* Like copy but here we use memmove on current node. + */ +status_t +BTree::Node::MoveEntries(uint32 start, uint32 end, int length) const +{ + status_t status = _SpaceCheck(length); + if (status != B_OK || length == 0/*B_OK*/) + return status; + + int entrySize = sizeof(btrfs_entry); + if (Level() != 0) + entrySize = sizeof(btrfs_index); + + uint8* base = (uint8*)fNode + sizeof(btrfs_header); + end++; + if (length < 0) { + // removing [start, end] + TRACE("Node::MoveEntries() removing ... start %" B_PRIu32 " end %" + B_PRIu32 " length %i\n", start, end, length); + length += _CalculateSpace(start, end - 1); + } else { + // length > 0 + // inserting into [start, end] - make room for later + TRACE("Node::MoveEntries() inserting ... start %" B_PRIu32 " end %" + B_PRIu32 " length %i\n", start, end, length); + length -= _CalculateSpace(start, end - 1); + std::swap(start, end); + } + + if (end >= ItemCount()) + return B_OK; + + int dataSize = _CalculateSpace(end, ItemCount() - 1, 2); + // moving items/block pointers + memmove(base + start * entrySize, base + end * entrySize, + _CalculateSpace(end, ItemCount() - 1)); + if (Level() == 0) { + // moving item data + int num = start - end; + for(uint32 i = start; i < ItemCount() + num; ++i) + Item(i)->SetOffset(Item(i)->Offset() - length); + + memmove(ItemData(ItemCount() - 1) - length, ItemData(ItemCount() - 1), + dataSize); + } + + return B_OK; +} + + // #pragma mark - BTree::Path implementation diff --git a/src/add-ons/kernel/file_systems/btrfs/BTree.h b/src/add-ons/kernel/file_systems/btrfs/BTree.h index f1c0e5b83f..14e675c1b5 100644 --- a/src/add-ons/kernel/file_systems/btrfs/BTree.h +++ b/src/add-ons/kernel/file_systems/btrfs/BTree.h @@ -133,6 +133,9 @@ public: off_t BlockNum() const { return fBlockNumber;} bool IsWritable() const { return fWritable; } + status_t Copy(const Node* origin, uint32 start, uint32 end, + int length) const; + status_t MoveEntries(uint32 start, uint32 end, int length) const; status_t SearchSlot(const btrfs_key& key, int* slot, btree_traversing type) const; @@ -141,6 +144,8 @@ public: Node& operator=(const Node&); //no implementation + void _Copy(const Node* origin, uint32 at, uint32 from, uint32 to, + int length) const; status_t _SpaceCheck(int length) const; int _CalculateSpace(uint32 from, uint32 to, uint8 type = 1) const; diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs.h b/src/add-ons/kernel/file_systems/btrfs/btrfs.h index 59f58e230d..f2010b91fb 100644 --- a/src/add-ons/kernel/file_systems/btrfs/btrfs.h +++ b/src/add-ons/kernel/file_systems/btrfs/btrfs.h @@ -132,6 +132,7 @@ struct btrfs_entry { { return B_LENDIAN_TO_HOST_INT32(offset); } uint32 Size() const { return B_LENDIAN_TO_HOST_INT32(size); } + void SetOffset(uint32 off) { offset = B_HOST_TO_LENDIAN_INT32(off); } } _PACKED;