Annotation of XNU/bsd/hfs/hfscommon/BTree/BTreeNodeOps.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             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.
        !            11:  * 
        !            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
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:        File:           BTreeNodeOps.c
        !            24: 
        !            25:        Contains:       Single-node operations for the BTree Module.
        !            26: 
        !            27:        Version:        xxx put the technology version here xxx
        !            28: 
        !            29:        Written by:     Gordon Sheridan and Bill Bruffey
        !            30: 
        !            31:        Copyright:      � 1992-1999 by Apple Computer, Inc., all rights reserved.
        !            32: 
        !            33:        File Ownership:
        !            34: 
        !            35:                DRI:                            Don Brady
        !            36: 
        !            37:                Other Contact:          Mark Day
        !            38: 
        !            39:                Technology:                     File Systems
        !            40: 
        !            41:        Writers:
        !            42: 
        !            43:                (msd)   Mark Day
        !            44:                (djb)   Don Brady
        !            45: 
        !            46:        Change History (most recent first):
        !            47: 
        !            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
        !            58:                                                                        returns an OSStatus.
        !            59:           <CS1>         4/23/97        djb             first checked in
        !            60: 
        !            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
        !            64: 
        !            65: 
        !            66:        History applicable to original Scarecrow Design:
        !            67: 
        !            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.  ��� 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.
        !            77: 
        !            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
        !            85:                                                                        NRCmds environments.
        !            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.
        !           100: 
        !           101: */
        !           102: 
        !           103: #include "../headers/BTreesPrivate.h"
        !           104: #include "../headers/HFSInstrumentation.h"
        !           105: 
        !           106: 
        !           107: 
        !           108: ///////////////////////// BTree Module Node Operations //////////////////////////
        !           109: //
        !           110: //     GetNode                         - Call FS Agent to get node
        !           111: //     GetNewNode                      - Call FS Agent to get a new node
        !           112: //     ReleaseNode                     - Call FS Agent to release node obtained by GetNode.
        !           113: //     UpdateNode                      - Mark a node as dirty and call FS Agent to release it.
        !           114: //
        !           115: //     CheckNode                       - Checks the validity of a node.
        !           116: //     ClearNode                       - Clear a node to all zeroes.
        !           117: //
        !           118: //     InsertRecord            - Inserts a record into a BTree node.
        !           119: //     InsertKeyRecord         - Inserts a key and record pair into a BTree node.
        !           120: //     DeleteRecord            - Deletes a record from a BTree node.
        !           121: //
        !           122: //     SearchNode                      - Return index for record that matches key.
        !           123: //     LocateRecord            - Return pointer to key and data, and size of data.
        !           124: //
        !           125: //     GetNodeDataSize         - Return the amount of space used for data in the node.
        !           126: //     GetNodeFreeSize         - Return the amount of free space in the node.
        !           127: //
        !           128: //     GetRecordOffset         - Return the offset for record "index".
        !           129: //     GetRecordAddress        - Return address of record "index".
        !           130: //     GetOffsetAddress        - Return address of offset for record "index".
        !           131: //
        !           132: //     InsertOffset            - Inserts a new offset into a node.
        !           133: //     DeleteOffset            - Deletes an offset from a node.
        !           134: //
        !           135: //     MoveRecordsLeft         - Move records left within a node.
        !           136: //     MoveRecordsRight        - Move records right within a node.
        !           137: //
        !           138: /////////////////////////////////////////////////////////////////////////////////
        !           139: 
        !           140: 
        !           141: 
        !           142: ////////////////////// Routines Internal To BTreeNodeOps.c //////////////////////
        !           143: 
        !           144: UInt16         GetRecordOffset         (BTreeControlBlockPtr    btree,
        !           145:                                                                 NodeDescPtr                     node,
        !           146:                                                                 UInt16                                  index );
        !           147: 
        !           148: UInt16    *GetOffsetAddress    (BTreeControlBlockPtr   btreePtr,
        !           149:                                                                 NodeDescPtr                     node,
        !           150:                                                                 UInt16                                 index );
        !           151:                                                                 
        !           152: void           InsertOffset            (BTreeControlBlockPtr    btreePtr,
        !           153:                                                                 NodeDescPtr                     node,
        !           154:                                                                 UInt16                                  index,
        !           155:                                                                 UInt16                                  delta );
        !           156: 
        !           157: void           DeleteOffset            (BTreeControlBlockPtr    btreePtr,
        !           158:                                                                 NodeDescPtr                     node,
        !           159:                                                                 UInt16                                  index );
        !           160: 
        !           161: 
        !           162: /////////////////////////////////////////////////////////////////////////////////
        !           163: 
        !           164: #define GetRecordOffset(btreePtr,node,index)           (*(short *) ((UInt8 *)(node) + (btreePtr)->nodeSize - ((index) << 1) - kOffsetSize))
        !           165: 
        !           166: #if HFS_DIAGNOSTIC
        !           167:                #include <sys/systm.h>
        !           168:            #define PRINTIT kprintf
        !           169: #endif /* HFS_DIAGNOSTIC */
        !           170: 
        !           171: static void PrintNode(const NodeDescPtr node, UInt16 nodeSize, UInt32 nodeNumber);
        !           172: 
        !           173: 
        !           174: 
        !           175: /*-------------------------------------------------------------------------------
        !           176: 
        !           177: Routine:       GetNode -       Call FS Agent to get node
        !           178: 
        !           179: Function:      Gets an existing BTree node from FS Agent and verifies it.
        !           180: 
        !           181: Input:         btreePtr        - pointer to BTree control block
        !           182:                        nodeNum         - number of node to request
        !           183:                        
        !           184: Output:                nodePtr         - pointer to beginning of node (nil if error)
        !           185:                        
        !           186: Result:
        !           187:                        noErr           - success
        !           188:                        != noErr        - failure
        !           189: -------------------------------------------------------------------------------*/
        !           190: 
        !           191: OSStatus       GetNode         (BTreeControlBlockPtr    btreePtr,
        !           192:                                                 UInt32                                  nodeNum,
        !           193:                                                 NodeRec                                *nodePtr )
        !           194: {
        !           195:        OSStatus                        err;
        !           196:        GetBlockProcPtr         getNodeProc;
        !           197:        
        !           198: 
        !           199:        LogStartTime(kTraceGetNode);
        !           200: 
        !           201:        //�� is nodeNum within proper range?
        !           202:        if( nodeNum >= btreePtr->totalNodes )
        !           203:        {
        !           204:                Panic("\pGetNode:nodeNum >= totalNodes");
        !           205:                err = fsBTInvalidNodeErr;
        !           206:                goto ErrorExit;
        !           207:        }
        !           208:        
        !           209:        nodePtr->blockSize = btreePtr->nodeSize;        // indicate the size of a node
        !           210:        
        !           211:        getNodeProc = btreePtr->getBlockProc;
        !           212:        err = getNodeProc (btreePtr->fileRefNum,
        !           213:                                           nodeNum,
        !           214:                                           kGetBlock,
        !           215:                                           nodePtr );
        !           216: 
        !           217:        if (err != noErr)
        !           218:        {
        !           219:                Panic ("\pGetNode: getNodeProc returned error.");
        !           220:        //      nodePtr->buffer = nil;
        !           221:                goto ErrorExit;
        !           222:        }
        !           223:        ++btreePtr->numGetNodes;
        !           224:        
        !           225:        //
        !           226:        // Optimization
        !           227:        // Only call CheckNode if the node came from disk.
        !           228:        // If it was in the cache, we'll assume its already a valid node.
        !           229:        //
        !           230:        
        !           231:        if ( nodePtr->blockReadFromDisk )       // if we read it from disk then check it
        !           232:        {
        !           233:                err = CheckNode (btreePtr, nodePtr->buffer);
        !           234: 
        !           235:                if (err != noErr)
        !           236:                {       
        !           237:                
        !           238:                VTOVCB(btreePtr->fileRefNum)->vcbFlags |= kHFS_DamagedVolume;
        !           239: 
        !           240:                  #if HFS_DIAGNOSTIC
        !           241:                        if (((NodeDescPtr)nodePtr->buffer)->numRecords != 0)
        !           242:                                PrintNode(nodePtr->buffer, btreePtr->nodeSize, nodeNum);
        !           243:                  #endif
        !           244: 
        !           245:                        if (DEBUG_BUILD)
        !           246:                        {
        !           247:                                // With the removal of bounds checking in IsItAHint(), it's possible that
        !           248:                                // GetNode() will be called to fetch a clear (all zeroes) node. We want
        !           249:                                // CheckNode() to fail in this case (it does), however we don't want to assert
        !           250:                                // this case because it is not really an "error". Returning an error from GetNode()
        !           251:                                // in this case will cause the hint checking code to ignore the hint and revert to
        !           252:                                // the full search mode.
        !           253:                                
        !           254:                                {
        !           255:                                        UInt32  *cur;
        !           256:                                        UInt32  *lastPlusOne;
        !           257:                                        
        !           258:                                        cur             = nodePtr->buffer;
        !           259:                                        lastPlusOne = (UInt32 *) ((UInt8 *) cur + btreePtr->nodeSize);
        !           260:                                        
        !           261:                                        while( cur < lastPlusOne )
        !           262:                                        {
        !           263:                                                if( *cur++ != 0 )
        !           264:                                                {
        !           265:                                                        Panic ("\pGetNode: CheckNode returned error.");
        !           266:                                                        break;
        !           267:                                                }
        !           268:                                        }
        !           269:                                }
        !           270:                        }
        !           271:                        
        !           272:                        (void) ReleaseNode (btreePtr, nodePtr);                 // ignore error
        !           273:                        goto ErrorExit;
        !           274:                }
        !           275:        }
        !           276: 
        !           277:        LogEndTime(kTraceGetNode, noErr);
        !           278: 
        !           279:        return noErr;
        !           280: 
        !           281: ErrorExit:
        !           282:        nodePtr->buffer                 = nil;
        !           283:        nodePtr->blockHeader    = nil;
        !           284:        
        !           285:        LogEndTime(kTraceGetNode, err);
        !           286: 
        !           287:        return  err;
        !           288: }
        !           289: 
        !           290: 
        !           291: 
        !           292: /*-------------------------------------------------------------------------------
        !           293: 
        !           294: Routine:       GetNewNode      -       Call FS Agent to get a new node
        !           295: 
        !           296: Function:      Gets a new BTree node from FS Agent and initializes it to an empty
        !           297:                        state.
        !           298: 
        !           299: Input:         btreePtr                - pointer to BTree control block
        !           300:                        nodeNum                 - number of node to request
        !           301:                        
        !           302: Output:                returnNodePtr   - pointer to beginning of node (nil if error)
        !           303:                        
        !           304: Result:                noErr           - success
        !           305:                        != noErr        - failure
        !           306: -------------------------------------------------------------------------------*/
        !           307: 
        !           308: OSStatus       GetNewNode      (BTreeControlBlockPtr    btreePtr,
        !           309:                                                 UInt32                                  nodeNum,
        !           310:                                                 NodeRec                                *returnNodePtr )
        !           311: {
        !           312:        OSStatus                         err;
        !           313:        NodeDescPtr                      node;
        !           314:        void                            *pos;
        !           315:        GetBlockProcPtr          getNodeProc;
        !           316:        
        !           317: 
        !           318:        //////////////////////// get buffer for new node ////////////////////////////
        !           319: 
        !           320:        returnNodePtr->blockSize = btreePtr->nodeSize;  // indicate the size of a node
        !           321: 
        !           322:        getNodeProc = btreePtr->getBlockProc;
        !           323:        err = getNodeProc (btreePtr->fileRefNum,
        !           324:                                           nodeNum,
        !           325:                                           kGetBlock+kGetEmptyBlock,
        !           326:                                           returnNodePtr );
        !           327:                                           
        !           328:        if (err != noErr)
        !           329:        {
        !           330:                Panic ("\pGetNewNode: getNodeProc returned error.");
        !           331:        //      returnNodePtr->buffer = nil;
        !           332:                return err;
        !           333:        }
        !           334:        ++btreePtr->numGetNewNodes;
        !           335:        
        !           336: 
        !           337:        ////////////////////////// initialize the node //////////////////////////////
        !           338: 
        !           339:        node = returnNodePtr->buffer;
        !           340:        
        !           341:        ClearNode (btreePtr, node);                                             // clear the node
        !           342: 
        !           343:        pos = (char *)node + btreePtr->nodeSize - 2;    // find address of last offset
        !           344:        *(UInt16 *)pos = sizeof (BTNodeDescriptor);             // set offset to beginning of free space
        !           345: 
        !           346: 
        !           347:        return noErr;
        !           348: }
        !           349: 
        !           350: 
        !           351: 
        !           352: /*-------------------------------------------------------------------------------
        !           353: 
        !           354: Routine:       ReleaseNode     -       Call FS Agent to release node obtained by GetNode.
        !           355: 
        !           356: Function:      Informs the FS Agent that a BTree node may be released.
        !           357: 
        !           358: Input:         btreePtr                - pointer to BTree control block
        !           359:                        nodeNum                 - number of node to release
        !           360:                                                
        !           361: Result:                noErr           - success
        !           362:                        != noErr        - failure
        !           363: -------------------------------------------------------------------------------*/
        !           364: 
        !           365: OSStatus       ReleaseNode     (BTreeControlBlockPtr    btreePtr,
        !           366:                                                 NodePtr                                 nodePtr )
        !           367: {
        !           368:        OSStatus                         err;
        !           369:        ReleaseBlockProcPtr      releaseNodeProc;
        !           370:        
        !           371:        
        !           372:        LogStartTime(kTraceReleaseNode);
        !           373: 
        !           374:        err = noErr;
        !           375:        
        !           376:        if (nodePtr->buffer != nil)
        !           377:        {
        !           378:                releaseNodeProc = btreePtr->releaseBlockProc;
        !           379:                err = releaseNodeProc (btreePtr->fileRefNum,
        !           380:                                                           nodePtr,
        !           381:                                                           kReleaseBlock );
        !           382:                PanicIf (err, "\pReleaseNode: releaseNodeProc returned error.");
        !           383:                ++btreePtr->numReleaseNodes;
        !           384:        }
        !           385: 
        !           386:        nodePtr->buffer                 = nil;
        !           387:        nodePtr->blockHeader    = nil;
        !           388:        
        !           389:        LogEndTime(kTraceReleaseNode, err);
        !           390: 
        !           391:        return err;
        !           392: }
        !           393: 
        !           394: 
        !           395: 
        !           396: /*-------------------------------------------------------------------------------
        !           397: 
        !           398: Routine:       UpdateNode      -       Mark a node as dirty and call FS Agent to release it.
        !           399: 
        !           400: Function:      Marks a BTree node dirty and informs the FS Agent that it may be released.
        !           401: 
        !           402:                        //�� have another routine that clears & writes a node, so we can call
        !           403:                        CheckNode from this routine.
        !           404: 
        !           405: Input:         btreePtr                - pointer to BTree control block
        !           406:                        nodeNum                 - number of node to release
        !           407:                        transactionID   - ID of transaction this node update is a part of
        !           408:                        flags                   - special flags to pass to ReleaseNodeProc
        !           409:                                                
        !           410: Result:                noErr           - success
        !           411:                        != noErr        - failure
        !           412: -------------------------------------------------------------------------------*/
        !           413: 
        !           414: OSStatus       UpdateNode      (BTreeControlBlockPtr    btreePtr,
        !           415:                                                 NodePtr                                 nodePtr,
        !           416:                                                 UInt32                                  transactionID,
        !           417:                                                 UInt32                                  flags )
        !           418: {
        !           419:        OSStatus                         err;
        !           420:        ReleaseBlockProcPtr      releaseNodeProc;
        !           421:        
        !           422:        
        !           423:        err = noErr;
        !           424:                
        !           425:        if (nodePtr->buffer != nil)                     //�� why call UpdateNode if nil ?!?
        !           426:        {
        !           427:                if (DEBUG_BUILD)
        !           428:                {
        !           429:                        if ( btreePtr->attributes & kBTVariableIndexKeysMask )
        !           430:                                (void) CheckNode (btreePtr, nodePtr->buffer);
        !           431:                }
        !           432: 
        !           433:                LogStartTime(kTraceReleaseNode);
        !           434: 
        !           435:                releaseNodeProc = btreePtr->releaseBlockProc;
        !           436:                err = releaseNodeProc (btreePtr->fileRefNum,
        !           437:                                                           nodePtr,
        !           438:                                                           flags | kMarkBlockDirty );
        !           439:                                                           
        !           440:                LogEndTime(kTraceReleaseNode, err);
        !           441: 
        !           442:                M_ExitOnError (err);
        !           443:                ++btreePtr->numUpdateNodes;
        !           444:        }
        !           445:        
        !           446:        nodePtr->buffer                 = nil;
        !           447:        nodePtr->blockHeader    = nil;
        !           448: 
        !           449:        return  noErr;
        !           450: 
        !           451: ErrorExit:
        !           452:        
        !           453:        return  err;
        !           454: }
        !           455: 
        !           456: 
        !           457: 
        !           458: /*-------------------------------------------------------------------------------
        !           459: 
        !           460: Routine:       CheckNode       -       Checks the validity of a node.
        !           461: 
        !           462: Function:      Checks the validity of a node by verifying that the fLink and bLink fields
        !           463:                        are within the forks EOF. The node type must be one of the four known
        !           464:                        types. The node height must be less than or equal to the tree height. The
        !           465:                        node must not have more than the maximum number of records, and the record
        !           466:                        offsets must make sense.
        !           467: 
        !           468: Input:         btreePtr                - pointer to BTree control block
        !           469:                        node                    - pointer to node to check
        !           470:                                                
        !           471: Result:                noErr           - success
        !           472:                        fsBTInvalidNodeErr              - failure
        !           473: -------------------------------------------------------------------------------*/
        !           474: 
        !           475: OSStatus       CheckNode       (BTreeControlBlockPtr    btreePtr, NodeDescPtr   node )
        !           476: {
        !           477:        SInt32          index;
        !           478:        SInt32          maxRecords;
        !           479:        UInt32          maxNode;
        !           480:        UInt16          nodeSize;
        !           481:        UInt16          offset;
        !           482:        UInt16          prevOffset;
        !           483: 
        !           484:        nodeSize = btreePtr->nodeSize;
        !           485: 
        !           486:        ///////////////////// are fLink and bLink within EOF ////////////////////////
        !           487: 
        !           488:        maxNode = (GetFileControlBlock(btreePtr->fileRefNum)->fcbEOF / nodeSize) - 1;
        !           489: 
        !           490:        if ( (node->fLink > maxNode) || (node->bLink > maxNode) )
        !           491:                return fsBTInvalidNodeErr;
        !           492: 
        !           493:        /////////////// check node type (leaf, index, header, map) //////////////////
        !           494: 
        !           495:        if ( (node->kind < kBTLeafNode) || (node->kind > kBTMapNode) )
        !           496:                return fsBTInvalidNodeErr;
        !           497: 
        !           498:        ///////////////////// is node height > tree depth? //////////////////////////
        !           499: 
        !           500:        if ( node->height > btreePtr->treeDepth )
        !           501:                return fsBTInvalidNodeErr;
        !           502: 
        !           503:        //////////////////////// check number of records ////////////////////////////
        !           504:                
        !           505:        //XXX can we calculate a more accurate minimum record size?
        !           506:        maxRecords = ( nodeSize - sizeof (BTNodeDescriptor) ) >> 3;
        !           507:        
        !           508:        if (node->numRecords > maxRecords)
        !           509:                return fsBTInvalidNodeErr;
        !           510: 
        !           511:        ////////////////////////// check record offsets /////////////////////////////
        !           512: 
        !           513:        index = node->numRecords;               /* start index at free space */
        !           514:        prevOffset = nodeSize - (index << 1);   /* use 2 bytes past end of free space */
        !           515: 
        !           516:        do {
        !           517:                offset = GetRecordOffset (btreePtr, node, index);
        !           518:                        
        !           519:                if (offset & 1)                                                         // offset is odd
        !           520:                        return fsBTInvalidNodeErr;
        !           521:                
        !           522:                if (offset >= prevOffset)                                       // offset >= previous offset
        !           523:                        return fsBTInvalidNodeErr;
        !           524: 
        !           525:                /* reject keys that overflow record slot */
        !           526:                if ((node->kind == kBTLeafNode) &&
        !           527:                    (index < node->numRecords) &&       /* ignore free space record */
        !           528:                    (CalcKeySize(btreePtr, (KeyPtr) ((Ptr)node + offset)) > (prevOffset - offset))) {
        !           529:                        return fsBTInvalidNodeErr;
        !           530:                }
        !           531:                
        !           532:                prevOffset = offset;
        !           533:        } while ( --index >= 0 );
        !           534: 
        !           535:        if (offset < sizeof (BTNodeDescriptor) )        // first offset < minimum ?
        !           536:                return fsBTInvalidNodeErr;
        !           537:        
        !           538:        return noErr;
        !           539: }
        !           540: 
        !           541: 
        !           542: #if HFS_DIAGNOSTIC
        !           543: static void PrintNode(const NodeDescPtr node, UInt16 nodeSize, UInt32 nodeNumber)
        !           544: {
        !           545:        struct row {
        !           546:                UInt16  word[8];
        !           547:        };
        !           548:        struct row      *offset;
        !           549:        UInt16  rows;
        !           550:        UInt32  *lp;
        !           551: 
        !           552:        PRINTIT("Dump of B-tree node #%ld ($%08lX)\n", nodeNumber, nodeNumber);
        !           553: 
        !           554:        rows = nodeSize/16;
        !           555:        lp = (UInt32*) node;
        !           556:        offset = 0;
        !           557:        
        !           558:        while (rows-- > 0)
        !           559:                PRINTIT("%04X: %08lX %08lX %08lX %08lX\n", (u_int)offset++, *lp++, *lp++, *lp++, *lp++);
        !           560: }
        !           561: #endif
        !           562: 
        !           563: 
        !           564: /*-------------------------------------------------------------------------------
        !           565: 
        !           566: Routine:       ClearNode       -       Clear a node to all zeroes.
        !           567: 
        !           568: Function:      Writes zeroes from beginning of node for nodeSize bytes.
        !           569: 
        !           570: Input:         btreePtr                - pointer to BTree control block
        !           571:                        node                    - pointer to node to clear
        !           572:                                                
        !           573: Result:                none
        !           574: -------------------------------------------------------------------------------*/
        !           575: 
        !           576: void   ClearNode       (BTreeControlBlockPtr   btreePtr, NodeDescPtr    node )
        !           577: {
        !           578:        ClearMemory( node, btreePtr->nodeSize );
        !           579: }
        !           580: 
        !           581: /*-------------------------------------------------------------------------------
        !           582: 
        !           583: Routine:       InsertRecord    -       Inserts a record into a BTree node.
        !           584: 
        !           585: Function:      
        !           586: 
        !           587: Note:          Record size must be even!
        !           588: 
        !           589: Input:         btreePtr                - pointer to BTree control block
        !           590:                        node                    - pointer to node to insert the record
        !           591:                        index                   - position record is to be inserted
        !           592:                        recPtr                  - pointer to record to insert
        !           593: 
        !           594: Result:                noErr           - success
        !           595:                        fsBTFullErr     - record larger than remaining free space.
        !           596: -------------------------------------------------------------------------------*/
        !           597: 
        !           598: Boolean                InsertRecord    (BTreeControlBlockPtr   btreePtr,
        !           599:                                                         NodeDescPtr                    node,
        !           600:                                                         UInt16                                 index,
        !           601:                                                         RecordPtr                              recPtr,
        !           602:                                                         UInt16                                 recSize )
        !           603: {
        !           604:        UInt16          freeSpace;
        !           605:        UInt16          indexOffset;
        !           606:        UInt16          freeOffset;
        !           607:        UInt16          bytesToMove;
        !           608:        void       *src;
        !           609:        void       *dst;
        !           610:        
        !           611:        //// will new record fit in node?
        !           612: 
        !           613:        freeSpace = GetNodeFreeSize (btreePtr, node);
        !           614:                                                                                        //�� we could get freeOffset & calc freeSpace
        !           615:        if ( freeSpace < recSize + 2)
        !           616:        {
        !           617:                return false;
        !           618:        }
        !           619: 
        !           620:        
        !           621:        //// make hole for new record
        !           622: 
        !           623:        indexOffset = GetRecordOffset (btreePtr, node, index);
        !           624:        freeOffset      = GetRecordOffset (btreePtr, node, node->numRecords);
        !           625: 
        !           626:        src = ((Ptr) node) + indexOffset;
        !           627:        dst = ((Ptr) src)  + recSize;
        !           628:        bytesToMove = freeOffset - indexOffset;
        !           629:        MoveRecordsRight (src, dst, bytesToMove);
        !           630: 
        !           631: 
        !           632:        //// adjust offsets for moved records
        !           633: 
        !           634:        InsertOffset (btreePtr, node, index, recSize);
        !           635: 
        !           636: 
        !           637:        //// move in the new record
        !           638: 
        !           639:        dst = ((Ptr) node) + indexOffset;
        !           640:        MoveRecordsLeft (recPtr, dst, recSize);
        !           641: 
        !           642:        return true;
        !           643: }
        !           644: 
        !           645: 
        !           646: 
        !           647: /*-------------------------------------------------------------------------------
        !           648: 
        !           649: Routine:       InsertKeyRecord -       Inserts a record into a BTree node.
        !           650: 
        !           651: Function:      
        !           652: 
        !           653: Note:          Record size must be even!
        !           654: 
        !           655: Input:         btreePtr                - pointer to BTree control block
        !           656:                        node                    - pointer to node to insert the record
        !           657:                        index                   - position record is to be inserted
        !           658:                        keyPtr                  - pointer to key for record to insert
        !           659:                        keyLength               - length of key (or maxKeyLength)
        !           660:                        recPtr                  - pointer to record to insert
        !           661:                        recSize                 - number of bytes to copy for record
        !           662: 
        !           663: Result:                noErr           - success
        !           664:                        fsBTFullErr     - record larger than remaining free space.
        !           665: -------------------------------------------------------------------------------*/
        !           666: 
        !           667: Boolean                InsertKeyRecord         (BTreeControlBlockPtr    btreePtr,
        !           668:                                                                 NodeDescPtr                     node,
        !           669:                                                                 UInt16                                  index,
        !           670:                                                                 KeyPtr                                  keyPtr,
        !           671:                                                                 UInt16                                  keyLength,
        !           672:                                                                 RecordPtr                               recPtr,
        !           673:                                                                 UInt16                                  recSize )
        !           674: {
        !           675:        UInt16          freeSpace;
        !           676:        UInt16          indexOffset;
        !           677:        UInt16          freeOffset;
        !           678:        UInt16          bytesToMove;
        !           679:        UInt8 *         src;
        !           680:        UInt8 *         dst;
        !           681:        UInt16          keySize;
        !           682:        UInt16          rawKeyLength;
        !           683:        UInt16          sizeOfLength;
        !           684:        
        !           685:        //// calculate actual key size
        !           686: 
        !           687:        if ( btreePtr->attributes & kBTBigKeysMask )
        !           688:                keySize = keyLength + sizeof(UInt16);
        !           689:        else
        !           690:                keySize = keyLength + sizeof(UInt8);
        !           691:        
        !           692:        if ( M_IsOdd (keySize) )
        !           693:                ++keySize;                      // add pad byte
        !           694: 
        !           695: 
        !           696:        //// will new record fit in node?
        !           697: 
        !           698:        freeSpace = GetNodeFreeSize (btreePtr, node);
        !           699:                                                                                        //�� we could get freeOffset & calc freeSpace
        !           700:        if ( freeSpace < keySize + recSize + 2)
        !           701:        {
        !           702:                return false;
        !           703:        }
        !           704: 
        !           705:        
        !           706:        //// make hole for new record
        !           707: 
        !           708:        indexOffset = GetRecordOffset (btreePtr, node, index);
        !           709:        freeOffset      = GetRecordOffset (btreePtr, node, node->numRecords);
        !           710: 
        !           711:        src = ((UInt8 *) node) + indexOffset;
        !           712:        dst = ((UInt8 *) src) + keySize + recSize;
        !           713:        bytesToMove = freeOffset - indexOffset;
        !           714:        MoveRecordsRight (src, dst, bytesToMove);
        !           715: 
        !           716: 
        !           717:        //// adjust offsets for moved records
        !           718: 
        !           719:        InsertOffset (btreePtr, node, index, keySize + recSize);
        !           720:        
        !           721: 
        !           722:        //// copy record key
        !           723: 
        !           724:        dst = ((UInt8 *) node) + indexOffset;
        !           725: 
        !           726:        if ( btreePtr->attributes & kBTBigKeysMask )
        !           727:        {
        !           728:                *((UInt16*) dst)++ = keyLength;         // use keyLength rather than key.length
        !           729:                rawKeyLength = keyPtr->length16;
        !           730:                sizeOfLength = 2;
        !           731:        }
        !           732:        else
        !           733:        {
        !           734:                *dst++ = keyLength;                                     // use keyLength rather than key.length
        !           735:                rawKeyLength = keyPtr->length8;
        !           736:                sizeOfLength = 1;
        !           737:        }
        !           738:        
        !           739:        MoveRecordsLeft ( ((UInt8 *) keyPtr) + sizeOfLength, dst, rawKeyLength);        // copy key
        !           740: 
        !           741:        // any pad bytes?
        !           742:        bytesToMove = keySize - rawKeyLength;
        !           743:        if (bytesToMove)
        !           744:                ClearMemory (dst + rawKeyLength, bytesToMove);  // clear pad bytes in index key
        !           745: 
        !           746: 
        !           747:        //// copy record data
        !           748: 
        !           749:        dst = ((UInt8 *) node) + indexOffset + keySize;
        !           750:        MoveRecordsLeft (recPtr, dst, recSize);
        !           751: 
        !           752:        return true;
        !           753: }
        !           754: 
        !           755: 
        !           756: 
        !           757: /*-------------------------------------------------------------------------------
        !           758: 
        !           759: Routine:       DeleteRecord    -       Deletes a record from a BTree node.
        !           760: 
        !           761: Function:      
        !           762: 
        !           763: Input:         btreePtr                - pointer to BTree control block
        !           764:                        node                    - pointer to node to insert the record
        !           765:                        index                   - position record is to be inserted
        !           766: 
        !           767: Result:                none
        !           768: -------------------------------------------------------------------------------*/
        !           769: 
        !           770: void           DeleteRecord    (BTreeControlBlockPtr   btreePtr,
        !           771:                                                         NodeDescPtr                    node,
        !           772:                                                         UInt16                                 index )
        !           773: {
        !           774:        SInt16          indexOffset;
        !           775:        SInt16          nextOffset;
        !           776:        SInt16          freeOffset;
        !           777:        SInt16          bytesToMove;
        !           778:        void       *src;
        !           779:        void       *dst;
        !           780:        
        !           781:        //// compress records
        !           782:        indexOffset = GetRecordOffset (btreePtr, node, index);
        !           783:        nextOffset      = GetRecordOffset (btreePtr, node, index + 1);
        !           784:        freeOffset      = GetRecordOffset (btreePtr, node, node->numRecords);
        !           785: 
        !           786:        src = ((Ptr) node) + nextOffset;
        !           787:        dst = ((Ptr) node) + indexOffset;
        !           788:        bytesToMove = freeOffset - nextOffset;
        !           789:        MoveRecordsLeft (src, dst, bytesToMove);
        !           790: 
        !           791:        //// Adjust the offsets
        !           792:        DeleteOffset (btreePtr, node, index);
        !           793:        
        !           794:        /* clear out new free space */
        !           795:        bytesToMove = nextOffset - indexOffset;
        !           796:        ClearMemory(GetRecordAddress(btreePtr, node, node->numRecords), bytesToMove);
        !           797: 
        !           798: }
        !           799: 
        !           800: 
        !           801: 
        !           802: /*-------------------------------------------------------------------------------
        !           803: 
        !           804: Routine:       SearchNode      -       Return index for record that matches key.
        !           805: 
        !           806: Function:      Returns the record index for the record that matches the search key.
        !           807:                        If no record was found that matches the search key, the "insert index"
        !           808:                        of where the record should go is returned instead.
        !           809: 
        !           810: Algorithm:     A binary search algorithm is used to find the specified key.
        !           811: 
        !           812: Input:         btreePtr        - pointer to BTree control block
        !           813:                        node            - pointer to node that contains the record
        !           814:                        searchKey       - pointer to the key to match
        !           815: 
        !           816: Output:                index           - pointer to beginning of key for record
        !           817: 
        !           818: Result:                true    - success (index = record index)
        !           819:                        false   - key did not match anything in node (index = insert index)
        !           820: -------------------------------------------------------------------------------*/
        !           821: Boolean
        !           822: SearchNode( BTreeControlBlockPtr btreePtr,
        !           823:            NodeDescPtr node,
        !           824:            KeyPtr searchKey,
        !           825:            UInt16 *returnIndex )
        !           826: {
        !           827:        SInt32          lowerBound;
        !           828:        SInt32          upperBound;
        !           829:        SInt32          index;
        !           830:        SInt32          result;
        !           831:        KeyPtr          trialKey;
        !           832:        UInt16          *offset;
        !           833:        KeyCompareProcPtr compareProc = btreePtr->keyCompareProc;
        !           834: 
        !           835:        lowerBound = 0;
        !           836:        upperBound = node->numRecords - 1;
        !           837:        offset = (UInt16 *) ((UInt8 *)(node) + (btreePtr)->nodeSize - kOffsetSize);
        !           838:        
        !           839:        while (lowerBound <= upperBound) {
        !           840:                index = (lowerBound + upperBound) >> 1;
        !           841: 
        !           842:                trialKey = (KeyPtr) ((UInt8 *)node + *(offset - index));
        !           843:                
        !           844:                result = compareProc(searchKey, trialKey);
        !           845: 
        !           846:                if (result <  0) {
        !           847:                        upperBound = index - 1;   /* search < trial */
        !           848:                } else if (result >  0) {
        !           849:                        lowerBound = index + 1;   /* search > trial */
        !           850:                } else {        
        !           851:                        *returnIndex = index;     /* search == trial */
        !           852:                        return true;
        !           853:                }
        !           854:        }
        !           855:        
        !           856:        *returnIndex = lowerBound;      /* lowerBound is insert index */
        !           857:        return false;
        !           858: }
        !           859: 
        !           860: 
        !           861: /*-------------------------------------------------------------------------------
        !           862: 
        !           863: Routine:       GetRecordByIndex        -       Return pointer to key and data, and size of data.
        !           864: 
        !           865: Function:      Returns a pointer to beginning of key for record, a pointer to the
        !           866:                        beginning of the data for the record, and the size of the record data
        !           867:                        (does not include the size of the key).
        !           868: 
        !           869: Input:         btreePtr        - pointer to BTree control block
        !           870:                        node            - pointer to node that contains the record
        !           871:                        index           - index of record to get
        !           872: 
        !           873: Output:                keyPtr          - pointer to beginning of key for record
        !           874:                        dataPtr         - pointer to beginning of data for record
        !           875:                        dataSize        - size of the data portion of the record
        !           876: 
        !           877: Result:                none
        !           878: -------------------------------------------------------------------------------*/
        !           879: 
        !           880: OSStatus       GetRecordByIndex        (BTreeControlBlockPtr    btreePtr,
        !           881:                                                                 NodeDescPtr                     node,
        !           882:                                                                 UInt16                                  index,
        !           883:                                                                 KeyPtr                                 *keyPtr,
        !           884:                                                                 UInt8 *                                *dataPtr,
        !           885:                                                                 UInt16                                 *dataSize )
        !           886: {
        !           887:        UInt16          offset;
        !           888:        UInt16          nextOffset;
        !           889:        UInt16          keySize;
        !           890:        
        !           891:        //
        !           892:        //      Make sure index is valid (in range 0..numRecords-1)
        !           893:        //
        !           894:        if (index >= node->numRecords)
        !           895:                return fsBTRecordNotFoundErr;
        !           896: 
        !           897:        //// find keyPtr
        !           898:        offset          = GetRecordOffset (btreePtr, node, index);
        !           899:        *keyPtr         = (KeyPtr) ((Ptr)node + offset);
        !           900: 
        !           901:        //// find dataPtr
        !           902:        keySize = CalcKeySize(btreePtr, *keyPtr);
        !           903:        if ( M_IsOdd (keySize) )
        !           904:                ++keySize;      // add pad byte
        !           905: 
        !           906:        offset += keySize;                      // add the key length to find data offset
        !           907:        *dataPtr = (UInt8 *) node + offset;
        !           908:        
        !           909:        //// find dataSize
        !           910:        nextOffset      = GetRecordOffset (btreePtr, node, index + 1);
        !           911:        *dataSize       = nextOffset - offset;
        !           912:        
        !           913:        return noErr;
        !           914: }
        !           915:                                                                 
        !           916: 
        !           917: 
        !           918: /*-------------------------------------------------------------------------------
        !           919: 
        !           920: Routine:       GetNodeDataSize -       Return the amount of space used for data in the node.
        !           921: 
        !           922: Function:      Gets the size of the data currently contained in a node, excluding
        !           923:                        the node header. (record data + offset overhead)
        !           924: 
        !           925: Input:         btreePtr                - pointer to BTree control block
        !           926:                        node                    - pointer to node that contains the record
        !           927: 
        !           928: Result:                - number of bytes used for data and offsets in the node.
        !           929: -------------------------------------------------------------------------------*/
        !           930: 
        !           931: UInt16         GetNodeDataSize (BTreeControlBlockPtr   btreePtr, NodeDescPtr    node )
        !           932: {
        !           933:        UInt16 freeOffset;
        !           934:        
        !           935:        freeOffset = GetRecordOffset (btreePtr, node, node->numRecords);
        !           936:        
        !           937:        return  freeOffset + (node->numRecords << 1) - sizeof (BTNodeDescriptor);
        !           938: }
        !           939: 
        !           940: 
        !           941: 
        !           942: /*-------------------------------------------------------------------------------
        !           943: 
        !           944: Routine:       GetNodeFreeSize -       Return the amount of free space in the node.
        !           945: 
        !           946: Function:      
        !           947: 
        !           948: Input:         btreePtr                - pointer to BTree control block
        !           949:                        node                    - pointer to node that contains the record
        !           950: 
        !           951: Result:                - number of bytes of free space in the node.
        !           952: -------------------------------------------------------------------------------*/
        !           953: 
        !           954: UInt16         GetNodeFreeSize (BTreeControlBlockPtr   btreePtr, NodeDescPtr    node )
        !           955: {
        !           956:        UInt16  freeOffset;
        !           957:        
        !           958:        freeOffset = GetRecordOffset (btreePtr, node, node->numRecords);        //�� inline?
        !           959:        
        !           960:        return btreePtr->nodeSize - freeOffset - (node->numRecords << 1) - kOffsetSize;
        !           961: }
        !           962: 
        !           963: 
        !           964: 
        !           965: /*-------------------------------------------------------------------------------
        !           966: 
        !           967: Routine:       GetRecordOffset -       Return the offset for record "index".
        !           968: 
        !           969: Function:      
        !           970: 
        !           971: Input:         btreePtr                - pointer to BTree control block
        !           972:                        node                    - pointer to node that contains the record
        !           973:                        index                   - record to obtain offset for
        !           974: 
        !           975: Result:                - offset (in bytes) from beginning of node of record specified by index
        !           976: -------------------------------------------------------------------------------*/
        !           977: // make this a macro (for inlining)
        !           978: #if 0
        !           979: UInt16         GetRecordOffset (BTreeControlBlockPtr   btreePtr,
        !           980:                                                         NodeDescPtr                    node,
        !           981:                                                         UInt16                                 index )
        !           982: {
        !           983:        void    *pos;
        !           984:        
        !           985:                
        !           986:        pos = (UInt8 *)node + btreePtr->nodeSize - (index << 1) - kOffsetSize;
        !           987:        
        !           988:        return *(short *)pos;
        !           989: }
        !           990: #endif
        !           991: 
        !           992: 
        !           993: 
        !           994: /*-------------------------------------------------------------------------------
        !           995: 
        !           996: Routine:       GetRecordAddress        -       Return address of record "index".
        !           997: 
        !           998: Function:      
        !           999: 
        !          1000: Input:         btreePtr                - pointer to BTree control block
        !          1001:                        node                    - pointer to node that contains the record
        !          1002:                        index                   - record to obtain offset address for
        !          1003: 
        !          1004: Result:                - pointer to record "index".
        !          1005: -------------------------------------------------------------------------------*/
        !          1006: // make this a macro (for inlining)
        !          1007: #if 0
        !          1008: UInt8 *                GetRecordAddress        (BTreeControlBlockPtr   btreePtr,
        !          1009:                                                                 NodeDescPtr                    node,
        !          1010:                                                                 UInt16                                 index )
        !          1011: {
        !          1012:        UInt8 *         pos;
        !          1013:        
        !          1014:        pos = (UInt8 *)node + GetRecordOffset (btreePtr, node, index);
        !          1015:        
        !          1016:        return pos;
        !          1017: }
        !          1018: #endif
        !          1019: 
        !          1020: 
        !          1021: 
        !          1022: /*-------------------------------------------------------------------------------
        !          1023: 
        !          1024: Routine:       GetRecordSize   -       Return size of record "index".
        !          1025: 
        !          1026: Function:      
        !          1027: 
        !          1028: Note:          This does not work on the FreeSpace index!
        !          1029: 
        !          1030: Input:         btreePtr                - pointer to BTree control block
        !          1031:                        node                    - pointer to node that contains the record
        !          1032:                        index                   - record to obtain record size for
        !          1033: 
        !          1034: Result:                - size of record "index".
        !          1035: -------------------------------------------------------------------------------*/
        !          1036: 
        !          1037: UInt16         GetRecordSize           (BTreeControlBlockPtr   btreePtr,
        !          1038:                                                                 NodeDescPtr                    node,
        !          1039:                                                                 UInt16                                 index )
        !          1040: {
        !          1041:        UInt16  *pos;
        !          1042:                
        !          1043:        pos = (UInt16 *) ((Ptr)node + btreePtr->nodeSize - (index << 1) - kOffsetSize);
        !          1044:        
        !          1045:        return  *(pos-1) - *pos;
        !          1046: }
        !          1047: 
        !          1048: 
        !          1049: 
        !          1050: /*-------------------------------------------------------------------------------
        !          1051: Routine:       GetOffsetAddress        -       Return address of offset for record "index".
        !          1052: 
        !          1053: Function:      
        !          1054: 
        !          1055: Input:         btreePtr                - pointer to BTree control block
        !          1056:                        node                    - pointer to node that contains the record
        !          1057:                        index                   - record to obtain offset address for
        !          1058: 
        !          1059: Result:                - pointer to offset for record "index".
        !          1060: -------------------------------------------------------------------------------*/
        !          1061: 
        !          1062: UInt16    *GetOffsetAddress    (BTreeControlBlockPtr   btreePtr,
        !          1063:                                                                 NodeDescPtr                    node,
        !          1064:                                                                 UInt16                                 index )
        !          1065: {
        !          1066:        void    *pos;
        !          1067:        
        !          1068:        pos = (Ptr)node + btreePtr->nodeSize - (index << 1) -2;
        !          1069:        
        !          1070:        return (UInt16 *)pos;
        !          1071: }
        !          1072: 
        !          1073: 
        !          1074: 
        !          1075: /*-------------------------------------------------------------------------------
        !          1076: Routine:       GetChildNodeNum -       Return child node number from index record "index".
        !          1077: 
        !          1078: Function:      Returns the first UInt32 stored after the key for record "index".
        !          1079: 
        !          1080: Assumes:       The node is an Index Node.
        !          1081:                        The key.length stored at record "index" is ODD. //�� change for variable length index keys
        !          1082: 
        !          1083: Input:         btreePtr                - pointer to BTree control block
        !          1084:                        node                    - pointer to node that contains the record
        !          1085:                        index                   - record to obtain child node number from
        !          1086: 
        !          1087: Result:                - child node number from record "index".
        !          1088: -------------------------------------------------------------------------------*/
        !          1089: 
        !          1090: UInt32         GetChildNodeNum                 (BTreeControlBlockPtr    btreePtr,
        !          1091:                                                                         NodeDescPtr                     nodePtr,
        !          1092:                                                                         UInt16                                  index )
        !          1093: {
        !          1094:        UInt8 *         pos;
        !          1095:        
        !          1096:        pos = GetRecordAddress (btreePtr, nodePtr, index);
        !          1097:        pos += CalcKeySize(btreePtr, (BTreeKey *) pos);         // key.length + size of length field
        !          1098:        
        !          1099:        return  *(UInt32 *)pos;
        !          1100: }
        !          1101: 
        !          1102: 
        !          1103: 
        !          1104: /*-------------------------------------------------------------------------------
        !          1105: Routine:       InsertOffset    -       Add an offset and adjust existing offsets by delta.
        !          1106: 
        !          1107: Function:      Add an offset at 'index' by shifting 'index+1' through the last offset
        !          1108:                        and adjusting them by 'delta', the size of the record to be inserted.
        !          1109:                        The number of records contained in the node is also incremented.
        !          1110: 
        !          1111: Input:         btreePtr        - pointer to BTree control block
        !          1112:                        node            - pointer to node
        !          1113:                        index           - index at which to insert record
        !          1114:                        delta           - size of record to be inserted
        !          1115: 
        !          1116: Result:                none
        !          1117: -------------------------------------------------------------------------------*/
        !          1118: 
        !          1119: void           InsertOffset            (BTreeControlBlockPtr    btreePtr,
        !          1120:                                                                 NodeDescPtr                     node,
        !          1121:                                                                 UInt16                                  index,
        !          1122:                                                                 UInt16                                  delta )
        !          1123: {
        !          1124:        UInt16          *src, *dst;
        !          1125:        UInt16           numOffsets;
        !          1126:        
        !          1127:        src = GetOffsetAddress (btreePtr, node, node->numRecords);      // point to free offset
        !          1128:        dst = src - 1;                                                                                          // point to new offset
        !          1129:        numOffsets = node->numRecords++ - index;                        // subtract index  & postincrement
        !          1130:        
        !          1131:        do {
        !          1132:                *dst++ = *src++ + delta;                                                                // to tricky?
        !          1133:        } while (numOffsets--);
        !          1134: }
        !          1135: 
        !          1136: 
        !          1137: 
        !          1138: /*-------------------------------------------------------------------------------
        !          1139: 
        !          1140: Routine:       DeleteOffset    -       Delete an offset.
        !          1141: 
        !          1142: Function:      Delete the offset at 'index' by shifting 'index+1' through the last offset
        !          1143:                        and adjusting them by the size of the record 'index'.
        !          1144:                        The number of records contained in the node is also decremented.
        !          1145: 
        !          1146: Input:         btreePtr        - pointer to BTree control block
        !          1147:                        node            - pointer to node
        !          1148:                        index           - index at which to delete record
        !          1149: 
        !          1150: Result:                none
        !          1151: -------------------------------------------------------------------------------*/
        !          1152: 
        !          1153: void           DeleteOffset            (BTreeControlBlockPtr    btreePtr,
        !          1154:                                                                 NodeDescPtr                     node,
        !          1155:                                                                 UInt16                                  index )
        !          1156: {
        !          1157:        UInt16          *src, *dst;
        !          1158:        UInt16           numOffsets;
        !          1159:        UInt16           delta;
        !          1160:        
        !          1161:        dst                     = GetOffsetAddress (btreePtr, node, index);
        !          1162:        src                     = dst - 1;
        !          1163:        delta           = *src - *dst;
        !          1164:        numOffsets      = --node->numRecords - index;   // predecrement numRecords & subtract index
        !          1165:        
        !          1166:        while (numOffsets--)
        !          1167:        {
        !          1168:                *--dst = *--src - delta;                                // work our way left
        !          1169:        }
        !          1170: }
        !          1171: 
        !          1172: 
        !          1173: 
        !          1174: /*-------------------------------------------------------------------------------
        !          1175: 
        !          1176: Routine:       MoveRecordsLeft -       Move records left within a node.
        !          1177: 
        !          1178: Function:      Moves a number of bytes from src to dst. Safely handles overlapping
        !          1179:                        ranges if the bytes are being moved to the "left". No bytes are moved
        !          1180:                        if bytesToMove is zero.
        !          1181: 
        !          1182: Input:         src                             - pointer to source
        !          1183:                        dst                             - pointer to destination
        !          1184:                        bytesToMove             - number of bytes to move records
        !          1185: 
        !          1186: Result:                none
        !          1187: -------------------------------------------------------------------------------*/
        !          1188: #if BCOPY_BROKEN
        !          1189: void           MoveRecordsLeft         (UInt8 *                                 src,
        !          1190:                                                                 UInt8 *                                 dst,
        !          1191:                                                                 UInt16                                  bytesToMove )
        !          1192: {
        !          1193:        while (bytesToMove--)
        !          1194:                *dst++ = *src++;
        !          1195: }
        !          1196: #endif                                                  
        !          1197: 
        !          1198: 
        !          1199: /*-------------------------------------------------------------------------------
        !          1200: 
        !          1201: Routine:       MoveRecordsRight        -       Move records right within a node.
        !          1202: 
        !          1203: Function:      Moves a number of bytes from src to dst. Safely handles overlapping
        !          1204:                        ranges if the bytes are being moved to the "right". No bytes are moved
        !          1205:                        if bytesToMove is zero.
        !          1206: 
        !          1207: Input:         src                             - pointer to source
        !          1208:                        dst                             - pointer to destination
        !          1209:                        bytesToMove             - number of bytes to move records
        !          1210:                        
        !          1211: Result:                none
        !          1212: -------------------------------------------------------------------------------*/
        !          1213: #if BCOPY_BROKEN
        !          1214: void           MoveRecordsRight        (UInt8 *                                 src,
        !          1215:                                                                 UInt8 *                                 dst,
        !          1216:                                                                 UInt16                                  bytesToMove )
        !          1217: {
        !          1218:        src += bytesToMove;
        !          1219:        dst += bytesToMove;
        !          1220:        
        !          1221:        while (bytesToMove--)
        !          1222:                *--dst = *--src;
        !          1223: }
        !          1224: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.