|
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "UF_STD.H" |
|
17 #include <e32math.h> |
|
18 |
|
19 const TUid KUidDictionaryFile={0x100000E4}; |
|
20 |
|
21 _LIT(KSystemIniFileLocationSpec,"Z:\\System\\System.ini"); |
|
22 |
|
23 const TUid KSystemIniFileUid = {0x1000010C}; |
|
24 |
|
25 // Thread contention resolution constants |
|
26 |
|
27 const TInt KSpinCount=40; |
|
28 const TInt KLockoutLimit=0xc0000; // to keep the lock-out time down to ~1sec (this is microseconds) |
|
29 const TInt KFailTime=0x1000; // ~ time to fail to open file |
|
30 const TInt KSpinLimit=KLockoutLimit-KSpinCount*KFailTime; |
|
31 |
|
32 LOCAL_C TUint8 const WaitDistribution[8]={0,0,0,0,0x1f,0x3f,0x7f,0xff}; // wait-time distribution mask |
|
33 |
|
34 class RYieldThread : public RThread |
|
35 { |
|
36 public: |
|
37 inline void Yield() const {SetPriority(Priority());} |
|
38 }; |
|
39 |
|
40 ///////////////////////////////////////////// |
|
41 // CDictionaryFileStore |
|
42 ///////////////////////////////////////////// |
|
43 |
|
44 LOCAL_C void EnsurePathL(RFs& aFs,const TDesC& aName) |
|
45 { |
|
46 TInt r=aFs.MkDirAll(TParsePtrC(aName).DriveAndPath()); |
|
47 if (r!=KErrAlreadyExists) |
|
48 User::LeaveIfError(r); |
|
49 } |
|
50 |
|
51 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemL(RFs& aFs) |
|
52 /** Opens the system dictionary file store. |
|
53 |
|
54 @param aFs Handle to a file server session. |
|
55 @return A pointer to the system file based dictionary store object. */ |
|
56 { |
|
57 CDictionaryFileStore* store=SystemLC(aFs); |
|
58 CleanupStack::Pop(); |
|
59 return store; |
|
60 } |
|
61 |
|
62 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemLC(RFs& aFs) |
|
63 /** Opens the system dictionary file store and puts the pointer to the file store |
|
64 object onto the cleanup stack. |
|
65 |
|
66 @param aFs Handle to a file server session. |
|
67 @return A pointer to the system file based dictionary store object. */ |
|
68 { |
|
69 TDriveUnit drive(static_cast<TUint>(RFs::GetSystemDrive())); |
|
70 TParse parse; |
|
71 User::LeaveIfError(parse.Set(drive.Name(), &KSystemIniFileLocationSpec, NULL)); |
|
72 |
|
73 EnsurePathL(aFs, parse.FullName()); |
|
74 return OpenLC(aFs, parse.FullName(), KSystemIniFileUid); |
|
75 } |
|
76 |
|
77 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenL(RFs& aFs,const TDesC& aName,TUid aFileId) |
|
78 /** Creates a file based dictionary store object. |
|
79 |
|
80 If the file with the specified full path name exists, then an attempt is made |
|
81 to open an existing file store contained within this file. Any existing file |
|
82 store must satisfy the following conditions: |
|
83 |
|
84 it must be a valid dictionary store |
|
85 |
|
86 the third UID component of the file store type must match the specified UID; |
|
87 this UID serves to differentiate between dictionary stores |
|
88 |
|
89 otherwise the function leaves with KErrCorrupt. |
|
90 |
|
91 If the file with the specified full path name does not exist, then an attempt |
|
92 is made to create a new file and to create a file based dictionary within |
|
93 it. The third UID component of the file store type is set to the specified |
|
94 UID value. |
|
95 |
|
96 Note that the file is opened in exclusive access mode. |
|
97 |
|
98 @param aFs Handle to a file server session. |
|
99 @param aName The full path name of the file. |
|
100 @param aUid3 The UID used to differentiate between dictionary stores. |
|
101 @return A pointer to the file based dictionary store object. |
|
102 @see TUid |
|
103 @see TUidType */ |
|
104 { |
|
105 CDictionaryFileStore* self = CDictionaryFileStore::OpenLC(aFs,aName,aFileId); |
|
106 CleanupStack::Pop(); |
|
107 return self; |
|
108 } |
|
109 |
|
110 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenLC(RFs& aFs,const TDesC& aName,TUid aFileId) |
|
111 /** Creates a file based dictionary store object and puts the pointer onto the |
|
112 cleanup stack. |
|
113 |
|
114 If the file with the specified full path name exists, then an attempt is made |
|
115 to open an existing file store contained within this file. Any existing file |
|
116 store must satisfy the following conditions: |
|
117 |
|
118 it must be a valid dictionary store |
|
119 |
|
120 the third UID component of the file store type must match the specified UID; |
|
121 this UID serves to differentiate between dictionary stores |
|
122 |
|
123 otherwise the function leaves with KErrCorrupt. |
|
124 |
|
125 If the file with the specified full path name does not exist, then an attempt |
|
126 is made to create a new file and to create a file based dictionary within |
|
127 it. The third UID component of the file store type is set to the specified |
|
128 UID value. |
|
129 |
|
130 Note that the file is opened in exclusive access mode. |
|
131 |
|
132 @param aFs Handle to a file server session. |
|
133 @param aName The full path name of the file. |
|
134 @param aUid3 The UID used to differentiate between dictionary stores. |
|
135 @return A pointer to the file based dictionary store object. |
|
136 @see TUid |
|
137 @see TUidType */ |
|
138 { |
|
139 CDictionaryFileStore* self = new(ELeave) CDictionaryFileStore(); |
|
140 CleanupStack::PushL(self); |
|
141 self->ConstructL(aFs,aName,aFileId); |
|
142 return self; |
|
143 } |
|
144 |
|
145 void CDictionaryFileStore::ConstructL(RFs& aFs,const TDesC& aName,TUid aFileId) |
|
146 // |
|
147 // try to open the file - if this fails KErrNotFound try to create it |
|
148 // if the file is in use retry after a pause |
|
149 // |
|
150 { |
|
151 RYieldThread thread; |
|
152 TInt64 seed; |
|
153 const TUidType type(KPermanentFileStoreLayoutUid,KUidDictionaryFile,aFileId); |
|
154 for (TInt wait=KLockoutLimit;;) |
|
155 { |
|
156 RFile file; |
|
157 TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite); |
|
158 switch (r) |
|
159 { |
|
160 case KErrNone: |
|
161 { |
|
162 TInt size; |
|
163 if (file.Size(size)==KErrNone && size!=0) |
|
164 { |
|
165 CFileStore* store=NULL; |
|
166 TRAP(r,store=CPermanentFileStore::FromL(file)); |
|
167 if (r==KErrNotSupported||r==KErrEof) |
|
168 r=KErrCorrupt; // treat a bad store file as corrupt |
|
169 else if (r==KErrNone && store->Type()!=type) |
|
170 { |
|
171 // treat a wrong 3rd UID as corrupt |
|
172 delete store; |
|
173 store = NULL; |
|
174 r=KErrCorrupt; |
|
175 } |
|
176 if (r==KErrCorrupt) |
|
177 { |
|
178 // silently replace the entire file if it is corrupt |
|
179 r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite); |
|
180 if (r==KErrInUse) |
|
181 break; // try again later... |
|
182 if (r==KErrNone) |
|
183 { |
|
184 CreateStoreL(file,type); |
|
185 return; |
|
186 } |
|
187 } |
|
188 __LEAVE_IF_ERROR(r); |
|
189 __ASSERT_DEBUG(store != NULL, User::Invariant()); |
|
190 //coverity[use_after_free] |
|
191 iStore = store; |
|
192 if (store->Root()==KNullStreamId) |
|
193 CDictionaryStore::ConstructL(); |
|
194 } |
|
195 else |
|
196 CreateStoreL(file,type); |
|
197 return; |
|
198 } |
|
199 case KErrNotFound: |
|
200 r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite); |
|
201 if (r==KErrNone) |
|
202 { |
|
203 CreateStoreL(file,type); |
|
204 return; |
|
205 } |
|
206 else if (r==KErrAlreadyExists) |
|
207 ; // try and open after delay |
|
208 else |
|
209 __LEAVE(r); |
|
210 break; |
|
211 case KErrInUse: |
|
212 break; |
|
213 default: |
|
214 __LEAVE(r); |
|
215 } |
|
216 wait-=KFailTime; |
|
217 if (wait<=0) |
|
218 break; // waited too long |
|
219 if (wait>KSpinLimit) |
|
220 { // straight back to retry |
|
221 thread.Yield(); // force another reschedule |
|
222 continue; |
|
223 } |
|
224 // random wait time... |
|
225 if (wait==KSpinLimit) |
|
226 { // initialise random number generator |
|
227 TThreadId id=thread.Id(); |
|
228 TUint idVal=*(const TUint*)&id; |
|
229 seed = MAKE_TINT64(idVal^TUint(this),idVal^TUint(&id)); |
|
230 Math::Rand(seed); |
|
231 Math::Rand(seed); |
|
232 } |
|
233 TInt pause=Math::Rand(seed)>>11; |
|
234 pause=(pause&WaitDistribution[(pause>>8)&0x7])<<10; |
|
235 if (pause) |
|
236 { |
|
237 wait-=pause; |
|
238 User::After(pause); |
|
239 } |
|
240 } |
|
241 __LEAVE(KErrInUse); |
|
242 } |
|
243 |
|
244 void CDictionaryFileStore::CreateStoreL(RFile& aFile,const TUidType& aType) |
|
245 { |
|
246 CFileStore* store = CPermanentFileStore::NewL(aFile); |
|
247 iStore = store; |
|
248 store->SetTypeL(aType); |
|
249 CDictionaryStore::ConstructL(); |
|
250 } |