|
1 // Copyright (c) 2004-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 <e32def.h> |
|
17 #include <e32property.h> |
|
18 #include <s32file.h> |
|
19 #include <connect/sbdefs.h> |
|
20 #include "srvres.h" |
|
21 #include "cachemgr.h" |
|
22 #include "srvparams.h" |
|
23 #include "shrepos.h" |
|
24 #include "sessnotf.h" |
|
25 #include "backup.h" |
|
26 |
|
27 #define UNUSED_VAR(a) a = a |
|
28 |
|
29 _LIT (KBackupFileName, "BACKUP") ; |
|
30 _LIT (KRestoreFileName, "RESTORE") ; |
|
31 _LIT(KBackupFileExt, ".bak"); |
|
32 _LIT(KRestoreFileExt, ".rst"); |
|
33 |
|
34 |
|
35 TRepositoryBackupState CRepositoryBackupClient::iBackupStatus ; |
|
36 |
|
37 |
|
38 // |
|
39 // Backup stream index class - Used to hold association between a UID (in |
|
40 // our case the UID of a repository) and a stream ID - Can't use CStreamDictionary |
|
41 // because that only lets you retrieve stream IDs by a (previously known) UID rather |
|
42 // than iterate through its contentsretrieving UID/StreamID pairs... |
|
43 // |
|
44 |
|
45 |
|
46 // |
|
47 // CRepositoryBackupStreamIndex::AddL |
|
48 // |
|
49 // Add a new repository UID and stream ID pair to the index |
|
50 void CRepositoryBackupStreamIndex::AddL(TUid aUid, TStreamId aSettingStreamId, TStreamId aDeletedSettingsStreamId, TStreamId aInstalledSettingsStreamId) |
|
51 { |
|
52 TRepositoryBackupStreamIndexElement newIndexElement; |
|
53 newIndexElement.Set(aUid,aSettingStreamId, aDeletedSettingsStreamId, aInstalledSettingsStreamId) ; |
|
54 iStreamIndex.AppendL(newIndexElement); |
|
55 } |
|
56 |
|
57 |
|
58 // |
|
59 // CRepositoryBackupStreamIndex::GetNext |
|
60 // |
|
61 // Iterate through the index retrieving the next Reposirory UID and Stream ID |
|
62 // pair. |
|
63 // |
|
64 TInt CRepositoryBackupStreamIndex::GetNext(TUid& aUid, TStreamId& aSettingsStreamId, TStreamId& aDeletedSettingsStreamId, TStreamId& aInstalledSettingsStreamId) |
|
65 { |
|
66 TInt error = KErrNone ; |
|
67 if (iIndex < iStreamIndex.Count()) |
|
68 { |
|
69 iStreamIndex[iIndex++].Get(aUid, aSettingsStreamId, aDeletedSettingsStreamId, aInstalledSettingsStreamId) ; |
|
70 } |
|
71 else |
|
72 { |
|
73 error = KErrNotFound ; |
|
74 } |
|
75 return error ; |
|
76 } |
|
77 |
|
78 |
|
79 // |
|
80 // Backup client class. |
|
81 // |
|
82 // Has Active object functionality to monitor the state of the publish and subscribe |
|
83 // flags associated with backup and restore and also implements MActiveBackupDataClient |
|
84 // to perform active backup according to the "proxy data holder" model. |
|
85 // |
|
86 |
|
87 |
|
88 |
|
89 // |
|
90 // Usual 2 phase construction factory NewL NewLC classes |
|
91 // |
|
92 CRepositoryBackupClient* CRepositoryBackupClient::NewLC(RFs& aFs) |
|
93 { |
|
94 CRepositoryBackupClient* me = new(ELeave)CRepositoryBackupClient(aFs); |
|
95 CleanupStack::PushL(me) ; |
|
96 me->ConstructL() ; |
|
97 return me ; |
|
98 } |
|
99 |
|
100 |
|
101 CRepositoryBackupClient* CRepositoryBackupClient::NewL(RFs& aFs) |
|
102 { |
|
103 CRepositoryBackupClient* me = CRepositoryBackupClient::NewLC(aFs) ; |
|
104 CleanupStack::Pop(me) ; |
|
105 return me ; |
|
106 } |
|
107 |
|
108 |
|
109 |
|
110 // |
|
111 // Constructor - doesn't really do anything! |
|
112 // |
|
113 CRepositoryBackupClient::CRepositoryBackupClient(RFs& aFs) : CActive(EPriorityStandard), iFs(aFs), iRomScanDone(EFalse) |
|
114 { |
|
115 } |
|
116 |
|
117 |
|
118 // |
|
119 // Phase 2 constructor |
|
120 // |
|
121 void CRepositoryBackupClient::ConstructL() |
|
122 { |
|
123 // Create repository object |
|
124 iRepository = new(ELeave) CServerRepository; |
|
125 |
|
126 // Notifier needed to open repositories. |
|
127 iNotifier = new(ELeave)CSessionNotifier ; |
|
128 |
|
129 // Attach to Backup/Restore Pub/Sub property. |
|
130 User::LeaveIfError(iBackupRestoreProperty.Attach(KUidSystemCategory, KUidBackupRestoreKey)) ; |
|
131 |
|
132 // Add ourself to the active scheduler |
|
133 CActiveScheduler::Add(this) ; |
|
134 |
|
135 // Initialise backup/restore status |
|
136 iBackupStatus = ENoBackupActivty ; |
|
137 |
|
138 // Set active and request notification of changes to backup/restore |
|
139 // Pub/Sub property. |
|
140 StartL() ; |
|
141 } |
|
142 |
|
143 |
|
144 |
|
145 // |
|
146 // Destructor |
|
147 // |
|
148 CRepositoryBackupClient::~CRepositoryBackupClient() |
|
149 { |
|
150 Cancel(); |
|
151 |
|
152 iBackupRestoreProperty.Close() ; |
|
153 |
|
154 if (iRepository) |
|
155 { |
|
156 iRepository->Close(); |
|
157 delete(iRepository); |
|
158 } |
|
159 |
|
160 if (iNotifier) |
|
161 delete(iNotifier) ; |
|
162 |
|
163 if (iActiveBackupClient) |
|
164 delete(iActiveBackupClient) ; |
|
165 |
|
166 iRestoredRepositoriesArray.ResetAndDestroy(); |
|
167 iRestoredRepositoriesArray.Close(); |
|
168 |
|
169 iFile.Close(); |
|
170 } |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 // |
|
176 // DoCancel - mandatory for active objects. |
|
177 // |
|
178 void CRepositoryBackupClient::DoCancel() |
|
179 { |
|
180 iBackupRestoreProperty.Cancel() ; |
|
181 } |
|
182 |
|
183 |
|
184 |
|
185 // |
|
186 // RunError |
|
187 // |
|
188 TInt CRepositoryBackupClient::RunError(TInt aError) |
|
189 { |
|
190 iRestoredRepositoriesArray.ResetAndDestroy(); |
|
191 UNUSED_VAR(aError); |
|
192 return KErrNone; |
|
193 } |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 // |
|
199 // Test BUR Pub/Sub property set status, and notify BUR that we're |
|
200 // ready to go as appropriate. |
|
201 // |
|
202 void CRepositoryBackupClient::TestBURstatusL(void) |
|
203 { |
|
204 TInt BURstatus ; |
|
205 TRepositoryBackupState lastBackupStatus = ENoBackupActivty; |
|
206 if (iBackupRestoreProperty.Get(BURstatus) != KErrNotFound) |
|
207 { |
|
208 BURstatus &= KBURPartTypeMask ; |
|
209 switch (BURstatus) |
|
210 { |
|
211 case EBURUnset: // State not yet set. Treat as no backup/restore in progress. |
|
212 case EBURNormal: |
|
213 // No backup or restore in progress. Probably |
|
214 // means we've just completed an operation? |
|
215 |
|
216 lastBackupStatus = iBackupStatus; |
|
217 iBackupStatus = ENoBackupActivty ; |
|
218 |
|
219 // Back to normal, so enable cache |
|
220 TServerResources::iCacheManager->EnableCache(); |
|
221 // delete the CActiveBackupClient |
|
222 if (iActiveBackupClient) |
|
223 { |
|
224 delete iActiveBackupClient ; |
|
225 iActiveBackupClient = NULL ; |
|
226 } |
|
227 |
|
228 // Notify the changed keys if a restoration was just completed |
|
229 if((lastBackupStatus == ERestoreInProgress)) |
|
230 { |
|
231 for(TInt i = 0; i < iRestoredRepositoriesArray.Count(); i++) |
|
232 { |
|
233 iRepository->OpenL(iRestoredRepositoriesArray[i]->Uid(), *iNotifier, EFalse); |
|
234 iRepository->RestoreNotify(*iRestoredRepositoriesArray[i]); |
|
235 iRepository->Close(); |
|
236 } |
|
237 iRestoredRepositoriesArray.ResetAndDestroy(); |
|
238 } |
|
239 |
|
240 break ; |
|
241 |
|
242 case EBURBackupFull : |
|
243 case EBURBackupPartial : |
|
244 // We don't distinguish between full and partial backups |
|
245 // as the Backup engine will give us UIDs for all the |
|
246 // repository data owners that want their stuff backed up |
|
247 // anyway. |
|
248 |
|
249 // We don't want cache activity during backup |
|
250 TServerResources::iCacheManager->DisableCache(); |
|
251 |
|
252 // Any (and all!) repositories which have been opened in the |
|
253 // course of system boot and normal operation will have been |
|
254 // added to TServerResources::iOwnerIdLookUpTable as they were |
|
255 // opened but there may well be repositories which need backing |
|
256 // up and haven't yet been opened so we need to make sure that |
|
257 // the lookup table is complete. |
|
258 CompleteOwnerIdLookupTableL(); |
|
259 |
|
260 // Register with BUR engine |
|
261 if (!iActiveBackupClient) |
|
262 { |
|
263 iActiveBackupClient = CActiveBackupClient::NewL(this) ; |
|
264 } |
|
265 iActiveBackupClient->ConfirmReadyForBURL(KErrNone); |
|
266 iBackupStatus = EBackupInProgress ; |
|
267 break ; |
|
268 |
|
269 case EBURRestoreFull : |
|
270 case EBURRestorePartial : |
|
271 // We don't distinguish between full and partial restore |
|
272 // either! |
|
273 |
|
274 // We don't want cache activity during restore either! |
|
275 TServerResources::iCacheManager->DisableCache(); |
|
276 |
|
277 // Register with BUR engine |
|
278 if (!iActiveBackupClient) |
|
279 { |
|
280 iActiveBackupClient = CActiveBackupClient::NewL(this) ; |
|
281 } |
|
282 iActiveBackupClient->ConfirmReadyForBURL(KErrNone); |
|
283 iBackupStatus = ERestoreInProgress ; |
|
284 break ; |
|
285 |
|
286 } |
|
287 } |
|
288 } |
|
289 |
|
290 |
|
291 // |
|
292 // Request notification of changes in BUR Pub/Sub status |
|
293 // |
|
294 void CRepositoryBackupClient::StartL() |
|
295 { |
|
296 if (!IsActive()) |
|
297 { |
|
298 TestBURstatusL(); |
|
299 NotifyChange(); |
|
300 } |
|
301 } |
|
302 |
|
303 |
|
304 // |
|
305 // Request notification of changes in BUR Pub/Sub status |
|
306 // |
|
307 void CRepositoryBackupClient::NotifyChange() |
|
308 { |
|
309 // Watch for changes in the property state. |
|
310 iBackupRestoreProperty.Subscribe(iStatus) ; |
|
311 SetActive(); |
|
312 } |
|
313 |
|
314 |
|
315 // |
|
316 // Handle changes of backup state through publish/subscribe |
|
317 // |
|
318 void CRepositoryBackupClient::RunL() |
|
319 { |
|
320 NotifyChange() ; |
|
321 TestBURstatusL(); |
|
322 } |
|
323 |
|
324 |
|
325 // |
|
326 // We can't estimate data size without A) having the SID of the data owner who's data |
|
327 // is to be backed up and B) going through the whole process of preparing the backup. |
|
328 // |
|
329 // The only sensible thing we can do is return an arbitrary value! |
|
330 // |
|
331 TUint CRepositoryBackupClient::GetExpectedDataSize(TDriveNumber /* aDrive */) |
|
332 { |
|
333 return KArbitraryNumber ; |
|
334 } |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 // |
|
340 // Called by BUR engine to request a chunk of backup data. |
|
341 // |
|
342 void CRepositoryBackupClient::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinished) |
|
343 { |
|
344 const TInt chunkSize = aBuffer.MaxSize() ; |
|
345 |
|
346 aFinished = EFalse ; |
|
347 |
|
348 // Pass a chunk of our prepared backup data in aBuffer |
|
349 User::LeaveIfError(iFile.Read(aBuffer, chunkSize)) ; |
|
350 TInt bytesRead = aBuffer.Length() ; |
|
351 |
|
352 // Check to see if this was the last chunk of data. |
|
353 if (bytesRead < chunkSize) |
|
354 { |
|
355 // Set "finished" flag so that BUR knows we're through... |
|
356 aFinished = ETrue ; |
|
357 |
|
358 // ...and then tidy up by closing and deleting the backup file. |
|
359 iFile.Close() ; |
|
360 TParse backupFilePath ; |
|
361 User::LeaveIfError(backupFilePath.Set(KBackupFileName, TServerResources::iBURDirectory, &KBackupFileExt)); |
|
362 TInt fileDeleteErr=iFs.Delete(backupFilePath.FullName()) ; |
|
363 #ifdef _DEBUG |
|
364 if (fileDeleteErr != KErrNone) |
|
365 { |
|
366 RDebug::Print(_L("CRepositoryBackupClient::GetBackupDataSectionL - Failed to delete file. Error = %d"), fileDeleteErr); |
|
367 } |
|
368 #else |
|
369 UNUSED_VAR(fileDeleteErr); |
|
370 #endif |
|
371 |
|
372 } |
|
373 } |
|
374 |
|
375 // |
|
376 // CRepositoryBackupClient::RestoreComplete |
|
377 // |
|
378 // Called when a Complete set of backup data has been received and written |
|
379 // to a file. We now need to open the file as a stream store, get the |
|
380 // index (list of repository UID and corresponding stream ID pairs, and then |
|
381 // reconstruct and save each repository in turn. |
|
382 // |
|
383 void CRepositoryBackupClient::RestoreComplete(TDriveNumber /* aDrive */) |
|
384 { |
|
385 } |
|
386 |
|
387 |
|
388 |
|
389 // |
|
390 // CRepositoryBackupClient::RestoreCompleteL |
|
391 // |
|
392 // Does the actual work of reconstructing repositories from backup data |
|
393 // |
|
394 // |
|
395 void CRepositoryBackupClient::RestoreCompleteL() |
|
396 { |
|
397 // All restore data recived so we can now recreate the repositories from the |
|
398 // backup store |
|
399 // Attempt to open the restore file as a CDirectFileStore |
|
400 TParse restoreFilePath ; |
|
401 User::LeaveIfError(restoreFilePath.Set(KRestoreFileName, TServerResources::iBURDirectory, &KRestoreFileExt)); |
|
402 CDirectFileStore* store = CDirectFileStore::OpenLC (iFs,restoreFilePath.FullName(), EFileRead|EFileShareReadersOnly); |
|
403 if (store->Type()[0] != KDirectFileStoreLayoutUid) |
|
404 { |
|
405 // store wasn't quite what we were expecting - can't return an error, can't leave |
|
406 // so all we can do is close the file, tidy up as best we can, and bail out!!!! |
|
407 CleanupStack::PopAndDestroy(store); |
|
408 // If a debug build - record error |
|
409 TInt fileDeleteErr=iFs.Delete(restoreFilePath.FullName()) ; |
|
410 #ifdef _DEBUG |
|
411 if (fileDeleteErr != KErrNone) |
|
412 { |
|
413 RDebug::Print(_L("CRepositoryBackupClient::RestoreCompleteL - Failed to delete file. Error = %d"), fileDeleteErr); |
|
414 } |
|
415 #else |
|
416 UNUSED_VAR(fileDeleteErr); |
|
417 #endif |
|
418 |
|
419 User::Leave(KErrCorrupt); |
|
420 } |
|
421 |
|
422 |
|
423 |
|
424 // Get the root stream and attempt to read a backup file header from it |
|
425 TStreamId rootStreamId = store->Root() ; |
|
426 RStoreReadStream rootStream ; |
|
427 RStoreReadStream indexStream ; |
|
428 rootStream.OpenLC(*store, rootStreamId); |
|
429 TRepositoryBackupStreamHeader header ; |
|
430 TRAPD(err, header.InternalizeL(rootStream)) ; |
|
431 |
|
432 // Check for a valid header by checking that the UID matches the UID |
|
433 // of Central Repository and that the version number is sane. |
|
434 if (err == KErrNotSupported) |
|
435 { |
|
436 // Not a valid header - assume it's an old style backup stream, |
|
437 // set extensions supported to none, set index stream to be |
|
438 // root stream and reset read pointer to beginning. |
|
439 iBackupExtensionsSupported = ENoBackupExtensions ; |
|
440 |
|
441 CleanupStack::PopAndDestroy(&rootStream) ; |
|
442 CleanupStack::PopAndDestroy(store) ; |
|
443 |
|
444 // Try re-opening as old-style backup stream with index |
|
445 // as root stream. |
|
446 CDirectFileStore* store = CDirectFileStore::OpenLC (iFs,restoreFilePath.FullName(), EFileRead|EFileShareReadersOnly); |
|
447 indexStream.OpenLC(*store, rootStreamId) ; |
|
448 } |
|
449 else |
|
450 { |
|
451 // Got a valid header. Check for extensions supported by this |
|
452 // stream and get stream to read index from |
|
453 CleanupStack::PopAndDestroy(&rootStream) ; |
|
454 iBackupExtensionsSupported = header.getBackupExtensionsSupported(); |
|
455 TStreamId indexStreamId = header.getIndexStreamId() ; |
|
456 indexStream.OpenLC (*store, indexStreamId) ; |
|
457 } |
|
458 |
|
459 CRepositoryBackupStreamIndex *restoreStreamIndex = CRepositoryBackupStreamIndex::NewLC(); |
|
460 restoreStreamIndex->InternalizeL(indexStream, iBackupExtensionsSupported); |
|
461 |
|
462 |
|
463 // Iterate through index and attempt restore of each repository stream |
|
464 // we find in it. |
|
465 restoreStreamIndex->Reset() ; |
|
466 TUid repositoryUid ; |
|
467 TStreamId settingsStreamId(KNullStreamIdValue); |
|
468 TStreamId deletedSettingsStreamId(KNullStreamIdValue); |
|
469 TStreamId installedSettingsStreamId(KNullStreamIdValue); |
|
470 |
|
471 while (restoreStreamIndex->GetNext(repositoryUid, settingsStreamId, deletedSettingsStreamId, installedSettingsStreamId) == KErrNone) |
|
472 { |
|
473 iRepository->OpenL(repositoryUid, *iNotifier, EFalse); |
|
474 iRepository->FailAllTransactions(); |
|
475 // Add the restored repository to the restored repositories list. |
|
476 // Pass its changed-keys list to further restoring functions to add entries for post-restoration notification. |
|
477 TInt repIndex = AddRestoredRepositoryL(repositoryUid); |
|
478 iRepository->RestoreRepositoryContentsL(*store, settingsStreamId, deletedSettingsStreamId, *iRestoredRepositoriesArray[repIndex]); |
|
479 iRepository->CommitChangesL(); |
|
480 iRepository->Close(); |
|
481 // If the backup contains an installed repository containing default values for the settings, read them in |
|
482 if (installedSettingsStreamId != KNullStreamId) |
|
483 { |
|
484 // create an empty repository in install directory, and restore the data from backup file |
|
485 iRepository->RestoreInstallRepositoryL(repositoryUid, *store, installedSettingsStreamId, *iRestoredRepositoriesArray[repIndex]); |
|
486 // remove the .ini install file (if exists) because it will clash with the restored file |
|
487 TServerResources::DeleteCentrepFileL(repositoryUid, EInstall, EIni); |
|
488 } |
|
489 } |
|
490 |
|
491 CleanupStack::PopAndDestroy(restoreStreamIndex) ; |
|
492 CleanupStack::PopAndDestroy(&indexStream); |
|
493 CleanupStack::PopAndDestroy(store); |
|
494 // If a debug build - record error |
|
495 TInt fileDeleteErr=iFs.Delete(restoreFilePath.FullName()); |
|
496 #ifdef _DEBUG |
|
497 if (fileDeleteErr != KErrNone) |
|
498 { |
|
499 RDebug::Print(_L("CRepositoryBackupClient::RestoreCompleteL (2nd) - Failed to delete file. Error = %d"), fileDeleteErr); |
|
500 } |
|
501 #else |
|
502 UNUSED_VAR(fileDeleteErr); |
|
503 #endif |
|
504 |
|
505 } |
|
506 |
|
507 // |
|
508 // CRepositoryBackupClient::CompleteOwnerIdLookupTableL |
|
509 // |
|
510 // Open each repository in TServerResources::iDataDirectory. |
|
511 // Save the Rep UID and Owner Id of the rep to be used by |
|
512 // InitialiseGetProxyBackupDataL. |
|
513 void CRepositoryBackupClient::CompleteOwnerIdLookupTableL() |
|
514 { |
|
515 |
|
516 // Read contents of persist, install, and ROM directories and |
|
517 // use them to build a list of repository candidates. |
|
518 RArray <TUint32> repositoryList ; |
|
519 CleanupClosePushL(repositoryList) ; |
|
520 |
|
521 for (TBackupDirectoryScan scanDir = EScanRom; scanDir <= EScanPersist; scanDir = (TBackupDirectoryScan)(scanDir+1)) |
|
522 { |
|
523 TPtrC directoryName ; |
|
524 switch (scanDir) |
|
525 { |
|
526 case EScanRom : |
|
527 if (TServerResources::iRomDirectory) |
|
528 { |
|
529 directoryName.Set(TServerResources::iRomDirectory->Des()) ; |
|
530 } |
|
531 else |
|
532 { |
|
533 // if ROM directory doesn't exist or there are no files, skip scanning |
|
534 continue; |
|
535 } |
|
536 break ; |
|
537 |
|
538 case EScanInstall : |
|
539 directoryName.Set(TServerResources::iInstallDirectory->Des()) ; |
|
540 break ; |
|
541 |
|
542 case EScanPersist : |
|
543 directoryName.Set(TServerResources::iDataDirectory->Des()) ; |
|
544 break ; |
|
545 } |
|
546 |
|
547 RDir dir; |
|
548 CleanupClosePushL(dir); |
|
549 User::LeaveIfError(dir.Open(iFs, directoryName, KEntryAttNormal)); |
|
550 |
|
551 TEntryArray dirEntries; |
|
552 TInt readError = KErrNone; |
|
553 |
|
554 while (readError != KErrEof) |
|
555 { |
|
556 readError = dir.Read(dirEntries); |
|
557 |
|
558 if(readError != KErrNone && readError != KErrEof) |
|
559 { |
|
560 User::Leave(readError); |
|
561 } |
|
562 else |
|
563 { |
|
564 const TInt dirCount = dirEntries.Count(); |
|
565 for (TInt i=0; i<dirCount; i++) |
|
566 { |
|
567 // Attempt to extract a repository UID from directory entry |
|
568 TUid uid; |
|
569 TInt insertionError; |
|
570 if (KErrNone == TServerResources::GetUid(const_cast<TEntry&>(dirEntries[i]), uid)) |
|
571 { |
|
572 insertionError=repositoryList.InsertInUnsignedKeyOrder(uid.iUid) ; |
|
573 // Should leave in all cases other than KErrNone or KErrAlreadyExists |
|
574 if((insertionError != KErrNone) && (insertionError != KErrAlreadyExists )) |
|
575 { |
|
576 User::Leave(insertionError); |
|
577 } |
|
578 } |
|
579 } |
|
580 } |
|
581 } |
|
582 |
|
583 CleanupStack::PopAndDestroy(&dir); |
|
584 } |
|
585 |
|
586 // Open all repositories in turn. Save repository UID and owner ID |
|
587 // in lookup table. |
|
588 for(TInt i = 0; i<repositoryList.Count(); i++) |
|
589 { |
|
590 // Look to see if this repository already has an entry in the owner ID lookup table |
|
591 if ( TServerResources::FindOwnerIdLookupMapping(repositoryList[i]) == KErrNotFound) |
|
592 { |
|
593 // Need to TRAP here as otherwise if ANY repository fails to open |
|
594 // (e.g. due to corruption) it would cause the entire backup to |
|
595 // fail |
|
596 TRAPD(err, iRepository->OpenL(TUid::Uid(repositoryList[i]), *iNotifier)); |
|
597 if (err == KErrNoMemory) |
|
598 { |
|
599 User::Leave(err) ; |
|
600 } |
|
601 |
|
602 else if (err == KErrNone) |
|
603 { |
|
604 // The act of opening a repository will cause it to add itself to the |
|
605 // Repository/Owner UID mapping table so we don't need to do anything |
|
606 // and can close it immediately! |
|
607 iRepository->Close(); |
|
608 } |
|
609 } |
|
610 } |
|
611 |
|
612 CleanupStack::PopAndDestroy() ; // repositoryList |
|
613 } |
|
614 |
|
615 // CRepositoryBackupClient::InitialiseGetProxyBackupDataL |
|
616 // |
|
617 // Prepare data to be backed up. We get the Sid/Uid of the entity whos data |
|
618 // is to be backed up. What we do is to open each repository in turn (identified |
|
619 // by directory listing), check its owner, and if it matches the Sid/Uid we've |
|
620 // been given by secure backup externalise it to a stream within a file store. |
|
621 // |
|
622 void CRepositoryBackupClient::InitialiseGetProxyBackupDataL(TSecureId aSID, TDriveNumber /* aDrive */) |
|
623 { |
|
624 // Prepare data for backup. |
|
625 |
|
626 // Create file store |
|
627 TParse backupFilePath ; |
|
628 User::LeaveIfError(backupFilePath.Set(KBackupFileName, TServerResources::iBURDirectory, &KBackupFileExt)); |
|
629 CDirectFileStore* store = CDirectFileStore::ReplaceLC(iFs, backupFilePath.FullName(), |
|
630 (EFileWrite | EFileShareExclusive)); |
|
631 const TUid uid2 = KNullUid ; |
|
632 store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; |
|
633 |
|
634 // Create a Backup Stream index |
|
635 CRepositoryBackupStreamIndex* backupStreamIndex = CRepositoryBackupStreamIndex::NewLC(); |
|
636 |
|
637 // Find the reps owned by aSID |
|
638 for(TInt i = 0; i < TServerResources::iOwnerIdLookUpTable.Count(); ++i) |
|
639 { |
|
640 const TOwnerIdMapping& lookupTableEntry = TServerResources::iOwnerIdLookUpTable[i]; |
|
641 |
|
642 if ( lookupTableEntry.iOwner == aSID ) |
|
643 { |
|
644 TStreamId settingStreamId(KNullStreamIdValue); |
|
645 TStreamId deletedSettingsStreamId(KNullStreamIdValue); |
|
646 TStreamId installedSettingStreamId(KNullStreamIdValue); |
|
647 // Found one match, open the repository and externalise content. |
|
648 TUid uid = TUid::Uid(lookupTableEntry.iRepUid); |
|
649 TRAPD(err,iRepository->OpenL(uid, *iNotifier)); |
|
650 if (err == KErrNoMemory) |
|
651 { |
|
652 User::Leave(err) ; |
|
653 } |
|
654 else if (err == KErrNone) |
|
655 { |
|
656 iRepository->FailAllTransactions(); |
|
657 // externalise repository contents |
|
658 iRepository->StoreRepositoryContentsL(*store, settingStreamId, deletedSettingsStreamId); |
|
659 // Close repository. |
|
660 iRepository->Close(); |
|
661 } |
|
662 |
|
663 TBool installExists=TServerResources::InstallFileExistsL(uid); |
|
664 if(installExists) |
|
665 { |
|
666 // load existing repository from install directory (default values installed post-build by SWI) |
|
667 // and externalise installed repository contents |
|
668 TRAPD(err, iRepository->BackupInstallRepositoryL(uid, *store, installedSettingStreamId)); |
|
669 // We trap and discard most errors to be able to continue backing up other repositories in the list |
|
670 if (err == KErrNoMemory) |
|
671 { |
|
672 User::Leave(err) ; |
|
673 } |
|
674 else if (err != KErrNone) |
|
675 { |
|
676 // If for any reason we haven't been able to back up the install repository, |
|
677 // we create an empty stream to preserve the format |
|
678 installedSettingStreamId = KNullStreamIdValue; |
|
679 } |
|
680 } |
|
681 // Add all to store index |
|
682 backupStreamIndex->AddL(uid, settingStreamId, deletedSettingsStreamId, installedSettingStreamId) ; |
|
683 |
|
684 } |
|
685 } |
|
686 // Write the stream index/dictionary as root stream within the store |
|
687 // so we can access it when we do a restore later on |
|
688 RStoreWriteStream indexStream ; |
|
689 TStreamId indexStreamId = indexStream.CreateLC(*store) ; |
|
690 backupStreamIndex->ExternalizeL(indexStream) ; |
|
691 indexStream.CommitL() ; |
|
692 CleanupStack::PopAndDestroy(&indexStream) ; |
|
693 CleanupStack::PopAndDestroy (backupStreamIndex) ; |
|
694 |
|
695 // Create the Header and write it as the root stream within the store |
|
696 // so we can access it when we do a restore later on |
|
697 TRepositoryBackupStreamHeader header (indexStreamId) ; |
|
698 RStoreWriteStream rootStream ; |
|
699 TStreamId rootStreamId = rootStream.CreateLC(*store) ; |
|
700 header.ExternalizeL(rootStream) ; |
|
701 rootStream.CommitL() ; |
|
702 |
|
703 CleanupStack::PopAndDestroy(&rootStream) ; |
|
704 store->SetRootL(rootStreamId); |
|
705 store->CommitL(); |
|
706 CleanupStack::PopAndDestroy(store) ; |
|
707 |
|
708 // Attempt to open file containing store ready to read back and send to |
|
709 // BUR engine as a stream of bytes. |
|
710 User::LeaveIfError(iFile.Open(iFs, backupFilePath.FullName(), (EFileRead | EFileShareExclusive))) ; |
|
711 } |
|
712 |
|
713 |
|
714 |
|
715 |
|
716 // |
|
717 // CRepositoryBackupClient::InitialiseRestoreProxyBaseDataL |
|
718 // |
|
719 // Called when secure backup is about to start sending restore data. |
|
720 // |
|
721 void CRepositoryBackupClient::InitialiseRestoreProxyBaseDataL(TSecureId aSID, TDriveNumber /* aDrive*/) |
|
722 { |
|
723 // prepare for restore - Don't think we need to do anything here except prepare |
|
724 // data structures to receive incoming data |
|
725 |
|
726 // Save SID so we can check that it corresponds with the owner information |
|
727 // in the restored data. |
|
728 iSid = aSID ; |
|
729 |
|
730 // Open file to receive restored data |
|
731 TParse restoreFilePath ; |
|
732 User::LeaveIfError(restoreFilePath.Set(KRestoreFileName, TServerResources::iBURDirectory, &KRestoreFileExt)); |
|
733 User::LeaveIfError(iFile.Replace (iFs, restoreFilePath.FullName(), (EFileWrite | EFileShareExclusive))); |
|
734 } |
|
735 |
|
736 |
|
737 |
|
738 |
|
739 // |
|
740 // CRepositoryBackupClient::RestoreBaseDataSectionL |
|
741 // |
|
742 // Called when secure backup has a chunk of restore data for us. Last data |
|
743 // segment identified by aFinished. |
|
744 // |
|
745 void CRepositoryBackupClient::RestoreBaseDataSectionL(TDesC8& aBuffer, TBool aFinished) |
|
746 { |
|
747 // Receive a chunk of restore data in aBuffer |
|
748 User::LeaveIfError(iFile.Write (aBuffer)) ; |
|
749 if (aFinished) |
|
750 { |
|
751 iFile.Close() ; |
|
752 |
|
753 // All restore data recived so we can now recreate the repositories from the |
|
754 // backup store |
|
755 RestoreCompleteL(); |
|
756 } |
|
757 } |
|
758 |
|
759 void CRepositoryBackupClient::TerminateMultiStageOperation() |
|
760 { |
|
761 // Backup/Restore operation aborted! |
|
762 // Tidy up all temporary data. |
|
763 HBufC* burFileName = HBufC::New(KMaxFileName); |
|
764 if(burFileName==NULL) |
|
765 { |
|
766 return; |
|
767 } |
|
768 TPtr burFileNamePtr(burFileName->Des()); |
|
769 iFile.FullName(burFileNamePtr); //get the full name of the temporary file |
|
770 iFile.Close(); // close the file |
|
771 // If a debug build - record error |
|
772 TInt fileDeleteErr=iFs.Delete(burFileNamePtr); |
|
773 #ifdef _DEBUG |
|
774 if (fileDeleteErr != KErrNone) |
|
775 { |
|
776 RDebug::Print(_L("CRepositoryBackupClient::TerminateMultiStageOperation - Failed to delete file. Error = %d"), fileDeleteErr); |
|
777 } |
|
778 #else |
|
779 UNUSED_VAR(fileDeleteErr); |
|
780 #endif |
|
781 |
|
782 delete burFileName; |
|
783 } |
|
784 |
|
785 |
|
786 // |
|
787 // CRepositoryBackupClient::GetDataChecksum |
|
788 // |
|
789 // Not required and we don't implement it. |
|
790 // |
|
791 TUint CRepositoryBackupClient::GetDataChecksum(TDriveNumber /* aDrive */) |
|
792 { |
|
793 return KArbitraryNumber; |
|
794 } |
|
795 |
|
796 // |
|
797 // CRepositoryBackupClient::GetSnapshotDataL |
|
798 // |
|
799 // Only required for incremental backup (which we don't support |
|
800 // |
|
801 void CRepositoryBackupClient::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */, TBool& /* aFinished */) |
|
802 { |
|
803 User::Leave(KErrNotSupported) ; |
|
804 } |
|
805 |
|
806 // |
|
807 // CRepositoryBackupClient::InitialiseGetBackupDataL |
|
808 // |
|
809 // Used by "normal" active backup to prepare data - we use |
|
810 // InitialiseRestoreProxyBaseDataL so this shouldn't be called! |
|
811 // |
|
812 void CRepositoryBackupClient::InitialiseGetBackupDataL(TDriveNumber /* aDrive */) |
|
813 { |
|
814 User::Leave(KErrNotSupported) ; |
|
815 } |
|
816 |
|
817 |
|
818 |
|
819 void CRepositoryBackupClient::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */) |
|
820 { |
|
821 // Check this! I Don't think this method should get called as we're a proxy |
|
822 // and so implement InitialiseGetProxyBackupDataL!! |
|
823 User::Leave(KErrNotSupported) ; |
|
824 } |
|
825 |
|
826 |
|
827 |
|
828 |
|
829 void CRepositoryBackupClient::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */) |
|
830 { |
|
831 // Check this! I Don't think this method should get called as we're a proxy |
|
832 // so don't do incremental backup!! |
|
833 User::Leave(KErrNotSupported) ; |
|
834 } |
|
835 |
|
836 |
|
837 |
|
838 void CRepositoryBackupClient::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinished */) |
|
839 { |
|
840 // Check this! I Don't think this method should get called as we're a proxy |
|
841 // so don't do incremental backup!! |
|
842 User::Leave(KErrNotSupported) ; |
|
843 } |
|
844 |
|
845 |
|
846 // |
|
847 // Incremental backup isn't supported for the proxy data holder model so this |
|
848 // method should never be called. |
|
849 // |
|
850 // Not acceptable to leave even though it's an ...L function which we don't implement |
|
851 void CRepositoryBackupClient::AllSnapshotsSuppliedL() |
|
852 { |
|
853 ; |
|
854 } |
|
855 |
|
856 |
|
857 |
|
858 // |
|
859 // Incremental backup not supported |
|
860 // |
|
861 void CRepositoryBackupClient::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */, TBool /* aLastSection */) |
|
862 { |
|
863 User::Leave(KErrNotSupported) ; |
|
864 } |
|
865 |
|
866 /** |
|
867 Adds a new entry to the restored repository list with the specified repository uid. |
|
868 |
|
869 Creates an object of the CRestoredRepository and inserts it to the list. |
|
870 If a repository of the specified uid is already on the list, the created object will |
|
871 be deleted and no repeated entry will be inserted to the list. |
|
872 |
|
873 @param aUid The uid of the repository to be added to this array. |
|
874 @return The index of the new or existing entry within the list. |
|
875 */ |
|
876 TInt CRepositoryBackupClient::AddRestoredRepositoryL(TUid aUid) |
|
877 { |
|
878 CRestoredRepository* rstRepos = new(ELeave) CRestoredRepository(aUid); |
|
879 CleanupStack::PushL(rstRepos); |
|
880 TInt err = iRestoredRepositoriesArray.InsertInOrder(rstRepos, TLinearOrder<CRestoredRepository>(CRestoredRepository::CompareUids)); |
|
881 if(err != KErrNone && err != KErrAlreadyExists) |
|
882 User::Leave(err); |
|
883 TInt index = iRestoredRepositoriesArray.FindInOrderL(rstRepos, TLinearOrder<CRestoredRepository>(CRestoredRepository::CompareUids)); |
|
884 CleanupStack::Pop(); |
|
885 |
|
886 if(err == KErrAlreadyExists) |
|
887 { |
|
888 delete rstRepos; |
|
889 } |
|
890 return index; |
|
891 } |