// 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 <e32math.h>
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(FileAttModified())
{
IndicateFileTimeModified(ETrue); //-- this will force writing file modification time to the media on Flush
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(FCB_FileSize());
}
TInt CFatFileCB::SeekToPosition(TUint aNewRelCluster, TUint 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<KSeekIndexSize,Fault(EFatFileSeekIndexTooSmall));
while(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=FCB_StartCluster();
return(aNewRelCluster);
}
iCurrentPos.iCluster=iSeekIndex[seekPos];
return(aNewRelCluster-((seekPos+1)<<iSeekIndexSize));
}
void CFatFileCB::SetSeekIndexValueL(TUint aRelCluster, TUint aStoredCluster)
//
// Sets a value in the seekindex
//
{
TInt seekPos=(aRelCluster>>iSeekIndexSize)-1;
__ASSERT_DEBUG(seekPos<KSeekIndexSize,Fault(EFatFileSeekIndexTooSmall));
__ASSERT_DEBUG(seekPos>=0,Fault(EFatFileSeekIndexTooSmall2));
iSeekIndex[seekPos] = aStoredCluster;
}
TBool CFatFileCB::IsSeekBackwards(TUint aPos)
//
// Return true if aPos<currentPos
//
{
TUint cluster=iCurrentPos.iCluster<<ClusterSizeLog2();
TInt offset=ClusterRelativePos(iCurrentPos.iPos);
TUint currentPos=cluster+offset;
return(aPos<currentPos);
}
void CFatFileCB::CheckPosL(TUint aPos)
//
// Check that the file is positioned correctly.
// If aPos<currentPos attempt to guess the new position.
//
{
__PRINT1(_L("CFatFileCB::CheckPosL(%d)"), aPos);
if (aPos==iCurrentPos.iPos)
return;
__ASSERT_DEBUG(aPos <= FCB_FileSize(), Fault(EFatFilePosBeyondEnd));
if (FileSizeModified() && IsSeekBackwards(aPos))
FlushDataL();
TUint newRelCluster=aPos>>ClusterSizeLog2();
if ( aPos && (aPos==(newRelCluster<<ClusterSizeLog2())) )
newRelCluster--;
TUint oldRelCluster=iCurrentPos.iPos>>ClusterSizeLog2();
if ( iCurrentPos.iPos && (iCurrentPos.iPos==(oldRelCluster<<ClusterSizeLog2())) )
oldRelCluster--;
TInt clusterOffset=newRelCluster-oldRelCluster;
TUint32 oldCluster=iCurrentPos.iCluster;
iCurrentPos.iPos=aPos;
if (clusterOffset==0)
return;
TInt seekOffset=clusterOffset;
if (iSeekIndex!=NULL)
{ // Can alter iCurrentPos.iCluster
seekOffset=SeekToPosition(newRelCluster,seekOffset);
if (seekOffset==0)
return;
}
if (clusterOffset==-1 && seekOffset!=1)
{ // Check previous cluster
TUint32 cluster=oldCluster-1;
if (FAT().GetNextClusterL(cluster) && cluster==oldCluster)
{
iCurrentPos.iCluster=oldCluster-1;
return;
}
}
if (seekOffset<0)
{
seekOffset=newRelCluster;
iCurrentPos.iCluster=FCB_StartCluster();
}
while (seekOffset--)
{
if (!FAT().GetNextClusterL(iCurrentPos.iCluster))
{
__PRINT(_L("CFatFileCB::CheckPosL() corrupt#1"));
User::Leave(KErrCorrupt);
}
TInt cluster=newRelCluster-seekOffset;
if (iSeekIndex!=NULL && cluster && (cluster>>iSeekIndexSize)<<iSeekIndexSize==cluster)
SetSeekIndexValueL(cluster,iCurrentPos.iCluster);
}
}
//-----------------------------------------------------------------------------
/**
Initialize FileCB from file's entry data.
@param aFatDirEntry this file DOS dir entry.
@param aFileDosEntryPos this file DOS entry dir. iterator in the parent directory.
*/
void CFatFileCB::SetupL(const TFatDirEntry& aFatDirEntry, const TEntryPos& aFileDosEntryPos)
{
__PRINT1(_L("CFatFileCB::SetupL[0x%x]"), this);
//-- set up a file control block
iCurrentPos.iCluster= FatMount().StartCluster(aFatDirEntry);
iCurrentPos.iPos=0;
SetAtt(aFatDirEntry.Attributes());
SetModified(aFatDirEntry.Time(FatMount().TimeOffset()));
FCB_SetStartCluster(iCurrentPos.iCluster);
FCB_SetFileSize(aFatDirEntry.Size());
iFileDosEntryPos = aFileDosEntryPos;
SetMaxSupportedSize(KMaxSupportedFatFileSize);
//-- create seek index
ASSERT(!iSeekIndex);
CreateSeekIndex();
if(!iSeekIndex)
User::Leave(KErrNoMemory);
IndicateFileAttModified(EFalse);
IndicateFileSizeModified(EFalse);
IndicateFileTimeModified(EFalse);
}
//-----------------------------------------------------------------------------
/**
Read data from the file.
@param aFilePos start read position within a file
@param aLength how many bytes to read; on return will be how many bytes actually read
@param aDes local buffer desctriptor
@param aMessage from file server, used to write data to the buffer in different address space.
@param aDesOffset offset within data descriptor where the data will be copied
@leave on media read error
*/
void CFatFileCB::ReadL(TInt64 aPos,TInt& aLength, TDes8* aDes, const RMessagePtr2& aMessage, TInt aOffset)
{
__PRINT3(_L("CFatFileCB::ReadL[0x%x] pos=%LU len=%d"), this, aPos, aLength);
if((TUint64)aPos > 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 = FCB_FileSize();
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);
}
//-----------------------------------------------------------------------------
/**
Write data to the file.
@param aFilePos start write position within a file
@param aLength how many bytes to write; on return contain amount of data actually written
@param aDes local buffer desctriptor
@param aMessage from file server, used to write data to the media from different address space.
@param aDesOffset offset within data descriptor
@leave on media read error
*/
void CFatFileCB::WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aSrc,const RMessagePtr2& aMessage, TInt aOffset)
{
__PRINT3(_L("CFatFileCB::WriteL[0x%x] pos=%LU len=%d"), this, 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 = FCB_StartCluster();
const TUint length = (TUint)aLength;
endPos = iCurrentPos.iPos + length;
if ((endPos > FCB_FileSize()) ||
(iCurrentPos.iPos > endPos) ) // Overflow condition
DoSetSizeL(iCurrentPos.iPos+length,EFalse);
TUint startPos=iCurrentPos.iPos;
TUint badcluster=0;
TUint 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.
const TUint32 cluster = FCB_StartCluster();
FCB_SetStartCluster(0);
FCB_SetFileSize(0);
IndicateFileSizeModified(ETrue);
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 = FCB_FileSize();
TUint ClustersNeeded = curSize >> ClusterSizeLog2();
if(curSize > (ClustersNeeded << ClusterSizeLog2()))
{
ClustersNeeded++;
}
TUint32 cluster = FCB_StartCluster();
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(FCB_StartCluster() == badcluster)
{
FCB_SetStartCluster(goodcluster);
FlushStartClusterL();
}
else
{
TUint32 aCluster = FCB_StartCluster();
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 > FCB_FileSize())
{
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<aNewMult)
{
TInt newVal=index;
TInt step=1<<(aNewMult-iSeekIndexSize);
index+=step-1;
while(index<indexEnd && newVal<newValEnd)
{
iSeekIndex[newVal] = iSeekIndex[index];
newVal++;
index+=step;
}
while(newVal<indexEnd)
iSeekIndex[newVal++] = 0;
}
else
{
TInt diffSize = iSeekIndexSize-aNewMult;
TInt oldVal=(KSeekIndexSize>>diffSize) - 1;
TInt newVal=indexEnd-1;
TInt skip=(1<<diffSize)-1;
if ((iSeekIndexSize - aNewMult) > 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<<ClusterSizeLog2();//KSeekIndexSize=128
if (aSize<=indexSize)
return(count);
while((aSize>>=1)>0)
{
count++;
}
return (count - (KSeekIndexSizeLog2 + ClusterSizeLog2()) + 1);
}
//-----------------------------------------------------------------------------
/**
Set file size.
@param aSize new file size.
*/
void CFatFileCB::SetSizeL(TInt64 aSize)
{
__PRINT2(_L("CFatFileCB::SetSizeL[0x%x] sz=%LU"), this, aSize);
//-- max. file size for FAT is 4GB-1
if (I64HIGH(aSize))
User::Leave(KErrNotSupported);
DoSetSizeL(I64LOW(aSize), FatMount().IsRuggedFSys());
}
void CFatFileCB::SetSizeL(TInt aSize)
{
SetSizeL(TInt64(aSize));
}
//-----------------------------------------------------------------------------
/**
Shrink file to zero size.
*/
void CFatFileCB::DoShrinkFileToZeroSizeL()
{
ASSERT(FCB_FileSize());
ASSERT(FileSizeModified());
ClearIndex(0); //-- clear seek index array
//-- update file dir. entry
const TUint32 cluster = FCB_StartCluster();
FCB_SetStartCluster(0);
FCB_SetFileSize(0);
FlushAllL();
//-- free cluster list.
CheckPosL(0);
FAT().FreeClusterListL(cluster);
FAT().FlushL();
}
//-----------------------------------------------------------------------------
/*
Shrink file to smaller size, but > 0
@param aNewSize new file size
@param aForceCachesFlush if ETrue, all file/FAT caches will be flushed
*/
void CFatFileCB::DoShrinkFileL(TUint32 aNewSize, TBool aForceCachesFlush)
{
ASSERT(FileSizeModified());
ASSERT(FCB_FileSize() > aNewSize && aNewSize);
if(aForceCachesFlush)
WriteFileSizeL(aNewSize); //-- write file size directly to its dir. entry
CheckPosL(aNewSize);
TUint32 cluster=iCurrentPos.iCluster;
if (FAT().GetNextClusterL(cluster))
{//-- truncate the cluster chain
FAT().WriteFatEntryEofL(iCurrentPos.iCluster);
FAT().FreeClusterListL(cluster);
}
ClearIndex(aNewSize);
FAT().FlushL();
}
//-----------------------------------------------------------------------------
/**
Expand a file.
@param aNewSize new file size.
@param aForceCachesFlush if ETrue, all file/FAT caches will be flushed
*/
void CFatFileCB::DoExpandFileL(TUint32 aNewSize, TBool aForceCachesFlush)
{
ASSERT(FCB_FileSize() < aNewSize);
ASSERT(FileSizeModified());
const TUint32 KClusterSzLog2 = ClusterSizeLog2();
const TUint32 newSizeClusters = (TUint32)(((TUint64)aNewSize + Pow2(KClusterSzLog2) - 1) >> KClusterSzLog2);
//-- expanding a file
if (FCB_StartCluster() == 0)
{//-- the initial file size is 0 (no cluster chain)
ClearIndex(0); //-- clear seek index array
//-- FAT().FreeClusterHint() will give us a hint of the last free cluster
const TUint32 tempStartCluster=FAT().AllocateClusterListL(newSizeClusters, FAT().FreeClusterHint());
FAT().FlushL();
iCurrentPos.iCluster=tempStartCluster;
FCB_SetStartCluster(tempStartCluster);
FCB_SetFileSize(aNewSize);
FlushAllL();
}
else
{
const TUint curSize = FCB_FileSize();
const TUint32 oldSizeClusters = ((curSize + Pow2(KClusterSzLog2) - 1) >> KClusterSzLog2);
ASSERT(newSizeClusters >= oldSizeClusters);
const TUint newClusters = newSizeClusters-oldSizeClusters; //-- Number of clusters we need to append to the existing cluster chain
if (newClusters)
{
TEntryPos currentPos=iCurrentPos;
CheckPosL(FCB_FileSize());
FAT().ExtendClusterListL(newClusters,iCurrentPos.iCluster);
iCurrentPos=currentPos;
}
FAT().FlushL();
if(aForceCachesFlush) // write file size if increasing
WriteFileSizeL(aNewSize);
}
}
//-----------------------------------------------------------------------------
/**
Set file size. This can involve extending/truncating file's cluster chain.
@param aSize new file size
@param aForceCachesFlush if ETrue, all changes in metadata will go to the media immediately.
it is used in Rugged FAT mode.
*/
void CFatFileCB::DoSetSizeL(TUint aSize, TBool aForceCachesFlush)
{
__PRINT4(_L("CFatFileCB::DoSetSizeL[0x%x] sz:%d, oldSz:%d, flush:%d"), this, aSize, FCB_FileSize(), aForceCachesFlush);
FatMount().CheckStateConsistentL();
FatMount().CheckWritableL();
// Can not change the file size if it is clamped
if(Mount().IsFileClamped(MAKE_TINT64(0,FCB_StartCluster())) > 0)
User::Leave(KErrInUse);
if(aSize == FCB_FileSize())
return;
IndicateFileSizeModified(ETrue);
TInt newIndexMult=CalcSeekIndexSize(aSize);
if (iSeekIndex!=NULL && newIndexMult!=iSeekIndexSize)
ResizeIndex(newIndexMult,aSize);
//-------------------------------------------
//-- shrinking file to 0 size
if(aSize == 0)
{
DoShrinkFileToZeroSizeL();
return;
}
//-------------------------------------------
//-- shrinking file to non-zero size
if (aSize < FCB_FileSize())
{
DoShrinkFileL(aSize, aForceCachesFlush);
return;
}
//-------------------------------------------
//-- expanding a file
DoExpandFileL(aSize, aForceCachesFlush);
}
//-----------------------------------------------------------------------------
/**
Set file entry details, like file attributes and modified time
This method doesn't write data to the media immediately, instead, all modified data are cached and can be flushed later
in FlushAllL()
@param aTime file modification time (and last access as well)
@param aSetAttMask file attributes OR mask
@param aClearAttMask file attributes AND mask
*/
void CFatFileCB::SetEntryL(const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
{
__PRINT1(_L("CFatFileCB::SetEntryL[0x%x]"), this);
FatMount().CheckStateConsistentL();
FatMount().CheckWritableL();
//-- change file attributes
const TUint setAttMask = (aSetAttMask & KEntryAttMaskSupported); //-- supported attributes to set
TUint newAtt = Att();
if (setAttMask|aClearAttMask)
{
newAtt |= setAttMask;
newAtt &= ~aClearAttMask;
SetAtt(newAtt);
IndicateFileAttModified(ETrue); //-- indicate that file attributes have changed
}
//-- set file entry modification time if required
if (aSetAttMask&KEntryAttModified)
{
SetModified(aTime); //-- set file modified time
IndicateFileAttModified(ETrue); //-- indicate that file attributes have changed
IndicateFileTimeModified(ETrue); //-- this will force writing file mod. time to the media on Flush
}
}
//-----------------------------------------------------------------------------
/**
The same as FlushAllL(). This method is called from RFile::Flush()
*/
void CFatFileCB::FlushDataL()
{
__PRINT1(_L("CFatFileCB::FlushDataL[0x%x]"), this);
FlushAllL();
}
//-----------------------------------------------------------------------------
/**
Flush the fide directory entry data: files size, attributes, time etc.
*/
void CFatFileCB::FlushAllL()
{
//-- define this symbol in order to enable legacy behaviour, i.e. compulsory updating file dir. entry on flush.
//-- otherwise the FlushAllL() will update the file dir. entry only if it differs from what is on the media, i.e.
//-- file size, start cluster, attributes and modification timestamp
#define ALWAYS_UPDATE_ENTRY_ON_FLUSH
__PRINT1(_L("CFatFileCB::FlushAllL[0x%x]"), this);
if (Mount().IsCurrentMount()==EFalse)
User::Leave(KErrDisMounted);
FatMount().CheckStateConsistentL();
FatMount().CheckWritableL();
if(!FileSizeModified() && !FileAttModified() && !FileTimeModified())
return; //-- nothing has changed in the file entry at all
//-- read file dir. entry
TFatDirEntry entry;
FatMount().ReadDirEntryL(iFileDosEntryPos,entry);
__ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
//-- the problem with KEntryAttModified here is that the file server uses this flag to
//-- deal with dirty file data. This means that this flag can be set even if there were no changes
//-- in file time and attributes. Just check if any of the entry field has changed at all
TBool bUpdateDirEntry = ETrue;
const TTimeIntervalSeconds timeOffset = FatMount().TimeOffset();
#ifndef ALWAYS_UPDATE_ENTRY_ON_FLUSH
TBool bTimeModified = FileTimeModified(); //-- check if file modifiication time has been changed explicitly
if(bTimeModified)
{//-- additional check; for FAT entry modification time has 2 sec. granularity.
bTimeModified = !entry.IsTimeTheSame(iModified, timeOffset);
}
if(!bTimeModified)
if(//-- TS is the same as on the media, check other entry fields
(entry.Attributes() == (Att() & KEntryAttMaskSupported)) && //-- file attributes have not changed
(entry.Size() == FCB_FileSize()) && //-- file size hasn't changed
(entry.StartCluster() == FCB_StartCluster()) //-- file start cluster hasn't changed
)
{
bUpdateDirEntry = EFalse; //-- no need to update file dir. entry
}
#endif //#ifndef ALWAYS_UPDATE_ENTRY_TS_ON_FLUSH
if(bUpdateDirEntry)
{//-- write entry to the media
__PRINT(_L(" CFatFileCB::FlushAllL #1"));
entry.SetAttributes(Att() & KEntryAttMaskSupported);
entry.SetSize(FCB_FileSize());
entry.SetTime(iModified, timeOffset);
entry.SetStartCluster(FCB_StartCluster());
const TBool setNotify = FatMount().GetNotifyUser();
if(setNotify)
{
FatMount().SetNotifyOff(); // do not launch a notifier
}
TRAPD(ret, FatMount().WriteDirEntryL(iFileDosEntryPos,entry));
if(setNotify)
{
FatMount().SetNotifyOn();
}
User::LeaveIfError(ret);
IndicateFileSizeModified(EFalse);
IndicateFileTimeModified(EFalse);
}
//-- KEntryAttModified must be reset anyway
IndicateFileAttModified(EFalse);
}
//-----------------------------------------------------------------------------
/**
Rename already opened file.
@param aNewName new file name; all trailing dots from the name will be removed
*/
void CFatFileCB::RenameL(const TDesC& aNewName)
{
__PRINT2(_L("CFatFileCB::RenameL[0x%x], name:%S"),this, &aNewName);
FatMount().CheckStateConsistentL();
FatMount().CheckWritableL();
const TPtrC fileName = RemoveTrailingDots(aNewName); //-- remove trailing dots from the name
FatMount().DoRenameOrReplaceL(*iFileName, fileName, CFatMountCB::EModeRename, iFileDosEntryPos);
AllocBufferL(iFileName, fileName);
if(!FatMount().IsRuggedFSys())
FAT().FlushL();
}
//***********************************************************
//* BlockMap interface
//***********************************************************
TInt CFatFileCB::BlockMap(SBlockMapInfo& aInfo, TInt64& aStartPos, TInt64 aEndPos)
//
// Retrieves the block map of a given section of the file, in the FAT file system.
//
{
__PRINT2(_L("CFatFileCB::BlockMap aStartPos=%ld aEndPos=%ld"), aStartPos, aEndPos);
if ( I64HIGH(aStartPos) || I64HIGH(aEndPos) )
return KErrNotSupported;
TUint startPos = I64LOW(aStartPos);
TUint endPos = I64LOW(aEndPos);
// aEndPos will always be >=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<KMaxLocalDrives))
aInfo.iLocalDriveNumber=drvNo;
else
return KErrNotSupported;
// Fetch the address of cluster 0
aInfo.iStartBlockAddress = fatMount.FAT().DataPositionInBytes(KFirstClusterNum);
TRAPD(r, CheckPosL(startPos));
if (r != KErrNone)
return r;
aInfo.iBlockStartOffset = fatMount.ClusterRelativePos(iCurrentPos.iPos);
aInfo.iBlockGranularity = 1 << FatMount().ClusterSizeLog2();
const TUint myStartPos = iCurrentPos.iPos;
if ( myStartPos + length > FCB_FileSize())
return KErrArgument;
TRAP(r, FatMount().BlockMapReadFromClusterListL(iCurrentPos, length, aInfo));
if (r != KErrNone)
return r;
aStartPos = iCurrentPos.iPos;
if ((I64LOW(aStartPos) == FCB_FileSize()) || ( 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()
{
__PRINT1(_L("CFatFileCB::FlushStartClusterL[0x%x]"), this);
CFatMountCB& mount = FatMount();
TFatDirEntry dirEntry;
mount.ReadDirEntryL(iFileDosEntryPos, dirEntry); //-- read this file's dir. entry
dirEntry.SetStartCluster(FCB_StartCluster()); //-- set new start cluster
mount.WriteDirEntryL(iFileDosEntryPos, dirEntry);//-- write the entry back
}
/**
This is a RuggedFAT - specific method. Writes file size to the corresponding field of its file directory entry.
*/
void CFatFileCB::WriteFileSizeL(TUint aSize)
{
__PRINT2(_L("CFatFileCB::WriteFileSizeL[0x%x], sz:%d"), this, aSize);
CFatMountCB& mount = FatMount();
TFatDirEntry dirEntry;
mount.ReadDirEntryL(iFileDosEntryPos, dirEntry); //-- read this file's dir. entry
dirEntry.SetSize(aSize); //-- set new size
mount.WriteDirEntryL(iFileDosEntryPos, dirEntry);//-- write the entry back
IndicateFileSizeModified(EFalse);
}