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