Annotation of kernel/bsd/hfs/hfscommon/Misc/BTreeWrapper.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.