Source to bsd/hfs/hfscommon/Misc/VolumeRequests.c
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: VolumeRequests.c
Contains: MountVolume and related utility routines for HFS & HFS Plus
Version: HFS Plus 1.0
Written by: Deric Horn
Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved.
File Ownership:
DRI: Deric Horn
Other Contacts: Mark Day, Don Brady
Technology: File Systems
Writers:
(JL) Jim Luther
(msd) Mark Day
(DSH) Deric Horn
(djb) Don Brady
Change History (most recent first):
<MacOSX> 7/28/98 djb GetDiskBlocks is now implemented in MacOSStubs.c (radar #2258148).
<MacOSX> 4/3/98 djb Conditionally remove FSVars reference from GetVolumeNameFromCatalog.
<MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
<CS47> 1/29/98 DSH TrashAllFSCaches is responsible for trashing all file system and
disk caches. Called from FlushVol when the HFS bit is set.
<CS46> 12/12/97 DSH 2003877, when vcbAllocPtr was copied to nextAllocation it was
getting sign extended.
<CS45> 11/26/97 DSH 2003459, fcbs was not being initialized if volume was offline
and we are executing an unconditional unmount.
<CS44> 11/24/97 DSH 2005507, FlushVolumeControlBlock() keeps MDB drCrDate in sync
with VolumeHeader createDate.
<CS43> 11/11/97 DSH 1685873, RemountWrappedVolumes was only remounting the first
HFS+ volume in the queue, causing HFS wrappers to be mounted if
multiple volumes had been mounted before InitHFSPlus.
<CS42> 11/4/97 DSH Clear FCB when getting a new one.
<CS41> 11/3/97 JL #2001483 - Removed unneeded parameters from MountVolume,
MountHFSVolume, MountHFSPlusVolume, GetVolumeInformation,
GetXVolumeInformation and AddVCB (and added local variables as
needed). Return WDCBRecPtr from UnMountVolume. Set wdcb
parameter to NULL in GetXVolumeInformation if working directory
was not specified.
<CS40> 10/31/97 DSH Added consistencyStatus parameter to MountCheck
<CS39> 10/23/97 msd Bug 1685113. The VolumeHeader's createDate should be in local
time (not GMT) and identical to the MDB's drCrDate (and VCB's
vcbCrDate). When checking for a remount of an offline HFS Plus
volume, compare write counts instead of mod dates (which could
be fooled by the user changing time zones). Force MountCheck to
run if the volume was last mounted by Bride 1.0b2 or earlier.
<CS38> 10/17/97 msd Conditionalize DebugStrs.
<CS37> 10/13/97 djb Update volumeNameEncodingHint when updating the volume name.
<CS36> 10/10/97 msd Bug 1683571. The dates in the volume header are in GMT, so be
sure to convert them when mounting a volume or flushing the
volume header.
<CS35> 10/2/97 DSH In UnmountVolume() check that the drive is on line before
determining if wrapper volume needs to be renamed causing IO.
<CS34> 10/1/97 DSH Run on disk version of MountCheck instead of ROM version for
boot volumes1682475.
<CS33> 10/1/97 djb Add calls to InvalidateCatalogCache (part of radar #1678833).
<CS32> 9/26/97 DSH Removed debugging code: support for 'W' key wrapper mounting.
<CS31> 9/17/97 DSH hfsPlusIOPosOffset was uninitialized for Wrapperless volumes.
<CS30> 9/5/97 djb In MountVol initialize Catalog cache before calling Catalog!
<CS29> 9/4/97 msd PropertyCloseVolume renamed to AttributesCloseVolume. Remove
call to AttributesOpenVolume (it no longer exists).
<CS28> 9/2/97 DSH VolumeHeader is now 3rd sector in partition, altVH is 2nd to
last cor compatability. Initial support for wrapperless
volumes.
<CS27> 8/26/97 djb Only call CountRootFiles during MountVol.
<CS26> 8/20/97 msd If the HFS Plus volume version doesn't match, mount the wrapper
instead.
<CS25> 8/19/97 djb Add error handling to RenameWrapperVolume.
<CS24> 8/15/97 msd Bug 1673999. In MakeVCBsExtendedVCBs, copy old VCB's vcbAllocPtr
to new VCB's nextAllocation field.
<CS23> 8/12/97 djb Fixed GetXVolInfo to only use extended vcb fields for local
volumes (radar# 1673177)
<CS22> 8/11/97 DSH vcbNmAlBlks is now taken from the embededExtent.blockCount
(1669121).
<CS21> 8/11/97 djb Return actual count of files in root directory for HFS Plus
volumes (Radar #1669118). Added local CountRootFiles routine.
8/5/97 msd Make sure version field in VolumeHeader is exactly
kHFSPlusVersion. 8/1/97 djb GetXVolumeInformation now returns
extFSErr when FSID is nonzero (Radar #1649503).
<CS20> 7/25/97 DSH Init and Dispose of GenericMRUCache within ExtendedVCB.
<CS19> 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision
<CS18> 7/15/97 DSH Remount Wrapper volumes mounted before HFS+ initialization
(166729)
<CS17> 7/15/97 djb Remove ioXVersion checking in GetXVolInfo (radar #1666217).
<CS16> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
<CS15> 7/7/97 djb Add GetVolumeNameFromCatalog routine.
<CS14> 7/7/97 DSH GetNewVRefNum now get's a recycled vRefNum. Bug 1664445 in
Installer was cacheing the vRefNum while CheckDisk unmounts and
remounts disk.
<CS13> 6/30/97 DSH shadowing values obsoleteVCBXTRef, and obsoleteVCBCTRef when
HFS+ volume is mounted.
<CS12> 6/26/97 DSH GetVolInfo returns HFS signature for HFS+ volumes, GetXVolInfo
returns real signature.
<CS11> 6/24/97 DSH MakeVCBsExtendedVCBs was using wdcb->count as count not byte
count.
<CS10> 6/18/97 djb Set/get volume encodingsBitmap.
<CS9> 6/16/97 msd Include String.h and Disks.h.
<CS8> 6/12/97 djb Get in sync with HFS Plus format changes.
<CS7> 6/11/97 msd Make GetXVolumeInformation return true allocation block size. It
now checks the ioXVersion field.
<CS6> 5/28/97 msd When flushing the volume header, write out the allocation file's
clump size (from the FCB). When mounting an HFS Plus volume,
zero the entire FCB extent record, not just the first extent,
for the various volume control files.
<CS5> 5/19/97 djb Add calls to CreateVolumeCatalogCache,
DisposeVolumeCatalogCache.
<CS4> 5/9/97 djb Get in sync with new FilesInternal.i
<CS3> 5/8/97 DSH Only mount HFS+ volumes with version < 2.0 in the VolumeHeader.
Return wrgVolTypErr if too new.
<CS2> 5/2/97 djb Disable Manual Eject code since its buggy!
<CS1> 4/25/97 djb first checked in
<HFS32> 4/11/97 DSH MountHFSPlusVolume gets volume name from catalog, and
UnmountVolume shadows the name back to the wrapper partition.
<HFS31> 4/8/97 msd Once volume is mounted, call AttributesOpenVolume to allow a
buffer to be allocated.
<HFS30> 4/7/97 msd In FlushVolumeControlBlock, don't update the attributes BTree
fields in the Volume Header unless an attributes BTree was
already open.
<HFS29> 4/7/97 msd In SetupFCB, add case for attributes BTree. Add code to set up
the attributes BTree. Remove call to PropertyOpenVolume. In
FlushVolumeControlBlock, write out any changes to the attributes
BTree.
<HFS28> 4/4/97 djb Get in sync with volume format changes.
<HFS27> 3/31/97 djb Added catalogDataCache to VCB; Remove ClearMem routine.
<HFS26> 3/18/97 msd In MountHFSPlusVolume, the free blocks calculation can overflow,
setting vcbFreeBks to a too-small value.
<HFS25> 3/17/97 DSH Added some utility functions AddVCB, GetParallelFCBFromRefNum,
casting for SC, and made some functions extern for DFA.
<HFS24> 3/5/97 msd Add calls to Property Manager to open and close the volume. When
unmounting an HFS+ volume, the allocation (bitmap) file now gets
closed.
<HFS23> 2/19/97 djb Update to 16-bit HFS Plus signature.
<HFS22> 2/12/97 msd In GetXVolumeInformation, the result code could be
uninitialized.
<HFS21> 1/23/97 DSH UpdateAlternateVoumeControlBlock()
<HFS20> 1/15/97 djb Remove MountCheckStub. Add file names to fcbs for debugging.
<HFS19> 1/13/97 DSH Use ExtendedVCB nextAllocation instead of vcbAllocPtr through
all code.
<HFS18> 1/9/97 djb Get in sync with new VolumeHeader and Extended VCB.
<HFS17> 1/6/97 djb Changed API to ParallelFCBFromRefnum (pragma parameter was
broken).
<HFS16> 1/6/97 msd Set only the defined bits in the MDB drAtrb field (when copying
from VCB vcbAtrb field).
<HFS15> 1/6/97 DSH CloseFile requires VCB to be passed in.
<HFS14> 1/6/97 djb FlushVolumeControlBlock was writing to absolute block 0 instead
of to block zero of the embedded volume.
<HFS13> 12/20/96 msd A comparison was using "=" instead of "=="; might have caused
the wrong volume to be set as the default.
<HFS12> 12/19/96 DSH Setting up ExtendedVCBs
<HFS11> 12/19/96 djb Updated for new B-tree Manager interface.
<HFS10> 12/18/96 msd Change GetVCBRefNum so it can actually return a VCB pointer.
<HFS9> 12/12/96 djb Use new SPI for GetCatalogNode.
<HFS8> 12/12/96 msd Fix a bunch of errors (mostly type mismatch) when compiling with
Metrowerks.
<HFS7> 12/12/96 DSH adding some util functions
<HFS6> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
<HFS5> 12/4/96 DSH Ported GetVolumeInformation & GetXVolumeInformation.
<3*> 11/20/96 DSH HFS Plus support to MountVolume
<HFS3> 11/20/96 DSH Added UnmountVol and related routines, also backed out <2>
because C_FXMKeyCmp is passed as a parameter from C but called
from Asm in BTOpen so we need a Case ON Asm entry point.
<HFS2> 11/20/96 msd Use CompareExtentKeys() instead of CFXMKeyCmp().
<HFS1> 11/19/96 DSH first checked in
<1> 11/19/96 DSH first checked in
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include "../../hfs.h"
#include "../headers/FileMgrInternal.h"
#define kIDSectorOffset 2
OSErr GetNewFCB( ExtendedVCB *vcb, FileReference* fRefPtr);
OSErr AccessBTree( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize, void *CompareRoutine );
UInt16 DivUp( UInt32 byteRun, UInt32 blockSize );
Boolean IsARamDiskDriver( void );
OSErr GetVCBRefNum( ExtendedVCB **vcb, short vRefNum );
OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
void RenameWrapperVolume( Str27 newVolumeName, UInt16 driveNumber );
OSErr CheckExternalFileSystem( ExtendedVCB *vcb );
OSErr FlushVolume( ExtendedVCB *vcb );
FCB *SetupFCB( ExtendedVCB *vcb, FileReference refNum, UInt32 fileID, UInt32 fileClumpSize );
void AddVCB( ExtendedVCB *vcb, short driveNumber, short ioDRefNum );
short IsPressed( unsigned short k );
FileReference GetNewVRefNum();
OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
#if TARGET_API_MAC_OS8
static UInt16 CountRootFiles(ExtendedVCB *vcb);
#endif /* TARGET_API_MAC_OS8 */
#if ( hasHFSManualEject )
static void SetVCBManEject(ExtendedVCB *vcb);
#endif
// External routines
extern OSErr C_FlushMDB( ExtendedVCB *volume );
extern OSErr DisposeVolumeCacheBlocks( ExtendedVCB *vcb );
extern void DisposeVolumeControlBlock( ExtendedVCB *vcb );
extern OSErr FlushVolumeBuffers( ExtendedVCB *vcb );
extern void MultiplyUInt32IntoUInt64( UInt64 *wideResult, UInt32 num1, UInt32 num2 );
extern void TrashCatalogNodeCache( void );
//�������������������������������������������������������������������������������
// Routine: VolumeWritable Asm: CVFlgs
//
// Function: Check the volume's flags to see if modify requests are allowed.
//
//�������������������������������������������������������������������������������
OSErr VolumeWritable( ExtendedVCB *vcb )
{
if ( !(vcb->vcbAtrb & 0x8000) ) // if the volume is not locked
{
if ( ! (*((Ptr)&(vcb->vcbAtrb) + 1) & kHFSVolumeHardwareLockMask) ) // if it's not write protected
return( noErr );
else
return( wPrErr );
}
else
{
return( vLckdErr );
}
}
//�������������������������������������������������������������������������������
// Routine: DivUp from Asm: DivUp
//
// Function: Given a number of bytes and block size, calculate the number of
// blocks needd to hold all the bytes.
//
// Result: Number of physical blocks needed
//�������������������������������������������������������������������������������
UInt16 DivUp( UInt32 byteRun, UInt32 blockSize )
{
UInt32 blocks;
blocks = (byteRun + blockSize - 1) / blockSize; // Divide up, remember this is integer math.
if ( blocks > 0xffff ) // maximum 16 bit value
blocks = 0xffff;
return( (UInt16) blocks );
}
//�������������������������������������������������������������������������������
// Routine: HFSBlocksFromTotalSectors
//
// Function: Given the total number of sectors on the volume, calculate
// the 16Bit number of allocation blocks, and allocation block size.
//
// Result: none
//�������������������������������������������������������������������������������
void HFSBlocksFromTotalSectors( UInt32 totalSectors, UInt32 *blockSize, UInt16 *blockCount )
{
UInt16 newBlockSizeInSectors = 1;
UInt32 newBlockCount = totalSectors;
while ( newBlockCount > 0XFFFF )
{
newBlockSizeInSectors++;
newBlockCount = totalSectors / newBlockSizeInSectors;
}
*blockSize = newBlockSizeInSectors * 512;
*blockCount = newBlockCount;
}
//�������������������������������������������������������������������������������
// Routine: ValidMasterDirectoryBlock
//
// Function: Run some sanity checks to make sure the MDB is valid
//
// Result: error
//�������������������������������������������������������������������������������
OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb )
{
OSErr err;
if ( (mdb->drSigWord == kHFSPlusSigWord) || (mdb->drSigWord == kHFSSigWord) ) // if HFS or HFS Plus volume
{
if ( (mdb->drAlBlkSiz != 0) && ((mdb->drAlBlkSiz & 0x01FF) == 0) ) // non zero multiple of 512
err = noErr;
else
err = badMDBErr;
}
else
{
err = noMacDskErr;
}
return( err );
}
//�������������������������������������������������������������������������������
// Routine: ValidVolumeHeader
//
// Function: Run some sanity checks to make sure the VolumeHeader is valid
//
// Result: error
//�������������������������������������������������������������������������������
OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader )
{
OSErr err;
if ( volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion )
{
if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) ) // non zero multiple of 512
err = noErr;
else
err = badMDBErr; //�� I want badVolumeHeaderErr in Errors.i
}
else
{
err = noMacDskErr;
}
return( err );
}
//_______________________________________________________________________
//
// Routine: CountRootFiles
//
// Input: pointer to VCB
//
// Function: Return a count of the number of files and folders in
// the root directory of a volume. For HFS volumes, this
// is maintained in the VCB (and MDB). For HFS Plus volumes,
// we get the valence of the root directory from its catalog
// record.
//_______________________________________________________________________
UInt16 CountRootFiles(ExtendedVCB *vcb)
{
OSErr err;
FSSpec spec;
CatalogNodeData catNodeData;
UInt32 hint;
UInt16 rootCount;
// if (vcb->vcbSigWord == kHFSSigWord || vcb->vcbFSID != 0) {
// return vcb->vcbNmFls;
// }
// Here, it's an HFS Plus volume, so get the valence from the root
// directory's catalog record.
rootCount = 0;
err = GetCatalogNode( vcb, kHFSRootFolderID, nil, kUndefinedStrLen, kNoHint, &spec, &catNodeData, &hint );
if ( err == noErr ) {
if (catNodeData.cnd_valence < 65536)
rootCount = catNodeData.cnd_valence;
else
rootCount = 65535; // if the value is too large, pin it
}
return rootCount;
}
//_______________________________________________________________________
//
// Routine: FlushVolumeControlBlock
// Arguments: ExtendedVCB *vcb
// Output: OSErr err
//
// Function: Flush volume information to either the VolumeHeader of the Master Directory Block
//_______________________________________________________________________
OSErr FlushVolumeControlBlock( ExtendedVCB *vcb )
{
OSErr err;
if ( ! IsVCBDirty( vcb ) ) // if it's not dirty
return( noErr );
if ( vcb->vcbSigWord == kHFSPlusSigWord )
{
err = C_FlushMDB( vcb ); // Go flush the VCB info BEFORE close
}
else
{
// This routine doesn't really return an error!!!
// So for now, we will just return noErr
err = C_FlushMDB( vcb ); // Go flush the VCB info BEFORE close
return( noErr );
}
return( err );
}
//�������������������������������������������������������������������������������