sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "UF_STD.H" sl@0: #include sl@0: sl@0: const TUid KUidDictionaryFile={0x100000E4}; sl@0: sl@0: _LIT(KSystemIniFileLocationSpec,"Z:\\System\\System.ini"); sl@0: sl@0: const TUid KSystemIniFileUid = {0x1000010C}; sl@0: sl@0: // Thread contention resolution constants sl@0: sl@0: const TInt KSpinCount=40; sl@0: const TInt KLockoutLimit=0xc0000; // to keep the lock-out time down to ~1sec (this is microseconds) sl@0: const TInt KFailTime=0x1000; // ~ time to fail to open file sl@0: const TInt KSpinLimit=KLockoutLimit-KSpinCount*KFailTime; sl@0: sl@0: LOCAL_C TUint8 const WaitDistribution[8]={0,0,0,0,0x1f,0x3f,0x7f,0xff}; // wait-time distribution mask sl@0: sl@0: class RYieldThread : public RThread sl@0: { sl@0: public: sl@0: inline void Yield() const {SetPriority(Priority());} sl@0: }; sl@0: sl@0: ///////////////////////////////////////////// sl@0: // CDictionaryFileStore sl@0: ///////////////////////////////////////////// sl@0: sl@0: LOCAL_C void EnsurePathL(RFs& aFs,const TDesC& aName) sl@0: { sl@0: TInt r=aFs.MkDirAll(TParsePtrC(aName).DriveAndPath()); sl@0: if (r!=KErrAlreadyExists) sl@0: User::LeaveIfError(r); sl@0: } sl@0: sl@0: EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemL(RFs& aFs) sl@0: /** Opens the system dictionary file store. sl@0: sl@0: @param aFs Handle to a file server session. sl@0: @return A pointer to the system file based dictionary store object. */ sl@0: { sl@0: CDictionaryFileStore* store=SystemLC(aFs); sl@0: CleanupStack::Pop(); sl@0: return store; sl@0: } sl@0: sl@0: EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemLC(RFs& aFs) sl@0: /** Opens the system dictionary file store and puts the pointer to the file store sl@0: object onto the cleanup stack. sl@0: sl@0: @param aFs Handle to a file server session. sl@0: @return A pointer to the system file based dictionary store object. */ sl@0: { sl@0: TDriveUnit drive(static_cast(RFs::GetSystemDrive())); sl@0: TParse parse; sl@0: User::LeaveIfError(parse.Set(drive.Name(), &KSystemIniFileLocationSpec, NULL)); sl@0: sl@0: EnsurePathL(aFs, parse.FullName()); sl@0: return OpenLC(aFs, parse.FullName(), KSystemIniFileUid); sl@0: } sl@0: sl@0: EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenL(RFs& aFs,const TDesC& aName,TUid aFileId) sl@0: /** Creates a file based dictionary store object. sl@0: sl@0: If the file with the specified full path name exists, then an attempt is made sl@0: to open an existing file store contained within this file. Any existing file sl@0: store must satisfy the following conditions: sl@0: sl@0: it must be a valid dictionary store sl@0: sl@0: the third UID component of the file store type must match the specified UID; sl@0: this UID serves to differentiate between dictionary stores sl@0: sl@0: otherwise the function leaves with KErrCorrupt. sl@0: sl@0: If the file with the specified full path name does not exist, then an attempt sl@0: is made to create a new file and to create a file based dictionary within sl@0: it. The third UID component of the file store type is set to the specified sl@0: UID value. sl@0: sl@0: Note that the file is opened in exclusive access mode. sl@0: sl@0: @param aFs Handle to a file server session. sl@0: @param aName The full path name of the file. sl@0: @param aUid3 The UID used to differentiate between dictionary stores. sl@0: @return A pointer to the file based dictionary store object. sl@0: @see TUid sl@0: @see TUidType */ sl@0: { sl@0: CDictionaryFileStore* self = CDictionaryFileStore::OpenLC(aFs,aName,aFileId); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenLC(RFs& aFs,const TDesC& aName,TUid aFileId) sl@0: /** Creates a file based dictionary store object and puts the pointer onto the sl@0: cleanup stack. sl@0: sl@0: If the file with the specified full path name exists, then an attempt is made sl@0: to open an existing file store contained within this file. Any existing file sl@0: store must satisfy the following conditions: sl@0: sl@0: it must be a valid dictionary store sl@0: sl@0: the third UID component of the file store type must match the specified UID; sl@0: this UID serves to differentiate between dictionary stores sl@0: sl@0: otherwise the function leaves with KErrCorrupt. sl@0: sl@0: If the file with the specified full path name does not exist, then an attempt sl@0: is made to create a new file and to create a file based dictionary within sl@0: it. The third UID component of the file store type is set to the specified sl@0: UID value. sl@0: sl@0: Note that the file is opened in exclusive access mode. sl@0: sl@0: @param aFs Handle to a file server session. sl@0: @param aName The full path name of the file. sl@0: @param aUid3 The UID used to differentiate between dictionary stores. sl@0: @return A pointer to the file based dictionary store object. sl@0: @see TUid sl@0: @see TUidType */ sl@0: { sl@0: CDictionaryFileStore* self = new(ELeave) CDictionaryFileStore(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aFs,aName,aFileId); sl@0: return self; sl@0: } sl@0: sl@0: void CDictionaryFileStore::ConstructL(RFs& aFs,const TDesC& aName,TUid aFileId) sl@0: // sl@0: // try to open the file - if this fails KErrNotFound try to create it sl@0: // if the file is in use retry after a pause sl@0: // sl@0: { sl@0: RYieldThread thread; sl@0: TInt64 seed; sl@0: const TUidType type(KPermanentFileStoreLayoutUid,KUidDictionaryFile,aFileId); sl@0: for (TInt wait=KLockoutLimit;;) sl@0: { sl@0: RFile file; sl@0: // When the file server write caching is enabled, the order of file write operations is not guaranteed. sl@0: // This could cause data inconsistency in some circumstances,for example, when the power is lost in the sl@0: // middle of a database transaction.Therefore, the file write caching is disabled for this file to maintain integrity. sl@0: sl@0: TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite|EFileWriteDirectIO); sl@0: switch (r) sl@0: { sl@0: case KErrNone: sl@0: { sl@0: TInt size; sl@0: if (file.Size(size)==KErrNone && size!=0) sl@0: { sl@0: CFileStore* store=NULL; sl@0: TRAP(r,store=CPermanentFileStore::FromL(file)); sl@0: if (r==KErrNotSupported||r==KErrEof) sl@0: r=KErrCorrupt; // treat a bad store file as corrupt sl@0: else if (r==KErrNone && store->Type()!=type) sl@0: { sl@0: // treat a wrong 3rd UID as corrupt sl@0: delete store; sl@0: store = NULL; sl@0: r=KErrCorrupt; sl@0: } sl@0: if (r==KErrCorrupt) sl@0: { sl@0: // silently replace the entire file if it is corrupt sl@0: // When the file server write caching is enabled, the order of file write operations is not guaranteed. sl@0: // This could cause data inconsistency in some circumstances,for example, when the power is lost in the sl@0: // middle of a database transaction.Therefore, the file write caching is disabled for this file to maintain integrity. sl@0: // sl@0: r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite|EFileWriteDirectIO); sl@0: if (r==KErrInUse) sl@0: break; // try again later... sl@0: if (r==KErrNone) sl@0: { sl@0: CreateStoreL(file,type); sl@0: return; sl@0: } sl@0: } sl@0: __LEAVE_IF_ERROR(r); sl@0: __ASSERT_DEBUG(store != NULL, User::Invariant()); sl@0: //coverity[use_after_free] sl@0: iStore = store; sl@0: if (store->Root()==KNullStreamId) sl@0: CDictionaryStore::ConstructL(); sl@0: } sl@0: else sl@0: CreateStoreL(file,type); sl@0: return; sl@0: } sl@0: case KErrNotFound: sl@0: // When the file server write caching is enabled, the order of file write operations is not guaranteed. sl@0: // This could cause data inconsistency in some circumstances,for example, when the power is lost in the sl@0: // middle of a database transaction.Therefore, the file write caching is disabled for this file to maintain integrity. sl@0: r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite|EFileWriteDirectIO); sl@0: if (r==KErrNone) sl@0: { sl@0: CreateStoreL(file,type); sl@0: return; sl@0: } sl@0: else if (r==KErrAlreadyExists) sl@0: ; // try and open after delay sl@0: else sl@0: __LEAVE(r); sl@0: break; sl@0: case KErrInUse: sl@0: break; sl@0: default: sl@0: __LEAVE(r); sl@0: } sl@0: wait-=KFailTime; sl@0: if (wait<=0) sl@0: break; // waited too long sl@0: if (wait>KSpinLimit) sl@0: { // straight back to retry sl@0: thread.Yield(); // force another reschedule sl@0: continue; sl@0: } sl@0: // random wait time... sl@0: if (wait==KSpinLimit) sl@0: { // initialise random number generator sl@0: TThreadId id=thread.Id(); sl@0: TUint idVal=*(const TUint*)&id; sl@0: seed = MAKE_TINT64(idVal^TUint(this),idVal^TUint(&id)); sl@0: Math::Rand(seed); sl@0: Math::Rand(seed); sl@0: } sl@0: TInt pause=Math::Rand(seed)>>11; sl@0: pause=(pause&WaitDistribution[(pause>>8)&0x7])<<10; sl@0: if (pause) sl@0: { sl@0: wait-=pause; sl@0: User::After(pause); sl@0: } sl@0: } sl@0: __LEAVE(KErrInUse); sl@0: } sl@0: sl@0: void CDictionaryFileStore::CreateStoreL(RFile& aFile,const TUidType& aType) sl@0: { sl@0: CFileStore* store = CPermanentFileStore::NewL(aFile); sl@0: iStore = store; sl@0: store->SetTypeL(aType); sl@0: CDictionaryStore::ConstructL(); sl@0: }