Annotation of kernel/bsd/hfs/hfscommon/Misc/VolumeRequests.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:           VolumeRequests.c
                     27: 
                     28:        Contains:       MountVolume and related utility routines for HFS & HFS Plus
                     29: 
                     30:        Version:        HFS Plus 1.0
                     31: 
                     32:        Written by:     Deric Horn
                     33: 
                     34:        Copyright:      � 1996-1998 by Apple Computer, Inc., all rights reserved.
                     35: 
                     36:        File Ownership:
                     37: 
                     38:                DRI:                            Deric Horn
                     39: 
                     40:                Other Contacts:         Mark Day, Don Brady
                     41: 
                     42:                Technology:                     File Systems
                     43: 
                     44:        Writers:
                     45: 
                     46:                (JL)    Jim Luther
                     47:                (msd)   Mark Day
                     48:                (DSH)   Deric Horn
                     49:                (djb)   Don Brady
                     50: 
                     51:        Change History (most recent first):
                     52:          <Rhap>         7/28/98        djb             GetDiskBlocks is now implemented in MacOSStubs.c (radar #2258148).
                     53:          <Rhap>          4/3/98        djb             Conditionally remove FSVars reference from GetVolumeNameFromCatalog.
                     54:          <Rhap>         3/31/98        djb             Sync up with final HFSVolumes.h header file.
                     55:          <CS47>         1/29/98        DSH             TrashAllFSCaches is responsible for trashing all file system and
                     56:                                                                        disk caches. Called from FlushVol when the HFS bit is set.
                     57:          <CS46>        12/12/97        DSH             2003877, when vcbAllocPtr was copied to nextAllocation it was
                     58:                                                                        getting sign extended.
                     59:          <CS45>        11/26/97        DSH             2003459, fcbs was not being initialized if volume was offline
                     60:                                                                        and we are executing an unconditional unmount.
                     61:          <CS44>        11/24/97        DSH             2005507, FlushVolumeControlBlock() keeps MDB drCrDate in sync
                     62:                                                                        with VolumeHeader createDate.
                     63:          <CS43>        11/11/97        DSH             1685873, RemountWrappedVolumes was only remounting the first
                     64:                                                                        HFS+ volume in the queue, causing HFS wrappers to be mounted if
                     65:                                                                        multiple volumes had been mounted before InitHFSPlus.
                     66:          <CS42>         11/4/97        DSH             Clear FCB when getting a new one.
                     67:          <CS41>         11/3/97        JL              #2001483 - Removed unneeded parameters from MountVolume,
                     68:                                                                        MountHFSVolume, MountHFSPlusVolume, GetVolumeInformation,
                     69:                                                                        GetXVolumeInformation and AddVCB (and added local variables as
                     70:                                                                        needed). Return WDCBRecPtr from UnMountVolume. Set wdcb
                     71:                                                                        parameter to NULL in GetXVolumeInformation if working directory
                     72:                                                                        was not specified.
                     73:          <CS40>        10/31/97        DSH             Added consistencyStatus parameter to MountCheck
                     74:          <CS39>        10/23/97        msd             Bug 1685113. The VolumeHeader's createDate should be in local
                     75:                                                                        time (not GMT) and identical to the MDB's drCrDate (and VCB's
                     76:                                                                        vcbCrDate). When checking for a remount of an offline HFS Plus
                     77:                                                                        volume, compare write counts instead of mod dates (which could
                     78:                                                                        be fooled by the user changing time zones). Force MountCheck to
                     79:                                                                        run if the volume was last mounted by Bride 1.0b2 or earlier.
                     80:          <CS38>        10/17/97        msd             Conditionalize DebugStrs.
                     81:          <CS37>        10/13/97        djb             Update volumeNameEncodingHint when updating the volume name.
                     82:          <CS36>        10/10/97        msd             Bug 1683571. The dates in the volume header are in GMT, so be
                     83:                                                                        sure to convert them when mounting a volume or flushing the
                     84:                                                                        volume header.
                     85:          <CS35>         10/2/97        DSH             In UnmountVolume() check that the drive is on line before
                     86:                                                                        determining if wrapper volume needs to be renamed causing IO.
                     87:          <CS34>         10/1/97        DSH             Run on disk version of MountCheck instead of ROM version for
                     88:                                                                        boot volumes1682475.
                     89:          <CS33>         10/1/97        djb             Add calls to InvalidateCatalogCache (part of radar #1678833).
                     90:          <CS32>         9/26/97        DSH             Removed debugging code: support for 'W' key wrapper mounting.
                     91:          <CS31>         9/17/97        DSH             hfsPlusIOPosOffset was uninitialized for Wrapperless volumes.
                     92:          <CS30>          9/5/97        djb             In MountVol initialize Catalog cache before calling Catalog!
                     93:          <CS29>          9/4/97        msd             PropertyCloseVolume renamed to AttributesCloseVolume. Remove
                     94:                                                                        call to AttributesOpenVolume (it no longer exists).
                     95:          <CS28>          9/2/97        DSH             VolumeHeader is now 3rd sector in partition, altVH is 2nd to
                     96:                                                                        last cor compatability.  Initial support for wrapperless
                     97:                                                                        volumes.
                     98:          <CS27>         8/26/97        djb             Only call CountRootFiles during MountVol.
                     99:          <CS26>         8/20/97        msd             If the HFS Plus volume version doesn't match, mount the wrapper
                    100:                                                                        instead.
                    101:          <CS25>         8/19/97        djb             Add error handling to RenameWrapperVolume.
                    102:          <CS24>         8/15/97        msd             Bug 1673999. In MakeVCBsExtendedVCBs, copy old VCB's vcbAllocPtr
                    103:                                                                        to new VCB's nextAllocation field.
                    104:          <CS23>         8/12/97        djb             Fixed GetXVolInfo to only use extended vcb fields for local
                    105:                                                                        volumes (radar# 1673177)
                    106:          <CS22>         8/11/97        DSH             vcbNmAlBlks is now taken from the embededExtent.blockCount
                    107:                                                                        (1669121).
                    108:          <CS21>         8/11/97        djb             Return actual count of files in root directory for HFS Plus
                    109:                                                                        volumes (Radar #1669118). Added local CountRootFiles routine.
                    110:                                                                        8/5/97 msd Make sure version field in VolumeHeader is exactly
                    111:                                                                        kHFSPlusVersion. 8/1/97 djb GetXVolumeInformation now returns
                    112:                                                                        extFSErr when FSID is nonzero (Radar #1649503).
                    113:          <CS20>         7/25/97        DSH             Init and Dispose of GenericMRUCache within ExtendedVCB.
                    114:          <CS19>         7/16/97        DSH             FilesInternal.x -> FileMgrInternal.x to avoid name collision
                    115:          <CS18>         7/15/97        DSH             Remount Wrapper volumes mounted before HFS+ initialization
                    116:                                                                        (166729)
                    117:          <CS17>         7/15/97        djb             Remove ioXVersion checking in GetXVolInfo (radar #1666217).
                    118:          <CS16>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
                    119:          <CS15>          7/7/97        djb             Add GetVolumeNameFromCatalog routine.
                    120:          <CS14>          7/7/97        DSH             GetNewVRefNum now get's a recycled vRefNum. Bug 1664445 in
                    121:                                                                        Installer was cacheing the vRefNum while CheckDisk unmounts and
                    122:                                                                        remounts disk.
                    123:          <CS13>         6/30/97        DSH             shadowing values obsoleteVCBXTRef, and obsoleteVCBCTRef when
                    124:                                                                        HFS+ volume is mounted.
                    125:          <CS12>         6/26/97        DSH             GetVolInfo returns HFS signature for HFS+ volumes, GetXVolInfo
                    126:                                                                        returns real signature.
                    127:          <CS11>         6/24/97        DSH             MakeVCBsExtendedVCBs was using wdcb->count as count not byte
                    128:                                                                        count.
                    129:          <CS10>         6/18/97        djb             Set/get volume encodingsBitmap.
                    130:           <CS9>         6/16/97        msd             Include String.h and Disks.h.
                    131:           <CS8>         6/12/97        djb             Get in sync with HFS Plus format changes.
                    132:           <CS7>         6/11/97        msd             Make GetXVolumeInformation return true allocation block size. It
                    133:                                                                        now checks the ioXVersion field.
                    134:           <CS6>         5/28/97        msd             When flushing the volume header, write out the allocation file's
                    135:                                                                        clump size (from the FCB). When mounting an HFS Plus volume,
                    136:                                                                        zero the entire FCB extent record, not just the first extent,
                    137:                                                                        for the various volume control files.
                    138:           <CS5>         5/19/97        djb             Add calls to CreateVolumeCatalogCache,
                    139:                                                                        DisposeVolumeCatalogCache.
                    140:           <CS4>          5/9/97        djb             Get in sync with new FilesInternal.i
                    141:           <CS3>          5/8/97        DSH             Only mount HFS+ volumes with version < 2.0 in the VolumeHeader.
                    142:                                                                        Return wrgVolTypErr if too new.
                    143:           <CS2>          5/2/97        djb             Disable Manual Eject code since its buggy!
                    144:           <CS1>         4/25/97        djb             first checked in
                    145: 
                    146:         <HFS32>         4/11/97        DSH             MountHFSPlusVolume gets volume name from catalog, and
                    147:                                                                        UnmountVolume shadows the name back to the wrapper partition.
                    148:         <HFS31>          4/8/97        msd             Once volume is mounted, call AttributesOpenVolume to allow a
                    149:                                                                        buffer to be allocated.
                    150:         <HFS30>          4/7/97        msd             In FlushVolumeControlBlock, don't update the attributes BTree
                    151:                                                                        fields in the Volume Header unless an attributes BTree was
                    152:                                                                        already open.
                    153:         <HFS29>          4/7/97        msd             In SetupFCB, add case for attributes BTree. Add code to set up
                    154:                                                                        the attributes BTree. Remove call to PropertyOpenVolume. In
                    155:                                                                        FlushVolumeControlBlock, write out any changes to the attributes
                    156:                                                                        BTree.
                    157:         <HFS28>          4/4/97        djb             Get in sync with volume format changes.
                    158:         <HFS27>         3/31/97        djb             Added catalogDataCache to VCB; Remove ClearMem routine.
                    159:         <HFS26>         3/18/97        msd             In MountHFSPlusVolume, the free blocks calculation can overflow,
                    160:                                                                        setting vcbFreeBks to a too-small value.
                    161:         <HFS25>         3/17/97        DSH             Added some utility functions AddVCB, GetParallelFCBFromRefNum,
                    162:                                                                        casting for SC, and made some functions extern for DFA.
                    163:         <HFS24>          3/5/97        msd             Add calls to Property Manager to open and close the volume. When
                    164:                                                                        unmounting an HFS+ volume, the allocation (bitmap) file now gets
                    165:                                                                        closed.
                    166:         <HFS23>         2/19/97        djb             Update to 16-bit HFS Plus signature.
                    167:         <HFS22>         2/12/97        msd             In GetXVolumeInformation, the result code could be
                    168:                                                                        uninitialized.
                    169:         <HFS21>         1/23/97        DSH             UpdateAlternateVoumeControlBlock()
                    170:         <HFS20>         1/15/97        djb             Remove MountCheckStub. Add file names to fcbs for debugging.
                    171:         <HFS19>         1/13/97        DSH             Use ExtendedVCB nextAllocation instead of vcbAllocPtr through
                    172:                                                                        all code.
                    173:         <HFS18>          1/9/97        djb             Get in sync with new VolumeHeader and Extended VCB.
                    174:         <HFS17>          1/6/97        djb             Changed API to ParallelFCBFromRefnum (pragma parameter was
                    175:                                                                        broken).
                    176:         <HFS16>          1/6/97        msd             Set only the defined bits in the MDB drAtrb field (when copying
                    177:                                                                        from VCB vcbAtrb field).
                    178:         <HFS15>          1/6/97        DSH             CloseFile requires VCB to be passed in.
                    179:         <HFS14>          1/6/97        djb             FlushVolumeControlBlock was writing to absolute block 0 instead
                    180:                                                                        of to block zero of the embedded volume.
                    181:         <HFS13>        12/20/96        msd             A comparison was using "=" instead of "=="; might have caused
                    182:                                                                        the wrong volume to be set as the default.
                    183:         <HFS12>        12/19/96        DSH             Setting up ExtendedVCBs
                    184:         <HFS11>        12/19/96        djb             Updated for new B-tree Manager interface.
                    185:         <HFS10>        12/18/96        msd             Change GetVCBRefNum so it can actually return a VCB pointer.
                    186:          <HFS9>        12/12/96        djb             Use new SPI for GetCatalogNode.
                    187:          <HFS8>        12/12/96        msd             Fix a bunch of errors (mostly type mismatch) when compiling with
                    188:                                                                        Metrowerks.
                    189:          <HFS7>        12/12/96        DSH             adding some util functions
                    190:          <HFS6>        12/10/96        msd             Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
                    191:          <HFS5>         12/4/96        DSH             Ported GetVolumeInformation & GetXVolumeInformation.
                    192:                <3*>    11/20/96        DSH             HFS Plus support to MountVolume
                    193:          <HFS3>        11/20/96        DSH             Added UnmountVol and related routines, also backed out <2>
                    194:                                                                        because C_FXMKeyCmp is passed as a parameter from C but called
                    195:                                                                        from Asm in BTOpen so we need a Case ON Asm entry point.
                    196:          <HFS2>        11/20/96        msd             Use CompareExtentKeys() instead of CFXMKeyCmp().
                    197:          <HFS1>        11/19/96        DSH             first checked in
                    198:                 <1>    11/19/96        DSH             first checked in
                    199: 
                    200: */
                    201: 
                    202: #if ( PRAGMA_LOAD_SUPPORTED )
                    203:         #pragma        load    PrecompiledHeaders
                    204: #else
                    205:         #if TARGET_OS_MAC
                    206:        #include        <Files.h>
                    207:         #include       <FSM.h>
                    208:         #include       <OSUtils.h>
                    209:         #include       <LowMemPriv.h>
                    210:         #include       <LowMem.h>
                    211:         #include       <StringCompare.h>
                    212:         #include       <Errors.h>
                    213:         #include       <Devices.h>
                    214:         #include       <SonyPriv.h>
                    215:         #include       <EDiskPriv.h>
                    216:         #include       <String.h>
                    217:         #include       <Disks.h>
                    218:         #else
                    219:        #include "../../hfs.h"
                    220:                #include "../headers/system/MacOSStubs.h"
                    221:         #endif         /* TARGET_OS_MAC */
                    222: #endif /* PRAGMA_LOAD_SUPPORTED */
                    223: 
                    224: #if TARGET_OS_MAC
                    225: #include       <HardwarePriv.h>
                    226: #endif
                    227: 
                    228: #include       "../headers/FileMgrInternal.h"
                    229: #include       "../headers/HFSVolumes.h"
                    230: 
                    231: 
                    232: #define                kIDSectorOffset 2
                    233: 
                    234: // Exported routine prototypes
                    235: OSErr  MountVolume( VolumeParam *volume, Boolean forceHFSWrapperToMount );
                    236: 
                    237: OSErr  MountHFSVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err );
                    238: 
                    239: OSErr  MountHFSPlusVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err, Boolean pureHFSPlusVolume );
                    240: 
                    241: OSErr  GetVolumeInformation( HVolumeParam *volume, WDCBRecPtr *wdcb );
                    242: 
                    243: OSErr  GetXVolumeInformation( XVolumeParam *volume, WDCBRecPtr *wdcb );
                    244: 
                    245: 
                    246: //     Utility function prototypes
                    247: #if TARGET_OS_MAC
                    248: OSErr  FindFileControlBlock( File *index, Ptr *fcbsH );
                    249: 
                    250: Boolean        GetNextFileControlBlock( UInt16 *index, Ptr fcbsPtr );
                    251: 
                    252: void   Get1stFileControlBlock( UInt16 *index, Ptr *fcbsH );
                    253: 
                    254: void   DisposeFileControlBlocks( ExtendedVCB *vcb );
                    255: #else
                    256: OSErr  GetNewFCB( ExtendedVCB *vcb, FileReference* fRefPtr);
                    257: #endif
                    258: 
                    259: OSErr  AccessBTree( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize, void *CompareRoutine );
                    260: 
                    261: UInt16 DivUp( UInt32 byteRun, UInt32 blockSize );
                    262: 
                    263: Boolean        IsARamDiskDriver( void );
                    264: 
                    265: OSErr  GetVCBRefNum( ExtendedVCB **vcb, short vRefNum );
                    266: 
                    267: OSErr  ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
                    268: 
                    269: void   RenameWrapperVolume( Str27 newVolumeName, UInt16 driveNumber );
                    270: 
                    271: OSErr  CheckExternalFileSystem( ExtendedVCB *vcb );
                    272: 
                    273: OSErr  FlushVolume( ExtendedVCB *vcb );
                    274: 
                    275: FCB            *SetupFCB( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize );
                    276: 
                    277: OSErr  GetDiskBlocks( ExtendedVCB *vcb, unsigned long *numBlocks);
                    278: 
                    279: void   AddVCB( ExtendedVCB     *vcb, short driveNumber, short ioDRefNum );
                    280: 
                    281: short  IsPressed( unsigned short k );
                    282: 
                    283: FileReference  GetNewVRefNum();
                    284: 
                    285: OSErr  GetVolumeNameFromCatalog(ExtendedVCB *vcb);
                    286: 
                    287: #if TARGET_OS_MAC
                    288: static UInt16 CountRootFiles(ExtendedVCB *vcb);
                    289: #endif /* TARGET_OS_MAC */
                    290: 
                    291: 
                    292: #if ( hasHFSManualEject )
                    293: static void SetVCBManEject(ExtendedVCB *vcb);
                    294: #endif
                    295: 
                    296: // External routines
                    297: 
                    298: extern OSErr   C_FlushMDB( ExtendedVCB *volume );
                    299: 
                    300: extern OSErr   DisposeVolumeCacheBlocks( ExtendedVCB *vcb );
                    301: 
                    302: extern void    DisposeVolumeControlBlock( ExtendedVCB *vcb );
                    303: 
                    304: extern OSErr   DeturmineVolume1( VolumeParam *iopb, short *nameLength, Boolean *nameSpecified, ExtendedVCB **vcb, WDCBRec **wdcb, unsigned char **pathName );
                    305: 
                    306: extern OSErr   DeturmineVolume3( VolumeParam *iopb, short *nameLength, Boolean *nameSpecified, ExtendedVCB **vcb, WDCBRec **wdcb, unsigned char **pathName );
                    307: 
                    308: extern OSErr   FlushVolumeBuffers( ExtendedVCB *vcb );
                    309: 
                    310: extern void    MultiplyUInt32IntoUInt64( UInt64 *wideResult, UInt32 num1, UInt32 num2 );
                    311: 
                    312: extern void            TrashCatalogNodeCache( void );
                    313: 
                    314: 
                    315: 
                    316: #if TARGET_OS_MAC
                    317: //�������������������������������������������������������������������������������
                    318: //     Routine:        MountVolume
                    319: //
                    320: // Function:   The VCB pointers are checked to see if a volume in the
                    321: //                             specified drive is already on-line (error if so).  Reads in the
                    322: //                             directory master block and allocates memory for VCB and additional
                    323: //                             data structures, depending on the volume type:
                    324: //
                    325: //                             - For MFS volumes (handled in MFSVol), space is allocated for
                    326: //                               a volume buffer, as well as the block map, which is read in
                    327: //                               from disk).
                    328: //
                    329: //                             - For TFS volumes, space is allocated for a bitmap cache, a volume
                    330: //                               control cache (for B*-Tree use), and a volume cache.  In addition,
                    331: //                               two FCBs are used by the B*-Trees.
                    332: //
                    333: //                             No new VCB storage is allocated for remounts.
                    334: //
                    335: //�������������������������������������������������������������������������������
                    336: 
                    337: OSErr  MountVolume( VolumeParam *volume, Boolean forceHFSWrapperToMount )
                    338: {
                    339:        Byte                                    blockBuffer[512];
                    340:        IOParam                                 *lowMemParamBlock;
                    341:        short                                   ioRefNum;
                    342:        short                                   vRefNum;
                    343:        OSErr                                   err;
                    344:        DrvQEl                                  *dqe;
                    345:        Boolean                                 pureHFSPlusVolume;
                    346:        
                    347:        
                    348:        //--- FSQueueSync was already called by the MountVol glue.
                    349:        
                    350:        vRefNum = volume->ioVRefNum;
                    351:        err = FindDrive( &ioRefNum, &dqe, vRefNum );                                                    //      Get driver refnum
                    352:        if ( err == noErr )
                    353:        {
                    354:                lowMemParamBlock                                = (IOParam *) LMParamBlock;
                    355:                lowMemParamBlock->ioVRefNum             = vRefNum;
                    356:                lowMemParamBlock->ioRefNum              = ioRefNum;
                    357:                lowMemParamBlock->ioBuffer              = (char *)blockBuffer;
                    358:                lowMemParamBlock->ioPosMode             = fsFromStart;
                    359:                lowMemParamBlock->ioPosOffset   = kIDSectorOffset * 512;                        //      MDB is always at block #2
                    360:                lowMemParamBlock->ioReqCount    = 512;                                                          //      MDB is always 1 512 byte block
                    361:                
                    362:                err = PBReadSync( (ParmBlkPtr) lowMemParamBlock );                                      //      Read the MDB
                    363:                
                    364:                pureHFSPlusVolume       = ((HFSPlusVolumeHeader *)blockBuffer)->signature == kHFSPlusSigWord;
                    365:                
                    366:                if (    ( ((HFSMasterDirectoryBlock *)blockBuffer)->drEmbedSigWord == kHFSPlusSigWord   //      Wrapped HFS+ volume
                    367:                        ||      pureHFSPlusVolume == true )                                                                     //      Pure HFS+ volume
                    368:                        &&      err == noErr
                    369:                        &&      forceHFSWrapperToMount == false )                                                       //      if we don't want to force the wrapper to mount
                    370:                {
                    371:                        err = MountHFSPlusVolume( vRefNum, lowMemParamBlock, err, pureHFSPlusVolume );
                    372:                }
                    373:                else                                                                                                                            //      pass all other volume formats / errors to MountHFSVolume
                    374:                {
                    375:                        err = MountHFSVolume( vRefNum, lowMemParamBlock, err );
                    376:                }
                    377:        }
                    378:        
                    379:        return( err );                                                                                                                  //      pass the error back to CmdDone
                    380: }
                    381: #endif /* TARGET_OS_MAC */
                    382: 
                    383: 
                    384: #if TARGET_OS_MAC
                    385: //�������������������������������������������������������������������������������
                    386: //     Routine:        MountHFSPlusVolume
                    387: //
                    388: // Function:   Called by MountVolume()
                    389: //
                    390: //     At this point we know that the MDB's Embeded signature indicates that
                    391: //     this is an HFS Plus disk with an HFS wrapper.
                    392: //
                    393: //�������������������������������������������������������������������������������
                    394: 
                    395: OSErr  MountHFSPlusVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err, Boolean pureHFSPlusVolume )
                    396: {
                    397:        HFSMasterDirectoryBlock *mdb;
                    398:        Byte                                    blockBuffer[512];
                    399:        HFSPlusVolumeHeader             *volumeHeader;
                    400:        ExtendedVCB                             *vcb;
                    401:        QHdr                                    *vcbQHdr;
                    402:        Byte                                    *flagsP;
                    403:        Byte                                    *pbFlagsP;
                    404:        SInt16                                  ioRefNum;
                    405:        FSVarsRec                               *fsVars;
                    406:        DrvQEl                                  *dqe;
                    407:        IOParam                                 *currentIORequestPB;
                    408:        FCB                                             *fcb;
                    409:        Ptr                                     fcbsP;
                    410:        ExtendedFCB                             *extendedFCB;
                    411:        UInt32                                  hfsPlusIOPosOffset;
                    412:        UInt16                                  hfsBlockCount;
                    413:        UInt32                                  hfsBlockSize;
                    414:        UInt32                                  lastMountedVersion;
                    415:        UInt16                                  fcbIndexP;
                    416: 
                    417:        //--    Now read the HFS Plus VolumeHeader located at the first block within the embeded volume
                    418: 
                    419:        ioRefNum = lowMemParamBlock->ioRefNum;
                    420:        
                    421:        if ( pureHFSPlusVolume == false )
                    422:        {
                    423:                mdb = (HFSMasterDirectoryBlock *) lowMemParamBlock->ioBuffer;
                    424: 
                    425:                hfsPlusIOPosOffset                              =       (mdb->drEmbedExtent.startBlock * mdb->drAlBlkSiz) + ( mdb->drAlBlSt * 512 );
                    426:                
                    427:                lowMemParamBlock->ioPosMode             =       fsFromStart;                            
                    428:                lowMemParamBlock->ioPosOffset   =       hfsPlusIOPosOffset + (kIDSectorOffset * 512);           //      VolumeHeader is 2 sectors in
                    429:                lowMemParamBlock->ioBuffer              =       (char *)blockBuffer;
                    430: 
                    431:                err = PBReadSync( (ParmBlkPtr) lowMemParamBlock );                                              //      Read the VolumeHeader
                    432:        }
                    433:        else
                    434:        {
                    435:                hfsPlusIOPosOffset      = 0;            //      From beginning of volume.
                    436:        }
                    437:        
                    438:        volumeHeader = (HFSPlusVolumeHeader *) lowMemParamBlock->ioBuffer;
                    439:        
                    440:        err = ValidVolumeHeader( volumeHeader );
                    441: 
                    442:        if (err == badMDBErr || err == noMacDskErr)
                    443:                return err;                                                                                                                     // it's not valid, so don't try to mount it
                    444: 
                    445:        if ( err == noErr )
                    446:        {
                    447:                err             = notARemountErr;                                                                                       //      cuz we're looking for remounts only here
                    448:                vcbQHdr = LMGetVCBQHdr();                                                                                       //      search the queue of VCBs
                    449: 
                    450:                for ( vcb = (ExtendedVCB*)vcbQHdr->qHead ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink )        //      search the queue of VCBs
                    451:                {
                    452:                        if (   (vcb->vcbDrvNum  == 0)                                                                   //      matching volume better be off-line (0 drive num)
                    453:                                && (vcb->vcbSigWord     == volumeHeader->signature)                             //      Same signature?
                    454:                                && (vcb->vcbCrDate      == volumeHeader->createDate)                    //      Same create date?
                    455:                                && (vcb->vcbWrCnt       == volumeHeader->writeCount)                    //      Same write count?
                    456:                           )
                    457:                        {
                    458:                                //      At this point, we're fairly certain that the two volumes are, in fact, the same,
                    459:                                //      but just to make sure (and avoid problems with stuck clocks), we'll compare the
                    460:                                //      volume names as well:
                    461:                                
                    462:                                //��    How do I compare unicode names?
                    463:                                //��    do we just skip this check?
                    464:                //              if ( EqualString( vcb->volumeName, volumeHeader->volumeName, true, true) )      //      caseSensitive, diacSensitive
                    465:                                        break;                                                                                                  //      Remount
                    466:                        }
                    467:                }
                    468:                if ( vcb == nil ) goto RemountExit;
                    469: 
                    470: 
                    471:                ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode;                           //      Drive status!
                    472:                ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff;                          //      Clear status byte for return
                    473:                
                    474:                err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock );                                     //      refnum and drivenum set up by read call
                    475: 
                    476: 
                    477:                //--    Now propagate the write protect status byte back to the vcb
                    478:                flagsP = (Byte *)((Ptr)(&(vcb->vcbAtrb))) + 1;
                    479:                pbFlagsP = (Byte *)((Ptr)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
                    480:                *flagsP = *pbFlagsP & kVolumeHardwareLockMask;
                    481: 
                    482:                vcb->vcbDrvNum  = driveNumber;
                    483:                vcb->vcbDRefNum = ioRefNum;                                                                                     //      Driver RefNum
                    484:                
                    485:                #if ( hasHFSManualEject )
                    486:                        SetVCBManEject(vcb);
                    487:                #endif
                    488: 
                    489: 
                    490:                if ( !(*flagsP & kVolumeHardwareLockMask) )                                                     //      if bit is NOT set
                    491:                {
                    492:                        vcb->vcbAtrb &= ~kVolumeUnmountedMask;                                                  //      clear the kVolumeUnmounted attribute
                    493:                        MarkVCBDirty( vcb );
                    494:                        err = FlushVolumeControlBlock( vcb );
                    495:                }
                    496:                
                    497:                err = noErr;
                    498: 
                    499:        }
                    500: 
                    501: 
                    502: RemountExit:
                    503:        if ( err == noErr ) goto CmdDone;                                                                               //      noErr implies a successful remount                      
                    504:                
                    505:        //--    if we are allowing new mounts, let the ROM handle the details.  Otherwise, let the error stand
                    506:        fsVars = (FSVarsRec*)LMGetFSMVars();
                    507:        if ( fsVars->fsFlags & fsNoAllocateMask )
                    508:                goto CmdDone;
                    509:                
                    510:        LMSetNewMount( -1 );                                                                                                    //      assume now that it's a new volume
                    511:        
                    512:        
                    513:        
                    514:        //--    First see if the disk is already mounted.
                    515: mv_Start:
                    516:        err = paramErr;
                    517:        driveNumber = lowMemParamBlock->ioVRefNum;
                    518:        if ( driveNumber <= 0 ) goto MtVolDone;
                    519:        err = GetVCBDriveNum( &vcb, driveNumber );
                    520:        if ( err == noErr )
                    521:        {
                    522:                if ( vcb->vcbDrvNum != 0 )
                    523:                {
                    524:                        err = volOnLinErr;
                    525:                        goto MtVolDone;
                    526:                }
                    527:        }
                    528:        
                    529:        //--    Find the appropriate drive queue entry and allocate a VCB.
                    530:        err = FindDrive( &ioRefNum, &dqe, driveNumber );
                    531:        if ( err != noErr ) goto MtVolDone;
                    532:        
                    533:        vcb = (ExtendedVCB *) NewPtrSysClear( sizeof( ExtendedVCB ) );          //      Zero out the Extended VCB
                    534: 
                    535:        if ( vcb == nil ) goto MtVolDone;                                                                       //      exit if we got no memory
                    536:        
                    537:        AddVCB( vcb, driveNumber, ioRefNum );                                                           //      prep the VCB for cache calls
                    538:        
                    539:        //--    Now try reading in the Volume Header.
                    540:        //      We use "hfsPlusIOPosOffset / 512" cuz the VCB is not set up yet, so it's an absolute read
                    541:        err = GetBlock_glue( gbDefault, (hfsPlusIOPosOffset / 512) + kIDSectorOffset , (Ptr*)&volumeHeader, vcb->vcbVRefNum, vcb );     //      no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
                    542: 
                    543:        if ( err != noErr )     goto MtVolEr2;                                                                  //      Quit & Release VCB on errors
                    544:        
                    545:        //--    Now check what manner of animal we have before us:
                    546:        err = RelBlock_glue( (Ptr)volumeHeader, rbTrashMask );
                    547:        
                    548:        err = ValidVolumeHeader( volumeHeader );
                    549:        if ( err != noErr )
                    550:        {
                    551:                if ( err == noMacDskErr )
                    552:                        goto MtVolEr2;
                    553:                else
                    554:                        goto MtVolEr1;
                    555:        }
                    556:        
                    557:        //      The VolumeHeader seems OK: transfer info from buffer into VCB.
                    558: 
                    559:        //      Initialize our dirID/nodePtr cache associated with this volume.
                    560:        err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
                    561:        ReturnIfError( err );
                    562: 
                    563:        //--    Copy fields between [vcbSigWord, vcbVN]
                    564: 
                    565:        vcb->vcbCrDate                                  =       volumeHeader->createDate;                                       // NOTE: local time, not GMT!
                    566:        vcb->vcbLsMod                                   =       UTCToLocal(volumeHeader->modifyDate);
                    567:        vcb->vcbAtrb                                    =       (UInt16)volumeHeader->attributes;                       //      VCB uses 16 bits, next 16 are for future API changes
                    568:        vcb->vcbClpSiz                                  =       volumeHeader->rsrcClumpSize;
                    569:        vcb->vcbNxtCNID                                 =       volumeHeader->nextCatalogID;
                    570:        vcb->vcbVolBkUp                                 =       UTCToLocal(volumeHeader->backupDate);
                    571:        vcb->vcbWrCnt                                   =       volumeHeader->writeCount;
                    572:        vcb->vcbXTClpSiz                                =       volumeHeader->extentsFile.clumpSize;
                    573:        vcb->vcbCTClpSiz                                =       volumeHeader->catalogFile.clumpSize;
                    574:        vcb->attributesClumpSize                =       volumeHeader->attributesFile.clumpSize;
                    575:        vcb->vcbFilCnt                                  =       volumeHeader->fileCount;
                    576:        vcb->vcbDirCnt                                  =       volumeHeader->folderCount;
                    577:        BlockMoveData( volumeHeader->finderInfo, vcb->vcbFndrInfo, sizeof( SInt32 ) * 8 );
                    578:        
                    579:        if ( pureHFSPlusVolume == true )
                    580:        {
                    581:                UInt32  totalSectors            =       (volumeHeader->blockSize / 512) * volumeHeader->totalBlocks;
                    582:                HFSBlocksFromTotalSectors( totalSectors, &hfsBlockSize, &hfsBlockCount );
                    583:        }
                    584:        else
                    585:        {
                    586:                hfsBlockSize                            =       mdb->drAlBlkSiz;
                    587:                hfsBlockCount                           =       mdb->drEmbedExtent.blockCount;
                    588:        }
                    589:        
                    590:        //      vcbFreeBks is the number of free bytes divided by the (HFS compatible) allocation block size.  Since the
                    591:        //      number of free bytes could overflow a UInt32, we actually divide both free bytes and allocation block size by
                    592:        //      512 before doing the division.  This prevents intermediate values from overflowing until the volume size is
                    593:        //      2 TB.  It's OK to divide by 512 since both HFS and HFS Plus require allocation blocks to be a multiple of 512.
                    594:        vcb->vcbFreeBks = (volumeHeader->freeBlocks * (volumeHeader->blockSize / 512)) / (hfsBlockSize / 512);
                    595:        
                    596: 
                    597:        //--    Fields taken from the MDB
                    598:        vcb->vcbSigWord                                 =       kHFSPlusSigWord;                                                //      new field in VCB space
                    599:        vcb->vcbNmAlBlks                                =       hfsBlockCount;                                                  //      number of HFS allocation blocks HFS+ volume
                    600:        vcb->vcbAlBlkSiz                                =       hfsBlockSize;                                                   //      add to extended vcb
                    601: 
                    602:        //--    Now fill in the Extended VCB info
                    603:        vcb->vcbSigWord                                 =       volumeHeader->signature;
                    604:        vcb->nextAllocation                             =       volumeHeader->nextAllocation;
                    605:        vcb->totalBlocks                                =       volumeHeader->totalBlocks;
                    606:        vcb->freeBlocks                                 =       volumeHeader->freeBlocks;
                    607:        vcb->blockSize                                  =       volumeHeader->blockSize;
                    608:        vcb->allocationsClumpSize               =       volumeHeader->allocationFile.clumpSize;
                    609:        vcb->checkedDate                                =       volumeHeader->checkedDate;
                    610:        vcb->encodingsBitmap                    =       volumeHeader->encodingsBitmap;
                    611:        
                    612:        //      Set the allocation block start for this HFS Plus wrapped volume
                    613:        vcb->vcbAlBlSt                                  =       hfsPlusIOPosOffset / 512;
                    614:        vcb->hfsPlusIOPosOffset                 =       hfsPlusIOPosOffset;
                    615:        
                    616:        //��    Questionables
                    617:        vcb->vcbVBMSt                                   = 0;                                                                            //�� (We should set this) BitMap start NOT used in HFS Plus
                    618:        vcb->vcbEmbedSigWord                    = 0;
                    619:        vcb->vcbEmbedExtent.startBlock  = 0;
                    620:        vcb->vcbEmbedExtent.blockCount  = 0;
                    621: 
                    622: 
                    623:        //--    Mark all the unused VCB fields with 0
                    624:        vcb->vcbAllocPtr                                =       0;                                                                              //      use extended VCB value                          
                    625:        
                    626:        //      Remember which implementation last mounted this volume
                    627:        lastMountedVersion                              =       volumeHeader->lastMountedVersion;
                    628:        
                    629:        currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead;                        //      current request
                    630:        currentIORequestPB->ioVRefNum = vcb->vcbVRefNum;                                                        //      return volume refnum to user
                    631:        
                    632:        lowMemParamBlock = (IOParam *) LMParamBlock;
                    633:        ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode;                                           //      drive status!
                    634:        ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff;                                          //      Clear status byte for return
                    635:        
                    636:        err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock );
                    637:        
                    638:        flagsP = (Byte *)((Ptr)(&(vcb->vcbAtrb))) + 1;
                    639:        pbFlagsP = (Byte *)((Ptr)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
                    640:        *flagsP = *pbFlagsP & kVolumeHardwareLockMask;
                    641:        
                    642:        if ( IsARamDiskDriver() )
                    643:        {
                    644:                vcb->vcbAtrb |= kVolumeNoCacheRequiredMask;                                                             //      yes:�mark VCB as a RAM Disk
                    645:        }
                    646:        
                    647:        vcb->vcbXTAlBlks = 0;   //      Unused, use fcb.fcbPLen instead
                    648:        vcb->vcbCTAlBlks = 0;   //      Unused, use fcb.fcbPLen instead
                    649:        
                    650:        vcb->vcbWrCnt++;                                                                                                                        //      Compensate for write of MDB on last flush
                    651:        
                    652:        
                    653:        //--    Try to find three free FCBs for use by the volume control B*-Trees:
                    654:        
                    655:        //
                    656:        //--    Set up the Extent FCB
                    657:        //
                    658:        err = FindFileControlBlock( &fcbIndexP, &fcbsP );                                                                       //      Get new FCB
                    659:        if ( err != noErr )     goto MtVolErr;
                    660:        
                    661:        fcb = GetFileControlBlock( fcbIndexP );
                    662:        fcb->fcbEOF = volumeHeader->extentsFile.logicalSize.lo;                                                         //      Set extent tree's LEOF
                    663:        fcb->fcbPLen = volumeHeader->extentsFile.totalBlocks * volumeHeader->blockSize;         //      Set extent tree's PEOF
                    664: 
                    665:        vcb->extentsRefNum              = fcbIndexP;                                                                                            //      Set Extents B*-Tree file RefNum
                    666: 
                    667:        ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
                    668: 
                    669:        extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
                    670:        BlockMoveData( volumeHeader->extentsFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
                    671:        
                    672:        //
                    673:        //--    Set up the Catalog FCB
                    674:        //
                    675:        err = FindFileControlBlock( &fcbIndexP, &fcbsP );
                    676:        if ( err != noErr )     goto MtVolErr;
                    677:        
                    678:        fcb = GetFileControlBlock( fcbIndexP );
                    679:        fcb->fcbEOF = volumeHeader->catalogFile.logicalSize.lo;                                                         //      Set catalog tree's LEOF
                    680:        fcb->fcbPLen = volumeHeader->catalogFile.totalBlocks * volumeHeader->blockSize;         //      Set catalog tree's PEOF
                    681: 
                    682:        vcb->catalogRefNum              = fcbIndexP;                                                                                            //      Set Catalog B*-Tree file RefNum
                    683: 
                    684:        ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
                    685:        
                    686:        extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
                    687:        BlockMoveData( volumeHeader->catalogFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
                    688: 
                    689:        
                    690:        //
                    691:        //--    Set up the Allocations FCB
                    692:        //
                    693:        err = FindFileControlBlock( &fcbIndexP, &fcbsP );
                    694:        if ( err != noErr )     goto MtVolErr;
                    695:        
                    696:        fcb = GetFileControlBlock( fcbIndexP );
                    697:        fcb->fcbEOF = volumeHeader->allocationFile.logicalSize.lo;                                                      //      Set catalog tree's LEOF
                    698:        fcb->fcbPLen = volumeHeader->allocationFile.totalBlocks * volumeHeader->blockSize;      //      Set catalog tree's PEOF
                    699: 
                    700:        vcb->allocationsRefNum  = fcbIndexP;                                                                                            //      Set Catalog B*-Tree file RefNum
                    701: 
                    702:        ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
                    703: 
                    704:        extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
                    705:        BlockMoveData( volumeHeader->allocationFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
                    706: 
                    707:        
                    708:        //
                    709:        //--    Set up the Attributes FCB
                    710:        //
                    711:        vcb->attributesRefNum = 0;              //      In case there isn't an attributes BTree
                    712:        
                    713:        if (volumeHeader->attributesFile.extents[0].blockCount != 0)
                    714:        {
                    715:                err = FindFileControlBlock( &fcbIndexP, &fcbsP );
                    716:                if ( err != noErr )     goto MtVolErr;
                    717:                
                    718:                fcb = GetFileControlBlock( fcbIndexP );
                    719:                fcb->fcbEOF = volumeHeader->attributesFile.logicalSize.lo;                                                      //      Set attribute tree's LEOF
                    720:                fcb->fcbPLen = volumeHeader->attributesFile.totalBlocks * volumeHeader->blockSize;      //      Set attribute tree's PEOF
                    721: 
                    722:                vcb->attributesRefNum   = fcbIndexP;                                                                                            //      Set Catalog B*-Tree file RefNum
                    723: 
                    724:                ClearMemory( (Ptr)fcb->fcbExtRec, sizeof(HFSExtentRecord) );
                    725: 
                    726:                extendedFCB = ParallelFCBFromRefnum( fcbIndexP );
                    727:                BlockMoveData( volumeHeader->attributesFile.extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord) );
                    728:        }
                    729:        
                    730:        
                    731:        vcb->vcbMAdr    = (Ptr)*(long *)SysBMCPtr;                                      //      Set up the volume bitmap cache
                    732:        vcb->vcbCtlBuf  = (Ptr)*(long *)SysCtlCPtr;                                     //      Set up the volume control cache
                    733:        
                    734:        //
                    735:        //--    Finish setting up the FCBs for the extent B*-Tree and the catalog B*-Tree:
                    736:        //
                    737: 
                    738:        err = AccessBTree( vcb, vcb->extentsRefNum, kHFSExtentsFileID, vcb->vcbXTClpSiz, (void *) CompareExtentKeysPlus );
                    739:        if ( err != noErr )     goto MtChkErr;
                    740:        
                    741:        err = AccessBTree( vcb, vcb->catalogRefNum, kHFSCatalogFileID, vcb->vcbCTClpSiz, (void *) CompareExtendedCatalogKeys );
                    742:        if ( err != noErr )     goto MtChkErr;
                    743:        
                    744:        if (vcb->attributesRefNum)
                    745:        {
                    746:                err = AccessBTree( vcb, vcb->attributesRefNum, kHFSAttributesFileID, vcb->attributesClumpSize, (void *) CompareAttributeKeys );
                    747:                if ( err != noErr )     goto MtChkErr;
                    748:        }
                    749: 
                    750:        (void) SetupFCB( vcb, vcb->allocationsRefNum, kHFSAllocationFileID, volumeHeader->allocationFile.clumpSize );
                    751:        
                    752: 
                    753:        err = CreateVolumeCatalogCache(vcb);
                    754:        if ( err )
                    755:                goto MtChkErr;
                    756: 
                    757:        // set up root file count...
                    758:        
                    759:        vcb->vcbNmFls = CountRootFiles(vcb);
                    760:        
                    761:        
                    762:        //      Get the volume name from the catalog file
                    763:        (void) GetVolumeNameFromCatalog(vcb);
                    764:        
                    765:        //      If the volume was not unmounted properly, then run MountCheck.
                    766:        //      If the volume was last mounted by Bride 1.0b2 ('8.01'), then the create date may be wrong, so
                    767:        //              we should run MountCheck to fix it.
                    768:        if ( !(vcb->vcbAtrb & (short)kVolumeUnmountedMask) ||
                    769:                        lastMountedVersion == '8.01')
                    770:        {
                    771:                UInt32          consistencyStatus;
                    772:                
                    773:                vcb->vcbAtrb &= ~kVolumeUnmountedMask;                                  //      From now until _Unmount (clear the bit)
                    774:                *(Ptr)FSCallAsync = 0;
                    775:                err = MountCheck( vcb, &consistencyStatus );
                    776:                if ( err )
                    777:                        goto MtChkErr;
                    778:        }
                    779:        else
                    780:        {
                    781:                vcb->vcbAtrb &= ~kVolumeUnmountedMask;                                  //      From now until _Unmount (clear the bit)
                    782:        }
                    783: 
                    784: CheckRemount:
                    785: 
                    786:        //      ��This comment was in TFSVol.a, should look into it
                    787:        //      Deleted stuff patched out by KillCheckRemountNiceWay in FileMgrPatches.a <SM1>
                    788: 
                    789: 
                    790: MtVolOK:
                    791:        err = noErr;
                    792: 
                    793: MtVolDone:
                    794:        if ( err == noErr )
                    795:        {
                    796:                if ( !(vcb->vcbAtrb & kVolumeHardwareLockMask) )                //      if the disk is not write protected
                    797:                {
                    798:                        MarkVCBDirty( vcb );                                                            //      mark VCB dirty so it will be written
                    799:                        err = FlushVolumeControlBlock( vcb );                           //      Go flush the VCB info BEFORE close
                    800:                }
                    801:        }
                    802:        goto    CmdDone;
                    803: 
                    804: 
                    805: 
                    806: MtChkErr:
                    807:        (void) DisposeVolumeCatalogCache(vcb);
                    808:        InvalidateCatalogCache( vcb );
                    809: 
                    810:        *((OSErr *)HFSDSErr) = err;
                    811:        err = badMDBErr;
                    812:        
                    813:        //--    Release any resources allocated so far before exiting with an error:
                    814: MtVolErr:
                    815:        DisposeFileControlBlocks( vcb );                                                                //      deallocate control file FCBs
                    816:        
                    817: MtVolEr1:
                    818:        DisposeVolumeCacheBlocks( vcb );                                                                //      invalidate any cache blocks for this volume
                    819:        
                    820: MtVolEr2:
                    821:        if ( (Byte)LMGetNewMount() == 0 )                                                               //      only deallocate VCB for new mounts
                    822:        {
                    823:                //              Remount case -- Must zero buffer and map ptrs in old VCB.
                    824:                //              Restore VCB to its original off-line state (ie clear VCBDrvNum,
                    825:                //              and move drive number to VCBDRefNum field)
                    826:                vcb->vcbDRefNum = vcb->vcbDrvNum;                                                       //      write drv number to VCBDRefNum field
                    827:                vcb->vcbDRefNum = 0;                                                                            //      clear drive number field of VCB
                    828:                vcb->vcbMAdr    = nil;                                                                          //      clear mapptr in VCB
                    829:                vcb->vcbBufAdr  = nil;                                                                          //      clear buffptr in VCB
                    830:        }
                    831:        else
                    832:        {
                    833:                DisposeVolumeControlBlock( vcb );
                    834:        }
                    835: 
                    836:        if ( err <= 0 ) goto CmdDone;
                    837:        
                    838:        currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead;
                    839:        goto mv_Start;  
                    840: 
                    841: CmdDone:
                    842: return( err );
                    843: 
                    844: }
                    845: #endif /* TARGET_OS_MAC */
                    846: 
                    847: 
                    848: 
                    849: #if TARGET_OS_MAC
                    850: //�������������������������������������������������������������������������������
                    851: //     Routine:        MountHFSVolume
                    852: //
                    853: // Function:   The VCB pointers are checked to see if a volume in the
                    854: //                             specified drive is already on-line (error if so).  Reads in the
                    855: //                             directory master block and allocates memory for VCB and additional
                    856: //                             data structures, depending on the volume type:
                    857: //
                    858: //                             - For MFS volumes (handled in MFSVol), space is allocated for
                    859: //                               a volume buffer, as well as the block map, which is read in
                    860: //                               from disk).
                    861: //
                    862: //                             - For TFS volumes, space is allocated for a bitmap cache, a volume
                    863: //                               control cache (for B*-Tree use), and a volume cache.  In addition,
                    864: //                               two FCBs are used by the B*-Trees.
                    865: //
                    866: //                             No new VCB storage is allocated for remounts.
                    867: //
                    868: //�������������������������������������������������������������������������������
                    869: 
                    870: OSErr  MountHFSVolume( short driveNumber, IOParam* lowMemParamBlock, OSErr err )
                    871: {
                    872:        HFSMasterDirectoryBlock *mdb;
                    873:        QHdr                                    *vcbQHdr;
                    874:        Byte                                    *flagsP;
                    875:        Byte                                    *mdbFlagsP;
                    876:        FSVarsRec                               *fsVars;
                    877:        IOParam                                 *currentIORequestPB;
                    878:        Ptr                                     fcbsP;
                    879:        FCB                                             *fcb;
                    880:        ExtendedVCB                             *vcb;
                    881:        DrvQEl                                  *dqe;
                    882:        short                                   ioRefNum;
                    883:        UInt16                                  fcbIndexP;
                    884:        
                    885:        if ( err != noErr )
                    886:                goto RemountExit;
                    887:        
                    888:        ioRefNum = lowMemParamBlock->ioRefNum;
                    889:        mdb = (HFSMasterDirectoryBlock *) lowMemParamBlock->ioBuffer;                   //      �� figure out how we use VolumeHeader & MasterDirectoryBlock, size of structures, etc.  
                    890:        
                    891:        err = ValidMasterDirectoryBlock( mdb );                                                         //      is this an HFS/HFS PlusDisk
                    892:        if ( err == noErr )
                    893:        {
                    894:                err = notARemountErr;                                                                                   //      cuz we're looking for remounts only here
                    895:                vcbQHdr = LMGetVCBQHdr();                                                                               //      search the queue of VCBs
                    896:                
                    897:                //      CheckRemountLoop:
                    898:                for ( vcb = (ExtendedVCB*)vcbQHdr->qHead ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink )        //      search the queue of VCBs
                    899:                {
                    900:                        if (   (vcb->vcbDrvNum  == 0)                                                           //      matching volume better be off-line (0 drive num)
                    901:                                && (vcb->vcbSigWord     == mdb->drSigWord)                                      //      Same signature?
                    902:                                && (vcb->vcbCrDate      == mdb->drCrDate)                                       //      Same create date?
                    903:                                && (vcb->vcbLsMod       == mdb->drLsMod)                                        //      Same mod date?
                    904:                           )
                    905:                        {
                    906:                                //      At this point, we're fairly certain that the two volumes are, in fact, the same,
                    907:                                //      but just to make sure (and avoid problems with stuck clocks), we'll compare the
                    908:                                //      volume names as well:
                    909:                                //��    Modify this call to use the extended VCB ascii name, not the Unicode name
                    910:                                if ( EqualString( vcb->vcbVN, mdb->drVN, true, true) )  //      caseSensitive, diacSensitive
                    911:                                        break;                                                                                          //      Remount
                    912:                        }
                    913:                }
                    914:                if ( vcb == nil ) goto RemountExit;
                    915:        
                    916:                //      We are now convinced that we have a remount.  We will rebuild the attributes
                    917:                //      byte, which is the only one that could have changed.  We'll also store the
                    918:                //      current drive number and driver refNum, and mark the volume dirty.
                    919:                //      Remount:
                    920:        
                    921:                ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode;                   //      Drive status!
                    922:                ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff;                  //      Clear status byte for return
                    923:                
                    924:                err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock );                             //      refnum and drivenum set up by read call
                    925:                
                    926:                //--    Now propagate the write protect status byte back to the vcb
                    927:                flagsP = ((Byte *)(&(vcb->vcbAtrb))) + 1;
                    928:                mdbFlagsP = ((Byte *)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
                    929:                *flagsP = *mdbFlagsP & kVolumeHardwareLockMask;
                    930: 
                    931:                vcb->vcbDrvNum  = driveNumber;
                    932:                vcb->vcbDRefNum = ioRefNum;                                                                             //      Driver RefNum
                    933:                
                    934:                #if ( hasHFSManualEject )
                    935:                        SetVCBManEject(vcb);
                    936:                #endif
                    937:                
                    938:                if ( !(*flagsP & kVolumeHardwareLockMask) )                                             //      if bit is NOT set
                    939:                {
                    940:                        vcb->vcbAtrb &= ~kVolumeUnmountedMask;                                          //      clear the kVolumeUnmounted attribute
                    941:                        MarkVCBDirty( vcb );
                    942:                        err = FlushVolumeControlBlock( vcb );                                           //      Go flush the VCB info BEFORE close
                    943:                }
                    944:                
                    945:                err = noErr;
                    946:        }
                    947: 
                    948: 
                    949: RemountExit:
                    950:        if ( err == noErr )
                    951:                goto CmdDone;                                                                                                   //      noErr implies a successful remount                      
                    952:                
                    953:        //--    if we are allowing new mounts, let the ROM handle the details.  Otherwise, let the error stand
                    954:        fsVars = (FSVarsRec*)LMGetFSMVars();                                                            //      $BB8
                    955:        if ( fsVars->fsFlags & fsNoAllocateMask )
                    956:                goto CmdDone;
                    957:                
                    958:        //�� This sets the word to -1, Asm only set the byte to -1
                    959:        LMSetNewMount( -1 );                                                                                            //      assume now that it's a new volume
                    960:        
                    961:        
                    962:        
                    963:        //--    First see if the disk is already mounted.
                    964: mv_Start:
                    965:        err = paramErr;
                    966:        driveNumber = lowMemParamBlock->ioVRefNum;
                    967:        if ( driveNumber <= 0 )
                    968:                goto MtVolDone;
                    969:        
                    970:        err = GetVCBDriveNum( &vcb, driveNumber );
                    971:        if ( err == noErr )
                    972:        {
                    973:                if ( vcb->vcbDrvNum != 0 )
                    974:                {
                    975:                        err = volOnLinErr;
                    976:                        goto MtVolDone;
                    977:                }
                    978:        }
                    979:        
                    980:        //--    Find the appropriate drive queue entry and allocate a VCB.
                    981:        err = FindDrive( &ioRefNum, &dqe, driveNumber );
                    982:        if ( err != noErr ) goto MtVolDone;
                    983:        
                    984:        vcb = (ExtendedVCB *) NewPtrSysClear( sizeof( ExtendedVCB ) );
                    985: 
                    986:        if ( vcb == nil ) goto MtVolDone;                                                                       //      exit if we got no memory
                    987:        
                    988:        AddVCB( vcb, driveNumber, ioRefNum );                                                           //      prep the VCB for cache calls
                    989: 
                    990:        //--    Now try reading in the master directory block.
                    991:        err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, vcb->vcbVRefNum, vcb );    //      no Flags, MDB is always block #2, vcb->vcbBufAdr == CacheQueueHeader
                    992:        if ( err != noErr )     goto MtVolEr2;                                                                  //      Quit & Release VCB on errors
                    993:        
                    994:        //--    Now check what manner of animal we have before us:
                    995:        err = RelBlock_glue( (Ptr)mdb, rbTrashMask );
                    996:        
                    997:        err = ValidMasterDirectoryBlock( mdb );
                    998:        if ( err != noErr )
                    999:        {
                   1000:                if ( err == noMacDskErr )
                   1001:                        goto MtVolEr2;
                   1002:                else
                   1003:                        goto MtVolEr1;
                   1004:        }
                   1005:        
                   1006:        //      The MDB seems OK: transfer all master directory info from buffer into VCB.
                   1007:        
                   1008:        //      vcbSigWord is the start of duplicate mdb/vcb info. Asm VCBDInfoSt Equ 8
                   1009:        //      copy all fields in mdb till the drVolBkUp field
                   1010:        
                   1011:        BlockMoveData( mdb, &(vcb->vcbSigWord),  (Size)(&(mdb->drVolBkUp)) - (Size)mdb );
                   1012: 
                   1013:        //      Initialize our dirID/nodePtr cache associated with this volume.
                   1014:        err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
                   1015:        ReturnIfError( err );
                   1016: 
                   1017:        //-- Some fields, vcbNmAlBlks, vcbAlBlkSiz, and vcbFreeBks are just around for API compatability.
                   1018:        //-- The HFS/HFS Plus code we will use the corresponding ExtendedVCB fields. vcbNmAlBlks * vcbAlBlkSiz
                   1019:        //-- still gives correct volume size.
                   1020:        vcb->totalBlocks        =       vcb->vcbNmAlBlks;
                   1021:        vcb->freeBlocks         =       vcb->vcbFreeBks;
                   1022:        vcb->blockSize          =       vcb->vcbAlBlkSiz;
                   1023: 
                   1024:        
                   1025:        currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead;                        //      current request
                   1026:        currentIORequestPB->ioVRefNum = vcb->vcbVRefNum;                                                        //      return volume refnum to user
                   1027:        
                   1028:        lowMemParamBlock = (IOParam *) LMParamBlock;
                   1029:        ((CntrlParam*)lowMemParamBlock)->csCode = drvStsCode;                                           //      drive status!
                   1030:        ((CntrlParam*)lowMemParamBlock)->csParam[1] &= 0x00ff;                                          //      Clear status byte for return
                   1031:        
                   1032:        err = PBStatusSync( (ParmBlkPtr)lowMemParamBlock );
                   1033:        
                   1034:        flagsP = ((Byte *)(&(vcb->vcbAtrb))) + 1;
                   1035:        mdbFlagsP = ((Byte *)(((CntrlParam*)lowMemParamBlock)->csParam)+2);
                   1036:        *flagsP = *mdbFlagsP & kVolumeHardwareLockMask;
                   1037:        
                   1038:        if ( IsARamDiskDriver() )
                   1039:        {
                   1040:                vcb->vcbAtrb |= kVolumeNoCacheRequiredMask;                                                             //      yes:�mark VCB as a RAM Disk
                   1041:        }
                   1042:        
                   1043:        //--    copy all fields in mdb between drXTFlSize & drVolBkUp
                   1044:        BlockMoveData( &(mdb->drVolBkUp), &(vcb->vcbVolBkUp), (Size)&(mdb->drXTFlSize) - (Size)&(mdb->drVolBkUp) ); //  66 bytes
                   1045:        
                   1046:        vcb->vcbXTAlBlks = DivUp( mdb->drXTFlSize, vcb->blockSize );                            //      Pick up PEOF of extent B*-Tree
                   1047:        vcb->vcbCTAlBlks = DivUp( mdb->drCTFlSize, vcb->blockSize );                            //      Pick up PEOF of catalog B*-Tree
                   1048:        
                   1049:                                                                                                                                                                //      ��� WHY ARE WE RESTARTING THE ROAVING PTR
                   1050:        vcb->nextAllocation                             =       mdb->drAllocPtr;
                   1051:        vcb->vcbAllocPtr = 0;                                                                                                           //      Restart the roving allocation ptr
                   1052:        vcb->vcbWrCnt++;                                                                                                                        //      Compensate for write of MDB on last flush
                   1053:        
                   1054:        
                   1055:        //--    Try to find two free FCBs for use by the volume control B*-Trees:
                   1056:        
                   1057:        //--    Set up the Extent FCB
                   1058:        err = FindFileControlBlock( &fcbIndexP, &fcbsP );
                   1059:        if ( err != noErr )     goto MtVolErr;
                   1060:        
                   1061:        fcb = GetFileControlBlock( fcbIndexP );
                   1062:        fcb->fcbEOF = mdb->drXTFlSize;                                                                                          //      Set catalog tree's LEOF
                   1063:        fcb->fcbPLen = mdb->drXTFlSize;                                                                                         //      Set catalog tree's PEOF
                   1064: 
                   1065:        vcb->extentsRefNum              = fcbIndexP;                                                                            //      Set Extents B*-Tree file RefNum
                   1066:        BlockMoveData( mdb->drXTExtRec, fcb->fcbExtRec, sizeof(HFSExtentRecord) );
                   1067:        
                   1068:        
                   1069:        //--    Set up the Catalog FCB
                   1070:        err = FindFileControlBlock( &fcbIndexP, &fcbsP );
                   1071:        if ( err != noErr )     goto MtVolErr;
                   1072:        
                   1073:        fcb = GetFileControlBlock( fcbIndexP );
                   1074:        fcb->fcbEOF = mdb->drCTFlSize;                                                          //      Set catalog tree's LEOF
                   1075:        fcb->fcbPLen = mdb->drCTFlSize;                                                         //      Set catalog tree's PEOF
                   1076: 
                   1077:        vcb->catalogRefNum              = fcbIndexP;                                                                            //      Set Catalog B*-Tree file RefNum
                   1078:        BlockMoveData( mdb->drCTExtRec, fcb->fcbExtRec, sizeof(HFSExtentRecord) );
                   1079:        
                   1080:        
                   1081:        vcb->vcbMAdr    = (Ptr)*(long *)SysBMCPtr;                                      //      Set up the volume bitmap cache
                   1082:        vcb->vcbCtlBuf  = (Ptr)*(long *)SysCtlCPtr;                                     //      Set up the volume control cache
                   1083:        
                   1084: 
                   1085:        //--    Finish setting up the FCBs for the extent B*-Tree and the catalog B*-Tree:
                   1086: 
                   1087:        err = AccessBTree( vcb, vcb->extentsRefNum, kHFSExtentsFileID, vcb->vcbXTClpSiz, (void *) CompareExtentKeys );
                   1088:        if ( err != noErr )     goto MtChkErr;
                   1089:        
                   1090:        err = AccessBTree( vcb, vcb->catalogRefNum, kHFSCatalogFileID, vcb->vcbCTClpSiz, (void *) CompareCatalogKeys );
                   1091:        if ( err != noErr )     goto MtChkErr;
                   1092: 
                   1093:        err = CreateVolumeCatalogCache(vcb);
                   1094:        if ( err )      goto MtChkErr;
                   1095: 
                   1096:        if ( !(vcb->vcbAtrb & (short)kVolumeUnmountedMask) )
                   1097:        {
                   1098:                UInt32          consistencyStatus;
                   1099: 
                   1100:                vcb->vcbAtrb &= ~kVolumeUnmountedMask;                                  //      From now until _Unmount (clear the bit)
                   1101:                *(Ptr)FSCallAsync = 0;
                   1102:                err = MountCheck( vcb, &consistencyStatus );
                   1103:                if ( err )      goto MtChkErr;
                   1104:        }
                   1105:        else
                   1106:        {
                   1107:                vcb->vcbAtrb &= ~kVolumeUnmountedMask;                                  //      From now until _Unmount (clear the bit)
                   1108:        }
                   1109: 
                   1110: CheckRemount:
                   1111: 
                   1112:        //      ��This comment was in TFSVol.a, should look into it
                   1113:        //      Deleted stuff patched out by KillCheckRemountNiceWay in FileMgrPatches.a <SM1>
                   1114: 
                   1115: 
                   1116: MtVolOK:
                   1117:        err = noErr;
                   1118: 
                   1119: MtVolDone:
                   1120:        if ( err == noErr )
                   1121:        {
                   1122:                if ( !(vcb->vcbAtrb & kVolumeHardwareLockMask) )                //      if the disk is not write protected
                   1123:                {
                   1124:                        MarkVCBDirty( vcb );                                                            //      mark VCB dirty so it will be written
                   1125:                        err = FlushVolumeControlBlock( vcb );                           //      Go flush the VCB info BEFORE close
                   1126:                }
                   1127:        }
                   1128:        goto    CmdDone;
                   1129: 
                   1130: 
                   1131: 
                   1132: MtChkErr:
                   1133:        (void) DisposeVolumeCatalogCache(vcb);
                   1134:        InvalidateCatalogCache( vcb );
                   1135: 
                   1136: 
                   1137:        *((OSErr *)HFSDSErr) = err;
                   1138:        err = badMDBErr;
                   1139:        
                   1140:        //--    Release any resources allocated so far before exiting with an error:
                   1141: MtVolErr:
                   1142:        DisposeFileControlBlocks( vcb );                                                        //      deallocate control file FCBs
                   1143:        
                   1144: MtVolEr1:
                   1145:        DisposeVolumeCacheBlocks( vcb );                                                        //      invalidate any cache blocks for this volume
                   1146:        
                   1147: MtVolEr2:
                   1148:        if ( (Byte)LMGetNewMount() == 0 )                                                       //      only deallocate VCB for new mounts
                   1149:        {
                   1150:                //              Remount case -- Must zero buffer and map ptrs in old VCB.
                   1151:                //              Restore VCB to its original off-line state (ie clear VCBDrvNum,
                   1152:                //              and move drive number to VCBDRefNum field)
                   1153:                vcb->vcbDRefNum = vcb->vcbDrvNum;                                               //      write drv number to VCBDRefNum field
                   1154:                vcb->vcbDRefNum = 0;                                                                    //      clear drive number field of VCB
                   1155:                vcb->vcbMAdr    = nil;                                                                  //      clear mapptr in VCB
                   1156:                vcb->vcbBufAdr  = nil;                                                                  //      clear buffptr in VCB
                   1157:        }
                   1158:        else
                   1159:        {
                   1160:                DisposeVolumeControlBlock( vcb );
                   1161:        }
                   1162: 
                   1163:        if ( err <= 0 )
                   1164:                goto CmdDone;
                   1165:        currentIORequestPB = (IOParam *) ((QHdr *)LMGetFSQHdr())->qHead;
                   1166:        goto mv_Start;  
                   1167: 
                   1168: CmdDone:
                   1169:        return( err );
                   1170: 
                   1171: }
                   1172: #endif /* TARGET_OS_MAC */
                   1173: 
                   1174: 
                   1175: #if TARGET_OS_MAC
                   1176: //�������������������������������������������������������������������������������
                   1177: //     Routine:        UnMountVolume
                   1178: //
                   1179: //     Function:       All files on the volume in the drive are closed and any changed
                   1180: //                             directory information is written out to the diskette.  Memory
                   1181: //                             for the VCB, volume buffer, and block map is deallocated.
                   1182: //
                   1183: //�������������������������������������������������������������������������������
                   1184: 
                   1185: OSErr  UnMountVolume( VolumeParam *volume, WDCBRecPtr *wdcb )
                   1186: {
                   1187:        FCB                                             *fcb;
                   1188:        OSErr                                   err;
                   1189:        SInt16                                  nameLength;
                   1190:        Boolean                                 nameSpecified;
                   1191:        ExtendedVCB                             *vcb;
                   1192:        unsigned char                   *pathName;
                   1193:        UInt16                                  index;
                   1194:        Ptr                                             fcbs;
                   1195:        Boolean                                 doneSearching;
                   1196:        Boolean                                 isHFSPlus;
                   1197:        FSSpec                                  spec;
                   1198:        UInt16                                  driveNumber;
                   1199:        HFSMasterDirectoryBlock *mdb;
                   1200:        Boolean                                 mustRenameWrapperVolume = false;
                   1201: 
                   1202:        LMSetFlushOnly( 0 );                                                                            //      Setup same as UnmountVol
                   1203:        err = DeturmineVolume3( volume, &nameLength, &nameSpecified, &vcb, wdcb, &pathName );
                   1204:        if ( err != noErr )
                   1205:                goto CmdDone;
                   1206:                
                   1207:        isHFSPlus       = ( vcb->vcbSigWord == kHFSPlusSigWord );
                   1208:        
                   1209:        //--    Get the volume name from the catalog file to set in the HFS wrapper later
                   1210:        if ( (isHFSPlus) && (vcb->vcbDrvNum != 0) )                                     //      HFS+ volume and on-line
                   1211:        {
                   1212:                UInt32                                  hint;
                   1213:                CatalogNodeData                 nodeData;
                   1214:                
                   1215:                err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint );
                   1216:                if ( err == noErr )
                   1217:                {
                   1218:                        err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, vcb->vcbVRefNum, vcb );    //      Read the MDB
                   1219:                        if ( err == noErr )
                   1220:                        {
                   1221:                                if ( mdb->drSigWord == kHFSSigWord )                    //      it's a wrapped volume
                   1222:                                {
                   1223:                                        if ( memcmp( spec.name, mdb->drVN, spec.name[0]+1 ) != 0 )      //      Has the name changed?
                   1224:                                        {
                   1225:                                                driveNumber = vcb->vcbDrvNum;
                   1226:                                                mustRenameWrapperVolume = true;
                   1227:                                        }
                   1228:                                }
                   1229:                                err = RelBlock_glue( (Ptr)mdb, rbTrashMask );
                   1230:                        }
                   1231:                }
                   1232:        }
                   1233:        
                   1234:        //      Initialize fcbs pointer
                   1235:        Get1stFileControlBlock( &index, &fcbs );
                   1236: 
                   1237:        if ( !(volume->ioTrap & kHFSMask) )                                                     //      if NOT Unconditional unmount?
                   1238:        {
                   1239:                //--    Search the FCB array for open files that reference the volume...
                   1240:                do
                   1241:                {
                   1242:                        fcb = GetFileControlBlock( index );
                   1243:                        if ( (fcb->fcbFlNm != 0) && (fcb->fcbVPtr == vcb) )     //      The file is currently open and on this volume
                   1244:                        {
                   1245:                                if ( fcb->fcbFlNm >= fsUsrCNID )                                //      is it a user file?
                   1246:                                {
                   1247:                                        //--    Found an open user file on the volume, so return a busy condition...
                   1248:                                        err = fBsyErr;
                   1249:                                        break;
                   1250:                                }
                   1251:                        }
                   1252:                        
                   1253:                        doneSearching = GetNextFileControlBlock( &index, fcbs );
                   1254:                        
                   1255:                } while ( !doneSearching );
                   1256:        }
                   1257:        
                   1258:        if ( err == noErr )
                   1259:        {
                   1260:                err = CheckExternalFileSystem( vcb );
                   1261:                if ( err == noErr )
                   1262:                {
                   1263:                        FlushVolume( vcb );
                   1264:                        //      Unmounting a TFS volume: close the volume control B*-Tree and use the
                   1265:                        //      volume buffer to write out the MDB
                   1266: 
                   1267:                        //      From UnmountForTheNineties in FileMgrPatches.a
                   1268:                        //      Here's the change:  we no longer check whether the volume is offline.  Instead we always
                   1269:                        //      go ahead and close the control files, since we no longer close them on _Offline or _Eject.
                   1270:        
                   1271:                        if ( vcb->vcbDrvNum != 0 )                                              //      Check drive number: vol. offline?
                   1272:                        {
                   1273:                                err = FlushVolumeBuffers( vcb );
                   1274:                                if ( err != noErr )
                   1275:                                        goto CmdDone;                                                   //      Punt on errors
                   1276:                        }
                   1277:                        else
                   1278:                        {
                   1279:                                //      here begins CloseControlFiles, which is derived from FlushBuffers
                   1280:                                //      Now we have to close the control files because we no longer close them 
                   1281:                                //      in Eject and Offline
                   1282:                                
                   1283:                                if ( LMGetFlushOnly() == 0 )                            //      volume needs flushing
                   1284:                                {
                   1285:                                        err = CloseFile( vcb, vcb->catalogRefNum, fcbs );
                   1286:                                        if ( err != noErr )
                   1287:                                                goto CmdDone;                                           //      Punt on errors
                   1288:                                        
                   1289:                                        err = CloseFile( vcb, vcb->extentsRefNum, fcbs );
                   1290:                                        if ( err != noErr )
                   1291:                                                goto CmdDone;                                           //      Punt on errors
                   1292:                                                
                   1293:                                        if ( isHFSPlus )
                   1294:                                        {
                   1295:                                                err = AttributesCloseVolume( vcb );
                   1296:                                                if ( err != noErr )
                   1297:                                                        goto CmdDone;
                   1298: 
                   1299:                                                err = CloseFile( vcb, vcb->allocationsRefNum, fcbs );
                   1300:                                                if ( err != noErr )
                   1301:                                                        goto CmdDone;
                   1302:                                        }
                   1303: 
                   1304:                                        (void) DisposeMRUCache(vcb->hintCachePtr);
                   1305:                                        (void) DisposeVolumeCatalogCache(vcb);
                   1306:                                        InvalidateCatalogCache( vcb );
                   1307:                                        DisposeVolumeCacheBlocks( vcb );
                   1308:                                }
                   1309:                        }
                   1310: 
                   1311:                        if ( LMGetFlushOnly() == 0 )                                    //      volume needs flushing
                   1312:                        {
                   1313:                                //      For UnMountVol, dequeue the VCB and trash any WDCBs for this volume ...
                   1314:                                DisposeVolumeControlBlock( vcb );
                   1315:                        }
                   1316:                        
                   1317:                        //      The volume is now unmounted, if it's an HFS+ volume, and the name does not match what's
                   1318:                        //      in the MDB, mount the HFS wrapper rename the wrapper volume and unmount it.
                   1319:                        if ( mustRenameWrapperVolume )
                   1320:                        {
                   1321:                                RenameWrapperVolume( spec.name, driveNumber );
                   1322:                        }
                   1323:                        
                   1324:                        err = noErr;
                   1325:                }
                   1326:        }
                   1327: 
                   1328: CmdDone:
                   1329:        return( err );
                   1330: }
                   1331: #endif /* TARGET_OS_MAC */
                   1332: 
                   1333: 
                   1334: #if TARGET_OS_MAC
                   1335: //�������������������������������������������������������������������������������
                   1336: //     Routine:        RenameWrapperVolume     
                   1337: //
                   1338: //     Function:       Called during UnmountVolume if the HFS+ volume name does not
                   1339: //                             match the name stored in the wrapper MDB.  This function
                   1340: //                             renames the HFS wrapper volume.
                   1341: //
                   1342: //�������������������������������������������������������������������������������
                   1343: void   RenameWrapperVolume( Str27 newVolumeName, UInt16 driveNumber )
                   1344: {
                   1345:        VolumeParam             volume;
                   1346:        ExtendedVCB             *vcb;
                   1347:        OSErr                   err;
                   1348:        UInt32                  hint;
                   1349:        FSSpec                  spec;
                   1350:        CatalogNodeData nodeData;
                   1351:        Ptr                             pmsp;
                   1352:        UInt32                  modDate;
                   1353:        WDCBRecPtr              wdcbPtr;
                   1354:        
                   1355:        ClearMemory( &volume, sizeof(VolumeParam) );
                   1356:        volume.ioVRefNum        = driveNumber;
                   1357:        
                   1358:        err = MountVolume( &volume, true );
                   1359:        if ( err != noErr )
                   1360:                return;         // punt on errors
                   1361:        
                   1362:        err = GetVCBDriveNum( &vcb, driveNumber );
                   1363:        if ( err != noErr )
                   1364:                goto ErrorExit;         // punt on errors
                   1365: 
                   1366:        modDate = vcb->vcbLsMod;
                   1367:        
                   1368:        err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint );
                   1369:        if ( err != noErr )
                   1370:        {
                   1371:                #if DEBUG_BUILD
                   1372:                        DebugStr("\p GetCatalogNode failed");
                   1373:                #endif
                   1374:                goto ErrorExit;         // punt on errors
                   1375:        }
                   1376:        
                   1377:        err = RenameCatalogNode( vcb, kHFSRootParentID, spec.name, newVolumeName, hint, &hint );
                   1378:        if ( err != noErr )
                   1379:        {
                   1380:                #if DEBUG_BUILD
                   1381:                        DebugStr("\p RenameCatalogNode failed");
                   1382:                #endif
                   1383:                goto ErrorExit;         // punt on errors
                   1384:        }
                   1385: 
                   1386:        BlockMoveData( newVolumeName, vcb->vcbVN, sizeof(Str27) );
                   1387:        vcb->vcbLsMod   = modDate;
                   1388:        MarkVCBDirty( vcb );
                   1389: 
                   1390:        pmsp    = LMGetPMSPPtr();
                   1391:        *((short*)(pmsp + kPoorMansSearchIndex))        = 0;                    //      Invalidate Poor Mans search path
                   1392: 
                   1393: ErrorExit:
                   1394: 
                   1395:        (void) UnMountVolume( &volume, &wdcbPtr );
                   1396: }
                   1397: #endif /*TARGET_OS_MAC */
                   1398: 
                   1399: 
                   1400: #if TARGET_OS_MAC
                   1401: //�������������������������������������������������������������������������������
                   1402: //     Routine:        CheckExternalFileSystem         Asm: CkExtFS
                   1403: //
                   1404: //     Function:       Simple routine to separate out calls to be handled by an
                   1405: //                             external file system.
                   1406: //
                   1407: //�������������������������������������������������������������������������������
                   1408: OSErr  CheckExternalFileSystem( ExtendedVCB *vcb )
                   1409: {
                   1410:        if ( vcb->vcbFSID == 0 )
                   1411:        {
                   1412:                return( noErr );
                   1413:        }
                   1414:        else
                   1415:        {
                   1416:                return( extFSErr );
                   1417:        }
                   1418: }
                   1419: #endif /* TARGET_OS_MAC */
                   1420: 
                   1421: 
                   1422: 
                   1423: 
                   1424: //�������������������������������������������������������������������������������
                   1425: //     Routine:        CheckVolumeConsistancy
                   1426: //
                   1427: //     Function:       Check kBootVolumeInconsistentMask, and run MountCheck if necessary
                   1428: //�������������������������������������������������������������������������������
                   1429: OSErr  CheckVolumeConsistency( ExtendedVCB *vcb )
                   1430: {
                   1431:        UInt32          consistencyStatus;
                   1432:        OSErr           err     = noErr;
                   1433:                
                   1434: #if TARGET_OS_RHAPSODY
                   1435:        if ( vcb->vcbSigWord == kHFSSigWord)                                    //      and is an HFS disk
                   1436: #else  /* TARGET_OS_RHAPSODY */
                   1437:        if ( ( *((UInt16*)&(((ROMHeaderRec *) LMGetROMBase())->MachineNumber)) == 0x077D ) &&   //      is supermario based
                   1438:                 ( vcb->vcbSigWord == kHFSSigWord ) )                                   //      and is an HFS disk
                   1439: #endif         /* TARGET_OS_RHAPSODY */
                   1440:        {
                   1441:                if ( vcb->vcbAtrb & kHFSBootVolumeInconsistentMask )            //      was marked inconsistant
                   1442:                {
                   1443:                        err = MountCheck( vcb, &consistencyStatus );
                   1444:                        
                   1445:                        if ( err == noErr )
                   1446:                                vcb->vcbAtrb &= ~kHFSVolumeSoftwareLockMask;            //      clear the bit
                   1447:                }
                   1448: #if TARGET_OS_MAC
                   1449:                if ( LMGetBootDrive() == vcb->vcbDrvNum )                               //      this is the boot volume
                   1450:                        vcb->vcbAtrb |= kHFSBootVolumeInconsistentMask;
                   1451: #endif         /* TARGET_OS_MAC */
                   1452:        }
                   1453:        
                   1454:        return( err );
                   1455: }
                   1456: 
                   1457: 
                   1458: 
                   1459: 
                   1460: //�������������������������������������������������������������������������������
                   1461: //     Routine:        VolumeWritable          Asm: CVFlgs
                   1462: //
                   1463: //     Function:       Check the volume's flags to see if modify requests are allowed.
                   1464: //
                   1465: //�������������������������������������������������������������������������������
                   1466: OSErr  VolumeWritable( ExtendedVCB *vcb )
                   1467: {
                   1468:        if ( !(vcb->vcbAtrb & 0x8000) )         //      if the volume is not locked
                   1469:        {
                   1470:                if ( ! (*((Ptr)&(vcb->vcbAtrb) + 1) & kHFSVolumeHardwareLockMask) )     //      if it's not write protected
                   1471:                        return( noErr );
                   1472:                else
                   1473:                        return( wPrErr );
                   1474:        }
                   1475:        else
                   1476:        {
                   1477:                return( vLckdErr );
                   1478:        }
                   1479: }
                   1480: 
                   1481: 
                   1482: 
                   1483: 
                   1484: 
                   1485: #if TARGET_OS_MAC
                   1486: 
                   1487: //�������������������������������������������������������������������������������
                   1488: //     Routine:        FlushVolume             Asm: FlushVFiles
                   1489: //
                   1490: //     Function:       All file buffers on the volume are flushed and any changed
                   1491: //                             directory information is written out to the disk.
                   1492: //
                   1493: //�������������������������������������������������������������������������������
                   1494: OSErr  FlushVolume( ExtendedVCB *vcb )
                   1495: {
                   1496:        UInt16                  index;
                   1497:        Ptr                             fcbs;
                   1498:        FCB                             *fcb;
                   1499:        OSErr                   err;
                   1500:        Boolean                 doneSearching;
                   1501:        
                   1502:        Get1stFileControlBlock( &index, &fcbs );
                   1503: 
                   1504: //ckNxtFCB
                   1505:        err = noErr;
                   1506:        do
                   1507:        {
                   1508:                fcb = GetFileControlBlock( index );
                   1509:                if ( (fcb->fcbFlNm != 0) && (fcb->fcbVPtr == vcb) )     //      The file is currently open and on this volume
                   1510:                {
                   1511:                        if ( fcb->fcbFlNm >= fsUsrCNID )                                //      is it a user file?
                   1512:                        {
                   1513:                                //--    Found an open user file on the volume, so return a busy condition...
                   1514:                                err = CloseFile( vcb, index, fcbs );
                   1515:                                if ( err != noErr )
                   1516:                                        break;
                   1517:                        }
                   1518:                }
                   1519:                
                   1520:                doneSearching = GetNextFileControlBlock( &index, fcbs );
                   1521:                
                   1522:        } while ( !doneSearching );
                   1523:        
                   1524:        return( err );
                   1525: }
                   1526: 
                   1527: 
                   1528: 
                   1529: //�������������������������������������������������������������������������������
                   1530: //     Routine:        DisposeFileControlBlocks from Asm: DsposFCBs
                   1531: //
                   1532: //     Function:       Clears the extent B*-Tree refNum & catalog refnum
                   1533: //
                   1534: //�������������������������������������������������������������������������������
                   1535: void   DisposeFileControlBlocks( ExtendedVCB *vcb )
                   1536: {
                   1537:        OSErr   err;
                   1538:        
                   1539:        err = AttributesCloseVolume( vcb );
                   1540: #if DEBUG_BUILD
                   1541:        if ( err != noErr ) DebugStr("\pHFS+: Can't close Property Manager");
                   1542: #endif
                   1543: 
                   1544:        if ( vcb->extentsRefNum != 0 )
                   1545:        {
                   1546:                //--    Clear extent B*-Tree refNum file number in FCB as unused
                   1547:                ( (FCB *) ( LMGetFCBSPtr() + vcb->extentsRefNum ) )->fcbFlNm = 0L;
                   1548:        }
                   1549:        if ( vcb->catalogRefNum != 0 )
                   1550:        {
                   1551:                //--    Clear catalog refnum file number in FCB as unused
                   1552:                ( (FCB *) ( LMGetFCBSPtr() + vcb->catalogRefNum ) )->fcbFlNm = 0L;
                   1553:        }
                   1554:        
                   1555:        if ( vcb->vcbSigWord == kHFSPlusSigWord && vcb->allocationsRefNum != 0)
                   1556:        {
                   1557:                //--    Clear allocation (bitmap) file number in FCB as unused
                   1558:                ( (FCB *) ( LMGetFCBSPtr() + vcb->allocationsRefNum ) )->fcbFlNm = 0L;
                   1559:        }
                   1560: }
                   1561: 
                   1562: #endif /* TARGET_OS_MAC */
                   1563: 
                   1564: 
                   1565: //�������������������������������������������������������������������������������
                   1566: //     Routine:        AccessBTree from Asm: AccessBT
                   1567: //
                   1568: //     Function:       Create an access path for a B*-Tree file:
                   1569: //                             1. Initialize the FCB
                   1570: //                             2. Attach a B*-Tree control block
                   1571: //
                   1572: //     Note:           For now the compare proc is the entry to the assembly glue calling a C compare function.
                   1573: //                             Once BTOpen is ported to C, we can pass in C comparison routines.
                   1574: //
                   1575: //     Result:         I/O result from BTOpen
                   1576: //�������������������������������������������������������������������������������
                   1577: #if TARGET_OS_MAC
                   1578: OSErr  AccessBTree( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize, void *CompareRoutine )
                   1579: {
                   1580:        FCB                             *fcb;
                   1581:        OSErr                   err;
                   1582: 
                   1583:        fcb = SetupFCB( vcb, refNum, fileID, fileClumpSize );
                   1584:        
                   1585:        err = OpenBTree( refNum, CompareRoutine );
                   1586:        
                   1587:        return( err );
                   1588: }
                   1589: #endif /* TARGET_OS_MAC */
                   1590: 
                   1591: //�������������������������������������������������������������������������������
                   1592: //     Routine:        SetupFCB fills in the FCB info
                   1593: //
                   1594: //     Returns:        The filled up FCB
                   1595: //�������������������������������������������������������������������������������
                   1596: #if TARGET_OS_MAC
                   1597: FCB    *SetupFCB( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize )
                   1598: {
                   1599:        FCB                             *fcb;
                   1600: 
                   1601:        fcb = (FCB *) GetFileControlBlock( refNum );
                   1602:        
                   1603:        fcb->fcbFlags           = 0;
                   1604:        fcb->fcbSBlk            = 0;
                   1605:        fcb->fcbCrPs            = 0;
                   1606:        fcb->fcbFlNm            = fileID;
                   1607:        fcb->fcbVPtr            = vcb;
                   1608:        fcb->fcbClmpSize        = fileClumpSize;
                   1609:        
                   1610:        // for debugging...     
                   1611:        switch (fileID)
                   1612:        {
                   1613:                case kHFSExtentsFileID:
                   1614:                        BlockMoveData( "\p**** EXTENTS B-TREE", fcb->fcbCName, sizeof("\p**** EXTENTS B-TREE") );
                   1615:                        break;
                   1616:                case kHFSCatalogFileID:
                   1617:                        BlockMoveData( "\p**** CATALOG B-TREE", fcb->fcbCName, sizeof("\p**** CATALOG B-TREE") );
                   1618:                        break;
                   1619:                case kHFSAllocationFileID:
                   1620:                        BlockMoveData( "\p**** VOLUME BITMAP", fcb->fcbCName,  sizeof("\p**** VOLUME BITMAP") );
                   1621:                        break;
                   1622:                case kHFSAttributesFileID:
                   1623:                        BlockMoveData( "\p**** ATTRIBUTES B-TREE", fcb->fcbCName,  sizeof("\p**** ATTRIBUTES B-TREE") );
                   1624:                        break;
                   1625:        }
                   1626:        
                   1627:        return( fcb );
                   1628: }
                   1629: #endif /* TARGET_OS_MAC */
                   1630: 
                   1631: 
                   1632: #if TARGET_OS_MAC
                   1633: 
                   1634: //�������������������������������������������������������������������������������
                   1635: //     Routine:        FindFileControlBlock from Asm: FindFCB
                   1636: //
                   1637: //     Function:       Find an unused FCB
                   1638: //
                   1639: //     Result:         error
                   1640: //�������������������������������������������������������������������������������
                   1641: OSErr  FindFileControlBlock( UInt16 *index, Ptr *fcbsH )
                   1642: {
                   1643:        Boolean                 doneSearching;
                   1644:        OSErr                   err;
                   1645:        FCB                             *fcb;
                   1646:        
                   1647:        Get1stFileControlBlock( index, fcbsH );
                   1648:        
                   1649:        do
                   1650:        {
                   1651:                doneSearching = GetNextFileControlBlock( index, *fcbsH );
                   1652:                if ( doneSearching == false )
                   1653:                {
                   1654:                        fcb = GetFileControlBlock( *index );
                   1655:                        if ( fcb->fcbFlNm == 0 )                                                                                //      FCB unused?
                   1656:                        {
                   1657:                                ClearMemory( fcb, sizeof( FCB ) );
                   1658:                                fcb->fcbFlNm = -1;                                                                                      //      Mark it in use
                   1659:                                err = noErr;
                   1660:                                doneSearching = true;
                   1661:                        }
                   1662:                }
                   1663:                else
                   1664:                {
                   1665:                        err = tmfoErr;
                   1666:                }
                   1667:        }       while ( doneSearching == false );
                   1668:        
                   1669:        return( err );
                   1670: }
                   1671: 
                   1672: 
                   1673: //�������������������������������������������������������������������������������
                   1674: //     Routine:        Get1stFileControlBlock from Asm: Gt1stFCB
                   1675: //
                   1676: //     Function:       Point to the first FCB
                   1677: //�������������������������������������������������������������������������������
                   1678: void   Get1stFileControlBlock( UInt16 *index, Ptr *fcbsH )
                   1679: {
                   1680:        //              struct FCBSRec {
                   1681:        //                      UInt16                                  length;                                                         //      first word is FCB part length
                   1682:        //                      FCB                                             fcb[1];                                                         //      fcb array
                   1683:        //              };
                   1684:        *fcbsH = LMGetFCBSPtr();
                   1685:        *index = 2;
                   1686: }
                   1687: 
                   1688: 
                   1689: //�������������������������������������������������������������������������������
                   1690: //     Routine:        GetNextFileControlBlock from Asm: GtNxtFCB
                   1691: //
                   1692: //     Function:       Increment to the next FCB
                   1693: //                                     Check if we've hit the end fcb yet
                   1694: //
                   1695: //     Result:         Return true if end was reached
                   1696: //�������������������������������������������������������������������������������
                   1697: Boolean        GetNextFileControlBlock( UInt16 *index, Ptr fcbsP )
                   1698: {
                   1699: 
                   1700:        *index += LMGetFSFCBLen();
                   1701:         
                   1702:        return ( *index == *((UInt16 *)fcbsP) );                                                                        //      first word is length
                   1703: }
                   1704: 
                   1705: #endif /* TARGET_OS_MAC */
                   1706: 
                   1707: 
                   1708: //�������������������������������������������������������������������������������
                   1709: //     Routine:        DivUp from Asm: DivUp
                   1710: //
                   1711: //     Function:       Given a number of bytes and block size, calculate the number of
                   1712: //                             blocks needd to hold all the bytes.
                   1713: //
                   1714: //     Result:         Number of physical blocks needed
                   1715: //�������������������������������������������������������������������������������
                   1716: UInt16 DivUp( UInt32 byteRun, UInt32 blockSize )
                   1717: {
                   1718:        UInt32  blocks;
                   1719:        
                   1720:        blocks = (byteRun + blockSize - 1) / blockSize;                                                 //      Divide up, remember this is integer math.
                   1721:        
                   1722:        if ( blocks > 0xffff )                                                                                                  //      maximum 16 bit value
                   1723:                blocks = 0xffff;
                   1724:                
                   1725:        return( (UInt16) blocks );
                   1726: }
                   1727: 
                   1728: 
                   1729: 
                   1730: 
                   1731: //�������������������������������������������������������������������������������
                   1732: //     Routine:        HFSBlocksFromTotalSectors
                   1733: //
                   1734: //     Function:       Given the total number of sectors on the volume, calculate
                   1735: //                             the 16Bit number of allocation blocks, and allocation block size.
                   1736: //
                   1737: //     Result:         none
                   1738: //�������������������������������������������������������������������������������
                   1739: void   HFSBlocksFromTotalSectors( UInt32 totalSectors, UInt32 *blockSize, UInt16 *blockCount )
                   1740: {
                   1741:        UInt16  newBlockSizeInSectors   = 1;
                   1742:        UInt32  newBlockCount                   = totalSectors;
                   1743:        
                   1744:        while ( newBlockCount > 0XFFFF )
                   1745:        {
                   1746:                newBlockSizeInSectors++;
                   1747:                newBlockCount   =  totalSectors / newBlockSizeInSectors;
                   1748:        }
                   1749:        
                   1750:        *blockSize      = newBlockSizeInSectors * 512;
                   1751:        *blockCount     = newBlockCount;
                   1752: }
                   1753: 
                   1754: 
                   1755: 
                   1756: 
                   1757: //�������������������������������������������������������������������������������
                   1758: //     Routine:        ValidMasterDirectoryBlock
                   1759: //
                   1760: //     Function:       Run some sanity checks to make sure the MDB is valid
                   1761: //
                   1762: //     Result:         error
                   1763: //�������������������������������������������������������������������������������
                   1764: OSErr  ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb )
                   1765: {
                   1766:        OSErr   err;
                   1767:        
                   1768:        if ( (mdb->drSigWord == kHFSPlusSigWord) || (mdb->drSigWord == kHFSSigWord) )   //      if HFS or HFS Plus volume
                   1769:        {
                   1770:                if ( (mdb->drAlBlkSiz != 0) && ((mdb->drAlBlkSiz & 0x01FF) == 0) )                      //      non zero multiple of 512
                   1771:                        err = noErr;
                   1772:                else
                   1773:                        err = badMDBErr;
                   1774:        }
                   1775:        else
                   1776:        {
                   1777:                err = noMacDskErr;
                   1778:        }
                   1779:        
                   1780:        return( err );
                   1781: }
                   1782: 
                   1783: 
                   1784: //�������������������������������������������������������������������������������
                   1785: //     Routine:        ValidVolumeHeader
                   1786: //
                   1787: //     Function:       Run some sanity checks to make sure the VolumeHeader is valid
                   1788: //
                   1789: //     Result:         error
                   1790: //�������������������������������������������������������������������������������
                   1791: OSErr  ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader )
                   1792: {
                   1793:        OSErr   err;
                   1794:        
                   1795:        if ( volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion )
                   1796:        {
                   1797:                if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) )                      //      non zero multiple of 512
                   1798:                        err = noErr;
                   1799:                else
                   1800:                        err = badMDBErr;                                                                        //��    I want badVolumeHeaderErr in Errors.i
                   1801:        }
                   1802:        else
                   1803:        {
                   1804:                err = noMacDskErr;
                   1805:        }
                   1806:        
                   1807:        return( err );
                   1808: }
                   1809: 
                   1810: 
                   1811: #if TARGET_OS_MAC
                   1812: 
                   1813: //�������������������������������������������������������������������������������
                   1814: //     Routine:        FindDrive from Asm: FindDrive
                   1815: //
                   1816: //     Function:       Given a drive number, this routine returns the RefNum
                   1817: //                             for the driver by searching the system drive queue.
                   1818: //
                   1819: //     Result:         error
                   1820: //�������������������������������������������������������������������������������
                   1821: OSErr  FindDrive( short *driverRefNum, DrvQEl **dqe, short driveNumber )
                   1822: {
                   1823:        OSErr   err             =       nsDrvErr;                                               //      initialize as "drive not found"
                   1824:        
                   1825:        *dqe = ((DrvQEl*)LMGetDrvQHdr()->qHead);                        //      get first DQE
                   1826:        while ( *dqe != 0 )                                                                     //      end of list?
                   1827:        {
                   1828:                if ( (**dqe).dQDrive != driveNumber )                   //      find the drive we're looking for?
                   1829:                {
                   1830:                        *dqe = (DrvQEl*)(**dqe).qLink;                          //      get ptr to next
                   1831:                }
                   1832:                else
                   1833:                {
                   1834:                        *driverRefNum = (**dqe).dQRefNum;                       //      return driver refnum
                   1835:                        if ( (**dqe).dQFSID == 0 )                                      //      is this a Mac Filesystem?
                   1836:                                err = noErr;
                   1837:                        else
                   1838:                                err = extFSErr;                                                 //      no, return error
                   1839:                        break;
                   1840:                }
                   1841:        }
                   1842:        
                   1843:        return( err );
                   1844: }
                   1845: 
                   1846: 
                   1847: //�������������������������������������������������������������������������������
                   1848: //     Routine:        GetVCBDriveNum from Asm: GetVCBDrv
                   1849: //
                   1850: //     Function:       Determine VCB from DriveNum/VRefNum field
                   1851: //
                   1852: //     Result:         error
                   1853: //�������������������������������������������������������������������������������
                   1854: OSErr  GetVCBDriveNum( ExtendedVCB **vcbResult, short driveNumber )
                   1855: {
                   1856:        ExtendedVCB     *vcb;
                   1857:        
                   1858:        for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink )     //      search the queue of VCBs
                   1859:        {
                   1860:                if ( vcb->vcbDrvNum == driveNumber )                                    //      success!
                   1861:                        break;
                   1862:                if ( vcb->vcbDrvNum == 0 )                                                              //      offline
                   1863:                {
                   1864:                        if ( vcb->vcbDRefNum == driveNumber * (-1) )            //      offline match
                   1865:                                break;
                   1866:                }
                   1867:        }
                   1868:        
                   1869:        *vcbResult = vcb;
                   1870: 
                   1871:        if ( vcb == nil )
                   1872:                return( nsvErr );
                   1873:        else
                   1874:                return( noErr );
                   1875:  }
                   1876: 
                   1877: 
                   1878: //�������������������������������������������������������������������������������
                   1879: //     Routine:        GetVCBRefNum from Asm: GetVCBRfn
                   1880: //
                   1881: //     Function:       Determine VCB from DriveNum/VRefNum field
                   1882: //
                   1883: //     Result:         error
                   1884: //�������������������������������������������������������������������������������
                   1885: OSErr  GetVCBRefNum( ExtendedVCB **vcbResult, short vRefNum )
                   1886: {
                   1887:        ExtendedVCB     *vcb;
                   1888:        
                   1889:        for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink )     //      search the queue of VCBs
                   1890:        {
                   1891:                if ( vcb->vcbVRefNum == vRefNum )                               //      success!
                   1892:                {
                   1893:                        *vcbResult = vcb;
                   1894:                        return( noErr );
                   1895:                }
                   1896:        }
                   1897:        
                   1898:        return( nsvErr );
                   1899: }
                   1900: 
                   1901: #endif /* TARGET_OS_MAC */
                   1902: 
                   1903: 
                   1904: //�������������������������������������������������������������������������������
                   1905: //     Routine:        IsARamDiskDriver from Asm: IsRAMDiskDriver
                   1906: //
                   1907: //     Function:       Test if disk driver is a RAM disk
                   1908: //
                   1909: //     Result:         true if RAM disk
                   1910: //�������������������������������������������������������������������������������
                   1911: Boolean        IsARamDiskDriver( void )
                   1912: {
                   1913: #if TARGET_OS_MAC
                   1914:        OSErr                   err;
                   1915:        ParamBlockRec   *pb;
                   1916:        Byte                    diskType;
                   1917:        
                   1918:        pb = (ParamBlockRec *) LMParamBlock;                                    //      general purpose I/O param block
                   1919:        pb->ioParam.ioCompletion        = 0;                                            //      no completion routine
                   1920:        pb->cntrlParam.csCode           = infoCC;                                       //      pass control code
                   1921:        pb->cntrlParam.csParam[0]       = 0;                                            //      start out clean
                   1922:        pb->cntrlParam.csParam[1]       = 0;
                   1923:        
                   1924:        err = PBControlSync( pb );                                                              //      get driver info�
                   1925:        
                   1926:        if ( err == noErr )                                                                             //      this control call supported
                   1927:        {
                   1928:                diskType = ((Byte *)(pb->cntrlParam.csParam))[3];
                   1929:                if ( (diskType == ramDiskType) || (diskType == romDiskType) )
                   1930:                        return( true );
                   1931:        }
                   1932:        
                   1933:        return( false );
                   1934: #else
                   1935:        return( false );
                   1936: #endif         /* TARGET_OS_MAC */
                   1937: }
                   1938: 
                   1939: 
                   1940: #if TARGET_OS_MAC
                   1941: 
                   1942: OSErr  MakeVCBsExtendedVCBs( void )
                   1943: {
                   1944:        VCB                                             *oVCB;
                   1945:        VCB                                             *nextVCB;
                   1946:        ExtendedVCB                             *exVCB;
                   1947:        ExtendedVCB                             *firstNewVCBInQueue     = nil;
                   1948:        QHdr                                    *vcbQHdr;
                   1949:        UInt16                                  fcbIndex;
                   1950:        UInt16                                  i;
                   1951:        Ptr                                             fcbs;
                   1952:        FCB                                             *fcb;
                   1953:        WDCBArray                               *wdcbsAry;
                   1954:        OSErr                                   err;
                   1955:                
                   1956:        vcbQHdr = LMGetVCBQHdr();                                                                                       //      search the queue of VCBs
                   1957: 
                   1958:        for ( oVCB = (VCB *)vcbQHdr->qHead ; (oVCB != nil) && (oVCB != (VCB *)firstNewVCBInQueue) ; )
                   1959:        {
                   1960:                nextVCB = (VCB *) oVCB->qLink;
                   1961:                
                   1962:                if ( (oVCB->vcbSigWord != kHFSPlusSigWord) && (oVCB->vcbFSID == 0) )    //      if it's an HFS Plus VCB, assume it is already of ExtendedVCB type
                   1963:                {
                   1964:                        exVCB = (ExtendedVCB *) NewPtrSysClear( sizeof(ExtendedVCB) );  //      allocate space for the new ExtendedVCB
                   1965:                        ReturnIfError( MemError() );
                   1966:                        BlockMoveData( oVCB, exVCB, sizeof(VCB) );                                              //      copy the original VCB over
                   1967:                        
                   1968:                        if ( firstNewVCBInQueue == nil )
                   1969:                                firstNewVCBInQueue = exVCB;
                   1970:                        
                   1971:                        //--    Set up the Extended fields, used internally in the HFS source
                   1972:                        exVCB->totalBlocks              =       exVCB->vcbNmAlBlks;
                   1973:                        exVCB->freeBlocks               =       exVCB->vcbFreeBks;
                   1974:                        exVCB->blockSize                =       exVCB->vcbAlBlkSiz;
                   1975:                        exVCB->nextAllocation   =       (UInt16)exVCB->vcbAllocPtr;                     //      Almost certain to be zero
                   1976:                        // Note: SuperMario ROMs clear vcbAllocPtr and then flush the MDB.
                   1977:                        // So, when an HFS disk gets mounted, the allocation pointer is cleared both in
                   1978:                        // memory and on disk.  The only way to fix this is to put HFS Plus in ROM.
                   1979: 
                   1980:                        //--    Set up the caches for this volume
                   1981:                        err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(exVCB->hintCachePtr) );
                   1982:                        ReturnIfError( err );
                   1983:                        
                   1984:                        err = CreateVolumeCatalogCache(exVCB);
                   1985:                        ReturnIfError( err );
                   1986:                        
                   1987:                        //--    If we are dealing with the default VCB, set the corresponding ExtendedVCB as the default
                   1988:                        if ( oVCB == (VCB*) LMGetDefVCBPtr() )
                   1989:                                LMSetDefVCBPtr( (Ptr) exVCB );
                   1990:                        
                   1991:                        //--    Remove and deallocate the original VCB
                   1992:                        err = Dequeue( (QElemPtr) oVCB, (QHdrPtr) vcbQHdr );                    //      Dequeue the VCB from the VCB Queue
                   1993:                        ReturnIfError( err );
                   1994:                        
                   1995:                        //--    Search the FCB list for refs to the old VCB pointer and update them
                   1996:                        Get1stFileControlBlock( &fcbIndex, &fcbs );
                   1997:                        do
                   1998:                        {
                   1999:                                fcb = GetFileControlBlock( fcbIndex );
                   2000:                                if ( fcb->fcbVPtr == (ExtendedVCB *) oVCB )     
                   2001:                                        fcb->fcbVPtr = exVCB;
                   2002:                        } while ( GetNextFileControlBlock( &fcbIndex, fcbs ) == false );//      while there's still some left
                   2003:                        
                   2004:                        //--    Search the WDCB list for refs to the old VCB pointer and update them
                   2005:                        wdcbsAry = (WDCBArray*)LMGetWDCBsPtr();                                                 //      Point to WDCB array
                   2006:                        for ( i=0 ; i< (wdcbsAry->count / sizeof(WDCBRec)) ; i++ )
                   2007:                        {
                   2008:                                if ( wdcbsAry->wdcb[i].wdVCBPtr == oVCB )
                   2009:                                        wdcbsAry->wdcb[i].wdVCBPtr = (VCB *) exVCB;
                   2010:                        }
                   2011:                        
                   2012:                        //--    Deallocate memory used by the old VCB
                   2013:                        DisposePtr( (Ptr) oVCB );
                   2014: 
                   2015:                        //--    Insert the new extended vcb in the queue
                   2016:                        Enqueue( (QElemPtr) exVCB, (QHdrPtr) vcbQHdr );
                   2017:                }
                   2018:                oVCB = nextVCB;
                   2019:        }
                   2020:        
                   2021:        return( noErr );
                   2022: }
                   2023: 
                   2024: 
                   2025: //�������������������������������������������������������������������������������
                   2026: //     Routine:        RemountWrappedVolumes
                   2027: //
                   2028: //     Function:       Called by InitHFSPlus, Attempt to re-mount all HFS+ volumes
                   2029: //                             previously mounted as HFS wrappers.
                   2030: //
                   2031: //     Note:           This routine assumes vcbEmbedSigWord is cleared during mount.
                   2032: //
                   2033: //�������������������������������������������������������������������������������
                   2034: extern void    RemountWrappedVolumes( void )
                   2035: {
                   2036:        ExtendedVCB             *vcb;
                   2037:        ExtendedVCB             *nextVCB;
                   2038:        OSErr                   err;
                   2039: 
                   2040:        for ( vcb = (ExtendedVCB *) ((QHdr*)LMGetVCBQHdr())->qHead ; vcb != nil ; )
                   2041:        {
                   2042:                //      PBMountVol and UnmountVol modify the vcb queue, so save the link
                   2043:                nextVCB = (ExtendedVCB *) vcb->qLink;
                   2044: 
                   2045:                if ( (vcb->vcbEmbedSigWord == kHFSPlusSigWord) && ( vcb->vcbFSID == 0) )
                   2046:                {       
                   2047:                        err = UnmountVol( nil, vcb->vcbVRefNum );
                   2048:                        if ( err == noErr )
                   2049:                        {
                   2050:                                ParamBlockRec theParam;
                   2051:                                
                   2052:                                theParam.ioParam.ioCompletion   = nil;
                   2053:                                theParam.ioParam.ioNamePtr              = nil;
                   2054:                                theParam.ioParam.ioVRefNum              = vcb->vcbDrvNum;
                   2055:                                (void) PBMountVol( &theParam );
                   2056:                        }
                   2057:                }
                   2058:                
                   2059:                vcb = nextVCB;
                   2060:        }
                   2061: }
                   2062: 
                   2063: 
                   2064: //�������������������������������������������������������������������������������
                   2065: //     Routine:        FillHFSStack
                   2066: //
                   2067: //     Function:       Called by HFSInit.  Fills the newly created HFS stack so we 
                   2068: //                             can identify how much of the stack is actually being used.
                   2069: //
                   2070: //�������������������������������������������������������������������������������
                   2071: extern void    FillHFSStack( void )
                   2072: {
                   2073:        Ptr             p;
                   2074:        SInt16  len             =       0;
                   2075:        char    *s              =       "HFS+ By Don Brady, Mark Day, and Deric Horn.   ";
                   2076:        
                   2077:        while ( s[len] != '\0' )
                   2078:                ++len;
                   2079:                
                   2080:        for ( p = LMGetHFSStkTop() - kFileSystemStackSize ; p + len < LMGetHFSStkTop() ; p += len )
                   2081:        {
                   2082:                BlockMoveData( s, p, len );
                   2083:        }
                   2084: }
                   2085: 
                   2086: 
                   2087: //�������������������������������������������������������������������������������
                   2088: //     Routine:        CheckVolumeOffLine from Asm: ExtOffLinCk
                   2089: //
                   2090: //     Function:       Simple routine to separate out calls to be handled by an
                   2091: //                             external file system.
                   2092: //
                   2093: //     Result:         noErr if we handle it
                   2094: //�������������������������������������������������������������������������������
                   2095: //�� Same function appears in CatSearch.c as ExtOffLineCheck(), but the code is slightly different
                   2096: //�� we should delete one copy.
                   2097: OSErr  CheckVolumeOffLine( ExtendedVCB *vcb )
                   2098: {
                   2099:        OSErr           err;
                   2100:        
                   2101:        err = CheckExternalFileSystem( vcb );
                   2102:        if ( err == noErr && vcb->vcbDrvNum == 0 )
                   2103:                err = volOffLinErr;
                   2104:        
                   2105:        LMSetReqstVol( (Ptr)vcb );
                   2106:        
                   2107:        return( err );
                   2108: }
                   2109: 
                   2110: #endif /* TARGET_OS_MAC */
                   2111: 
                   2112: 
                   2113: 
                   2114: 
                   2115: //_______________________________________________________________________
                   2116: //
                   2117: //     Routine:        CountRootFiles
                   2118: //
                   2119: //     Input:          pointer to VCB
                   2120: //
                   2121: //     Function:       Return a count of the number of files and folders in
                   2122: //                             the root directory of a volume.  For HFS volumes, this
                   2123: //                             is maintained in the VCB (and MDB).  For HFS Plus volumes,
                   2124: //                             we get the valence of the root directory from its catalog
                   2125: //                             record.
                   2126: //_______________________________________________________________________
                   2127: UInt16 CountRootFiles(ExtendedVCB *vcb)
                   2128: {
                   2129:        OSErr                   err;
                   2130:        FSSpec                  spec;
                   2131:        CatalogNodeData catNodeData;
                   2132:        UInt32                  hint;
                   2133:        UInt16                  rootCount;
                   2134:        
                   2135: //     if (vcb->vcbSigWord == kHFSSigWord || vcb->vcbFSID != 0) {
                   2136: //             return vcb->vcbNmFls;
                   2137: //     }
                   2138:        
                   2139:        //      Here, it's an HFS Plus volume, so get the valence from the root
                   2140:        //      directory's catalog record.
                   2141:        
                   2142:        rootCount = 0;
                   2143:        
                   2144:        err = GetCatalogNode( vcb, kHFSRootFolderID, nil, kNoHint, &spec, &catNodeData, &hint );
                   2145:        if ( err == noErr ) {
                   2146:                if (catNodeData.valence < 65536)
                   2147:                        rootCount = catNodeData.valence;
                   2148:                else
                   2149:                        rootCount = 65535;                      //      if the value is too large, pin it
                   2150:        }
                   2151: 
                   2152:        return rootCount;
                   2153: }
                   2154: 
                   2155: #if TARGET_OS_MAC
                   2156: 
                   2157: //_______________________________________________________________________
                   2158: //
                   2159: //     Routine:        GetVolumeInformation    :       GetVolInfo
                   2160: //     Arguments:      HVolumeParam    *volume
                   2161: //     Output:         WDCBRec                 **wdcb          (Needed for ExtFsHook in CmdDone)
                   2162: //                             OSErr                   err
                   2163: //
                   2164: //     Function:       Return information about the volume in a mounted drive.
                   2165: //                             If the IOVolIndex field is 0, the name of the default
                   2166: //                             volume is returned; if non-zero, the name of the nth
                   2167: //                             mounted volume is returned. The maximum length of a
                   2168: //                             volume name is 27 bytes.  The drive number for the
                   2169: //                             volume is also returned.
                   2170: //_______________________________________________________________________
                   2171: 
                   2172: OSErr  GetVolumeInformation( HVolumeParam *volume, WDCBRecPtr *wdcb )
                   2173: {
                   2174:        FSSpec                  spec;
                   2175:        UInt32                  maxBlocks;
                   2176:        SInt16                  nameLength;
                   2177:        SInt16                  volumeIndex;
                   2178:        FileReference                   vRefNum;
                   2179:        OSErr                   err;
                   2180:        Ptr                             fcbs;
                   2181:        FCB                             *fcb;
                   2182:        ExtendedVCB             *vcb;
                   2183:        unsigned char   *pathName;
                   2184:        CatalogNodeData catNodeData;
                   2185:        Boolean                 doneSearching;
                   2186:        Boolean                 nameSpecified;
                   2187:        WDCBArray               *wdcbsAry;
                   2188:        UInt16                  fcbIndex;
                   2189: 
                   2190:        volumeIndex = volume->ioVolIndex;
                   2191:        if ( volumeIndex == 0 )
                   2192:        {
                   2193:                err = DeturmineVolume1( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
                   2194:                if ( err != noErr )     goto CmdDone;
                   2195:        }
                   2196:        else if ( volume->ioVolIndex < 0 )
                   2197:        {
                   2198:                err = DeturmineVolume3( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
                   2199:                if ( err != noErr )     goto CmdDone;
                   2200:        }
                   2201:        else
                   2202:        {
                   2203:                nameSpecified = false;                                          //      Never any name specified (ioNamePtr is output arg)
                   2204:                volume->ioVRefNum = 0;
                   2205: 
                   2206:                for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink )     //      search the queue of VCBs
                   2207:                {
                   2208:                        if ( --volumeIndex == 0 )
                   2209:                                break;
                   2210:                }
                   2211:                if ( vcb == nil )
                   2212:                {
                   2213:                        err = nsvErr;
                   2214:                        goto CmdDone;
                   2215:                }
                   2216:        }
                   2217: 
                   2218:        //      first copy the heart of the VCB into the parameter block
                   2219:        volume->ioVCrDate       =       vcb->vcbCrDate;
                   2220:        volume->ioVLsMod        =       vcb->vcbLsMod;
                   2221:        volume->ioVAtrb         =       vcb->vcbAtrb;
                   2222:        volume->ioVNmFls        =       vcb->vcbNmFls;                          // don't call CountRootFiles(vcb) anymore
                   2223:        volume->ioVBitMap       =       vcb->vcbVBMSt;
                   2224:        volume->ioVNmAlBlks     =       vcb->vcbNmAlBlks;                       //      we return the HFS volume format equivalents cuz ioVNmAlBlks is a short
                   2225:        volume->ioVAlBlkSiz     =       vcb->vcbAlBlkSiz;
                   2226:        volume->ioVClpSiz       =       vcb->vcbClpSiz;
                   2227:        volume->ioAlBlSt        =       vcb->vcbAlBlSt;
                   2228:        volume->ioVNxtCNID      =       vcb->vcbNxtCNID;
                   2229:        volume->ioVFrBlk        =       vcb->vcbFreeBks;
                   2230:        
                   2231:        if ( vcb->vcbFSID != 0 )
                   2232:                volume->ioAllocPtr      =       vcb->vcbAllocPtr;               // external file system
                   2233:        else if ( vcb->nextAllocation < 0xFFFF )
                   2234:                volume->ioAllocPtr      =       vcb->nextAllocation;
                   2235:        else
                   2236:                volume->ioAllocPtr      =       0xFFFF;
                   2237:        
                   2238: 
                   2239:        Get1stFileControlBlock( &fcbIndex, &fcbs );
                   2240:        doneSearching           =       false;
                   2241: 
                   2242:        do
                   2243:        {
                   2244:                fcb = GetFileControlBlock( fcbIndex );
                   2245:                if ( fcb->fcbVPtr == (ExtendedVCB *) vcb )              //      The file is currently open and on this volume
                   2246:                {
                   2247:                        if ( fcb->fcbFlNm >= fsUsrCNID )
                   2248:                                break;
                   2249:                }
                   2250:                doneSearching = GetNextFileControlBlock( &fcbIndex, fcbs );
                   2251:        } while ( doneSearching == false );
                   2252:        
                   2253:        if ( doneSearching == true )
                   2254:                volume->ioVAtrb         &=      ~kFilesOpenMask;                //      Clear if no open files match
                   2255:        else
                   2256:                volume->ioVAtrb         |=      kFilesOpenMask;                 //      Set if any files are opened
                   2257: 
                   2258:        if ( vcb == (ExtendedVCB *) LMGetDefVCBPtr() )          //      Are we supposedly the default?
                   2259:                volume->ioVAtrb         |=      kDefaultVolumeMask;             //      Set volume as the default
                   2260:        else
                   2261:                volume->ioVAtrb         &=      ~kDefaultVolumeMask;    //      Clear volume as the default
                   2262:        
                   2263:        *wdcb = nil;
                   2264:        
                   2265:        if ( (volume->ioVolIndex <= 0) && (nameSpecified == 0) )
                   2266:        {
                   2267:                vRefNum = volume->ioVRefNum;
                   2268:                if ( vRefNum > 0 )                                                              //      If driveNum, ignore it
                   2269:                {
                   2270:                        goto    retVRef;
                   2271:                }
                   2272:                else if ( vRefNum == 0 )
                   2273:                {
                   2274:                        vRefNum = 2;
                   2275:                }
                   2276:                else if ( vRefNum <= WDRfnMax )
                   2277:                {
                   2278:                        //      a WDRefNum was supplied as VRefNum: change the number of files to be the                <21Sep85>
                   2279:                        //      valence of the directory in question:                                                                           <21Sep85>
                   2280:                        vRefNum -= WDRfnMin;                                    //      Change WDRefNum to index
                   2281:                }
                   2282:                else
                   2283:                {
                   2284:                        goto retVRef;
                   2285:                }
                   2286:                
                   2287:                wdcbsAry = (WDCBArray*)LMGetWDCBsPtr();                                                 //      Point to WDCB array
                   2288:                *wdcb = (WDCBRec*)((Ptr)wdcbsAry + vRefNum);
                   2289: 
                   2290:                err = CheckVolumeOffLine( vcb );                        //      check external FS err
                   2291:                if ( err == noErr )
                   2292:                {
                   2293:                        if ( (**wdcb).wdDirID != fsRtDirID )
                   2294:                        {
                   2295:                                //��    This will change to handle Don's meta struct
                   2296:                                err = GetCatalogNode( (ExtendedVCB*)vcb, (**wdcb).wdDirID, nil, (**wdcb).wdCatHint, &spec, &catNodeData, (UInt32*)&((**wdcb).wdCatHint) );
                   2297:                                if ( err == noErr )
                   2298:                                {
                   2299:                                        volume->ioVNmFls = (UInt16) catNodeData.valence;
                   2300:                                }
                   2301:                        }
                   2302:                }
                   2303:        }
                   2304:        
                   2305:        //      Do some hairy checking: if a working directory was specified, it shouldn't
                   2306:        //      be overwritten by the volRefNum.        However, if a volume NAME was used, the
                   2307:        //      volRefNum field is ignored, and SHOULD be filled in with the volume's VRefNum.
                   2308: retVRef:
                   2309:        if( (nameSpecified != 0) || (volume->ioVRefNum >= 0) )
                   2310:        {
                   2311:                volume->ioVRefNum = vcb->vcbVRefNum;
                   2312:        }
                   2313:        //      Copy the volume name field if specified.
                   2314:        if ( volume->ioNamePtr != 0 )
                   2315:                BlockMoveData( vcb->vcbVN, volume->ioNamePtr, vcb->vcbVN[0]+1 );
                   2316: 
                   2317: 
                   2318:        //      Many applications call GetVolInfo for preflighting when saving files. However,
                   2319:        //      they tend to use signed integers when calculating the volume's free space
                   2320:        //      (vcbFreeBlks * vcbAlBlkSize).  If the free space is greater than 2 gigabytes they
                   2321:        //      get a negative result and think there is not enough space left on the volume.
                   2322:        //      
                   2323:        //      To fix this problem we high water mark vcbFreeBlks and vcbNmAlBlks so that when
                   2324:        //      multiplied by vcbAlBlkSiz the result is always less than or equal to 2GB.
                   2325: 
                   2326:        if ( volume->ioVAlBlkSiz > 0x8000 )                     //      Do the mock up
                   2327:        {
                   2328:                //      Calculate the maximum number of allocation blocks that can fit within 2 gigabytes�                                                                                      <LgVol>
                   2329:                //      Divide 2 gig by block allocation size
                   2330:                maxBlocks = 0x7FFFFFFF / volume->ioVAlBlkSiz;
                   2331:                
                   2332:                //      Clip total and free to the maximum�     
                   2333:                if ( volume->ioVNmAlBlks > maxBlocks )
                   2334:                {
                   2335:                        volume->ioVNmAlBlks = maxBlocks;                //      pin the value limit
                   2336:                        
                   2337:                        if ( volume->ioVFrBlk > maxBlocks )
                   2338:                        {
                   2339:                                volume->ioVFrBlk = maxBlocks;
                   2340:                        }
                   2341:                }
                   2342:        }
                   2343:        
                   2344:        //      Subtract the physical sizes of the extent B*-Tree and the catalog B*-Tree <21Sep85>
                   2345:        //      from the volume size, so that the difference between the volume size and        <21Sep85>
                   2346:        //      the free space reflects only the user's allocations:                      <21Sep85>
                   2347:        volume->ioVNmAlBlks     -= vcb->vcbXTAlBlks;            //      Take out XT allocation
                   2348:        volume->ioVNmAlBlks     -= vcb->vcbCTAlBlks;            //      Take out CT allocation
                   2349:        
                   2350:        if ( !(volume->ioTrap & kHFSMask) )             //      TFGetVolInfo vs. plain GetVolInfo?
                   2351:        {                                                                               //      GetVolInfo
                   2352:                if ( volume->ioVNmAlBlks > kMaxHFSAllocationBlocks )
                   2353:                        volume->ioVNmAlBlks = kMaxHFSAllocationBlocks;
                   2354:                
                   2355:                if ( volume->ioVFrBlk > kMaxHFSAllocationBlocks )
                   2356:                        volume->ioVFrBlk = kMaxHFSAllocationBlocks;
                   2357:        }
                   2358:        else            //      Return some additional information for TGetVolInfo requests:
                   2359:        {
                   2360:                volume->ioVRefNum       =       vcb->vcbVRefNum;                //      ALWAYS return VRefNum
                   2361:                volume->ioVDrvInfo      =       vcb->vcbDrvNum;                 //      Driver number
                   2362:                volume->ioVDRefNum      =       vcb->vcbDRefNum;                //      Driver RefNum
                   2363:                volume->ioVFSID         =       vcb->vcbFSID;                   //      File System ID
                   2364:                
                   2365:                //      We return  kHFSSigWord for HFS+ volumes for copatability with
                   2366:                //      existing applications.  All StuffIt products, AppleShare, FileSharing,
                   2367:                //      and others incorrectly assume the volume is unsupported or MFS if the
                   2368:                //      sigWord is not 'BD'. GetXVolInfo() returns the "real" value.
                   2369:                volume->ioVSigWord      = vcb->vcbSigWord == kHFSPlusSigWord ? kHFSSigWord : vcb->vcbSigWord;
                   2370:                
                   2371:                
                   2372: //volume->ioVFilCnt    =       0;                                      //      Clear
                   2373: //volume->ioVFilCnt    =       vcb->vcbNmFls;          //      Stuff low word as if MFS
                   2374:                
                   2375:                volume->ioVBkUp         =       vcb->vcbVolBkUp;        //      Last backup date
                   2376:                volume->ioVSeqNum       =       vcb->vcbVSeqNum;        //      Volume sequence number
                   2377:                volume->ioVWrCnt        =       vcb->vcbWrCnt;          //      Volume write count
                   2378:                volume->ioVFilCnt       =       vcb->vcbFilCnt;         //      Files count for volume
                   2379:                volume->ioVDirCnt       =       vcb->vcbDirCnt;         //      Directory count for volume
                   2380: 
                   2381:                BlockMoveData( vcb->vcbFndrInfo, volume->ioVFndrInfo, sizeof( SInt32 ) * 8 );
                   2382:        }
                   2383: 
                   2384: GVIDone:
                   2385:        LMSetReqstVol( (Ptr)vcb );
                   2386: 
                   2387:        err = CheckExternalFileSystem( vcb );
                   2388:        
                   2389: CmdDone:
                   2390:        return( err );
                   2391: 
                   2392: }
                   2393: 
                   2394: 
                   2395: 
                   2396: 
                   2397: //_______________________________________________________________________
                   2398: //
                   2399: //     Routine:        GetXVolumeInformation   :       GetXVolInfo
                   2400: //     Arguments:      XVolumeParam    *volume
                   2401: //     Output:         WDCBRecPtr              *wdcb           (Needed for ExtFsHook in CmdDone)
                   2402: //                             OSErr                   err
                   2403: //
                   2404: //     Function:       Return information about the volume in a mounted drive.
                   2405: //                             If the IOVolIndex field is 0, the name of the default
                   2406: //                             volume is returned; if non-zero, the name of the nth
                   2407: //                             mounted volume is returned. The maximum length of a
                   2408: //                             volume name is 27 bytes.  The drive number for the
                   2409: //                             volume is also returned.
                   2410: //_______________________________________________________________________
                   2411: 
                   2412: OSErr  GetXVolumeInformation( XVolumeParam *volume, WDCBRecPtr *wdcb )
                   2413: {
                   2414:        FSSpec                  spec;
                   2415:        SInt16                  nameLength;
                   2416:        SInt16                  volumeIndex;
                   2417:        FileReference                   vRefNum;
                   2418:        OSErr                   err;
                   2419:        Ptr                             fcbs;
                   2420:        FCB                             *fcb;
                   2421:        ExtendedVCB             *vcb;
                   2422:        unsigned char   *pathName;
                   2423:        CatalogNodeData catNodeData;
                   2424:        Boolean                 doneSearching;
                   2425:        Boolean                 nameSpecified;
                   2426:        WDCBArray               *wdcbsAry;
                   2427:        UInt16                  fcbIndex;
                   2428: 
                   2429: // The Installer doesn't setup ioXVersion (radar #1666217)
                   2430: #if 0
                   2431:        if (volume->ioXVersion != 0)
                   2432:                return paramErr;
                   2433: #endif
                   2434: 
                   2435:        err = noErr;            //      Assume things will work
                   2436:        
                   2437:        volumeIndex = volume->ioVolIndex;
                   2438:        if ( volumeIndex == 0 )
                   2439:        {
                   2440:                err = DeturmineVolume1( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
                   2441:                if ( err != noErr )     goto CmdDone;
                   2442:        }
                   2443:        else if ( volume->ioVolIndex < 0 )
                   2444:        {
                   2445:                err = DeturmineVolume3( (VolumeParam*)volume, &nameLength, &nameSpecified, (ExtendedVCB **)&vcb, wdcb, &pathName );
                   2446:                if ( err != noErr )     goto CmdDone;
                   2447:        }
                   2448:        else
                   2449:        {
                   2450:                nameSpecified = false;                                          //      Never any name specified (ioNamePtr is output arg)
                   2451:                volume->ioVRefNum = 0;
                   2452: 
                   2453:                for ( vcb = (ExtendedVCB*)((LMGetVCBQHdr())->qHead) ; vcb != nil ; vcb = (ExtendedVCB*)vcb->qLink )     //      search the queue of VCBs
                   2454:                {
                   2455:                        if ( --volumeIndex == 0 )
                   2456:                                break;
                   2457:                }
                   2458:                if ( vcb == nil )
                   2459:                {
                   2460:                        err = nsvErr;
                   2461:                        goto CmdDone;
                   2462:                }
                   2463:        }
                   2464: 
                   2465:        //      first copy the heart of the VCB into the parameter block
                   2466:        volume->ioVCrDate       =       vcb->vcbCrDate;
                   2467:        volume->ioVLsMod        =       vcb->vcbLsMod;
                   2468:        volume->ioVAtrb         =       vcb->vcbAtrb;
                   2469:        volume->ioVBitMap       =       vcb->vcbVBMSt;
                   2470:        volume->ioVNmAlBlks     =       vcb->vcbNmAlBlks;                       //      16 bit value
                   2471:        volume->ioVClpSiz       =       vcb->vcbClpSiz;
                   2472:        volume->ioAlBlSt        =       vcb->vcbAlBlSt;
                   2473:        volume->ioVNxtCNID      =       vcb->vcbNxtCNID;
                   2474:        volume->ioVFrBlk        =       vcb->vcbFreeBks;
                   2475:        volume->ioVNmFls        =       vcb->vcbNmFls;                          // don't call CountRootFiles(vcb) anymore
                   2476: 
                   2477:        if ( vcb->vcbFSID == 0 )        // an HFS or HFS Plus disk
                   2478:        {
                   2479:                volume->ioVAlBlkSiz     = vcb->blockSize;                       //      return true allocation blocks
                   2480: 
                   2481:                if ( vcb->nextAllocation < 0xFFFF )
                   2482:                        volume->ioAllocPtr      =       vcb->nextAllocation;
                   2483:                else
                   2484:                        volume->ioAllocPtr      =       0xFFFF;
                   2485:        }
                   2486:        else    //      an external file system
                   2487:        {
                   2488:                volume->ioVAlBlkSiz     =       vcb->vcbAlBlkSiz;                       
                   2489:                volume->ioAllocPtr      =       vcb->vcbAllocPtr;
                   2490:        }
                   2491: 
                   2492: 
                   2493:        Get1stFileControlBlock( &fcbIndex, &fcbs );
                   2494:        doneSearching           =       false;
                   2495: 
                   2496:        do
                   2497:        {
                   2498:                fcb = GetFileControlBlock( fcbIndex );
                   2499:                if ( fcb->fcbVPtr == vcb )                                              //      The file is currently open and on this volume
                   2500:                {
                   2501:                        if ( fcb->fcbFlNm >= fsUsrCNID )
                   2502:                                break;
                   2503:                }
                   2504:                doneSearching = GetNextFileControlBlock( &fcbIndex, fcbs );
                   2505:        } while ( doneSearching == false );
                   2506:        
                   2507:        if ( doneSearching == true )
                   2508:                volume->ioVAtrb         &=      ~kFilesOpenMask;                //      Clear if no open files match
                   2509:        else
                   2510:                volume->ioVAtrb         |=      kFilesOpenMask;                 //      Set if any files are opened
                   2511: 
                   2512:        if ( vcb == (ExtendedVCB *) LMGetDefVCBPtr() )          //      Are we supposedly the default?
                   2513:                volume->ioVAtrb         |=      kDefaultVolumeMask;             //      Set volume as the default
                   2514:        else
                   2515:                volume->ioVAtrb         &=      ~kDefaultVolumeMask;    //      Clear volume as the default
                   2516:        
                   2517:        
                   2518:        *wdcb = nil;
                   2519:        
                   2520:        if ( (volume->ioVolIndex <= 0) && (nameSpecified == 0) )
                   2521:        {
                   2522:                vRefNum = volume->ioVRefNum;
                   2523:                if ( vRefNum > 0 )                                                              //      If driveNum, ignore it
                   2524:                {
                   2525:                        goto    retVRef;
                   2526:                }
                   2527:                else if ( vRefNum == 0 )
                   2528:                {
                   2529:                        vRefNum = 2;
                   2530:                }
                   2531:                else if ( vRefNum <= WDRfnMax )
                   2532:                {
                   2533:                        //      a WDRefNum was supplied as VRefNum: change the number of files to be the                <21Sep85>
                   2534:                        //      valence of the directory in question:                                                                           <21Sep85>
                   2535:                        vRefNum -= WDRfnMin;                                            //      Change WDRefNum to index
                   2536:                }
                   2537:                else
                   2538:                {
                   2539:                        goto retVRef;
                   2540:                }
                   2541:                
                   2542:                wdcbsAry = (WDCBArray*)LMGetWDCBsPtr();                 //      Point to WDCB array
                   2543:                *wdcb = (WDCBRec*)((Ptr)wdcbsAry + vRefNum);
                   2544: 
                   2545:                err = CheckVolumeOffLine( (ExtendedVCB*)vcb );                  //      check external FS err
                   2546:                if ( err == noErr )
                   2547:                {
                   2548:                        if ( (**wdcb).wdDirID != fsRtDirID )
                   2549:                        {
                   2550:                                //��    This will change to handle Don's meta struct
                   2551:                                err = GetCatalogNode( (ExtendedVCB*)vcb, (**wdcb).wdDirID, nil, (**wdcb).wdCatHint, &spec, &catNodeData, (UInt32*)&((**wdcb).wdCatHint) );
                   2552:                                if ( err == noErr )
                   2553:                                {
                   2554:                                        volume->ioVNmFls = (UInt16) catNodeData.valence;
                   2555:                                }
                   2556:                        }
                   2557:                }
                   2558:        }
                   2559:        
                   2560:        //      If a working directory was specified, it shouldn't be overwritten by
                   2561:        //      the volRefNum.  However, if a volume NAME was used, the volRefNum
                   2562:        //      field is ignored, and SHOULD be filled in with the volume's VRefNum.
                   2563: retVRef:
                   2564:        if( (nameSpecified != 0) || (volume->ioVRefNum >= 0) )
                   2565:        {
                   2566:                volume->ioVRefNum = vcb->vcbVRefNum;
                   2567:        }
                   2568:        //      Copy the volume name field if specified.
                   2569:        if ( volume->ioNamePtr != 0 )
                   2570:                BlockMoveData( vcb->vcbVN, volume->ioNamePtr, vcb->vcbVN[0]+1 );
                   2571: 
                   2572: 
                   2573:        //      Calculate the total and free bytes available on the volume as a 64 bit integer:
                   2574: 
                   2575:        if ( vcb->vcbSigWord == kHFSPlusSigWord )
                   2576:        {
                   2577:                //--    Change to use ExtendedVCB fields for HFS Plus
                   2578:                MultiplyUInt32IntoUInt64( &(volume->ioVTotalBytes), vcb->totalBlocks, vcb->blockSize );
                   2579:                MultiplyUInt32IntoUInt64( &(volume->ioVFreeBytes), vcb->freeBlocks, vcb->blockSize );
                   2580:        }
                   2581:        else
                   2582:        {
                   2583:                //--    It's just an HFS volume or some other external file system
                   2584:                MultiplyUInt32IntoUInt64( &(volume->ioVTotalBytes), volume->ioVNmAlBlks, volume->ioVAlBlkSiz );
                   2585:                MultiplyUInt32IntoUInt64( &(volume->ioVFreeBytes), volume->ioVFrBlk, volume->ioVAlBlkSiz );
                   2586:        }
                   2587:        
                   2588:        
                   2589:        volume->ioVRefNum       =       vcb->vcbVRefNum;                        //      VRefNum
                   2590:        volume->ioVSigWord      =       vcb->vcbSigWord;                        //      Volume signature
                   2591:        volume->ioVDrvInfo      =       vcb->vcbDrvNum;                         //      Driver number
                   2592:        volume->ioVDRefNum      =       vcb->vcbDRefNum;                        //      Driver RefNum
                   2593:        volume->ioVFSID         =       vcb->vcbFSID;                           //      File System ID
                   2594:        volume->ioVBkUp         =       vcb->vcbVolBkUp;                        //      Last backup date
                   2595:        volume->ioVSeqNum       =       vcb->vcbVSeqNum;                        //      Volume sequence number
                   2596:        volume->ioVWrCnt        =       vcb->vcbWrCnt;                          //      Volume write count
                   2597:        volume->ioVFilCnt       =       vcb->vcbFilCnt;                         //      Files count for volume
                   2598:        volume->ioVDirCnt       =       vcb->vcbDirCnt;                         //      Directory count for volume
                   2599: 
                   2600:        BlockMoveData( vcb->vcbFndrInfo, volume->ioVFndrInfo, sizeof( SInt32 ) * 8 );
                   2601: 
                   2602: CmdDone:
                   2603:        if ( err == noErr && volume->ioVFSID != 0)
                   2604:        {
                   2605:                LMSetReqstVol((Ptr) vcb);
                   2606:                err = extFSErr;         // not an HFS or HFS Plus volume, let others have a crack at this call...
                   2607:        }
                   2608: 
                   2609:        return( err );
                   2610: }
                   2611: 
                   2612: #endif /* TARGET_OS_MAC */
                   2613: 
                   2614: 
                   2615: //_______________________________________________________________________
                   2616: //
                   2617: //     Routine:        FlushVolumeControlBlock
                   2618: //     Arguments:      ExtendedVCB             *vcb
                   2619: //     Output:         OSErr                   err
                   2620: //
                   2621: //     Function:       Flush volume information to either the VolumeHeader of the Master Directory Block
                   2622: //_______________________________________________________________________
                   2623: 
                   2624: OSErr  FlushVolumeControlBlock( ExtendedVCB *vcb )
                   2625: {
                   2626:        OSErr                   err;
                   2627: #if TARGET_OS_MAC
                   2628:        HFSPlusVolumeHeader     *volumeHeader;
                   2629:        FileReference   index;
                   2630:        FCB                             *fcb;
                   2631:        ExtendedFCB             *extendedFCB;
                   2632: #endif 
                   2633:        if ( ! IsVCBDirty( vcb ) )                      //      if it's not dirty
                   2634:                return( noErr );
                   2635: 
                   2636:        if ( vcb->vcbSigWord == kHFSPlusSigWord )
                   2637:        {
                   2638: #if TARGET_OS_MAC
                   2639:                err = GetBlock_glue( gbDefault, (vcb->hfsPlusIOPosOffset / 512) + kIDSectorOffset, (Ptr*)&volumeHeader, vcb->vcbVRefNum, vcb ); //      no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
                   2640:                #if( DEBUG_BUILD )
                   2641:                        if ( volumeHeader->signature != vcb->vcbSigWord )
                   2642:                                DebugStr("\p Bad VolumeHeader, signature does not match vcb" );
                   2643:                #endif
                   2644:                ReturnIfError( err );
                   2645:                
                   2646:                //      2005507, Keep the MDB creation date and VolumeHeader creation date in sync.
                   2647:                if ( vcb->hfsPlusIOPosOffset != 0 )                                                             //      It's a wrapped HFS+ volume
                   2648:                {
                   2649:                        HFSMasterDirectoryBlock *mdb;
                   2650: 
                   2651:                        err = GetBlock_glue(    gbDefault,
                   2652:                                                kIDSectorOffset,
                   2653:                                                (Ptr*)&mdb,
                   2654:                                                vcb->vcbVRefNum,
                   2655:                                                vcb );
                   2656:                        if ( err == noErr )
                   2657:                        {
                   2658:                                if ( mdb->drCrDate      != vcb->vcbCrDate )                                     //      The creation date changed
                   2659:                                {
                   2660:                                        mdb->drCrDate   = vcb->vcbCrDate;
                   2661:                                        err = RelBlock_glue( (Ptr)mdb, rbWriteMask );           //      Force it to be written
                   2662:                                }
                   2663:                                else
                   2664:                                {
                   2665:                                        err = RelBlock_glue( (Ptr)mdb, rbFreeMask );            //      Just release it
                   2666:                                }
                   2667:                        }
                   2668:                }
                   2669: 
                   2670:        //      volumeHeader->signature                 =       vcb->signature;
                   2671:        //      volumeHeader->version                   =
                   2672:                volumeHeader->attributes                =       vcb->vcbAtrb;                           //      VCB uses 16 bits, next 16 are for future API changes
                   2673:                volumeHeader->lastMountedVersion=       kHFSPlusMountVersion;           //      Let others know we've mounted volume for writing
                   2674:        //��    volumeName
                   2675:                volumeHeader->createDate                =       vcb->vcbCrDate;                         //      NOTE: local time, not GMT!
                   2676:                volumeHeader->modifyDate                =       LocalToUTC(vcb->vcbLsMod);
                   2677:                volumeHeader->backupDate                =       LocalToUTC(vcb->vcbVolBkUp);
                   2678:                volumeHeader->checkedDate               =       vcb->checkedDate;
                   2679:                volumeHeader->fileCount                 =       vcb->vcbFilCnt;
                   2680:                volumeHeader->folderCount               =       vcb->vcbDirCnt;
                   2681:                volumeHeader->blockSize                 =       vcb->blockSize;
                   2682:                volumeHeader->totalBlocks               =       vcb->totalBlocks;
                   2683:                volumeHeader->freeBlocks                =       vcb->freeBlocks;
                   2684:                volumeHeader->nextAllocation    =       vcb->nextAllocation;
                   2685:                volumeHeader->rsrcClumpSize             =       vcb->vcbClpSiz;
                   2686:                volumeHeader->dataClumpSize             =       vcb->vcbClpSiz;
                   2687:                volumeHeader->nextCatalogID             =       vcb->vcbNxtCNID;
                   2688:                volumeHeader->writeCount                =       vcb->vcbWrCnt;
                   2689:                volumeHeader->encodingsBitmap   =       vcb->encodingsBitmap;
                   2690: 
                   2691:                //���should we use the vcb or fcb clumpSize values ????? -djb
                   2692:                volumeHeader->allocationFile.clumpSize  = vcb->allocationsClumpSize;
                   2693:                volumeHeader->extentsFile.clumpSize     = vcb->vcbXTClpSiz;
                   2694:                volumeHeader->catalogFile.clumpSize     = vcb->vcbCTClpSiz;
                   2695:                
                   2696:                BlockMoveData( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
                   2697:        
                   2698:                index = vcb->extentsRefNum;
                   2699:                extendedFCB = GetParallelFCB( index );
                   2700:                BlockMoveData( extendedFCB->extents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) );
                   2701:                fcb = GetFileControlBlock( index );
                   2702:                volumeHeader->extentsFile.logicalSize.lo = fcb->fcbEOF;
                   2703:                volumeHeader->extentsFile.logicalSize.hi = 0;
                   2704:                volumeHeader->extentsFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
                   2705:        
                   2706:                index = vcb->catalogRefNum;
                   2707:                extendedFCB = GetParallelFCB( index );
                   2708:                BlockMoveData( extendedFCB->extents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) );
                   2709:                fcb = GetFileControlBlock( index );
                   2710:                volumeHeader->catalogFile.logicalSize.lo = fcb->fcbPLen;
                   2711:                volumeHeader->catalogFile.logicalSize.hi = 0;
                   2712:                volumeHeader->catalogFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
                   2713: 
                   2714:                index = vcb->allocationsRefNum;
                   2715:                extendedFCB = GetParallelFCB( index );
                   2716:                BlockMoveData( extendedFCB->extents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) );
                   2717:                fcb = GetFileControlBlock( index );
                   2718:                volumeHeader->allocationFile.logicalSize.lo = fcb->fcbPLen;
                   2719:                volumeHeader->allocationFile.logicalSize.hi = 0;
                   2720:                volumeHeader->allocationFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
                   2721:        
                   2722:                index = vcb->attributesRefNum;
                   2723:                if (index != 0)         //      Only update fields if an attributes file existed and was open
                   2724:                {
                   2725:                        extendedFCB = GetParallelFCB( index );
                   2726:                        BlockMoveData( extendedFCB->extents, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) );
                   2727:                        fcb = GetFileControlBlock( index );
                   2728:                        volumeHeader->attributesFile.logicalSize.lo = fcb->fcbPLen;
                   2729:                        volumeHeader->attributesFile.logicalSize.hi = 0;
                   2730:                        volumeHeader->attributesFile.clumpSize = fcb->fcbClmpSize;
                   2731:                        volumeHeader->attributesFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
                   2732:                }
                   2733:                
                   2734:                //--    Write the MDB out by releasing the block dirty
                   2735:                
                   2736:                err = RelBlock_glue( (Ptr)volumeHeader, rbWriteMask );          //      force it to be written
                   2737:        
                   2738:                #if( hasHFSManualEject )
                   2739:                        // The critical volume info that needs to be maintained
                   2740:                        // for volumes in manual-eject drives has just been flushed.
                   2741:                        if (err == noErr)
                   2742:                                vcb->vcbFlags &= ~vcbFlushCriticalInfoMask;
                   2743:                #endif
                   2744:                
                   2745:                MarkVCBClean( vcb );
                   2746: #else
                   2747:                // This does now what above does also, so lets keep it all together in a single place
                   2748:         err = C_FlushMDB( vcb );               //      Go flush the VCB info BEFORE close
                   2749: #endif
                   2750:        }
                   2751:        else
                   2752:        {
                   2753:                // This routine doesn't really return an error!!!
                   2754:                // So for now, we will just return noErr
                   2755:                err = C_FlushMDB( vcb );                //      Go flush the VCB info BEFORE close
                   2756:                return( noErr );
                   2757:        }
                   2758: 
                   2759:        return( err );
                   2760: }
                   2761: 
                   2762: 
                   2763: ExtendedFCB* GetParallelFCB(FileReference fref)
                   2764: {
                   2765: #if TARGET_OS_MAC
                   2766:        ParallelFCB*    pfcbArray;
                   2767:        FSVarsRec*              fsVars;
                   2768:        short                   index;
                   2769: 
                   2770:        index = fref / sizeof(FCB);
                   2771:        
                   2772:        fsVars = (FSVarsRec*) LMGetFSMVars();
                   2773: 
                   2774:        pfcbArray = (ParallelFCB*) fsVars->fcbPBuf;
                   2775: 
                   2776:        return &pfcbArray->extendedFCB[index];
                   2777: #else
                   2778:        return &VTOH(fref)->h_xfcb->fcb_extFCB;
                   2779: #endif /* TARGET_OS_MAC */
                   2780: }
                   2781: 
                   2782: 
                   2783: //_______________________________________________________________________
                   2784: //
                   2785: //     Routine:        FlushAlternateVolumeControlBlock
                   2786: //     Arguments:      ExtendedVCB             *vcb
                   2787: //                             Boolean                 ifHFSPlus
                   2788: //     Output:         OSErr                   err
                   2789: //
                   2790: //     Function:       Flush volume information to either the Alternate VolumeHeader of the 
                   2791: //                             Alternate Master Directory Block.  Called by the BTree when the catalog
                   2792: //                             or extent files grow.  Simply BlockMoves the original to the alternate
                   2793: //                             location.
                   2794: //_______________________________________________________________________
                   2795: 
                   2796: OSErr  FlushAlternateVolumeControlBlock( ExtendedVCB *vcb, Boolean isHFSPlus )
                   2797: {
                   2798:        OSErr                   err;
                   2799:        UInt32                  alternateBlockLocation;
                   2800: 
                   2801:        err = FlushVolumeControlBlock( vcb );
                   2802:        
                   2803:        if ( isHFSPlus )                                                                                                                        //      Flush the VolumeHeader
                   2804:        {
                   2805:                HFSPlusVolumeHeader     *volumeHeader;
                   2806:                HFSPlusVolumeHeader     *alternateVolumeHeader;
                   2807: 
                   2808:                //--    Get the VolumeHeader Block, 1st block in the HFS Plus partition
                   2809: #if TARGET_OS_MAC
                   2810:                err = GetBlock_glue( gbDefault, (vcb->hfsPlusIOPosOffset / 512) + kIDSectorOffset, (Ptr*)&volumeHeader, vcb->vcbVRefNum, vcb ); //      VH is always 1st sector of HFS Plus partition
                   2811: #else
                   2812:                 err = GetBlock_glue( gbDefault, (vcb->hfsPlusIOPosOffset / 512) + kIDSectorOffset, (Ptr*)&volumeHeader, kNoFileReference, vcb );       //      VH is always 1st sector of HFS Plus partition
                   2813: #endif
                   2814:                ReturnIfError( err );
                   2815:                
                   2816:                //--    Get the Alternate VolumeHeader Block, last sector in the HFS Plus partition
                   2817:                alternateBlockLocation = (vcb->hfsPlusIOPosOffset / 512) + vcb->totalBlocks * (vcb->blockSize / 512) - 2;
                   2818: #if TARGET_OS_MAC
                   2819:                err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateVolumeHeader, vcb->vcbVRefNum, vcb );   //      Alt VH is always 2nd to last sector of HFS Plus partition
                   2820: #else
                   2821:                 err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateVolumeHeader, kNoFileReference, vcb ); //      Alt VH is always 2nd to last sector of HFS Plus partition
                   2822: #endif
                   2823:                if ( err == noErr )
                   2824:                {
                   2825:                        //--    Copy the VolumeHeader to the alternate location
                   2826:                        BlockMoveData( volumeHeader, alternateVolumeHeader, sizeof(HFSPlusVolumeHeader) );
                   2827:        
                   2828:                        //--    And write it back to the disk, NOW!
                   2829:                        err = RelBlock_glue( (Ptr)volumeHeader, rbFreeMask );                           //      free the MDB
                   2830:                        err = RelBlock_glue( (Ptr)alternateVolumeHeader, rbWriteMask );         //      force it to be written
                   2831:                }
                   2832:                else
                   2833:                {                       
                   2834:                        err = RelBlock_glue( (Ptr)volumeHeader, rbFreeMask );                           //      free the VH
                   2835:                }
                   2836:        }
                   2837:        else                                                                                                                                            //      Flush the MasterDirectoryBlock
                   2838:        {
                   2839:                HFSMasterDirectoryBlock *mdb;
                   2840:                HFSMasterDirectoryBlock *alternateMDB;
                   2841:                UInt32                                  numBlocks;
                   2842: 
                   2843:                
                   2844:                err = GetDiskBlocks( vcb, &numBlocks );
                   2845:                ReturnIfError( err );
                   2846: 
                   2847:                //--    Get the MDB, 2nd block on HFS disk
                   2848: #if TARGET_OS_MAC
                   2849:                err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, vcb->vcbVRefNum, vcb );    //      no Flags, MDB is always block
                   2850: #else
                   2851:                 err = GetBlock_glue( gbDefault, kIDSectorOffset, (Ptr*)&mdb, kNoFileReference, vcb );  //      no Flags, MDB is always block
                   2852: #endif
                   2853:                ReturnIfError( err );
                   2854: 
                   2855:                //--    Get the Alternate MDB, 2nd to last block on disk
                   2856:                alternateBlockLocation = numBlocks - 2;
                   2857: #if TARGET_OS_MAC
                   2858:                err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateMDB, vcb->vcbVRefNum, vcb );    //      no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
                   2859: #else
                   2860:                 err = GetBlock_glue( gbDefault, alternateBlockLocation, (Ptr*)&alternateMDB, kNoFileReference, vcb );  //      no Flags, VH is always block #0, vcb->vcbBufAdr == CacheQueueHeader
                   2861: #endif
                   2862:                if ( err == noErr )
                   2863:                {
                   2864:                        //--    Copy the MDB to the alternate location
                   2865:                        BlockMoveData( mdb, alternateMDB, sizeof(HFSMasterDirectoryBlock) );
                   2866:                        
                   2867:                        //--    And write it back to the disk, NOW!
                   2868:                        err = RelBlock_glue( (Ptr)mdb, rbFreeMask );                                            //      free the MDB
                   2869:                        err = RelBlock_glue( (Ptr)alternateMDB, rbWriteMask );                          //      force it to be written
                   2870:                }
                   2871:                else
                   2872:                {
                   2873:                        err = RelBlock_glue( (Ptr)mdb, rbFreeMask );                                            //      free the MDB
                   2874:                }
                   2875:        }
                   2876: 
                   2877:        return( err );
                   2878: }
                   2879: 
                   2880: 
                   2881: 
                   2882: //_______________________________________________________________________
                   2883: //
                   2884: //     Routine:        TrashAllFSCaches
                   2885: //     Arguments:      ExtendedVCB             *vcb
                   2886: //     Output:         OSErr                   err
                   2887: //
                   2888: //     Function:       Trash all file system related caches as well as the disk cache.
                   2889: //                             This allows applications such as Disk First Aid or Norton Utilities
                   2890: //                             to be able to repair disks without first unmounting the volume.
                   2891: //                             
                   2892: //                             All file system caches should also have a call to the cache
                   2893: //                             trashing routine here!
                   2894: //_______________________________________________________________________
                   2895: #if TARGET_OS_MAC
                   2896: OSErr  TrashAllFSCaches( ExtendedVCB *vcb )
                   2897: {
                   2898:        OSErr                   err;
                   2899:        FSVarsRec*              fsVars  = (FSVarsRec*) LMGetFSMVars();
                   2900:        
                   2901:        InvalidateCatalogCache( vcb );                          //      Calls TrashCatalogIterator 
                   2902:        TrashCatalogNodeCache( );                                       //      Trash Catalog node cache, gCatalogFSSpec
                   2903:        err = TrashCacheBlocks( 0 );                            //      Trash BTree node cache
                   2904:        TrashMRUCache( vcb->hintCachePtr );                     //      Trash the heuristic hint cache
                   2905:        ClearMemory( fsVars->gAttributesBuffer, fsVars->gAttributesBufferSize );        //      Clear the buffer used by MountCheck and CatSearch
                   2906:        TrashVolumeDiskCache( vcb );                            //      Trash the disk cache, calls TRASHVBLKSA7
                   2907:        
                   2908:        return( err );
                   2909: }
                   2910: #endif /* TARGET_OS_MAC */
                   2911: 
                   2912: 
                   2913: #if TARGET_OS_MAC
                   2914: OSErr GetDiskBlocks( ExtendedVCB *vcb, unsigned long *numBlocks)
                   2915: {
                   2916:        /* Various constants for GetDiskBlocks() */
                   2917:        enum
                   2918:        {
                   2919:                /* return format list status code */
                   2920:                kFmtLstCode = 6,
                   2921:                
                   2922:                /* reference number of .SONY driver */
                   2923:                kSonyRefNum = 0xfffb,
                   2924:                
                   2925:                /* values returned by DriveStatus in DrvSts.twoSideFmt */
                   2926:                kSingleSided = 0,
                   2927:                kDoubleSided = -1,
                   2928:                kSingleSidedSize = 800,         /* 400K */
                   2929:                kDoubleSidedSize = 1600,        /* 800K */
                   2930:                
                   2931:                /* values in DrvQEl.qType */
                   2932:                kWordDrvSiz = 0,
                   2933:                kLongDrvSiz = 1,
                   2934:                
                   2935:                /* more than enough formatListRecords */
                   2936:                kMaxFormatListRecs = 16
                   2937:        };
                   2938:        
                   2939:        DrvQEl                  *driveQElementPtr;
                   2940:        unsigned long   blocks;
                   2941:        ParamBlockRec   pb;
                   2942:        DrvSts                  status;
                   2943:        FormatListRec   formatListRecords[kMaxFormatListRecs];
                   2944:        short                   formatListRecIndex;
                   2945:        OSErr                   err;
                   2946:        short                   driverRefNum;
                   2947: 
                   2948:        blocks = 0;
                   2949:        
                   2950:        //      Find the drive queue element for this volume
                   2951:        err = FindDrive( &driverRefNum, &driveQElementPtr, vcb->vcbDrvNum );
                   2952:        ReturnIfError( err );
                   2953:        
                   2954:        //      Make sure this is a real driver (dQRefNum < 0).
                   2955:        //      AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
                   2956:        //      problems if you try to use it as a driver refNum.
                   2957: 
                   2958:        if ( driveQElementPtr->dQRefNum >= 0 )
                   2959:        {
                   2960:                err = paramErr;
                   2961:        }
                   2962:        else
                   2963:        {
                   2964:                //      Attempt to get the drive's format list.
                   2965:                //      (see the Technical Note "What Your Sony Drives For You")
                   2966:                
                   2967:                pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive;
                   2968:                pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum;
                   2969:                pb.cntrlParam.csCode = kFmtLstCode;
                   2970:                pb.cntrlParam.csParam[0] = kMaxFormatListRecs;
                   2971:                *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0];
                   2972:                
                   2973:                err = PBStatusSync(&pb);
                   2974:                
                   2975:                if ( err == noErr )
                   2976:                {
                   2977:                        //      The drive supports ReturnFormatList status call.
                   2978:                        
                   2979:                        //      Get the current disk's size.
                   2980:                        for( formatListRecIndex = 0;
                   2981:                                 formatListRecIndex < pb.cntrlParam.csParam[0];
                   2982:                         ++formatListRecIndex )
                   2983:                {
                   2984:                        if ( (formatListRecords[formatListRecIndex].formatFlags &
                   2985:                                  diCIFmtFlagsCurrentMask) != 0 )
                   2986:                        {
                   2987:                                blocks = formatListRecords[formatListRecIndex].volSize;
                   2988:                        }
                   2989:                        }
                   2990:                if ( blocks == 0 )
                   2991:                {
                   2992:                        //      This should never happen
                   2993:                        err = paramErr;
                   2994:                }
                   2995:                }
                   2996:                else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum )
                   2997:                {
                   2998:                        //      The drive is a non-SuperDrive floppy which only supports 400K and 800K disks
                   2999:                        
                   3000:                        err = DriveStatus(driveQElementPtr->dQDrive, &status);
                   3001:                        if ( err == noErr )
                   3002:                        {
                   3003:                                switch ( status.twoSideFmt )
                   3004:                                {
                   3005:                                case kSingleSided:
                   3006:                                        blocks = kSingleSidedSize;
                   3007:                                        break;
                   3008:                                case kDoubleSided:
                   3009:                                        blocks = kDoubleSidedSize;
                   3010:                                        break;
                   3011:                                default:
                   3012:                                        //      This should never happen
                   3013:                                        err = paramErr;
                   3014:                                        break;
                   3015:                                }
                   3016:                        }
                   3017:                }
                   3018:                else
                   3019:                {
                   3020:                        //      The drive is not a floppy and it doesn't support ReturnFormatList
                   3021:                        //      so use the dQDrvSz field(s)
                   3022:                        
                   3023:                        err = noErr;                    //      reset err
                   3024:                        switch ( driveQElementPtr->qType )
                   3025:                        {
                   3026:                        case kWordDrvSiz:
                   3027:                                blocks = driveQElementPtr->dQDrvSz;
                   3028:                                break;
                   3029:                        case kLongDrvSiz:
                   3030:                                blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) +
                   3031:                                                 driveQElementPtr->dQDrvSz;
                   3032:                                break;
                   3033:                        default:
                   3034:                                //      This should never happen
                   3035:                                err = paramErr;
                   3036:                                break;
                   3037:                        }
                   3038:                }
                   3039:        }
                   3040:        
                   3041:        *numBlocks = blocks;
                   3042:        
                   3043:        return ( err );
                   3044: }
                   3045: #endif         /* TARGET_OS_MAC */
                   3046: 
                   3047: 
                   3048: //
                   3049: //     Sets up a VCB for calls to GetBlock()
                   3050: //
                   3051: void   AddVCB( ExtendedVCB     *vcb, short driveNumber, short ioRefNum )
                   3052: {
                   3053: #if TARGET_OS_MAC
                   3054:        OSErr                   err                     = noErr;
                   3055:        WDCBArray               *wdcbsAry;
                   3056:        QHdr                    *vcbQHdr;
                   3057:        WDCBRecPtr              wdcb;
                   3058:                        
                   3059:        vcbQHdr = LMGetVCBQHdr();
                   3060:        if ( vcbQHdr->qHead == nil )
                   3061:        {                                                                                                                                       //       Queue is empty, new vcb is the default now
                   3062:                LMSetDefVCBPtr( (Ptr) vcb );
                   3063:                wdcbsAry = (WDCBArray*)LMGetWDCBsPtr();                                                 //      Point to WDCB array
                   3064:                
                   3065:                wdcb = &(wdcbsAry->wdcb[0]);
                   3066:                wdcb->wdVCBPtr  = (VCB *) vcb;                                                                  //      Set default VCB pointer in default WDCB
                   3067:                wdcb->wdDirID   = fsRtDirID;                                                                    //      Default to root directory
                   3068:                wdcb->wdCatHint = 0;                                                                                    //      Clear catalog hint
                   3069:                wdcb->wdProcID  = 0;                                                                                    //      And procID of WDCB 'owner'
                   3070:                vcbQHdr = LMGetVCBQHdr();                                                                               //      Reset for VCB insertion
                   3071:        }
                   3072:        
                   3073: 
                   3074:        Enqueue( (QElemPtr)vcb, (QHdrPtr)vcbQHdr );                                                     //      Insert the new VCB in the queue
                   3075: 
                   3076:        vcb->vcbDrvNum  = driveNumber;
                   3077:        vcb->vcbDRefNum = ioRefNum;
                   3078:        
                   3079:        #if ( hasHFSManualEject )
                   3080:                SetVCBManEject(vcb);                                                                                    //      set vcb maneject flag appropriately     <SM7> <BH 03Aug93>
                   3081:        #endif
                   3082: 
                   3083: 
                   3084:        vcb->vcbBufAdr = LMGetSysVolCPtr();                                                                     //      always use system-wide cache �
                   3085: 
                   3086:        vcb->vcbVRefNum = GetNewVRefNum();                                                                      //      Assign a refNum to this new volume.
                   3087: 
                   3088:        if ( vcb == (ExtendedVCB *) LMGetDefVCBPtr() )                                          //      Are we supposedly the default?
                   3089:        {
                   3090:                LMSetDefVRefNum( vcb->vcbVRefNum );
                   3091:        }
                   3092: #else
                   3093: #pragma unused(vcb,driveNumber,ioRefNum,wdcbH)
                   3094: #endif         /* TARGET_OS_MAC */
                   3095: }
                   3096: 
                   3097: 
                   3098: //--------------------------------------------------------------------------------------
                   3099: //     Routine:        SetVCBManEject
                   3100: //     Input:          VCB ptr
                   3101: //     Called by:      MountVol
                   3102: //     Function:       Sets or clears the manual-eject bit in the flags word of the input VCB
                   3103: //                             based on the type of the drive indicated by vcbDrvNum.  All registers
                   3104: //                             are preserved.  The manual-eject flag should only be changed at MountVol
                   3105: //                             time.
                   3106: //--------------------------------------------------------------------------------------
                   3107: 
                   3108: #if ( hasHFSManualEject )
                   3109: 
                   3110:        static void SetVCBManEject(ExtendedVCB *vcb)
                   3111:        {
                   3112:                DrvQEl  *driveQElementPtr;
                   3113:                DrvSts  *driveStatsPtr;
                   3114:                short   driverRefNum;
                   3115:                OSErr   err;
                   3116:        
                   3117:                //      Find the drive queue element for this volume
                   3118:                err = FindDrive( &driverRefNum, &driveQElementPtr, vcb->vcbDrvNum );
                   3119:                
                   3120:                if (err) return;
                   3121:                
                   3122:                driveStatsPtr = (DrvSts*) ((Ptr) driveQElementPtr - offsetof(DrvSts, qLink));
                   3123:        
                   3124:                if ( driveStatsPtr->installed & (1 << kdqManualEjectBit) )              // manual eject drive asserted?
                   3125:                        vcb->vcbFlags |= vcbManualEjectMask;
                   3126:                else
                   3127:                        vcb->vcbFlags &= ~vcbManualEjectMask;
                   3128:        }
                   3129: 
                   3130: #endif
                   3131: 
                   3132: 
                   3133: //
                   3134: //     Simple utility function to deturmine if a keyboard key is pressed.
                   3135: //
                   3136: short IsPressed( UInt16 k )            // k =  any keyboard scan code, 0-127
                   3137: {
                   3138: #if TARGET_OS_MAC
                   3139:        unsigned char   km[16];
                   3140: 
                   3141:        GetKeys( *( (KeyMap*) &km ) );                                                                          //      Ugly casting to compile with MPWC & SC
                   3142:        return ( ( km[k>>3] >> (k & 7) ) & 1);
                   3143: #else
                   3144: #pragma unused(k)
                   3145:        return( 0 );
                   3146: #endif         /* TARGET_OS_MAC */
                   3147: }
                   3148: 
                   3149: 
                   3150: #if TARGET_OS_MAC
                   3151: //
                   3152: //     Utility function to allocate a new vRefNum. 
                   3153: //     This function cycles through all vRefNums, rather than reuse them.
                   3154: //
                   3155: FileReference  GetNewVRefNum()
                   3156: {
                   3157:        FileReference           refNum;
                   3158:        ExtendedVCB     *tempVCB;
                   3159:        OSErr           err                     = noErr;
                   3160: 
                   3161:        #if (0)         //      See bug 1664445
                   3162:        {
                   3163:                FSVarsRec       *fsVars;
                   3164:        
                   3165:        fsVars = (FSVarsRec*)LMGetFSMVars();
                   3166:        for ( refNum = fsVars->nextVRefNum ; err == noErr ; refNum-- )
                   3167:        {
                   3168:                if ( refNum >= 0x8001 )                                                                                 //      if we've cycled through all the possible vRef nums, start over
                   3169:                        refNum = -1;
                   3170:                        
                   3171:                err = GetVCBRefNum( &tempVCB, refNum );                                                 //      Check if already assigned
                   3172:        }
                   3173:        
                   3174:        fsVars->nextVRefNum     = refNum;
                   3175:        return( ++refNum );                                                                                                     //      for loop post decrements
                   3176:        }
                   3177:        #else
                   3178:        {
                   3179:                for ( refNum = -1 ; err == noErr ; refNum-- )
                   3180:                {
                   3181:                        err = GetVCBRefNum( &tempVCB, refNum );                                                 //      Check if already assigned
                   3182:                }
                   3183:                return( ++refNum );                                                                                                     //      for loop post decrements
                   3184:        }
                   3185:        #endif
                   3186: }
                   3187: #endif /* TARGET_OS_MAC */
                   3188: 
                   3189: //�������������������������������������������������������������������������������
                   3190: 
                   3191: OSErr GetVolumeNameFromCatalog( ExtendedVCB *vcb )
                   3192: {
                   3193:        FSSpec                  spec;
                   3194:        CatalogNodeData nodeData;
                   3195:        UInt32                  hint;
                   3196:        OSErr                   err;
                   3197: #if TARGET_OS_MAC
                   3198:        FSVarsRec               *fsVars;
                   3199: 
                   3200:        fsVars = (FSVarsRec*) LMGetFSMVars();
                   3201:        if ( fsVars->gIsUnicodeInstalled )
                   3202: #else
                   3203:        if ( true )
                   3204: #endif /*TARGET_OS_MAC */
                   3205:        {
                   3206:                err = GetCatalogNode( vcb, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint );
                   3207:        
                   3208:                if ( err == noErr )
                   3209:                {
                   3210: #if TARGET_OS_MAC
                   3211:                        BlockMoveData( spec.name, vcb->vcbVN, sizeof(Str27) );
                   3212: #else
                   3213:                        vcb->vcbVN[0] = strlen(spec.name);
                   3214:                        BlockMoveData( spec.name, &vcb->vcbVN[1], sizeof(Str27)-1 );
                   3215: #endif
                   3216:                        vcb->volumeNameEncodingHint = nodeData.textEncoding;            // save encoding for FSFindTextEncodingForVolume
                   3217:                }
                   3218:        }
                   3219:        else
                   3220:        {
                   3221:                err = paramErr;
                   3222:        }
                   3223:                
                   3224:        return err;
                   3225: }
                   3226: 

unix.superglobalmegacorp.com

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