userlibandfileserver/fileserver/sfat32/sl_file.cpp
branchRCL_3
changeset 22 2f92ad2dc5db
parent 2 4122176ea935
child 41 0ffb4e86fcc9
--- a/userlibandfileserver/fileserver/sfat32/sl_file.cpp	Mon Mar 15 12:45:50 2010 +0200
+++ b/userlibandfileserver/fileserver/sfat32/sl_file.cpp	Wed Mar 31 23:38:45 2010 +0300
@@ -25,13 +25,12 @@
 
 CFatFileCB::CFatFileCB()
 	{
-
 	__PRINT1(_L("CFatFileCB created 0x%x"),this);
 	}
 
 CFatFileCB::~CFatFileCB()
 	{
-	__PRINT1(_L("CFatFileCB deleted 0x%x"),this);
+	__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()
@@ -39,9 +38,12 @@
     const CMountCB* pMount  = &Mount();
     if(pMount)
         {//-- do some finalisation work if CMountCB is valid
-        if (iAtt&KEntryAttModified)
+        if(FileAttModified())
+            {
+            IndicateFileTimeModified(ETrue); //-- this will force writing file modification time to the media on Flush
             TRAP_IGNORE(FlushAllL());
         }
+        }
 
     delete[] iSeekIndex;
 	}
@@ -59,10 +61,10 @@
 
 	Mem::FillZ(iSeekIndex, sizeof(TUint32) * KSeekIndexSize);
 
-	iSeekIndexSize=CalcSeekIndexSize(Size());
+	iSeekIndexSize=CalcSeekIndexSize(FCB_FileSize());
 	}
 
-TInt CFatFileCB::SeekToPosition(TInt aNewRelCluster,TInt aClusterOffset)
+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
@@ -81,7 +83,7 @@
 		return(aClusterOffset);
 	if (seekPos<0)
 		{
-		iCurrentPos.iCluster=iStartCluster;
+		iCurrentPos.iCluster=FCB_StartCluster();
 		return(aNewRelCluster);
 		}
 
@@ -89,7 +91,7 @@
 	return(aNewRelCluster-((seekPos+1)<<iSeekIndexSize));
 	}
 
-void CFatFileCB::SetSeekIndexValueL(TInt aRelCluster,TInt aStoredCluster)
+void CFatFileCB::SetSeekIndexValueL(TUint aRelCluster, TUint aStoredCluster)
 //
 // Sets a value in the seekindex
 //
@@ -122,19 +124,22 @@
 	__PRINT1(_L("CFatFileCB::CheckPosL(%d)"), aPos);
 	if (aPos==iCurrentPos.iPos)
 		return;
-    __ASSERT_DEBUG(aPos <= (TUint)Size(), Fault(EFatFilePosBeyondEnd));
+    __ASSERT_DEBUG(aPos <= FCB_FileSize(), Fault(EFatFilePosBeyondEnd));
 
-	if (iFileSizeModified && IsSeekBackwards(aPos))
+	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;
-	TInt oldCluster=iCurrentPos.iCluster;
+	TUint32 oldCluster=iCurrentPos.iCluster;
+
 	iCurrentPos.iPos=aPos;
 	if (clusterOffset==0)
 		return;
@@ -147,7 +152,7 @@
 		}
 	if (clusterOffset==-1 && seekOffset!=1)
 		{ // Check previous cluster
-		TInt cluster=oldCluster-1;
+		TUint32 cluster=oldCluster-1;
 		if (FAT().GetNextClusterL(cluster) && cluster==oldCluster)
 			{
             iCurrentPos.iCluster=oldCluster-1;
@@ -157,7 +162,7 @@
 	if (seekOffset<0)
 		{
 		seekOffset=newRelCluster;
-		iCurrentPos.iCluster=iStartCluster;
+		iCurrentPos.iCluster=FCB_StartCluster();
 		}
 	while (seekOffset--)
 		{
@@ -172,30 +177,60 @@
 		}
 	}
 
-void CFatFileCB::SetL(const TFatDirEntry& aFatDirEntry,TShare aShare,const TEntryPos& aPos)
-//
-// Initialize FileCB from entry data
-//
+//-----------------------------------------------------------------------------
+/** 
+    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);
+	
 
-	__PRINT(_L("CFatFileCB::SetL"));
-	SetSize(aFatDirEntry.Size()); 
+    //-- set up a file control block
 	iCurrentPos.iCluster= FatMount().StartCluster(aFatDirEntry);
-	iStartCluster=iCurrentPos.iCluster;
 	iCurrentPos.iPos=0;
-	iAtt=aFatDirEntry.Attributes();
-	iModified= aFatDirEntry.Time(FatMount().TimeOffset());
-	iShare=aShare;
-	iFileDirPos=aPos;
+	
+    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);
 	}
 
 //-----------------------------------------------------------------------------
-// from CFileCB::MExtendedFileInterface
+/**
+    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)
 	{
-	__PRINT2(_L("CFatFileCB::ReadL aFilePos=%LU aLength=%d"),aPos,aLength);
+	__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
@@ -205,7 +240,7 @@
 	CheckPosL(I64LOW(aPos));
 	
 	const TUint startPos = iCurrentPos.iPos;
-	const TUint curSize  = (TUint)Size();
+	const TUint curSize  = FCB_FileSize();
 	const TUint length   = (TUint)aLength;
 	
 	if((startPos + length > curSize) || (startPos > startPos + length) )
@@ -222,10 +257,22 @@
 	}
 
 //-----------------------------------------------------------------------------
-// from CFileCB::MExtendedFileInterface
+/**
+    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)
 	{
-	__PRINT2(_L("CFatFileCB::WriteL aFilePos=%LU aLength=%d"),aPos,aLength);
+	__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)
@@ -236,17 +283,17 @@
     const TUint pos = I64LOW(aPos);
   	CheckPosL(pos);
   	
-	const TUint startCluster = (TUint)iStartCluster;
+	const TUint startCluster = FCB_StartCluster();
 	const TUint length       = (TUint)aLength;
 	
 	endPos = iCurrentPos.iPos + length; 
-	if ((endPos           > (TUint)Size()) ||
+	if ((endPos           > FCB_FileSize()) ||
 	    (iCurrentPos.iPos > endPos)         ) // Overflow condition 
 		DoSetSizeL(iCurrentPos.iPos+length,EFalse);
    	
 	TUint startPos=iCurrentPos.iPos;
-	TInt badcluster=0;
-	TInt goodcluster=0;
+	TUint badcluster=0;
+	TUint goodcluster=0;
    	
 	TRAPD(ret, FatMount().WriteToClusterListL(iCurrentPos,aLength,aSrc,aMessage,aOffset,badcluster, goodcluster));
    	
@@ -254,9 +301,11 @@
 		{
         if(startCluster == 0)
 			{ //Empty File, revert all the clusters allocated.
-			TInt cluster = iStartCluster;
-			iStartCluster = 0;
-			SetSize(0);
+			const TUint32 cluster = FCB_StartCluster();
+			FCB_SetStartCluster(0);
+			FCB_SetFileSize(0);
+			IndicateFileSizeModified(ETrue);
+            
 			FlushAllL();
 
 			iCurrentPos.iCluster = 0;
@@ -267,14 +316,14 @@
 			}
 		else
 			{ //Calculate the clusters required based on file size, revert extra clusters if allocated.
-			const TUint curSize = (TUint)Size();
+			const TUint curSize = FCB_FileSize();
 			TUint ClustersNeeded = curSize >> ClusterSizeLog2();
 			if(curSize > (ClustersNeeded << ClusterSizeLog2()))
 				{
 				ClustersNeeded++;
 				}
 
-			TInt cluster = iStartCluster;
+			TUint32 cluster = FCB_StartCluster();
 			while(--ClustersNeeded)
 				{
 				FAT().GetNextClusterL(cluster);
@@ -296,14 +345,14 @@
 
 	if(badcluster != 0)
 		{
-		if(iStartCluster == badcluster)
+		if(FCB_StartCluster() == badcluster)
 			{
-			iStartCluster = goodcluster;
+            FCB_SetStartCluster(goodcluster);
 			FlushStartClusterL();
 			}
 		else
 			{
-			TInt aCluster = iStartCluster;
+			TUint32 aCluster = FCB_StartCluster();
 			do
 				{
                 if((TUint)badcluster == FAT().ReadL(aCluster))
@@ -318,7 +367,7 @@
 		}
 	aLength=iCurrentPos.iPos-startPos;
 
-	if(FatMount().IsRuggedFSys() && pos+(TUint)aLength>(TUint)Size())
+	if(FatMount().IsRuggedFSys() && pos+(TUint)aLength > FCB_FileSize())
 		{
 		WriteFileSizeL(pos+aLength);
 		}
@@ -441,169 +490,228 @@
 	}
 
 //-----------------------------------------------------------------------------
-
+/**
+    Set file size.
+    @param aSize new file size.
+*/
 void CFatFileCB::SetSizeL(TInt64 aSize)
 	{
-	__PRINT(_L("CFatFileCB::SetSizeL"));
+	__PRINT2(_L("CFatFileCB::SetSizeL[0x%x] sz=%LU"), this, aSize);
 	
-	// FAT supports 32 bits only for file size
+	//-- max. file size for FAT is 4GB-1
 	if (I64HIGH(aSize))
 		User::Leave(KErrNotSupported);
 
-	if(FatMount().IsRuggedFSys())
-		DoSetSizeL(I64LOW(aSize),ETrue);
-	else
-		DoSetSizeL(I64LOW(aSize),EFalse);
+    DoSetSizeL(I64LOW(aSize), FatMount().IsRuggedFSys());
 	}
 
 
 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
-//
+//-----------------------------------------------------------------------------
+/**
+    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)
 	{
-	__PRINT2(_L("CFatFileCB::DoSetSizeL sz:%d, fileWrite=%d"),aSize ,aIsSizeWrite);
+	__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,iStartCluster)) > 0)
+	if(Mount().IsFileClamped(MAKE_TINT64(0,FCB_StartCluster())) > 0)
 		User::Leave(KErrInUse);
 	
-	iFileSizeModified=ETrue;
+	if(aSize == FCB_FileSize())
+        return;
+
+    IndicateFileSizeModified(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())
+
+	//-------------------------------------------
+    //-- shrinking file to 0 size
+    if(aSize == 0)
+        {
+        DoShrinkFileToZeroSizeL();
+        return;
+        }
+
+    //-------------------------------------------
+	//-- shrinking file to non-zero size
+    if (aSize < FCB_FileSize())
 		{
-		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()))
-		newSize++;	//	File size is not an exact multiple of cluster size
-					//	Increment the number of clusters required to accomodate tail
-	
-	if (iStartCluster==0)
-		{
-        //-- FAT().FreeClusterHint() will give us a hint of the last free cluster
-        ClearIndex(0); //-- clear seek index array
-        TInt tempStartCluster=FAT().AllocateClusterListL(newSize, FAT().FreeClusterHint());
-		FAT().FlushL();
-		iCurrentPos.iCluster=tempStartCluster;
-		iStartCluster=tempStartCluster;
-		SetSize(aSize);
-		FlushAllL();
-		}
-	else
-		{
-		const TUint curSize = (TUint)Size(); 
-		TUint oldSize=curSize>>ClusterSizeLog2();	//	Number of clusters we had previously
-		if (curSize>(oldSize<<ClusterSizeLog2()))
-			oldSize++;
-	
-		TInt newClusters=newSize-oldSize;	//	Number of clusters we need to prepare
-		if (newClusters)
-			{
-			TEntryPos currentPos=iCurrentPos;
-			CheckPosL(Size());
-			FAT().ExtendClusterListL(newClusters,iCurrentPos.iCluster);
-			iCurrentPos=currentPos;
-			}
-		FAT().FlushL();
-		if(aIsSizeWrite)			// write file size if increasing
-			WriteFileSizeL(aSize);
-		}
+        DoShrinkFileL(aSize, aForceCachesFlush);
+        return;
+        }
+    
+    //-------------------------------------------
+	//-- expanding a file
+    DoExpandFileL(aSize, aForceCachesFlush);
+
 	}
 
 //-----------------------------------------------------------------------------
 /**
-    Set the entry's attributes and modified time.
+    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)
 	{
-	__PRINT(_L("CFatFileCB::SetEntryL"));
+	__PRINT1(_L("CFatFileCB::SetEntryL[0x%x]"), this);
     
     FatMount().CheckStateConsistentL();
     FatMount().CheckWritableL();
 
-	TUint setAttMask=aSetAttMask&KEntryAttMaskSupported;
+    //-- change file attributes
+    const TUint setAttMask = (aSetAttMask & KEntryAttMaskSupported); //-- supported attributes to set
+    TUint newAtt = Att();
+
 	if (setAttMask|aClearAttMask)
 		{
-		iAtt|=setAttMask;
-		iAtt&=(~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)
-		iModified=aTime;
-	iAtt|=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
+        }
+
 	}
 
-/**
-    This is a RuggedFAT - specific method. Writes file size to the corresponding field of this
-    file direcrory entry.
-*/
-void CFatFileCB::WriteFileSizeL(TUint aSize)
-	{
-	__PRINT(_L("CFatFileCB::WriteFileSizeL"));
-	TEntryPos entryPos=iFileDirPos;
-	entryPos.iPos+=_FOFF(SFatDirEntry,iSize);
-	TPtrC8 size((TUint8*)&aSize,sizeof(TUint));
-	
-    //-- use directory cache when dealing with directories
-    FatMount().DirWriteL(entryPos,size);
-	iFileSizeModified=EFalse;
-    }
 
 //-----------------------------------------------------------------------------
 /** 
-    Flush file size, attributes, time etc. to the media.
-    It doesn't matter if whole directory entry is being written of only part of it. Anyway, a single DOS
-    dir. entry always fits into 1 sector.
+    The same as FlushAllL(). This method is called from RFile::Flush()
 */
 void CFatFileCB::FlushDataL()
 	{
-	__PRINT(_L("CFatFileCB::FlushDataL"));
+	__PRINT1(_L("CFatFileCB::FlushDataL[0x%x]"), this);
     FlushAllL();
 	}
 
@@ -613,7 +721,13 @@
 */
 void CFatFileCB::FlushAllL()
 	{
-	__PRINT(_L("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);
@@ -621,21 +735,58 @@
     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(iFileDirPos,entry);
+	FatMount().ReadDirEntryL(iFileDosEntryPos,entry);
 	__ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
-	entry.SetAttributes(iAtt&KEntryAttMaskSupported);
-	entry.SetSize(Size());
-	entry.SetTime(iModified, FatMount().TimeOffset());
-	entry.SetStartCluster(iStartCluster);
+
+    //-- 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);
+        }
 
-	TBool setNotify = FatMount().GetNotifyUser();
+    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(iFileDirPos,entry));
+	    TRAPD(ret, FatMount().WriteDirEntryL(iFileDosEntryPos,entry));
 	
 	if(setNotify)
 		{
@@ -643,8 +794,14 @@
 		}
 
 	User::LeaveIfError(ret);
-	iAtt&=(~KEntryAttModified);
-	iFileSizeModified=EFalse;
+
+        IndicateFileSizeModified(EFalse);
+        IndicateFileTimeModified(EFalse);
+	    }
+
+
+        //-- KEntryAttModified must be reset anyway
+        IndicateFileAttModified(EFalse); 
 	}
 
 //-----------------------------------------------------------------------------
@@ -663,7 +820,7 @@
     const TPtrC fileName = RemoveTrailingDots(aNewName); //-- remove trailing dots from the name
 
 
-	FatMount().DoRenameOrReplaceL(*iFileName, fileName, CFatMountCB::EModeRename,iFileDirPos);
+	FatMount().DoRenameOrReplaceL(*iFileName, fileName, CFatMountCB::EModeRename, iFileDosEntryPos);
 	
     AllocBufferL(iFileName, fileName);
 	
@@ -712,7 +869,7 @@
 	aInfo.iBlockStartOffset = fatMount.ClusterRelativePos(iCurrentPos.iPos);
 	aInfo.iBlockGranularity = 1 << FatMount().ClusterSizeLog2();
 	const TUint myStartPos = iCurrentPos.iPos;
-	if ( myStartPos + length > (TUint)Size())
+	if ( myStartPos + length > FCB_FileSize())
 		return KErrArgument;
 
 	TRAP(r, FatMount().BlockMapReadFromClusterListL(iCurrentPos, length, aInfo));
@@ -720,7 +877,7 @@
 		return r;
 
 	aStartPos = iCurrentPos.iPos;
-	if ((I64LOW(aStartPos) == (TUint)Size()) || ( I64LOW(aStartPos) == (myStartPos + length)))
+	if ((I64LOW(aStartPos) == FCB_FileSize()) || ( I64LOW(aStartPos) == (myStartPos + length)))
 		return KErrCompletion;
 	else
 		return KErrNone;
@@ -756,17 +913,37 @@
 */
 void CFatFileCB::FlushStartClusterL()
 	{
-	__PRINT(_L("CFatFileCB::FlushStartClusterL"));
+	__PRINT1(_L("CFatFileCB::FlushStartClusterL[0x%x]"), this);
 
     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
+    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);
+    }
+
+
 
 
 
+
+