Annotation of XNU/bsd/hfs/hfscommon/BTree/BTree.c, revision 1.1.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:           BTree.c
                     24: 
                     25:        Contains:       Implementation of public interface routines for B-tree manager.
                     26: 
                     27:        Version:        HFS Plus 1.0
                     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:                (DSH)   Deric Horn
                     45:                (djb)   Don Brady
                     46: 
                     47:        Change History (most recent first):
                     48:          <MOSXS>        9/22/99        ser             Added routines  BTGetLastSync and BTSetLastSync
                     49:           <MOSXS>        6/1/99        djb             Sync up with Mac OS 8.6.
                     50:           <MOSXS>       6/30/98        djb             In BTOpenPath make sure nodes are contiguous on disk (radar #2249539).
                     51:           <MOSXS>       4/15/98        djb             In BTOpenPath need to clear nodeRec.buffer if GetBlockProc fails.
                     52:           <MOSXS>       4/11/98        djb             Add RequireFileLock checking to all external entry points.
                     53: 
                     54:           <MOSXS>      03/23/98        djb             In BTOpenPath use kTrashBlock option when releasing the header so
                     55:                                                                        that we get a full node when we call GetNode. 
                     56: 
                     57:           <CS9>        12/12/97        djb             Radar #2202682, BTIterateRecord with kBTreeCurrentRecord was not
                     58:                                                                        checking if we had a record and could call BlockMove with an
                     59:                                                                        uninitialize source pointer (causing a bus error).
                     60:           <CS8>        10/24/97        msd             In BTIterateRecord, when moving to the previous or next record
                     61:                                                                        and we have to move to another node, see if we need to release
                     62:                                                                        the node about to be "shifted out" (opposite sibling of the
                     63:                                                                        direction we need to move).
                     64:           <CS7>         7/25/97        DSH             BTSearchRecord now takes a heuristicHint, nodeNum, and tries it
                     65:                                                                        before calling SearchBTree
                     66:           <CS6>         7/24/97        djb             GetBlockProc now take a file refnum instead of an FCB ptr.
                     67:           <CS5>         7/22/97        djb             Move trace points from BTreeWrapper.c to here.
                     68:           <CS4>         7/21/97        djb             LogEndTime now takes an error code.
                     69:           <CS3>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
                     70:                                                                        collision
                     71:           <CS2>         5/19/97        djb             Add summary traces to BTIterateRecord.
                     72:           <CS1>         4/23/97        djb             first checked in
                     73: 
                     74:          <HFS7>         2/19/97        djb             Enable variable sized index keys for HFS+ volumes. Added node
                     75:                                                                        cache to support nodes larger than 512 bytes.
                     76:          <HFS6>         1/27/97        djb             Calls to InsertTree and DeleteTree are now recursive (to support
                     77:                                                                        variable sized index keys).
                     78:          <HFS5>         1/13/97        djb             Added support for getting current record to BTIterateRecord.
                     79:          <HFS4>          1/6/97        djb             Initialize "BigKeys" attribute in BTOpen.
                     80:          <HFS3>          1/3/97        djb             Added support for large keys.
                     81:          <HFS2>        12/23/96        djb             On exit map fsBTEmptyErr and fsBTEndOfIterationErr to
                     82:                                                                        fsBTRecordNotFoundErr.
                     83:          <HFS1>        12/19/96        djb             first checked in
                     84: 
                     85:        History applicable to original Scarecrow Design:
                     86: 
                     87:                <13>    10/25/96        ser             Changing for new VFPI
                     88:                <12>    10/18/96        ser             Converting over VFPI changes
                     89:                <11>     9/17/96        dkh             More BTree statistics. Modified hint checks to not bail out when
                     90:                                                                        an error is returned from GetNode.
                     91:                <10>     9/16/96        dkh             Revised BTree statistics.
                     92:                 <9>     8/23/96        dkh             Remove checks for multiple paths to BTree file. Need to add
                     93:                                                                        equivalent mechanism later.
                     94:                 <8>     6/20/96        dkh             Radar #1358740. Switch from using Pools to debug MemAllocators.
                     95:                 <7>     3/14/96        jev             Fix BTreeSetRecord, recordFound was not set for the case of a
                     96:                                                                        simple replace causing the leafRecords count to get bumped even
                     97:                                                                        though we didn't have to add a record.
                     98:                 <6>      3/1/96        prp             Fix lint problems. Bug in BTSetRecord that does not initialize
                     99:                                                                        recordFound.
                    100:                 <5>     1/22/96        dkh             Add #include Memory.h
                    101:                 <4>     1/10/96        msd             Use the real function names from Math64.i.
                    102:                 <3>      1/4/96        jev             Fix BTItererateRecord for the condition when the iterator
                    103:                                                                        position routine does not find the record and we are looking for
                    104:                                                                        the next record. In such a case, if the node's forrward link is
                    105:                                                                        non-zero, we have to keep iterating next and not return
                    106:                                                                        fsBTEndOfIterationErr error.
                    107:                 <2>     12/7/95        dkh             D10E2 build. Changed usage of Ref data type to LogicalAddress.
                    108:                 <1>    10/18/95        rst             Moved from Scarecrow project.
                    109: 
                    110:                <24>     7/18/95        mbb             Change MoveData & ClearBytes to BlockMoveData & BlockZero.
                    111:                <23>     1/31/95        prp             GetBlockProc interface uses a 64 bit node number.
                    112:                <22>     1/12/95        wjk             Adopt Model FileSystem changes in D5.
                    113:                <21>    11/16/94        prp             Add IsItAHint routine and use it whenever hint's node number was
                    114:                                                                        used for testing.
                    115:                <20>    11/10/94        prp             BTGetInfo name collides with the same name in FileManagerPriv.i.
                    116:                                                                        Change it to BTGetInformation.
                    117:                <19>     9/30/94        prp             Get in sync with D2 interface changes.
                    118:                <18>     7/22/94        wjk             Convert to the new set of header files.
                    119:                <17>     12/9/93        wjk             Cleanup usage of char, Byte, int8, UInt8, etc.
                    120:                <16>     12/2/93        wjk             Move from Makefiles to BuildFiles. Fit into the ModernOS and
                    121:                                                                        NRCmds environments.
                    122:                <15>    11/30/93        wjk             Move from Makefiles to BuildFiles. Fit into the ModernOS and
                    123:                                                                        NRCmds environments.
                    124:                <14>     9/30/93        gs              Rename E_NoGetNodeProc and E_NoReleaseNodeProc to
                    125:                                                                        E_NoXxxxBlockProc.
                    126:                <13>     8/31/93        prp             Use Set64U instead of Set64.
                    127:                <12>     8/16/93        prp             In BTSearchRecord, if the input hint found the node and record,
                    128:                                                                        set the local nodeNum variable correctly so that the resultant
                    129:                                                                        iterator gets set correctly.
                    130:                <11>      7/1/93        gs              Fix bug in BTIterateRecord related to kBTreePrevRecord
                    131:                                                                        operation.
                    132:                <10>      6/2/93        gs              Update for changes to FSErrors.h and add some comments.
                    133:                 <9>     5/24/93        gs              Fix bug in BTInsert/Set/ReplaceRecord which didn't set node hint
                    134:                                                                        properly in some cases.
                    135:                 <8>     5/24/93        gs              Do NOT map fsBTEmptyErr to fsBTRecordNotFoundErr in BTSearchRecord.
                    136:                 <7>     5/24/93        gs              Rename BTFlush to BTFlushPath.
                    137:                 <6>     5/21/93        gs              Add hint optimization to Set/Replace routines.
                    138:                 <5>     5/10/93        gs              Remove Panic from BTInitialize for small logicalEOF. Implement
                    139:                                                                        Insert, Set, Replace, and Delete.
                    140:                 <4>     3/23/93        gs              Finish BTInitialize.
                    141:                 <3>      2/8/93        gs              Implement BTSearchRecord and BTIterateRecord.
                    142:                 <2>     12/8/92        gs              Implement Open and Close routines.
                    143:                 <1>    11/15/92        gs              first checked in
                    144: 
                    145: */
                    146: 
                    147: #include "../headers/BTreesPrivate.h"
                    148: 
                    149: #include "../headers/HFSInstrumentation.h"
                    150: 
                    151: 
                    152: //////////////////////////////////// Globals ////////////////////////////////////
                    153: 
                    154: 
                    155: /////////////////////////// BTree Module Entry Points ///////////////////////////
                    156: 
                    157: 
                    158: 
                    159: /*-------------------------------------------------------------------------------
                    160: Routine:       BTOpenPath      -       Open a file for access as a B*Tree.
                    161: 
                    162: Function:      Create BTree control block for a file, if necessary. Validates the
                    163:                        file to be sure it looks like a BTree file.
                    164: 
                    165: 
                    166: Input:         filePtr                         - pointer to file to open as a B-tree
                    167:                        keyCompareProc          - pointer to client's KeyCompare function
                    168:                        getBlockProc            - pointer to client's GetBlock function
                    169:                        releaseBlockProc        - pointer to client's ReleaseBlock function
                    170:                        setEndOfForkProc        - pointer to client's SetEOF function
                    171: 
                    172: Result:                noErr                           - success
                    173:                        paramErr                        - required ptr was nil
                    174:                        fsBTInvalidFileErr                              -
                    175:                        memFullErr                      -
                    176:                        != noErr                        - failure
                    177: -------------------------------------------------------------------------------*/
                    178: 
                    179: OSStatus       BTOpenPath                      (FCB                                    *filePtr,
                    180:                                                                 KeyCompareProcPtr               keyCompareProc,
                    181:                                                                 GetBlockProcPtr                 getBlockProc,
                    182:                                                                 ReleaseBlockProcPtr     releaseBlockProc,
                    183:                                                                 SetEndOfForkProcPtr     setEndOfForkProc,
                    184:                                                                 SetBlockSizeProcPtr     setBlockSizeProc )
                    185: {
                    186:        OSStatus                                err;
                    187:        BTreeControlBlockPtr    btreePtr;
                    188:        BTHeaderRec                             *header;
                    189:        NodeRec                                 nodeRec;
                    190: 
                    191:        LogStartTime(kTraceOpenBTree);
                    192: 
                    193:        ////////////////////// Preliminary Error Checking ///////////////////////////
                    194: 
                    195:        if ( filePtr == nil                             ||
                    196:                 getBlockProc == nil            ||
                    197:                 releaseBlockProc == nil        ||
                    198:                 setEndOfForkProc == nil        ||
                    199:                 setBlockSizeProc == nil )
                    200:        {
                    201:                return  paramErr;
                    202:        }
                    203: 
                    204:        if ( filePtr->fcbBTCBPtr != nil )                       // already has a BTreeCB
                    205:                return noErr;
                    206: 
                    207:                                                                                                // is file large enough to contain header node?
                    208:        if ( filePtr->fcbEOF < kMinNodeSize )
                    209:                return fsBTInvalidFileErr;                                                      //�� or E_BadHeader?
                    210: 
                    211: 
                    212:        //////////////////////// Allocate Control Block /////////////////////////////
                    213: 
                    214:        btreePtr = (BTreeControlBlock*) NewPtrSysClear( sizeof( BTreeControlBlock ) );
                    215:        if (btreePtr == nil)
                    216:        {
                    217:                Panic ("\pBTOpen: no memory for btreePtr.");
                    218:                return  memFullErr;
                    219:        }
                    220: 
                    221:        btreePtr->getBlockProc          = getBlockProc;
                    222:        btreePtr->releaseBlockProc      = releaseBlockProc;
                    223:        btreePtr->setEndOfForkProc      = setEndOfForkProc;
                    224:        btreePtr->keyCompareProc        = keyCompareProc;
                    225: 
                    226:        /////////////////////////// Read Header Node ////////////////////////////////
                    227: 
                    228:        nodeRec.buffer                          = nil;                          // so we can call ReleaseNode
                    229:        nodeRec.blockSize                       = kMinNodeSize;
                    230:        btreePtr->fileRefNum            = GetFileRefNumFromFCB(filePtr);
                    231:        filePtr->fcbBTCBPtr                     = (Ptr) btreePtr;       // attach btree cb to file
                    232: 
                    233:        RequireFileLock(btreePtr->fileRefNum, false);
                    234: 
                    235:        // it is now safe to call M_ExitOnError (err)
                    236: 
                    237:        err = setBlockSizeProc (btreePtr->fileRefNum, kMinNodeSize, 1);
                    238:        M_ExitOnError (err);
                    239: 
                    240: 
                    241:        err = getBlockProc (btreePtr->fileRefNum,
                    242:                                                kHeaderNodeNum,
                    243:                                                kGetBlock,
                    244:                                                &nodeRec );
                    245:        if (err != noErr)
                    246:        {
                    247:                nodeRec.buffer = nil;
                    248:                nodeRec.blockHeader     = nil;
                    249:                Panic("\pBTOpen: getNodeProc returned error getting header node.");
                    250:                goto ErrorExit;
                    251:        }
                    252: 
                    253:        header = (BTHeaderRec*) ((u_long)nodeRec.buffer + sizeof(BTNodeDescriptor));
                    254: 
                    255: 
                    256:        ///////////////////////////// verify header /////////////////////////////////
                    257: 
                    258:        err = VerifyHeader (filePtr, header);
                    259:        M_ExitOnError (err);
                    260: 
                    261: 
                    262:        ///////////////////// Initalize fields from header //////////////////////////
                    263:        
                    264:     PanicIf ( (FCBTOVCB(filePtr)->vcbSigWord != 0x4244) && (header->nodeSize == 512), "\p BTOpenPath: wrong node size for HFS+ volume!");      // 0x4244 = 'BD'
                    265: 
                    266:        btreePtr->treeDepth                     = header->treeDepth;
                    267:        btreePtr->rootNode                      = header->rootNode;
                    268:        btreePtr->leafRecords           = header->leafRecords;
                    269:        btreePtr->firstLeafNode         = header->firstLeafNode;
                    270:        btreePtr->lastLeafNode          = header->lastLeafNode;
                    271:        btreePtr->nodeSize                      = header->nodeSize;
                    272:        btreePtr->maxKeyLength          = header->maxKeyLength;
                    273:        btreePtr->totalNodes            = header->totalNodes;
                    274:        btreePtr->freeNodes                     = header->freeNodes;
                    275:        // ignore                                         header->clumpSize;    //�� rename this field?
                    276:        btreePtr->btreeType                     = header->btreeType;
                    277: 
                    278:        btreePtr->attributes            = header->attributes;
                    279: 
                    280:        if ( btreePtr->maxKeyLength > 40 )
                    281:                btreePtr->attributes |= (kBTBigKeysMask + kBTVariableIndexKeysMask);    //�� we need a way to save these attributes
                    282: 
                    283:        /////////////////////// Initialize dynamic fields ///////////////////////////
                    284: 
                    285:        btreePtr->version                       = kBTreeVersion;
                    286:        btreePtr->flags                         = 0;
                    287:        btreePtr->writeCount            = 1;
                    288: 
                    289:        btreePtr->numGetNodes           = 1;            // for earlier call to getNodeProc
                    290: 
                    291:        /////////////////////////// Check Header Node ///////////////////////////////
                    292: 
                    293:        //�� set kBadClose attribute bit, and UpdateNode
                    294: 
                    295:        // if nodeSize is 512 then we don't need to release, just CheckNode
                    296: 
                    297:        if ( btreePtr->nodeSize == kMinNodeSize )
                    298:        {
                    299:                err = CheckNode (btreePtr, nodeRec.buffer);
                    300:                if (err)
                    301:                        VTOVCB(btreePtr->fileRefNum)->vcbFlags |= kHFS_DamagedVolume;
                    302:                M_ExitOnError (err);
                    303:        }
                    304:        else
                    305:        {
                    306:                err = setBlockSizeProc (btreePtr->fileRefNum, btreePtr->nodeSize, 32);  //���we should try and get this down to 8
                    307:                M_ExitOnError (err);
                    308: 
                    309:                /*
                    310:                 * Need to use kTrashBlock option to force the
                    311:                 * buffer cache to read the entire node
                    312:                 */
                    313:                err = releaseBlockProc(btreePtr->fileRefNum, &nodeRec, kTrashBlock);
                    314:                M_ExitOnError (err);
                    315: 
                    316:                err = GetNode (btreePtr, kHeaderNodeNum, &nodeRec );            // calls CheckNode...
                    317:                M_ExitOnError (err);
                    318:        }
                    319: 
                    320:        //�� total nodes * node size <= LEOF?
                    321: 
                    322: 
                    323:        err = ReleaseNode (btreePtr, &nodeRec);
                    324:        M_ExitOnError (err);
                    325: 
                    326:        /*
                    327:         * Under Mac OS, b-tree nodes can be non-contiguous on disk when the
                    328:         * allocation block size is smaller than the b-tree node size.
                    329:         */
                    330:        if ( !NodesAreContiguous(FCBTOVCB(filePtr), filePtr, btreePtr->nodeSize) )
                    331:                return fsBTInvalidNodeErr;
                    332: 
                    333:        //////////////////////////////// Success ////////////////////////////////////
                    334: 
                    335:        //�� align LEOF to multiple of node size?       - just on close
                    336: 
                    337:        LogEndTime(kTraceOpenBTree, noErr);
                    338: 
                    339:        return noErr;
                    340: 
                    341: 
                    342:        /////////////////////// Error - Clean up and Exit ///////////////////////////
                    343: 
                    344: ErrorExit:
                    345: 
                    346:        filePtr->fcbBTCBPtr = nil;
                    347:        (void) ReleaseNode (btreePtr, &nodeRec);
                    348:        DisposePtr( (Ptr) btreePtr );
                    349: 
                    350:        LogEndTime(kTraceOpenBTree, err);
                    351: 
                    352:        return err;
                    353: }
                    354: 
                    355: 
                    356: 
                    357: /*-------------------------------------------------------------------------------
                    358: Routine:       BTClosePath     -       Flush BTree Header and Deallocate Memory for BTree.
                    359: 
                    360: Function:      Flush the BTreeControlBlock fields to header node, and delete BTree control
                    361:                        block and key descriptor associated with the file if filePtr is last
                    362:                        path of type kBTreeType ('btre').
                    363: 
                    364: 
                    365: Input:         filePtr         - pointer to file to delete BTree control block for.
                    366: 
                    367: Result:                noErr                   - success
                    368:                        fsBTInvalidFileErr      -
                    369:                        != noErr                - failure
                    370: -------------------------------------------------------------------------------*/
                    371: 
                    372: OSStatus       BTClosePath                     (FCB                                    *filePtr)
                    373: {
                    374:        OSStatus                                err;
                    375:        BTreeControlBlockPtr    btreePtr;
                    376: 
                    377:        LogStartTime(kTraceCloseBTree);
                    378: 
                    379:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                    380: 
                    381:        if (btreePtr == nil)
                    382:                return fsBTInvalidFileErr;
                    383: 
                    384:        RequireFileLock(btreePtr->fileRefNum, false);
                    385: 
                    386:        ////////////////////// Check for other BTree Paths //////////////////////////
                    387: 
                    388:        btreePtr->attributes &= ~kBTBadCloseMask;               // clear "bad close" attribute bit
                    389:        err = UpdateHeader (btreePtr);
                    390:        M_ExitOnError (err);
                    391: 
                    392:        DisposePtr( (Ptr) btreePtr );
                    393:        filePtr->fcbBTCBPtr = nil;
                    394: 
                    395:        LogEndTime(kTraceCloseBTree, noErr);
                    396: 
                    397:        return  noErr;
                    398: 
                    399:        /////////////////////// Error - Clean Up and Exit ///////////////////////////
                    400: 
                    401: ErrorExit:
                    402: 
                    403:        LogEndTime(kTraceCloseBTree, err);
                    404: 
                    405:        return  err;
                    406: }
                    407: 
                    408: 
                    409: 
                    410: /*-------------------------------------------------------------------------------
                    411: Routine:       BTSearchRecord  -       Search BTree for a record with a matching key.
                    412: 
                    413: Function:      Search for position in B*Tree indicated by searchKey. If a valid node hint
                    414:                        is provided, it will be searched first, then SearchTree will be called.
                    415:                        If a BTreeIterator is provided, it will be set to the position found as
                    416:                        a result of the search. If a record exists at that position, and a BufferDescriptor
                    417:                        is supplied, the record will be copied to the buffer (as much as will fit),
                    418:                        and recordLen will be set to the length of the record.
                    419: 
                    420:                        If an error other than fsBTRecordNotFoundErr occurs, the BTreeIterator, if any,
                    421:                        is invalidated, and recordLen is set to 0.
                    422: 
                    423: 
                    424: Input:         pathPtr                 - pointer to path for BTree file.
                    425:                        searchKey               - pointer to search key to match.
                    426:                        hintPtr                 - pointer to hint (may be nil)
                    427: 
                    428: Output:                record                  - pointer to BufferDescriptor containing record
                    429:                        recordLen               - length of data at recordPtr
                    430:                        iterator                - pointer to BTreeIterator indicating position result of search
                    431: 
                    432: Result:                noErr                   - success, record contains copy of record found
                    433:                        fsBTRecordNotFoundErr   - record was not found, no data copied
                    434:                        fsBTInvalidFileErr      - no BTreeControlBlock is allocated for the fork
                    435:                        fsBTInvalidKeyLengthErr         -
                    436:                        != noErr                - failure
                    437: -------------------------------------------------------------------------------*/
                    438: 
                    439: OSStatus       BTSearchRecord          (FCB                                            *filePtr,
                    440:                                                                 BTreeIterator                          *searchIterator,
                    441:                                                                 UInt32                                         heuristicHint,
                    442:                                                                 FSBufferDescriptor                     *record,
                    443:                                                                 UInt16                                         *recordLen,
                    444:                                                                 BTreeIterator                          *resultIterator )
                    445: {
                    446:        OSStatus                                err;
                    447:        BTreeControlBlockPtr    btreePtr;
                    448:        TreePathTable                   treePathTable;
                    449:        UInt32                                  nodeNum;
                    450:        BlockDescriptor                 node;
                    451:        UInt16                                  index;
                    452:        BTreeKeyPtr                             keyPtr;
                    453:        RecordPtr                               recordPtr;
                    454:        UInt16                                  len;
                    455:        Boolean                                 foundRecord;
                    456:        Boolean                                 validHint;
                    457: 
                    458: 
                    459:        LogStartTime(kTraceSearchBTree);
                    460: 
                    461:        if (filePtr == nil)                                                                     return  paramErr;
                    462:        if (searchIterator == nil)                                                      return  paramErr;
                    463: 
                    464:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                    465:        if (btreePtr == nil)                                                            return  fsBTInvalidFileErr;
                    466: 
                    467:        RequireFileLock(btreePtr->fileRefNum, true);
                    468: 
                    469:        foundRecord = false;
                    470: 
                    471:        ////////////////////////////// Take A Hint //////////////////////////////////
                    472: 
                    473:        err = IsItAHint (btreePtr, searchIterator, &validHint);
                    474:        M_ExitOnError (err);
                    475: 
                    476:        if (validHint)
                    477:        {
                    478:                nodeNum = searchIterator->hint.nodeNum;
                    479:                
                    480:                err = GetNode (btreePtr, nodeNum, &node);
                    481:                if( err == noErr )
                    482:                {
                    483:                        if ( ((BTNodeDescriptor*) node.buffer)->kind == kBTLeafNode &&
                    484:                                 ((BTNodeDescriptor*) node.buffer)->numRecords  >  0 )
                    485:                        {
                    486:                                foundRecord = SearchNode (btreePtr, node.buffer, &searchIterator->key, &index);
                    487: 
                    488:                                //�� if !foundRecord, we could still skip tree search if ( 0 < index < numRecords )
                    489:                        }
                    490: 
                    491:                        if (foundRecord == false)
                    492:                        {
                    493:                                err = ReleaseNode (btreePtr, &node);
                    494:                                M_ExitOnError (err);
                    495:                        }
                    496:                        else
                    497:                        {
                    498:                                ++btreePtr->numValidHints;
                    499:                        }
                    500:                }
                    501:                
                    502:                if( foundRecord == false )
                    503:                        (void) BTInvalidateHint( searchIterator );
                    504:        }
                    505: 
                    506:        ////////////////////////////// Try the heuristicHint //////////////////////////////////
                    507: 
                    508:        if ( (foundRecord == false) && (heuristicHint != kInvalidMRUCacheKey) && (nodeNum != heuristicHint) )
                    509:        {
                    510:                LogStartTime(kHeuristicHint);
                    511:                nodeNum = heuristicHint;
                    512:                
                    513:                err = GetNode (btreePtr, nodeNum, &node);
                    514:                if( err == noErr )
                    515:                {
                    516:                        if ( ((BTNodeDescriptor*) node.buffer)->kind == kBTLeafNode &&
                    517:                                 ((BTNodeDescriptor*) node.buffer)->numRecords  >  0 )
                    518:                        {
                    519:                                foundRecord = SearchNode (btreePtr, node.buffer, &searchIterator->key, &index);
                    520:                        }
                    521: 
                    522:                        if (foundRecord == false)
                    523:                        {
                    524:                                err = ReleaseNode (btreePtr, &node);
                    525:                                M_ExitOnError (err);
                    526:                        }
                    527:                }
                    528:                LogEndTime(kHeuristicHint, (foundRecord == false));
                    529:        }
                    530: 
                    531:        //////////////////////////// Search The Tree ////////////////////////////////
                    532: 
                    533:        if (foundRecord == false)
                    534:        {
                    535:                err = SearchTree ( btreePtr, &searchIterator->key, treePathTable, &nodeNum, &node, &index);
                    536:                switch (err)
                    537:                {
                    538:                        case noErr:                     foundRecord = true;                             break;
                    539:                        case fsBTRecordNotFoundErr:                                                                     break;
                    540:                        default:                                goto ErrorExit;
                    541:                }
                    542:        }
                    543: 
                    544: 
                    545:        //////////////////////////// Get the Record /////////////////////////////////
                    546: 
                    547:        if (foundRecord == true)
                    548:        {
                    549:                //XXX Should check for errors! Or BlockMove could choke on recordPtr!!!
                    550:                GetRecordByIndex (btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len);
                    551: 
                    552:                if (recordLen != nil)                   *recordLen = len;
                    553: 
                    554:                if (record != nil)
                    555:                {
                    556:                        ByteCount recordSize;
                    557: 
                    558:                        recordSize = record->itemCount * record->itemSize;
                    559:                        
                    560:                        if (len > recordSize)   len = recordSize;
                    561: 
                    562:                        BlockMoveData (recordPtr, record->bufferAddress, len);
                    563:                }
                    564:        }
                    565: 
                    566: 
                    567:        /////////////////////// Success - Update Iterator ///////////////////////////
                    568: 
                    569:        if (resultIterator != nil)
                    570:        {
                    571:                resultIterator->hint.writeCount = btreePtr->writeCount;
                    572:                resultIterator->hint.nodeNum = nodeNum;
                    573:                resultIterator->hint.index = index;
                    574: #if DEBUG_BUILD
                    575:                resultIterator->hint.reserved1 = 0;
                    576:                resultIterator->hint.reserved2 = 0;
                    577:                resultIterator->version = 0;
                    578:                resultIterator->reserved = 0;
                    579: #endif
                    580:                // copy the key in the BTree when found rather than searchIterator->key to get proper case/diacriticals
                    581:                if (foundRecord == true)
                    582:                        BlockMoveData ((Ptr)keyPtr, (Ptr)&resultIterator->key, CalcKeySize(btreePtr, keyPtr));
                    583:                else
                    584:                        BlockMoveData ((Ptr)&searchIterator->key, (Ptr)&resultIterator->key, CalcKeySize(btreePtr, &searchIterator->key));
                    585:        }
                    586: 
                    587:        err = ReleaseNode (btreePtr, &node);
                    588:        M_ExitOnError (err);
                    589: 
                    590:        LogEndTime(kTraceSearchBTree, (foundRecord == false));
                    591: 
                    592:        if (foundRecord == false)       return  fsBTRecordNotFoundErr;
                    593:        else                                            return  noErr;
                    594: 
                    595: 
                    596:        /////////////////////// Error - Clean Up and Exit ///////////////////////////
                    597: 
                    598: ErrorExit:
                    599: 
                    600:        if (recordLen != nil)
                    601:                *recordLen = 0;
                    602: 
                    603:        if (resultIterator != nil)
                    604:        {
                    605:                resultIterator->hint.writeCount = 0;
                    606:                resultIterator->hint.nodeNum    = 0;
                    607:                resultIterator->hint.index              = 0;
                    608:                resultIterator->hint.reserved1  = 0;
                    609:                resultIterator->hint.reserved2  = 0;
                    610: 
                    611:                resultIterator->version                 = 0;
                    612:                resultIterator->reserved                = 0;
                    613:                resultIterator->key.length16    = 0;    // zero out two bytes to cover both types of keys
                    614:        }
                    615: 
                    616:        if ( err == fsBTEmptyErr )
                    617:                err = fsBTRecordNotFoundErr;
                    618: 
                    619:        LogEndTime(kTraceSearchBTree, err);
                    620: 
                    621:        return err;
                    622: }
                    623: 
                    624: 
                    625: 
                    626: /*-------------------------------------------------------------------------------
                    627: Routine:       BTIterateRecord -       Find the first, next, previous, or last record.
                    628: 
                    629: Function:      Find the first, next, previous, or last record in the BTree
                    630: 
                    631: Input:         pathPtr                 - pointer to path iterate records for.
                    632:                        operation               - iteration operation (first,next,prev,last)
                    633:                        iterator                - pointer to iterator indicating start position
                    634: 
                    635: Output:                iterator                - iterator is updated to indicate new position
                    636:                        newKeyPtr               - pointer to buffer to copy key found by iteration
                    637:                        record                  - pointer to buffer to copy record found by iteration
                    638:                        recordLen               - length of record
                    639: 
                    640: Result:                noErr                   - success
                    641:                        != noErr                - failure
                    642: -------------------------------------------------------------------------------*/
                    643: 
                    644: OSStatus       BTIterateRecord         (FCB                                            *filePtr,
                    645:                                                                 BTreeIterationOperation         operation,
                    646:                                                                 BTreeIterator                          *iterator,
                    647:                                                                 FSBufferDescriptor                     *record,
                    648:                                                                 UInt16                                         *recordLen )
                    649: {
                    650:        OSStatus                                        err;
                    651:        BTreeControlBlockPtr            btreePtr;
                    652:        BTreeKeyPtr                                     keyPtr;
                    653:        RecordPtr                                       recordPtr;
                    654:        UInt16                                          len;
                    655: 
                    656:        Boolean                                         foundRecord;
                    657:        UInt32                                          nodeNum;
                    658: 
                    659:        BlockDescriptor                         left,           node,           right;
                    660:        UInt16                                          index;
                    661: 
                    662: 
                    663:        LogStartTime(kTraceGetBTreeRecord);
                    664: 
                    665:        ////////////////////////// Priliminary Checks ///////////////////////////////
                    666: 
                    667:        left.buffer             = nil;
                    668:        right.buffer    = nil;
                    669:        node.buffer             = nil;
                    670: 
                    671: 
                    672:        if (filePtr == nil)
                    673:        {
                    674:                return  paramErr;
                    675:        }
                    676: 
                    677:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                    678:        if (btreePtr == nil)
                    679:        {
                    680:                return  fsBTInvalidFileErr;                     //�� handle properly
                    681:        }
                    682: 
                    683:        RequireFileLock(btreePtr->fileRefNum, true);
                    684: 
                    685:        if ((operation != kBTreeFirstRecord)    &&
                    686:                (operation != kBTreeNextRecord)         &&
                    687:                (operation != kBTreeCurrentRecord)      &&
                    688:                (operation != kBTreePrevRecord)         &&
                    689:                (operation != kBTreeLastRecord))
                    690:        {
                    691:                err = fsInvalidIterationMovmentErr;
                    692:                goto ErrorExit;
                    693:        }
                    694: 
                    695:        /////////////////////// Find First or Last Record ///////////////////////////
                    696: 
                    697:        if ((operation == kBTreeFirstRecord) || (operation == kBTreeLastRecord))
                    698:        {
                    699:                if (operation == kBTreeFirstRecord)             nodeNum = btreePtr->firstLeafNode;
                    700:                else                                                                    nodeNum = btreePtr->lastLeafNode;
                    701: 
                    702:                if (nodeNum == 0)
                    703:                {
                    704:                        err = fsBTEmptyErr;
                    705:                        goto ErrorExit;
                    706:                }
                    707: 
                    708:                err = GetNode (btreePtr, nodeNum, &node);
                    709:                M_ExitOnError (err);
                    710: 
                    711:                if ( ((NodeDescPtr) node.buffer)->kind != kBTLeafNode ||
                    712:                         ((NodeDescPtr) node.buffer)->numRecords <=  0 )
                    713:                {
                    714:                        err = ReleaseNode (btreePtr, &node);
                    715:                        M_ExitOnError (err);
                    716: 
                    717:                        err = fsBTInvalidNodeErr;
                    718:                        goto ErrorExit;
                    719:                }
                    720: 
                    721:                if (operation == kBTreeFirstRecord)             index = 0;
                    722:                else                                                                    index = ((BTNodeDescriptor*) node.buffer)->numRecords - 1;
                    723: 
                    724:                goto CopyData;                                          //�� is there a cleaner way?
                    725:        }
                    726: 
                    727: 
                    728:        //////////////////////// Find Iterator Position /////////////////////////////
                    729: 
                    730:        err = FindIteratorPosition (btreePtr, iterator,
                    731:                                                                &left, &node, &right, &nodeNum, &index, &foundRecord);
                    732:        M_ExitOnError (err);
                    733: 
                    734: 
                    735:        ///////////////////// Find Next Or Previous Record //////////////////////////
                    736: 
                    737:        if (operation == kBTreePrevRecord)
                    738:        {
                    739:                if (index > 0)
                    740:                {
                    741:                        --index;
                    742:                }
                    743:                else
                    744:                {
                    745:                        if (left.buffer == nil)
                    746:                        {
                    747:                                nodeNum = ((NodeDescPtr) node.buffer)->bLink;
                    748:                                if ( nodeNum > 0)
                    749:                                {
                    750:                                        err = GetNode (btreePtr, nodeNum, &left);
                    751:                                        M_ExitOnError (err);
                    752:                                } else {
                    753:                                        err = fsBTStartOfIterationErr;
                    754:                                        goto ErrorExit;
                    755:                                }
                    756:                        }
                    757:                        //      Before we stomp on "right", we'd better release it if needed
                    758:                        if (right.buffer != nil) {
                    759:                                err = ReleaseNode(btreePtr, &right);
                    760:                                M_ExitOnError(err);
                    761:                        }
                    762:                        right           = node;
                    763:                        node            = left;
                    764:                        left.buffer     = nil;
                    765:                        index           = ((NodeDescPtr) node.buffer)->numRecords -1;
                    766:                }
                    767:        }
                    768:        else if (operation == kBTreeNextRecord)
                    769:        {
                    770:                if ((foundRecord != true) &&
                    771:                        (((NodeDescPtr) node.buffer)->fLink == 0) &&
                    772:                        (index == ((NodeDescPtr) node.buffer)->numRecords))
                    773:                {
                    774:                        err = fsBTEndOfIterationErr;
                    775:                        goto ErrorExit;
                    776:                } 
                    777:        
                    778:                // we did not find the record but the index is already positioned correctly
                    779:                if ((foundRecord == false) && (index != ((NodeDescPtr) node.buffer)->numRecords)) 
                    780:                        goto CopyData;
                    781: 
                    782:                // we found the record OR we have to look in the next node
                    783:                if (index < ((NodeDescPtr) node.buffer)->numRecords -1)
                    784:                {
                    785:                        ++index;
                    786:                }
                    787:                else
                    788:                {
                    789:                        if (right.buffer == nil)
                    790:                        {
                    791:                                nodeNum = ((NodeDescPtr) node.buffer)->fLink;
                    792:                                if ( nodeNum > 0)
                    793:                                {
                    794:                                        err = GetNode (btreePtr, nodeNum, &right);
                    795:                                        M_ExitOnError (err);
                    796:                                } else {
                    797:                                        err = fsBTEndOfIterationErr;
                    798:                                        goto ErrorExit;
                    799:                                }
                    800:                        }
                    801:                        //      Before we stomp on "left", we'd better release it if needed
                    802:                        if (left.buffer != nil) {
                    803:                                err = ReleaseNode(btreePtr, &left);
                    804:                                M_ExitOnError(err);
                    805:                        }
                    806:                        left             = node;
                    807:                        node             = right;
                    808:                        right.buffer = nil;
                    809:                        index            = 0;
                    810:                }
                    811:        }
                    812:        else // operation == kBTreeCurrentRecord
                    813:        {
                    814:                // make sure we have something... <CS9>
                    815:                if ((foundRecord != true) &&
                    816:                        (index >= ((NodeDescPtr) node.buffer)->numRecords))
                    817:                {
                    818:                        err = fsBTEndOfIterationErr;
                    819:                        goto ErrorExit;
                    820:                } 
                    821:        }
                    822: 
                    823:        //////////////////// Copy Record And Update Iterator ////////////////////////
                    824: 
                    825: CopyData:
                    826: 
                    827:        // added check for errors <CS9>
                    828:        err = GetRecordByIndex (btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len);
                    829:        M_ExitOnError (err);
                    830: 
                    831:        if (recordLen != nil)
                    832:                *recordLen = len;
                    833: 
                    834:        if (record != nil)
                    835:        {
                    836:                ByteCount recordSize;
                    837: 
                    838:                recordSize = record->itemCount * record->itemSize;
                    839:        
                    840:                if (len > recordSize)   len = recordSize;
                    841: 
                    842:                BlockMoveData (recordPtr, record->bufferAddress, len);
                    843:        }
                    844: 
                    845:        if (iterator != nil)                                            // first & last do not require iterator
                    846:        {
                    847:                iterator->hint.writeCount       = btreePtr->writeCount;
                    848:                iterator->hint.nodeNum          = nodeNum;
                    849:                iterator->hint.index            = index;
                    850:                iterator->hint.reserved1        = 0;
                    851:                iterator->hint.reserved2        = 0;
                    852: 
                    853:                iterator->version                       = 0;
                    854:                iterator->reserved                      = 0;
                    855: 
                    856:                BlockMoveData ((Ptr)keyPtr, (Ptr)&iterator->key, CalcKeySize(btreePtr, keyPtr));
                    857:        }
                    858: 
                    859: 
                    860:        ///////////////////////////// Release Nodes /////////////////////////////////
                    861: 
                    862:        err = ReleaseNode (btreePtr, &node);
                    863:        M_ExitOnError (err);
                    864: 
                    865:        if (left.buffer != nil)
                    866:        {
                    867:                err = ReleaseNode (btreePtr, &left);
                    868:                M_ExitOnError (err);
                    869:        }
                    870: 
                    871:        if (right.buffer != nil)
                    872:        {
                    873:                err = ReleaseNode (btreePtr, &right);
                    874:                M_ExitOnError (err);
                    875:        }
                    876: 
                    877:        LogEndTime(kTraceGetBTreeRecord, noErr);
                    878: 
                    879:        return noErr;
                    880: 
                    881:        /////////////////////// Error - Clean Up and Exit ///////////////////////////
                    882: 
                    883: ErrorExit:
                    884: 
                    885:        (void)  ReleaseNode (btreePtr, &left);
                    886:        (void)  ReleaseNode (btreePtr, &node);
                    887:        (void)  ReleaseNode (btreePtr, &right);
                    888: 
                    889:        if (recordLen != nil)
                    890:                *recordLen = 0;
                    891: 
                    892:        if (iterator != nil)
                    893:        {
                    894:                iterator->hint.writeCount       = 0;
                    895:                iterator->hint.nodeNum          = 0;
                    896:                iterator->hint.index            = 0;
                    897:                iterator->hint.reserved1        = 0;
                    898:                iterator->hint.reserved2        = 0;
                    899: 
                    900:                iterator->version                       = 0;
                    901:                iterator->reserved                      = 0;
                    902:                iterator->key.length16          = 0;
                    903:        }
                    904: 
                    905:        if ( err == fsBTEmptyErr || err == fsBTEndOfIterationErr )
                    906:                err = fsBTRecordNotFoundErr;
                    907: 
                    908:        LogEndTime(kTraceGetBTreeRecord, err);
                    909: 
                    910:        return err;
                    911: }
                    912: 
                    913: 
                    914: /*-------------------------------------------------------------------------------
                    915: Routine:       BTIterateRecords
                    916: 
                    917: Function:      Find a series of records
                    918: 
                    919: Input:         filePtr         - b-tree file
                    920:                operation       - iteration operation (first,next,prev,last)
                    921:                iterator        - pointer to iterator indicating start position
                    922:                callBackProc    - pointer to routince to process a record
                    923:                callBackState   - pointer to state data (used by callBackProc)
                    924: 
                    925: Output:                iterator        - iterator is updated to indicate new position
                    926: 
                    927: Result:                noErr           - success
                    928:                != noErr        - failure
                    929: -------------------------------------------------------------------------------*/
                    930: 
                    931: OSStatus
                    932: BTIterateRecords(FCB *filePtr, BTreeIterationOperation operation, BTreeIterator *iterator,
                    933:                 IterateCallBackProcPtr  callBackProc, void * callBackState)
                    934: {
                    935:        OSStatus                err;
                    936:        BTreeControlBlockPtr    btreePtr;
                    937:        BTreeKeyPtr             keyPtr;
                    938:        RecordPtr               recordPtr;
                    939:        UInt16                  len;
                    940:        Boolean                 foundRecord;
                    941:        UInt32                  nodeNum;
                    942:        BlockDescriptor         left, node, right;
                    943:        UInt16                  index;
                    944: 
                    945: 
                    946:        ////////////////////////// Priliminary Checks ///////////////////////////////
                    947: 
                    948:        left.buffer  = nil;
                    949:        right.buffer = nil;
                    950:        node.buffer  = nil;
                    951: 
                    952:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                    953: 
                    954:        RequireFileLock(btreePtr->fileRefNum, true);
                    955: 
                    956:        if ((operation != kBTreeFirstRecord)    &&
                    957:                (operation != kBTreeNextRecord)         &&
                    958:                (operation != kBTreeCurrentRecord)      &&
                    959:                (operation != kBTreePrevRecord)         &&
                    960:                (operation != kBTreeLastRecord))
                    961:        {
                    962:                err = fsInvalidIterationMovmentErr;
                    963:                goto ErrorExit;
                    964:        }
                    965: 
                    966:        /////////////////////// Find First or Last Record ///////////////////////////
                    967: 
                    968:        if ((operation == kBTreeFirstRecord) || (operation == kBTreeLastRecord))
                    969:        {
                    970:                if (operation == kBTreeFirstRecord)
                    971:                        nodeNum = btreePtr->firstLeafNode;
                    972:                else
                    973:                        nodeNum = btreePtr->lastLeafNode;
                    974: 
                    975:                if (nodeNum == 0)
                    976:                {
                    977:                        err = fsBTEmptyErr;
                    978:                        goto ErrorExit;
                    979:                }
                    980: 
                    981:                err = GetNode(btreePtr, nodeNum, &node);
                    982:                M_ExitOnError(err);
                    983: 
                    984:                if ( ((NodeDescPtr)node.buffer)->kind != kBTLeafNode ||
                    985:                         ((NodeDescPtr)node.buffer)->numRecords <=  0 )
                    986:                {
                    987:                        err = ReleaseNode(btreePtr, &node);
                    988:                        M_ExitOnError(err);
                    989: 
                    990:                        err = fsBTInvalidNodeErr;
                    991:                        goto ErrorExit;
                    992:                }
                    993: 
                    994:                if (operation == kBTreeFirstRecord)
                    995:                        index = 0;
                    996:                else
                    997:                        index = ((BTNodeDescriptor*) node.buffer)->numRecords - 1;
                    998: 
                    999:                goto ProcessData;
                   1000:        }
                   1001: 
                   1002:        //////////////////////// Find Iterator Position /////////////////////////////
                   1003: 
                   1004:        err = FindIteratorPosition(btreePtr, iterator, &left, &node, &right,
                   1005:                                   &nodeNum, &index, &foundRecord);
                   1006:        M_ExitOnError(err);
                   1007: 
                   1008: 
                   1009:        ///////////////////// Find Next Or Previous Record //////////////////////////
                   1010: 
                   1011:        if (operation == kBTreePrevRecord)
                   1012:        {
                   1013:                if (index > 0)
                   1014:                {
                   1015:                        --index;
                   1016:                }
                   1017:                else
                   1018:                {
                   1019:                        if (left.buffer == nil)
                   1020:                        {
                   1021:                                nodeNum = ((NodeDescPtr) node.buffer)->bLink;
                   1022:                                if ( nodeNum > 0)
                   1023:                                {
                   1024:                                        err = GetNode(btreePtr, nodeNum, &left);
                   1025:                                        M_ExitOnError(err);
                   1026:                                } else {
                   1027:                                        err = fsBTStartOfIterationErr;
                   1028:                                        goto ErrorExit;
                   1029:                                }
                   1030:                        }
                   1031:                        // Before we stomp on "right", we'd better release it if needed
                   1032:                        if (right.buffer != nil) {
                   1033:                                err = ReleaseNode(btreePtr, &right);
                   1034:                                M_ExitOnError(err);
                   1035:                        }
                   1036:                        right       = node;
                   1037:                        node        = left;
                   1038:                        left.buffer = nil;
                   1039:                        index       = ((NodeDescPtr) node.buffer)->numRecords -1;
                   1040:                }
                   1041:        }
                   1042:        else if (operation == kBTreeNextRecord)
                   1043:        {
                   1044:                if ((foundRecord != true) &&
                   1045:                        (((NodeDescPtr)node.buffer)->fLink == 0) &&
                   1046:                        (index == ((NodeDescPtr)node.buffer)->numRecords))
                   1047:                {
                   1048:                        err = fsBTEndOfIterationErr;
                   1049:                        goto ErrorExit;
                   1050:                } 
                   1051:        
                   1052:                // we did not find the record but the index is already positioned correctly
                   1053:                if ((foundRecord == false) && (index != ((NodeDescPtr)node.buffer)->numRecords)) 
                   1054:                        goto ProcessData;
                   1055: 
                   1056:                // we found the record OR we have to look in the next node
                   1057:                if (index < ((NodeDescPtr)node.buffer)->numRecords -1)
                   1058:                {
                   1059:                        ++index;
                   1060:                }
                   1061:                else
                   1062:                {
                   1063:                        if (right.buffer == nil)
                   1064:                        {
                   1065:                                nodeNum = ((NodeDescPtr)node.buffer)->fLink;
                   1066:                                if ( nodeNum > 0)
                   1067:                                {
                   1068:                                        err = GetNode(btreePtr, nodeNum, &right);
                   1069:                                        M_ExitOnError(err);
                   1070:                                } else {
                   1071:                                        err = fsBTEndOfIterationErr;
                   1072:                                        goto ErrorExit;
                   1073:                                }
                   1074:                        }
                   1075:                        // Before we stomp on "left", we'd better release it if needed
                   1076:                        if (left.buffer != nil) {
                   1077:                                err = ReleaseNode(btreePtr, &left);
                   1078:                                M_ExitOnError(err);
                   1079:                        }
                   1080:                        left         = node;
                   1081:                        node         = right;
                   1082:                        right.buffer = nil;
                   1083:                        index        = 0;
                   1084:                }
                   1085:        }
                   1086:        else // operation == kBTreeCurrentRecord
                   1087:        {
                   1088:                // make sure we have something... <CS9>
                   1089:                if ((foundRecord != true) &&
                   1090:                        (index >= ((NodeDescPtr)node.buffer)->numRecords))
                   1091:                {
                   1092:                        err = fsBTEndOfIterationErr;
                   1093:                        goto ErrorExit;
                   1094:                } 
                   1095:        }
                   1096: 
                   1097:        ////////////////////  Process Records Using Callback  ////////////////////////
                   1098: 
                   1099: ProcessData:
                   1100:        err = GetRecordByIndex(btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len);
                   1101:        
                   1102:        while (err == 0) {
                   1103:                if (callBackProc(keyPtr, recordPtr, len, callBackState) == 0)
                   1104:                        break;
                   1105:                
                   1106:                if ((index+1) < ((NodeDescPtr)node.buffer)->numRecords) {
                   1107:                        ++index;
                   1108:                } else {
                   1109:                        if (right.buffer == nil)
                   1110:                        {
                   1111:                                nodeNum = ((NodeDescPtr)node.buffer)->fLink;
                   1112:                                if ( nodeNum > 0)
                   1113:                                {
                   1114:                                        err = GetNode(btreePtr, nodeNum, &right);
                   1115:                                        M_ExitOnError(err);
                   1116:                                } else {
                   1117:                                        err = fsBTEndOfIterationErr;
                   1118:                                        break;
                   1119:                                }
                   1120:                        }
                   1121:                        // Before we stomp on "left", we'd better release it if needed
                   1122:                        if (left.buffer != nil) {
                   1123:                                err = ReleaseNode(btreePtr, &left);
                   1124:                                M_ExitOnError(err);
                   1125:                        }
                   1126:                        left         = node;
                   1127:                        node         = right;
                   1128:                        right.buffer = nil;
                   1129:                        index        = 0;
                   1130:                }
                   1131:                err = GetRecordByIndex(btreePtr, node.buffer, index,
                   1132:                                                &keyPtr, &recordPtr, &len);
                   1133:        }
                   1134: 
                   1135: 
                   1136:        ///////////////// Update Iterator to Last Item Processed /////////////////////
                   1137: 
                   1138: 
                   1139:        if (iterator != nil)    // first & last have optional iterator
                   1140:        {
                   1141:                iterator->hint.writeCount = btreePtr->writeCount;
                   1142:                iterator->hint.nodeNum    = nodeNum;
                   1143:                iterator->hint.index      = index;
                   1144:                iterator->version         = 0;
                   1145: 
                   1146:                BlockMoveData((Ptr)keyPtr, (Ptr)&iterator->key, CalcKeySize(btreePtr, keyPtr));
                   1147:        }
                   1148:        M_ExitOnError(err);
                   1149: 
                   1150: 
                   1151:        ///////////////////////////// Release Nodes /////////////////////////////////
                   1152: 
                   1153:        err = ReleaseNode(btreePtr, &node);
                   1154:        M_ExitOnError(err);
                   1155: 
                   1156:        if (left.buffer != nil)
                   1157:        {
                   1158:                err = ReleaseNode(btreePtr, &left);
                   1159:                M_ExitOnError(err);
                   1160:        }
                   1161: 
                   1162:        if (right.buffer != nil)
                   1163:        {
                   1164:                err = ReleaseNode(btreePtr, &right);
                   1165:                M_ExitOnError(err);
                   1166:        }
                   1167: 
                   1168:        return noErr;
                   1169: 
                   1170:        /////////////////////// Error - Clean Up and Exit ///////////////////////////
                   1171: 
                   1172: ErrorExit:
                   1173: 
                   1174:        (void) ReleaseNode(btreePtr, &left);
                   1175:        (void) ReleaseNode(btreePtr, &node);
                   1176:        (void) ReleaseNode(btreePtr, &right);
                   1177: 
                   1178:        if (iterator != nil)
                   1179:        {
                   1180:                iterator->hint.writeCount = 0;
                   1181:                iterator->hint.nodeNum    = 0;
                   1182:                iterator->hint.index      = 0;
                   1183:                iterator->version         = 0;
                   1184:                iterator->key.length16    = 0;
                   1185:        }
                   1186: 
                   1187:        if ( err == fsBTEmptyErr || err == fsBTEndOfIterationErr )
                   1188:                err = fsBTRecordNotFoundErr;
                   1189: 
                   1190:        return err;
                   1191: }
                   1192: 
                   1193: 
                   1194: //////////////////////////////// BTInsertRecord /////////////////////////////////
                   1195: 
                   1196: OSStatus       BTInsertRecord          (FCB                                            *filePtr,
                   1197:                                                                 BTreeIterator                          *iterator,
                   1198:                                                                 FSBufferDescriptor                     *record,
                   1199:                                                                 UInt16                                          recordLen )
                   1200: {
                   1201:        OSStatus                                err;
                   1202:        BTreeControlBlockPtr    btreePtr;
                   1203:        TreePathTable                   treePathTable;
                   1204:        SInt32                                  nodesNeeded;
                   1205:        BlockDescriptor                 nodeRec;
                   1206:        UInt32                                  insertNodeNum;
                   1207:        UInt16                                  index;
                   1208:        Boolean                                 recordFit;
                   1209: 
                   1210: 
                   1211:        ////////////////////////// Priliminary Checks ///////////////////////////////
                   1212: 
                   1213:        nodeRec.buffer = nil;                                   // so we can call ReleaseNode
                   1214: 
                   1215:        err = CheckInsertParams (filePtr, iterator, record, recordLen);
                   1216:        if (err != noErr)
                   1217:                return  err;
                   1218: 
                   1219:        LogStartTime(kTraceInsertBTreeRecord);
                   1220: 
                   1221:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1222: 
                   1223:        RequireFileLock(btreePtr->fileRefNum, false);
                   1224: 
                   1225: 
                   1226:        ///////////////////////// Find Insert Position //////////////////////////////
                   1227: 
                   1228:        // always call SearchTree for Insert
                   1229:        err = SearchTree (btreePtr, &iterator->key, treePathTable, &insertNodeNum, &nodeRec, &index);
                   1230: 
                   1231:        switch (err)                            // set/replace/insert decision point
                   1232:        {
                   1233:                case noErr:                     err = fsBTDuplicateRecordErr;
                   1234:                                                                goto ErrorExit;
                   1235: 
                   1236:                case fsBTRecordNotFoundErr:     break;
                   1237: 
                   1238:                case fsBTEmptyErr:      // if tree empty add 1st leaf node
                   1239: 
                   1240:                                                                if (btreePtr->freeNodes == 0)
                   1241:                                                                {
                   1242:                                                                        err = ExtendBTree (btreePtr, btreePtr->totalNodes + 1);
                   1243:                                                                        M_ExitOnError (err);
                   1244:                                                                }
                   1245: 
                   1246:                                                                err = AllocateNode (btreePtr, &insertNodeNum);
                   1247:                                                                M_ExitOnError (err);
                   1248: 
                   1249:                                                                err = GetNewNode (btreePtr, insertNodeNum, &nodeRec);
                   1250:                                                                M_ExitOnError (err);
                   1251: 
                   1252:                                                                ((NodeDescPtr)nodeRec.buffer)->kind = kBTLeafNode;
                   1253:                                                                ((NodeDescPtr)nodeRec.buffer)->height   = 1;
                   1254: 
                   1255:                                                                recordFit = InsertKeyRecord (btreePtr, nodeRec.buffer, 0,
                   1256:                                                                                                                         &iterator->key, KeyLength(btreePtr, &iterator->key),
                   1257:                                                                                                                         record->bufferAddress, recordLen );
                   1258:                                                                if (recordFit != true)
                   1259:                                                                {
                   1260:                                                                        err = fsBTRecordTooLargeErr;
                   1261:                                                                        goto ErrorExit;
                   1262:                                                                }
                   1263: 
                   1264:                                                                err = UpdateNode (btreePtr, &nodeRec, 0, kLockTransaction);
                   1265:                                                                M_ExitOnError (err);
                   1266: 
                   1267:                                                                // update BTreeControlBlock
                   1268:                                                                btreePtr->treeDepth                     = 1;
                   1269:                                                                btreePtr->rootNode                      = insertNodeNum;
                   1270:                                                                btreePtr->firstLeafNode         = insertNodeNum;
                   1271:                                                                btreePtr->lastLeafNode          = insertNodeNum;
                   1272:                                                                M_BTreeHeaderDirty (btreePtr);
                   1273: 
                   1274:                                                                goto Success;
                   1275: 
                   1276:                default:                                goto ErrorExit;
                   1277:        }
                   1278: 
                   1279:        if (index > 0)
                   1280:        {
                   1281:                recordFit = InsertKeyRecord (btreePtr, nodeRec.buffer, index,
                   1282:                                                                                &iterator->key, KeyLength(btreePtr, &iterator->key),
                   1283:                                                                                record->bufferAddress, recordLen);
                   1284:                if (recordFit == true)
                   1285:                {
                   1286:                        err = UpdateNode (btreePtr, &nodeRec, 0, kLockTransaction);
                   1287:                        M_ExitOnError (err);
                   1288: 
                   1289:                        goto Success;
                   1290:                }
                   1291:        }
                   1292: 
                   1293:        /////////////////////// Extend File If Necessary ////////////////////////////
                   1294: 
                   1295:        nodesNeeded =  btreePtr->treeDepth + 1 - btreePtr->freeNodes;   //�� math limit
                   1296:        if (nodesNeeded > 0)
                   1297:        {
                   1298:                nodesNeeded += btreePtr->totalNodes;
                   1299:                if (nodesNeeded > CalcMapBits (btreePtr))       // we'll need to add a map node too!
                   1300:                        ++nodesNeeded;
                   1301: 
                   1302:                err = ExtendBTree (btreePtr, nodesNeeded);
                   1303:                M_ExitOnError (err);
                   1304:        }
                   1305: 
                   1306:        // no need to delete existing record
                   1307: 
                   1308:        err = InsertTree (btreePtr, treePathTable, &iterator->key, record->bufferAddress,
                   1309:                                          recordLen, &nodeRec, index, 1, kInsertRecord, &insertNodeNum);
                   1310:        M_ExitOnError (err);
                   1311: 
                   1312: 
                   1313:        //////////////////////////////// Success ////////////////////////////////////
                   1314: 
                   1315: Success:
                   1316:        ++btreePtr->writeCount;
                   1317:        ++btreePtr->leafRecords;
                   1318:        M_BTreeHeaderDirty (btreePtr);
                   1319: 
                   1320:        // create hint
                   1321:        iterator->hint.writeCount       = btreePtr->writeCount;
                   1322:        iterator->hint.nodeNum          = insertNodeNum;
                   1323:        iterator->hint.index            = 0;                                            // unused
                   1324:        iterator->hint.reserved1        = 0;
                   1325:        iterator->hint.reserved2        = 0;
                   1326: 
                   1327:        LogEndTime(kTraceInsertBTreeRecord, noErr);
                   1328: 
                   1329:        return noErr;
                   1330: 
                   1331: 
                   1332:        ////////////////////////////// Error Exit ///////////////////////////////////
                   1333: 
                   1334: ErrorExit:
                   1335: 
                   1336:        (void) ReleaseNode (btreePtr, &nodeRec);
                   1337: 
                   1338:        iterator->hint.writeCount       = 0;
                   1339:        iterator->hint.nodeNum          = 0;
                   1340:        iterator->hint.index            = 0;
                   1341:        iterator->hint.reserved1        = 0;
                   1342:        iterator->hint.reserved2        = 0;
                   1343:        
                   1344:        if (err == fsBTEmptyErr)
                   1345:                err = fsBTRecordNotFoundErr;
                   1346: 
                   1347:        LogEndTime(kTraceInsertBTreeRecord, err);
                   1348: 
                   1349:        return err;
                   1350: }
                   1351: 
                   1352: 
                   1353: //////////////////////////////// BTReplaceRecord ////////////////////////////////
                   1354: 
                   1355: OSStatus       BTReplaceRecord         (FCB                                            *filePtr,
                   1356:                                                                 BTreeIterator                          *iterator,
                   1357:                                                                 FSBufferDescriptor                     *record,
                   1358:                                                                 UInt16                                          recordLen )
                   1359: {
                   1360:        OSStatus                                err;
                   1361:        BTreeControlBlockPtr    btreePtr;
                   1362:        TreePathTable                   treePathTable;
                   1363:        SInt32                                  nodesNeeded;
                   1364:        BlockDescriptor                 nodeRec;
                   1365:        UInt32                                  insertNodeNum;
                   1366:        UInt16                                  index;
                   1367:        Boolean                                 recordFit;
                   1368:        Boolean                                 validHint;
                   1369: 
                   1370: 
                   1371:        ////////////////////////// Priliminary Checks ///////////////////////////////
                   1372: 
                   1373:        nodeRec.buffer = nil;                                   // so we can call ReleaseNode
                   1374: 
                   1375:        err = CheckInsertParams (filePtr, iterator, record, recordLen);
                   1376:        if (err != noErr)
                   1377:                return err;
                   1378: 
                   1379:        LogStartTime(kTraceReplaceBTreeRecord);
                   1380: 
                   1381:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1382: 
                   1383:        RequireFileLock(btreePtr->fileRefNum, false);
                   1384: 
                   1385:        ////////////////////////////// Take A Hint //////////////////////////////////
                   1386: 
                   1387:        err = IsItAHint (btreePtr, iterator, &validHint);
                   1388:        M_ExitOnError (err);
                   1389: 
                   1390:        if (validHint)
                   1391:        {
                   1392:                insertNodeNum = iterator->hint.nodeNum;
                   1393: 
                   1394:                err = GetNode (btreePtr, insertNodeNum, &nodeRec);
                   1395:                if( err == noErr )
                   1396:                {
                   1397:                        err = TrySimpleReplace (btreePtr, nodeRec.buffer, iterator, record, recordLen, &recordFit);
                   1398:                        M_ExitOnError (err);
                   1399: 
                   1400:                        if (recordFit)
                   1401:                        {
                   1402:                                err = UpdateNode (btreePtr, &nodeRec, 0, 0);
                   1403:                                M_ExitOnError (err);
                   1404: 
                   1405:                                ++btreePtr->numValidHints;
                   1406: 
                   1407:                                goto Success;
                   1408:                        }
                   1409:                        else
                   1410:                        {
                   1411:                                (void) BTInvalidateHint( iterator );
                   1412:                        }
                   1413:                        
                   1414:                        err = ReleaseNode (btreePtr, &nodeRec);
                   1415:                        M_ExitOnError (err);
                   1416:                }
                   1417:                else
                   1418:                {
                   1419:                        (void) BTInvalidateHint( iterator );
                   1420:                }
                   1421:        }
                   1422: 
                   1423: 
                   1424:        ////////////////////////////// Get A Clue ///////////////////////////////////
                   1425: 
                   1426:        err = SearchTree (btreePtr, &iterator->key, treePathTable, &insertNodeNum, &nodeRec, &index);
                   1427:        M_ExitOnError (err);                                    // record must exit for Replace
                   1428: 
                   1429:        // optimization - if simple replace will work then don't extend btree
                   1430:        // �� if we tried this before, and failed because it wouldn't fit then we shouldn't try this again...
                   1431: 
                   1432:        err = TrySimpleReplace (btreePtr, nodeRec.buffer, iterator, record, recordLen, &recordFit);
                   1433:        M_ExitOnError (err);
                   1434: 
                   1435:        if (recordFit)
                   1436:        {
                   1437:                err = UpdateNode (btreePtr, &nodeRec, 0, 0);
                   1438:                M_ExitOnError (err);
                   1439: 
                   1440:                goto Success;
                   1441:        }
                   1442: 
                   1443: 
                   1444:        //////////////////////////// Make Some Room /////////////////////////////////
                   1445: 
                   1446:        nodesNeeded =  btreePtr->treeDepth + 1 - btreePtr->freeNodes;   //�� math limit
                   1447:        if (nodesNeeded > 0)
                   1448:        {
                   1449:                nodesNeeded += btreePtr->totalNodes;
                   1450:                if (nodesNeeded > CalcMapBits (btreePtr))       // we'll need to add a map node too!
                   1451:                        ++nodesNeeded;
                   1452: 
                   1453:                err = ExtendBTree (btreePtr, nodesNeeded);
                   1454:                M_ExitOnError (err);
                   1455:        }
                   1456: 
                   1457: 
                   1458:        DeleteRecord (btreePtr, nodeRec.buffer, index); // delete existing key/record
                   1459: 
                   1460:        err = InsertTree (btreePtr, treePathTable, &iterator->key, record->bufferAddress,
                   1461:                                          recordLen, &nodeRec, index, 1, kReplaceRecord, &insertNodeNum);
                   1462:        M_ExitOnError (err);
                   1463: 
                   1464:        ++btreePtr->writeCount; /* writeCount changes only if the tree structure changed */
                   1465: 
                   1466: Success:
                   1467:        // create hint
                   1468:        iterator->hint.writeCount       = btreePtr->writeCount;
                   1469:        iterator->hint.nodeNum          = insertNodeNum;
                   1470:        iterator->hint.index            = 0;                                            // unused
                   1471:        iterator->hint.reserved1        = 0;
                   1472:        iterator->hint.reserved2        = 0;
                   1473: 
                   1474:        LogEndTime(kTraceReplaceBTreeRecord, noErr);
                   1475: 
                   1476:        return noErr;
                   1477: 
                   1478: 
                   1479:        ////////////////////////////// Error Exit ///////////////////////////////////
                   1480: 
                   1481: ErrorExit:
                   1482: 
                   1483:        (void) ReleaseNode (btreePtr, &nodeRec);
                   1484: 
                   1485:        iterator->hint.writeCount       = 0;
                   1486:        iterator->hint.nodeNum          = 0;
                   1487:        iterator->hint.index            = 0;
                   1488:        iterator->hint.reserved1        = 0;
                   1489:        iterator->hint.reserved2        = 0;
                   1490: 
                   1491: 
                   1492:        LogEndTime(kTraceReplaceBTreeRecord, err);
                   1493: 
                   1494:        return err;
                   1495: }
                   1496: 
                   1497: 
                   1498: 
                   1499: //////////////////////////////// BTDeleteRecord /////////////////////////////////
                   1500: 
                   1501: OSStatus       BTDeleteRecord          (FCB                                            *filePtr,
                   1502:                                                                 BTreeIterator                          *iterator )
                   1503: {
                   1504:        OSStatus                                err;
                   1505:        BTreeControlBlockPtr    btreePtr;
                   1506:        TreePathTable                   treePathTable;
                   1507:        BlockDescriptor                 nodeRec;
                   1508:        UInt32                                  nodeNum;
                   1509:        UInt16                                  index;
                   1510: 
                   1511:        LogStartTime(kTraceDeleteBTreeRecord);
                   1512: 
                   1513:        ////////////////////////// Priliminary Checks ///////////////////////////////
                   1514: 
                   1515:        nodeRec.buffer = nil;                                   // so we can call ReleaseNode
                   1516: 
                   1517:        M_ReturnErrorIf (filePtr == nil,        paramErr);
                   1518:        M_ReturnErrorIf (iterator == nil,       paramErr);
                   1519: 
                   1520:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1521:        if (btreePtr == nil)
                   1522:        {
                   1523:                err = fsBTInvalidFileErr;
                   1524:                goto ErrorExit;
                   1525:        }
                   1526: 
                   1527:        RequireFileLock(btreePtr->fileRefNum, false);
                   1528: 
                   1529: 
                   1530:        /////////////////////////////// Find Key ////////////////////////////////////
                   1531: 
                   1532:        //�� check hint for simple delete case (index > 0, numRecords > 2)
                   1533: 
                   1534:        err = SearchTree (btreePtr, &iterator->key, treePathTable, &nodeNum, &nodeRec, &index);
                   1535:        M_ExitOnError (err);                                    // record must exit for Delete
                   1536: 
                   1537: 
                   1538:        ///////////////////////////// Delete Record /////////////////////////////////
                   1539: 
                   1540:        err = DeleteTree (btreePtr, treePathTable, &nodeRec, index, 1);
                   1541:        M_ExitOnError (err);
                   1542: 
                   1543:        ++btreePtr->writeCount;
                   1544:        --btreePtr->leafRecords;
                   1545:        M_BTreeHeaderDirty (btreePtr);
                   1546: 
                   1547:        iterator->hint.nodeNum  = 0;
                   1548: 
                   1549:        LogEndTime(kTraceDeleteBTreeRecord, noErr);
                   1550: 
                   1551:        return noErr;
                   1552: 
                   1553:        ////////////////////////////// Error Exit ///////////////////////////////////
                   1554: 
                   1555: ErrorExit:
                   1556:        (void) ReleaseNode (btreePtr, &nodeRec);
                   1557: 
                   1558:        LogEndTime(kTraceDeleteBTreeRecord, err);
                   1559: 
                   1560:        return  err;
                   1561: }
                   1562: 
                   1563: 
                   1564: 
                   1565: OSStatus       BTGetInformation        (FCB                                    *filePtr,
                   1566:                                                                 UInt16                                  version,
                   1567:                                                                 BTreeInfoRec                   *info )
                   1568: {
                   1569: #pragma unused (version)
                   1570: 
                   1571:        BTreeControlBlockPtr    btreePtr;
                   1572: 
                   1573: 
                   1574:        M_ReturnErrorIf (filePtr == nil,        paramErr);
                   1575: 
                   1576:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1577: 
                   1578:        RequireFileLock(btreePtr->fileRefNum, true);
                   1579: 
                   1580:        M_ReturnErrorIf (btreePtr == nil,       fsBTInvalidFileErr);
                   1581:        M_ReturnErrorIf (info == nil,           paramErr);
                   1582: 
                   1583:        //�� check version?
                   1584: 
                   1585:        info->nodeSize          = btreePtr->nodeSize;
                   1586:        info->maxKeyLength      = btreePtr->maxKeyLength;
                   1587:        info->treeDepth         = btreePtr->treeDepth;
                   1588:        info->numRecords        = btreePtr->leafRecords;
                   1589:        info->numNodes          = btreePtr->totalNodes;
                   1590:        info->numFreeNodes      = btreePtr->freeNodes;
                   1591:        info->lastfsync         = btreePtr->lastfsync;
                   1592:        info->reserved          = 0;
                   1593: 
                   1594:        return noErr;
                   1595: }
                   1596: 
                   1597: 
                   1598: 
                   1599: /*-------------------------------------------------------------------------------
                   1600: Routine:       BTFlushPath     -       Flush BTreeControlBlock to Header Node.
                   1601: 
                   1602: Function:      Brief_description_of_the_function_and_any_side_effects
                   1603: 
                   1604: 
                   1605: Input:         pathPtr         - pointer to path control block for B*Tree file to flush
                   1606: 
                   1607: Output:                none
                   1608: 
                   1609: Result:                noErr           - success
                   1610:                        != noErr        - failure
                   1611: -------------------------------------------------------------------------------*/
                   1612: 
                   1613: OSStatus       BTFlushPath                             (FCB                                    *filePtr)
                   1614: {
                   1615:        OSStatus                                err;
                   1616:        BTreeControlBlockPtr    btreePtr;
                   1617: 
                   1618: 
                   1619:        LogStartTime(kTraceFlushBTree);
                   1620: 
                   1621:        M_ReturnErrorIf (filePtr == nil,        paramErr);
                   1622: 
                   1623:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1624: 
                   1625:        M_ReturnErrorIf (btreePtr == nil,       fsBTInvalidFileErr);
                   1626: 
                   1627:        RequireFileLock(btreePtr->fileRefNum, false);
                   1628: 
                   1629:        err = UpdateHeader (btreePtr);
                   1630: 
                   1631:        LogEndTime(kTraceFlushBTree, err);
                   1632: 
                   1633:        return  err;
                   1634: }
                   1635: 
                   1636: 
                   1637: 
                   1638: /*-------------------------------------------------------------------------------
                   1639: Routine:       BTInvalidateHint        -       Invalidates the hint within a BTreeInterator.
                   1640: 
                   1641: Function:      Invalidates the hint within a BTreeInterator.
                   1642: 
                   1643: 
                   1644: Input:         iterator        - pointer to BTreeIterator
                   1645: 
                   1646: Output:                iterator        - iterator with the hint.nodeNum cleared
                   1647: 
                   1648: Result:                noErr                   - success
                   1649:                        paramErr        - iterator == nil
                   1650: -------------------------------------------------------------------------------*/
                   1651: 
                   1652: 
                   1653: OSStatus       BTInvalidateHint        (BTreeIterator                          *iterator )
                   1654: {
                   1655:        if (iterator == nil)
                   1656:                return  paramErr;
                   1657: 
                   1658:        iterator->hint.nodeNum = 0;
                   1659: 
                   1660:        return  noErr;
                   1661: }
                   1662: 
                   1663: 
                   1664: 
                   1665: 
                   1666: /*-------------------------------------------------------------------------------
                   1667: Routine:       BTGetLastSync
                   1668: 
                   1669: Function:      Returns the last time that this btree was flushed, does not include header.
                   1670: 
                   1671: Input:         filePtr - pointer file control block
                   1672: 
                   1673: Output:                lastfsync       - time in seconds of last update
                   1674: 
                   1675: Result:                noErr                   - success
                   1676:                        paramErr        - iterator == nil
                   1677: -------------------------------------------------------------------------------*/
                   1678: 
                   1679: 
                   1680: OSStatus       BTGetLastSync           (FCB                                    *filePtr,
                   1681:                                                                 UInt32                                 *lastsync)
                   1682: {
                   1683:        BTreeControlBlockPtr    btreePtr;
                   1684: 
                   1685: 
                   1686:        M_ReturnErrorIf (filePtr == nil,        paramErr);
                   1687: 
                   1688:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1689:        
                   1690:        /* Maybe instead of requiring a lock..an atomic set might be more appropriate */
                   1691:        RequireFileLock(btreePtr->fileRefNum, true);
                   1692: 
                   1693:        M_ReturnErrorIf (btreePtr == nil,       fsBTInvalidFileErr);
                   1694:        M_ReturnErrorIf (lastsync == nil,       paramErr);
                   1695: 
                   1696:        *lastsync               = btreePtr->lastfsync;
                   1697: 
                   1698:        return noErr;
                   1699: }
                   1700: 
                   1701: 
                   1702: 
                   1703: 
                   1704: /*-------------------------------------------------------------------------------
                   1705: Routine:       BTSetLastSync
                   1706: 
                   1707: Function:      Sets the last time that this btree was flushed, does not include header.
                   1708: 
                   1709: 
                   1710: Input:         fcb     - pointer file control block
                   1711: 
                   1712: Output:                lastfsync       - time in seconds of last update
                   1713: 
                   1714: Result:                noErr                   - success
                   1715:                        paramErr        - iterator == nil
                   1716: -------------------------------------------------------------------------------*/
                   1717: 
                   1718: 
                   1719: OSStatus       BTSetLastSync           (FCB                                    *filePtr,
                   1720:                                                                 UInt32                                 lastsync)
                   1721: {
                   1722:        BTreeControlBlockPtr    btreePtr;
                   1723: 
                   1724: 
                   1725:        M_ReturnErrorIf (filePtr == nil,        paramErr);
                   1726: 
                   1727:        btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
                   1728:        
                   1729:        /* Maybe instead of requiring a lock..an atomic set might be more appropriate */
                   1730:        RequireFileLock(btreePtr->fileRefNum, true);
                   1731: 
                   1732:        M_ReturnErrorIf (btreePtr == nil,       fsBTInvalidFileErr);
                   1733:        M_ReturnErrorIf (lastsync == nil,       paramErr);
                   1734: 
                   1735:        btreePtr->lastfsync = lastsync;
                   1736: 
                   1737:        return noErr;
                   1738: }
                   1739: 
                   1740: 

unix.superglobalmegacorp.com

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