|
|
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: BTreeWrapper.c ! 27: ! 28: Contains: Interface glue for new B-tree manager. ! 29: ! 30: Version: HFS Plus 1.0 ! 31: ! 32: Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved. ! 33: ! 34: File Ownership: ! 35: ! 36: DRI: Don Brady ! 37: ! 38: Other Contact: Mark Day ! 39: ! 40: Technology: xxx put technology here xxx ! 41: ! 42: Writers: ! 43: ! 44: (msd) Mark Day ! 45: (DSH) Deric Horn ! 46: (djb) Don Brady ! 47: ! 48: Change History (most recent first): ! 49: <Rhap> 8/10/98 djb Removed all references to btcb global iterator (lastIterator). ! 50: <Rhap> 04/02/98 djb GetBTreeRecord is only used for MacOS builds. ! 51: <Rhap> 03/31/98 djb Sync up with final HFSVolumes.h header file. ! 52: <CS18> 9/4/97 msd Fix ValidHFSRecord to determine the type of B-tree by FileID, ! 53: not record size. Add better checking for attribute b-tree keys. ! 54: <CS17> 8/22/97 djb Get blockReadFromDisk flag from GetCacheBlock call. ! 55: <CS16> 8/14/97 djb Remove reserved field checks in ValidHFSRecord (radar #1649593). ! 56: Only call if ValidHFSRecord DEBUG_BUILD is true. ! 57: <CS15> 8/11/97 djb Bug 1670441. In SetEndOfForkProc, don't DebugStr if the disk is ! 58: full. ! 59: <CS14> 7/25/97 DSH Pass heuristicHint to BTSearchRecord from SearchBTreeRecord. ! 60: <CS13> 7/24/97 djb CallBackProcs now take a file refNum instead of an FCB. ! 61: GetBlockProc now reports if block came from disk. ! 62: <CS12> 7/22/97 djb Move all trace points to BTree.c file. ! 63: <CS11> 7/21/97 djb LogEndTime now takes an error code. ! 64: <CS10> 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision ! 65: <CS9> 7/15/97 msd Bug #1664103. OpenBTree is not propagating errors from ! 66: BTOpenPath. ! 67: <CS8> 7/9/97 djb Remove maxCNID check from ValidHFSRecord (radar #1649593). ! 68: <CS7> 6/13/97 djb In ValidHFSRecord HFSPlus threads names can be > 31 chars. ! 69: <CS6> 6/2/97 DSH Also flush AlternateVolumeHeader whenever Attributes or Startup ! 70: files change size. ! 71: <CS5> 5/28/97 msd In ValidHFSRecord, check for attribute keys. ! 72: <CS4> 5/19/97 djb Move summary traces from GetBTreeRecord to BTIterateRecord. ! 73: <CS3> 5/9/97 djb Get in sync with new FilesInternal.i. ! 74: <CS2> 5/7/97 djb Add summary traces to B-tree SPI. ! 75: <CS1> 4/24/97 djb first checked in ! 76: <HFS18> 4/16/97 djb Always use new B-tree code. ! 77: <HFS17> 4/4/97 djb Remove clumpSize test from ValidHFSRecord. ! 78: <HFS16> 4/4/97 djb Get in sync with volume format changes. ! 79: <HFS15> 3/17/97 DSH Casting for SC, BlockProcs are now not static. ! 80: <HFS14> 3/3/97 djb Call trash block after closing btree! ! 81: <HFS13> 2/19/97 djb Add support for accessing bigger B-tree nodes. ! 82: <HFS12> 2/6/97 msd In CheckBTreeKey, remove test and DebugStr for parent ID being ! 83: too big. ! 84: <HFS11> 1/23/97 DSH SetEndOfForkProc now calls through to update the Alternate MDB ! 85: or VolumeHeader. ! 86: <HFS10> 1/16/97 djb Switched to dynamic lengths for BufferDescriptor length field in ! 87: SearchBTreeRecord and GetBTreeRecord. Round up to clump size in ! 88: SetEndOfForkProc. ! 89: <HFS9> 1/15/97 djb Don't return errors for bad file ids in key. ! 90: <HFS8> 1/13/97 djb Adding support for getting current record. ValidHFSRecord now ! 91: supports variable sized thread records. ! 92: <HFS7> 1/9/97 djb Call CheckBTreeKey before using key length in a BlockMoveData ! 93: call. ! 94: <HFS6> 1/6/97 djb Implement SetEndOfForkProc. ! 95: <HFS5> 1/6/97 djb Added HFS Plus support to CheckBTreeKey and ValidHFSRecord. ! 96: <HFS4> 1/3/97 djb Added support for large keys. Integrated latest HFSVolumesPriv.h ! 97: changes. ! 98: <HFS3> 12/23/96 djb Fixed problem in SearchBTreeRecord (dataSize is an output so it ! 99: was undefined). Added some debugging code. ! 100: <HFS2> 12/20/96 msd Fix OpenBTree to use the real data type for the key compare proc ! 101: pointer (not void *). Fixed problem in SearchBTreeRecord that ! 102: assigns a pointer to a buffer size field (forgot to dereference ! 103: the pointer). ! 104: <HFS1> 12/19/96 djb first checked in ! 105: ! 106: */ ! 107: ! 108: #include "../headers/FileMgrInternal.h" ! 109: ! 110: #include "../headers/BTreesInternal.h" ! 111: #include "../headers/BTreesPrivate.h" ! 112: ! 113: ! 114: ! 115: ! 116: // B-tree callbacks... ! 117: #if TARGET_OS_MAC ! 118: OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block ); ! 119: OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options ); ! 120: OSStatus SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount ); ! 121: #endif ! 122: ! 123: ! 124: // local routines ! 125: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb); ! 126: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize); ! 127: ! 128: ! 129: #if TARGET_OS_MAC ! 130: OSErr OpenBTree(FileReference refNum, KeyCompareProcPtr keyCompareProc) ! 131: { ! 132: FCB *fcb; ! 133: OSStatus result; ! 134: ! 135: ! 136: fcb = GetFileControlBlock(refNum); ! 137: ! 138: result = BTOpenPath (fcb, keyCompareProc, GetBlockProc, ReleaseBlockProc, SetEndOfForkProc, SetBlockSizeProc); ! 139: ExitOnError(result); ! 140: ! 141: ErrorExit: ! 142: ! 143: return result; ! 144: } ! 145: #endif /* TARGET_OS_MAC */ ! 146: ! 147: ! 148: #if TARGET_OS_MAC ! 149: OSErr CloseBTree(FileReference refNum) ! 150: { ! 151: OSErr result; ! 152: ! 153: ! 154: result = BTClosePath ( GetFileControlBlock(refNum) ); ! 155: ExitOnError(result); ! 156: ! 157: TrashCacheBlocks (refNum); ! 158: ! 159: ErrorExit: ! 160: ! 161: return result; ! 162: } ! 163: #endif ! 164: ! 165: ! 166: #if TARGET_OS_MAC ! 167: OSErr FlushBTree(FileReference refNum) ! 168: { ! 169: OSErr result; ! 170: ! 171: ! 172: result = BTFlushPath( GetFileControlBlock(refNum) ); ! 173: ! 174: return result; ! 175: } ! 176: #endif ! 177: ! 178: ! 179: OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void* foundKey, void* data, UInt16 *dataSize, UInt32 *newHint) ! 180: { ! 181: FSBufferDescriptor btRecord; ! 182: BTreeIterator searchIterator; ! 183: FCB *fcb; ! 184: BTreeControlBlock *btcb; ! 185: OSStatus result; ! 186: ! 187: ! 188: fcb = GetFileControlBlock(refNum); ! 189: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 190: ! 191: btRecord.bufferAddress = data; ! 192: btRecord.itemCount = 1; ! 193: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength ) ! 194: btRecord.itemSize = sizeof(HFSExtentRecord); ! 195: else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength ) ! 196: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 197: else ! 198: btRecord.itemSize = sizeof(CatalogRecord); ! 199: ! 200: searchIterator.hint.writeCount = 0; // clear these out for debugging... ! 201: searchIterator.hint.reserved1 = 0; ! 202: searchIterator.hint.reserved2 = 0; ! 203: ! 204: searchIterator.hint.nodeNum = hint; ! 205: searchIterator.hint.index = 0; ! 206: ! 207: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 208: ExitOnError(result); ! 209: ! 210: BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 211: ! 212: // We only optimize for catalog records ! 213: if( btRecord.itemSize == sizeof(CatalogRecord) ) ! 214: { ! 215: UInt32 heuristicHint; ! 216: UInt32 *cachedHint; ! 217: Ptr hintCachePtr = fcb->fcbVPtr->hintCachePtr; ! 218: ! 219: // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of ! 220: // dirID and nodeNumber, in hopes that the current search will be in the same node ! 221: // as the last search with the same parentID. ! 222: result = GetMRUCacheBlock( ((HFSCatalogKey *)key)->parentID, hintCachePtr, (Ptr *)&cachedHint ); ! 223: heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; ! 224: ! 225: result = BTSearchRecord( fcb, &searchIterator, heuristicHint, &btRecord, dataSize, &searchIterator ); ! 226: ! 227: InsertMRUCacheBlock( hintCachePtr, ((HFSCatalogKey *)key)->parentID, (Ptr) &(searchIterator.hint.nodeNum) ); ! 228: } ! 229: else ! 230: { ! 231: result = BTSearchRecord( fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, dataSize, &searchIterator ); ! 232: } ! 233: ! 234: if (result == noErr) ! 235: { ! 236: *newHint = searchIterator.hint.nodeNum; ! 237: ! 238: result = CheckBTreeKey(&searchIterator.key, btcb); ! 239: ExitOnError(result); ! 240: ! 241: BlockMoveData(&searchIterator.key, foundKey, CalcKeySize(btcb, &searchIterator.key)); //�� warning, this could overflow user's buffer!!! ! 242: ! 243: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) ) ! 244: DebugStr("\pSearchBTreeRecord: bad record?"); ! 245: } ! 246: ! 247: ErrorExit: ! 248: ! 249: return result; ! 250: } ! 251: ! 252: ! 253: ! 254: // Note ! 255: // The new B-tree manager differs from the original b-tree in how it does iteration. We need ! 256: // to account for these differences here. We save an iterator in the BTree control block so ! 257: // that we have a context in which to perfrom the iteration. Also note that the old B-tree ! 258: // allowed you to specify any number relative to the last operation (including 0) whereas the ! 259: // new B-tree only allows next/previous. ! 260: #if TARGET_OS_MAC ! 261: OSErr GetBTreeRecord(FileReference refNum, SInt16 selectionIndex, void* key, void* data, UInt16 *dataSize, UInt32 *newHint) ! 262: { ! 263: FSBufferDescriptor btRecord; ! 264: BTreeIterator *iterator; ! 265: FCB *fcb; ! 266: BTreeControlBlock *btcb; ! 267: OSStatus result; ! 268: UInt16 operation; ! 269: ! 270: ! 271: fcb = GetFileControlBlock(refNum); ! 272: ! 273: // pick up our iterator in the BTCB for context... ! 274: ! 275: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 276: iterator = &btcb->lastIterator; ! 277: ! 278: btRecord.bufferAddress = data; ! 279: btRecord.itemCount = 1; ! 280: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength ) ! 281: btRecord.itemSize = sizeof(HFSExtentRecord); ! 282: else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength ) ! 283: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 284: else ! 285: btRecord.itemSize = sizeof(CatalogRecord); ! 286: ! 287: // now we have to map index into next/prev operations... ! 288: ! 289: if (selectionIndex == 1) ! 290: { ! 291: operation = kBTreeNextRecord; ! 292: } ! 293: else if (selectionIndex == -1) ! 294: { ! 295: operation = kBTreePrevRecord; ! 296: } ! 297: else if (selectionIndex == 0) ! 298: { ! 299: operation = kBTreeCurrentRecord; ! 300: } ! 301: else if (selectionIndex == (SInt16) 0x8001) ! 302: { ! 303: operation = kBTreeFirstRecord; ! 304: } ! 305: else if (selectionIndex == (SInt16) 0x7FFF) ! 306: { ! 307: operation = kBTreeLastRecord; ! 308: } ! 309: else if (selectionIndex > 1) ! 310: { ! 311: UInt32 i; ! 312: ! 313: for (i = 1; i < selectionIndex; ++i) ! 314: { ! 315: result = BTIterateRecord( fcb, kBTreeNextRecord, iterator, &btRecord, dataSize ); ! 316: ExitOnError(result); ! 317: } ! 318: operation = kBTreeNextRecord; ! 319: } ! 320: else // (selectionIndex < -1) ! 321: { ! 322: SInt32 i; ! 323: ! 324: for (i = -1; i > selectionIndex; --i) ! 325: { ! 326: result = BTIterateRecord( fcb, kBTreePrevRecord, iterator, &btRecord, dataSize ); ! 327: ExitOnError(result); ! 328: } ! 329: operation = kBTreePrevRecord; ! 330: } ! 331: ! 332: result = BTIterateRecord( fcb, operation, iterator, &btRecord, dataSize ); ! 333: ! 334: if (result == noErr) ! 335: { ! 336: *newHint = iterator->hint.nodeNum; ! 337: ! 338: result = CheckBTreeKey(&iterator->key, btcb); ! 339: ExitOnError(result); ! 340: ! 341: BlockMoveData(&iterator->key, key, CalcKeySize(btcb, &iterator->key)); //�� warning, this could overflow user's buffer!!! ! 342: ! 343: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) ) ! 344: DebugStr("\pGetBTreeRecord: bad record?"); ! 345: ! 346: } ! 347: ! 348: ErrorExit: ! 349: ! 350: return result; ! 351: } ! 352: #endif /* TARGET_OS_MAC */ ! 353: ! 354: ! 355: OSErr InsertBTreeRecord(FileReference refNum, void* key, void* data, UInt16 dataSize, UInt32 *newHint) ! 356: { ! 357: FSBufferDescriptor btRecord; ! 358: BTreeIterator iterator; ! 359: FCB *fcb; ! 360: BTreeControlBlock *btcb; ! 361: OSStatus result; ! 362: ! 363: ! 364: fcb = GetFileControlBlock(refNum); ! 365: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 366: ! 367: btRecord.bufferAddress = data; ! 368: btRecord.itemSize = dataSize; ! 369: btRecord.itemCount = 1; ! 370: ! 371: iterator.hint.nodeNum = 0; // no hint ! 372: ! 373: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 374: ExitOnError(result); ! 375: ! 376: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 377: ! 378: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, dataSize) ) ! 379: DebugStr("\pInsertBTreeRecord: bad record?"); ! 380: ! 381: result = BTInsertRecord( fcb, &iterator, &btRecord, dataSize ); ! 382: ! 383: *newHint = iterator.hint.nodeNum; ! 384: ! 385: ErrorExit: ! 386: ! 387: return result; ! 388: } ! 389: ! 390: ! 391: OSErr DeleteBTreeRecord(FileReference refNum, void* key) ! 392: { ! 393: BTreeIterator iterator; ! 394: FCB *fcb; ! 395: BTreeControlBlock *btcb; ! 396: OSStatus result; ! 397: ! 398: ! 399: fcb = GetFileControlBlock(refNum); ! 400: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 401: ! 402: iterator.hint.nodeNum = 0; // no hint ! 403: ! 404: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 405: ExitOnError(result); ! 406: ! 407: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 408: ! 409: result = BTDeleteRecord( fcb, &iterator ); ! 410: ! 411: ErrorExit: ! 412: ! 413: return result; ! 414: } ! 415: ! 416: ! 417: OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void *newData, UInt16 dataSize, UInt32 *newHint) ! 418: { ! 419: FSBufferDescriptor btRecord; ! 420: BTreeIterator iterator; ! 421: FCB *fcb; ! 422: BTreeControlBlock *btcb; ! 423: OSStatus result; ! 424: ! 425: ! 426: fcb = GetFileControlBlock(refNum); ! 427: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 428: ! 429: btRecord.bufferAddress = newData; ! 430: btRecord.itemSize = dataSize; ! 431: btRecord.itemCount = 1; ! 432: ! 433: iterator.hint.nodeNum = hint; ! 434: ! 435: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 436: ExitOnError(result); ! 437: ! 438: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 439: ! 440: if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) ) ! 441: DebugStr("\pReplaceBTreeRecord: bad record?"); ! 442: ! 443: result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize ); ! 444: ! 445: *newHint = iterator.hint.nodeNum; ! 446: ! 447: //���do we need to invalidate the iterator? ! 448: ! 449: ErrorExit: ! 450: ! 451: return result; ! 452: } ! 453: ! 454: ! 455: ! 456: #if TARGET_OS_MAC ! 457: OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block ) ! 458: { ! 459: OSStatus result; ! 460: short cacheOptions = 0; ! 461: ! 462: if (options == kGetBlock) ! 463: cacheOptions = gbDefault; ! 464: else if (options & kForceReadBlock) ! 465: cacheOptions = gbReadMask; ! 466: else if (options & kGetEmptyBlock) ! 467: cacheOptions = gbNoReadMask; ! 468: else ! 469: Panic ("\pGetBlockProc: Invalid option!"); ! 470: ! 471: if ( block->blockSize == 512 ) ! 472: { ! 473: result = GetBlock_glue( cacheOptions, blockNum, (Ptr *)&block->buffer, fileRefNum, GetFileControlBlock(fileRefNum)->fcbVPtr ); ! 474: block->blockReadFromDisk = BlockCameFromDisk(); ! 475: } ! 476: else ! 477: { ! 478: result = GetCacheBlock( fileRefNum, blockNum, block->blockSize, cacheOptions, &block->buffer, &block->blockReadFromDisk); ! 479: } ! 480: ! 481: return result; ! 482: } ! 483: #endif /* TARGET_OS_MAC */ ! 484: ! 485: ! 486: #if TARGET_OS_MAC ! 487: OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options ) ! 488: { ! 489: #pragma unused (fileRefNum) ! 490: ! 491: OSStatus result; ! 492: short cacheOptions = 0; ! 493: ! 494: ! 495: if (options == kReleaseBlock) ! 496: cacheOptions = rbDefault; ! 497: else if (options & kMarkBlockDirty) ! 498: cacheOptions = rbDirtyMask; ! 499: else if (options & kForceWriteBlock) ! 500: cacheOptions = rbWriteMask; ! 501: else if (options & kTrashBlock) ! 502: cacheOptions = rbTrashMask; ! 503: else ! 504: Panic ("\pGetBlockProc: Invalid option!"); ! 505: ! 506: //�� if kReleaseBlock and just markdirty should we call markblock?? ! 507: ! 508: if ( blockPtr->blockSize == 512 ) ! 509: result = RelBlock_glue( blockPtr->buffer, cacheOptions ); ! 510: else ! 511: result = ReleaseCacheBlock( blockPtr->buffer, cacheOptions ); ! 512: ! 513: return result; ! 514: } ! 515: #endif /* TARGET_OS_MAC */ ! 516: ! 517: ! 518: #if TARGET_OS_MAC ! 519: OSStatus ! 520: SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount) ! 521: { ! 522: #pragma unused (fileRefNum) ! 523: ! 524: OSStatus result; ! 525: ! 526: // for HFS Plus volumes we'll need to set up a big node cache... ! 527: ! 528: if ( blockSize > 512 ) ! 529: result = InitializeBlockCache (blockSize, minBlockCount); ! 530: else ! 531: result = noErr; ! 532: ! 533: return result; ! 534: } ! 535: #endif /* TARGET_OS_MAC */ ! 536: ! 537: ! 538: ! 539: OSStatus ! 540: SetEndOfForkProc ( FileReference fileRefNum, FSSize minEOF, FSSize maxEOF ) ! 541: { ! 542: #pragma unused (maxEOF) ! 543: ! 544: OSStatus result; ! 545: UInt32 actualBytesAdded; ! 546: UInt32 bytesToAdd; ! 547: ExtendedVCB *vcb; ! 548: FCB *filePtr; ! 549: ! 550: ! 551: filePtr = GetFileControlBlock(fileRefNum); ! 552: ! 553: if ( minEOF > filePtr->fcbEOF ) ! 554: { ! 555: bytesToAdd = minEOF - filePtr->fcbEOF; ! 556: ! 557: if (bytesToAdd < filePtr->fcbClmpSize) ! 558: bytesToAdd = filePtr->fcbClmpSize; //���why not always be a mutiple of clump size ??? ! 559: } ! 560: else ! 561: { ! 562: if ( DEBUG_BUILD ) ! 563: DebugStr("\pSetEndOfForkProc: minEOF is smaller than current size!"); ! 564: return -1; ! 565: } ! 566: ! 567: vcb = filePtr->fcbVPtr; ! 568: result = ExtendFileC ( vcb, filePtr, bytesToAdd, 0, &actualBytesAdded ); ! 569: ReturnIfError(result); ! 570: ! 571: if (DEBUG_BUILD && actualBytesAdded < bytesToAdd) ! 572: DebugStr("\pSetEndOfForkProc: actualBytesAdded < bytesToAdd!"); ! 573: ! 574: filePtr->fcbEOF = filePtr->fcbPLen; // new B-tree looks at fcbEOF ! 575: ! 576: // ! 577: // Update the Alternate MDB or Alternate VolumeHeader ! 578: // ! 579: if ( vcb->vcbSigWord == kHFSPlusSigWord ) ! 580: { ! 581: // If any of the HFS+ private files change size, flush them back to the Alternate volume header ! 582: if ( (filePtr->fcbFlNm == kHFSExtentsFileID) ! 583: || (filePtr->fcbFlNm == kHFSCatalogFileID) ! 584: || (filePtr->fcbFlNm == kHFSStartupFileID) ! 585: || (filePtr->fcbFlNm == kHFSAttributesFileID) ) ! 586: { ! 587: MarkVCBDirty( vcb ); ! 588: result = FlushAlternateVolumeControlBlock( vcb, true ); ! 589: } ! 590: } ! 591: else if ( vcb->vcbSigWord == kHFSSigWord ) ! 592: { ! 593: if ( filePtr->fcbFlNm == kHFSExtentsFileID ) ! 594: { ! 595: vcb->vcbXTAlBlks = filePtr->fcbPLen / vcb->blockSize; ! 596: MarkVCBDirty( vcb ); ! 597: result = FlushAlternateVolumeControlBlock( vcb, false ); ! 598: } ! 599: else if ( filePtr->fcbFlNm == kHFSCatalogFileID ) ! 600: { ! 601: vcb->vcbCTAlBlks = filePtr->fcbPLen / vcb->blockSize; ! 602: MarkVCBDirty( vcb ); ! 603: result = FlushAlternateVolumeControlBlock( vcb, false ); ! 604: } ! 605: } ! 606: ! 607: return result; ! 608: ! 609: } // end SetEndOfForkProc ! 610: ! 611: ! 612: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb) ! 613: { ! 614: UInt16 keyLen; ! 615: ! 616: if ( btcb->attributes & kBTBigKeysMask ) ! 617: keyLen = key->length16; ! 618: else ! 619: keyLen = key->length8; ! 620: ! 621: if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) ) ! 622: { ! 623: if ( DEBUG_BUILD ) ! 624: DebugStr("\pCheckBTreeKey: bad key length!"); ! 625: return fsBTInvalidKeyLengthErr; ! 626: } ! 627: ! 628: return noErr; ! 629: } ! 630: ! 631: ! 632: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize) ! 633: { ! 634: UInt32 cNodeID; ! 635: ! 636: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength ) ! 637: { ! 638: return ( recordSize == sizeof(HFSExtentRecord) ); ! 639: } ! 640: else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength ) ! 641: { ! 642: return ( recordSize == sizeof(HFSPlusExtentRecord) ); ! 643: } ! 644: else if (btcb->maxKeyLength == kAttributeKeyMaximumLength ) ! 645: { ! 646: HFSPlusAttrRecord *attributeRecord = (HFSPlusAttrRecord *) record; ! 647: ! 648: switch (attributeRecord->recordType) { ! 649: case kHFSPlusAttrInlineData: ! 650: break; ! 651: ! 652: case kHFSPlusAttrForkData: ! 653: break; ! 654: ! 655: case kHFSPlusAttrExtents: ! 656: break; ! 657: } ! 658: } ! 659: else // Catalog record ! 660: { ! 661: CatalogRecord *catalogRecord = (CatalogRecord*) record; ! 662: ! 663: switch(catalogRecord->recordType) ! 664: { ! 665: case kHFSFolderRecord: ! 666: { ! 667: if ( recordSize != sizeof(HFSCatalogFolder) ) ! 668: return false; ! 669: if ( catalogRecord->hfsFolder.flags != 0 ) ! 670: return false; ! 671: if ( catalogRecord->hfsFolder.valence > 0x7FFF ) ! 672: return false; ! 673: ! 674: cNodeID = catalogRecord->hfsFolder.folderID; ! 675: ! 676: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 677: return false; ! 678: } ! 679: break; ! 680: ! 681: case kHFSPlusFolderRecord: ! 682: { ! 683: if ( recordSize != sizeof(HFSPlusCatalogFolder) ) ! 684: return false; ! 685: if ( catalogRecord->hfsPlusFolder.flags != 0 ) ! 686: return false; ! 687: if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF ) ! 688: return false; ! 689: ! 690: cNodeID = catalogRecord->hfsPlusFolder.folderID; ! 691: ! 692: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 693: return false; ! 694: } ! 695: break; ! 696: ! 697: case kHFSFileRecord: ! 698: { ! 699: // UInt16 i; ! 700: HFSExtentDescriptor *dataExtent; ! 701: HFSExtentDescriptor *rsrcExtent; ! 702: ! 703: if ( recordSize != sizeof(HFSCatalogFile) ) ! 704: return false; ! 705: if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 ) ! 706: return false; ! 707: ! 708: cNodeID = catalogRecord->hfsFile.fileID; ! 709: ! 710: if ( cNodeID < 16 ) ! 711: return false; ! 712: ! 713: // make sure 0 � LEOF � PEOF for both forks ! 714: ! 715: if ( catalogRecord->hfsFile.dataLogicalSize < 0 ) ! 716: return false; ! 717: if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize ) ! 718: return false; ! 719: if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 ) ! 720: return false; ! 721: if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize ) ! 722: return false; ! 723: ! 724: dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents; ! 725: rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents; ! 726: ! 727: #if 0 ! 728: for (i = 0; i < kHFSExtentDensity; ++i) ! 729: { ! 730: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) ) ! 731: return false; ! 732: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) ) ! 733: return false; ! 734: } ! 735: #endif ! 736: } ! 737: break; ! 738: ! 739: case kHFSPlusFileRecord: ! 740: { ! 741: // UInt16 i; ! 742: HFSPlusExtentDescriptor *dataExtent; ! 743: HFSPlusExtentDescriptor *rsrcExtent; ! 744: ! 745: if ( recordSize != sizeof(HFSPlusCatalogFile) ) ! 746: return false; ! 747: if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 ) ! 748: return false; ! 749: ! 750: cNodeID = catalogRecord->hfsPlusFile.fileID; ! 751: ! 752: if ( cNodeID < 16 ) ! 753: return false; ! 754: ! 755: // make sure 0 � LEOF � PEOF for both forks ! 756: ! 757: if ( catalogRecord->hfsPlusFile.dataFork.logicalSize.hi != 0 ) ! 758: return false; ! 759: if ( catalogRecord->hfsPlusFile.resourceFork.logicalSize.hi != 0 ) ! 760: return false; ! 761: ! 762: dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents; ! 763: rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents; ! 764: ! 765: #if 0 ! 766: for (i = 0; i < kHFSPlusExtentDensity; ++i) ! 767: { ! 768: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) ) ! 769: return false; ! 770: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) ) ! 771: return false; ! 772: } ! 773: #endif ! 774: } ! 775: break; ! 776: ! 777: case kHFSFolderThreadRecord: ! 778: case kHFSFileThreadRecord: ! 779: { ! 780: if ( recordSize != sizeof(HFSCatalogThread) ) ! 781: return false; ! 782: ! 783: cNodeID = catalogRecord->hfsThread.parentID; ! 784: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 785: return false; ! 786: ! 787: if ( (catalogRecord->hfsThread.nodeName[0] == 0) || ! 788: (catalogRecord->hfsThread.nodeName[0] > 31) ) ! 789: return false; ! 790: } ! 791: break; ! 792: ! 793: case kHFSPlusFolderThreadRecord: ! 794: case kHFSPlusFileThreadRecord: ! 795: { ! 796: if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255))) ! 797: return false; ! 798: ! 799: cNodeID = catalogRecord->hfsPlusThread.parentID; ! 800: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 801: return false; ! 802: ! 803: if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) || ! 804: (catalogRecord->hfsPlusThread.nodeName.length > 255) ) ! 805: return false; ! 806: } ! 807: break; ! 808: ! 809: default: ! 810: return false; ! 811: } ! 812: } ! 813: ! 814: return true; // record appears to be OK ! 815: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.