|
|
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: BTreeAllocate.c ! 24: ! 25: Contains: BTree Node Allocation routines 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: (djb) Don Brady ! 44: (ser) Scott Roberts ! 45: (msd) Mark Day ! 46: ! 47: Change History (most recent first): ! 48: ! 49: <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6. ! 50: <CS3> 11/24/97 djb Remove some debug code (Panic calls). ! 51: <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB. ! 52: <CS1> 4/23/97 djb first checked in ! 53: ! 54: <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType. ! 55: <HFS1> 12/19/96 djb first checked in ! 56: ! 57: History applicable to original Scarecrow Design: ! 58: ! 59: <4> 10/25/96 ser Changing for new VFPI ! 60: <3> 10/18/96 ser Converting over VFPI changes ! 61: <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i. ! 62: <1> 10/18/95 rst Moved from Scarecrow project. ! 63: ! 64: <8> 1/12/95 wjk Adopt Model FileSystem changes in D5. ! 65: <7> 9/30/94 prp Get in sync with D2 interface changes. ! 66: <6> 7/22/94 wjk Convert to the new set of header files. ! 67: <5> 8/31/93 prp Use U64SetU instead of S64Set. ! 68: <4> 5/21/93 gs Fix ExtendBTree bug. ! 69: <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode. ! 70: <2> 3/23/93 gs finish ExtendBTree routine. ! 71: <1> 2/8/93 gs first checked in ! 72: <0> 1/1/93 gs begin AllocateNode and FreeNode ! 73: ! 74: */ ! 75: ! 76: #include "../headers/BTreesPrivate.h" ! 77: ! 78: ///////////////////// Routines Internal To BTreeAllocate.c ////////////////////// ! 79: ! 80: OSStatus GetMapNode (BTreeControlBlockPtr btreePtr, ! 81: BlockDescriptor *nodePtr, ! 82: UInt16 **mapPtr, ! 83: UInt16 *mapSize ); ! 84: ! 85: ///////////////////////////////////////////////////////////////////////////////// ! 86: ! 87: /*------------------------------------------------------------------------------- ! 88: ! 89: Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number. ! 90: ! 91: Function: Searches the map records for the first free node, marks it "in use" and ! 92: returns the node number found. This routine should really only be called ! 93: when we know there are free blocks, otherwise it's just a waste of time. ! 94: ! 95: Note: We have to examine map nodes a word at a time rather than a long word ! 96: because the External BTree Mgr used map records that were not an integral ! 97: number of long words. Too bad. In our spare time could develop a more ! 98: sophisticated algorithm that read map records by long words (and long ! 99: word aligned) and handled the spare bytes at the beginning and end ! 100: appropriately. ! 101: ! 102: Input: btreePtr - pointer to control block for BTree file ! 103: ! 104: Output: nodeNum - number of node allocated ! 105: ! 106: ! 107: Result: noErr - success ! 108: fsBTNoMoreMapNodesErr - no free blocks were found ! 109: != noErr - failure ! 110: -------------------------------------------------------------------------------*/ ! 111: ! 112: OSStatus AllocateNode (BTreeControlBlockPtr btreePtr, UInt32 *nodeNum) ! 113: { ! 114: OSStatus err; ! 115: BlockDescriptor node; ! 116: UInt16 *mapPtr, *pos; ! 117: UInt16 mapSize, size; ! 118: UInt16 freeWord; ! 119: UInt16 mask; ! 120: UInt16 bitOffset; ! 121: UInt32 nodeNumber; ! 122: ! 123: ! 124: nodeNumber = 0; // first node number of header map record ! 125: node.buffer = nil; // clear node.buffer to get header node ! 126: // - and for ErrorExit ! 127: ! 128: while (true) ! 129: { ! 130: err = GetMapNode (btreePtr, &node, &mapPtr, &mapSize); ! 131: M_ExitOnError (err); ! 132: ! 133: //////////////////////// Find Word with Free Bit //////////////////////////// ! 134: ! 135: pos = mapPtr; ! 136: size = mapSize; ! 137: size >>= 1; // convert to number of words ! 138: //�� assumes mapRecords contain an integral number of words ! 139: ! 140: while ( size-- ) ! 141: { ! 142: if ( *pos++ != 0xFFFF ) // assume test fails, and increment pos ! 143: break; ! 144: } ! 145: ! 146: --pos; // whoa! backup ! 147: ! 148: if (*pos != 0xFFFF) // hey, we got one! ! 149: break; ! 150: ! 151: nodeNumber += mapSize << 3; // covert to number of bits (nodes) ! 152: } ! 153: ! 154: ///////////////////////// Find Free Bit in Word ///////////////////////////// ! 155: ! 156: freeWord = *pos; ! 157: bitOffset = 15; ! 158: mask = 0x8000; ! 159: ! 160: do { ! 161: if ( (freeWord & mask) == 0) ! 162: break; ! 163: mask >>= 1; ! 164: } while (--bitOffset); ! 165: ! 166: ////////////////////// Calculate Free Node Number /////////////////////////// ! 167: ! 168: nodeNumber += ((pos - mapPtr) << 4) + (15 - bitOffset); // (pos-mapPtr) = # of words! ! 169: ! 170: ! 171: ///////////////////////// Check for End of Map ////////////////////////////// ! 172: ! 173: if (nodeNumber >= btreePtr->totalNodes) ! 174: { ! 175: err = fsBTFullErr; ! 176: goto ErrorExit; ! 177: } ! 178: ! 179: /////////////////////////// Allocate the Node /////////////////////////////// ! 180: ! 181: *pos |= mask; // set the map bit for the node ! 182: ! 183: err = UpdateNode (btreePtr, &node, 0, kLockTransaction); ! 184: M_ExitOnError (err); ! 185: ! 186: --btreePtr->freeNodes; ! 187: btreePtr->flags |= kBTHeaderDirty; ! 188: *nodeNum = nodeNumber; ! 189: ! 190: return noErr; ! 191: ! 192: ////////////////////////////////// Error Exit /////////////////////////////////// ! 193: ! 194: ErrorExit: ! 195: ! 196: (void) ReleaseNode (btreePtr, &node); ! 197: *nodeNum = 0; ! 198: ! 199: return err; ! 200: } ! 201: ! 202: ! 203: ! 204: /*------------------------------------------------------------------------------- ! 205: ! 206: Routine: FreeNode - Clear allocation bit for node. ! 207: ! 208: Function: Finds the bit representing the node specified by nodeNum in the node ! 209: map and clears the bit. ! 210: ! 211: ! 212: Input: btreePtr - pointer to control block for BTree file ! 213: nodeNum - number of node to mark free ! 214: ! 215: Output: none ! 216: ! 217: Result: noErr - success ! 218: fsBTNoMoreMapNodesErr - node number is beyond end of node map ! 219: != noErr - GetNode or ReleaseNode encountered some difficulty ! 220: -------------------------------------------------------------------------------*/ ! 221: ! 222: OSStatus FreeNode (BTreeControlBlockPtr btreePtr, UInt32 nodeNum) ! 223: { ! 224: OSStatus err; ! 225: BlockDescriptor node; ! 226: UInt32 nodeIndex; ! 227: UInt16 mapSize; ! 228: UInt16 *mapPos; ! 229: UInt16 bitOffset; ! 230: ! 231: ! 232: //////////////////////////// Find Map Record //////////////////////////////// ! 233: nodeIndex = 0; // first node number of header map record ! 234: node.buffer = nil; // invalidate node.buffer to get header node ! 235: ! 236: while (nodeNum >= nodeIndex) ! 237: { ! 238: err = GetMapNode (btreePtr, &node, &mapPos, &mapSize); ! 239: M_ExitOnError (err); ! 240: ! 241: nodeIndex += mapSize << 3; // covert to number of bits (nodes) ! 242: } ! 243: ! 244: //////////////////////////// Mark Node Free ///////////////////////////////// ! 245: ! 246: nodeNum -= (nodeIndex - (mapSize << 3)); // relative to this map record ! 247: bitOffset = 15 - (nodeNum & 0x0000000F); // last 4 bits are bit offset ! 248: mapPos += nodeNum >> 4; // point to word containing map bit ! 249: M_ClearBitNum (*mapPos, bitOffset); // clear it ! 250: ! 251: err = UpdateNode (btreePtr, &node, 0, kLockTransaction); ! 252: M_ExitOnError (err); ! 253: ! 254: ! 255: ++btreePtr->freeNodes; ! 256: btreePtr->flags |= kBTHeaderDirty; //�� how about a macro for this ! 257: ! 258: return noErr; ! 259: ! 260: ErrorExit: ! 261: ! 262: (void) ReleaseNode (btreePtr, &node); ! 263: ! 264: return err; ! 265: } ! 266: ! 267: ! 268: ! 269: /*------------------------------------------------------------------------------- ! 270: ! 271: Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes. ! 272: ! 273: Function: This routine calls the the FSAgent to extend the end of fork, if necessary, ! 274: to accomodate the number of nodes requested. It then allocates as many ! 275: map nodes as are necessary to account for all the nodes in the B*Tree. ! 276: If newTotalNodes is less than the current number of nodes, no action is ! 277: taken. ! 278: ! 279: Note: Internal HFS File Manager BTree Module counts on an integral number of ! 280: long words in map records, although they are not long word aligned. ! 281: ! 282: Input: btreePtr - pointer to control block for BTree file ! 283: newTotalNodes - total number of nodes the B*Tree is to extended to ! 284: ! 285: Output: none ! 286: ! 287: Result: noErr - success ! 288: != noErr - failure ! 289: -------------------------------------------------------------------------------*/ ! 290: ! 291: OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr, ! 292: UInt32 newTotalNodes ) ! 293: { ! 294: OSStatus err; ! 295: FCB *filePtr; ! 296: FSSize minEOF, maxEOF; ! 297: UInt16 nodeSize; ! 298: UInt32 oldTotalNodes; ! 299: UInt32 newMapNodes; ! 300: UInt32 mapBits, totalMapBits; ! 301: UInt32 recStartBit; ! 302: UInt32 nodeNum, nextNodeNum; ! 303: UInt32 firstNewMapNodeNum, lastNewMapNodeNum; ! 304: BlockDescriptor mapNode, newNode; ! 305: UInt16 *mapPos; ! 306: UInt16 *mapStart; ! 307: UInt16 mapSize; ! 308: UInt16 mapNodeRecSize; ! 309: UInt32 bitInWord, bitInRecord; ! 310: UInt16 mapIndex; ! 311: ! 312: ! 313: oldTotalNodes = btreePtr->totalNodes; ! 314: if (newTotalNodes <= oldTotalNodes) // we're done! ! 315: return noErr; ! 316: ! 317: nodeSize = btreePtr->nodeSize; ! 318: filePtr = GetFileControlBlock(btreePtr->fileRefNum); ! 319: ! 320: mapNode.buffer = nil; ! 321: newNode.buffer = nil; ! 322: ! 323: mapNodeRecSize = nodeSize - sizeof(BTNodeDescriptor) - 6; // 2 bytes of free space (see note) ! 324: ! 325: //�� update for proper 64 bit arithmetic!! ! 326: ! 327: ! 328: //////////////////////// Count Bits In Node Map ///////////////////////////// ! 329: ! 330: totalMapBits = 0; ! 331: do { ! 332: err = GetMapNode (btreePtr, &mapNode, &mapStart, &mapSize); ! 333: M_ExitOnError (err); ! 334: ! 335: mapBits = mapSize << 3; // mapSize (in bytes) * 8 ! 336: recStartBit = totalMapBits; // bit number of first bit in map record ! 337: totalMapBits += mapBits; ! 338: ! 339: } while ( ((BTNodeDescriptor*)mapNode.buffer)->fLink != 0 ); ! 340: ! 341: if (DEBUG_BUILD && totalMapBits != CalcMapBits (btreePtr)) ! 342: Panic ("\pExtendBTree: totalMapBits != CalcMapBits"); ! 343: ! 344: /////////////////////// Extend LEOF If Necessary //////////////////////////// ! 345: ! 346: minEOF = newTotalNodes * nodeSize; ! 347: if ( filePtr->fcbEOF < minEOF ) ! 348: { ! 349: //�� ! 350: //�� ???? Does this B*Tree pack stop working when LEOF > 2^32-1? ! 351: //�� ! 352: maxEOF = ((UInt32)0xFFFFFFFFL); ! 353: ! 354: err = btreePtr->setEndOfForkProc (btreePtr->fileRefNum, minEOF, maxEOF); ! 355: M_ExitOnError (err); ! 356: } ! 357: ! 358: ! 359: //////////////////// Calc New Total Number Of Nodes ///////////////////////// ! 360: ! 361: newTotalNodes = filePtr->fcbEOF / nodeSize; //�� hack! ! 362: //�� do we wish to perform any verification of newTotalNodes at this point? ! 363: ! 364: btreePtr->totalNodes = newTotalNodes; //�� do we need to update freeNodes here too? ! 365: ! 366: ! 367: ////////////// Calculate Number Of New Map Nodes Required /////////////////// ! 368: ! 369: newMapNodes = 0; ! 370: if (newTotalNodes > totalMapBits) ! 371: { ! 372: newMapNodes = (((newTotalNodes - totalMapBits) >> 3) / mapNodeRecSize) + 1; ! 373: firstNewMapNodeNum = oldTotalNodes; ! 374: lastNewMapNodeNum = firstNewMapNodeNum + newMapNodes - 1; ! 375: } ! 376: else ! 377: { ! 378: err = ReleaseNode (btreePtr, &mapNode); ! 379: M_ExitOnError (err); ! 380: ! 381: goto Success; ! 382: } ! 383: ! 384: ! 385: /////////////////////// Initialize New Map Nodes //////////////////////////// ! 386: ! 387: ((BTNodeDescriptor*)mapNode.buffer)->fLink = firstNewMapNodeNum; ! 388: ! 389: nodeNum = firstNewMapNodeNum; ! 390: while (true) ! 391: { ! 392: err = GetNewNode (btreePtr, nodeNum, &newNode); ! 393: M_ExitOnError (err); ! 394: ! 395: ((NodeDescPtr)newNode.buffer)->numRecords = 1; ! 396: ((NodeDescPtr)newNode.buffer)->kind = kBTMapNode; ! 397: ! 398: // set free space offset ! 399: *(UInt16 *)((Ptr)newNode.buffer + nodeSize - 4) = nodeSize - 6; ! 400: ! 401: if (nodeNum++ == lastNewMapNodeNum) ! 402: break; ! 403: ! 404: ((BTNodeDescriptor*)newNode.buffer)->fLink = nodeNum; // point to next map node ! 405: ! 406: err = UpdateNode (btreePtr, &newNode, 0, kLockTransaction); ! 407: M_ExitOnError (err); ! 408: } ! 409: ! 410: err = UpdateNode (btreePtr, &newNode, 0, kLockTransaction); ! 411: M_ExitOnError (err); ! 412: ! 413: ! 414: ///////////////////// Mark New Map Nodes Allocated ////////////////////////// ! 415: ! 416: nodeNum = firstNewMapNodeNum; ! 417: do { ! 418: bitInRecord = nodeNum - recStartBit; ! 419: ! 420: while (bitInRecord >= mapBits) ! 421: { ! 422: nextNodeNum = ((NodeDescPtr)mapNode.buffer)->fLink; ! 423: if ( nextNodeNum == 0) ! 424: { ! 425: err = fsBTNoMoreMapNodesErr; ! 426: goto ErrorExit; ! 427: } ! 428: ! 429: err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction); ! 430: M_ExitOnError (err); ! 431: ! 432: err = GetNode (btreePtr, nextNodeNum, &mapNode); ! 433: M_ExitOnError (err); ! 434: ! 435: mapIndex = 0; ! 436: ! 437: mapStart = (UInt16 *) GetRecordAddress (btreePtr, mapNode.buffer, mapIndex); ! 438: mapSize = GetRecordSize (btreePtr, mapNode.buffer, mapIndex); ! 439: ! 440: if (DEBUG_BUILD && mapSize != M_MapRecordSize (btreePtr->nodeSize) ) ! 441: { ! 442: Panic ("\pExtendBTree: mapSize != M_MapRecordSize"); ! 443: } ! 444: ! 445: mapBits = mapSize << 3; // mapSize (in bytes) * 8 ! 446: recStartBit = totalMapBits; // bit number of first bit in map record ! 447: totalMapBits += mapBits; ! 448: ! 449: bitInRecord = nodeNum - recStartBit; ! 450: } ! 451: ! 452: mapPos = mapStart + ((nodeNum - recStartBit) >> 4); ! 453: bitInWord = 15 - ((nodeNum - recStartBit) & 0x0000000F); ! 454: M_SetBitNum (*mapPos, bitInWord); ! 455: ! 456: ++nodeNum; ! 457: ! 458: } while (nodeNum <= lastNewMapNodeNum); ! 459: ! 460: err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction); ! 461: M_ExitOnError (err); ! 462: ! 463: ! 464: //////////////////////////////// Success //////////////////////////////////// ! 465: ! 466: Success: ! 467: ! 468: btreePtr->totalNodes = newTotalNodes; ! 469: btreePtr->freeNodes += (newTotalNodes - oldTotalNodes) - newMapNodes; ! 470: ! 471: btreePtr->flags |= kBTHeaderDirty; //�� how about a macro for this ! 472: ! 473: return noErr; ! 474: ! 475: ! 476: ////////////////////////////// Error Exit /////////////////////////////////// ! 477: ! 478: ErrorExit: ! 479: ! 480: (void) ReleaseNode (btreePtr, &mapNode); ! 481: (void) ReleaseNode (btreePtr, &newNode); ! 482: ! 483: return err; ! 484: } ! 485: ! 486: ! 487: ! 488: /*------------------------------------------------------------------------------- ! 489: ! 490: Routine: GetMapNode - Get the next map node and pointer to the map record. ! 491: ! 492: Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases ! 493: it and gets the next node. If nodePtr->buffer is nil, then the header ! 494: node is retrieved. ! 495: ! 496: ! 497: Input: btreePtr - pointer to control block for BTree file ! 498: nodePtr - pointer to a BlockDescriptor of a map node ! 499: ! 500: Output: nodePtr - pointer to the BlockDescriptor for the next map node ! 501: mapPtr - pointer to the map record within the map node ! 502: mapSize - number of bytes in the map record ! 503: ! 504: Result: noErr - success ! 505: fsBTNoMoreMapNodesErr - we've run out of map nodes ! 506: fsBTInvalidNodeErr - bad node, or not node type kMapNode ! 507: != noErr - failure ! 508: -------------------------------------------------------------------------------*/ ! 509: ! 510: OSStatus GetMapNode (BTreeControlBlockPtr btreePtr, ! 511: BlockDescriptor *nodePtr, ! 512: UInt16 **mapPtr, ! 513: UInt16 *mapSize ) ! 514: { ! 515: OSStatus err; ! 516: UInt16 mapIndex; ! 517: UInt32 nextNodeNum; ! 518: ! 519: if (nodePtr->buffer != nil) // if iterator is valid... ! 520: { ! 521: nextNodeNum = ((NodeDescPtr)nodePtr->buffer)->fLink; ! 522: if (nextNodeNum == 0) ! 523: { ! 524: err = fsBTNoMoreMapNodesErr; ! 525: goto ErrorExit; ! 526: } ! 527: ! 528: err = ReleaseNode (btreePtr, nodePtr); ! 529: M_ExitOnError (err); ! 530: ! 531: err = GetNode (btreePtr, nextNodeNum, nodePtr); ! 532: M_ExitOnError (err); ! 533: ! 534: if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTMapNode) ! 535: { ! 536: err = fsBTBadNodeType; ! 537: goto ErrorExit; ! 538: } ! 539: ! 540: ++btreePtr->numMapNodesRead; ! 541: mapIndex = 0; ! 542: } else { ! 543: err = GetNode (btreePtr, kHeaderNodeNum, nodePtr); ! 544: M_ExitOnError (err); ! 545: ! 546: if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTHeaderNode) ! 547: { ! 548: err = fsBTInvalidHeaderErr; //�� or fsBTBadNodeType ! 549: goto ErrorExit; ! 550: } ! 551: ! 552: mapIndex = 2; ! 553: } ! 554: ! 555: ! 556: *mapPtr = (UInt16 *) GetRecordAddress (btreePtr, nodePtr->buffer, mapIndex); ! 557: *mapSize = GetRecordSize (btreePtr, nodePtr->buffer, mapIndex); ! 558: ! 559: return noErr; ! 560: ! 561: ! 562: ErrorExit: ! 563: ! 564: (void) ReleaseNode (btreePtr, nodePtr); ! 565: ! 566: *mapPtr = nil; ! 567: *mapSize = 0; ! 568: ! 569: return err; ! 570: } ! 571: ! 572: ! 573: ! 574: ////////////////////////////////// CalcMapBits ////////////////////////////////// ! 575: ! 576: UInt32 CalcMapBits (BTreeControlBlockPtr btreePtr) ! 577: { ! 578: UInt32 mapBits; ! 579: ! 580: mapBits = M_HeaderMapRecordSize (btreePtr->nodeSize) << 3; ! 581: ! 582: while (mapBits < btreePtr->totalNodes) ! 583: mapBits += M_MapRecordSize (btreePtr->nodeSize) << 3; ! 584: ! 585: return mapBits; ! 586: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.