messagingfw/msgsrvnstore/server/src/CMsvCachedStore.cpp
changeset 0 8e480a14352b
child 34 b66b8f3a7fd8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/CMsvCachedStore.cpp	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,805 @@
+// Copyright (c) 2001-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 "CMsvCachedStore.h"
+#include "MSVSTORE.H"
+#include "MSVUTILS.H"
+
+#include <mmsvstoremanager.h>
+
+const TInt KMsvFlatBufferChunkSize=0x400;
+
+
+enum TCMsvCachedStorePanic {
+	EReadingWhileCommitingStream=1,
+	EReadingWhileCommitingStore=2,
+	EReadingOrWritingWhileRevertingStore=3,
+	EReadingOrWritingWhileDeleteStream=4
+	};
+
+_LIT(KCachedStorePanic, "CMsvCachedStore");
+
+void Panic(TCMsvCachedStorePanic aPanic)
+	{
+	User::Panic(KCachedStorePanic,aPanic);
+	}
+
+
+class HMsvReadBuf : public TMemBuf
+	{
+public:
+	HMsvReadBuf(const TDesC8 &aBuf, CMsvCachedStore &aStore);
+private:
+	virtual void DoRelease();
+private:
+	CMsvCachedStore &iCachedStore;
+	};
+
+
+class HMsvWriteBuf : public TBufBuf
+	{
+public:
+	static HMsvWriteBuf* NewL(TUid aUid,CMsvCachedStore& aStore);
+private:
+	HMsvWriteBuf(TUid aUid,CMsvCachedStore& aStore);
+	virtual void DoRelease();
+	virtual void DoSynchL();
+private:
+	CBufBase*        iBuf;
+	CMsvCachedStore* iStore;
+	TUid			 iUid;
+	};
+
+
+const TUid KMsvEntryFile={0x10003C68};
+
+TPairedTUidHBufC8::TPairedTUidHBufC8() : iBuf(NULL) {}
+
+void TPairedTUidHBufC8::ExternalizeL(RWriteStream &aStream) const
+	{
+	aStream << iUid;
+	aStream << *iBuf;
+	}
+
+void TPairedTUidHBufC8::InternalizeL(RReadStream &aStream)
+	{
+	aStream >> iUid;
+	// the 0x1000000 means that it will return KErrCorrupt
+	// if the file says it contains a string of longer than 16 meg
+	iBuf=HBufC8::NewL(aStream,0x1000000);
+	}
+
+
+CMsvCachedStore* CMsvCachedStore::OpenL(TMsvId aId, MMsvStoreManager& aStoreManager, TBool aReadOnly)
+	{
+	CMsvCachedStore* me = new(ELeave) CMsvCachedStore(aId, aStoreManager);
+	CleanupStack::PushL(me);
+	me->ConstructL(aReadOnly);
+	CleanupStack::Pop(me);
+	return(me);
+	}
+
+
+CMsvCachedStore::CMsvCachedStore(TMsvId aId, MMsvStoreManager& aStoreManager)
+	: iEntryId(aId), iStoreManager(aStoreManager)
+	{
+	}
+
+void CMsvCachedStore::ConstructL(TBool aReadOnly)
+	{
+	iStreams=new(ELeave) CArrayFixFlat<TPairedTUidHBufC8>(5);
+
+	RFile storeFile;
+	TInt err = iStoreManager.OpenFileStoreForRead(iEntryId, storeFile);
+	
+	if( err != KErrNotFound )
+		{
+		if( err==KErrNone )
+			LoadL(storeFile); // the load takes ownership of the RFile
+		else
+			User::Leave(err);
+		}
+	else if(aReadOnly)
+		User::Leave(err);
+	}
+
+TInt CMsvCachedStore::Size() const
+	{
+	return iSize;
+	}
+
+void CMsvCachedStore::DeleteL()
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	if(iHeaderFieldList.Count())
+		{
+		iStoreManager.DeleteHeaderEntryL(iMtmId, iEntryId);
+		}	
+#endif
+
+	iStoreManager.DeleteFileStoreL(iEntryId);
+	}
+
+
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+
+CMsvCachedStore* CMsvCachedStore::OpenL(TMsvId aId, MMsvStoreManager& aStoreManager, TBool aReadOnly,TUid aMtmId)
+	{
+	CMsvCachedStore* me = new(ELeave) CMsvCachedStore(aId, aStoreManager);
+	CleanupStack::PushL(me);
+	me->ConstructDBL(aReadOnly,aMtmId);
+	CleanupStack::Pop(me);
+	return(me);
+	}
+
+
+void CMsvCachedStore::ConstructDBL(TBool aReadOnly,TUid aMtmId)
+	{
+	iStreams=new(ELeave) CArrayFixFlat<TPairedTUidHBufC8>(5);
+
+	RFile storeFile;
+	TInt err = iStoreManager.OpenFileStoreForRead(iEntryId, storeFile);
+	
+	if(err != KErrNotFound)
+		{
+		if( err==KErrNone )
+			{
+			LoadL(storeFile); // the load takes ownership of the RFile
+			if(aReadOnly)
+				isNewEntry = EFalse;
+			else
+				isNewEntry = ETrue;
+			TRAP_IGNORE(LoadHeaderEntryL(aMtmId,aReadOnly));
+			}
+		else
+			{
+			User::Leave(err);
+			}
+		}
+	else 
+		{
+		TRAPD(err2, LoadHeaderEntryL(aMtmId,aReadOnly));
+		if (err2 == KErrNotFound)
+				{
+				User::Leave(err);
+				}
+		}
+	isDbStore=iStoreManager.DoesHeaderTableExist(aMtmId);	
+	}
+
+
+
+/**
+Assign the  header Fields in to header Field list.
+@param aHeaderFields : CHeaderFields*
+@return None.
+*/
+void CMsvCachedStore::AssignL(CHeaderFields* aHeaderFields)
+	{
+	TUid uid = aHeaderFields->iUid;
+	for(TInt index=0; index<iHeaderFieldList.Count(); index++)
+		{
+		if(iHeaderFieldList[index]->iUid == uid)
+			{
+			delete iHeaderFieldList[index];
+			iHeaderFieldList[index] = aHeaderFields;
+			return;
+			}		
+		}
+	iHeaderFieldList.AppendL(aHeaderFields);
+	}
+
+/**
+Get the header Fields for respective UID.
+@param aUid : A Uid
+@param aHeaderFields : CHeaderFields*&
+
+@return None.
+*/
+
+void CMsvCachedStore::GetHeaderL(TUid aUid, CHeaderFields*& aHeaderFields)
+	{
+	for(TInt index=0; index<iHeaderFieldList.Count(); index++)
+		{
+		if(iHeaderFieldList[index]->iUid == aUid)
+			{
+			aHeaderFields = iHeaderFieldList[index];
+			return;
+			}	
+		}
+	User::Leave(KErrNotFound);
+	}
+
+
+/**
+Load the Header Entry .
+@param aMtmId A Mtm TUid.
+@return None.
+@internalComponent
+*/
+
+void CMsvCachedStore::LoadHeaderEntryL(const TUid aMtmId,TBool aReadOnly)
+	{
+	TRAPD (err ,iStoreManager.LoadHeaderEntryL(aMtmId, iEntryId, iHeaderFieldList));
+	if((err == KErrNotFound) && aReadOnly)
+		{
+		User::Leave(err);
+		}
+		
+	if(err == KErrNotFound)
+		{
+		isNewEntry = ETrue;
+		iSize = 0;
+		}
+	else
+		{
+		isNewEntry = EFalse;
+		if(err == KErrNone)
+			{
+			for(TInt index=0; index<iHeaderFieldList.Count(); index++)
+				{
+				for(TInt i =0 ; i < (iHeaderFieldList)[index]->iFieldPairList.Count() ;i++ )
+					{
+					if(((iHeaderFieldList)[index]->iFieldPairList[i]->iFieldTextValue) != NULL)
+						iSize += (iHeaderFieldList)[index]->iFieldPairList[i]->iFieldTextValue->Length();
+					}
+				}
+			}
+		else
+			{
+			User::Leave(err);	
+			}
+		}
+	}
+	
+#endif
+/**
+
+The CMsvCachedStore::Remove method
+
+Removes the stream from the array, ignores the fact that
+it might not exist.
+
+@internalAll
+@param				 aUid	Stream to remove
+*/
+void CMsvCachedStore::Remove(TUid aUid)
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	for(TInt index=0; index<iHeaderFieldList.Count(); index++)
+		{
+		if( (iHeaderFieldList)[index]->iUid == aUid )
+			{
+			iHeaderFieldList.Remove(index);
+			TRAP_IGNORE(iStoreManager.UpdateHeaderEntryL(iMtmId, iEntryId, iHeaderFieldList)); 
+			return;
+			}
+		}	
+#endif
+
+	DeleteStream(aUid);
+	}
+
+
+/**
+
+The CMsvCachedStore::RemoveL method
+
+Removes a stream from the array, leaves if the stream is not found
+
+@leave 
+@internalAll
+@param				 aUid	Stream to remove
+*/
+void CMsvCachedStore::RemoveL(TUid aUid)
+	{
+	User::LeaveIfError(DeleteStream(aUid));
+	}
+
+
+/**
+
+The CMsvCachedStore::Revert method
+
+Reloads the array of streams from the store
+ignores errors that might occur.
+
+
+@internalAll
+*/
+void CMsvCachedStore::Revert()
+	{
+     TRAP_IGNORE(RevertL());
+	}
+
+
+/**
+
+The CMsvCachedStore::RevertL method
+
+  Reloads the streams from the file
+
+@leave
+@internalAll
+*/
+void CMsvCachedStore::RevertL()
+	{
+	__ASSERT_ALWAYS(iReaderCount==0 && iWriterCount==0, Panic(EReadingOrWritingWhileRevertingStore));
+	CleanArray();
+	iStreams=new(ELeave) CArrayFixFlat<TPairedTUidHBufC8>(5);
+	
+	RFile storeFile;
+	User::LeaveIfError(iStoreManager.OpenFileStoreForRead(iEntryId, storeFile));
+	LoadL(storeFile); // the load takes ownership of the RFile	
+
+	}
+
+
+/**
+
+The CMsvCachedStore::Commit method
+
+  Saves the current state of the stream array to the file
+
+@return			error
+@internalAll
+*/
+TInt CMsvCachedStore::Commit() 
+	{
+	TRAPD(error,CommitL());
+	return(error);
+	}
+
+
+/**
+
+The CMsvCachedStore::CommitL method
+
+  Saves the current state of the stream array to the file
+  leaves with if error occurs
+
+@leave
+@internalAll
+*/
+void CMsvCachedStore::CommitL()
+	{
+	__ASSERT_ALWAYS(iWriterCount==0,Panic(EReadingWhileCommitingStore));
+	SaveL();
+	}
+
+
+void CMsvCachedStore::CleanArray()
+	{
+	if(iStreams!=NULL)
+		{
+		TInt count=iStreams->Count();
+		while(count--) delete iStreams->At(count).iBuf;
+		}
+	delete iStreams;
+	iStreams=NULL;
+	}
+
+/**
+
+The CMsvCachedStore::~CMsvCachedStore method
+
+@internalAll
+*/
+CMsvCachedStore::~CMsvCachedStore()
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	iHeaderFieldList.ResetAndDestroy();
+	iHeaderFieldList.Close();
+#endif
+	CleanArray();
+	}
+
+
+TBool CMsvCachedStore::IsNullL() const
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	if(iStreams->Count()==0)
+		{
+		if(iHeaderFieldList.Count() ==0)
+			{
+			return ETrue;
+			}
+		else
+			{
+			return EFalse;
+			}
+		}
+	else
+		{
+		return EFalse;
+		}
+#else
+	return(iStreams->Count()==0);
+#endif
+	}
+
+
+/**
+
+The CMsvCachedStore::IsPresentL method
+
+  checks to see if the stream is in the array
+
+@return		ETrue if it exists EFalse if not.
+@internalAll
+@param				 aUid	stream to check for
+*/
+TBool CMsvCachedStore::IsPresentL(TUid aUid) const
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	for(TInt index=0; index<iHeaderFieldList.Count(); index++)
+		{
+		if(iHeaderFieldList[index]->iUid == aUid)
+			{
+			return ETrue;
+			}
+		}
+#endif 	
+	TInt pos;
+	if(FindStream(aUid,pos)==KErrNone) return(ETrue);
+	else return(EFalse);
+	}
+
+
+
+/**
+
+The CMsvCachedStore::CreateOrReplaceStreamL method
+
+  If a stream is present with this id it replaces the
+  data in that stream with aBuf, otherwise it adds a new
+  stream with the data in aBuf
+
+@internalAll
+@param				 aUid	stream id
+@param				 *aBuf	data, takes ownership
+*/
+void CMsvCachedStore::CreateOrReplaceStreamL(TUid aUid, CBufBase &aBuf)
+	{
+	__ASSERT_ALWAYS(iReaderCount==0, Panic(EReadingWhileCommitingStream));
+	TInt pos;
+	HBufC8* buffer=FlattenLC(aBuf);
+	if(FindStream(aUid,pos)==KErrNone)
+		{
+		delete iStreams->At(pos).iBuf;
+		iStreams->At(pos).iBuf=buffer;
+		}
+	else
+		{
+		TPairedTUidHBufC8 entry;
+		entry.iUid=aUid;
+		entry.iBuf=buffer;
+		iStreams->InsertL(pos,entry);
+		}
+	CleanupStack::Pop(buffer);
+	}
+
+HBufC8* CMsvCachedStore::FlattenLC(CBufBase &aBuf)
+	{
+	TInt size=aBuf.Size();
+	HBufC8 *buffer=HBufC8::NewLC(size);
+	TPtr8 ptr(buffer->Des());
+
+	RDesWriteStream writer(ptr);
+	RBufReadStream reader(aBuf);
+	writer.WriteL(reader,size);
+	writer.CommitL();
+	return(buffer);
+	}
+
+
+/**
+
+The CMsvCachedStore::GetStream method
+
+  If it returns with KErrNone it sets aData to point to the
+  data in the store this id
+
+@return			error code if the stream was not found
+@internalAll
+@param				 aUid	stream id
+@param				 *&aData	returned pointer to data
+*/
+HBufC8* CMsvCachedStore::GetStreamL(TUid aUid) const
+	{
+	TInt pos;
+	if(FindStream(aUid, pos) != 0)
+		User::Leave(KErrNotFound);
+	
+	return iStreams->At(pos).iBuf;
+	}
+
+
+/**
+
+The CMsvCachedStore::FindStream method
+
+  Finds the stream of id aUid, if it returns with KErrNone then
+  pos is set to the position of the 
+  if it is not found pos is set to where is should be inserted
+
+@internalAll
+@param				 aUid
+@param				 &pos
+*/
+TInt CMsvCachedStore::FindStream(TUid aUid,TInt &pos) const
+	{
+	TPairedTUidHBufC8 entry;
+	entry.iUid=aUid;
+	TKeyArrayFix key(_FOFF(TPairedTUidHBufC8,iUid),ECmpTInt32);
+	return(iStreams->FindIsq(entry,key,pos));
+	}
+
+
+/**
+
+The CMsvCachedStore::DeleteStream method
+
+  deletes the stream with this id
+
+@return			error code KErrNone unless the stream wasn't found
+@internalAll
+@param				 aUid	the stream id to delete
+*/
+TInt CMsvCachedStore::DeleteStream(TUid aUid)
+	{
+	__ASSERT_ALWAYS(iReaderCount==0 && iWriterCount==0,Panic(EReadingOrWritingWhileDeleteStream));
+	TInt pos;
+	TInt error=FindStream(aUid,pos);
+	if(error==KErrNone)
+		{
+		delete iStreams->At(pos).iBuf;
+		iStreams->Delete(pos);
+		}
+	return(error);
+	}
+
+
+/**
+
+The CMsvCachedStore::LoadL method
+
+loads the streams from a file
+
+  should this create the file if it is corupt???
+
+@leave				leaves if we can't find the file, if we run out of memory, if the file is corrupt
+@internalAll
+@param				 &aFile	file to load the streams from, take ownership of the file
+*/
+void CMsvCachedStore::LoadL(RFile &aFile)
+	{
+	__ASSERT_DEBUG(iStreams->Count()==0,User::Invariant());
+
+	// Need to cache the file size
+	User::LeaveIfError(aFile.Size(iSize));
+
+	RFileReadStream in(aFile);
+	in.PushL();
+	TCheckedUid check;
+	in >> check;
+	if(check.UidType().IsValid()==EFalse) User::Leave(KErrCorrupt);
+	if(check.UidType()[0]!=KMsvEntryFile) User::Leave(KErrCorrupt);
+	in >> *iStreams;
+	CleanupStack::PopAndDestroy(); // close RFileReadStream in
+	}
+
+
+
+/**
+
+The CMsvCachedStore::SaveL method
+
+Saves the current state to iFileName
+
+@leave				leaves if we can't replace the file, if we run out of disk space,
+@internalAll
+*/
+void CMsvCachedStore::SaveL()
+	{
+	RFile tempStoreFile;
+	iStoreManager.OpenTempStoreFileL(iEntryId, tempStoreFile);
+	RFileWriteStream out(tempStoreFile);
+	out.PushL();
+	WriteToFileStreamL(out);
+	CleanupStack::PopAndDestroy(&out); // close RFileWriteStream out
+	iStoreManager.ReplaceFileStoreL(iEntryId);
+
+	// Need the size
+	RFile storeFile;
+	User::LeaveIfError(iStoreManager.OpenFileStoreForRead(iEntryId, storeFile));
+	CleanupClosePushL(storeFile);
+	User::LeaveIfError(storeFile.Size(iSize));
+	CleanupStack::PopAndDestroy(&storeFile);
+	
+
+	}
+
+void CMsvCachedStore::WriteToFileStreamL(RFileWriteStream &aOut)
+	{
+	TCheckedUid check(TUidType(KMsvEntryFile,KMsvEntryFile,KNullUid));
+	aOut << check;
+	aOut << *iStreams;
+	aOut.CommitL();	
+	}
+
+
+
+
+
+EXPORT_C void RMsvReadStream::OpenL(const CMsvStore& aMsvStore, TUid aUid)
+/** Prepares an existing stream with UID for reading.
+
+After this function has been called, the stream can be read from with the 
+functions provided by the RReadStream base class.
+
+@param aMsvStore The CMsvStore the stream is in. 
+@param aUid The UID of the stream to open with read access 
+@leave KErrNotFound There is no stream with UID aUid 
+@leave Other Standard stream leave codes. */
+	{
+	HBufC8 *buffer=aMsvStore.iStore->GetStreamL(aUid);
+	HMsvReadBuf *tidy= new (ELeave) HMsvReadBuf(*buffer, *(aMsvStore.iStore));
+	Attach(tidy);
+	}
+
+
+EXPORT_C void RMsvReadStream::OpenLC(const CMsvStore& aMsvStore,TUid aUid)
+/** Prepares an existing stream with UID for reading.
+
+After this function has been called, the stream can be read from with the 
+functions provided by the RReadStream base class.
+
+The object is placed on the cleanup stack. 
+
+@param aMsvStore The CMsvStore the stream is in. 
+@param aUid The UID of the stream to open with read access 
+@leave KErrNotFound There is no stream with UID aUid 
+@leave Other Standard stream leave codes. */
+	{
+	OpenL(aMsvStore,aUid);
+	PushL();
+	}
+
+
+
+/**
+
+The RMsvReadStream::OpenLC method
+
+ties the read stream to a HMsvReadBuf
+
+
+@leave				leaves if we can't find the stream
+@param				 aStore   aStore is the CMsvCachedStore within which we look for the stream
+@param				 aUid		id of stream to open for reading
+*/
+void RMsvReadStream::OpenLC(CMsvCachedStore& aStore,TUid aUid)
+	{
+	HBufC8 *buffer=aStore.GetStreamL(aUid);
+	HMsvReadBuf *tidy= new (ELeave) HMsvReadBuf(*buffer, aStore);
+	Attach(tidy);
+	}
+
+
+
+HMsvWriteBuf* HMsvWriteBuf::NewL(TUid aUid,CMsvCachedStore& aStore)
+	{
+	HMsvWriteBuf* self=new (ELeave) HMsvWriteBuf(aUid,aStore);
+	self->PushL();
+	self->iBuf=CBufSeg::NewL(KMsvFlatBufferChunkSize);
+	CleanupStack::Pop(self);
+	self->Set(*(self->iBuf),0);
+	return(self);
+	}
+
+HMsvWriteBuf::HMsvWriteBuf(TUid aUid,CMsvCachedStore& aStore) : iBuf(NULL), iStore(&aStore), iUid(aUid)
+	{
+	iStore->iWriterCount++;
+	}
+
+void HMsvWriteBuf::DoRelease()
+	{
+	__ASSERT_DEBUG(iStore==NULL || iStore->iWriterCount>0,User::Invariant());
+	delete iBuf;
+	// we decrememt the writer count if it wasn't done in DoSynchL (called if client commits)
+	if(iStore) iStore->iWriterCount--;
+	iStore=NULL;
+	delete this;
+	}
+
+void HMsvWriteBuf::DoSynchL()
+	{
+	// if we have already sync'd it will be null so ignore the sync
+	if(iStore!=NULL)
+		{
+		__ASSERT_DEBUG(iStore->iWriterCount>0,User::Invariant());
+		TBufBuf::DoSynchL();
+		iStore->CreateOrReplaceStreamL(iUid,*iBuf);
+		// decrement the writer count, after a commit all writes are ignored, this is the
+		// same as other stores, also set iStore to NULL so we don't decrement the writer
+		// count in DoRelease as well.
+		iStore->iWriterCount--;
+		iStore=NULL;
+		}
+	}
+
+
+
+
+HMsvReadBuf::HMsvReadBuf(const TDesC8 &aBuf,CMsvCachedStore &aStore) : iCachedStore(aStore)
+	{ 
+	TUint8* ptr=(TUint8 *)aBuf.Ptr();
+	Set(ptr,ptr+aBuf.Length(),ERead);
+	aStore.iReaderCount++;
+	}
+
+void HMsvReadBuf::DoRelease()
+	{
+	__ASSERT_ALWAYS(iCachedStore.iReaderCount>0,User::Invariant());
+	iCachedStore.iReaderCount--;
+	delete this;
+	}
+
+
+EXPORT_C void RMsvWriteStream::AssignLC(CMsvStore &aMsvStore, TUid aUid)
+/** Prepares a stream for writing; the object is placed on the cleanup stack. 
+
+After this function has been called, the stream can be written to with the 
+functions provided by the RWriteStream base class.
+
+If the stream does not exist, it is created.
+
+@param aMsvStore The CMsvStore the stream is in 
+@param aUid The UID of the stream to open with write access 
+@leave KErrAccessDenied Store is not open for writing 
+@leave Other Standard stream leave codes */
+	{
+	if (aMsvStore.iLockStatus==CMsvStore::EMsvStoreUnlocked)
+		User::Leave(KErrAccessDenied);
+	AssignL(aMsvStore,aUid);
+	PushL();
+	}
+
+EXPORT_C void RMsvWriteStream::AssignL(CMsvStore &aMsvStore, TUid aUid)
+/** Prepares a stream for writing. 
+
+After this function has been called, the stream can be written to with the 
+functions provided by the RWriteStream base class.
+
+If the stream does not exist, it is created.
+
+@param aMsvStore The CMsvStore the stream is in 
+@param aUid The UID of the stream to open with write access 
+@leave KErrAccessDenied Store is not open for writing 
+@leave Other Standard stream leave codes */
+	{
+	if (aMsvStore.iLockStatus==CMsvStore::EMsvStoreUnlocked)
+		User::Leave(KErrAccessDenied);
+
+	Attach(HMsvWriteBuf::NewL(aUid,*(aMsvStore.iStore)));
+	}
+
+void RMsvWriteStream::AssignLC(CMsvCachedStore &aStore, TUid aUid)
+	{
+	Attach(HMsvWriteBuf::NewL(aUid,aStore));
+	PushL();
+	}