|
|
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: BTreeWrapper.c ! 24: ! 25: Contains: Interface glue for new B-tree manager. ! 26: ! 27: Version: HFS Plus 1.0 ! 28: ! 29: Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved. ! 30: ! 31: File Ownership: ! 32: ! 33: DRI: Don Brady ! 34: ! 35: Other Contact: Mark Day ! 36: ! 37: Technology: xxx put technology here xxx ! 38: ! 39: Writers: ! 40: ! 41: (msd) Mark Day ! 42: (DSH) Deric Horn ! 43: (djb) Don Brady ! 44: ! 45: Change History (most recent first): ! 46: <MacOSX> 8/10/98 djb Removed all references to btcb global iterator (lastIterator). ! 47: <MacOSX> 04/02/98 djb GetBTreeRecord is only used for MacOS builds. ! 48: <MacOSX> 03/31/98 djb Sync up with final HFSVolumes.h header file. ! 49: <CS18> 9/4/97 msd Fix ValidHFSRecord to determine the type of B-tree by FileID, ! 50: not record size. Add better checking for attribute b-tree keys. ! 51: <CS17> 8/22/97 djb Get blockReadFromDisk flag from GetCacheBlock call. ! 52: <CS16> 8/14/97 djb Remove reserved field checks in ValidHFSRecord (radar #1649593). ! 53: Only call if ValidHFSRecord HFS_DIAGNOSTIC is true. ! 54: <CS15> 8/11/97 djb Bug 1670441. In SetEndOfForkProc, don't DebugStr if the disk is ! 55: full. ! 56: <CS14> 7/25/97 DSH Pass heuristicHint to BTSearchRecord from SearchBTreeRecord. ! 57: <CS13> 7/24/97 djb CallBackProcs now take a file refNum instead of an FCB. ! 58: GetBlockProc now reports if block came from disk. ! 59: <CS12> 7/22/97 djb Move all trace points to BTree.c file. ! 60: <CS11> 7/21/97 djb LogEndTime now takes an error code. ! 61: <CS10> 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision ! 62: <CS9> 7/15/97 msd Bug #1664103. OpenBTree is not propagating errors from ! 63: BTOpenPath. ! 64: <CS8> 7/9/97 djb Remove maxCNID check from ValidHFSRecord (radar #1649593). ! 65: <CS7> 6/13/97 djb In ValidHFSRecord HFSPlus threads names can be > 31 chars. ! 66: <CS6> 6/2/97 DSH Also flush AlternateVolumeHeader whenever Attributes or Startup ! 67: files change size. ! 68: <CS5> 5/28/97 msd In ValidHFSRecord, check for attribute keys. ! 69: <CS4> 5/19/97 djb Move summary traces from GetBTreeRecord to BTIterateRecord. ! 70: <CS3> 5/9/97 djb Get in sync with new FilesInternal.i. ! 71: <CS2> 5/7/97 djb Add summary traces to B-tree SPI. ! 72: <CS1> 4/24/97 djb first checked in ! 73: <HFS18> 4/16/97 djb Always use new B-tree code. ! 74: <HFS17> 4/4/97 djb Remove clumpSize test from ValidHFSRecord. ! 75: <HFS16> 4/4/97 djb Get in sync with volume format changes. ! 76: <HFS15> 3/17/97 DSH Casting for SC, BlockProcs are now not static. ! 77: <HFS14> 3/3/97 djb Call trash block after closing btree! ! 78: <HFS13> 2/19/97 djb Add support for accessing bigger B-tree nodes. ! 79: <HFS12> 2/6/97 msd In CheckBTreeKey, remove test and DebugStr for parent ID being ! 80: too big. ! 81: <HFS11> 1/23/97 DSH SetEndOfForkProc now calls through to update the Alternate MDB ! 82: or VolumeHeader. ! 83: <HFS10> 1/16/97 djb Switched to dynamic lengths for BufferDescriptor length field in ! 84: SearchBTreeRecord and GetBTreeRecord. Round up to clump size in ! 85: SetEndOfForkProc. ! 86: <HFS9> 1/15/97 djb Don't return errors for bad file ids in key. ! 87: <HFS8> 1/13/97 djb Adding support for getting current record. ValidHFSRecord now ! 88: supports variable sized thread records. ! 89: <HFS7> 1/9/97 djb Call CheckBTreeKey before using key length in a BlockMoveData ! 90: call. ! 91: <HFS6> 1/6/97 djb Implement SetEndOfForkProc. ! 92: <HFS5> 1/6/97 djb Added HFS Plus support to CheckBTreeKey and ValidHFSRecord. ! 93: <HFS4> 1/3/97 djb Added support for large keys. Integrated latest HFSVolumesPriv.h ! 94: changes. ! 95: <HFS3> 12/23/96 djb Fixed problem in SearchBTreeRecord (dataSize is an output so it ! 96: was undefined). Added some debugging code. ! 97: <HFS2> 12/20/96 msd Fix OpenBTree to use the real data type for the key compare proc ! 98: pointer (not void *). Fixed problem in SearchBTreeRecord that ! 99: assigns a pointer to a buffer size field (forgot to dereference ! 100: the pointer). ! 101: <HFS1> 12/19/96 djb first checked in ! 102: ! 103: */ ! 104: ! 105: #include "../headers/BTreesPrivate.h" ! 106: ! 107: ! 108: ! 109: ! 110: // B-tree callbacks... ! 111: #if TARGET_API_MAC_OS8 ! 112: OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block ); ! 113: OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options ); ! 114: OSStatus SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount ); ! 115: #endif ! 116: ! 117: ! 118: // local routines ! 119: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb); ! 120: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize); ! 121: ! 122: ! 123: ! 124: ! 125: OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void* foundKey, void* data, UInt16 *dataSize, UInt32 *newHint) ! 126: { ! 127: FSBufferDescriptor btRecord; ! 128: BTreeIterator searchIterator; ! 129: FCB *fcb; ! 130: BTreeControlBlock *btcb; ! 131: OSStatus result; ! 132: ! 133: ! 134: fcb = GetFileControlBlock(refNum); ! 135: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 136: ! 137: btRecord.bufferAddress = data; ! 138: btRecord.itemCount = 1; ! 139: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength ) ! 140: btRecord.itemSize = sizeof(HFSExtentRecord); ! 141: else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength ) ! 142: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 143: else ! 144: btRecord.itemSize = sizeof(CatalogRecord); ! 145: ! 146: searchIterator.hint.writeCount = 0; // clear these out for debugging... ! 147: searchIterator.hint.reserved1 = 0; ! 148: searchIterator.hint.reserved2 = 0; ! 149: ! 150: searchIterator.hint.nodeNum = hint; ! 151: searchIterator.hint.index = 0; ! 152: ! 153: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 154: ExitOnError(result); ! 155: ! 156: BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 157: ! 158: // We only optimize for catalog records ! 159: if( btRecord.itemSize == sizeof(CatalogRecord) ) ! 160: { ! 161: UInt32 heuristicHint; ! 162: UInt32 *cachedHint; ! 163: Ptr hintCachePtr = FCBTOVCB(fcb)->hintCachePtr; ! 164: ! 165: // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of ! 166: // dirID and nodeNumber, in hopes that the current search will be in the same node ! 167: // as the last search with the same parentID. ! 168: result = GetMRUCacheBlock( ((HFSCatalogKey *)key)->parentID, hintCachePtr, (Ptr *)&cachedHint ); ! 169: heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; ! 170: ! 171: result = BTSearchRecord( fcb, &searchIterator, heuristicHint, &btRecord, dataSize, &searchIterator ); ! 172: ! 173: InsertMRUCacheBlock( hintCachePtr, ((HFSCatalogKey *)key)->parentID, (Ptr) &(searchIterator.hint.nodeNum) ); ! 174: } ! 175: else ! 176: { ! 177: result = BTSearchRecord( fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, dataSize, &searchIterator ); ! 178: } ! 179: ! 180: if (result == noErr) ! 181: { ! 182: *newHint = searchIterator.hint.nodeNum; ! 183: ! 184: result = CheckBTreeKey(&searchIterator.key, btcb); ! 185: ExitOnError(result); ! 186: ! 187: BlockMoveData(&searchIterator.key, foundKey, CalcKeySize(btcb, &searchIterator.key)); //�� warning, this could overflow user's buffer!!! ! 188: ! 189: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) ) ! 190: DebugStr("\pSearchBTreeRecord: bad record?"); ! 191: } ! 192: ! 193: ErrorExit: ! 194: ! 195: return result; ! 196: } ! 197: ! 198: ! 199: ! 200: OSErr InsertBTreeRecord(FileReference refNum, void* key, void* data, UInt16 dataSize, UInt32 *newHint) ! 201: { ! 202: FSBufferDescriptor btRecord; ! 203: BTreeIterator iterator; ! 204: FCB *fcb; ! 205: BTreeControlBlock *btcb; ! 206: OSStatus result; ! 207: ! 208: ! 209: fcb = GetFileControlBlock(refNum); ! 210: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 211: ! 212: btRecord.bufferAddress = data; ! 213: btRecord.itemSize = dataSize; ! 214: btRecord.itemCount = 1; ! 215: ! 216: iterator.hint.nodeNum = 0; // no hint ! 217: ! 218: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 219: ExitOnError(result); ! 220: ! 221: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 222: ! 223: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, dataSize) ) ! 224: DebugStr("\pInsertBTreeRecord: bad record?"); ! 225: ! 226: result = BTInsertRecord( fcb, &iterator, &btRecord, dataSize ); ! 227: ! 228: *newHint = iterator.hint.nodeNum; ! 229: ! 230: ErrorExit: ! 231: ! 232: return result; ! 233: } ! 234: ! 235: ! 236: OSErr DeleteBTreeRecord(FileReference refNum, void* key) ! 237: { ! 238: BTreeIterator iterator; ! 239: FCB *fcb; ! 240: BTreeControlBlock *btcb; ! 241: OSStatus result; ! 242: ! 243: ! 244: fcb = GetFileControlBlock(refNum); ! 245: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 246: ! 247: iterator.hint.nodeNum = 0; // no hint ! 248: ! 249: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 250: ExitOnError(result); ! 251: ! 252: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 253: ! 254: result = BTDeleteRecord( fcb, &iterator ); ! 255: ! 256: ErrorExit: ! 257: ! 258: return result; ! 259: } ! 260: ! 261: ! 262: OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void *newData, UInt16 dataSize, UInt32 *newHint) ! 263: { ! 264: FSBufferDescriptor btRecord; ! 265: BTreeIterator iterator; ! 266: FCB *fcb; ! 267: BTreeControlBlock *btcb; ! 268: OSStatus result; ! 269: ! 270: ! 271: fcb = GetFileControlBlock(refNum); ! 272: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr; ! 273: ! 274: btRecord.bufferAddress = newData; ! 275: btRecord.itemSize = dataSize; ! 276: btRecord.itemCount = 1; ! 277: ! 278: iterator.hint.nodeNum = hint; ! 279: ! 280: result = CheckBTreeKey((BTreeKey *) key, btcb); ! 281: ExitOnError(result); ! 282: ! 283: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen? ! 284: ! 285: if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) ) ! 286: DebugStr("\pReplaceBTreeRecord: bad record?"); ! 287: ! 288: result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize ); ! 289: ! 290: *newHint = iterator.hint.nodeNum; ! 291: ! 292: //���do we need to invalidate the iterator? ! 293: ! 294: ErrorExit: ! 295: ! 296: return result; ! 297: } ! 298: ! 299: ! 300: ! 301: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb) ! 302: { ! 303: UInt16 keyLen; ! 304: ! 305: if ( btcb->attributes & kBTBigKeysMask ) ! 306: keyLen = key->length16; ! 307: else ! 308: keyLen = key->length8; ! 309: ! 310: if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) ) ! 311: { ! 312: if ( DEBUG_BUILD ) ! 313: DebugStr("\pCheckBTreeKey: bad key length!"); ! 314: return fsBTInvalidKeyLengthErr; ! 315: } ! 316: ! 317: return noErr; ! 318: } ! 319: ! 320: ! 321: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize) ! 322: { ! 323: UInt32 cNodeID; ! 324: ! 325: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength ) ! 326: { ! 327: return ( recordSize == sizeof(HFSExtentRecord) ); ! 328: } ! 329: else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength ) ! 330: { ! 331: return ( recordSize == sizeof(HFSPlusExtentRecord) ); ! 332: } ! 333: else // Catalog record ! 334: { ! 335: CatalogRecord *catalogRecord = (CatalogRecord*) record; ! 336: ! 337: switch(catalogRecord->recordType) ! 338: { ! 339: case kHFSFolderRecord: ! 340: { ! 341: if ( recordSize != sizeof(HFSCatalogFolder) ) ! 342: return false; ! 343: if ( catalogRecord->hfsFolder.flags != 0 ) ! 344: return false; ! 345: if ( catalogRecord->hfsFolder.valence > 0x7FFF ) ! 346: return false; ! 347: ! 348: cNodeID = catalogRecord->hfsFolder.folderID; ! 349: ! 350: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 351: return false; ! 352: } ! 353: break; ! 354: ! 355: case kHFSPlusFolderRecord: ! 356: { ! 357: if ( recordSize != sizeof(HFSPlusCatalogFolder) ) ! 358: return false; ! 359: if ( catalogRecord->hfsPlusFolder.flags != 0 ) ! 360: return false; ! 361: if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF ) ! 362: return false; ! 363: ! 364: cNodeID = catalogRecord->hfsPlusFolder.folderID; ! 365: ! 366: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 367: return false; ! 368: } ! 369: break; ! 370: ! 371: case kHFSFileRecord: ! 372: { ! 373: // UInt16 i; ! 374: HFSExtentDescriptor *dataExtent; ! 375: HFSExtentDescriptor *rsrcExtent; ! 376: ! 377: if ( recordSize != sizeof(HFSCatalogFile) ) ! 378: return false; ! 379: if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 ) ! 380: return false; ! 381: ! 382: cNodeID = catalogRecord->hfsFile.fileID; ! 383: ! 384: if ( cNodeID < 16 ) ! 385: return false; ! 386: ! 387: // make sure 0 � LEOF � PEOF for both forks ! 388: ! 389: if ( catalogRecord->hfsFile.dataLogicalSize < 0 ) ! 390: return false; ! 391: if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize ) ! 392: return false; ! 393: if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 ) ! 394: return false; ! 395: if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize ) ! 396: return false; ! 397: ! 398: dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents; ! 399: rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents; ! 400: ! 401: #if 0 ! 402: for (i = 0; i < kHFSExtentDensity; ++i) ! 403: { ! 404: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) ) ! 405: return false; ! 406: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) ) ! 407: return false; ! 408: } ! 409: #endif ! 410: } ! 411: break; ! 412: ! 413: case kHFSPlusFileRecord: ! 414: { ! 415: // UInt16 i; ! 416: HFSPlusExtentDescriptor *dataExtent; ! 417: HFSPlusExtentDescriptor *rsrcExtent; ! 418: ! 419: if ( recordSize != sizeof(HFSPlusCatalogFile) ) ! 420: return false; ! 421: if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 ) ! 422: return false; ! 423: ! 424: cNodeID = catalogRecord->hfsPlusFile.fileID; ! 425: ! 426: if ( cNodeID < 16 ) ! 427: return false; ! 428: ! 429: // make sure 0 � LEOF � PEOF for both forks ! 430: ! 431: dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents; ! 432: rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents; ! 433: ! 434: #if 0 ! 435: for (i = 0; i < kHFSPlusExtentDensity; ++i) ! 436: { ! 437: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) ) ! 438: return false; ! 439: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) ) ! 440: return false; ! 441: } ! 442: #endif ! 443: } ! 444: break; ! 445: ! 446: case kHFSFolderThreadRecord: ! 447: case kHFSFileThreadRecord: ! 448: { ! 449: if ( recordSize != sizeof(HFSCatalogThread) ) ! 450: return false; ! 451: ! 452: cNodeID = catalogRecord->hfsThread.parentID; ! 453: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 454: return false; ! 455: ! 456: if ( (catalogRecord->hfsThread.nodeName[0] == 0) || ! 457: (catalogRecord->hfsThread.nodeName[0] > 31) ) ! 458: return false; ! 459: } ! 460: break; ! 461: ! 462: case kHFSPlusFolderThreadRecord: ! 463: case kHFSPlusFileThreadRecord: ! 464: { ! 465: if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255))) ! 466: return false; ! 467: ! 468: cNodeID = catalogRecord->hfsPlusThread.parentID; ! 469: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) ! 470: return false; ! 471: ! 472: if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) || ! 473: (catalogRecord->hfsPlusThread.nodeName.length > 255) ) ! 474: return false; ! 475: } ! 476: break; ! 477: ! 478: default: ! 479: return false; ! 480: } ! 481: } ! 482: ! 483: return true; // record appears to be OK ! 484: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.