diff -r a41df078684a -r 4122176ea935 userlibandfileserver/fileserver/sfat32/sl_file.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfat32/sl_file.cpp Mon Dec 21 16:14:42 2009 +0000 @@ -0,0 +1,772 @@ +// 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\sfat\sl_file.cpp +// +// + +#include "sl_std.h" +#include "sl_cache.h" +#include + +const TInt KSeekIndexSize=128; // Cache 128 clusters +const TInt KSeekIndexSizeLog2=7; +const TInt KFirstClusterNum=2; + +CFatFileCB::CFatFileCB() + { + + __PRINT1(_L("CFatFileCB created 0x%x"),this); + } + +CFatFileCB::~CFatFileCB() + { + __PRINT1(_L("CFatFileCB deleted 0x%x"),this); + + //-- a nasty trick to find out if the CFatFileCB is in consistent state on the moment of destruction. + //-- Because of OOM conditions CFatFileCB might not be fully constructed and to be deleted, while FlushAll() + //-- implies valid iMount. + const CMountCB* pMount = &Mount(); + if(pMount) + {//-- do some finalisation work if CMountCB is valid + if (iAtt&KEntryAttModified) + TRAP_IGNORE(FlushAllL()); + } + + delete[] iSeekIndex; + } + + +void CFatFileCB::CreateSeekIndex() +// +// Create a seek index +// + { + + iSeekIndex = new TUint32[KSeekIndexSize]; + if (iSeekIndex == NULL) + return; + + Mem::FillZ(iSeekIndex, sizeof(TUint32) * KSeekIndexSize); + + iSeekIndexSize=CalcSeekIndexSize(Size()); + } + +TInt CFatFileCB::SeekToPosition(TInt aNewRelCluster,TInt aClusterOffset) +// +// Use the seek index to set iCurrentPos.iCluster as close as possible to aNewRelCluster +// Return aNewRelCluster-aCurrentPos.iCluster +// + { + TInt clusterOffset=aClusterOffset; + TInt seekPos=(aNewRelCluster>>iSeekIndexSize)-1; + __ASSERT_DEBUG(seekPos=0 && iSeekIndex[seekPos]==0 && clusterOffset!=0) + { + seekPos--; + clusterOffset--; + } + if (clusterOffset==0) // Counted back to the current cluster + return(aClusterOffset); + if (seekPos<0) + { + iCurrentPos.iCluster=iStartCluster; + return(aNewRelCluster); + } + + iCurrentPos.iCluster=iSeekIndex[seekPos]; + return(aNewRelCluster-((seekPos+1)<>iSeekIndexSize)-1; + __ASSERT_DEBUG(seekPos=0,Fault(EFatFileSeekIndexTooSmall2)); + iSeekIndex[seekPos] = aStoredCluster; + } + +TBool CFatFileCB::IsSeekBackwards(TUint aPos) +// +// Return true if aPos>ClusterSizeLog2(); + if ( aPos && (aPos==(newRelCluster<>ClusterSizeLog2(); + if ( iCurrentPos.iPos && (iCurrentPos.iPos==(oldRelCluster<>iSeekIndexSize)< KMaxSupportedFatFileSize-1) + User::Leave(KErrNotSupported); //-- max. position in the file is 0xFFFFFFFE + + FatMount().CheckStateConsistentL(); + + CheckPosL(I64LOW(aPos)); + + const TUint startPos = iCurrentPos.iPos; + const TUint curSize = (TUint)Size(); + const TUint length = (TUint)aLength; + + if((startPos + length > curSize) || (startPos > startPos + length) ) + aLength=curSize-startPos; + + FatMount().ReadFromClusterListL(iCurrentPos,aLength,aDes,aMessage,aOffset); + aLength=iCurrentPos.iPos-startPos; + } + + +void CFatFileCB::ReadL(TInt aFilePos,TInt& aLength,const TAny* aTrg,const RMessagePtr2& aMessage) + { + ReadL(TInt64(aFilePos),aLength,(TDes8*) aTrg,aMessage, 0); + } + +//----------------------------------------------------------------------------- +// from CFileCB::MExtendedFileInterface +void CFatFileCB::WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aSrc,const RMessagePtr2& aMessage, TInt aOffset) + { + __PRINT2(_L("CFatFileCB::WriteL aFilePos=%LU aLength=%d"),aPos,aLength); + // FAT supports 32 bits only for file size + TUint64 endPos = aPos + aLength; + if(endPos > KMaxSupportedFatFileSize) + User::Leave(KErrNotSupported); + + FatMount().CheckStateConsistentL(); + FatMount().CheckWritableL(); + const TUint pos = I64LOW(aPos); + CheckPosL(pos); + + const TUint startCluster = (TUint)iStartCluster; + const TUint length = (TUint)aLength; + + endPos = iCurrentPos.iPos + length; + if ((endPos > (TUint)Size()) || + (iCurrentPos.iPos > endPos) ) // Overflow condition + DoSetSizeL(iCurrentPos.iPos+length,EFalse); + + TUint startPos=iCurrentPos.iPos; + TInt badcluster=0; + TInt goodcluster=0; + + TRAPD(ret, FatMount().WriteToClusterListL(iCurrentPos,aLength,aSrc,aMessage,aOffset,badcluster, goodcluster)); + + if (ret == KErrCorrupt || ret == KErrDied) + { + if(startCluster == 0) + { //Empty File, revert all the clusters allocated. + TInt cluster = iStartCluster; + iStartCluster = 0; + SetSize(0); + FlushAllL(); + + iCurrentPos.iCluster = 0; + iCurrentPos.iPos = 0; + + FAT().FreeClusterListL(cluster); + FAT().FlushL(); + } + else + { //Calculate the clusters required based on file size, revert extra clusters if allocated. + const TUint curSize = (TUint)Size(); + TUint ClustersNeeded = curSize >> ClusterSizeLog2(); + if(curSize > (ClustersNeeded << ClusterSizeLog2())) + { + ClustersNeeded++; + } + + TInt cluster = iStartCluster; + while(--ClustersNeeded) + { + FAT().GetNextClusterL(cluster); + } + + iCurrentPos.iCluster = cluster; + + if (FAT().GetNextClusterL(cluster)) + { + FAT().FreeClusterListL(cluster); + } + + FAT().WriteFatEntryEofL(iCurrentPos.iCluster); + FAT().FlushL(); + } + } + + User::LeaveIfError(ret); + + if(badcluster != 0) + { + if(iStartCluster == badcluster) + { + iStartCluster = goodcluster; + FlushStartClusterL(); + } + else + { + TInt aCluster = iStartCluster; + do + { + if((TUint)badcluster == FAT().ReadL(aCluster)) + { + FAT().WriteL(aCluster, goodcluster); + FAT().FlushL(); + break; + } + } + while(FAT().GetNextClusterL(aCluster)); + } + } + aLength=iCurrentPos.iPos-startPos; + + if(FatMount().IsRuggedFSys() && pos+(TUint)aLength>(TUint)Size()) + { + WriteFileSizeL(pos+aLength); + } + + } + + +void CFatFileCB::WriteL(TInt aFilePos,TInt& aLength,const TAny* aSrc,const RMessagePtr2& aMessage) + { + WriteL(TInt64(aFilePos),aLength,(TDesC8*) aSrc,aMessage, 0); + } + + + +//----------------------------------------------------------------------------- + +void CFatFileCB::ResizeIndex(TInt aNewMult,TUint aNewSize) +// +// Resize the seek index to accomodate a larger or smaller filesize +// Assumes KSeekIndexSize is a power of 2. +// + { + + TInt maxNewIndex=aNewSize>>(ClusterSizeLog2()+aNewMult); + + + TInt index=0; + TInt indexEnd=KSeekIndexSize; + TInt newValEnd=maxNewIndex; + + if (iSeekIndexSize>diffSize) - 1; + TInt newVal=indexEnd-1; + TInt skip=(1< KSeekIndexSizeLog2) + { + ClearIndex(0); //-- Invalidate every entry. + } + else + { + while(newVal>=index) + { + + iSeekIndex[newVal--] = iSeekIndex[oldVal--]; + + + for(TInt i=skip;i>0;i--) + { + iSeekIndex[newVal--] = 0; + + } + } + } + } + iSeekIndexSize=aNewMult; + } + + +/** + Zero freed clusters in the index + + @param aNewSize new size of the file that the index corresponds to. + if = 0 all existing index will be zero filled +*/ +void CFatFileCB::ClearIndex(TUint aNewSize) + { + + if (!iSeekIndex) + return; + + if(aNewSize==0) + { + //-- zero fill all the array + Mem::FillZ(iSeekIndex, KSeekIndexSize*sizeof(TUint32)); + return; + } + + // Files that fill up a cluster exactly do not have a trailing empty + // cluster. So the entry for that position must also be invalidated + aNewSize--; + TInt firstInvalidIndex=aNewSize>>(iSeekIndexSize+ClusterSizeLog2()); + + TInt indexLen=KSeekIndexSize-firstInvalidIndex; + + Mem::FillZ(iSeekIndex+firstInvalidIndex, indexLen * sizeof(TUint32)); + } + +TInt CFatFileCB::CalcSeekIndexSize(TUint aSize) +// +// Find the nearest power of 2 > aSize +// + { + TInt count = 0; + const TUint indexSize=KSeekIndexSize<>=1)>0) + { + count++; + } + return (count - (KSeekIndexSizeLog2 + ClusterSizeLog2()) + 1); + } + +//----------------------------------------------------------------------------- + +void CFatFileCB::SetSizeL(TInt64 aSize) + { + __PRINT(_L("CFatFileCB::SetSizeL")); + + // FAT supports 32 bits only for file size + if (I64HIGH(aSize)) + User::Leave(KErrNotSupported); + + if(FatMount().IsRuggedFSys()) + DoSetSizeL(I64LOW(aSize),ETrue); + else + DoSetSizeL(I64LOW(aSize),EFalse); + } + + +void CFatFileCB::SetSizeL(TInt aSize) +// +// Envelope function around DoSetSizeL to enable aSize to +// be written to disk for rugged fat file system +// + { + SetSizeL(TInt64(aSize)); + } + +void CFatFileCB::DoSetSizeL(TUint aSize,TBool aIsSizeWrite) +// +// Extend or truncate the file. +// Expects the modified attribute and iSize are set afterwards. +// Does not alter iCurrentPos, the current file position. +// Writes size of file to disk if aIsSizeWrite set +// + { + __PRINT2(_L("CFatFileCB::DoSetSizeL sz:%d, fileWrite=%d"),aSize ,aIsSizeWrite); + + FatMount().CheckStateConsistentL(); + FatMount().CheckWritableL(); + + + // Can not change the file size if it is clamped + if(Mount().IsFileClamped(MAKE_TINT64(0,iStartCluster)) > 0) + User::Leave(KErrInUse); + + iFileSizeModified=ETrue; + + TInt newIndexMult=CalcSeekIndexSize(aSize); + if (iSeekIndex!=NULL && newIndexMult!=iSeekIndexSize) + ResizeIndex(newIndexMult,aSize); + if (aSize == 0) + { + if (Size() != 0) + { + ClearIndex(0); //-- clear seek index array + TInt cluster=iStartCluster; + iStartCluster = 0; + SetSize(0); + FlushAllL(); + CheckPosL(0); + FAT().FreeClusterListL(cluster); + FAT().FlushL(); + } + return; + } + if (aSize<(TUint)Size()) + { + if(aIsSizeWrite) // write file size if decreasing + WriteFileSizeL(aSize); + CheckPosL(aSize); + TInt cluster=iCurrentPos.iCluster; + if (FAT().GetNextClusterL(cluster)) + { + FAT().WriteFatEntryEofL(iCurrentPos.iCluster); + FAT().FreeClusterListL(cluster); + } + ClearIndex(aSize); + FAT().FlushL(); + return; + } + + TUint newSize=aSize>>ClusterSizeLog2(); // Number of clusters we now need + if (aSize > (newSize<>ClusterSizeLog2(); // Number of clusters we had previously + if (curSize>(oldSize<=0 at this point + const TUint length = endPos - startPos; + + // Store the position of cluster zero in aInfo + CFatMountCB& fatMount = FatMount(); + + TInt drvNo=-1; + TBusLocalDrive* locDrv; + if((fatMount.LocalDrive()->GetLocalDrive(locDrv)==KErrNone) && ((drvNo=GetLocalDriveNumber(locDrv))>=0) && (drvNo (TUint)Size()) + return KErrArgument; + + TRAP(r, FatMount().BlockMapReadFromClusterListL(iCurrentPos, length, aInfo)); + if (r != KErrNone) + return r; + + aStartPos = iCurrentPos.iPos; + if ((I64LOW(aStartPos) == (TUint)Size()) || ( I64LOW(aStartPos) == (myStartPos + length))) + return KErrCompletion; + else + return KErrNone; + } + + + +TInt CFatFileCB::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput) + { + switch(aInterfaceId) + { + case EExtendedFileInterface: + ((CFileCB::MExtendedFileInterface*&) aInterface) = this; + return KErrNone; + + case EBlockMapInterface: + aInterface = (CFileCB::MBlockMapInterface*) this; + return KErrNone; + + case EGetLocalDrive: + return FatMount().LocalDrive()->GetLocalDrive((TBusLocalDrive*&) aInterface); + + default: + return CFileCB::GetInterface(aInterfaceId,aInterface,aInput); + } + } + + + + +/** + Overwrites file's start cluster (iStartCluster) in its directory entry. +*/ +void CFatFileCB::FlushStartClusterL() + { + __PRINT(_L("CFatFileCB::FlushStartClusterL")); + + CFatMountCB& mount = FatMount(); + TFatDirEntry dirEntry; + + mount.ReadDirEntryL(iFileDirPos, dirEntry); //-- read this file's dir. entry + dirEntry.SetStartCluster(iStartCluster); //-- set new start cluster + mount.WriteDirEntryL(iFileDirPos, dirEntry);//-- write the entry back + } + + + + +