|
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_noc.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, KSAUidSoftwareInstallKeyValue)); |
|
41 |
|
42 // Initialise SWI operation and status |
|
43 TInt swiProperty; |
|
44 const TInt error = iSWIKey.Get(KUidSystemCategory, KSAUidSoftwareInstallKeyValue, swiProperty); |
|
45 |
|
46 if (error == KErrNone) |
|
47 { |
|
48 iSWIOperation=swiProperty & KSASwisOperationMask; |
|
49 iSWIStatus= swiProperty & KSASwisOperationStatusMask; |
|
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( ESASwisNone), |
|
68 iSWIStatus( ESASwisStatusSuccess) |
|
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 NotifyChange(); |
|
102 |
|
103 // Get SWI Key |
|
104 TInt swiProperty; |
|
105 User::LeaveIfError(iSWIKey.Get(KUidSystemCategory, KSAUidSoftwareInstallKeyValue, swiProperty)); |
|
106 |
|
107 HandleSWIEventL(swiProperty); |
|
108 } |
|
109 |
|
110 void CCentRepSWIWatcher::HandleSWIEventL(TInt aSWIProperty) |
|
111 { |
|
112 iSWIOperation=aSWIProperty & KSASwisOperationMask; |
|
113 iSWIStatus= aSWIProperty & KSASwisOperationStatusMask; |
|
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 ESASwisNone: |
|
120 break; |
|
121 case ESASwisInstall: |
|
122 case ESASwisUninstall: |
|
123 if(iSWIStatus==ESASwisStatusSuccess) |
|
124 { |
|
125 // Handle SWI events |
|
126 FindChangedEntriesL(); |
|
127 } |
|
128 else if(iSWIStatus==ESASwisStatusAborted) |
|
129 { |
|
130 // Update directory to reset timestamps |
|
131 ReadInstallDirL(iInstallEntryArray); |
|
132 SaveInstallDirL(); |
|
133 } |
|
134 break; |
|
135 case ESASwisRestore: |
|
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 |
|
157 // Renable cache activity in case of errors during SWI events |
|
158 TServerResources::iCacheManager->EnableCache(); |
|
159 |
|
160 return KErrNone; |
|
161 } |
|
162 |
|
163 void CCentRepSWIWatcher::DoCancel() |
|
164 { |
|
165 // Cancel subscription to SW P&S flag |
|
166 iSWIKey.Cancel(); |
|
167 iSWIKey.Close(); |
|
168 } |
|
169 |
|
170 void CCentRepSWIWatcher::ReadInstallDirL(RPointerArray<CInstallEntry> &aEntryArray) |
|
171 { |
|
172 RDir dir; |
|
173 CleanupClosePushL(dir); |
|
174 |
|
175 //Empty contents of directory |
|
176 aEntryArray.ResetAndDestroy(); |
|
177 |
|
178 // Read contents of install directory |
|
179 User::LeaveIfError(dir.Open(iFs, iInstallDir, KEntryAttNormal)); |
|
180 |
|
181 TEntryArray dirEntries; |
|
182 TInt readError = KErrNone; |
|
183 |
|
184 while (readError != KErrEof) |
|
185 { |
|
186 readError = dir.Read(dirEntries); |
|
187 |
|
188 if(readError != KErrNone && readError != KErrEof) |
|
189 { |
|
190 User::Leave(readError); |
|
191 } |
|
192 else |
|
193 { |
|
194 const TInt dirCount = dirEntries.Count(); |
|
195 for (TInt i=0; i<dirCount; i++) |
|
196 { |
|
197 CInstallEntry* installEntry = CInstallEntry::NewL(); |
|
198 CleanupStack::PushL(installEntry); |
|
199 installEntry->SetL(const_cast<TEntry&>(dirEntries[i])); |
|
200 if (installEntry->FileExt()==EUnknown) |
|
201 { |
|
202 CleanupStack::PopAndDestroy(); |
|
203 } |
|
204 else |
|
205 { |
|
206 User::LeaveIfError(aEntryArray.Append(installEntry)); |
|
207 CleanupStack::Pop(installEntry); |
|
208 } |
|
209 } |
|
210 } |
|
211 } |
|
212 |
|
213 CleanupStack::PopAndDestroy(&dir); |
|
214 } |
|
215 |
|
216 TBool CCentRepSWIWatcher::MatchEntries( const CInstallEntry &aSource, const CInstallEntry &aTarget) |
|
217 { |
|
218 return((aSource.Uid()==aTarget.Uid()) && |
|
219 (aSource.FileExt()==aTarget.FileExt())); |
|
220 } |
|
221 |
|
222 void CCentRepSWIWatcher::FindChangedEntriesL(TBool aStartup) |
|
223 { |
|
224 // Find added or updated entries |
|
225 ReadInstallDirL(iCurrentInstallDirEntries); |
|
226 |
|
227 TInt newCount=iCurrentInstallDirEntries.Count(); |
|
228 TInt currentCount=iInstallEntryArray.Count(); |
|
229 TInt i; |
|
230 TInt r; |
|
231 TInt operation; |
|
232 |
|
233 // If both counts are 0, we shouldn't have been notified, just return |
|
234 if( (newCount==0) && (currentCount==0)) |
|
235 return; |
|
236 |
|
237 if(aStartup) |
|
238 { |
|
239 operation=ESASwisNone; |
|
240 } |
|
241 else |
|
242 { |
|
243 operation=iSWIOperation; |
|
244 } |
|
245 |
|
246 // We don't want cache activity during SWI operations |
|
247 TServerResources::iCacheManager->DisableCache(); |
|
248 |
|
249 if( newCount==0) // currentCount > 0, newCount = 0 |
|
250 { // All installed files have been deleted |
|
251 // Handle deletes of all files |
|
252 for(i=0;i<currentCount;i++) |
|
253 { |
|
254 iInstallEntryArray[i]->HandleFileDeleteL(operation); |
|
255 } |
|
256 // Free memory of elements |
|
257 iInstallEntryArray.ResetAndDestroy(); |
|
258 } |
|
259 else |
|
260 { |
|
261 if( currentCount==0) // currentCount = 0, newCount > 0 |
|
262 { // All new files need to be handled |
|
263 for(i=0;i<newCount;i++) |
|
264 { |
|
265 CInstallEntry* newEntry=iCurrentInstallDirEntries[i]; |
|
266 newEntry->HandleFileCreateL(operation); |
|
267 } |
|
268 } |
|
269 else // currentCount > 0, newCount > 0 |
|
270 { |
|
271 // Find added and modified entries by going through new entries and |
|
272 // looking for them in current array |
|
273 for(i=0;i<newCount;i++) |
|
274 { |
|
275 CInstallEntry* newEntry=iCurrentInstallDirEntries[i]; |
|
276 r=iInstallEntryArray.Find( newEntry, MatchEntries); |
|
277 // If we find new entry in current array, check modification date |
|
278 if(r>=KErrNone) |
|
279 { |
|
280 CInstallEntry* currentEntry=iInstallEntryArray[r]; |
|
281 if( newEntry->Modified() > currentEntry->Modified()) |
|
282 { |
|
283 // Deal with newly installed file, note use newEntry |
|
284 // so we use new timestamp |
|
285 newEntry->HandleFileUpdateL(operation); |
|
286 } |
|
287 } |
|
288 else if(r==KErrNotFound) // File has been added |
|
289 { |
|
290 // Handle add |
|
291 newEntry->HandleFileCreateL(operation); |
|
292 // Don't leave on KErrNotFound |
|
293 r=KErrNone; |
|
294 } |
|
295 User::LeaveIfError(r); |
|
296 } |
|
297 |
|
298 // Find deleted entries by going through current entries and looking for them |
|
299 // in new array |
|
300 for(i=0;i<currentCount;i++) |
|
301 { |
|
302 CInstallEntry* currentEntry=iInstallEntryArray[i]; |
|
303 r=iCurrentInstallDirEntries.Find( currentEntry, MatchEntries); |
|
304 // If we don't find current entry in new array, it's been deleted |
|
305 if(r==KErrNotFound) |
|
306 { |
|
307 // Deal with uninstalls |
|
308 currentEntry->HandleFileDeleteL(operation); |
|
309 // Don't leave on KErrNotFound |
|
310 r=KErrNone; |
|
311 } |
|
312 User::LeaveIfError(r); |
|
313 } |
|
314 } |
|
315 |
|
316 // Clear out old list |
|
317 iInstallEntryArray.ResetAndDestroy(); |
|
318 |
|
319 // Re-read directory - if any files were corrupt they have been deleted |
|
320 // during the merge, so we need to re-read in case this has occurred |
|
321 ReadInstallDirL(iInstallEntryArray); |
|
322 } |
|
323 |
|
324 SaveInstallDirL(); |
|
325 iCurrentInstallDirEntries.ResetAndDestroy(); |
|
326 |
|
327 // SWI operations finished, enable cache |
|
328 TServerResources::iCacheManager->EnableCache(); |
|
329 } |
|
330 |
|
331 CInstallEntry::CInstallEntry() : |
|
332 iUid(KNullUid), |
|
333 iModified(0), |
|
334 iFileExt(EUnknown) |
|
335 { |
|
336 } |
|
337 |
|
338 CInstallEntry::~CInstallEntry() |
|
339 { |
|
340 if( iRepository) |
|
341 { |
|
342 iRepository->Close(); |
|
343 delete iRepository; |
|
344 } |
|
345 delete iNotifier; |
|
346 } |
|
347 |
|
348 void CInstallEntry::SetL(TEntry& aEntry) |
|
349 { |
|
350 // Get uid from file name |
|
351 const TInt KUidLen = 8; |
|
352 TPtrC uidPtr=aEntry.iName.Des().LeftTPtr(KUidLen); |
|
353 TLex lex=uidPtr; |
|
354 |
|
355 TUint32 uid; |
|
356 User::LeaveIfError(lex.Val(uid,EHex)); |
|
357 iUid.iUid=static_cast<TInt32>(uid); |
|
358 |
|
359 // save extension type |
|
360 _LIT(KIniFileExtension, ".txt"); |
|
361 _LIT(KExternalizedFileExt, ".cre"); |
|
362 |
|
363 const TInt KExtLen = 4; |
|
364 TPtrC extPtr=aEntry.iName.Des().RightTPtr(KExtLen); |
|
365 |
|
366 if(extPtr.Compare(KIniFileExtension)==0) |
|
367 { |
|
368 iFileExt=EIni; |
|
369 } |
|
370 else if(extPtr.Compare(KExternalizedFileExt)==0) |
|
371 { |
|
372 iFileExt=ECre; |
|
373 } |
|
374 else |
|
375 { |
|
376 iFileExt=EUnknown; |
|
377 } |
|
378 |
|
379 iModified=aEntry.iModified; |
|
380 } |
|
381 |
|
382 void CInstallEntry::ConstructL() |
|
383 { |
|
384 // Create repository object |
|
385 iRepository = new(ELeave) CServerRepository; |
|
386 // Notifier needed to open repositories. |
|
387 iNotifier = new(ELeave)CSessionNotifier ; |
|
388 } |
|
389 |
|
390 CInstallEntry* CInstallEntry::NewL() |
|
391 { |
|
392 CInstallEntry* self=new(ELeave)CInstallEntry(); |
|
393 CleanupStack::PushL(self); |
|
394 self->ConstructL(); |
|
395 CleanupStack::Pop(self); |
|
396 return self; |
|
397 } |
|
398 |
|
399 TUid CInstallEntry::Uid() const |
|
400 { |
|
401 return iUid; |
|
402 } |
|
403 |
|
404 TTime CInstallEntry::Modified() const |
|
405 { |
|
406 return iModified; |
|
407 } |
|
408 |
|
409 TCentRepFileType CInstallEntry::FileExt() const |
|
410 { |
|
411 return iFileExt; |
|
412 } |
|
413 |
|
414 void CInstallEntry::ExternalizeL(RWriteStream& aStream) const |
|
415 { |
|
416 aStream << iUid.iUid; |
|
417 aStream << iModified.Int64(); |
|
418 TUint32 fileExt=iFileExt; |
|
419 aStream << fileExt; |
|
420 } |
|
421 |
|
422 void CInstallEntry::InternalizeL(RReadStream& aStream) |
|
423 { |
|
424 aStream >> iUid.iUid; |
|
425 TInt64 time; |
|
426 aStream >> time; |
|
427 iModified=time; |
|
428 TUint32 fileExt; |
|
429 aStream >> fileExt; |
|
430 iFileExt = static_cast<TCentRepFileType>(fileExt); |
|
431 } |
|
432 |
|
433 |
|
434 void CCentRepSWIWatcher::ReadAndInternalizeInstallDirL(const TDesC& aInstallDirFilePath) |
|
435 { |
|
436 RFile file; |
|
437 TInt e=file.Open(TServerResources::iFs,aInstallDirFilePath, EFileRead|EFileShareReadersOnly); |
|
438 if(e == KErrNotFound || e == KErrPathNotFound) |
|
439 { |
|
440 User::Leave(KErrNotFound); |
|
441 } |
|
442 CleanupClosePushL(file); |
|
443 |
|
444 CDirectFileStore* store = CDirectFileStore::FromLC (file); |
|
445 if(store->Type()[0] != KDirectFileStoreLayoutUid) |
|
446 { |
|
447 User::Leave(KErrCorrupt); |
|
448 } |
|
449 |
|
450 iInstallEntryArray.ResetAndDestroy(); |
|
451 |
|
452 // Get the root stream and attempt to read the index from it |
|
453 TStreamId rootStreamId = store->Root() ; |
|
454 RStoreReadStream rootStream ; |
|
455 rootStream.OpenLC(*store, rootStreamId); |
|
456 |
|
457 // Internalize the repository |
|
458 TUint32 count; |
|
459 rootStream >> count; |
|
460 for(TUint i=0; i<count;i++) |
|
461 { |
|
462 CInstallEntry* installEntry = CInstallEntry::NewL(); |
|
463 CleanupStack::PushL(installEntry); |
|
464 rootStream >> *installEntry; |
|
465 User::LeaveIfError(iInstallEntryArray.Append(installEntry)); |
|
466 CleanupStack::Pop(installEntry); |
|
467 } |
|
468 |
|
469 CleanupStack::PopAndDestroy(&rootStream); |
|
470 CleanupStack::PopAndDestroy(store); |
|
471 CleanupStack::PopAndDestroy(); |
|
472 } |
|
473 |
|
474 void CCentRepSWIWatcher::GetInstallDirL() |
|
475 { |
|
476 _LIT(KInstallDirFile, "installdir.bin"); |
|
477 HBufC* filePath = HBufC::NewLC(TServerResources::iDataDirectory->Length() + KInstallDirFile().Length()); |
|
478 TPtr installDirFilePath(filePath->Des()); |
|
479 installDirFilePath.Append(*TServerResources::iDataDirectory); |
|
480 installDirFilePath.Append(KInstallDirFile); |
|
481 |
|
482 TRAPD(err, ReadAndInternalizeInstallDirL(installDirFilePath)); // try to open installdir file and internalize its contents |
|
483 if (err != KErrNone) |
|
484 { |
|
485 TInt fileDeleteErr = TServerResources::iFs.Delete(installDirFilePath); |
|
486 // If a debug build - record error |
|
487 #ifdef _DEBUG |
|
488 if (fileDeleteErr != KErrNone && err != KErrNotFound) |
|
489 { |
|
490 RDebug::Print(_L("CCentRepSWIWatcher::GetInstallDirL - Failed to delete file. Error = %d"), fileDeleteErr); |
|
491 } |
|
492 #else |
|
493 (void)fileDeleteErr; |
|
494 #endif |
|
495 |
|
496 // No file saved - read initial contents of directory |
|
497 ReadInstallDirL(iInstallEntryArray); |
|
498 SaveInstallDirL(); |
|
499 } |
|
500 CleanupStack::PopAndDestroy(filePath); |
|
501 } |
|
502 |
|
503 void CCentRepSWIWatcher::SaveInstallDirL() |
|
504 { |
|
505 _LIT(KInstallDirFile, "installdir.bin"); |
|
506 _LIT(KInstallDirTmpFile, "installdir.tmp"); |
|
507 |
|
508 TBuf<KMaxFileName> installDirTrnsFilePath; |
|
509 installDirTrnsFilePath.Append(*TServerResources::iDataDirectory); |
|
510 installDirTrnsFilePath.Append(KInstallDirTmpFile); |
|
511 |
|
512 // Create file store |
|
513 CDirectFileStore* store = CDirectFileStore::ReplaceLC(TServerResources::iFs, installDirTrnsFilePath, |
|
514 (EFileWrite | EFileShareExclusive)); |
|
515 const TUid uid2 = KNullUid ; |
|
516 store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; |
|
517 |
|
518 // Write the stream index/dictionary as root stream within the store |
|
519 // so we can access it when we do a restore later on |
|
520 RStoreWriteStream rootStream ; |
|
521 TStreamId rootStreamId = rootStream.CreateLC(*store) ; |
|
522 |
|
523 TUint32 count=iInstallEntryArray.Count(); |
|
524 rootStream << count; |
|
525 for(TUint i=0; i<count;i++) |
|
526 { |
|
527 rootStream << *iInstallEntryArray[i]; |
|
528 } |
|
529 |
|
530 rootStream.CommitL() ; |
|
531 |
|
532 CleanupStack::PopAndDestroy(&rootStream) ; |
|
533 store->SetRootL(rootStreamId); |
|
534 store->CommitL(); |
|
535 CleanupStack::PopAndDestroy(store) ; |
|
536 |
|
537 TBuf<KMaxFileName> installDirFilePath; |
|
538 installDirFilePath.Append(*TServerResources::iDataDirectory); |
|
539 installDirFilePath.Append(KInstallDirFile); |
|
540 |
|
541 User::LeaveIfError(TServerResources::iFs.Replace(installDirTrnsFilePath, installDirFilePath)); |
|
542 } |
|
543 |
|
544 |
|
545 void CInstallEntry::HandleFileDeleteL(TInt aOperation) |
|
546 { |
|
547 // File should only have been deleted if operation was uninstall |
|
548 // or in startup case |
|
549 if((aOperation!=ESASwisNone) && (aOperation!=ESASwisUninstall)) |
|
550 User::Leave(KErrAbort); |
|
551 |
|
552 iRepository->HandleSWIDeleteL(Uid(), *iNotifier); |
|
553 } |
|
554 |
|
555 void CInstallEntry::HandleFileCreateL(TInt aOperation) |
|
556 { |
|
557 // File should only have been created if operation was install |
|
558 // or in startup case |
|
559 if((aOperation!=ESASwisNone) && (aOperation!=ESASwisInstall)) |
|
560 User::Leave(KErrAbort); |
|
561 |
|
562 iRepository->HandleSWIUpdateL(Uid(), Modified(), *iNotifier); |
|
563 } |
|
564 |
|
565 void CInstallEntry::HandleFileUpdateL(TInt aOperation) |
|
566 { |
|
567 // File should only have been modified if operation was install |
|
568 // or in startup case |
|
569 if((aOperation!=ESASwisNone) && (aOperation!=ESASwisInstall)) |
|
570 User::Leave(KErrAbort); |
|
571 |
|
572 iRepository->HandleSWIUpdateL(Uid(), Modified(), *iNotifier); |
|
573 } |