--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfat/sl_mnt16.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,605 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32\sfat32\sl_mnt16.cpp
+// CFatMountCB code, specific to the EFAT.FSY
+//
+//
+
+/**
+ @file
+*/
+
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//!!
+//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
+//!!
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+#include "sl_std.h"
+#include "sl_cache.h"
+#include "sl_leafdir_cache.h"
+
+
+//-------------------------------------------------------------------------------------------------------------------
+/**
+ Write aligned members of TFatBootSector to media
+
+ @param aMediaPos media position the data will be written to
+ @param aBootSector data to write
+ @return Media write error code
+*/
+TInt CFatMountCB::DoWriteBootSector(TInt64 aMediaPos, const TFatBootSector& aBootSector) const
+ {
+ __PRINT2(_L("#- CFatMountCB::DoWriteBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);
+
+ ASSERT(aMediaPos>=0);
+
+ TBuf8<KDefaultSectorSize> bootSecBuf(KDefaultSectorSize);
+ bootSecBuf.FillZ();
+
+ //-- externalize boot sector to the data buffer
+ aBootSector.Externalize(bootSecBuf);
+
+ //-- put a boot sector signature to the last 2 bytes
+ bootSecBuf[KDefaultSectorSize-2] = 0x55;
+ bootSecBuf[KDefaultSectorSize-1] = 0xaa;
+
+ //-- write boot sector to the media
+ TInt r=LocalDrive()->Write(aMediaPos, bootSecBuf);
+ if (r!=KErrNone)
+ {//-- write failure
+ __PRINT2(_L("CFatMountCB::DoWriteBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
+ }
+
+ return r;
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+
+/**
+ Read non aligned boot data from media into TFatBootSector structure
+
+ @param aMediaPos media position the data will be read from
+ @param aBootSector refrence to TFatBootSector populate
+ @return Media read error code
+*/
+TInt CFatMountCB::DoReadBootSector(TInt64 aMediaPos, TFatBootSector& aBootSector) const
+ {
+ __PRINT2(_L("#- CFatMountCB::DoReadBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);
+
+ ASSERT(aMediaPos>=0);
+
+ TBuf8<KSizeOfFatBootSector> bootSecBuf(KSizeOfFatBootSector);
+
+ //-- read boot sector from the media
+ TInt r=LocalDrive()->Read(aMediaPos, KSizeOfFatBootSector, bootSecBuf);
+ if (r != KErrNone)
+ {
+ __PRINT2(_L("CFatMountCB::DoReadBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
+
+ //-- fiddling with the error code; taken from MountL()
+ if (r==KErrNotSupported)
+ return KErrNotReady;
+ #if defined(_LOCKABLE_MEDIA)
+ else if(r==KErrLocked)
+ return KErrLocked;
+ #endif
+ else if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown)
+ return KErrCorrupt;
+
+ return r;
+ }
+
+ ASSERT(r==KErrNone);
+
+ //-- initialise TFatBootSector object
+ aBootSector.Internalize(bootSecBuf);
+
+ //-- Validate the partition size, and fix up if the out of bounds
+ TLocalDriveCapsV2Buf localDriveCaps;
+ r = LocalDrive()->Caps(localDriveCaps);
+ ASSERT(r==KErrNone);
+
+ if(!(localDriveCaps().iMediaAtt & KMediaAttVariableSize))
+ {//-- this is not a RAM drive.
+ const TUint32 maxSectors = I64LOW(localDriveCaps().iSize >> KDefSectorSzLog2);
+
+ if(aBootSector.TotalSectors())
+ aBootSector.SetTotalSectors(Min(aBootSector.TotalSectors(), maxSectors));
+ else
+ aBootSector.SetHugeSectors(Min(aBootSector.HugeSectors(), maxSectors));
+ }
+
+ return KErrNone;
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+
+/**
+ Read and validate the boot sector.
+ @param aBootSector reference to the boot sector object to be read.
+ @param aDoNotReadBkBootSec if true, there won't be an attempt to read backup sector (N/A for FAT12/16)
+ @return standard error code.
+*/
+TInt CFatMountCB::ReadBootSector(TFatBootSector& aBootSector, TBool /*aDoNotReadBkBootSec=EFalse*/)
+ {
+ //-- read main boot sector from the sector 0
+ TInt nRes = DoReadBootSector(KBootSectorNum << KDefSectorSzLog2, aBootSector);
+ if(nRes == KErrNone)
+ {
+ if(aBootSector.IsValid())
+ {//-- main boot sector is valid, everything is OK
+ return KErrNone;
+ }
+ else
+ {
+ __PRINT(_L("Boot Sector is invalid! dump:\n"));
+ aBootSector.PrintDebugInfo();
+ return KErrCorrupt;
+ }
+ }
+
+ //-- can't read boot sector
+ return nRes;
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+
+/**
+Write a new volume label to BPB in media
+
+@param aVolumeLabel Descriptor containing the new volume label
+@leave
+*/
+void CFatMountCB::WriteVolumeLabelL(const TDesC8& aVolumeLabel) const
+ {
+ if(aVolumeLabel.Length() > KVolumeLabelSize)
+ User::Leave(KErrArgument);
+
+ User::LeaveIfError(LocalDrive()->Write(KFat16VolumeLabelPos,aVolumeLabel));
+ }
+
+
+
+//-------------------------------------------------------------------------------------------------------------------
+
+const TUint16 KFat16CleanShutDownMask = 0x08000; ///< Mask used to indicate test clean/dirty bit for Fat16
+
+/**
+Set or reset "VolumeClean" (ClnShutBitmask) flag.
+
+@param aClean if ETrue, marks the volume as clean, otherwise as dirty.
+@leave if write error occured.
+*/
+void CFatMountCB::SetVolumeCleanL(TBool aClean)
+ {
+ //-- The volume can't be set clean if there are objects opened on it. This precondition must be checked before calling this function
+ if(aClean && LockStatus()!=0)
+ {
+ __PRINT1(_L("#- CFatMountCB::SetVolumeCleanL drive:%d isn't free!"),DriveNumber());
+ ASSERT(0);
+ User::Leave(KErrInUse);
+ return;
+ }
+
+ if(FatType() == EFat12)
+ {//-- Fat12 doesn't support this feature; do nothing other than notify the underlying drive
+ // (ignoring any error for now as there's nothing we can do with it)
+ (void)LocalDrive()->Finalise(aClean);
+ return;
+ }
+
+ //-- further read and write will be directly from the CProxyDrive, bypassing FAT cache.
+ //-- this is because CFatTable doesn't allow access to FAT[1]
+
+ if(Is16BitFat())
+ {//-- Fat16
+ __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT16, efat.fsy"),DriveNumber(), aClean);
+
+ if(FatConfig().FAT16_UseCleanShutDownBit())
+ {
+
+ TFat16Entry fatEntry;
+ const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
+ TPtr8 ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize);
+
+ User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry
+
+ const TFat16Entry tmp = fatEntry;
+
+ if(aClean)
+ fatEntry |= KFat16CleanShutDownMask; //-- set ClnShutBit flag
+ else
+ fatEntry &= ~KFat16CleanShutDownMask; //-- reset ClnShutBit flag
+
+ if(tmp != fatEntry)
+ {//-- write FAT[1] entry to all available FATs
+ for(TInt i=0; i<NumberOfFats(); ++i)
+ {
+ const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i);
+ User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT16[1] entry
+ }
+ }
+
+ //-- Notify the underlying media that the mount is consistent
+ // (ignoring any error for now as there's nothing we can do with it)
+ (void)LocalDrive()->Finalise(aClean);
+
+ __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry: %x->%x"), tmp, fatEntry);
+
+ }
+ else //if(FatConfig().FAT16_UseCleanShutDownBit())
+ {
+ __PRINT(_L("#- changing FAT16[1] is disabled in config!"));
+ }
+
+ }// if(Is16BitFat())
+ else
+ {//-- must never get here
+ ASSERT(0);
+ }
+
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+
+/**
+Determine whether "VolumeClean" (ClnShutBitmask) flag is set.
+
+@return ETrue if the volume is marked as clean and EFalse otherwise.
+@leave if is called for FAT12 or if read error occured.
+*/
+TBool CFatMountCB::VolumeCleanL()
+ {
+ TFatDriveInterface& drive = DriveInterface();
+
+ if(Is16BitFat())
+ {//-- Fat16
+ TFat16Entry fatEntry;
+ const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
+ TPtr8 ptrFatEntry((TUint8*)&fatEntry, KFatEntrySize);
+
+ User::LeaveIfError(drive.ReadNonCritical(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry
+ return (fatEntry & KFat16CleanShutDownMask);
+ }
+ else
+ {//-- Fat12 doesn't support this feature, shan't get here, actually
+ ASSERT(0);
+ User::Leave(KErrNotSupported);
+ return ETrue; //-- to satisfy the compiler
+ }
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+
+/**
+Mount a Fat volume.
+
+@param aForceMount Flag to indicate whether mount should be forced to succeed if an error occurs
+@leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
+*/
+void CFatMountCB::MountL(TBool aForceMount)
+ {
+ const TInt driveNo = Drive().DriveNumber();
+
+ __PRINT2(_L("CFatMountCB::MountL() drv:%d, forceMount=%d\n"),driveNo,aForceMount);
+
+ ASSERT(State() == ENotMounted || State() == EDismounted);
+ SetState(EMounting);
+ SetReadOnly(EFalse);
+
+
+ User::LeaveIfError(CreateDrive(Drive().DriveNumber()));
+
+ //-- read FAT configuration parameters from estart.txt
+ iFatConfig.ReadConfig(driveNo);
+
+
+ //-- initialise interface to the low-level drive access
+ if(!iDriverInterface.Init(this))
+ User::LeaveIfError(KErrNoMemory);
+
+ //-- get drive capabilities
+ TLocalDriveCapsV2Buf capsBuf;
+ User::LeaveIfError(LocalDrive()->Caps(capsBuf));
+
+ iSize=capsBuf().iSize;
+ iRamDrive = EFalse;
+
+ if(capsBuf().iMediaAtt & KMediaAttVariableSize)
+ {//-- this is a RAM drive
+ UserSvr::UnlockRamDrive();
+ iRamDrive = ETrue;
+ }
+
+ if(aForceMount)
+ {//-- the state is "forcedly mounted", special case. This is an inconsistent state.
+ SetState(EInit_Forced);
+ return;
+ }
+
+ //-- read and validate boot sector (sector 0)
+ TFatBootSector bootSector;
+ User::LeaveIfError(ReadBootSector(bootSector, iRamDrive));
+
+ //-- print out boot sector debug information
+ bootSector.PrintDebugInfo();
+
+ //-- determine FAT type by data from boot sector. This is done by counting number of clusters, not by BPB_RootEntCnt
+ iFatType=bootSector.FatType();
+ ASSERT(iFatType != EInvalid); //-- this shall be checked in ReadBootSector()
+
+ //-- values from the boot sector are checked in TFatBootSector::IsValid()
+ //-- store volume UID, it can be checked on Remount
+ iUniqueID = bootSector.UniqueID();
+
+ //-- populate volume parameters with the values from boot sector. They had been validated in TFatBootSector::IsValid()
+ iVolParam.Populate(bootSector);
+
+ //-- initialize the volume
+ InitializeL(capsBuf());
+ ASSERT(State()==EInit_R);
+
+ GetVolumeLabelFromDiskL(bootSector);
+
+ __PRINT2(_L("CFatMountCB::MountL() Completed, drv: %d, state:%d"), DriveNumber(), State());
+ }
+
+
+
+//-------------------------------------------------------------------------------------------------------------------
+
+/**
+Initialize the FAT cache and disk access
+
+@param aLocDrvCaps local drive capabilities
+@leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
+*/
+void CFatMountCB::InitializeL(const TLocalDriveCaps& aLocDrvCaps, TBool /*aIgnoreFSInfo=EFalse*/)
+ {
+ __PRINT1(_L("CFatMountCB::InitializeL() drv:%d"), DriveNumber());
+
+ ASSERT(State() == EMounting); //-- we must get here only from MountL()
+
+ //========== Find out number of clusters on the volume
+ if(iRamDrive && SectorsPerCluster()!=1)
+ {// Align iFirstFreeByte to cluster boundary if internal ram drive
+ const TInt sectorsPerClusterLog2=ClusterSizeLog2()-SectorSizeLog2();
+ const TInt rootDirEndSector=RootDirEnd()>>SectorSizeLog2();
+ const TInt alignedSector=((rootDirEndSector+SectorsPerCluster()-1)>>sectorsPerClusterLog2)<<sectorsPerClusterLog2;
+ iFirstFreeByte=alignedSector<<SectorSizeLog2();
+ }
+ else
+ {
+ iFirstFreeByte=RootDirEnd();
+ }
+
+
+ {//-- check if volume geometry looks valid
+ const TInt usableSectors=TotalSectors()-(iFirstFreeByte>>SectorSizeLog2());
+ iUsableClusters=usableSectors>>(ClusterSizeLog2()-SectorSizeLog2());
+
+ const TUint32 KMinClusters = 32; //-- absolute minimum number of clusters on the volume
+ const TUint32 KMaxClusters =(TotalSectors()-FirstFatSector()-NumberOfFats()*(FatSizeInBytes()>>SectorSizeLog2())) >> (ClusterSizeLog2()-SectorSizeLog2());
+
+ if(usableSectors <=0 || iUsableClusters < KMinClusters || iUsableClusters > KMaxClusters)
+ {
+ __PRINT(_L("CFatMountCB::InitializeL() Wrong number of usable cluster/sectors on the volume!"));
+ User::Leave(KErrCorrupt);
+ }
+ }
+
+
+ //========== initialise RawDisk interface
+ //-- CFatMountCB parameters might have changed, e.g. after formatting. Reconstruct directory cache with new parameters
+
+ delete iRawDisk;
+ iRawDisk=CRawDisk::NewL(*this, aLocDrvCaps);
+ iRawDisk->InitializeL();
+
+
+ //========== create FAT table object
+ delete iFatTable;
+ iFatTable=CFatTable::NewL(*this, aLocDrvCaps);
+
+ //========== create and setup leaf direcotry cache if cache limit is set bigger than one
+ const TUint32 cacheLimit = iFatConfig.LeafDirCacheSize();
+ if (cacheLimit > 1)
+ {
+ // destroy the old leaf dir cache to avoid memory leak.
+ delete iLeafDirCache;
+ iLeafDirCache = CLeafDirCache::NewL(cacheLimit);
+ }
+ else
+ {
+ iLeafDirCache = NULL;
+ }
+
+ //========== find out free clusters number on the volume
+ FAT().CountFreeClustersL();
+
+ SetState(EInit_R); //-- the state is "Initialized, but not writen"
+
+ //-- make a callback, telling FileServer about free space discovered.
+ const TInt64 freeSpace = ((TInt64)FAT().NumberOfFreeClusters()) << ClusterSizeLog2();
+ SetDiskSpaceChange(freeSpace);
+
+ __PRINT3(_L("#- CFatMountCB::InitializeL() done. drv:%d, Free clusters:%d, 1st Free cluster:%d"),DriveNumber(), FAT().NumberOfFreeClusters(), FAT().FreeClusterHint());
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+
+
+
+/**
+Checks for end of file for all Fat types
+
+@param aCluster Cluster to check
+@return Result of test
+*/
+TBool CFatMountCB::IsEndOfClusterCh(TInt aCluster) const
+ {
+ if(Is16BitFat())
+ return(aCluster>=0xFFF8 && aCluster<=0xFFFF);
+ else
+ return(aCluster>=0xFF8 && aCluster<=0xFFF);
+ }
+
+/**
+Set a cluster to the end of cluster chain marker
+
+@param aCluster cluster to set to end of chain marker
+*/
+void CFatMountCB::SetEndOfClusterCh(TInt &aCluster) const
+ {
+ if(Is16BitFat())
+ aCluster=0xFFF8;
+ else
+ aCluster=0xFF8;
+ }
+
+/**
+Initialize data to represent the root directory
+
+@param anEntry Entry to initialise
+*/
+void CFatMountCB::InitializeRootEntry(TFatDirEntry & anEntry) const
+ {
+ anEntry.SetName(_L8("ROOT"));
+ anEntry.SetAttributes(KEntryAttDir);
+ anEntry.SetStartCluster(0);
+ }
+
+
+/**
+Implementation of CMountCB::FileSystemSubType(). Retrieves the sub type of Fat file system
+and returns the name as a descriptor.
+
+@param aName Name of the sub type of Fat file system
+@return KErrNone if successful; KErrArgument if aName is not long enough; KErrNotReady if
+ the mount is not ready.
+
+@see CMountCB::FileSystemSubType()
+*/
+TInt CFatMountCB::SubType(TDes& aName) const
+ {
+ if(aName.MaxLength() < 5)
+ return KErrArgument;
+
+ switch (iFatType)
+ {
+ case EFat12:
+ {
+ aName = KFSSubType_FAT12;
+ return KErrNone;
+ }
+ case EFat16:
+ {
+ aName = KFSSubType_FAT16;
+ return KErrNone;
+ }
+ default:
+ // case EInvalidFatType
+ return KErrNotReady;
+ }
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+/**
+ CFatMountCB control method.
+ @param aLevel specifies the operation to perfrom on the mount
+ @param aOption specific option for the given operation
+ @param aParam pointer to generic parameter, its meaning depends on aLevel and aOption
+
+ @return standard error code.
+*/
+TInt CFatMountCB::MountControl(TInt aLevel, TInt aOption, TAny* aParam)
+ {
+ TInt nRes = KErrNotSupported;
+
+ if(aLevel == ECheckFsMountable)
+ {
+ return MntCtl_DoCheckFileSystemMountable();
+ }
+
+ //-- mount state query: check if is in finalised state
+ if(aLevel == EMountStateQuery && aOption == ESQ_IsMountFinalised)
+ {
+ TBool bFinalised;
+ nRes = IsFinalised(bFinalised);
+ if(nRes == KErrNone)
+ {
+ *((TBool*)aParam) = bFinalised;
+ }
+
+ return nRes;
+ }
+
+ //-- File System - specific queries
+ if(aLevel == EMountFsParamQuery && aOption == ESQ_GetMaxSupportedFileSize)
+ {//-- this is a query to provide the max. supported file size; aParam is a pointer to TUint64 to return the value
+ *(TUint64*)aParam = KMaxSupportedFatFileSize;
+ return KErrNone;
+ }
+
+
+ return nRes;
+ }
+
+//-------------------------------------------------------------------------------------------------------------------
+/**
+Reports whether the specified interface is supported - if it is,
+the supplied interface object is modified to it
+
+@param aInterfaceId The interface of interest
+@param aInterface The interface object
+@return KErrNone if the interface is supported, otherwise KErrNotFound
+
+@see CMountCB::GetInterface()
+*/
+TInt CFatMountCB::GetInterface(TInt aInterfaceId, TAny*& aInterface,TAny* aInput)
+ {
+ switch(aInterfaceId)
+ {
+ case (CMountCB::EFileAccessor):
+ ((CMountCB::MFileAccessor*&) aInterface) = this;
+ return KErrNone;
+
+ case (CMountCB::EGetFileSystemSubType):
+ aInterface = (MFileSystemSubType*) (this);
+ return KErrNone;
+
+ case (CMountCB::EGetClusterSize):
+ aInterface = (MFileSystemClusterSize*) (this);
+ return KErrNone;
+
+ case CMountCB::ELocalBufferSupport:
+ // RAM drives doesn't support local buffers (this results in file caching being disabled)
+ if (iRamDrive)
+ return KErrNotSupported;
+ else
+ return LocalDrive()->LocalBufferSupport();
+
+ case EGetProxyDrive:
+ ((CProxyDrive*&)aInterface) = LocalDrive();
+ return KErrNone;
+
+ default:
+ return(CMountCB::GetInterface(aInterfaceId, aInterface, aInput));
+ }
+ }
+