sl@0: // Copyright (c) 2004-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 <e32def.h>
sl@0: #include <e32property.h>
sl@0: #include <s32file.h>
sl@0: #include <connect/sbdefs.h>
sl@0: #include "srvres.h"
sl@0: #include "cachemgr.h"
sl@0: #include "srvparams.h"
sl@0: #include "shrepos.h"
sl@0: #include "sessnotf.h"
sl@0: #include "backup.h"
sl@0: 
sl@0: #define UNUSED_VAR(a) a = a
sl@0: 
sl@0: _LIT (KBackupFileName, "BACKUP") ;
sl@0: _LIT (KRestoreFileName, "RESTORE") ;
sl@0: _LIT(KBackupFileExt, ".bak");
sl@0: _LIT(KRestoreFileExt, ".rst");
sl@0: 
sl@0: 
sl@0: TRepositoryBackupState CRepositoryBackupClient::iBackupStatus ;
sl@0: 
sl@0: 
sl@0: //
sl@0: // Backup stream index class - Used to hold association between a UID (in
sl@0: // our case the UID of a repository) and a stream ID - Can't use CStreamDictionary
sl@0: // because that only lets you retrieve stream IDs by a (previously known) UID rather
sl@0: // than iterate through its contentsretrieving UID/StreamID pairs...
sl@0: // 
sl@0: 
sl@0: 
sl@0: //
sl@0: // CRepositoryBackupStreamIndex::AddL
sl@0: //
sl@0: // Add a new repository UID and stream ID pair to the index
sl@0: void CRepositoryBackupStreamIndex::AddL(TUid aUid, TStreamId aSettingStreamId, TStreamId aDeletedSettingsStreamId, TStreamId aInstalledSettingsStreamId) 
sl@0: 	{
sl@0: 	TRepositoryBackupStreamIndexElement newIndexElement;
sl@0: 	newIndexElement.Set(aUid,aSettingStreamId, aDeletedSettingsStreamId, aInstalledSettingsStreamId) ;
sl@0: 	iStreamIndex.AppendL(newIndexElement);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // 
sl@0: // CRepositoryBackupStreamIndex::GetNext
sl@0: //
sl@0: // Iterate through the index retrieving the next Reposirory UID and Stream ID
sl@0: // pair.
sl@0: //
sl@0: TInt CRepositoryBackupStreamIndex::GetNext(TUid& aUid, TStreamId& aSettingsStreamId, TStreamId& aDeletedSettingsStreamId, TStreamId& aInstalledSettingsStreamId)
sl@0: 	{
sl@0: 	TInt error = KErrNone ;
sl@0: 	if (iIndex < iStreamIndex.Count())
sl@0: 		{
sl@0: 		iStreamIndex[iIndex++].Get(aUid, aSettingsStreamId, aDeletedSettingsStreamId, aInstalledSettingsStreamId) ;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		error = KErrNotFound ;
sl@0: 		}
sl@0: 	return error ;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // Backup client class.
sl@0: //
sl@0: // Has Active object functionality to monitor the state of the publish and subscribe 
sl@0: // flags associated with backup and restore and also implements MActiveBackupDataClient
sl@0: // to perform active backup according to the "proxy data holder" model.
sl@0: //
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // Usual 2 phase construction factory NewL NewLC classes
sl@0: //	
sl@0: CRepositoryBackupClient* CRepositoryBackupClient::NewLC(RFs& aFs) 
sl@0: 	{
sl@0: 	CRepositoryBackupClient* me = new(ELeave)CRepositoryBackupClient(aFs);
sl@0: 	CleanupStack::PushL(me) ;
sl@0: 	me->ConstructL() ;
sl@0: 	return me ;
sl@0: 	}
sl@0: 	
sl@0: 	
sl@0: CRepositoryBackupClient* CRepositoryBackupClient::NewL(RFs& aFs) 
sl@0: 	{
sl@0: 	CRepositoryBackupClient* me = CRepositoryBackupClient::NewLC(aFs) ;
sl@0: 	CleanupStack::Pop(me) ;
sl@0: 	return me ;
sl@0: 	}
sl@0: 	
sl@0: 		
sl@0: 		
sl@0: // 
sl@0: // Constructor - doesn't really do anything!
sl@0: //
sl@0: CRepositoryBackupClient::CRepositoryBackupClient(RFs& aFs) : CActive(EPriorityStandard), iFs(aFs), iRomScanDone(EFalse)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // 
sl@0: // Phase 2 constructor
sl@0: //	
sl@0: void CRepositoryBackupClient::ConstructL()
sl@0: 	{
sl@0: 	// Create repository object
sl@0: 	iRepository = new(ELeave) CServerRepository;
sl@0: 	
sl@0: 	// Notifier needed to open repositories.		
sl@0: 	iNotifier = new(ELeave)CSessionNotifier ;
sl@0: 
sl@0: 	// Attach to Backup/Restore Pub/Sub property.	
sl@0: 	User::LeaveIfError(iBackupRestoreProperty.Attach(KUidSystemCategory, KUidBackupRestoreKey)) ;
sl@0: 	
sl@0: 	// Add ourself to the active scheduler
sl@0: 	CActiveScheduler::Add(this) ;
sl@0: 	
sl@0: 	// Initialise backup/restore status
sl@0: 	iBackupStatus = ENoBackupActivty ;
sl@0: 	
sl@0: 	// Set active and request notification of changes to backup/restore
sl@0: 	// Pub/Sub property.
sl@0: 	StartL() ;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // Destructor
sl@0: //
sl@0: CRepositoryBackupClient::~CRepositoryBackupClient()
sl@0: 	{
sl@0: 	Cancel();
sl@0: 	
sl@0: 	iBackupRestoreProperty.Close() ;
sl@0: 	
sl@0: 	if (iRepository)
sl@0: 		{
sl@0: 		iRepository->Close();
sl@0: 		delete(iRepository);
sl@0: 		}
sl@0: 		
sl@0: 	if (iNotifier)
sl@0: 		delete(iNotifier) ;
sl@0: 	
sl@0: 	if (iActiveBackupClient)
sl@0: 		delete(iActiveBackupClient) ;	
sl@0: 		
sl@0: 	iRestoredRepositoriesArray.ResetAndDestroy();
sl@0: 	iRestoredRepositoriesArray.Close();
sl@0: 	
sl@0: 	iFile.Close();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: 
sl@0: // 
sl@0: // DoCancel - mandatory for active objects.
sl@0: //	
sl@0: void CRepositoryBackupClient::DoCancel()
sl@0: 	{
sl@0: 	iBackupRestoreProperty.Cancel() ;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // RunError
sl@0: //
sl@0: TInt CRepositoryBackupClient::RunError(TInt aError)
sl@0: 	{
sl@0: 	iRestoredRepositoriesArray.ResetAndDestroy();
sl@0: 	UNUSED_VAR(aError);
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // Test BUR Pub/Sub property set status, and notify BUR that we're
sl@0: // ready to go as appropriate. 
sl@0: //
sl@0: void CRepositoryBackupClient::TestBURstatusL(void)
sl@0: 	{
sl@0: 	TInt BURstatus ;
sl@0: 	TRepositoryBackupState lastBackupStatus = ENoBackupActivty;
sl@0: 	if (iBackupRestoreProperty.Get(BURstatus) != KErrNotFound)
sl@0: 		{
sl@0: 		BURstatus &= KBURPartTypeMask ;
sl@0: 		switch (BURstatus)
sl@0: 			{
sl@0: 			case EBURUnset:	// State not yet set. Treat as no backup/restore in progress.
sl@0: 			case EBURNormal:
sl@0: 				// No backup or restore in progress. Probably
sl@0: 				// means we've just completed an operation?
sl@0: 				
sl@0: 				lastBackupStatus = iBackupStatus;
sl@0: 				iBackupStatus = ENoBackupActivty ;
sl@0: 				
sl@0: 				// Back to normal, so enable cache
sl@0: 				TServerResources::iCacheManager->EnableCache();				
sl@0: 				// delete the CActiveBackupClient
sl@0: 				if (iActiveBackupClient)
sl@0: 					{
sl@0: 					delete iActiveBackupClient ;
sl@0: 					iActiveBackupClient = NULL ;
sl@0: 					}
sl@0: 					
sl@0: 				// Notify the changed keys if a restoration was just completed
sl@0: 				if((lastBackupStatus == ERestoreInProgress)) 
sl@0: 			    	{
sl@0: 				    for(TInt i = 0; i < iRestoredRepositoriesArray.Count(); i++)
sl@0: 				    	{
sl@0: 						iRepository->OpenL(iRestoredRepositoriesArray[i]->Uid(), *iNotifier, EFalse);
sl@0: 						iRepository->RestoreNotify(*iRestoredRepositoriesArray[i]);
sl@0: 						iRepository->Close();
sl@0: 						}
sl@0: 					iRestoredRepositoriesArray.ResetAndDestroy();
sl@0: 					}
sl@0: 
sl@0: 				break ;
sl@0: 				
sl@0: 			case EBURBackupFull :
sl@0: 			case EBURBackupPartial :
sl@0: 				// We don't distinguish between full and partial backups
sl@0: 				// as the Backup engine will give us UIDs for all the
sl@0: 				// repository data owners that want their stuff backed up
sl@0: 				// anyway.
sl@0: 				
sl@0: 				// We don't want cache activity during backup
sl@0: 				TServerResources::iCacheManager->DisableCache();
sl@0: 				
sl@0: 				// Any (and all!) repositories which have been opened in the
sl@0: 				// course of system boot and normal operation will have been
sl@0: 				// added to TServerResources::iOwnerIdLookUpTable as they were
sl@0: 				// opened but there may well be repositories which need backing
sl@0: 				// up and haven't yet been opened so we need to make sure that
sl@0: 				// the lookup table is complete.
sl@0: 				CompleteOwnerIdLookupTableL();
sl@0: 
sl@0: 				// Register with BUR engine
sl@0: 				if (!iActiveBackupClient)
sl@0: 					{
sl@0: 					iActiveBackupClient = CActiveBackupClient::NewL(this) ;
sl@0: 					}	
sl@0: 				iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
sl@0: 				iBackupStatus = EBackupInProgress ;
sl@0: 				break ;
sl@0: 				
sl@0: 			case EBURRestoreFull :
sl@0: 			case EBURRestorePartial :
sl@0: 				// We don't distinguish between full and partial restore
sl@0: 				// either!
sl@0: 				
sl@0: 				// We don't want cache activity during restore either!
sl@0: 				TServerResources::iCacheManager->DisableCache();
sl@0: 				
sl@0: 				// Register with BUR engine
sl@0: 				if (!iActiveBackupClient)
sl@0: 					{
sl@0: 					iActiveBackupClient = CActiveBackupClient::NewL(this) ;
sl@0: 					}
sl@0: 				iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
sl@0: 				iBackupStatus = ERestoreInProgress ;
sl@0: 				break ;
sl@0: 							
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // Request notification of changes in BUR Pub/Sub status
sl@0: //
sl@0: void CRepositoryBackupClient::StartL()
sl@0: 	{
sl@0: 	if (!IsActive())
sl@0: 		{
sl@0: 		TestBURstatusL();	
sl@0: 		NotifyChange();
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // Request notification of changes in BUR Pub/Sub status
sl@0: //
sl@0: void CRepositoryBackupClient::NotifyChange()
sl@0: 	{
sl@0: 	// Watch for changes in the property state. 
sl@0: 	iBackupRestoreProperty.Subscribe(iStatus) ;
sl@0: 	SetActive();
sl@0: 	}
sl@0: 
sl@0: 	
sl@0: //
sl@0: // Handle changes of backup state through publish/subscribe
sl@0: //
sl@0: void CRepositoryBackupClient::RunL()
sl@0: 	{	
sl@0: 	NotifyChange() ;
sl@0: 	TestBURstatusL();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // We can't estimate data size without A) having the SID of the data owner who's data
sl@0: // is to be backed up and B) going through the whole process of preparing the backup.
sl@0: //
sl@0: // The only sensible thing we can do is return an arbitrary value!
sl@0: //
sl@0: TUint CRepositoryBackupClient::GetExpectedDataSize(TDriveNumber /* aDrive */)
sl@0: 	{
sl@0: 	return KArbitraryNumber ;
sl@0: 	}	
sl@0: 
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // Called by BUR engine to request a chunk of backup data.
sl@0: //	
sl@0: void CRepositoryBackupClient::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinished)
sl@0: 	{
sl@0: 	const TInt chunkSize = aBuffer.MaxSize() ;
sl@0: 
sl@0: 	aFinished = EFalse ;
sl@0: 		
sl@0: 	// Pass a chunk of our prepared backup data in aBuffer
sl@0: 	User::LeaveIfError(iFile.Read(aBuffer, chunkSize)) ;
sl@0: 	TInt bytesRead = aBuffer.Length() ;
sl@0: 
sl@0: 	// Check to see if this was the last chunk of data.
sl@0: 	if (bytesRead < chunkSize)
sl@0: 		{
sl@0: 		// Set "finished" flag so that BUR knows we're through...
sl@0: 		aFinished = ETrue ;
sl@0: 		
sl@0: 		// ...and then tidy up by closing and deleting the backup file.
sl@0: 		iFile.Close() ;
sl@0: 		TParse backupFilePath ;
sl@0: 		User::LeaveIfError(backupFilePath.Set(KBackupFileName, TServerResources::iBURDirectory, &KBackupFileExt));
sl@0: 		TInt fileDeleteErr=iFs.Delete(backupFilePath.FullName()) ;
sl@0: 		#ifdef _DEBUG
sl@0: 			if (fileDeleteErr != KErrNone)
sl@0: 			{
sl@0: 				RDebug::Print(_L("CRepositoryBackupClient::GetBackupDataSectionL - Failed to delete file. Error = %d"), fileDeleteErr);
sl@0: 			}
sl@0: 		#else
sl@0: 			UNUSED_VAR(fileDeleteErr);
sl@0: 		#endif
sl@0: 
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // CRepositoryBackupClient::RestoreComplete
sl@0: //
sl@0: // Called when a Complete set of backup data has been received and written
sl@0: // to a file. We now need to open the file as a stream store, get the
sl@0: // index (list of repository UID and corresponding stream ID pairs, and then
sl@0: // reconstruct and save each repository in turn.
sl@0: // 
sl@0: void CRepositoryBackupClient::RestoreComplete(TDriveNumber /* aDrive */)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CRepositoryBackupClient::RestoreRepositoryAndListL(TUid repositoryUid, CDirectFileStore* store, TStreamId settingsStreamId, TStreamId deletedSettingsStreamId, TInt& repIndex)
sl@0:     {
sl@0:     // Add the restored repository to the restored repositories list.
sl@0:     // Pass its changed-keys list to further restoring functions to add entries for post-restoration notification.
sl@0:     repIndex = AddRestoredRepositoryL(repositoryUid);
sl@0:     iRepository->RestoreRepositoryContentsL(*store, settingsStreamId, deletedSettingsStreamId, *iRestoredRepositoriesArray[repIndex]);
sl@0:     iRepository->CommitChangesL();
sl@0:     }
sl@0: 
sl@0: 	
sl@0: //
sl@0: // CRepositoryBackupClient::RestoreCompleteL
sl@0: //
sl@0: // Does the actual work of reconstructing repositories from backup data
sl@0: //
sl@0: //
sl@0: void CRepositoryBackupClient::RestoreCompleteL()
sl@0: 	{
sl@0: 	// All restore data recived so we can now recreate the repositories from the
sl@0: 	// backup store
sl@0: 	// Attempt to open the restore file as a CDirectFileStore
sl@0: 	TParse restoreFilePath ;
sl@0: 	User::LeaveIfError(restoreFilePath.Set(KRestoreFileName, TServerResources::iBURDirectory, &KRestoreFileExt));
sl@0: 	CDirectFileStore* store = CDirectFileStore::OpenLC (iFs,restoreFilePath.FullName(), EFileRead|EFileShareReadersOnly);
sl@0: 	if (store->Type()[0] != KDirectFileStoreLayoutUid)
sl@0: 		{
sl@0: 		// store wasn't quite what we were expecting - can't return an error, can't leave
sl@0: 		// so all we can do is close the file, tidy up as best we can, and bail out!!!! 
sl@0: 		CleanupStack::PopAndDestroy(store);
sl@0: 		// If a debug build - record error
sl@0: 		TInt fileDeleteErr=iFs.Delete(restoreFilePath.FullName()) ;
sl@0: 		#ifdef _DEBUG
sl@0: 			if (fileDeleteErr != KErrNone)
sl@0: 			{
sl@0: 				RDebug::Print(_L("CRepositoryBackupClient::RestoreCompleteL - Failed to delete file. Error = %d"), fileDeleteErr);
sl@0: 			}
sl@0: 		#else
sl@0: 			UNUSED_VAR(fileDeleteErr);
sl@0: 		#endif
sl@0: 
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}		
sl@0: 
sl@0: 
sl@0: 	// Get the root stream and attempt to read a backup file header from it
sl@0: 	TStreamId rootStreamId = store->Root() ;
sl@0: 	RStoreReadStream rootStream ;
sl@0: 	RStoreReadStream indexStream ;
sl@0: 	rootStream.OpenLC(*store, rootStreamId);
sl@0: 	TRepositoryBackupStreamHeader header ;
sl@0: 	TRAPD(err, header.InternalizeL(rootStream)) ;
sl@0: 	
sl@0: 	// Check for a valid header by checking that the UID matches the UID
sl@0: 	// of Central Repository and that the version number is sane.
sl@0: 	if (err == KErrNotSupported)
sl@0: 	    {
sl@0:    		// Not a valid header - assume it's an old style backup stream,
sl@0: 		// set extensions supported to none, set index stream to be
sl@0: 		// root stream and reset read pointer to beginning.
sl@0: 		iBackupExtensionsSupported = ENoBackupExtensions ;
sl@0: 
sl@0: 		CleanupStack::PopAndDestroy(&rootStream) ;
sl@0: 		CleanupStack::PopAndDestroy(store) ;
sl@0: 
sl@0: 		// Try re-opening as old-style backup stream with index
sl@0: 		// as root stream.		
sl@0: 		CDirectFileStore* store = CDirectFileStore::OpenLC (iFs,restoreFilePath.FullName(), EFileRead|EFileShareReadersOnly);
sl@0: 		indexStream.OpenLC(*store, rootStreamId) ;
sl@0: 	    }
sl@0: 	else
sl@0: 		{
sl@0: 	    // Got a valid header. Check for extensions supported by this
sl@0: 	    // stream and get stream to read index from
sl@0: 	    CleanupStack::PopAndDestroy(&rootStream) ;
sl@0: 	    iBackupExtensionsSupported = header.getBackupExtensionsSupported();	
sl@0: 	    TStreamId indexStreamId = header.getIndexStreamId() ;
sl@0: 	    indexStream.OpenLC (*store, indexStreamId) ; 		
sl@0: 		}
sl@0: 	
sl@0: 	CRepositoryBackupStreamIndex *restoreStreamIndex = CRepositoryBackupStreamIndex::NewLC();	
sl@0: 	restoreStreamIndex->InternalizeL(indexStream, iBackupExtensionsSupported);
sl@0: 
sl@0: 	
sl@0: 	// Iterate through index and attempt restore of each repository stream
sl@0: 	// we find in it.
sl@0: 	restoreStreamIndex->Reset();	
sl@0: 	TUid repositoryUid;
sl@0: 	TStreamId settingsStreamId(KNullStreamIdValue);
sl@0: 	TStreamId deletedSettingsStreamId(KNullStreamIdValue);
sl@0: 	TStreamId installedSettingsStreamId(KNullStreamIdValue);
sl@0: 	
sl@0: 	while (restoreStreamIndex->GetNext(repositoryUid, settingsStreamId, deletedSettingsStreamId, installedSettingsStreamId) == KErrNone)
sl@0: 		{
sl@0: 		iRepository->OpenL(repositoryUid, *iNotifier, EFalse);
sl@0: 		iRepository->FailAllTransactions();
sl@0: 		TInt repIndex;
sl@0: 		TRAPD(err, RestoreRepositoryAndListL(repositoryUid, store, settingsStreamId, deletedSettingsStreamId, repIndex));
sl@0: 		iRepository->Close();
sl@0: 	    User::LeaveIfError(err);
sl@0: 		// If the backup contains an installed repository containing default values for the settings, read them in
sl@0: 		if (installedSettingsStreamId != KNullStreamId)
sl@0: 			{
sl@0: 			// create an empty repository in install directory, and restore the data from backup file
sl@0: 			iRepository->RestoreInstallRepositoryL(repositoryUid, *store, installedSettingsStreamId, *iRestoredRepositoriesArray[repIndex]);
sl@0: 			// remove the .ini install file (if exists) because it will clash with the restored file
sl@0: 			TServerResources::DeleteCentrepFileL(repositoryUid, EInstall, EIni);
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	CleanupStack::PopAndDestroy(restoreStreamIndex) ;
sl@0: 	CleanupStack::PopAndDestroy(&indexStream);
sl@0: 	CleanupStack::PopAndDestroy(store);
sl@0: 	// If a debug build - record error
sl@0: 	TInt fileDeleteErr=iFs.Delete(restoreFilePath.FullName());
sl@0: 	#ifdef _DEBUG
sl@0: 		if (fileDeleteErr != KErrNone)
sl@0: 		{
sl@0: 			RDebug::Print(_L("CRepositoryBackupClient::RestoreCompleteL (2nd) - Failed to delete file. Error = %d"), fileDeleteErr);
sl@0: 		}
sl@0: 	#else
sl@0: 		UNUSED_VAR(fileDeleteErr);
sl@0: 	#endif
sl@0: 
sl@0: 	}
sl@0: 	
sl@0: //
sl@0: // CRepositoryBackupClient::CompleteOwnerIdLookupTableL
sl@0: //
sl@0: // Open each repository in TServerResources::iDataDirectory.
sl@0: // Save the Rep UID and Owner Id of the rep to be used by
sl@0: // InitialiseGetProxyBackupDataL.
sl@0: void CRepositoryBackupClient::CompleteOwnerIdLookupTableL()
sl@0: 	{
sl@0: 
sl@0: 	// Read contents of persist, install, and ROM directories and
sl@0: 	// use them to build a list of repository candidates.
sl@0: 	RArray <TUint32> repositoryList ;
sl@0: 	CleanupClosePushL(repositoryList) ;
sl@0: 
sl@0: 	for (TBackupDirectoryScan scanDir = EScanRom; scanDir <= EScanPersist; scanDir = (TBackupDirectoryScan)(scanDir+1))
sl@0: 		{
sl@0: 		TPtrC directoryName ;
sl@0: 		switch (scanDir)
sl@0: 			{
sl@0: 				case EScanRom :
sl@0: 					if (TServerResources::iRomDirectory)
sl@0: 						{
sl@0: 						directoryName.Set(TServerResources::iRomDirectory->Des()) ;						
sl@0: 						}
sl@0: 					else
sl@0: 						{
sl@0: 						// if ROM directory doesn't exist or there are no files, skip scanning
sl@0: 						continue;
sl@0: 						}
sl@0: 					break ;
sl@0: 					
sl@0: 				case EScanInstall :
sl@0: 					directoryName.Set(TServerResources::iInstallDirectory->Des()) ;
sl@0: 					break ;
sl@0: 					
sl@0: 				case EScanPersist :
sl@0: 					directoryName.Set(TServerResources::iDataDirectory->Des()) ;
sl@0: 					break ;				
sl@0: 			}
sl@0: 			
sl@0: 		RDir dir;
sl@0: 	    CleanupClosePushL(dir);
sl@0: 		User::LeaveIfError(dir.Open(iFs, directoryName, KEntryAttNormal));
sl@0: 	    
sl@0: 	    TEntryArray dirEntries;
sl@0: 	    TInt readError = KErrNone;
sl@0: 	    
sl@0: 		while (readError != KErrEof)  
sl@0: 			{
sl@0: 		    readError = dir.Read(dirEntries);
sl@0: 	    
sl@0: 		    if(readError != KErrNone && readError != KErrEof) 
sl@0: 		    	{
sl@0: 		    	User::Leave(readError);
sl@0: 		    	}
sl@0: 		    else
sl@0: 		    	{
sl@0: 		    	const TInt dirCount = dirEntries.Count();   
sl@0: 		    	for (TInt i=0; i<dirCount; i++)
sl@0: 		    		{
sl@0: 		    		// Attempt to extract a repository UID from directory entry
sl@0: 		    		TUid uid;
sl@0: 					TInt insertionError;
sl@0: 		    		if (KErrNone == TServerResources::GetUid(const_cast<TEntry&>(dirEntries[i]), uid))
sl@0: 		    			{
sl@0: 		    			insertionError=repositoryList.InsertInUnsignedKeyOrder(uid.iUid) ;
sl@0: 						// Should leave in all cases other than KErrNone or KErrAlreadyExists						
sl@0: 						if((insertionError != KErrNone) && (insertionError != KErrAlreadyExists ))
sl@0: 							{
sl@0: 							User::Leave(insertionError);
sl@0: 							}						
sl@0: 		    			}
sl@0: 		    		}
sl@0: 		    	}
sl@0: 			}
sl@0: 	    
sl@0: 		CleanupStack::PopAndDestroy(&dir);
sl@0: 		}
sl@0: 		
sl@0: 	// Open all repositories in turn. Save repository UID and owner ID
sl@0: 	// in lookup table.
sl@0: 	for(TInt i = 0; i<repositoryList.Count(); i++)
sl@0: 		{
sl@0: 		// Look to see if this repository already has an entry in the owner ID lookup table
sl@0: 		if ( TServerResources::FindOwnerIdLookupMapping(repositoryList[i]) == KErrNotFound)
sl@0: 			{
sl@0: 			// Need to TRAP here as otherwise if ANY repository fails to open
sl@0: 			// (e.g. due to corruption) it would cause the entire backup to
sl@0: 			// fail
sl@0: 			TRAPD(err, iRepository->OpenL(TUid::Uid(repositoryList[i]), *iNotifier));
sl@0: 			if (err == KErrNoMemory)
sl@0: 				{
sl@0: 				User::Leave(err) ;
sl@0: 				}
sl@0: 			
sl@0: 			else if (err == KErrNone)
sl@0: 				{
sl@0: 				// The act of opening a repository will cause it to add itself to the
sl@0: 				// Repository/Owner UID mapping table so we don't need to do anything
sl@0: 				// and can close it immediately!
sl@0: 				iRepository->Close();
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 		
sl@0: 	CleanupStack::PopAndDestroy() ; // repositoryList	
sl@0: 	}
sl@0: 
sl@0: // CRepositoryBackupClient::InitialiseGetProxyBackupDataL
sl@0: //
sl@0: // Prepare data to be backed up. We get the Sid/Uid of the entity whos data
sl@0: // is to be backed up. What we do is to open each repository in turn (identified
sl@0: // by directory listing), check its owner, and if it matches the Sid/Uid we've
sl@0: // been given by secure backup externalise it to a stream within a file store.
sl@0: //
sl@0: void CRepositoryBackupClient::InitialiseGetProxyBackupDataL(TSecureId aSID, TDriveNumber /* aDrive */) 
sl@0: 	{
sl@0: 	// Prepare data for backup.
sl@0: 
sl@0: 	// Create file store
sl@0: 	TParse backupFilePath ;
sl@0: 	User::LeaveIfError(backupFilePath.Set(KBackupFileName, TServerResources::iBURDirectory, &KBackupFileExt));
sl@0: 	CDirectFileStore* store = CDirectFileStore::ReplaceLC(iFs, backupFilePath.FullName(),
sl@0: 	                                                      (EFileWrite | EFileShareExclusive));
sl@0: 	const TUid uid2  = KNullUid ;	                                                     
sl@0: 	store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; 
sl@0: 	
sl@0: 	// Create a Backup Stream index
sl@0: 	CRepositoryBackupStreamIndex* backupStreamIndex = CRepositoryBackupStreamIndex::NewLC();	
sl@0: 	  
sl@0: 	// Find the reps owned by aSID
sl@0: 	for(TInt i = 0; i < TServerResources::iOwnerIdLookUpTable.Count(); ++i)
sl@0: 		{
sl@0: 		const TOwnerIdMapping& lookupTableEntry = TServerResources::iOwnerIdLookUpTable[i];
sl@0: 		
sl@0: 		if ( lookupTableEntry.iOwner == aSID )
sl@0: 			{
sl@0: 			TStreamId settingStreamId(KNullStreamIdValue);
sl@0: 			TStreamId deletedSettingsStreamId(KNullStreamIdValue);
sl@0: 			TStreamId installedSettingStreamId(KNullStreamIdValue);
sl@0: 			// Found one match, open the repository and externalise content.
sl@0: 			TUid uid = TUid::Uid(lookupTableEntry.iRepUid);
sl@0: 			TRAPD(err,iRepository->OpenL(uid, *iNotifier));
sl@0: 			if (err == KErrNoMemory)
sl@0: 				{
sl@0: 				User::Leave(err) ;
sl@0: 				}
sl@0: 			else if (err == KErrNone)
sl@0: 				{			
sl@0: 				iRepository->FailAllTransactions();
sl@0: 				// externalise repository contents
sl@0: 				iRepository->StoreRepositoryContentsL(*store, settingStreamId, deletedSettingsStreamId);
sl@0: 				// Close repository.
sl@0: 				iRepository->Close();
sl@0: 				}
sl@0: 				
sl@0: 			TBool installExists=TServerResources::InstallFileExistsL(uid);
sl@0: 			if(installExists)
sl@0: 				{			
sl@0: 				// load existing repository from install directory (default values installed post-build by SWI)
sl@0: 				// and externalise installed repository contents				
sl@0: 				TRAPD(err, iRepository->BackupInstallRepositoryL(uid, *store, installedSettingStreamId));
sl@0: 				// We trap and discard most errors to be able to continue backing up other repositories in the list
sl@0: 				if (err == KErrNoMemory)
sl@0: 					{
sl@0: 					User::Leave(err) ;
sl@0: 					}
sl@0: 				else if (err != KErrNone)
sl@0: 					{
sl@0: 					// If for any reason we haven't been able to back up the install repository, 
sl@0: 					// we create an empty stream to preserve the format
sl@0: 					installedSettingStreamId = KNullStreamIdValue;
sl@0: 					}
sl@0: 				}
sl@0: 			// Add all to store index
sl@0: 			backupStreamIndex->AddL(uid, settingStreamId, deletedSettingsStreamId, installedSettingStreamId) ;
sl@0: 
sl@0: 			}
sl@0: 		}
sl@0: 	// Write the stream index/dictionary as root stream within the store
sl@0: 	// so we can access it when we do a restore later on
sl@0: 	RStoreWriteStream indexStream ;
sl@0: 	TStreamId indexStreamId = indexStream.CreateLC(*store) ;
sl@0: 	backupStreamIndex->ExternalizeL(indexStream) ;
sl@0: 	indexStream.CommitL() ;
sl@0: 	CleanupStack::PopAndDestroy(&indexStream) ;
sl@0: 	CleanupStack::PopAndDestroy (backupStreamIndex) ;
sl@0: 		
sl@0: 	// Create the Header and write it as the root stream within the store
sl@0: 	// so we can access it when we do a restore later on
sl@0: 	TRepositoryBackupStreamHeader header (indexStreamId) ;
sl@0: 	RStoreWriteStream rootStream ;
sl@0: 	TStreamId rootStreamId = rootStream.CreateLC(*store) ;
sl@0: 	header.ExternalizeL(rootStream) ;
sl@0: 	rootStream.CommitL() ;
sl@0: 	
sl@0: 	CleanupStack::PopAndDestroy(&rootStream) ;
sl@0: 	store->SetRootL(rootStreamId);
sl@0: 	store->CommitL();
sl@0: 	CleanupStack::PopAndDestroy(store) ; 
sl@0: 	
sl@0: 	// Attempt to open file containing store ready to read back and send to
sl@0: 	// BUR engine as a stream of bytes.
sl@0: 	User::LeaveIfError(iFile.Open(iFs, backupFilePath.FullName(), (EFileRead | EFileShareExclusive))) ;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // CRepositoryBackupClient::InitialiseRestoreProxyBaseDataL
sl@0: //
sl@0: // Called when secure backup is about to start sending restore data.
sl@0: //
sl@0: void CRepositoryBackupClient::InitialiseRestoreProxyBaseDataL(TSecureId aSID, TDriveNumber /* aDrive*/)
sl@0: 	{
sl@0: 	// prepare for restore - Don't think we need to do anything here except prepare
sl@0: 	// data structures to receive incoming data
sl@0: 	
sl@0: 	// Save SID so we can check that it corresponds with the owner information 
sl@0: 	// in the restored data.
sl@0: 	iSid = aSID ;
sl@0: 	
sl@0: 	// Open file to receive restored data
sl@0: 	TParse restoreFilePath ;
sl@0: 	User::LeaveIfError(restoreFilePath.Set(KRestoreFileName, TServerResources::iBURDirectory, &KRestoreFileExt));
sl@0: 	User::LeaveIfError(iFile.Replace (iFs, restoreFilePath.FullName(), (EFileWrite | EFileShareExclusive)));
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // CRepositoryBackupClient::RestoreBaseDataSectionL
sl@0: //
sl@0: // Called when secure backup has a chunk of restore data for us. Last data
sl@0: // segment identified by aFinished.
sl@0: //
sl@0: void CRepositoryBackupClient::RestoreBaseDataSectionL(TDesC8& aBuffer, TBool aFinished)
sl@0: 	{
sl@0: 	// Receive a chunk of restore data in aBuffer 
sl@0: 	User::LeaveIfError(iFile.Write (aBuffer)) ;
sl@0: 	if (aFinished)
sl@0: 		{
sl@0: 		iFile.Close() ;
sl@0: 		
sl@0: 		// All restore data recived so we can now recreate the repositories from the
sl@0: 		// backup store	
sl@0: 		RestoreCompleteL();	
sl@0: 		}
sl@0: 	}
sl@0: 	
sl@0: void CRepositoryBackupClient::TerminateMultiStageOperation()
sl@0: 	{
sl@0: 	// Backup/Restore operation aborted!
sl@0: 	// Tidy up all temporary data.
sl@0: 	HBufC* burFileName = HBufC::New(KMaxFileName);
sl@0: 	if(burFileName==NULL)
sl@0: 		{
sl@0: 		return;
sl@0: 		}
sl@0: 	TPtr burFileNamePtr(burFileName->Des());
sl@0: 	iFile.FullName(burFileNamePtr); //get the full name of the temporary file
sl@0: 	iFile.Close(); // close the file
sl@0: 	// If a debug build - record error
sl@0: 	TInt fileDeleteErr=iFs.Delete(burFileNamePtr);
sl@0: 	#ifdef _DEBUG
sl@0: 		if (fileDeleteErr != KErrNone)
sl@0: 		{
sl@0: 			RDebug::Print(_L("CRepositoryBackupClient::TerminateMultiStageOperation - Failed to delete file. Error = %d"), fileDeleteErr);
sl@0: 		}
sl@0: 	#else
sl@0: 		UNUSED_VAR(fileDeleteErr);
sl@0: 	#endif
sl@0: 
sl@0: 	delete burFileName;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // CRepositoryBackupClient::GetDataChecksum
sl@0: //
sl@0: // Not required and we don't implement it.
sl@0: //
sl@0: TUint CRepositoryBackupClient::GetDataChecksum(TDriveNumber /* aDrive */) 
sl@0: 	{
sl@0: 	return KArbitraryNumber;
sl@0: 	}
sl@0: 
sl@0: // 
sl@0: // CRepositoryBackupClient::GetSnapshotDataL
sl@0: //
sl@0: // Only required for incremental backup (which we don't support
sl@0: //
sl@0: void CRepositoryBackupClient::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */, TBool& /* aFinished */) 
sl@0: 	{
sl@0: 	User::Leave(KErrNotSupported) ;
sl@0: 	}
sl@0: 
sl@0: // 
sl@0: // CRepositoryBackupClient::InitialiseGetBackupDataL
sl@0: //
sl@0: // Used by "normal" active backup to prepare data - we use
sl@0: // InitialiseRestoreProxyBaseDataL so this shouldn't be called!
sl@0: //	
sl@0: void CRepositoryBackupClient::InitialiseGetBackupDataL(TDriveNumber /* aDrive */)
sl@0: 	{
sl@0: 	User::Leave(KErrNotSupported) ;
sl@0: 	}
sl@0: 	
sl@0: 
sl@0: 
sl@0: void CRepositoryBackupClient::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */)
sl@0: 	{
sl@0: 	// Check this! I Don't think this method should get called as we're a proxy
sl@0: 	// and so implement InitialiseGetProxyBackupDataL!! 
sl@0: 	User::Leave(KErrNotSupported) ;		
sl@0: 	}
sl@0: 	
sl@0: 
sl@0: 
sl@0: 
sl@0: void CRepositoryBackupClient::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */)
sl@0: 	{
sl@0: 	// Check this! I Don't think this method should get called as we're a proxy
sl@0: 	// so don't do incremental backup!! 
sl@0: 	User::Leave(KErrNotSupported) ;			
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: void CRepositoryBackupClient::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinished */)
sl@0: 	{
sl@0: 	// Check this! I Don't think this method should get called as we're a proxy
sl@0: 	// so don't do incremental backup!! 
sl@0: 	User::Leave(KErrNotSupported) ;		
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // Incremental backup isn't supported for the proxy data holder model so this
sl@0: // method should never be called.
sl@0: //
sl@0: // Not acceptable to leave even though it's an ...L function which we don't implement
sl@0: void CRepositoryBackupClient::AllSnapshotsSuppliedL() 
sl@0: 	{
sl@0: 	;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: //
sl@0: // Incremental backup not supported
sl@0: //	
sl@0: void CRepositoryBackupClient::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */, TBool /* aLastSection */) 
sl@0: 	{
sl@0: 	User::Leave(KErrNotSupported) ;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Adds a new entry to the restored repository list with the specified repository uid.
sl@0: 
sl@0: Creates an object of the CRestoredRepository and inserts it to the list.
sl@0: If a repository of the specified uid is already on the list, the created object will 
sl@0: be deleted and no repeated entry will be inserted to the list.
sl@0: 
sl@0: @param aUid The uid of the repository to be added to this array.
sl@0: @return The index of the new or existing entry within the list.
sl@0: */
sl@0: TInt CRepositoryBackupClient::AddRestoredRepositoryL(TUid aUid)
sl@0: 	{
sl@0: 	CRestoredRepository* rstRepos = new(ELeave) CRestoredRepository(aUid);
sl@0: 	CleanupStack::PushL(rstRepos);
sl@0: 	TInt err = iRestoredRepositoriesArray.InsertInOrder(rstRepos, TLinearOrder<CRestoredRepository>(CRestoredRepository::CompareUids));
sl@0: 	if(err != KErrNone && err != KErrAlreadyExists)
sl@0: 		User::Leave(err);
sl@0: 	TInt index = iRestoredRepositoriesArray.FindInOrderL(rstRepos, TLinearOrder<CRestoredRepository>(CRestoredRepository::CompareUids));
sl@0: 	CleanupStack::Pop();
sl@0: 	
sl@0: 	if(err == KErrAlreadyExists)
sl@0: 		{
sl@0: 		delete rstRepos;
sl@0: 		}
sl@0: 	return index;
sl@0: 	}