diff -r 000000000000 -r 8e480a14352b messagingfw/msgsrvnstore/server/src/CMsvCachedStore.cpp --- /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 + +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(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(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; indexiUid == 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; indexiUid == 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; indexiFieldPairList.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; indexiUid == 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(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; indexiUid == 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(); + }