|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: File: BTreeMiscOps.c ! 24: ! 25: Contains: Miscellaneous operations for the BTree Module. ! 26: ! 27: Version: xxx put the technology version here xxx ! 28: ! 29: Written by: Gordon Sheridan and Bill Bruffey ! 30: ! 31: Copyright: � 1992-1999 by Apple Computer, Inc., all rights reserved. ! 32: ! 33: File Ownership: ! 34: ! 35: DRI: Don Brady ! 36: ! 37: Other Contact: Mark Day ! 38: ! 39: Technology: File Systems ! 40: ! 41: Writers: ! 42: ! 43: (DSH) Deric Horn ! 44: (msd) Mark Day ! 45: (djb) Don Brady ! 46: ! 47: Change History (most recent first): ! 48: ! 49: <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6. ! 50: <CS2> 9/4/97 djb Optimize TrySimpleReplace for the case where record size is not ! 51: changing. ! 52: <CS1> 4/23/97 djb first checked in ! 53: ! 54: <HFS7> 3/31/97 djb Move ClearMemory to Utilities.c. ! 55: <HFS6> 3/17/97 DSH Casting for DFA ! 56: <HFS5> 2/27/97 msd Remove temporary fix from last revision. BTree EOF's should be ! 57: correct now, so check for strict equality. ! 58: <HFS4> 2/26/97 msd Fix a casting problem in ClearMemory. TEMPORARY FIX: Made ! 59: VerifyHeader more lenient, allowing the EOF to be greater than ! 60: the amount actually used by nodes; this should really be fixed ! 61: in the formatting code (which needs to compute the real BTree ! 62: sizes before writing the volume header). ! 63: <HFS3> 2/19/97 djb Added ClearMemory. Changed CalcKeyLength to KeyLength. ! 64: <HFS2> 1/3/97 djb Added support for large keys. ! 65: <HFS1> 12/19/96 djb first checked in ! 66: ! 67: History applicable to original Scarecrow Design: ! 68: ! 69: <9> 10/25/96 ser Changing for new VFPI ! 70: <8> 10/18/96 ser Converting over VFPI changes ! 71: <7> 9/17/96 dkh More BTree statistics. Change IsItAHint to not always check to ! 72: see if the hint node is allocated. ! 73: <6> 9/16/96 dkh Revised BTree statistics. ! 74: <5> 6/20/96 dkh Radar #1358740. Change from using Pools to debug MemAllocators. ! 75: <4> 1/22/96 dkh Change Pools.i inclusion to PoolsPriv.i ! 76: <3> 1/10/96 msd Change 64-bit math to use real function names from Math64.i. ! 77: <2> 12/7/95 dkh D10E2 build. Changed usage of Ref data type to LogicalAddress. ! 78: <1> 10/18/95 rst Moved from Scarecrow project. ! 79: ! 80: <19> 4/26/95 prp In UpdateHeader, clear the dirty flag after the BTree is updated. ! 81: <18> 1/12/95 wjk Adopt Model FileSystem changes in D5. ! 82: <17> 11/16/94 prp Add IsItAHint routine and use it whenever hint's node number was ! 83: used for testing. ! 84: <16> 10/5/94 bk add pools.h include file ! 85: <15> 9/30/94 prp Get in sync with D2 interface changes. ! 86: <14> 7/22/94 wjk Convert to the new set of header files. ! 87: <13> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and ! 88: NRCmds environments. ! 89: <12> 11/30/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and ! 90: NRCmds environments. ! 91: <11> 11/23/93 wjk Changes required to compile on the RS6000. ! 92: <10> 8/31/93 prp Use U64SetU instead of S64Set. ! 93: <9> 6/2/93 gs Update for changes to FSErrors.h and add some comments. ! 94: <8> 5/21/93 gs Modify UpdateHeader to write out attributes. Remove ! 95: Get/UpdateNode from TrySimpleReplace. ! 96: <7> 5/10/93 gs Add TrySimpleReplace routine. ! 97: <6> 3/23/93 gs Change MoveData to take void * instead of Ptr. Add UpdateHeader ! 98: and ClearBytes routines. ! 99: <5> 2/8/93 gs Add FindIteratorPosition. ! 100: <4> 12/10/92 gs Implement CheckKeyDescriptor and the KeyDescriptor interpreter. ! 101: <3> 12/8/92 gs Add GetKeyDescriptor, VerifyHeader, and Alloc/Dealloc memory ! 102: routines. ! 103: <2> 12/2/92 gs Add CompareKeys routine. ! 104: <1> 11/15/92 gs first checked in ! 105: ! 106: */ ! 107: ! 108: #include "../headers/BTreesPrivate.h" ! 109: ! 110: ! 111: ////////////////////////////// Routine Definitions ////////////////////////////// ! 112: ! 113: /*------------------------------------------------------------------------------- ! 114: Routine: CalcKeyRecordSize - Return size of combined key/record structure. ! 115: ! 116: Function: Rounds keySize and recSize so they will end on word boundaries. ! 117: Does NOT add size of offset. ! 118: ! 119: Input: keySize - length of key (including length field) ! 120: recSize - length of record data ! 121: ! 122: Output: none ! 123: ! 124: Result: UInt16 - size of combined key/record that will be inserted in btree ! 125: -------------------------------------------------------------------------------*/ ! 126: ! 127: UInt16 CalcKeyRecordSize (UInt16 keySize, ! 128: UInt16 recSize ) ! 129: { ! 130: if ( M_IsOdd (keySize) ) keySize += 1; // pad byte ! 131: ! 132: if (M_IsOdd (recSize) ) recSize += 1; // pad byte ! 133: ! 134: return (keySize + recSize); ! 135: } ! 136: ! 137: ! 138: ! 139: /*------------------------------------------------------------------------------- ! 140: Routine: VerifyHeader - Validate fields of the BTree header record. ! 141: ! 142: Function: Examines the fields of the BTree header record to determine if the ! 143: fork appears to contain a valid BTree. ! 144: ! 145: Input: forkPtr - pointer to fork control block ! 146: header - pointer to BTree header ! 147: ! 148: ! 149: Result: noErr - success ! 150: != noErr - failure ! 151: -------------------------------------------------------------------------------*/ ! 152: ! 153: OSStatus VerifyHeader (FCB *filePtr, ! 154: BTHeaderRec *header ) ! 155: { ! 156: UInt32 forkSize; ! 157: UInt32 totalNodes; ! 158: ! 159: ! 160: switch (header->nodeSize) // node size == 512*2^n ! 161: { ! 162: case 512: ! 163: case 1024: ! 164: case 2048: ! 165: case 4096: ! 166: case 8192: ! 167: case 16384: ! 168: case 32768: break; ! 169: default: return fsBTInvalidHeaderErr; //�� E_BadNodeType ! 170: } ! 171: ! 172: totalNodes = header->totalNodes; ! 173: ! 174: forkSize = totalNodes * header->nodeSize; ! 175: ! 176: if ( forkSize != filePtr->fcbEOF ) ! 177: return fsBTInvalidHeaderErr; ! 178: ! 179: if ( header->freeNodes >= totalNodes ) ! 180: return fsBTInvalidHeaderErr; ! 181: ! 182: if ( header->rootNode >= totalNodes ) ! 183: return fsBTInvalidHeaderErr; ! 184: ! 185: if ( header->firstLeafNode >= totalNodes ) ! 186: return fsBTInvalidHeaderErr; ! 187: ! 188: if ( header->lastLeafNode >= totalNodes ) ! 189: return fsBTInvalidHeaderErr; ! 190: ! 191: if ( header->treeDepth > kMaxTreeDepth ) ! 192: return fsBTInvalidHeaderErr; ! 193: ! 194: ! 195: /////////////////////////// Check BTree Type //////////////////////////////// ! 196: ! 197: switch (header->btreeType) ! 198: { ! 199: case 0: // HFS Type - no Key Descriptor ! 200: case kUserBTreeType: // with Key Descriptors etc. ! 201: case kReservedBTreeType: // Desktop Mgr BTree ? ! 202: break; ! 203: ! 204: default: return fsBTUnknownVersionErr; ! 205: } ! 206: ! 207: return noErr; ! 208: } ! 209: ! 210: ! 211: ! 212: /*------------------------------------------------------------------------------- ! 213: Routine: UpdateHeader - Write BTreeInfoRec fields to Header node. ! 214: ! 215: Function: Checks the kBTHeaderDirty flag in the BTreeInfoRec and updates the ! 216: header node if necessary. ! 217: ! 218: Input: btreePtr - pointer to BTreeInfoRec ! 219: ! 220: ! 221: Result: noErr - success ! 222: != noErr - failure ! 223: -------------------------------------------------------------------------------*/ ! 224: ! 225: OSStatus UpdateHeader (BTreeControlBlockPtr btreePtr) ! 226: { ! 227: OSStatus err; ! 228: BlockDescriptor node; ! 229: BTHeaderRec *header; ! 230: ! 231: ! 232: if ((btreePtr->flags & kBTHeaderDirty) == 0) // btree info already flushed ! 233: return noErr; ! 234: ! 235: ! 236: err = GetNode (btreePtr, kHeaderNodeNum, &node ); ! 237: if (err != noErr) ! 238: return err; ! 239: ! 240: header = (BTHeaderRec*) ((void *)node.buffer + sizeof(BTNodeDescriptor)); ! 241: ! 242: header->treeDepth = btreePtr->treeDepth; ! 243: header->rootNode = btreePtr->rootNode; ! 244: header->leafRecords = btreePtr->leafRecords; ! 245: header->firstLeafNode = btreePtr->firstLeafNode; ! 246: header->lastLeafNode = btreePtr->lastLeafNode; ! 247: header->nodeSize = btreePtr->nodeSize; //�� this shouldn't change ! 248: header->maxKeyLength = btreePtr->maxKeyLength; //�� neither should this ! 249: header->totalNodes = btreePtr->totalNodes; ! 250: header->freeNodes = btreePtr->freeNodes; ! 251: header->btreeType = btreePtr->btreeType; ! 252: ! 253: // ignore header->clumpSize; //�� rename this field? ! 254: ! 255: err = UpdateNode (btreePtr, &node, 0, kLockTransaction); ! 256: ! 257: btreePtr->flags &= (~kBTHeaderDirty); ! 258: ! 259: return err; ! 260: } ! 261: ! 262: ! 263: ! 264: /*------------------------------------------------------------------------------- ! 265: Routine: FindIteratorPosition - One_line_description. ! 266: ! 267: Function: Brief_description_of_the_function_and_any_side_effects ! 268: ! 269: Algorithm: see FSC.BT.BTIterateRecord.PICT ! 270: ! 271: Note: //�� document side-effects of bad node hints ! 272: ! 273: Input: btreePtr - description ! 274: iterator - description ! 275: ! 276: ! 277: Output: iterator - description ! 278: left - description ! 279: middle - description ! 280: right - description ! 281: nodeNum - description ! 282: returnIndex - description ! 283: foundRecord - description ! 284: ! 285: ! 286: Result: noErr - success ! 287: != noErr - failure ! 288: -------------------------------------------------------------------------------*/ ! 289: ! 290: OSStatus FindIteratorPosition (BTreeControlBlockPtr btreePtr, ! 291: BTreeIteratorPtr iterator, ! 292: BlockDescriptor *left, ! 293: BlockDescriptor *middle, ! 294: BlockDescriptor *right, ! 295: UInt32 *returnNodeNum, ! 296: UInt16 *returnIndex, ! 297: Boolean *foundRecord ) ! 298: { ! 299: OSStatus err; ! 300: Boolean foundIt; ! 301: UInt32 nodeNum; ! 302: UInt16 leftIndex, index, rightIndex; ! 303: Boolean validHint; ! 304: ! 305: // assume btreePtr valid ! 306: // assume left, middle, right point to BlockDescriptors ! 307: // assume nodeNum points to UInt32 ! 308: // assume index points to UInt16 ! 309: // assume foundRecord points to Boolean ! 310: ! 311: left->buffer = nil; ! 312: middle->buffer = nil; ! 313: right->buffer = nil; ! 314: ! 315: foundIt = false; ! 316: ! 317: if (iterator == nil) // do we have an iterator? ! 318: { ! 319: err = fsBTInvalidIteratorErr; ! 320: goto ErrorExit; ! 321: } ! 322: ! 323: err = IsItAHint (btreePtr, iterator, &validHint); ! 324: M_ExitOnError (err); ! 325: ! 326: nodeNum = iterator->hint.nodeNum; ! 327: if (! validHint) // does the hint appear to be valid? ! 328: { ! 329: goto SearchTheTree; ! 330: } ! 331: ! 332: err = GetNode (btreePtr, nodeNum, middle); ! 333: if( err == fsBTInvalidNodeErr ) // returned if nodeNum is out of range ! 334: goto SearchTheTree; ! 335: ! 336: M_ExitOnError (err); ! 337: ! 338: if ( ((NodeDescPtr) middle->buffer)->kind != kBTLeafNode || ! 339: ((NodeDescPtr) middle->buffer)->numRecords <= 0 ) ! 340: { ! 341: goto SearchTheTree; ! 342: } ! 343: ! 344: ++btreePtr->numValidHints; ! 345: ! 346: foundIt = SearchNode (btreePtr, middle->buffer, &iterator->key, &index); ! 347: if (foundIt == true) ! 348: { ! 349: goto SuccessfulExit; ! 350: } ! 351: ! 352: if (index == 0) ! 353: { ! 354: if (((NodeDescPtr) middle->buffer)->bLink == 0) // before 1st btree record ! 355: { ! 356: goto SuccessfulExit; ! 357: } ! 358: ! 359: nodeNum = ((NodeDescPtr) middle->buffer)->bLink; ! 360: ! 361: err = GetLeftSiblingNode (btreePtr, middle->buffer, left); ! 362: M_ExitOnError (err); ! 363: ! 364: if ( ((NodeDescPtr) left->buffer)->kind != kBTLeafNode || ! 365: ((NodeDescPtr) left->buffer)->numRecords <= 0 ) ! 366: { ! 367: goto SearchTheTree; ! 368: } ! 369: ! 370: foundIt = SearchNode (btreePtr, left->buffer, &iterator->key, &leftIndex); ! 371: if (foundIt == true) ! 372: { ! 373: *right = *middle; ! 374: *middle = *left; ! 375: left->buffer = nil; ! 376: index = leftIndex; ! 377: ! 378: goto SuccessfulExit; ! 379: } ! 380: ! 381: if (leftIndex == 0) // we're lost! ! 382: { ! 383: goto SearchTheTree; ! 384: } ! 385: else if (leftIndex >= ((NodeDescPtr) left->buffer)->numRecords) ! 386: { ! 387: nodeNum = ((NodeDescPtr) left->buffer)->fLink; ! 388: ! 389: PanicIf (index != 0, "\pFindIteratorPosition: index != 0"); //�� just checking... ! 390: goto SuccessfulExit; ! 391: } ! 392: else ! 393: { ! 394: *right = *middle; ! 395: *middle = *left; ! 396: left->buffer = nil; ! 397: index = leftIndex; ! 398: ! 399: goto SuccessfulExit; ! 400: } ! 401: } ! 402: else if (index >= ((NodeDescPtr) middle->buffer)->numRecords) ! 403: { ! 404: if (((NodeDescPtr) middle->buffer)->fLink == 0) // beyond last record ! 405: { ! 406: goto SuccessfulExit; ! 407: } ! 408: ! 409: nodeNum = ((NodeDescPtr) middle->buffer)->fLink; ! 410: ! 411: err = GetRightSiblingNode (btreePtr, middle->buffer, right); ! 412: M_ExitOnError (err); ! 413: ! 414: if ( ((NodeDescPtr) right->buffer)->kind != kBTLeafNode || ! 415: ((NodeDescPtr) right->buffer)->numRecords <= 0 ) ! 416: { ! 417: goto SearchTheTree; ! 418: } ! 419: ! 420: foundIt = SearchNode (btreePtr, right->buffer, &iterator->key, &rightIndex); ! 421: if (rightIndex >= ((NodeDescPtr) right->buffer)->numRecords) // we're lost ! 422: { ! 423: goto SearchTheTree; ! 424: } ! 425: else // we found it, or rightIndex==0, or rightIndex<numRecs ! 426: { ! 427: *left = *middle; ! 428: *middle = *right; ! 429: right->buffer = nil; ! 430: index = rightIndex; ! 431: ! 432: goto SuccessfulExit; ! 433: } ! 434: } ! 435: ! 436: ! 437: //////////////////////////// Search The Tree //////////////////////////////// ! 438: ! 439: SearchTheTree: ! 440: { ! 441: TreePathTable treePathTable; // so we only use stack space if we need to ! 442: ! 443: err = ReleaseNode (btreePtr, left); M_ExitOnError (err); ! 444: err = ReleaseNode (btreePtr, middle); M_ExitOnError (err); ! 445: err = ReleaseNode (btreePtr, right); M_ExitOnError (err); ! 446: ! 447: err = SearchTree ( btreePtr, &iterator->key, treePathTable, &nodeNum, middle, &index); ! 448: switch (err) //�� separate find condition from exceptions ! 449: { ! 450: case noErr: foundIt = true; break; ! 451: case fsBTRecordNotFoundErr: break; ! 452: default: goto ErrorExit; ! 453: } ! 454: } ! 455: ! 456: /////////////////////////////// Success! //////////////////////////////////// ! 457: ! 458: SuccessfulExit: ! 459: ! 460: *returnNodeNum = nodeNum; ! 461: *returnIndex = index; ! 462: *foundRecord = foundIt; ! 463: ! 464: return noErr; ! 465: ! 466: ! 467: ////////////////////////////// Error Exit /////////////////////////////////// ! 468: ! 469: ErrorExit: ! 470: ! 471: (void) ReleaseNode (btreePtr, left); ! 472: (void) ReleaseNode (btreePtr, middle); ! 473: (void) ReleaseNode (btreePtr, right); ! 474: ! 475: *returnNodeNum = 0; ! 476: *returnIndex = 0; ! 477: *foundRecord = false; ! 478: ! 479: return err; ! 480: } ! 481: ! 482: ! 483: ! 484: /////////////////////////////// CheckInsertParams /////////////////////////////// ! 485: ! 486: OSStatus CheckInsertParams (FCB *filePtr, ! 487: BTreeIterator *iterator, ! 488: FSBufferDescriptor *record, ! 489: UInt16 recordLen ) ! 490: { ! 491: BTreeControlBlockPtr btreePtr; ! 492: ! 493: if (filePtr == nil) return paramErr; ! 494: ! 495: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; ! 496: if (btreePtr == nil) return fsBTInvalidFileErr; ! 497: if (iterator == nil) return paramErr; ! 498: if (record == nil) return paramErr; ! 499: ! 500: // check total key/record size limit ! 501: if ( CalcKeyRecordSize (CalcKeySize(btreePtr, &iterator->key), recordLen) > (btreePtr->nodeSize >> 1)) ! 502: return fsBTRecordTooLargeErr; ! 503: ! 504: return noErr; ! 505: } ! 506: ! 507: ! 508: ! 509: /*------------------------------------------------------------------------------- ! 510: Routine: TrySimpleReplace - Attempts a simple insert, set, or replace. ! 511: ! 512: Function: If a hint exitst for the iterator, attempt to find the key in the hint ! 513: node. If the key is found, an insert operation fails. If the is not ! 514: found, a replace operation fails. If the key was not found, and the ! 515: insert position is greater than 0 and less than numRecords, the record ! 516: is inserted, provided there is enough freeSpace. If the key was found, ! 517: and there is more freeSpace than the difference between the new record ! 518: and the old record, the old record is deleted and the new record is ! 519: inserted. ! 520: ! 521: Assumptions: iterator key has already been checked by CheckKey ! 522: ! 523: ! 524: Input: btreePtr - description ! 525: iterator - description ! 526: record - description ! 527: recordLen - description ! 528: operation - description ! 529: ! 530: ! 531: Output: recordInserted - description ! 532: ! 533: ! 534: Result: noErr - success ! 535: E_RecordExits - insert operation failure ! 536: != noErr - GetNode, ReleaseNode, UpdateNode returned an error ! 537: -------------------------------------------------------------------------------*/ ! 538: ! 539: OSStatus TrySimpleReplace (BTreeControlBlockPtr btreePtr, ! 540: NodeDescPtr nodePtr, ! 541: BTreeIterator *iterator, ! 542: FSBufferDescriptor *record, ! 543: UInt16 recordLen, ! 544: Boolean *recordInserted ) ! 545: { ! 546: UInt32 oldSpace; ! 547: UInt32 spaceNeeded; ! 548: UInt16 index; ! 549: UInt16 keySize; ! 550: Boolean foundIt; ! 551: Boolean didItFit; ! 552: ! 553: ! 554: *recordInserted = false; // we'll assume this won't work... ! 555: ! 556: if ( nodePtr->kind != kBTLeafNode ) ! 557: return noErr; // we're in the weeds! ! 558: ! 559: foundIt = SearchNode (btreePtr, nodePtr, &iterator->key, &index); ! 560: ! 561: if ( foundIt == false ) ! 562: return noErr; // we might be lost... ! 563: ! 564: keySize = CalcKeySize(btreePtr, &iterator->key); // includes length field ! 565: ! 566: spaceNeeded = CalcKeyRecordSize (keySize, recordLen); ! 567: ! 568: oldSpace = GetRecordSize (btreePtr, nodePtr, index); ! 569: ! 570: if ( spaceNeeded == oldSpace ) ! 571: { ! 572: UInt8 * dst; ! 573: ! 574: dst = GetRecordAddress (btreePtr, nodePtr, index); ! 575: ! 576: if ( M_IsOdd (keySize) ) ! 577: ++keySize; // add pad byte ! 578: ! 579: dst += keySize; // skip over key to point at record ! 580: ! 581: BlockMoveData(record->bufferAddress, dst, recordLen); // blast away... ! 582: ! 583: *recordInserted = true; ! 584: } ! 585: else if ( (GetNodeFreeSize(btreePtr, nodePtr) + oldSpace) >= spaceNeeded) ! 586: { ! 587: DeleteRecord (btreePtr, nodePtr, index); ! 588: ! 589: didItFit = InsertKeyRecord (btreePtr, nodePtr, index, ! 590: &iterator->key, KeyLength(btreePtr, &iterator->key), ! 591: record->bufferAddress, recordLen); ! 592: PanicIf (didItFit == false, "\pTrySimpleInsert: InsertKeyRecord returned false!"); ! 593: ! 594: *recordInserted = true; ! 595: } ! 596: // else not enough space... ! 597: ! 598: return noErr; ! 599: } ! 600: ! 601: ! 602: /*------------------------------------------------------------------------------- ! 603: Routine: IsItAHint - checks the hint within a BTreeInterator. ! 604: ! 605: Function: checks the hint within a BTreeInterator. If it is non-zero, it may ! 606: possibly be valid. ! 607: ! 608: Input: btreePtr - pointer to control block for BTree file ! 609: iterator - pointer to BTreeIterator ! 610: ! 611: Output: answer - true if the hint looks reasonable ! 612: - false if the hint is 0 ! 613: ! 614: Result: noErr - success ! 615: -------------------------------------------------------------------------------*/ ! 616: ! 617: ! 618: OSStatus IsItAHint (BTreeControlBlockPtr btreePtr, BTreeIterator *iterator, Boolean *answer) ! 619: { ! 620: ++btreePtr->numHintChecks; ! 621: ! 622: #if DEBUG_BUILD ! 623: if (iterator->hint.nodeNum >= btreePtr->totalNodes) ! 624: { ! 625: *answer = false; ! 626: } else ! 627: ! 628: #endif ! 629: if (iterator->hint.nodeNum == 0) ! 630: { ! 631: *answer = false; ! 632: } ! 633: else ! 634: { ! 635: *answer = true; ! 636: ++btreePtr->numPossibleHints; ! 637: } ! 638: ! 639: return noErr; ! 640: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.