2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 Contains: Single-node operations for the BTree Module.
27 Version: xxx put the technology version here xxx
29 Written by: Gordon Sheridan and Bill Bruffey
31 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
37 Other Contact: Mark Day
39 Technology: File Systems
46 Change History (most recent first):
48 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
49 <MOSXS> 4/113/99 djb Fix key size checking bug in CheckNode.
50 <MOSXS> 3/19/99 djb Added key size checking to CheckNode.
51 <MOSXS> 3/26/98 djb Added PrintNode for debugging.
52 <CS5> 9/4/97 djb Removed GetRightSiblingNode and GetLeftSiblingNode - they are
53 now macros. SearchNode is now in BTreeSearchNode.a.
54 <CS4> 8/22/97 djb Turn off debugging code in CheckKey.
55 <CS3> 7/24/97 djb Add summary traces for Get/Rel Node. Made GetRecordOffset into a
56 macro. Only call CheckNode if the node came from disk.
57 <CS2> 7/21/97 msd Make GetRecordByIndex check its record index input; it now
59 <CS1> 4/23/97 djb first checked in
61 <HFS3> 2/19/97 djb Changes to support big node cache.
62 <HFS2> 1/3/97 djb Added support for large keys.
63 <HFS1> 12/19/96 djb first checked in
66 History applicable to original Scarecrow Design:
68 <6> 10/25/96 ser Changing for new VFPI
69 <5> 9/17/96 dkh Add bounds checking to GetNode. Update GetNode to not assert
70 that CheckNode failed if the node is all zeroes. This can happen
71 if the hint case if the fetched node has been deallocated
72 <4> 3/7/96 dkh Change GetNewNode() to not use kGetEmptyBlock. Instead use
73 kGetBlock to fetch a block from the disk itself. \80\80\80 Why?
74 <3> 1/22/96 dkh Add #include Memory.h
75 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
76 <1> 10/18/95 rst Moved from Scarecrow project.
78 <17> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
79 <16> 1/31/95 prp GetBlockProc interface uses a 64 bit node number.
80 <15> 1/12/95 wjk Adopt Model FileSystem changes in D5.
81 <14> 9/30/94 prp Get in sync with D2 interface changes.
82 <13> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
83 <12> 7/22/94 wjk Convert to the new set of header files.
84 <11> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
86 <10> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
87 agree with their prototypes.
88 <9> 8/31/93 prp Use U64SetU instead of S64Set.
89 <8> 5/21/93 gs Maintain statistical counters on Get/Release node routines.
90 <7> 5/10/93 gs Change keySize parameter to keyLength for InsertKeyRecord
91 routine. Calculate number of bytes in key from keyLength to
92 account for length and pad bytes. Add GetChildNodeNum routine.
93 <6> 3/23/93 gs Add InsertKeyRecord routine.
94 <5> 2/8/93 gs Fix bug in SearchNode that caused "off by 1" error when final
95 compare was searchKey > trialKey. Add UpdateNode.
96 <4> 12/10/92 gs Change keyLength field of key to 'length'.
97 <3> 12/8/92 gs Incorporate suggestions from preliminary code review.
98 <2> 12/2/92 gs Implement routines.
99 <1> 11/15/92 gs Define routine interfaces.
103 #include "../headers/BTreesPrivate.h"
107 ///////////////////////// BTree Module Node Operations //////////////////////////
109 // GetNode - Call FS Agent to get node
110 // GetNewNode - Call FS Agent to get a new node
111 // ReleaseNode - Call FS Agent to release node obtained by GetNode.
112 // UpdateNode - Mark a node as dirty and call FS Agent to release it.
114 // CheckNode - Checks the validity of a node.
115 // ClearNode - Clear a node to all zeroes.
117 // InsertRecord - Inserts a record into a BTree node.
118 // InsertKeyRecord - Inserts a key and record pair into a BTree node.
119 // DeleteRecord - Deletes a record from a BTree node.
121 // SearchNode - Return index for record that matches key.
122 // LocateRecord - Return pointer to key and data, and size of data.
124 // GetNodeDataSize - Return the amount of space used for data in the node.
125 // GetNodeFreeSize - Return the amount of free space in the node.
127 // GetRecordOffset - Return the offset for record "index".
128 // GetRecordAddress - Return address of record "index".
129 // GetOffsetAddress - Return address of offset for record "index".
131 // InsertOffset - Inserts a new offset into a node.
132 // DeleteOffset - Deletes an offset from a node.
134 /////////////////////////////////////////////////////////////////////////////////
138 ////////////////////// Routines Internal To BTreeNodeOps.c //////////////////////
140 UInt16
GetRecordOffset (BTreeControlBlockPtr btree
,
144 UInt16
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
148 void InsertOffset (BTreeControlBlockPtr btreePtr
,
153 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
158 /////////////////////////////////////////////////////////////////////////////////
160 #define GetRecordOffset(btreePtr,node,index) (*(short *) ((UInt8 *)(node) + (btreePtr)->nodeSize - ((index) << 1) - kOffsetSize))
163 #include <sys/systm.h>
164 #define PRINTIT kprintf
165 #endif /* HFS_DIAGNOSTIC */
167 static void PrintNode(const NodeDescPtr node
, UInt16 nodeSize
, UInt32 nodeNumber
);
171 /*-------------------------------------------------------------------------------
173 Routine: GetNode - Call FS Agent to get node
175 Function: Gets an existing BTree node from FS Agent and verifies it.
177 Input: btreePtr - pointer to BTree control block
178 nodeNum - number of node to request
180 Output: nodePtr - pointer to beginning of node (nil if error)
185 -------------------------------------------------------------------------------*/
187 OSStatus
GetNode (BTreeControlBlockPtr btreePtr
,
192 GetBlockProcPtr getNodeProc
;
195 //\80\80 is nodeNum within proper range?
196 if( nodeNum
>= btreePtr
->totalNodes
)
198 Panic("\pGetNode:nodeNum >= totalNodes");
199 err
= fsBTInvalidNodeErr
;
203 nodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
205 getNodeProc
= btreePtr
->getBlockProc
;
206 err
= getNodeProc (btreePtr
->fileRefNum
,
213 Panic ("\pGetNode: getNodeProc returned error.");
214 // nodePtr->buffer = nil;
217 ++btreePtr
->numGetNodes
;
221 // Only call CheckNode if the node came from disk.
222 // If it was in the cache, we'll assume its already a valid node.
225 if ( nodePtr
->blockReadFromDisk
) // if we read it from disk then check it
227 err
= CheckNode (btreePtr
, nodePtr
->buffer
);
232 VTOVCB(btreePtr
->fileRefNum
)->vcbFlags
|= kHFS_DamagedVolume
;
235 if (((NodeDescPtr
)nodePtr
->buffer
)->numRecords
!= 0)
236 PrintNode(nodePtr
->buffer
, btreePtr
->nodeSize
, nodeNum
);
241 // With the removal of bounds checking in IsItAHint(), it's possible that
242 // GetNode() will be called to fetch a clear (all zeroes) node. We want
243 // CheckNode() to fail in this case (it does), however we don't want to assert
244 // this case because it is not really an "error". Returning an error from GetNode()
245 // in this case will cause the hint checking code to ignore the hint and revert to
246 // the full search mode.
252 cur
= nodePtr
->buffer
;
253 lastPlusOne
= (UInt32
*) ((UInt8
*) cur
+ btreePtr
->nodeSize
);
255 while( cur
< lastPlusOne
)
259 Panic ("\pGetNode: CheckNode returned error.");
266 (void) TrashNode (btreePtr
, nodePtr
); // ignore error
274 nodePtr
->buffer
= nil
;
275 nodePtr
->blockHeader
= nil
;
282 /*-------------------------------------------------------------------------------
284 Routine: GetNewNode - Call FS Agent to get a new node
286 Function: Gets a new BTree node from FS Agent and initializes it to an empty
289 Input: btreePtr - pointer to BTree control block
290 nodeNum - number of node to request
292 Output: returnNodePtr - pointer to beginning of node (nil if error)
294 Result: noErr - success
296 -------------------------------------------------------------------------------*/
298 OSStatus
GetNewNode (BTreeControlBlockPtr btreePtr
,
300 NodeRec
*returnNodePtr
)
305 GetBlockProcPtr getNodeProc
;
308 //////////////////////// get buffer for new node ////////////////////////////
310 returnNodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
312 getNodeProc
= btreePtr
->getBlockProc
;
313 err
= getNodeProc (btreePtr
->fileRefNum
,
315 kGetBlock
+kGetEmptyBlock
,
320 Panic ("\pGetNewNode: getNodeProc returned error.");
321 // returnNodePtr->buffer = nil;
324 ++btreePtr
->numGetNewNodes
;
327 ////////////////////////// initialize the node //////////////////////////////
329 node
= returnNodePtr
->buffer
;
331 ClearNode (btreePtr
, node
); // clear the node
333 pos
= (char *)node
+ btreePtr
->nodeSize
- 2; // find address of last offset
334 *(UInt16
*)pos
= sizeof (BTNodeDescriptor
); // set offset to beginning of free space
342 /*-------------------------------------------------------------------------------
344 Routine: ReleaseNode - Call FS Agent to release node obtained by GetNode.
346 Function: Informs the FS Agent that a BTree node may be released.
348 Input: btreePtr - pointer to BTree control block
349 nodeNum - number of node to release
351 Result: noErr - success
353 -------------------------------------------------------------------------------*/
355 OSStatus
ReleaseNode (BTreeControlBlockPtr btreePtr
,
359 ReleaseBlockProcPtr releaseNodeProc
;
364 if (nodePtr
->buffer
!= nil
)
366 releaseNodeProc
= btreePtr
->releaseBlockProc
;
367 err
= releaseNodeProc (btreePtr
->fileRefNum
,
370 PanicIf (err
, "\pReleaseNode: releaseNodeProc returned error.");
371 ++btreePtr
->numReleaseNodes
;
374 nodePtr
->buffer
= nil
;
375 nodePtr
->blockHeader
= nil
;
383 /*-------------------------------------------------------------------------------
385 Routine: TrashNode - Call FS Agent to release node obtained by GetNode, and
386 not store it...mark it as bad.
388 Function: Informs the FS Agent that a BTree node may be released and thrown away.
390 Input: btreePtr - pointer to BTree control block
391 nodeNum - number of node to release
393 Result: noErr - success
395 -------------------------------------------------------------------------------*/
397 OSStatus
TrashNode (BTreeControlBlockPtr btreePtr
,
401 ReleaseBlockProcPtr releaseNodeProc
;
406 if (nodePtr
->buffer
!= nil
)
408 releaseNodeProc
= btreePtr
->releaseBlockProc
;
409 err
= releaseNodeProc (btreePtr
->fileRefNum
,
411 kReleaseBlock
| kTrashBlock
);
412 PanicIf (err
, "\TrashNode: releaseNodeProc returned error.");
413 ++btreePtr
->numReleaseNodes
;
416 nodePtr
->buffer
= nil
;
417 nodePtr
->blockHeader
= nil
;
424 /*-------------------------------------------------------------------------------
426 Routine: UpdateNode - Mark a node as dirty and call FS Agent to release it.
428 Function: Marks a BTree node dirty and informs the FS Agent that it may be released.
430 //\80\80 have another routine that clears & writes a node, so we can call
431 CheckNode from this routine.
433 Input: btreePtr - pointer to BTree control block
434 nodeNum - number of node to release
435 transactionID - ID of transaction this node update is a part of
436 flags - special flags to pass to ReleaseNodeProc
438 Result: noErr - success
440 -------------------------------------------------------------------------------*/
442 OSStatus
UpdateNode (BTreeControlBlockPtr btreePtr
,
444 UInt32 transactionID
,
448 ReleaseBlockProcPtr releaseNodeProc
;
453 if (nodePtr
->buffer
!= nil
) //\80\80 why call UpdateNode if nil ?!?
457 if ( btreePtr
->attributes
& kBTVariableIndexKeysMask
)
458 (void) CheckNode (btreePtr
, nodePtr
->buffer
);
461 releaseNodeProc
= btreePtr
->releaseBlockProc
;
462 err
= releaseNodeProc (btreePtr
->fileRefNum
,
464 flags
| kMarkBlockDirty
);
465 ++btreePtr
->numUpdateNodes
;
469 nodePtr
->buffer
= nil
;
470 nodePtr
->blockHeader
= nil
;
481 /*-------------------------------------------------------------------------------
483 Routine: CheckNode - Checks the validity of a node.
485 Function: Checks the validity of a node by verifying that the fLink and bLink fields
486 are within the forks EOF. The node type must be one of the four known
487 types. The node height must be less than or equal to the tree height. The
488 node must not have more than the maximum number of records, and the record
489 offsets must make sense.
491 Input: btreePtr - pointer to BTree control block
492 node - pointer to node to check
494 Result: noErr - success
495 fsBTInvalidNodeErr - failure
496 -------------------------------------------------------------------------------*/
498 OSStatus
CheckNode (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
507 nodeSize
= btreePtr
->nodeSize
;
509 ///////////////////// are fLink and bLink within EOF ////////////////////////
511 maxNode
= (GetFileControlBlock(btreePtr
->fileRefNum
)->fcbEOF
/ nodeSize
) - 1;
513 if ( (node
->fLink
> maxNode
) || (node
->bLink
> maxNode
) )
514 return fsBTInvalidNodeErr
;
516 /////////////// check node type (leaf, index, header, map) //////////////////
518 if ( (node
->kind
< kBTLeafNode
) || (node
->kind
> kBTMapNode
) )
519 return fsBTInvalidNodeErr
;
521 ///////////////////// is node height > tree depth? //////////////////////////
523 if ( node
->height
> btreePtr
->treeDepth
)
524 return fsBTInvalidNodeErr
;
526 //////////////////////// check number of records ////////////////////////////
528 //XXX can we calculate a more accurate minimum record size?
529 maxRecords
= ( nodeSize
- sizeof (BTNodeDescriptor
) ) >> 3;
531 if (node
->numRecords
== 0 || node
->numRecords
> maxRecords
)
532 return fsBTInvalidNodeErr
;
534 ////////////////////////// check record offsets /////////////////////////////
536 index
= node
->numRecords
; /* start index at free space */
537 prevOffset
= nodeSize
- (index
<< 1); /* use 2 bytes past end of free space */
540 offset
= GetRecordOffset (btreePtr
, node
, index
);
542 if (offset
& 1) // offset is odd
543 return fsBTInvalidNodeErr
;
545 if (offset
>= prevOffset
) // offset >= previous offset
546 return fsBTInvalidNodeErr
;
548 /* reject keys that overflow record slot */
549 if ((node
->kind
== kBTLeafNode
) &&
550 (index
< node
->numRecords
) && /* ignore free space record */
551 (CalcKeySize(btreePtr
, (KeyPtr
) ((Ptr
)node
+ offset
)) > (prevOffset
- offset
))) {
552 return fsBTInvalidNodeErr
;
556 } while ( --index
>= 0 );
558 if (offset
< sizeof (BTNodeDescriptor
) ) // first offset < minimum ?
559 return fsBTInvalidNodeErr
;
566 static void PrintNode(const NodeDescPtr node
, UInt16 nodeSize
, UInt32 nodeNumber
)
575 PRINTIT("Dump of B-tree node #%ld ($%08lX)\n", nodeNumber
, nodeNumber
);
582 PRINTIT("%04X: %08lX %08lX %08lX %08lX\n", (u_int
)offset
++, *lp
++, *lp
++, *lp
++, *lp
++);
587 /*-------------------------------------------------------------------------------
589 Routine: ClearNode - Clear a node to all zeroes.
591 Function: Writes zeroes from beginning of node for nodeSize bytes.
593 Input: btreePtr - pointer to BTree control block
594 node - pointer to node to clear
597 -------------------------------------------------------------------------------*/
599 void ClearNode (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
601 ClearMemory( node
, btreePtr
->nodeSize
);
604 /*-------------------------------------------------------------------------------
606 Routine: InsertRecord - Inserts a record into a BTree node.
610 Note: Record size must be even!
612 Input: btreePtr - pointer to BTree control block
613 node - pointer to node to insert the record
614 index - position record is to be inserted
615 recPtr - pointer to record to insert
617 Result: noErr - success
618 fsBTFullErr - record larger than remaining free space.
619 -------------------------------------------------------------------------------*/
621 Boolean
InsertRecord (BTreeControlBlockPtr btreePtr
,
634 //// will new record fit in node?
636 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
637 //\80\80 we could get freeOffset & calc freeSpace
638 if ( freeSpace
< recSize
+ 2)
644 //// make hole for new record
646 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
647 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
649 src
= ((Ptr
) node
) + indexOffset
;
650 dst
= ((Ptr
) src
) + recSize
;
651 bytesToMove
= freeOffset
- indexOffset
;
653 MoveRecordsRight (src
, dst
, bytesToMove
);
656 //// adjust offsets for moved records
658 InsertOffset (btreePtr
, node
, index
, recSize
);
661 //// move in the new record
663 dst
= ((Ptr
) node
) + indexOffset
;
664 MoveRecordsLeft (recPtr
, dst
, recSize
);
671 /*-------------------------------------------------------------------------------
673 Routine: InsertKeyRecord - Inserts a record into a BTree node.
677 Note: Record size must be even!
679 Input: btreePtr - pointer to BTree control block
680 node - pointer to node to insert the record
681 index - position record is to be inserted
682 keyPtr - pointer to key for record to insert
683 keyLength - length of key (or maxKeyLength)
684 recPtr - pointer to record to insert
685 recSize - number of bytes to copy for record
687 Result: noErr - success
688 fsBTFullErr - record larger than remaining free space.
689 -------------------------------------------------------------------------------*/
691 Boolean
InsertKeyRecord (BTreeControlBlockPtr btreePtr
,
709 //// calculate actual key size
711 if ( btreePtr
->attributes
& kBTBigKeysMask
)
712 keySize
= keyLength
+ sizeof(UInt16
);
714 keySize
= keyLength
+ sizeof(UInt8
);
716 if ( M_IsOdd (keySize
) )
717 ++keySize
; // add pad byte
720 //// will new record fit in node?
722 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
723 //\80\80 we could get freeOffset & calc freeSpace
724 if ( freeSpace
< keySize
+ recSize
+ 2)
730 //// make hole for new record
732 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
733 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
735 src
= ((UInt8
*) node
) + indexOffset
;
736 dst
= ((UInt8
*) src
) + keySize
+ recSize
;
737 bytesToMove
= freeOffset
- indexOffset
;
739 MoveRecordsRight (src
, dst
, bytesToMove
);
742 //// adjust offsets for moved records
744 InsertOffset (btreePtr
, node
, index
, keySize
+ recSize
);
749 dst
= ((UInt8
*) node
) + indexOffset
;
751 if ( btreePtr
->attributes
& kBTBigKeysMask
)
753 *((UInt16
*) dst
)++ = keyLength
; // use keyLength rather than key.length
754 rawKeyLength
= keyPtr
->length16
;
759 *dst
++ = keyLength
; // use keyLength rather than key.length
760 rawKeyLength
= keyPtr
->length8
;
764 MoveRecordsLeft ( ((UInt8
*) keyPtr
) + sizeOfLength
, dst
, rawKeyLength
); // copy key
767 bytesToMove
= keySize
- rawKeyLength
;
769 ClearMemory (dst
+ rawKeyLength
, bytesToMove
); // clear pad bytes in index key
772 //// copy record data
774 dst
= ((UInt8
*) node
) + indexOffset
+ keySize
;
775 MoveRecordsLeft (recPtr
, dst
, recSize
);
782 /*-------------------------------------------------------------------------------
784 Routine: DeleteRecord - Deletes a record from a BTree node.
788 Input: btreePtr - pointer to BTree control block
789 node - pointer to node to insert the record
790 index - position record is to be inserted
793 -------------------------------------------------------------------------------*/
795 void DeleteRecord (BTreeControlBlockPtr btreePtr
,
806 //// compress records
807 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
808 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
809 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
811 src
= ((Ptr
) node
) + nextOffset
;
812 dst
= ((Ptr
) node
) + indexOffset
;
813 bytesToMove
= freeOffset
- nextOffset
;
815 MoveRecordsLeft (src
, dst
, bytesToMove
);
817 //// Adjust the offsets
818 DeleteOffset (btreePtr
, node
, index
);
820 /* clear out new free space */
821 bytesToMove
= nextOffset
- indexOffset
;
822 ClearMemory(GetRecordAddress(btreePtr
, node
, node
->numRecords
), bytesToMove
);
828 /*-------------------------------------------------------------------------------
830 Routine: SearchNode - Return index for record that matches key.
832 Function: Returns the record index for the record that matches the search key.
833 If no record was found that matches the search key, the "insert index"
834 of where the record should go is returned instead.
836 Algorithm: A binary search algorithm is used to find the specified key.
838 Input: btreePtr - pointer to BTree control block
839 node - pointer to node that contains the record
840 searchKey - pointer to the key to match
842 Output: index - pointer to beginning of key for record
844 Result: true - success (index = record index)
845 false - key did not match anything in node (index = insert index)
846 -------------------------------------------------------------------------------*/
848 SearchNode( BTreeControlBlockPtr btreePtr
,
851 UInt16
*returnIndex
)
859 KeyCompareProcPtr compareProc
= btreePtr
->keyCompareProc
;
862 upperBound
= node
->numRecords
- 1;
863 offset
= (UInt16
*) ((UInt8
*)(node
) + (btreePtr
)->nodeSize
- kOffsetSize
);
865 while (lowerBound
<= upperBound
) {
866 index
= (lowerBound
+ upperBound
) >> 1;
868 trialKey
= (KeyPtr
) ((UInt8
*)node
+ *(offset
- index
));
870 result
= compareProc(searchKey
, trialKey
);
873 upperBound
= index
- 1; /* search < trial */
874 } else if (result
> 0) {
875 lowerBound
= index
+ 1; /* search > trial */
877 *returnIndex
= index
; /* search == trial */
882 *returnIndex
= lowerBound
; /* lowerBound is insert index */
887 /*-------------------------------------------------------------------------------
889 Routine: GetRecordByIndex - Return pointer to key and data, and size of data.
891 Function: Returns a pointer to beginning of key for record, a pointer to the
892 beginning of the data for the record, and the size of the record data
893 (does not include the size of the key).
895 Input: btreePtr - pointer to BTree control block
896 node - pointer to node that contains the record
897 index - index of record to get
899 Output: keyPtr - pointer to beginning of key for record
900 dataPtr - pointer to beginning of data for record
901 dataSize - size of the data portion of the record
904 -------------------------------------------------------------------------------*/
906 OSStatus
GetRecordByIndex (BTreeControlBlockPtr btreePtr
,
918 // Make sure index is valid (in range 0..numRecords-1)
920 if (index
>= node
->numRecords
)
921 return fsBTRecordNotFoundErr
;
924 offset
= GetRecordOffset (btreePtr
, node
, index
);
925 *keyPtr
= (KeyPtr
) ((Ptr
)node
+ offset
);
928 keySize
= CalcKeySize(btreePtr
, *keyPtr
);
929 if ( M_IsOdd (keySize
) )
930 ++keySize
; // add pad byte
932 offset
+= keySize
; // add the key length to find data offset
933 *dataPtr
= (UInt8
*) node
+ offset
;
936 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
937 *dataSize
= nextOffset
- offset
;
944 /*-------------------------------------------------------------------------------
946 Routine: GetNodeDataSize - Return the amount of space used for data in the node.
948 Function: Gets the size of the data currently contained in a node, excluding
949 the node header. (record data + offset overhead)
951 Input: btreePtr - pointer to BTree control block
952 node - pointer to node that contains the record
954 Result: - number of bytes used for data and offsets in the node.
955 -------------------------------------------------------------------------------*/
957 UInt16
GetNodeDataSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
961 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
963 return freeOffset
+ (node
->numRecords
<< 1) - sizeof (BTNodeDescriptor
);
968 /*-------------------------------------------------------------------------------
970 Routine: GetNodeFreeSize - Return the amount of free space in the node.
974 Input: btreePtr - pointer to BTree control block
975 node - pointer to node that contains the record
977 Result: - number of bytes of free space in the node.
978 -------------------------------------------------------------------------------*/
980 UInt16
GetNodeFreeSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
984 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
); //\80\80 inline?
986 return btreePtr
->nodeSize
- freeOffset
- (node
->numRecords
<< 1) - kOffsetSize
;
991 /*-------------------------------------------------------------------------------
993 Routine: GetRecordOffset - Return the offset for record "index".
997 Input: btreePtr - pointer to BTree control block
998 node - pointer to node that contains the record
999 index - record to obtain offset for
1001 Result: - offset (in bytes) from beginning of node of record specified by index
1002 -------------------------------------------------------------------------------*/
1003 // make this a macro (for inlining)
1005 UInt16
GetRecordOffset (BTreeControlBlockPtr btreePtr
,
1012 pos
= (UInt8
*)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
;
1014 return *(short *)pos
;
1020 /*-------------------------------------------------------------------------------
1022 Routine: GetRecordAddress - Return address of record "index".
1026 Input: btreePtr - pointer to BTree control block
1027 node - pointer to node that contains the record
1028 index - record to obtain offset address for
1030 Result: - pointer to record "index".
1031 -------------------------------------------------------------------------------*/
1032 // make this a macro (for inlining)
1034 UInt8
* GetRecordAddress (BTreeControlBlockPtr btreePtr
,
1040 pos
= (UInt8
*)node
+ GetRecordOffset (btreePtr
, node
, index
);
1048 /*-------------------------------------------------------------------------------
1050 Routine: GetRecordSize - Return size of record "index".
1054 Note: This does not work on the FreeSpace index!
1056 Input: btreePtr - pointer to BTree control block
1057 node - pointer to node that contains the record
1058 index - record to obtain record size for
1060 Result: - size of record "index".
1061 -------------------------------------------------------------------------------*/
1063 UInt16
GetRecordSize (BTreeControlBlockPtr btreePtr
,
1069 pos
= (UInt16
*) ((Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
);
1071 return *(pos
-1) - *pos
;
1076 /*-------------------------------------------------------------------------------
1077 Routine: GetOffsetAddress - Return address of offset for record "index".
1081 Input: btreePtr - pointer to BTree control block
1082 node - pointer to node that contains the record
1083 index - record to obtain offset address for
1085 Result: - pointer to offset for record "index".
1086 -------------------------------------------------------------------------------*/
1088 UInt16
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
1094 pos
= (Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) -2;
1096 return (UInt16
*)pos
;
1101 /*-------------------------------------------------------------------------------
1102 Routine: GetChildNodeNum - Return child node number from index record "index".
1104 Function: Returns the first UInt32 stored after the key for record "index".
1106 Assumes: The node is an Index Node.
1107 The key.length stored at record "index" is ODD. //\80\80 change for variable length index keys
1109 Input: btreePtr - pointer to BTree control block
1110 node - pointer to node that contains the record
1111 index - record to obtain child node number from
1113 Result: - child node number from record "index".
1114 -------------------------------------------------------------------------------*/
1116 UInt32
GetChildNodeNum (BTreeControlBlockPtr btreePtr
,
1117 NodeDescPtr nodePtr
,
1122 pos
= GetRecordAddress (btreePtr
, nodePtr
, index
);
1123 pos
+= CalcKeySize(btreePtr
, (BTreeKey
*) pos
); // key.length + size of length field
1125 return *(UInt32
*)pos
;
1130 /*-------------------------------------------------------------------------------
1131 Routine: InsertOffset - Add an offset and adjust existing offsets by delta.
1133 Function: Add an offset at 'index' by shifting 'index+1' through the last offset
1134 and adjusting them by 'delta', the size of the record to be inserted.
1135 The number of records contained in the node is also incremented.
1137 Input: btreePtr - pointer to BTree control block
1138 node - pointer to node
1139 index - index at which to insert record
1140 delta - size of record to be inserted
1143 -------------------------------------------------------------------------------*/
1145 void InsertOffset (BTreeControlBlockPtr btreePtr
,
1153 src
= GetOffsetAddress (btreePtr
, node
, node
->numRecords
); // point to free offset
1154 dst
= src
- 1; // point to new offset
1155 numOffsets
= node
->numRecords
++ - index
; // subtract index & postincrement
1158 *dst
++ = *src
++ + delta
; // to tricky?
1159 } while (numOffsets
--);
1164 /*-------------------------------------------------------------------------------
1166 Routine: DeleteOffset - Delete an offset.
1168 Function: Delete the offset at 'index' by shifting 'index+1' through the last offset
1169 and adjusting them by the size of the record 'index'.
1170 The number of records contained in the node is also decremented.
1172 Input: btreePtr - pointer to BTree control block
1173 node - pointer to node
1174 index - index at which to delete record
1177 -------------------------------------------------------------------------------*/
1179 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
1187 dst
= GetOffsetAddress (btreePtr
, node
, index
);
1189 delta
= *src
- *dst
;
1190 numOffsets
= --node
->numRecords
- index
; // predecrement numRecords & subtract index
1192 while (numOffsets
--)
1194 *--dst
= *--src
- delta
; // work our way left