persistentstorage/store/UFILE/UF_BUF.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/store/UFILE/UF_BUF.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,663 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+//
+
+#include "UF_STD.H"
+#include "S32FILEBUFSIZE.H"
+
+//#define MAP_ROM_FILES
+#ifdef _DEBUG
+//#define IO_TRACING
+//#define SIMULATE_PARTIAL_WRITE
+#endif
+
+#ifdef IO_TRACING
+#include <e32svr.h>
+_LIT(KTraceWrite,"RFile::Write [%d,%d)\n");
+#define _TRACE_WRITE(p,l) RDebug::Print(KTraceWrite,(p),(p)+(l))
+_LIT(KTraceRead,"RFile::Read [%d,%d)\n");
+#define _TRACE_READ(p,l) RDebug::Print(KTraceRead,(p),(p)+(l))
+_LIT(KTraceSize,"RFile::Size\n");
+#define _TRACE_SIZE() RDebug::Print(KTraceSize)
+_LIT(KTraceFlush,"RFile::Flush\n");
+#define _TRACE_FLUSH() RDebug::Print(KTraceFlush)
+_LIT(KTraceSetSize,"RFile::SetSize %d\n");
+#define _TRACE_SETSIZE(s) RDebug::Print(KTraceSetSize,(s))
+#else
+#define _TRACE_WRITE(p,l)
+#define _TRACE_READ(p,l)
+#define _TRACE_SIZE()
+#define _TRACE_FLUSH()
+#define _TRACE_SETSIZE(s)
+#endif
+
+EXPORT_C RFileBuf::RFileBuf()
+	: iBase(NULL),iSize(KDefaultFileBufSize),iWLim(NULL)
+/** Constructs the object with a default intermediate buffer size.
+
+The size of the intermediate buffer is the value of the constant KDefaultFileBufSize. */
+	{}
+
+EXPORT_C RFileBuf::RFileBuf(TInt aSize)
+	: iBase(NULL),iSize(aSize),iWLim(NULL)
+/** Constructs the object with the specified intermediate buffer size.
+
+If the intermediate buffer size is zero, then the class provides an MStreamBuf 
+interface to unbuffered file I/O.
+
+@param aSize The size of the intermediate buffer. */
+	{}
+
+RFileBuf::RFileBuf(TCapture<RFileBuf> aCapture)
+//
+// Take over from the buffer wrapped inside aCapture.
+//
+	{
+	RFileBuf& buf=aCapture.Object();
+	iBase=buf.iBase;
+	iSize=buf.iSize;
+	SetBuf(ERead,buf.Ptr(ERead),buf.End(ERead));
+	SetBuf(EWrite,buf.Ptr(EWrite),buf.End(EWrite));
+	SetLimit(EWrite,buf.Limit(EWrite));
+	buf.iBase=NULL;
+	buf.SetBuf(ERead|EWrite,NULL,NULL);
+	iFile=buf.File();
+	buf.Detach();
+	SetPos(ERead,buf.Pos(ERead));
+	SetPos(EWrite,buf.Pos(EWrite));
+	iExt=buf.iExt;
+	}
+
+EXPORT_C void RFileBuf::Reset()
+/** Frees the intermediate buffer.
+
+If there is any read data in the intermediate buffer, then the function reverts 
+the read position within the stream.
+
+The intermediate buffer must not contain any outstanding write data, otherwise 
+the function raises a STORE-File 6 panic. */
+	{
+	__ASSERT_ALWAYS(Span(EWrite)==0,Panic(EFileWriteOutstanding));
+	MovePos(ERead,Lag(ERead));
+	Free();
+	}
+
+EXPORT_C TInt RFileBuf::Open(RFs& aFs,const TDesC& aName,TUint aFileMode)
+/** Opens the specified file and attaches it to this stream buffer.
+
+If the file cannot be opened, then it is not attached to this stream buffer.
+
+@param aFs Handle to a file server session through which the file is opened.
+@param aName The name of the file to be opened.
+@param aFileMode The mode in which the file is to be accessed. The mode is 
+defined by the TFileMode type.
+@return KErrNone, if successful, otherwise one of the other system wide error 
+codes.
+@see Attach()
+@see TFileMode
+@see RFile */
+	{
+	RFile file;
+	TInt r=file.Open(aFs,aName,aFileMode);
+	if (r==KErrNone)
+		Attach(file);
+	return r;
+	}
+
+EXPORT_C TInt RFileBuf::Create(RFs& aFs,const TDesC& aName,TUint aFileMode)
+/** Creates a file with the specified name and attaches it to this stream buffer.
+
+The file must not already exist.
+
+If the file cannot be created and opened, then it is not attached to this 
+stream buffer.
+
+@param aFs Handle to a file server session through which the file is created.
+@param aName The name of the file to be created.
+@param aFileMode The mode in which the file is to be accessed. The mode is 
+defined by the TFileMode type.
+@return KErrNone, if successful, otherwise one of the other system wide error 
+codes.
+@see Attach()
+@see TFileMode
+@see RFile */
+	{
+	RFile file;
+	TInt r=file.Create(aFs,aName,aFileMode);
+	if (r==KErrNone)
+		Attach(file);
+	return r;
+	}
+
+EXPORT_C TInt RFileBuf::Replace(RFs& aFs,const TDesC& aName,TUint aFileMode)
+/** Replaces the file with the specified name and attaches it to this stream buffer.
+
+If there is an existing file with the same name, then this function overwrites 
+it. If the file does not already exist, it is created.
+
+If the file cannot be replaced, then it is not attached to this stream buffer.
+
+@param aFs Handle to a file server session through which the file is replaced.
+@param aName The name of the file to be replaced.
+@param aFileMode The mode in which the file is to be accessed. The mode is 
+defined by the TFileMode type.
+@return KErrNone, if successful, otherwise one of the other system wide error 
+codes.
+@see Attach()
+@see TFileMode
+@see RFile */
+	{
+	RFile file;
+	TInt r=file.Replace(aFs,aName,aFileMode);
+	if (r==KErrNone)
+		Attach(file);
+	return r;
+	}
+
+EXPORT_C TInt RFileBuf::Temp(RFs& aFs,const TDesC& aPath,TFileName& aName,TUint aFileMode)
+/** Creates and opens a temporary file with a unique name and attaches it to this 
+stream buffer.
+
+@param aFs Handle to a file server session through which the file is created.
+@param aPath The directory in which the file is created.
+@param aName On return, contains the full path and file name of the file. The 
+filename is guaranteed to be unique within the specified directory.
+@param aFileMode The mode in which the file is to be accessed. The mode is 
+defined by the TFileMode type.
+@see Attach()
+@see TFileMode
+@see RFile */
+	{
+	RFile file;
+	TInt r=file.Temp(aFs,aPath,aName,aFileMode);
+	if (r==KErrNone)
+		Attach(file);
+	return r;
+	}
+
+EXPORT_C void RFileBuf::Attach(RFile& aFile,TInt aPos)
+/** Attaches the specified file to this stream buffer.
+
+The function also re-sets the intermediate buffer's read and write marks to 
+the beginning of the intermediate buffer and sets the read and write stream 
+positions to the specified offset within the file.
+
+@param aFile The file to be attached.
+@param aPos The offset within the file to which the read and write stream positions 
+are set. By default this is zero.
+@see Detach()
+@see Reattach() */
+	{
+	__ASSERT_ALWAYS(Span(EWrite)==0,Panic(EFileWriteOutstanding));
+	TUint8* base=iBase;
+	SetBuf(ERead|EWrite,base,base);
+	iFile=aFile;
+	aFile=RFile();
+	SetPos(ERead|EWrite,aPos);
+	iExt=-1;
+	}
+
+EXPORT_C void RFileBuf::Close()
+/** Writes any outstanding data from the intermediate buffer before freeing the 
+intermediate buffer and closing the attached file. */
+	{
+	TInt lag=Span(EWrite);
+	if (lag>0)
+		{
+		_TRACE_WRITE(Pos(EWrite),lag);
+		File().Write(Pos(EWrite),TPtrC8(iBase,lag));
+		}
+	Free();
+	File().Close();
+	}
+
+EXPORT_C void RFileBuf::SetSizeL(TInt aSize)
+/** Changes the size of the file attached to this buffer to the specified value.
+
+Writes any outstanding data from the intermediate buffer to the stream hosted 
+by the file. Any data in the intermediate buffer that would lie beyond the 
+end of the truncated file, is not written.
+
+@param aSize The new size of the file. */
+	{
+	TUint8* base=iBase;
+	TInt pos=Pos(EWrite);
+	TInt excess=aSize-pos;
+	if (excess>0)
+		FileWriteL(base,Min(excess,Span(EWrite)),0);
+	MovePos(ERead,Lag(ERead));
+	SetBuf(ERead,base,base);
+//
+	_TRACE_SETSIZE(aSize);
+	TInt r=File().SetSize(aSize);
+	if (r!=KErrNone)
+		{
+		SetPos(EWrite,pos);
+		iExt=-1;
+		__LEAVE(r);
+		}
+//
+	SetPos(EWrite,Min(pos+Lag(EWrite), aSize)); 
+	SetBuf(EWrite,base,base);
+	iExt=aSize;
+	}
+
+EXPORT_C TInt RFileBuf::UnderflowL(TInt aMaxLength)
+//
+// Fill the buffer's read area.
+//
+	{
+	__ASSERT_DEBUG(Avail(ERead)==0,User::Invariant());
+	TUint8* base=iBase;
+	if (base==NULL)
+		{
+#if defined(MAP_ROM_FILES)
+		if (Ptr(ERead))
+			return 0;		// memory mapped ROM file
+		TInt pos=0;
+		TInt err = File().Seek(ESeekAddress,pos);
+		if (err==KErrNone)
+			{				// memory map a ROM file into the read zone
+			base=(TUint8*)pos;
+			TInt len=EndL();
+			SetPos(ERead,len);
+			SetBuf(ERead,base,base+len);
+			return len;
+			}
+#endif
+		base=AllocL();
+		}
+
+	TInt lag=Pos(ERead)-Pos(EWrite);
+	TInt span=Span(EWrite);
+	if (lag>=0&&lag<span)
+		{
+		SetBuf(ERead,base+lag,base+span);
+		MovePos(ERead,span-lag);
+		return span-lag;
+		}
+
+	FileWriteL(base,Span(EWrite));
+	SetBuf(EWrite,base,base);
+	
+	// Align file position with file 'blocks' when possible
+	TInt align = (Pos(ERead) + aMaxLength + KMaxFileBufReadAhead) & (KFileBufBlockSize-1);
+	TInt readahead = KMaxFileBufReadAhead - align;
+	if(readahead < 0)
+		{
+		// if read-ahead doesn't cross block boundary do it all
+		readahead = KMaxFileBufReadAhead;	
+		}
+	TInt len=FileReadL(base, Min(iSize, aMaxLength+readahead));
+	
+	SetBuf(ERead,base,base+len);
+	return len;
+	}
+
+EXPORT_C void RFileBuf::OverflowL()
+//
+// Set up the buffer's write area.
+//
+	{
+	__ASSERT_DEBUG(Avail(EWrite)==0,User::Invariant());
+	TUint8* base=iBase;
+	if (base==NULL)
+		base=AllocL();
+	MovePos(ERead,Lag(ERead));
+	SetBuf(ERead,base,base);
+//
+	__ASSERT_DEBUG(Lag(EWrite)==Span(EWrite),User::Invariant());
+	FileWriteL(base,Lag(EWrite),0);
+	SetBuf(EWrite,base,base+iSize);
+	}
+
+EXPORT_C void RFileBuf::DoRelease()
+//
+// Release all resources, losing any outstanding data.
+//
+	{
+	Free();
+	File().Close();
+	}
+
+EXPORT_C void RFileBuf::DoSynchL()
+//
+// Synchronise this buffer with its file, giving up on outstanding writes in case of failure.
+//
+	{
+	TUint8* base=iBase;
+#if defined(MAP_ROM_FILES)
+	if (base!=NULL)	// do not do this for memory mapped ROM files
+#endif
+		{
+		MovePos(ERead,Lag(ERead));
+		TInt span=Span(EWrite);
+		TInt rewind=span-Lag(EWrite);
+		SetBuf(ERead|EWrite,base,base);
+		iExt=-1;
+		FileWriteL(base,span,rewind);
+		}
+	TInt handle = File().SubSessionHandle();
+	if (handle!=0)
+		{
+		_TRACE_FLUSH();
+		TInt r=File().Flush();
+		if (r!=KErrNone&&r!=KErrAccessDenied)
+			{
+			__LEAVE(r);
+			}
+		}
+	}
+
+EXPORT_C TInt RFileBuf::DoReadL(TAny* aPtr,TInt aMaxLength)
+//
+// Read direct from file if asked to transfer more than a bufferful.
+//
+	{
+	__ASSERT_DEBUG(aMaxLength>=0,Panic(EFileReadLengthNegative));
+	__ASSERT_DEBUG(aMaxLength>0,Panic(EFileReadNoTransfer));
+	TInt avail=Avail(ERead);
+	__ASSERT_DEBUG(avail>=0&&Avail(EWrite)>=0,User::Invariant());
+	if (avail>0)
+		{
+		TInt len=Min(aMaxLength,avail);
+		TUint8* ptr=Ptr(ERead);
+		aPtr=Mem::Copy(aPtr,ptr,len);
+		SetPtr(ERead,ptr+len);
+		aMaxLength-=len;
+		if (aMaxLength==0)
+			return len; // that's it
+		}
+	__ASSERT_DEBUG(Avail(ERead)==0,User::Invariant());
+	if (aMaxLength<iSize)
+		return avail+TStreamBuf::DoReadL(aPtr,aMaxLength);
+//
+	TUint8* base=iBase;
+	FileWriteL(base,Span(EWrite));
+	SetBuf(ERead|EWrite,base,base);
+	return avail+FileReadL(aPtr,aMaxLength);
+	}
+
+EXPORT_C TInt RFileBuf::DoReadL(TDes8& aDes,TInt aMaxLength,TRequestStatus& aStatus)
+//
+// Read up to aMaxLength bytes asynchronously.
+//
+	{
+//#pragma message( __FILE__ " : 'RFileBuf::DoReadL(TDes8&,TInt,TRequestStatus&)' not implemented" )
+	__ASSERT_DEBUG(aMaxLength<=aDes.MaxLength(),Panic(EFileReadBeyondEnd));
+	aDes.SetLength(DoReadL((TUint8*)aDes.Ptr(),aMaxLength));
+	TRequestStatus* stat=&aStatus;
+	User::RequestComplete(stat,KErrNone);
+	return aMaxLength;
+	}
+
+EXPORT_C void RFileBuf::DoWriteL(const TAny* aPtr,TInt aLength)
+//
+// Write direct to file if asked to transfer more than a bufferful.
+//
+	{
+	__ASSERT_DEBUG(aLength>=0,Panic(EFileWriteLengthNegative));
+	__ASSERT_DEBUG(aLength>0,Panic(EFileWriteNoTransfer));
+	TInt avail=Avail(EWrite);
+	__ASSERT_DEBUG(Avail(ERead)>=0&&avail>=0,User::Invariant());
+	if (avail>0)
+		{
+		TInt len=Min(aLength,avail);
+		SetPtr(EWrite,Mem::Copy(Ptr(EWrite),aPtr,len));
+		aLength-=len;
+		if (aLength==0)
+			return; // done
+//
+		aPtr=(TUint8*)aPtr+len;
+		}
+	__ASSERT_DEBUG(Avail(EWrite)==0,User::Invariant());
+	if (aLength<iSize)
+		TStreamBuf::DoWriteL(aPtr,aLength);
+	else
+		{
+		__ASSERT_DEBUG(Lag(EWrite)==Span(EWrite),User::Invariant());
+		TUint8* base=iBase;
+		FileWriteL(base,Lag(EWrite),0);
+		MovePos(ERead,Lag(ERead));
+		SetBuf(ERead|EWrite,base,base);
+		FileWriteL(aPtr,aLength,0);
+		}
+	}
+
+EXPORT_C TInt RFileBuf::DoWriteL(const TDesC8& aDes,TInt aMaxLength,TRequestStatus& aStatus)
+//
+// Write up to aMaxLength bytes asynchronously.
+//
+	{
+//#pragma message( __FILE__ " : 'RFileBuf::DoWriteL(const TDesC8&,TInt,TRequestStatus&)' not implemented" )
+	__ASSERT_DEBUG(aMaxLength<=aDes.Length(),Panic(EFileWriteBeyondEnd));
+	DoWriteL(aDes.Ptr(),aMaxLength);
+	TRequestStatus* stat=&aStatus;
+	User::RequestComplete(stat,KErrNone);
+	return aMaxLength;
+	}
+
+EXPORT_C TStreamPos RFileBuf::DoSeekL(TMark aMark,TStreamLocation aLocation,TInt anOffset)
+//
+// Position the mark(s) indicated by aMark at anOffset from aLocation.
+//
+	{
+	TUint8* base=iBase;
+	TInt end=EndL();
+//
+	switch (aLocation)
+		{
+	case EStreamBeginning:
+		break;
+	case EStreamMark:
+		anOffset+=Mark(aMark);
+		break;
+	case EStreamEnd:
+		anOffset+=end;
+		break;
+	default:
+		Panic(EFileLocationInvalid);
+		break;
+		}
+	TInt r=KErrNone;
+	if (anOffset<0)
+		{
+		anOffset=0;
+		r=KErrEof;
+		}
+	else if (anOffset>end)
+		{
+		anOffset=end;
+		r=KErrEof;
+		}
+//
+	__ASSERT_ALWAYS(!(aMark&~(ERead|EWrite)),Panic(EFileMarkInvalid));
+	if (aMark&ERead)
+		{
+		TInt lag=anOffset-Pos(ERead);
+#if defined(MAP_ROM_FILES)
+		if (base==NULL&&End(ERead)!=NULL)	// memory mapped
+			SetPtr(ERead,End(ERead)+lag);
+		else
+#endif
+		if (lag>=base-End(ERead)&&lag<=0)
+			SetPtr(ERead,End(ERead)+lag);
+		else
+			{
+			SetPos(ERead,anOffset);
+			SetBuf(ERead,base,base);
+			}
+		}
+	if (aMark&EWrite)
+		{
+		TInt lag=anOffset-Pos(EWrite);
+		TInt span=Span(EWrite);
+		if (lag>=0&&lag<=span)
+			{
+			SetLimit(EWrite,base+span);
+			SetPtr(EWrite,base+lag);
+			}
+		else
+			{
+			FileWriteL(base,span,0);
+			SetPos(EWrite,anOffset);
+			SetBuf(EWrite,base,base);
+			}
+		}
+	__LEAVE_IF_ERROR(r);
+	return TStreamPos(anOffset);
+	}
+
+TUint8* RFileBuf::AllocL()
+//
+// Allocate space and return a pointer to this buffer's buffer space
+//
+	{
+	__ASSERT_DEBUG(iBase==NULL && iSize>0,User::Invariant());
+//
+	TUint8* base=(TUint8*)User::AllocL(iSize);
+	iBase=base;
+	SetBuf(ERead|EWrite,base,base);
+	return base;
+	}
+
+void RFileBuf::Free()
+//
+// Free this buffer's buffer space.
+//
+	{
+	User::Free(iBase);
+	iBase=NULL;
+	SetBuf(ERead|EWrite,NULL,NULL);
+	}
+
+void RFileBuf::SetPos(TMark aMark,TInt aPos)
+//
+// Set the file position for the mark(s) indicated by aMark
+//
+	{
+	__ASSERT_ALWAYS(!(aMark&~(ERead|EWrite)),Panic(EFileMarkInvalid));
+	if (aMark&ERead)
+		SetPos(ERead,aPos);
+	if (aMark&EWrite)
+		SetPos(EWrite,aPos);
+	}
+
+TInt RFileBuf::FileReadL(TAny* aPtr,TInt aMaxLength)
+//
+// Read from the file at the current read position.
+//
+	{
+	__ASSERT_DEBUG(aMaxLength>=0,Panic(EFileReadLengthNegative));
+	if (aMaxLength==0)
+		return 0;
+//
+	TPtr8 des((TUint8*)aPtr,aMaxLength);
+	TInt pos=Pos(ERead);
+	__LEAVE_IF_ERROR(File().Read(pos,des));
+	TInt len=des.Length();
+	_TRACE_READ(pos,len);
+	pos+=len;
+	if (len<aMaxLength)
+		iExt=pos; // end-of-file encountered
+	SetPos(ERead,pos);
+	return len;
+	}
+
+void RFileBuf::FileWriteL(const TAny* aPtr,TInt aLength)
+//
+// Write to the file at the current write position
+// Use write buffer status to determine the rewind
+//
+	{
+	FileWriteL(aPtr,aLength,Span(EWrite)-Lag(EWrite));
+	}
+
+void RFileBuf::FileWriteL(const TAny* aPtr,TInt aLength,TInt aRewind)
+//
+// Write to the file at the current write position.
+// Rewind write position after write
+//
+	{
+	__ASSERT_DEBUG(aLength>=0,Panic(EFileWriteLengthNegative));
+	if (aLength==0)
+		return;
+//
+	TInt ext=iExt;
+	iExt=-1;
+	TInt pos=Pos(EWrite);
+	_TRACE_WRITE(pos,aLength);
+#ifdef SIMULATE_PARTIAL_WRITE
+	TPtrC8 ptr((TUint8*)aPtr,aLength);
+	TInt partial = aLength >> 1;
+	if (partial)
+		{
+		__LEAVE_IF_ERROR(File().Write(pos, ptr.Left(partial)));
+		}
+	__LEAVE_IF_ERROR(File().Write(pos + partial, ptr.Mid(partial)));
+#else
+
+#if defined SYSLIBS_TEST && defined _DEBUG
+	const TInt KDefaultMediaBlockSize = 512;
+	TInt startSectorAddr = pos & ~(KDefaultMediaBlockSize - 1);
+	TInt endSectorAddr = (pos + aLength - 1) & ~(KDefaultMediaBlockSize - 1);
+	if(startSectorAddr != endSectorAddr && aLength < KDefaultMediaBlockSize)
+		{
+		TInt len1 = startSectorAddr + KDefaultMediaBlockSize - 	pos;
+		TInt len2 = aLength - len1;
+		__LEAVE_IF_ERROR(File().Write(pos, TPtrC8((TUint8*)aPtr, len1)));
+		__LEAVE_IF_ERROR(File().Write(pos + len1, TPtrC8((TUint8*)aPtr + len1, len2)));
+		}
+	else
+		{
+		__LEAVE_IF_ERROR(File().Write(pos,TPtrC8((TUint8*)aPtr,aLength)));
+		}
+#else //SYSLIBS_TEST		
+	__LEAVE_IF_ERROR(File().Write(pos,TPtrC8((TUint8*)aPtr,aLength)));
+#endif//SYSLIBS_TEST
+
+#endif
+	pos+=aLength;
+	if (ext>=0)
+		iExt=Max(pos,ext);
+	SetPos(EWrite,pos-aRewind);
+	}
+
+TInt RFileBuf::EndL()
+//
+// Determine the end of the file.
+//
+	{
+	TInt ext=iExt;
+	if (ext<0)
+		{
+		_TRACE_SIZE();
+		__LEAVE_IF_ERROR(File().Size(ext));
+		iExt=ext;
+		}
+	return Max(ext,Reach(EWrite));
+	}
+
+TInt RFileBuf::Mark(TMark aMark) const
+//
+// Return the position of the mark indicated by aMark.
+//
+	{
+	if (aMark==ERead)
+		return Mark(ERead);
+//
+	__ASSERT_ALWAYS(aMark==EWrite,Panic(EFileMarkInvalid));
+	return Mark(EWrite);
+	}
+