Annotation of kernel/bsd/hfs/hfscommon/BTree/BTree.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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