diff -r 000000000000 -r 08ec8eefde2f persistentstorage/store/UFILE/UF_DICT.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/store/UFILE/UF_DICT.CPP Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,250 @@ +// 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 + +const TUid KUidDictionaryFile={0x100000E4}; + +_LIT(KSystemIniFileLocationSpec,"Z:\\System\\System.ini"); + +const TUid KSystemIniFileUid = {0x1000010C}; + +// Thread contention resolution constants + +const TInt KSpinCount=40; +const TInt KLockoutLimit=0xc0000; // to keep the lock-out time down to ~1sec (this is microseconds) +const TInt KFailTime=0x1000; // ~ time to fail to open file +const TInt KSpinLimit=KLockoutLimit-KSpinCount*KFailTime; + +LOCAL_C TUint8 const WaitDistribution[8]={0,0,0,0,0x1f,0x3f,0x7f,0xff}; // wait-time distribution mask + +class RYieldThread : public RThread + { +public: + inline void Yield() const {SetPriority(Priority());} + }; + +///////////////////////////////////////////// +// CDictionaryFileStore +///////////////////////////////////////////// + +LOCAL_C void EnsurePathL(RFs& aFs,const TDesC& aName) + { + TInt r=aFs.MkDirAll(TParsePtrC(aName).DriveAndPath()); + if (r!=KErrAlreadyExists) + User::LeaveIfError(r); + } + +EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemL(RFs& aFs) +/** Opens the system dictionary file store. + +@param aFs Handle to a file server session. +@return A pointer to the system file based dictionary store object. */ + { + CDictionaryFileStore* store=SystemLC(aFs); + CleanupStack::Pop(); + return store; + } + +EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemLC(RFs& aFs) +/** Opens the system dictionary file store and puts the pointer to the file store +object onto the cleanup stack. + +@param aFs Handle to a file server session. +@return A pointer to the system file based dictionary store object. */ + { + TDriveUnit drive(static_cast(RFs::GetSystemDrive())); + TParse parse; + User::LeaveIfError(parse.Set(drive.Name(), &KSystemIniFileLocationSpec, NULL)); + + EnsurePathL(aFs, parse.FullName()); + return OpenLC(aFs, parse.FullName(), KSystemIniFileUid); + } + +EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenL(RFs& aFs,const TDesC& aName,TUid aFileId) + /** Creates a file based dictionary store object. + + If the file with the specified full path name exists, then an attempt is made + to open an existing file store contained within this file. Any existing file + store must satisfy the following conditions: + + it must be a valid dictionary store + + the third UID component of the file store type must match the specified UID; + this UID serves to differentiate between dictionary stores + + otherwise the function leaves with KErrCorrupt. + + If the file with the specified full path name does not exist, then an attempt + is made to create a new file and to create a file based dictionary within + it. The third UID component of the file store type is set to the specified + UID value. + + Note that the file is opened in exclusive access mode. + + @param aFs Handle to a file server session. + @param aName The full path name of the file. + @param aUid3 The UID used to differentiate between dictionary stores. + @return A pointer to the file based dictionary store object. + @see TUid + @see TUidType */ + { + CDictionaryFileStore* self = CDictionaryFileStore::OpenLC(aFs,aName,aFileId); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenLC(RFs& aFs,const TDesC& aName,TUid aFileId) + /** Creates a file based dictionary store object and puts the pointer onto the + cleanup stack. + + If the file with the specified full path name exists, then an attempt is made + to open an existing file store contained within this file. Any existing file + store must satisfy the following conditions: + + it must be a valid dictionary store + + the third UID component of the file store type must match the specified UID; + this UID serves to differentiate between dictionary stores + + otherwise the function leaves with KErrCorrupt. + + If the file with the specified full path name does not exist, then an attempt + is made to create a new file and to create a file based dictionary within + it. The third UID component of the file store type is set to the specified + UID value. + + Note that the file is opened in exclusive access mode. + + @param aFs Handle to a file server session. + @param aName The full path name of the file. + @param aUid3 The UID used to differentiate between dictionary stores. + @return A pointer to the file based dictionary store object. + @see TUid + @see TUidType */ + { + CDictionaryFileStore* self = new(ELeave) CDictionaryFileStore(); + CleanupStack::PushL(self); + self->ConstructL(aFs,aName,aFileId); + return self; + } + +void CDictionaryFileStore::ConstructL(RFs& aFs,const TDesC& aName,TUid aFileId) +// +// try to open the file - if this fails KErrNotFound try to create it +// if the file is in use retry after a pause +// + { + RYieldThread thread; + TInt64 seed; + const TUidType type(KPermanentFileStoreLayoutUid,KUidDictionaryFile,aFileId); + for (TInt wait=KLockoutLimit;;) + { + RFile file; + TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite); + switch (r) + { + case KErrNone: + { + TInt size; + if (file.Size(size)==KErrNone && size!=0) + { + CFileStore* store=NULL; + TRAP(r,store=CPermanentFileStore::FromL(file)); + if (r==KErrNotSupported||r==KErrEof) + r=KErrCorrupt; // treat a bad store file as corrupt + else if (r==KErrNone && store->Type()!=type) + { + // treat a wrong 3rd UID as corrupt + delete store; + store = NULL; + r=KErrCorrupt; + } + if (r==KErrCorrupt) + { + // silently replace the entire file if it is corrupt + r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite); + if (r==KErrInUse) + break; // try again later... + if (r==KErrNone) + { + CreateStoreL(file,type); + return; + } + } + __LEAVE_IF_ERROR(r); + __ASSERT_DEBUG(store != NULL, User::Invariant()); + //coverity[use_after_free] + iStore = store; + if (store->Root()==KNullStreamId) + CDictionaryStore::ConstructL(); + } + else + CreateStoreL(file,type); + return; + } + case KErrNotFound: + r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite); + if (r==KErrNone) + { + CreateStoreL(file,type); + return; + } + else if (r==KErrAlreadyExists) + ; // try and open after delay + else + __LEAVE(r); + break; + case KErrInUse: + break; + default: + __LEAVE(r); + } + wait-=KFailTime; + if (wait<=0) + break; // waited too long + if (wait>KSpinLimit) + { // straight back to retry + thread.Yield(); // force another reschedule + continue; + } + // random wait time... + if (wait==KSpinLimit) + { // initialise random number generator + TThreadId id=thread.Id(); + TUint idVal=*(const TUint*)&id; + seed = MAKE_TINT64(idVal^TUint(this),idVal^TUint(&id)); + Math::Rand(seed); + Math::Rand(seed); + } + TInt pause=Math::Rand(seed)>>11; + pause=(pause&WaitDistribution[(pause>>8)&0x7])<<10; + if (pause) + { + wait-=pause; + User::After(pause); + } + } + __LEAVE(KErrInUse); + } + +void CDictionaryFileStore::CreateStoreL(RFile& aFile,const TUidType& aType) + { + CFileStore* store = CPermanentFileStore::NewL(aFile); + iStore = store; + store->SetTypeL(aType); + CDictionaryStore::ConstructL(); + }