diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfat/sl_mnt16.cpp --- /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 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 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; iWrite(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)<>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)); + } + } +