userlibandfileserver/fileserver/sfat/sl_mnt16.cpp
changeset 0 a41df078684a
child 2 4122176ea935
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfat/sl_mnt16.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,596 @@
+// 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 
+*/
+
+#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));
+        }
+    }
+