2 // lf_hfs_btree_tree_ops.c
5 // Created by Yakov Ben Zaken on 22/03/2018.
8 #include "lf_hfs_btrees_private.h"
9 #include "lf_hfs_btrees_io.h"
10 #include "lf_hfs_utils.h"
11 #include "lf_hfs_generic_buf.h"
13 /////////////////////// Routines Internal To BTree Module ///////////////////////
18 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
20 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
22 NodeDescPtr rightNode
);
24 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
25 BlockDescriptor
*blockPtr
);
27 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
29 NodeDescPtr rightNode
,
30 u_int16_t rightInsertIndex
,
34 u_int16_t
*insertIndex
,
35 u_int32_t
*insertNodeNum
,
37 u_int16_t
*recsRotated
);
39 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
41 NodeDescPtr rightNode
);
43 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
44 BlockDescriptor
*leftNode
,
45 BlockDescriptor
*rightNode
,
46 u_int32_t rightNodeNum
,
51 u_int16_t
*insertIndex
,
52 u_int32_t
*insertNodeNum
,
53 u_int16_t
*recsRotated
);
57 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
58 TreePathTable treePathTable
,
59 InsertKey
*primaryKey
,
60 InsertKey
*secondaryKey
,
61 BlockDescriptor
*targetNode
,
64 u_int32_t
*insertNode
);
66 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
68 BlockDescriptor
*rightNode
,
73 BlockDescriptor
*leftNode
,
74 Boolean
*updateParent
,
75 Boolean
*insertParent
,
78 static u_int16_t
GetKeyLength (const BTreeControlBlock
*btreePtr
,
80 Boolean forLeafNode
);
84 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
87 /*-------------------------------------------------------------------------------
89 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
91 Function: Searches BTree for specified key, setting up the Tree Path Table to
92 reflect the search path.
95 Input: btreePtr - pointer to control block of BTree to search
96 keyPtr - pointer to the key to search for
97 treePathTable - pointer to the tree path table to construct
99 Output: nodeNum - number of the node containing the key position
100 iterator - BTreeIterator specifying record or insert position
102 Result: noErr - key found, index is record index
103 fsBTRecordNotFoundErr - key not found, index is insert index
104 fsBTEmptyErr - key not found, return params are nil
105 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
106 -------------------------------------------------------------------------------*/
108 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
109 BTreeKeyPtr searchKey
,
110 TreePathTable treePathTable
,
112 BlockDescriptor
*nodePtr
,
113 u_int16_t
*returnIndex
)
116 int16_t level
; // Expected depth of current node
117 u_int32_t curNodeNum
; // Current node we're searching
121 int8_t nodeKind
; // Kind of current node (index/leaf)
127 curNodeNum
= btreePtr
->rootNode
;
128 level
= btreePtr
->treeDepth
;
130 if (level
== 0) // is the tree empty?
137 treePathTable
[0].node
= 0;
138 treePathTable
[0].index
= 0;
143 // [2550929] Node number 0 is the header node. It is never a valid
144 // index or leaf node. If we're ever asked to search through node 0,
145 // something has gone wrong (typically a bad child node number, or
146 // we found a node full of zeroes that we thought was an index node).
150 LFHFS_LOG(LEVEL_ERROR
, "SearchTree: curNodeNum is zero!");
155 err
= GetNode (btreePtr
, curNodeNum
, 0, &nodeRec
);
158 LFHFS_LOG(LEVEL_ERROR
, "SearchTree: GetNode returned with error %d!",err
);
163 // [2550929] Sanity check the node height and node type. We expect
164 // particular values at each iteration in the search. This checking
165 // quickly finds bad pointers, loops, and other damage to the
166 // hierarchy of the B-tree.
168 if (((BTNodeDescriptor
*)nodeRec
.buffer
)->height
!= level
)
170 LFHFS_LOG(LEVEL_ERROR
, "Incorrect node height");
174 nodeKind
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
;
177 // Nodes at level 1 must be leaves, by definition
178 if (nodeKind
!= kBTLeafNode
)
180 LFHFS_LOG(LEVEL_ERROR
, "Incorrect node type: expected leaf");
187 // A node at any other depth must be an index node
188 if (nodeKind
!= kBTIndexNode
)
190 LFHFS_LOG(LEVEL_ERROR
, "Incorrect node type: expected index");
196 keyFound
= SearchNode (btreePtr
, nodeRec
.buffer
, searchKey
, &index
);
198 treePathTable
[level
].node
= curNodeNum
;
200 if (nodeKind
== kBTLeafNode
)
202 treePathTable
[level
].index
= index
;
203 break; // were done...
206 if ( (keyFound
!= true) && (index
!= 0))
209 treePathTable
[level
].index
= index
;
211 err
= GetRecordByIndex (btreePtr
, nodeRec
.buffer
, index
, &keyPtr
, &dataPtr
, &dataSize
);
214 // [2550929] If we got an error, it is probably because the index was bad
215 // (typically a corrupt node that confused SearchNode). Invalidate the node
216 // so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9
217 // sources call this InvalidateNode.
218 LFHFS_LOG(LEVEL_ERROR
, "SearchTree: GetRecordByIndex returned with errpr %d!",err
);
220 (void) TrashNode(btreePtr
, &nodeRec
);
224 // Get the child pointer out of this index node. We're now done with the current
225 // node and can continue the search with the child node.
226 curNodeNum
= *(u_int32_t
*)dataPtr
;
227 err
= ReleaseNode (btreePtr
, &nodeRec
);
230 LFHFS_LOG(LEVEL_ERROR
, "SearchTree: ReleaseNode returned with errpr %d!",err
);
234 // The child node should be at a level one less than the parent.
238 *nodeNum
= curNodeNum
;
240 *returnIndex
= index
;
243 return noErr
; // searchKey found, index identifies record in node
245 return fsBTRecordNotFoundErr
; // searchKey not found, index identifies insert point
248 (void) ReleaseNode(btreePtr
, &nodeRec
);
249 // fall into ErrorExit
254 nodePtr
->buffer
= nil
;
255 nodePtr
->blockHeader
= nil
;
260 ////////////////////////////////// InsertTree ///////////////////////////////////
262 OSStatus
InsertTree ( BTreeControlBlockPtr btreePtr
,
263 TreePathTable treePathTable
,
267 BlockDescriptor
*targetNode
,
270 Boolean replacingKey
,
271 u_int32_t
*insertNode
)
273 InsertKey primaryKey
;
276 primaryKey
.keyPtr
= keyPtr
;
277 primaryKey
.keyLength
= GetKeyLength(btreePtr
, primaryKey
.keyPtr
, (level
== 1));
278 primaryKey
.recPtr
= recPtr
;
279 primaryKey
.recSize
= recSize
;
280 primaryKey
.replacingKey
= replacingKey
;
281 primaryKey
.skipRotate
= false;
283 err
= InsertLevel (btreePtr
, treePathTable
, &primaryKey
, nil
,
284 targetNode
, index
, level
, insertNode
);
288 } // End of InsertTree
291 ////////////////////////////////// InsertLevel //////////////////////////////////
293 OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
294 TreePathTable treePathTable
,
295 InsertKey
*primaryKey
,
296 InsertKey
*secondaryKey
,
297 BlockDescriptor
*targetNode
,
300 u_int32_t
*insertNode
)
303 BlockDescriptor leftNode
;
304 u_int32_t targetNodeNum
;
305 u_int32_t newNodeNum
;
307 Boolean insertParent
;
308 Boolean updateParent
;
312 #if defined(applec) && !defined(__SC__)
313 if ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
))
315 LFHFS_LOG(LEVEL_ERROR
, " InsertLevel: non-leaf at level 1! ");
319 leftNode
.buffer
= nil
;
320 leftNode
.blockHeader
= nil
;
321 targetNodeNum
= treePathTable
[level
].node
;
323 insertParent
= false;
324 updateParent
= false;
327 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
329 ////// process first insert //////
331 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
332 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &newRoot
);
337 // Extend the treePathTable by adding an entry for the new
338 // root node that references the current targetNode.
340 // If inserting the secondaryKey changes the first key of
341 // the target node, then we'll have to update the second
342 // key in the new root node.
344 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
345 treePathTable
[level
+ 1].index
= 1; // 1 since we always split/rotate left
349 *insertNode
= newNodeNum
;
351 ////// process second insert (if any) //////
353 if ( secondaryKey
!= nil
)
357 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
,
358 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &temp
);
362 //////////////////////// Update Parent(s) ///////////////////////////////
364 if ( insertParent
|| updateParent
)
366 BlockDescriptor parentNode
;
367 u_int32_t parentNodeNum
;
372 parentNode
.buffer
= nil
;
373 parentNode
.blockHeader
= nil
;
377 if (level
== btreePtr
->treeDepth
)
379 LFHFS_LOG(LEVEL_ERROR
, " InsertLevel: unfinished insert!?");
384 // Get Parent Node data...
385 index
= treePathTable
[level
].index
;
386 parentNodeNum
= treePathTable
[level
].node
;
388 if (parentNodeNum
== 0)
390 LFHFS_LOG(LEVEL_ERROR
, " InsertLevel: parent node is zero!?");
394 err
= GetNode (btreePtr
, parentNodeNum
, 0, &parentNode
); // released as target node in next level up
396 ////////////////////////// Update Parent Index //////////////////////////////
401 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
403 // debug: check if ptr == targetNodeNum
404 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
405 if ((*(u_int32_t
*) recPtr
) != targetNodeNum
)
407 LFHFS_LOG(LEVEL_ERROR
, " InsertLevel: parent ptr doesn't match target node!");
411 // need to delete and re-insert this parent key/ptr
412 // we delete it here and it gets re-inserted in the
413 // InsertLevel call below.
414 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
416 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
417 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
418 primaryKey
->recPtr
= (u_int8_t
*) &targetNodeNum
;
419 primaryKey
->recSize
= sizeof(targetNodeNum
);
420 primaryKey
->replacingKey
= kReplaceRecord
;
421 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
424 ////////////////////////// Add New Parent Index /////////////////////////////
428 InsertKey
*insertKeyPtr
;
432 insertKeyPtr
= &insertKey
;
433 secondaryKey
= &insertKey
;
437 insertKeyPtr
= primaryKey
;
440 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
.buffer
, 0);
441 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
442 insertKeyPtr
->recPtr
= (u_int8_t
*) &((NodeDescPtr
)targetNode
->buffer
)->bLink
;
443 insertKeyPtr
->recSize
= sizeof(u_int32_t
);
444 insertKeyPtr
->replacingKey
= kInsertRecord
;
445 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
448 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
449 &parentNode
, index
, level
, insertNode
);
453 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
); // all done with target
456 err
= UpdateNode (btreePtr
, &leftNode
, 0, kLockTransaction
); // all done with left sibling
463 (void) ReleaseNode (btreePtr
, targetNode
);
464 (void) ReleaseNode (btreePtr
, &leftNode
);
466 LFHFS_LOG(LEVEL_ERROR
, " InsertLevel: an error occurred!");
470 } // End of InsertLevel
474 ////////////////////////////////// InsertNode ///////////////////////////////////
476 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
479 BlockDescriptor
*rightNode
,
486 BlockDescriptor
*leftNode
,
487 Boolean
*updateParent
,
488 Boolean
*insertParent
,
491 BlockDescriptor
*targetNode
= NULL
;
492 u_int32_t leftNodeNum
;
493 u_int16_t recsRotated
;
499 if (rightNode
->buffer
== leftNode
->buffer
)
501 LFHFS_LOG(LEVEL_ERROR
, " InsertNode: rightNode == leftNode");
505 leftNodeNum
= ((NodeDescPtr
) rightNode
->buffer
)->bLink
;
508 /////////////////////// Try Simple Insert ///////////////////////////////
510 /* sanity check our left and right nodes here. */
511 if (node
== leftNodeNum
) {
512 if (leftNode
->buffer
== NULL
) {
513 err
= fsBTInvalidNodeErr
;
517 targetNode
= leftNode
;
521 // we can assume right node is initialized.
522 targetNode
= rightNode
;
526 recordFit
= InsertKeyRecord (btreePtr
, targetNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
533 if ( (index
== 0) && (((NodeDescPtr
) targetNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
534 *updateParent
= true; // the first record changed so we need to update the parent
538 //////////////////////// Try Rotate Left ////////////////////////////////
540 if ( !recordFit
&& leftNodeNum
> 0 )
542 if (leftNode
->buffer
!= nil
)
544 LFHFS_LOG(LEVEL_ERROR
, " InsertNode: leftNode already acquired!");
548 if ( leftNode
->buffer
== nil
)
550 err
= GetNode (btreePtr
, leftNodeNum
, 0, leftNode
); // will be released by caller or a split below
553 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
556 if (((NodeDescPtr
) leftNode
->buffer
)->fLink
!= node
)
558 LFHFS_LOG(LEVEL_ERROR
, " InsertNode, RotateLeft: invalid sibling link!");
562 if ( !key
->skipRotate
) // are rotates allowed?
564 err
= RotateLeft (btreePtr
, leftNode
->buffer
, rightNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
565 key
->recSize
, newIndex
, newNode
, &recordFit
, &recsRotated
);
570 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
571 *updateParent
= true;
577 //////////////////////// Try Split Left /////////////////////////////////
581 // might not have left node...
582 err
= SplitLeft (btreePtr
, leftNode
, rightNode
, node
, index
, key
->keyPtr
,
583 key
->recPtr
, key
->recSize
, newIndex
, newNode
, &recsRotated
);
586 // if we split root node - add new root
588 if ( ((NodeDescPtr
) rightNode
->buffer
)->height
== btreePtr
->treeDepth
)
590 err
= AddNewRootNode (btreePtr
, leftNode
->buffer
, rightNode
->buffer
); // Note: does not update TPT
596 *insertParent
= true;
598 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
599 *updateParent
= true;
606 (void) ReleaseNode (btreePtr
, leftNode
);
609 } // End of InsertNode
612 /*-------------------------------------------------------------------------------
613 Routine: DeleteTree - One_line_description.
615 Function: Brief_description_of_the_function_and_any_side_effects
619 Input: btreePtr - description
620 treePathTable - description
621 targetNode - description
624 Result: noErr - success
626 -------------------------------------------------------------------------------*/
628 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
629 TreePathTable treePathTable
,
630 BlockDescriptor
*targetNode
,
635 BlockDescriptor parentNode
;
636 BTNodeDescriptor
*targetNodePtr
;
637 u_int32_t targetNodeNum
;
638 Boolean deleteRequired
;
639 Boolean updateRequired
;
641 // XXXdbg - initialize these to null in case we get an
642 // error and try to exit before it's initialized
643 parentNode
.buffer
= nil
;
644 parentNode
.blockHeader
= nil
;
646 deleteRequired
= false;
647 updateRequired
= false;
649 targetNodeNum
= treePathTable
[level
].node
;
650 targetNodePtr
= targetNode
->buffer
;
651 if (targetNodePtr
== nil
)
653 LFHFS_LOG(LEVEL_ERROR
, "DeleteTree: targetNode has nil buffer!");
658 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
660 DeleteRecord (btreePtr
, targetNodePtr
, index
);
662 //coalesce remaining records?
664 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
666 BlockDescriptor siblingNode
;
667 u_int32_t siblingNodeNum
;
669 deleteRequired
= true;
671 siblingNode
.buffer
= nil
;
672 siblingNode
.blockHeader
= nil
;
674 ////////////////// Get Siblings & Update Links //////////////////////////
676 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
677 if ( siblingNodeNum
!= 0 )
679 err
= GetNode (btreePtr
, siblingNodeNum
, 0, &siblingNode
);
683 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
685 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
686 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
689 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update firstLeafNode
691 btreePtr
->firstLeafNode
= targetNodePtr
->fLink
;
694 siblingNodeNum
= targetNodePtr
->fLink
; // Right Sibling Node
695 if ( siblingNodeNum
!= 0 )
697 err
= GetNode (btreePtr
, siblingNodeNum
, 0, &siblingNode
);
701 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
703 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
704 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
707 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
709 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
712 //////////////////////// Free Empty Node ////////////////////////////////
714 GenericLFBuf
*psBuf
= targetNode
->blockHeader
;
715 lf_hfs_generic_buf_set_cache_flag(psBuf
, GEN_BUF_LITTLE_ENDIAN
);
716 ClearNode (btreePtr
, targetNodePtr
);
718 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
721 err
= FreeNode (btreePtr
, targetNodeNum
);
724 else if ( index
== 0 ) // did we delete the first record?
726 updateRequired
= true; // yes, so we need to update parent
730 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
732 deleteRequired
= false;
733 updateRequired
= false;
735 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
737 btreePtr
->rootNode
= 0;
738 btreePtr
->treeDepth
= 0;
740 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
742 err
= CollapseTree (btreePtr
, targetNode
);
748 if ( updateRequired
|| deleteRequired
)
750 ++level
; // next level
752 //// Get Parent Node and index
753 index
= treePathTable
[level
].index
;
754 err
= GetNode (btreePtr
, treePathTable
[level
].node
, 0, &parentNode
);
757 if ( updateRequired
)
762 u_int32_t insertNode
;
765 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
767 //debug: check if ptr == targetNodeNum
768 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
769 if ((*(u_int32_t
*) recPtr
) != targetNodeNum
)
771 LFHFS_LOG(LEVEL_ERROR
, " DeleteTree: parent ptr doesn't match targetNodeNum!!");
775 // need to delete and re-insert this parent key/ptr
776 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
778 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
779 recPtr
= (u_int8_t
*) &targetNodeNum
;
780 recSize
= sizeof(targetNodeNum
);
782 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
783 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
786 else // deleteRequired
788 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
794 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
801 (void) ReleaseNode (btreePtr
, targetNode
);
802 (void) ReleaseNode (btreePtr
, &parentNode
);
810 ///////////////////////////////// CollapseTree //////////////////////////////////
812 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
813 BlockDescriptor
*blockPtr
)
816 u_int32_t originalRoot
;
819 originalRoot
= btreePtr
->rootNode
;
822 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
826 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
827 break; // this will make a fine root node
829 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
830 break; // we've hit bottom
832 nodeNum
= btreePtr
->rootNode
;
833 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
834 --btreePtr
->treeDepth
;
836 //// Clear and Free Current Old Root Node ////
837 GenericLFBuf
*psBuf
= blockPtr
->blockHeader
;
838 lf_hfs_generic_buf_set_cache_flag(psBuf
, GEN_BUF_LITTLE_ENDIAN
);
839 ClearNode (btreePtr
, blockPtr
->buffer
);
840 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
);
842 err
= FreeNode (btreePtr
, nodeNum
);
845 //// Get New Root Node
846 err
= GetNode (btreePtr
, btreePtr
->rootNode
, 0, blockPtr
);
850 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
853 if (btreePtr
->rootNode
!= originalRoot
)
854 M_BTreeHeaderDirty (btreePtr
);
856 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
); // always update!
862 /////////////////////////////////// ErrorExit ///////////////////////////////////
865 (void) ReleaseNode (btreePtr
, blockPtr
);
871 ////////////////////////////////// RotateLeft ///////////////////////////////////
873 /*-------------------------------------------------------------------------------
875 Routine: RotateLeft - One_line_description.
877 Function: Brief_description_of_the_function_and_any_side_effects
879 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
881 Input: btreePtr - description
882 leftNode - description
883 rightNode - description
884 rightInsertIndex - description
887 recSize - description
890 insertNodeNum - description
891 recordFit - description
894 Result: noErr - success
896 -------------------------------------------------------------------------------*/
898 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
899 NodeDescPtr leftNode
,
900 NodeDescPtr rightNode
,
901 u_int16_t rightInsertIndex
,
905 u_int16_t
*insertIndex
,
906 u_int32_t
*insertNodeNum
,
908 u_int16_t
*recsRotated
)
913 int32_t leftSize
, rightSize
;
914 int32_t moveSize
= 0;
916 u_int16_t lengthFieldSize
;
917 u_int16_t index
, moveIndex
;
920 ///////////////////// Determine If Record Will Fit //////////////////////////
922 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
924 // the key's length field is 8-bits in HFS and 16-bits in HFS+
925 if ( btreePtr
->attributes
& kBTBigKeysMask
)
926 lengthFieldSize
= sizeof(u_int16_t
);
928 lengthFieldSize
= sizeof(u_int8_t
);
930 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(u_int16_t
);
932 if ( M_IsOdd (insertSize
) )
933 ++insertSize
; // add pad byte;
935 nodeSize
= btreePtr
->nodeSize
;
937 // add size of insert record to right node
938 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
939 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
943 while ( leftSize
< rightSize
)
945 if ( moveIndex
< rightInsertIndex
)
947 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
949 else if ( moveIndex
== rightInsertIndex
)
951 moveSize
= insertSize
;
953 else // ( moveIndex > rightInsertIndex )
955 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
958 leftSize
+= moveSize
;
959 rightSize
-= moveSize
;
963 if ( leftSize
> nodeSize
) // undo last move
965 rightSize
+= moveSize
;
969 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
979 // we've found balance point, moveIndex == number of records moved into leftNode
982 //////////////////////////// Rotate Records /////////////////////////////////
984 *recsRotated
= moveIndex
;
988 while ( index
< moveIndex
)
990 if ( index
== rightInsertIndex
) // insert new record in left node
992 u_int16_t leftInsertIndex
;
994 leftInsertIndex
= leftNode
->numRecords
;
996 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
997 keyPtr
, keyLength
, recPtr
, recSize
);
1000 LFHFS_LOG(LEVEL_ERROR
, "RotateLeft: InsertKeyRecord (left) returned false!");
1001 err
= fsBTBadRotateErr
;
1005 *insertIndex
= leftInsertIndex
;
1006 *insertNodeNum
= rightNode
->bLink
;
1010 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
1013 LFHFS_LOG(LEVEL_ERROR
, "RotateLeft: RotateRecordLeft returned false!");
1014 err
= fsBTBadRotateErr
;
1022 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
1024 rightInsertIndex
-= index
; // adjust for records already rotated
1026 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
1027 keyPtr
, keyLength
, recPtr
, recSize
);
1030 LFHFS_LOG(LEVEL_ERROR
, "RotateLeft: InsertKeyRecord (right) returned false!");
1031 err
= fsBTBadRotateErr
;
1035 *insertIndex
= rightInsertIndex
;
1036 *insertNodeNum
= leftNode
->fLink
;
1043 ////////////////////////////// Error Exit ///////////////////////////////////
1057 /////////////////////////////////// SplitLeft ///////////////////////////////////
1059 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
1060 BlockDescriptor
*leftNode
,
1061 BlockDescriptor
*rightNode
,
1062 u_int32_t rightNodeNum
,
1067 u_int16_t
*insertIndex
,
1068 u_int32_t
*insertNodeNum
,
1069 u_int16_t
*recsRotated
)
1072 NodeDescPtr left
, right
;
1073 u_int32_t newNodeNum
;
1077 ///////////////////////////// Compare Nodes /////////////////////////////////
1079 right
= rightNode
->buffer
;
1080 left
= leftNode
->buffer
;
1082 if (right
->bLink
!= 0 && left
== 0)
1084 LFHFS_LOG(LEVEL_ERROR
, " SplitLeft: left sibling missing!?" );
1087 /* type should be kBTLeafNode or kBTIndexNode */
1089 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1090 return fsBTInvalidNodeErr
;
1094 if ( left
->fLink
!= rightNodeNum
)
1095 return fsBTInvalidNodeErr
; //E_BadSibling ?
1097 if ( left
->height
!= right
->height
)
1098 return fsBTInvalidNodeErr
; //E_BadNodeHeight ?
1100 if ( left
->kind
!= right
->kind
)
1101 return fsBTInvalidNodeErr
; //E_BadNodeType ?
1105 ///////////////////////////// Allocate Node /////////////////////////////////
1107 err
= AllocateNode (btreePtr
, &newNodeNum
);
1108 M_ExitOnError (err
);
1111 /////////////// Update Forward Link In Original Left Node ///////////////////
1116 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1118 left
->fLink
= newNodeNum
;
1119 err
= UpdateNode (btreePtr
, leftNode
, 0, kLockTransaction
);
1120 M_ExitOnError (err
);
1124 /////////////////////// Initialize New Left Node ////////////////////////////
1126 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1127 M_ExitOnError (err
);
1130 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1132 left
= leftNode
->buffer
;
1133 left
->fLink
= rightNodeNum
;
1136 // Steal Info From Right Node
1138 left
->bLink
= right
->bLink
;
1139 left
->kind
= right
->kind
;
1140 left
->height
= right
->height
;
1142 right
->bLink
= newNodeNum
; // update Right bLink
1144 if ( (left
->kind
== kBTLeafNode
) && (left
->bLink
== 0) )
1146 // if we're adding a new first leaf node - update BTreeInfoRec
1148 btreePtr
->firstLeafNode
= newNodeNum
;
1149 M_BTreeHeaderDirty (btreePtr
); //AllocateNode should have set the bit already...
1152 ////////////////////////////// Rotate Left //////////////////////////////////
1154 err
= RotateLeft (btreePtr
, left
, right
, index
, keyPtr
, recPtr
, recSize
,
1155 insertIndex
, insertNodeNum
, &recordFit
, recsRotated
);
1157 M_ExitOnError (err
);
1163 (void) ReleaseNode (btreePtr
, leftNode
);
1164 (void) ReleaseNode (btreePtr
, rightNode
);
1166 //Free new node if allocated?
1177 /////////////////////////////// RotateRecordLeft ////////////////////////////////
1179 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
1180 NodeDescPtr leftNode
,
1181 NodeDescPtr rightNode
)
1187 size
= GetRecordSize (btreePtr
, rightNode
, 0);
1188 recPtr
= GetRecordAddress (btreePtr
, rightNode
, 0);
1190 recordFit
= InsertRecord (btreePtr
, leftNode
, leftNode
->numRecords
, recPtr
, size
);
1195 DeleteRecord (btreePtr
, rightNode
, 0);
1201 //////////////////////////////// AddNewRootNode /////////////////////////////////
1203 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
1204 NodeDescPtr leftNode
,
1205 NodeDescPtr rightNode
)
1208 BlockDescriptor rootNode
;
1212 u_int16_t keyLength
;
1214 rootNode
.buffer
= nil
;
1215 rootNode
.blockHeader
= nil
;
1217 if (leftNode
== nil
|| rightNode
== nil
)
1219 LFHFS_LOG(LEVEL_ERROR
, "AddNewRootNode: %s nil", (leftNode
== nil
&& rightNode
== nil
)? "left and right node are" : ((leftNode
== nil
) ? "left node is" : "right node is"));
1223 /////////////////////// Initialize New Root Node ////////////////////////////
1225 err
= AllocateNode (btreePtr
, &rootNum
);
1226 M_ExitOnError (err
);
1228 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1229 M_ExitOnError (err
);
1232 ModifyBlockStart(btreePtr
->fileRefNum
, &rootNode
);
1234 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1235 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1238 ///////////////////// Insert Left Node Index Record /////////////////////////
1240 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1241 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1243 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1244 (u_int8_t
*) &rightNode
->bLink
, 4 );
1247 LFHFS_LOG(LEVEL_ERROR
, "AddNewRootNode:InsertKeyRecord failed for left index record\n");
1251 //////////////////// Insert Right Node Index Record /////////////////////////
1253 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1254 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1256 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1257 (u_int8_t
*) &leftNode
->fLink
, 4 );
1261 LFHFS_LOG(LEVEL_ERROR
, "AddNewRootNode:InsertKeyRecord failed for right index record\n");
1265 /////////////////////////// Release Root Node ///////////////////////////////
1267 err
= UpdateNode (btreePtr
, &rootNode
, 0, kLockTransaction
);
1268 M_ExitOnError (err
);
1270 // update BTreeInfoRec
1272 btreePtr
->rootNode
= rootNum
;
1273 M_BTreeHeaderDirty(btreePtr
);
1278 ////////////////////////////// Error Exit ///////////////////////////////////
1286 static u_int16_t
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1290 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1291 length
= KeyLength (btreePtr
, key
); // just use actual key length
1293 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //shouldn't we clear the pad bytes?