2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 Contains: Single-node operations for the BTree Module.
30 Version: xxx put the technology version here xxx
32 Written by: Gordon Sheridan and Bill Bruffey
34 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
40 Other Contact: Mark Day
42 Technology: File Systems
49 Change History (most recent first):
51 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
52 <MOSXS> 4/113/99 djb Fix key size checking bug in CheckNode.
53 <MOSXS> 3/19/99 djb Added key size checking to CheckNode.
54 <MOSXS> 3/26/98 djb Added PrintNode for debugging.
55 <CS5> 9/4/97 djb Removed GetRightSiblingNode and GetLeftSiblingNode - they are
56 now macros. SearchNode is now in BTreeSearchNode.a.
57 <CS4> 8/22/97 djb Turn off debugging code in CheckKey.
58 <CS3> 7/24/97 djb Add summary traces for Get/Rel Node. Made GetRecordOffset into a
59 macro. Only call CheckNode if the node came from disk.
60 <CS2> 7/21/97 msd Make GetRecordByIndex check its record index input; it now
62 <CS1> 4/23/97 djb first checked in
64 <HFS3> 2/19/97 djb Changes to support big node cache.
65 <HFS2> 1/3/97 djb Added support for large keys.
66 <HFS1> 12/19/96 djb first checked in
69 History applicable to original Scarecrow Design:
71 <6> 10/25/96 ser Changing for new VFPI
72 <5> 9/17/96 dkh Add bounds checking to GetNode. Update GetNode to not assert
73 that CheckNode failed if the node is all zeroes. This can happen
74 if the hint case if the fetched node has been deallocated
75 <4> 3/7/96 dkh Change GetNewNode() to not use kGetEmptyBlock. Instead use
76 kGetBlock to fetch a block from the disk itself. \80\80\80 Why?
77 <3> 1/22/96 dkh Add #include Memory.h
78 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
79 <1> 10/18/95 rst Moved from Scarecrow project.
81 <17> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
82 <16> 1/31/95 prp GetBlockProc interface uses a 64 bit node number.
83 <15> 1/12/95 wjk Adopt Model FileSystem changes in D5.
84 <14> 9/30/94 prp Get in sync with D2 interface changes.
85 <13> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
86 <12> 7/22/94 wjk Convert to the new set of header files.
87 <11> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
89 <10> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
90 agree with their prototypes.
91 <9> 8/31/93 prp Use U64SetU instead of S64Set.
92 <8> 5/21/93 gs Maintain statistical counters on Get/Release node routines.
93 <7> 5/10/93 gs Change keySize parameter to keyLength for InsertKeyRecord
94 routine. Calculate number of bytes in key from keyLength to
95 account for length and pad bytes. Add GetChildNodeNum routine.
96 <6> 3/23/93 gs Add InsertKeyRecord routine.
97 <5> 2/8/93 gs Fix bug in SearchNode that caused "off by 1" error when final
98 compare was searchKey > trialKey. Add UpdateNode.
99 <4> 12/10/92 gs Change keyLength field of key to 'length'.
100 <3> 12/8/92 gs Incorporate suggestions from preliminary code review.
101 <2> 12/2/92 gs Implement routines.
102 <1> 11/15/92 gs Define routine interfaces.
106 #include "../headers/BTreesPrivate.h"
110 ///////////////////////// BTree Module Node Operations //////////////////////////
112 // GetNode - Call FS Agent to get node
113 // GetNewNode - Call FS Agent to get a new node
114 // ReleaseNode - Call FS Agent to release node obtained by GetNode.
115 // UpdateNode - Mark a node as dirty and call FS Agent to release it.
117 // CheckNode - Checks the validity of a node.
118 // ClearNode - Clear a node to all zeroes.
120 // InsertRecord - Inserts a record into a BTree node.
121 // InsertKeyRecord - Inserts a key and record pair into a BTree node.
122 // DeleteRecord - Deletes a record from a BTree node.
124 // SearchNode - Return index for record that matches key.
125 // LocateRecord - Return pointer to key and data, and size of data.
127 // GetNodeDataSize - Return the amount of space used for data in the node.
128 // GetNodeFreeSize - Return the amount of free space in the node.
130 // GetRecordOffset - Return the offset for record "index".
131 // GetRecordAddress - Return address of record "index".
132 // GetOffsetAddress - Return address of offset for record "index".
134 // InsertOffset - Inserts a new offset into a node.
135 // DeleteOffset - Deletes an offset from a node.
137 /////////////////////////////////////////////////////////////////////////////////
141 ////////////////////// Routines Internal To BTreeNodeOps.c //////////////////////
143 UInt16
GetRecordOffset (BTreeControlBlockPtr btree
,
147 UInt16
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
151 void InsertOffset (BTreeControlBlockPtr btreePtr
,
156 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
161 /////////////////////////////////////////////////////////////////////////////////
163 #define GetRecordOffset(btreePtr,node,index) (*(short *) ((UInt8 *)(node) + (btreePtr)->nodeSize - ((index) << 1) - kOffsetSize))
166 #include <sys/systm.h>
167 #define PRINTIT kprintf
168 #endif /* HFS_DIAGNOSTIC */
170 static void PrintNode(const NodeDescPtr node
, UInt16 nodeSize
, UInt32 nodeNumber
);
174 /*-------------------------------------------------------------------------------
176 Routine: GetNode - Call FS Agent to get node
178 Function: Gets an existing BTree node from FS Agent and verifies it.
180 Input: btreePtr - pointer to BTree control block
181 nodeNum - number of node to request
183 Output: nodePtr - pointer to beginning of node (nil if error)
188 -------------------------------------------------------------------------------*/
190 OSStatus
GetNode (BTreeControlBlockPtr btreePtr
,
195 GetBlockProcPtr getNodeProc
;
198 //\80\80 is nodeNum within proper range?
199 if( nodeNum
>= btreePtr
->totalNodes
)
201 Panic("\pGetNode:nodeNum >= totalNodes");
202 err
= fsBTInvalidNodeErr
;
206 nodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
208 getNodeProc
= btreePtr
->getBlockProc
;
209 err
= getNodeProc (btreePtr
->fileRefNum
,
216 Panic ("\pGetNode: getNodeProc returned error.");
217 // nodePtr->buffer = nil;
220 ++btreePtr
->numGetNodes
;
224 // Only call CheckNode if the node came from disk.
225 // If it was in the cache, we'll assume its already a valid node.
228 if ( nodePtr
->blockReadFromDisk
) // if we read it from disk then check it
230 err
= CheckNode (btreePtr
, nodePtr
->buffer
);
235 VTOVCB(btreePtr
->fileRefNum
)->vcbFlags
|= kHFS_DamagedVolume
;
238 if (((NodeDescPtr
)nodePtr
->buffer
)->numRecords
!= 0)
239 PrintNode(nodePtr
->buffer
, btreePtr
->nodeSize
, nodeNum
);
244 // With the removal of bounds checking in IsItAHint(), it's possible that
245 // GetNode() will be called to fetch a clear (all zeroes) node. We want
246 // CheckNode() to fail in this case (it does), however we don't want to assert
247 // this case because it is not really an "error". Returning an error from GetNode()
248 // in this case will cause the hint checking code to ignore the hint and revert to
249 // the full search mode.
255 cur
= nodePtr
->buffer
;
256 lastPlusOne
= (UInt32
*) ((UInt8
*) cur
+ btreePtr
->nodeSize
);
258 while( cur
< lastPlusOne
)
262 Panic ("\pGetNode: CheckNode returned error.");
269 (void) TrashNode (btreePtr
, nodePtr
); // ignore error
277 nodePtr
->buffer
= nil
;
278 nodePtr
->blockHeader
= nil
;
285 /*-------------------------------------------------------------------------------
287 Routine: GetNewNode - Call FS Agent to get a new node
289 Function: Gets a new BTree node from FS Agent and initializes it to an empty
292 Input: btreePtr - pointer to BTree control block
293 nodeNum - number of node to request
295 Output: returnNodePtr - pointer to beginning of node (nil if error)
297 Result: noErr - success
299 -------------------------------------------------------------------------------*/
301 OSStatus
GetNewNode (BTreeControlBlockPtr btreePtr
,
303 NodeRec
*returnNodePtr
)
308 GetBlockProcPtr getNodeProc
;
311 //////////////////////// get buffer for new node ////////////////////////////
313 returnNodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
315 getNodeProc
= btreePtr
->getBlockProc
;
316 err
= getNodeProc (btreePtr
->fileRefNum
,
318 kGetBlock
+kGetEmptyBlock
,
323 Panic ("\pGetNewNode: getNodeProc returned error.");
324 // returnNodePtr->buffer = nil;
327 ++btreePtr
->numGetNewNodes
;
330 ////////////////////////// initialize the node //////////////////////////////
332 node
= returnNodePtr
->buffer
;
334 ClearNode (btreePtr
, node
); // clear the node
336 pos
= (char *)node
+ btreePtr
->nodeSize
- 2; // find address of last offset
337 *(UInt16
*)pos
= sizeof (BTNodeDescriptor
); // set offset to beginning of free space
345 /*-------------------------------------------------------------------------------
347 Routine: ReleaseNode - Call FS Agent to release node obtained by GetNode.
349 Function: Informs the FS Agent that a BTree node may be released.
351 Input: btreePtr - pointer to BTree control block
352 nodeNum - number of node to release
354 Result: noErr - success
356 -------------------------------------------------------------------------------*/
358 OSStatus
ReleaseNode (BTreeControlBlockPtr btreePtr
,
362 ReleaseBlockProcPtr releaseNodeProc
;
367 if (nodePtr
->buffer
!= nil
)
369 releaseNodeProc
= btreePtr
->releaseBlockProc
;
370 err
= releaseNodeProc (btreePtr
->fileRefNum
,
373 PanicIf (err
, "\pReleaseNode: releaseNodeProc returned error.");
374 ++btreePtr
->numReleaseNodes
;
377 nodePtr
->buffer
= nil
;
378 nodePtr
->blockHeader
= nil
;
386 /*-------------------------------------------------------------------------------
388 Routine: TrashNode - Call FS Agent to release node obtained by GetNode, and
389 not store it...mark it as bad.
391 Function: Informs the FS Agent that a BTree node may be released and thrown away.
393 Input: btreePtr - pointer to BTree control block
394 nodeNum - number of node to release
396 Result: noErr - success
398 -------------------------------------------------------------------------------*/
400 OSStatus
TrashNode (BTreeControlBlockPtr btreePtr
,
404 ReleaseBlockProcPtr releaseNodeProc
;
409 if (nodePtr
->buffer
!= nil
)
411 releaseNodeProc
= btreePtr
->releaseBlockProc
;
412 err
= releaseNodeProc (btreePtr
->fileRefNum
,
414 kReleaseBlock
| kTrashBlock
);
415 PanicIf (err
, "\TrashNode: releaseNodeProc returned error.");
416 ++btreePtr
->numReleaseNodes
;
419 nodePtr
->buffer
= nil
;
420 nodePtr
->blockHeader
= nil
;
427 /*-------------------------------------------------------------------------------
429 Routine: UpdateNode - Mark a node as dirty and call FS Agent to release it.
431 Function: Marks a BTree node dirty and informs the FS Agent that it may be released.
433 //\80\80 have another routine that clears & writes a node, so we can call
434 CheckNode from this routine.
436 Input: btreePtr - pointer to BTree control block
437 nodeNum - number of node to release
438 transactionID - ID of transaction this node update is a part of
439 flags - special flags to pass to ReleaseNodeProc
441 Result: noErr - success
443 -------------------------------------------------------------------------------*/
445 OSStatus
UpdateNode (BTreeControlBlockPtr btreePtr
,
447 UInt32 transactionID
,
451 ReleaseBlockProcPtr releaseNodeProc
;
456 if (nodePtr
->buffer
!= nil
) //\80\80 why call UpdateNode if nil ?!?
460 if ( btreePtr
->attributes
& kBTVariableIndexKeysMask
)
461 (void) CheckNode (btreePtr
, nodePtr
->buffer
);
464 releaseNodeProc
= btreePtr
->releaseBlockProc
;
465 err
= releaseNodeProc (btreePtr
->fileRefNum
,
467 flags
| kMarkBlockDirty
);
468 ++btreePtr
->numUpdateNodes
;
472 nodePtr
->buffer
= nil
;
473 nodePtr
->blockHeader
= nil
;
484 /*-------------------------------------------------------------------------------
486 Routine: CheckNode - Checks the validity of a node.
488 Function: Checks the validity of a node by verifying that the fLink and bLink fields
489 are within the forks EOF. The node type must be one of the four known
490 types. The node height must be less than or equal to the tree height. The
491 node must not have more than the maximum number of records, and the record
492 offsets must make sense.
494 Input: btreePtr - pointer to BTree control block
495 node - pointer to node to check
497 Result: noErr - success
498 fsBTInvalidNodeErr - failure
499 -------------------------------------------------------------------------------*/
501 OSStatus
CheckNode (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
510 nodeSize
= btreePtr
->nodeSize
;
512 ///////////////////// are fLink and bLink within EOF ////////////////////////
514 maxNode
= (GetFileControlBlock(btreePtr
->fileRefNum
)->fcbEOF
/ nodeSize
) - 1;
516 if ( (node
->fLink
> maxNode
) || (node
->bLink
> maxNode
) )
517 return fsBTInvalidNodeErr
;
519 /////////////// check node type (leaf, index, header, map) //////////////////
521 if ( (node
->kind
< kBTLeafNode
) || (node
->kind
> kBTMapNode
) )
522 return fsBTInvalidNodeErr
;
524 ///////////////////// is node height > tree depth? //////////////////////////
526 if ( node
->height
> btreePtr
->treeDepth
)
527 return fsBTInvalidNodeErr
;
529 //////////////////////// check number of records ////////////////////////////
531 //XXX can we calculate a more accurate minimum record size?
532 maxRecords
= ( nodeSize
- sizeof (BTNodeDescriptor
) ) >> 3;
534 if (node
->numRecords
== 0 || node
->numRecords
> maxRecords
)
535 return fsBTInvalidNodeErr
;
537 ////////////////////////// check record offsets /////////////////////////////
539 index
= node
->numRecords
; /* start index at free space */
540 prevOffset
= nodeSize
- (index
<< 1); /* use 2 bytes past end of free space */
543 offset
= GetRecordOffset (btreePtr
, node
, index
);
545 if (offset
& 1) // offset is odd
546 return fsBTInvalidNodeErr
;
548 if (offset
>= prevOffset
) // offset >= previous offset
549 return fsBTInvalidNodeErr
;
551 /* reject keys that overflow record slot */
552 if ((node
->kind
== kBTLeafNode
) &&
553 (index
< node
->numRecords
) && /* ignore free space record */
554 (CalcKeySize(btreePtr
, (KeyPtr
) ((Ptr
)node
+ offset
)) > (prevOffset
- offset
))) {
555 return fsBTInvalidNodeErr
;
559 } while ( --index
>= 0 );
561 if (offset
< sizeof (BTNodeDescriptor
) ) // first offset < minimum ?
562 return fsBTInvalidNodeErr
;
569 static void PrintNode(const NodeDescPtr node
, UInt16 nodeSize
, UInt32 nodeNumber
)
578 PRINTIT("Dump of B-tree node #%ld ($%08lX)\n", nodeNumber
, nodeNumber
);
585 PRINTIT("%04X: %08lX %08lX %08lX %08lX\n", (u_int
)offset
++, *lp
++, *lp
++, *lp
++, *lp
++);
590 /*-------------------------------------------------------------------------------
592 Routine: ClearNode - Clear a node to all zeroes.
594 Function: Writes zeroes from beginning of node for nodeSize bytes.
596 Input: btreePtr - pointer to BTree control block
597 node - pointer to node to clear
600 -------------------------------------------------------------------------------*/
602 void ClearNode (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
604 ClearMemory( node
, btreePtr
->nodeSize
);
607 /*-------------------------------------------------------------------------------
609 Routine: InsertRecord - Inserts a record into a BTree node.
613 Note: Record size must be even!
615 Input: btreePtr - pointer to BTree control block
616 node - pointer to node to insert the record
617 index - position record is to be inserted
618 recPtr - pointer to record to insert
620 Result: noErr - success
621 fsBTFullErr - record larger than remaining free space.
622 -------------------------------------------------------------------------------*/
624 Boolean
InsertRecord (BTreeControlBlockPtr btreePtr
,
637 //// will new record fit in node?
639 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
640 //\80\80 we could get freeOffset & calc freeSpace
641 if ( freeSpace
< recSize
+ 2)
647 //// make hole for new record
649 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
650 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
652 src
= ((Ptr
) node
) + indexOffset
;
653 dst
= ((Ptr
) src
) + recSize
;
654 bytesToMove
= freeOffset
- indexOffset
;
656 MoveRecordsRight (src
, dst
, bytesToMove
);
659 //// adjust offsets for moved records
661 InsertOffset (btreePtr
, node
, index
, recSize
);
664 //// move in the new record
666 dst
= ((Ptr
) node
) + indexOffset
;
667 MoveRecordsLeft (recPtr
, dst
, recSize
);
674 /*-------------------------------------------------------------------------------
676 Routine: InsertKeyRecord - Inserts a record into a BTree node.
680 Note: Record size must be even!
682 Input: btreePtr - pointer to BTree control block
683 node - pointer to node to insert the record
684 index - position record is to be inserted
685 keyPtr - pointer to key for record to insert
686 keyLength - length of key (or maxKeyLength)
687 recPtr - pointer to record to insert
688 recSize - number of bytes to copy for record
690 Result: noErr - success
691 fsBTFullErr - record larger than remaining free space.
692 -------------------------------------------------------------------------------*/
694 Boolean
InsertKeyRecord (BTreeControlBlockPtr btreePtr
,
712 //// calculate actual key size
714 if ( btreePtr
->attributes
& kBTBigKeysMask
)
715 keySize
= keyLength
+ sizeof(UInt16
);
717 keySize
= keyLength
+ sizeof(UInt8
);
719 if ( M_IsOdd (keySize
) )
720 ++keySize
; // add pad byte
723 //// will new record fit in node?
725 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
726 //\80\80 we could get freeOffset & calc freeSpace
727 if ( freeSpace
< keySize
+ recSize
+ 2)
733 //// make hole for new record
735 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
736 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
738 src
= ((UInt8
*) node
) + indexOffset
;
739 dst
= ((UInt8
*) src
) + keySize
+ recSize
;
740 bytesToMove
= freeOffset
- indexOffset
;
742 MoveRecordsRight (src
, dst
, bytesToMove
);
745 //// adjust offsets for moved records
747 InsertOffset (btreePtr
, node
, index
, keySize
+ recSize
);
752 dst
= ((UInt8
*) node
) + indexOffset
;
754 if ( btreePtr
->attributes
& kBTBigKeysMask
)
756 *((UInt16
*) dst
)++ = keyLength
; // use keyLength rather than key.length
757 rawKeyLength
= keyPtr
->length16
;
762 *dst
++ = keyLength
; // use keyLength rather than key.length
763 rawKeyLength
= keyPtr
->length8
;
767 MoveRecordsLeft ( ((UInt8
*) keyPtr
) + sizeOfLength
, dst
, rawKeyLength
); // copy key
770 bytesToMove
= keySize
- rawKeyLength
;
772 ClearMemory (dst
+ rawKeyLength
, bytesToMove
); // clear pad bytes in index key
775 //// copy record data
777 dst
= ((UInt8
*) node
) + indexOffset
+ keySize
;
778 MoveRecordsLeft (recPtr
, dst
, recSize
);
785 /*-------------------------------------------------------------------------------
787 Routine: DeleteRecord - Deletes a record from a BTree node.
791 Input: btreePtr - pointer to BTree control block
792 node - pointer to node to insert the record
793 index - position record is to be inserted
796 -------------------------------------------------------------------------------*/
798 void DeleteRecord (BTreeControlBlockPtr btreePtr
,
809 //// compress records
810 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
811 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
812 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
814 src
= ((Ptr
) node
) + nextOffset
;
815 dst
= ((Ptr
) node
) + indexOffset
;
816 bytesToMove
= freeOffset
- nextOffset
;
818 MoveRecordsLeft (src
, dst
, bytesToMove
);
820 //// Adjust the offsets
821 DeleteOffset (btreePtr
, node
, index
);
823 /* clear out new free space */
824 bytesToMove
= nextOffset
- indexOffset
;
825 ClearMemory(GetRecordAddress(btreePtr
, node
, node
->numRecords
), bytesToMove
);
831 /*-------------------------------------------------------------------------------
833 Routine: SearchNode - Return index for record that matches key.
835 Function: Returns the record index for the record that matches the search key.
836 If no record was found that matches the search key, the "insert index"
837 of where the record should go is returned instead.
839 Algorithm: A binary search algorithm is used to find the specified key.
841 Input: btreePtr - pointer to BTree control block
842 node - pointer to node that contains the record
843 searchKey - pointer to the key to match
845 Output: index - pointer to beginning of key for record
847 Result: true - success (index = record index)
848 false - key did not match anything in node (index = insert index)
849 -------------------------------------------------------------------------------*/
851 SearchNode( BTreeControlBlockPtr btreePtr
,
854 UInt16
*returnIndex
)
862 KeyCompareProcPtr compareProc
= btreePtr
->keyCompareProc
;
865 upperBound
= node
->numRecords
- 1;
866 offset
= (UInt16
*) ((UInt8
*)(node
) + (btreePtr
)->nodeSize
- kOffsetSize
);
868 while (lowerBound
<= upperBound
) {
869 index
= (lowerBound
+ upperBound
) >> 1;
871 trialKey
= (KeyPtr
) ((UInt8
*)node
+ *(offset
- index
));
873 result
= compareProc(searchKey
, trialKey
);
876 upperBound
= index
- 1; /* search < trial */
877 } else if (result
> 0) {
878 lowerBound
= index
+ 1; /* search > trial */
880 *returnIndex
= index
; /* search == trial */
885 *returnIndex
= lowerBound
; /* lowerBound is insert index */
890 /*-------------------------------------------------------------------------------
892 Routine: GetRecordByIndex - Return pointer to key and data, and size of data.
894 Function: Returns a pointer to beginning of key for record, a pointer to the
895 beginning of the data for the record, and the size of the record data
896 (does not include the size of the key).
898 Input: btreePtr - pointer to BTree control block
899 node - pointer to node that contains the record
900 index - index of record to get
902 Output: keyPtr - pointer to beginning of key for record
903 dataPtr - pointer to beginning of data for record
904 dataSize - size of the data portion of the record
907 -------------------------------------------------------------------------------*/
909 OSStatus
GetRecordByIndex (BTreeControlBlockPtr btreePtr
,
921 // Make sure index is valid (in range 0..numRecords-1)
923 if (index
>= node
->numRecords
)
924 return fsBTRecordNotFoundErr
;
927 offset
= GetRecordOffset (btreePtr
, node
, index
);
928 *keyPtr
= (KeyPtr
) ((Ptr
)node
+ offset
);
931 keySize
= CalcKeySize(btreePtr
, *keyPtr
);
932 if ( M_IsOdd (keySize
) )
933 ++keySize
; // add pad byte
935 offset
+= keySize
; // add the key length to find data offset
936 *dataPtr
= (UInt8
*) node
+ offset
;
939 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
940 *dataSize
= nextOffset
- offset
;
947 /*-------------------------------------------------------------------------------
949 Routine: GetNodeDataSize - Return the amount of space used for data in the node.
951 Function: Gets the size of the data currently contained in a node, excluding
952 the node header. (record data + offset overhead)
954 Input: btreePtr - pointer to BTree control block
955 node - pointer to node that contains the record
957 Result: - number of bytes used for data and offsets in the node.
958 -------------------------------------------------------------------------------*/
960 UInt16
GetNodeDataSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
964 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
966 return freeOffset
+ (node
->numRecords
<< 1) - sizeof (BTNodeDescriptor
);
971 /*-------------------------------------------------------------------------------
973 Routine: GetNodeFreeSize - Return the amount of free space in the node.
977 Input: btreePtr - pointer to BTree control block
978 node - pointer to node that contains the record
980 Result: - number of bytes of free space in the node.
981 -------------------------------------------------------------------------------*/
983 UInt16
GetNodeFreeSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
987 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
); //\80\80 inline?
989 return btreePtr
->nodeSize
- freeOffset
- (node
->numRecords
<< 1) - kOffsetSize
;
994 /*-------------------------------------------------------------------------------
996 Routine: GetRecordOffset - Return the offset for record "index".
1000 Input: btreePtr - pointer to BTree control block
1001 node - pointer to node that contains the record
1002 index - record to obtain offset for
1004 Result: - offset (in bytes) from beginning of node of record specified by index
1005 -------------------------------------------------------------------------------*/
1006 // make this a macro (for inlining)
1008 UInt16
GetRecordOffset (BTreeControlBlockPtr btreePtr
,
1015 pos
= (UInt8
*)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
;
1017 return *(short *)pos
;
1023 /*-------------------------------------------------------------------------------
1025 Routine: GetRecordAddress - Return address of record "index".
1029 Input: btreePtr - pointer to BTree control block
1030 node - pointer to node that contains the record
1031 index - record to obtain offset address for
1033 Result: - pointer to record "index".
1034 -------------------------------------------------------------------------------*/
1035 // make this a macro (for inlining)
1037 UInt8
* GetRecordAddress (BTreeControlBlockPtr btreePtr
,
1043 pos
= (UInt8
*)node
+ GetRecordOffset (btreePtr
, node
, index
);
1051 /*-------------------------------------------------------------------------------
1053 Routine: GetRecordSize - Return size of record "index".
1057 Note: This does not work on the FreeSpace index!
1059 Input: btreePtr - pointer to BTree control block
1060 node - pointer to node that contains the record
1061 index - record to obtain record size for
1063 Result: - size of record "index".
1064 -------------------------------------------------------------------------------*/
1066 UInt16
GetRecordSize (BTreeControlBlockPtr btreePtr
,
1072 pos
= (UInt16
*) ((Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
);
1074 return *(pos
-1) - *pos
;
1079 /*-------------------------------------------------------------------------------
1080 Routine: GetOffsetAddress - Return address of offset for record "index".
1084 Input: btreePtr - pointer to BTree control block
1085 node - pointer to node that contains the record
1086 index - record to obtain offset address for
1088 Result: - pointer to offset for record "index".
1089 -------------------------------------------------------------------------------*/
1091 UInt16
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
1097 pos
= (Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) -2;
1099 return (UInt16
*)pos
;
1104 /*-------------------------------------------------------------------------------
1105 Routine: GetChildNodeNum - Return child node number from index record "index".
1107 Function: Returns the first UInt32 stored after the key for record "index".
1109 Assumes: The node is an Index Node.
1110 The key.length stored at record "index" is ODD. //\80\80 change for variable length index keys
1112 Input: btreePtr - pointer to BTree control block
1113 node - pointer to node that contains the record
1114 index - record to obtain child node number from
1116 Result: - child node number from record "index".
1117 -------------------------------------------------------------------------------*/
1119 UInt32
GetChildNodeNum (BTreeControlBlockPtr btreePtr
,
1120 NodeDescPtr nodePtr
,
1125 pos
= GetRecordAddress (btreePtr
, nodePtr
, index
);
1126 pos
+= CalcKeySize(btreePtr
, (BTreeKey
*) pos
); // key.length + size of length field
1128 return *(UInt32
*)pos
;
1133 /*-------------------------------------------------------------------------------
1134 Routine: InsertOffset - Add an offset and adjust existing offsets by delta.
1136 Function: Add an offset at 'index' by shifting 'index+1' through the last offset
1137 and adjusting them by 'delta', the size of the record to be inserted.
1138 The number of records contained in the node is also incremented.
1140 Input: btreePtr - pointer to BTree control block
1141 node - pointer to node
1142 index - index at which to insert record
1143 delta - size of record to be inserted
1146 -------------------------------------------------------------------------------*/
1148 void InsertOffset (BTreeControlBlockPtr btreePtr
,
1156 src
= GetOffsetAddress (btreePtr
, node
, node
->numRecords
); // point to free offset
1157 dst
= src
- 1; // point to new offset
1158 numOffsets
= node
->numRecords
++ - index
; // subtract index & postincrement
1161 *dst
++ = *src
++ + delta
; // to tricky?
1162 } while (numOffsets
--);
1167 /*-------------------------------------------------------------------------------
1169 Routine: DeleteOffset - Delete an offset.
1171 Function: Delete the offset at 'index' by shifting 'index+1' through the last offset
1172 and adjusting them by the size of the record 'index'.
1173 The number of records contained in the node is also decremented.
1175 Input: btreePtr - pointer to BTree control block
1176 node - pointer to node
1177 index - index at which to delete record
1180 -------------------------------------------------------------------------------*/
1182 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
1190 dst
= GetOffsetAddress (btreePtr
, node
, index
);
1192 delta
= *src
- *dst
;
1193 numOffsets
= --node
->numRecords
- index
; // predecrement numRecords & subtract index
1195 while (numOffsets
--)
1197 *--dst
= *--src
- delta
; // work our way left