|
1 // Copyright (c) 1997-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 // Implements installed file notification |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @internalComponent |
|
20 */ |
|
21 |
|
22 #include "install.h" |
|
23 #include "srvrepos.h" |
|
24 #include "srvres.h" |
|
25 #include "srvparams.h" |
|
26 #include "cachemgr.h" |
|
27 |
|
28 CCentRepSWIWatcher* CCentRepSWIWatcher::NewL(RFs& aFs) |
|
29 { |
|
30 CCentRepSWIWatcher* self = new(ELeave) CCentRepSWIWatcher(aFs); |
|
31 CleanupStack::PushL(self); |
|
32 self->ConstructL(); |
|
33 CleanupStack::Pop(self); |
|
34 return self; |
|
35 } |
|
36 |
|
37 void CCentRepSWIWatcher::ConstructL() |
|
38 { |
|
39 // Attach to SWI property |
|
40 User::LeaveIfError(iSWIKey.Attach( KUidSystemCategory, KUidSoftwareInstallKey)); |
|
41 |
|
42 // Initialise SWI operation and status |
|
43 TInt swiProperty; |
|
44 const TInt error = iSWIKey.Get(KUidSystemCategory, KUidSoftwareInstallKey, swiProperty); |
|
45 |
|
46 if (error == KErrNone) |
|
47 { |
|
48 iSWIOperation=swiProperty & KSwisOperationMask; |
|
49 iSWIStatus= swiProperty & KSwisOperationStatusMask; |
|
50 } |
|
51 else if (error != KErrNotFound) |
|
52 { |
|
53 User::LeaveIfError(error); |
|
54 } |
|
55 |
|
56 // Get last saved contents of install directory |
|
57 GetInstallDirL(); |
|
58 |
|
59 // Do any actions required by pre server start-up SWI activity |
|
60 TRAP_IGNORE(FindChangedEntriesL(ETrue)); |
|
61 } |
|
62 |
|
63 CCentRepSWIWatcher::CCentRepSWIWatcher(RFs& aFs) : |
|
64 CActive(EPriorityStandard), |
|
65 iInstallDir(*TServerResources::iInstallDirectory), |
|
66 iFs(aFs), |
|
67 iSWIOperation( ESwisNone), |
|
68 iSWIStatus( ESwisStatusSuccess) |
|
69 { |
|
70 CActiveScheduler::Add(this); |
|
71 } |
|
72 |
|
73 CCentRepSWIWatcher::~CCentRepSWIWatcher() |
|
74 { |
|
75 Cancel(); |
|
76 iSWIKey.Cancel(); |
|
77 iSWIKey.Close(); |
|
78 iInstallEntryArray.ResetAndDestroy(); |
|
79 iCurrentInstallDirEntries.ResetAndDestroy(); |
|
80 } |
|
81 |
|
82 void CCentRepSWIWatcher::Start() |
|
83 { |
|
84 if(IsActive()) |
|
85 return; |
|
86 |
|
87 NotifyChange(); |
|
88 } |
|
89 |
|
90 void CCentRepSWIWatcher::NotifyChange() |
|
91 { |
|
92 |
|
93 // Register for P&S of SWI flag |
|
94 iSWIKey.Subscribe(iStatus); |
|
95 |
|
96 SetActive(); |
|
97 } |
|
98 |
|
99 void CCentRepSWIWatcher::RunL() |
|
100 { |
|
101 // Get SWI Key |
|
102 TInt swiProperty; |
|
103 User::LeaveIfError(iSWIKey.Get(KUidSystemCategory, KUidSoftwareInstallKey, swiProperty)); |
|
104 |
|
105 HandleSWIEventL(swiProperty); |
|
106 |
|
107 NotifyChange(); |
|
108 } |
|
109 |
|
110 void CCentRepSWIWatcher::HandleSWIEventL(TInt aSWIProperty) |
|
111 { |
|
112 iSWIOperation=aSWIProperty & KSwisOperationMask; |
|
113 iSWIStatus= aSWIProperty & KSwisOperationStatusMask; |
|
114 |
|
115 // Need to handle successful and aborted install/uninstall and successful restore |
|
116 // Can't handle aborted restore |
|
117 switch(iSWIOperation) |
|
118 { |
|
119 case ESwisNone: |
|
120 break; |
|
121 case ESwisInstall: |
|
122 case ESwisUninstall: |
|
123 if(iSWIStatus==ESwisStatusSuccess) |
|
124 { |
|
125 // Handle SWI events |
|
126 FindChangedEntriesL(); |
|
127 } |
|
128 else if(iSWIStatus==ESwisStatusAborted) |
|
129 { |
|
130 // Update directory to reset timestamps |
|
131 ReadInstallDirL(iInstallEntryArray); |
|
132 SaveInstallDirL(); |
|
133 } |
|
134 break; |
|
135 case ESwisRestore: |
|
136 break; |
|
137 default: |
|
138 break; |
|
139 } |
|
140 } |
|
141 |
|
142 // Catch leaves so they don't stop the server |
|
143 TInt CCentRepSWIWatcher::RunError( TInt aError) |
|
144 { |
|
145 static_cast<void>(aError); |
|
146 |
|
147 RDebug::Print(_L("Run error %d"), aError); |
|
148 |
|
149 // Reinitialise directory list |
|
150 iInstallEntryArray.ResetAndDestroy(); |
|
151 |
|
152 if(!IsActive()) |
|
153 { |
|
154 NotifyChange(); |
|
155 } |
|
156 return KErrNone; |
|
157 } |
|
158 |
|
159 void CCentRepSWIWatcher::DoCancel() |
|
160 { |
|
161 // Cancel subscription to SW P&S flag |
|
162 iSWIKey.Cancel(); |
|
163 iSWIKey.Close(); |
|
164 } |
|
165 |
|
166 void CCentRepSWIWatcher::ReadInstallDirL(RPointerArray<CInstallEntry> &aEntryArray) |
|
167 { |
|
168 CDir* installDir=NULL; |
|
169 //Empty contents of directory |
|
170 aEntryArray.ResetAndDestroy(); |
|
171 // Read contents of install directory |
|
172 User::LeaveIfError(iFs.GetDir(iInstallDir,KEntryAttNormal, ESortByDate, installDir)); |
|
173 CleanupStack::PushL(installDir); |
|
174 const TInt fileCount = installDir->Count(); |
|
175 TInt i = 0; |
|
176 for(;i<fileCount; ++i) |
|
177 { |
|
178 CInstallEntry* installEntry = CInstallEntry::NewL(); |
|
179 CleanupStack::PushL(installEntry); |
|
180 TEntry entry=(*installDir)[i]; |
|
181 installEntry->SetL(entry); |
|
182 User::LeaveIfError(aEntryArray.Append(installEntry)); |
|
183 CleanupStack::Pop(installEntry); |
|
184 } |
|
185 CleanupStack::PopAndDestroy(installDir); |
|
186 } |
|
187 |
|
188 TBool CCentRepSWIWatcher::MatchEntries( const CInstallEntry &aSource, const CInstallEntry &aTarget) |
|
189 { |
|
190 return((aSource.Uid()==aTarget.Uid()) && |
|
191 (aSource.FileExt()==aTarget.FileExt())); |
|
192 } |
|
193 |
|
194 void CCentRepSWIWatcher::FindChangedEntriesL(TBool aStartup) |
|
195 { |
|
196 // Find added or updated entries |
|
197 ReadInstallDirL(iCurrentInstallDirEntries); |
|
198 |
|
199 TInt newCount=iCurrentInstallDirEntries.Count(); |
|
200 TInt currentCount=iInstallEntryArray.Count(); |
|
201 TInt i; |
|
202 TInt r; |
|
203 TInt operation; |
|
204 |
|
205 // If both counts are 0, we shouldn't have been notified, just return |
|
206 if( (newCount==0) && (currentCount==0)) |
|
207 return; |
|
208 |
|
209 if(aStartup) |
|
210 { |
|
211 operation=ESwisNone; |
|
212 } |
|
213 else |
|
214 { |
|
215 operation=iSWIOperation; |
|
216 } |
|
217 |
|
218 if( newCount==0) // currentCount > 0, newCount = 0 |
|
219 { // All installed files have been deleted |
|
220 // Handle deletes of all files |
|
221 for(i=0;i<currentCount;i++) |
|
222 { |
|
223 iInstallEntryArray[i]->HandleFileDeleteL(operation); |
|
224 } |
|
225 // Free memory of elements |
|
226 iInstallEntryArray.ResetAndDestroy(); |
|
227 } |
|
228 else |
|
229 { |
|
230 if( currentCount==0) // currentCount = 0, newCount > 0 |
|
231 { // All new files need to be handled |
|
232 for(i=0;i<newCount;i++) |
|
233 { |
|
234 CInstallEntry* newEntry=iCurrentInstallDirEntries[i]; |
|
235 newEntry->HandleFileCreateL(operation); |
|
236 } |
|
237 } |
|
238 else // currentCount > 0, newCount > 0 |
|
239 { |
|
240 // Find added and modified entries by going through new entries and |
|
241 // looking for them in current array |
|
242 for(i=0;i<newCount;i++) |
|
243 { |
|
244 CInstallEntry* newEntry=iCurrentInstallDirEntries[i]; |
|
245 r=iInstallEntryArray.Find( newEntry, MatchEntries); |
|
246 // If we find new entry in current array, check modification date |
|
247 if(r>=KErrNone) |
|
248 { |
|
249 CInstallEntry* currentEntry=iInstallEntryArray[r]; |
|
250 if( newEntry->Modified() > currentEntry->Modified()) |
|
251 { |
|
252 // Deal with newly installed file, note use newEntry |
|
253 // so we use new timestamp |
|
254 newEntry->HandleFileUpdateL(operation); |
|
255 } |
|
256 } |
|
257 else if(r==KErrNotFound) // File has been added |
|
258 { |
|
259 // Handle add |
|
260 newEntry->HandleFileCreateL(operation); |
|
261 // Don't leave on KErrNotFound |
|
262 r=KErrNone; |
|
263 } |
|
264 User::LeaveIfError(r); |
|
265 } |
|
266 |
|
267 // Find deleted entries by going through current entries and looking for them |
|
268 // in new array |
|
269 for(i=0;i<currentCount;i++) |
|
270 { |
|
271 CInstallEntry* currentEntry=iInstallEntryArray[i]; |
|
272 r=iCurrentInstallDirEntries.Find( currentEntry, MatchEntries); |
|
273 // If we don't find current entry in new array, it's been deleted |
|
274 if(r==KErrNotFound) |
|
275 { |
|
276 // Deal with uninstalls |
|
277 currentEntry->HandleFileDeleteL(operation); |
|
278 // Don't leave on KErrNotFound |
|
279 r=KErrNone; |
|
280 } |
|
281 User::LeaveIfError(r); |
|
282 } |
|
283 } |
|
284 |
|
285 // Clear out old list |
|
286 iInstallEntryArray.ResetAndDestroy(); |
|
287 |
|
288 // Re-read directory - if any files were corrupt they have been deleted |
|
289 // during the merge, so we need to re-read in case this has occurred |
|
290 ReadInstallDirL(iInstallEntryArray); |
|
291 } |
|
292 |
|
293 SaveInstallDirL(); |
|
294 iCurrentInstallDirEntries.ResetAndDestroy(); |
|
295 } |
|
296 |
|
297 CInstallEntry::CInstallEntry() : |
|
298 iUid(KNullUid), |
|
299 iModified(0), |
|
300 iFileExt(EUnknown) |
|
301 { |
|
302 } |
|
303 |
|
304 CInstallEntry::~CInstallEntry() |
|
305 { |
|
306 if( iRepository) |
|
307 { |
|
308 iRepository->Close(*iNotifier); |
|
309 delete iRepository; |
|
310 } |
|
311 delete iNotifier; |
|
312 } |
|
313 |
|
314 void CInstallEntry::SetL(TEntry& aEntry) |
|
315 { |
|
316 // Get uid from file name |
|
317 const TInt KUidLen = 8; |
|
318 TPtrC uidPtr=aEntry.iName.Des().LeftTPtr(KUidLen); |
|
319 TLex lex=uidPtr; |
|
320 |
|
321 TUint32 uid; |
|
322 User::LeaveIfError(lex.Val(uid,EHex)); |
|
323 iUid.iUid=static_cast<TInt32>(uid); |
|
324 |
|
325 // save extension type |
|
326 _LIT(KIniFileExtension, ".txt"); |
|
327 _LIT(KExternalizedFileExt, ".cre"); |
|
328 |
|
329 const TInt KExtLen = 4; |
|
330 TPtrC extPtr=aEntry.iName.Des().RightTPtr(KExtLen); |
|
331 |
|
332 if(extPtr.Compare(KIniFileExtension)==0) |
|
333 { |
|
334 iFileExt=EIni; |
|
335 } |
|
336 else if(extPtr.Compare(KExternalizedFileExt)==0) |
|
337 { |
|
338 iFileExt=ECre; |
|
339 } |
|
340 else |
|
341 { |
|
342 iFileExt=EUnknown; |
|
343 } |
|
344 |
|
345 iModified=aEntry.iModified; |
|
346 } |
|
347 |
|
348 void CInstallEntry::ConstructL() |
|
349 { |
|
350 // Create repository object |
|
351 iRepository = new(ELeave) CServerRepository; |
|
352 // Notifier needed to open repositories. |
|
353 iNotifier = new(ELeave)CSessionNotifier ; |
|
354 } |
|
355 |
|
356 CInstallEntry* CInstallEntry::NewL() |
|
357 { |
|
358 CInstallEntry* self=new(ELeave)CInstallEntry(); |
|
359 CleanupStack::PushL(self); |
|
360 self->ConstructL(); |
|
361 CleanupStack::Pop(self); |
|
362 return self; |
|
363 } |
|
364 |
|
365 TUid CInstallEntry::Uid() const |
|
366 { |
|
367 return iUid; |
|
368 } |
|
369 |
|
370 TTime CInstallEntry::Modified() const |
|
371 { |
|
372 return iModified; |
|
373 } |
|
374 |
|
375 TCentRepFileType CInstallEntry::FileExt() const |
|
376 { |
|
377 return iFileExt; |
|
378 } |
|
379 |
|
380 void CInstallEntry::ExternalizeL(RWriteStream& aStream) const |
|
381 { |
|
382 aStream << iUid.iUid; |
|
383 aStream << iModified.Int64(); |
|
384 TUint32 fileExt=iFileExt; |
|
385 aStream << fileExt; |
|
386 } |
|
387 |
|
388 void CInstallEntry::InternalizeL(RReadStream& aStream) |
|
389 { |
|
390 aStream >> iUid.iUid; |
|
391 TInt64 time; |
|
392 aStream >> time; |
|
393 iModified=time; |
|
394 TUint32 fileExt; |
|
395 aStream >> fileExt; |
|
396 iFileExt = static_cast<TCentRepFileType>(fileExt); |
|
397 } |
|
398 |
|
399 void CCentRepSWIWatcher::GetInstallDirL() |
|
400 { |
|
401 _LIT(KInstallDirFile, "installdir.bin"); |
|
402 |
|
403 TBuf<KMaxFileName> installDirFilePath; |
|
404 installDirFilePath.Append(*TServerResources::iDataDirectory); |
|
405 installDirFilePath.Append(KInstallDirFile); |
|
406 |
|
407 TEntry entry; |
|
408 TInt e = TServerResources::iFs.Entry(installDirFilePath, entry); |
|
409 if(e==KErrNotFound || e==KErrPathNotFound) |
|
410 { |
|
411 // No file saved - read initial contents of directory |
|
412 ReadInstallDirL(iInstallEntryArray); |
|
413 SaveInstallDirL(); |
|
414 return; |
|
415 } |
|
416 |
|
417 CDirectFileStore* store = |
|
418 CDirectFileStore::OpenLC (TServerResources::iFs,installDirFilePath, EFileRead|EFileShareReadersOnly); |
|
419 if(store->Type()[0] != KDirectFileStoreLayoutUid) |
|
420 { |
|
421 TServerResources::iFs.Delete(installDirFilePath); |
|
422 } |
|
423 |
|
424 iInstallEntryArray.ResetAndDestroy(); |
|
425 |
|
426 // Get the root stream and attempt to read the index from it |
|
427 TStreamId rootStreamId = store->Root() ; |
|
428 RStoreReadStream rootStream ; |
|
429 rootStream.OpenLC(*store, rootStreamId); |
|
430 |
|
431 // Internalize the repository |
|
432 TUint32 count; |
|
433 rootStream >> count; |
|
434 for(TInt i=0; i<count;i++) |
|
435 { |
|
436 CInstallEntry* installEntry = CInstallEntry::NewL(); |
|
437 rootStream >> *installEntry; |
|
438 CleanupStack::PushL(installEntry); |
|
439 User::LeaveIfError(iInstallEntryArray.Append(installEntry)); |
|
440 CleanupStack::Pop(installEntry); |
|
441 } |
|
442 |
|
443 CleanupStack::PopAndDestroy(&rootStream); |
|
444 CleanupStack::PopAndDestroy(store); |
|
445 } |
|
446 |
|
447 void CCentRepSWIWatcher::SaveInstallDirL() |
|
448 { |
|
449 _LIT(KInstallDirFile, "installdir.bin"); |
|
450 _LIT(KInstallDirTmpFile, "installdir.tmp"); |
|
451 |
|
452 TBuf<KMaxFileName> installDirTrnsFilePath; |
|
453 installDirTrnsFilePath.Append(*TServerResources::iDataDirectory); |
|
454 installDirTrnsFilePath.Append(KInstallDirTmpFile); |
|
455 |
|
456 // Create file store |
|
457 CDirectFileStore* store = CDirectFileStore::ReplaceLC(TServerResources::iFs, installDirTrnsFilePath, |
|
458 (EFileWrite | EFileShareExclusive)); |
|
459 const TUid uid2 = KNullUid ; |
|
460 store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; |
|
461 |
|
462 // Write the stream index/dictionary as root stream within the store |
|
463 // so we can access it when we do a restore later on |
|
464 RStoreWriteStream rootStream ; |
|
465 TStreamId rootStreamId = rootStream.CreateLC(*store) ; |
|
466 |
|
467 TUint32 count=iInstallEntryArray.Count(); |
|
468 rootStream << count; |
|
469 for(TInt i=0; i<count;i++) |
|
470 { |
|
471 rootStream << *iInstallEntryArray[i]; |
|
472 } |
|
473 |
|
474 rootStream.CommitL() ; |
|
475 |
|
476 CleanupStack::PopAndDestroy(&rootStream) ; |
|
477 store->SetRootL(rootStreamId); |
|
478 store->CommitL(); |
|
479 CleanupStack::PopAndDestroy(store) ; |
|
480 |
|
481 TBuf<KMaxFileName> installDirFilePath; |
|
482 installDirFilePath.Append(*TServerResources::iDataDirectory); |
|
483 installDirFilePath.Append(KInstallDirFile); |
|
484 |
|
485 TEntry entry; |
|
486 if(TServerResources::iFs.Entry(installDirFilePath,entry)==KErrNone) |
|
487 { |
|
488 User::LeaveIfError(TServerResources::iFs.Replace(installDirTrnsFilePath, installDirFilePath)); |
|
489 } |
|
490 else |
|
491 { |
|
492 User::LeaveIfError(TServerResources::iFs.Rename(installDirTrnsFilePath, installDirFilePath)); |
|
493 } |
|
494 } |
|
495 |
|
496 |
|
497 void CInstallEntry::HandleFileDeleteL(TInt aOperation) |
|
498 { |
|
499 // File should only have been deleted if operation was uninstall |
|
500 // or in startup case |
|
501 if((aOperation!=ESwisNone) && (aOperation!=ESwisUninstall)) |
|
502 User::Leave(KErrAbort); |
|
503 |
|
504 // We don't want cache activity during SWI operations |
|
505 TServerResources::iCacheManager->DisableCache(); |
|
506 |
|
507 iRepository->HandleSWIDeleteL(Uid(), *iNotifier); |
|
508 |
|
509 // Renable cache activity |
|
510 TServerResources::iCacheManager->EnableCache(); |
|
511 } |
|
512 |
|
513 void CInstallEntry::HandleFileCreateL(TInt aOperation) |
|
514 { |
|
515 // File should only have been created if operation was install |
|
516 // or in startup case |
|
517 if((aOperation!=ESwisNone) && (aOperation!=ESwisInstall)) |
|
518 User::Leave(KErrAbort); |
|
519 |
|
520 // We don't want cache activity during SWI operations |
|
521 TServerResources::iCacheManager->DisableCache(); |
|
522 |
|
523 iRepository->HandleSWIUpdateL(Uid(), Modified(), *iNotifier); |
|
524 |
|
525 // Renable cache activity |
|
526 TServerResources::iCacheManager->EnableCache(); |
|
527 } |
|
528 |
|
529 void CInstallEntry::HandleFileUpdateL(TInt aOperation) |
|
530 { |
|
531 // File should only have been modified if operation was install |
|
532 // or in startup case |
|
533 if((aOperation!=ESwisNone) && (aOperation!=ESwisInstall)) |
|
534 User::Leave(KErrAbort); |
|
535 |
|
536 // We don't want cache activity during SWI operations |
|
537 TServerResources::iCacheManager->DisableCache(); |
|
538 |
|
539 iRepository->HandleSWIUpdateL(Uid(), Modified(), *iNotifier); |
|
540 |
|
541 // Renable cache activity |
|
542 TServerResources::iCacheManager->EnableCache(); |
|
543 } |