persistentstorage/centralrepository/cenrepsrv/install.cpp
changeset 0 08ec8eefde2f
child 12 6b6fd149daa2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/centralrepository/cenrepsrv/install.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,573 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implements installed file notification
+// 
+//
+
+/**
+ @internalComponent
+*/
+
+#include "install.h"
+#include "srvrepos_noc.h"
+#include "srvres.h"
+#include "srvparams.h"
+#include "cachemgr.h"
+
+CCentRepSWIWatcher* CCentRepSWIWatcher::NewL(RFs& aFs)
+	{
+	CCentRepSWIWatcher* self = new(ELeave) CCentRepSWIWatcher(aFs);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+void CCentRepSWIWatcher::ConstructL()
+	{
+	// Attach to SWI property
+	User::LeaveIfError(iSWIKey.Attach( KUidSystemCategory, KSAUidSoftwareInstallKeyValue));
+	
+	// Initialise SWI operation and status
+	TInt swiProperty;
+	const TInt error = iSWIKey.Get(KUidSystemCategory, KSAUidSoftwareInstallKeyValue, swiProperty);
+	
+	if (error == KErrNone)
+		{
+		iSWIOperation=swiProperty & KSASwisOperationMask;
+		iSWIStatus= swiProperty & KSASwisOperationStatusMask;
+		}
+	else if (error != KErrNotFound)
+		{
+		User::LeaveIfError(error);
+		}
+	
+	// Get last saved contents of install directory
+	GetInstallDirL();
+
+	// Do any actions required by pre server start-up SWI activity
+	TRAP_IGNORE(FindChangedEntriesL(ETrue));
+	}
+	
+CCentRepSWIWatcher::CCentRepSWIWatcher(RFs& aFs) :
+ 	CActive(EPriorityStandard), 
+ 	iInstallDir(*TServerResources::iInstallDirectory),
+ 	iFs(aFs),
+ 	iSWIOperation( ESASwisNone),
+	iSWIStatus( ESASwisStatusSuccess)
+	{
+ 	CActiveScheduler::Add(this);
+	}
+	
+CCentRepSWIWatcher::~CCentRepSWIWatcher()
+	{
+	Cancel();
+	iSWIKey.Cancel();
+	iSWIKey.Close();
+	iInstallEntryArray.ResetAndDestroy();
+	iCurrentInstallDirEntries.ResetAndDestroy();
+	}
+
+void CCentRepSWIWatcher::Start()
+	{
+	if(IsActive())
+		return;
+	
+	NotifyChange();
+	}
+	
+ void CCentRepSWIWatcher::NotifyChange()
+ 	{
+	
+	// Register for P&S of SWI flag
+	iSWIKey.Subscribe(iStatus);
+	
+	SetActive();
+	}
+
+void CCentRepSWIWatcher::RunL()
+	{	
+	NotifyChange();
+		
+	// Get SWI Key 
+	TInt swiProperty;
+	User::LeaveIfError(iSWIKey.Get(KUidSystemCategory, KSAUidSoftwareInstallKeyValue, swiProperty));
+	
+	HandleSWIEventL(swiProperty);
+	}
+	
+void CCentRepSWIWatcher::HandleSWIEventL(TInt aSWIProperty)
+	{	
+	iSWIOperation=aSWIProperty & KSASwisOperationMask;
+	iSWIStatus=   aSWIProperty & KSASwisOperationStatusMask;
+
+	// Need to handle successful and aborted install/uninstall and successful restore
+	// Can't handle aborted restore
+	switch(iSWIOperation)
+		{
+		case ESASwisNone:
+			break;
+		case ESASwisInstall:
+		case ESASwisUninstall:
+			if(iSWIStatus==ESASwisStatusSuccess)
+				{
+				// Handle SWI events
+				FindChangedEntriesL();
+				}
+			else if(iSWIStatus==ESASwisStatusAborted)
+				{
+				// Update directory to reset timestamps
+				ReadInstallDirL(iInstallEntryArray);
+				SaveInstallDirL();
+				}
+			break;
+		case ESASwisRestore:
+			break;
+		default:
+			break;
+		}
+	}
+	
+// Catch leaves so they don't stop the server
+TInt CCentRepSWIWatcher::RunError( TInt aError)
+	{
+	static_cast<void>(aError);
+	
+	RDebug::Print(_L("Run error %d"), aError);
+	
+	// Reinitialise directory list
+	iInstallEntryArray.ResetAndDestroy();
+	
+	if(!IsActive())
+		{
+		NotifyChange();
+		}
+		
+	// Renable cache activity in case of errors during SWI events 
+	TServerResources::iCacheManager->EnableCache();
+		
+	return KErrNone;
+	}
+	
+void CCentRepSWIWatcher::DoCancel()
+	{
+	// Cancel subscription to SW P&S flag
+	iSWIKey.Cancel();
+	iSWIKey.Close();
+	}
+
+void CCentRepSWIWatcher::ReadInstallDirL(RPointerArray<CInstallEntry> &aEntryArray)
+	{
+	RDir dir;
+    CleanupClosePushL(dir);
+    
+	//Empty contents of directory
+	aEntryArray.ResetAndDestroy();
+
+	// Read contents of install directory
+	User::LeaveIfError(dir.Open(iFs, iInstallDir, KEntryAttNormal));
+    
+    TEntryArray dirEntries;
+    TInt readError = KErrNone;
+    
+	while (readError != KErrEof)  
+		{
+	    readError = dir.Read(dirEntries);
+    
+	    if(readError != KErrNone && readError != KErrEof) 
+	    	{
+	    	User::Leave(readError);
+	    	}
+	    else
+	    	{
+	    	const TInt dirCount = dirEntries.Count();   
+	    	for (TInt i=0; i<dirCount; i++)
+	    		{
+	    		CInstallEntry* installEntry = CInstallEntry::NewL();
+	    		CleanupStack::PushL(installEntry);
+	    		installEntry->SetL(const_cast<TEntry&>(dirEntries[i]));
+	    		if (installEntry->FileExt()==EUnknown)
+	    		    {
+	    		    CleanupStack::PopAndDestroy();
+	    		    }
+	    		else
+	    		    {
+	    		    User::LeaveIfError(aEntryArray.Append(installEntry));
+	    		    CleanupStack::Pop(installEntry);
+	    		    }
+	    		}
+	    	}
+		}
+
+	CleanupStack::PopAndDestroy(&dir);
+	}
+	
+TBool CCentRepSWIWatcher::MatchEntries( const CInstallEntry &aSource, const CInstallEntry &aTarget)
+	{
+	return((aSource.Uid()==aTarget.Uid()) &&
+	       (aSource.FileExt()==aTarget.FileExt()));
+	}
+		
+void CCentRepSWIWatcher::FindChangedEntriesL(TBool aStartup)
+	{
+	// Find added or updated entries
+	ReadInstallDirL(iCurrentInstallDirEntries);
+		
+	TInt newCount=iCurrentInstallDirEntries.Count();
+	TInt currentCount=iInstallEntryArray.Count();
+	TInt i;
+	TInt r;
+	TInt operation;
+
+	// If both counts are 0, we shouldn't have been notified, just return
+	if( (newCount==0) && (currentCount==0))
+		return;
+	
+	if(aStartup)
+		{
+		operation=ESASwisNone;
+		}
+	else
+		{
+		operation=iSWIOperation;
+		}
+
+	// We don't want cache activity during SWI operations
+	TServerResources::iCacheManager->DisableCache();
+
+	if( newCount==0)						// currentCount > 0, newCount = 0
+		{									// All installed files have been deleted
+		// Handle deletes of all files
+		for(i=0;i<currentCount;i++)
+			{
+			iInstallEntryArray[i]->HandleFileDeleteL(operation);
+			}
+		// Free memory of elements
+		iInstallEntryArray.ResetAndDestroy();
+		}
+	else 
+		{	
+		if( currentCount==0)				// currentCount = 0, newCount > 0
+			{								// All new files need to be handled
+			for(i=0;i<newCount;i++)
+				{
+				CInstallEntry* newEntry=iCurrentInstallDirEntries[i];
+				newEntry->HandleFileCreateL(operation);
+				}
+			}
+		else								// currentCount > 0, newCount > 0
+			{
+			// Find added and modified entries by going through new entries and
+			// looking for them in current array
+			for(i=0;i<newCount;i++)
+				{
+				CInstallEntry* newEntry=iCurrentInstallDirEntries[i];
+				r=iInstallEntryArray.Find( newEntry, MatchEntries);
+				// If we find new entry in current array, check modification date
+				if(r>=KErrNone)
+					{
+					CInstallEntry* currentEntry=iInstallEntryArray[r];
+					if( newEntry->Modified() > currentEntry->Modified())
+						{												
+						// Deal with newly installed file, note use newEntry
+						// so we use new timestamp
+						newEntry->HandleFileUpdateL(operation);
+						}
+					}
+				else if(r==KErrNotFound)		// File has been added
+					{
+					// Handle add
+					newEntry->HandleFileCreateL(operation);
+					// Don't leave on KErrNotFound
+					r=KErrNone;
+					}
+				User::LeaveIfError(r);
+				}
+	
+			// Find deleted entries by going through current entries and looking for them 
+			// in new array
+			for(i=0;i<currentCount;i++)
+				{
+				CInstallEntry* currentEntry=iInstallEntryArray[i];
+				r=iCurrentInstallDirEntries.Find( currentEntry, MatchEntries);
+				// If we don't find current entry in new array, it's been deleted
+				if(r==KErrNotFound)
+					{
+					// Deal with uninstalls
+					currentEntry->HandleFileDeleteL(operation);
+					// Don't leave on KErrNotFound
+					r=KErrNone;
+					}
+				User::LeaveIfError(r);
+				}
+			}
+
+		// Clear out old list
+		iInstallEntryArray.ResetAndDestroy();
+		
+		// Re-read directory - if any files were corrupt they have been deleted
+		// during the merge, so we need to re-read in case this has occurred
+		ReadInstallDirL(iInstallEntryArray);
+		}
+		
+	SaveInstallDirL();
+	iCurrentInstallDirEntries.ResetAndDestroy();
+	
+	// SWI operations finished, enable cache
+	TServerResources::iCacheManager->EnableCache();				
+	} 
+
+CInstallEntry::CInstallEntry() :
+	iUid(KNullUid),
+	iModified(0),
+	iFileExt(EUnknown)
+	{
+	}
+
+CInstallEntry::~CInstallEntry()
+	{
+	if( iRepository)
+		{
+		iRepository->Close();
+		delete iRepository;
+		}
+	delete iNotifier;
+	}
+
+void CInstallEntry::SetL(TEntry& aEntry)	
+	{
+	// Get uid from file name
+	const TInt KUidLen = 8;
+	TPtrC uidPtr=aEntry.iName.Des().LeftTPtr(KUidLen);
+	TLex  lex=uidPtr;
+
+	TUint32 uid;
+	User::LeaveIfError(lex.Val(uid,EHex)); 
+	iUid.iUid=static_cast<TInt32>(uid);
+	
+	// save extension type 
+	_LIT(KIniFileExtension, ".txt");
+	_LIT(KExternalizedFileExt, ".cre");
+
+	const TInt KExtLen = 4;
+	TPtrC extPtr=aEntry.iName.Des().RightTPtr(KExtLen);
+	
+	if(extPtr.Compare(KIniFileExtension)==0)
+		{
+		iFileExt=EIni;
+		}
+	else if(extPtr.Compare(KExternalizedFileExt)==0)
+		{
+		iFileExt=ECre;
+		}
+	else
+		{
+		iFileExt=EUnknown;
+		}
+		
+	iModified=aEntry.iModified;
+	}
+	
+void CInstallEntry::ConstructL()	
+	{
+	// Create repository object
+	iRepository = new(ELeave) CServerRepository;
+	// Notifier needed to open repositories.		
+	iNotifier = new(ELeave)CSessionNotifier ;
+	}
+	
+CInstallEntry* CInstallEntry::NewL()
+	{
+	CInstallEntry* self=new(ELeave)CInstallEntry();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+TUid CInstallEntry::Uid() const
+	{
+	return iUid;
+	}
+	
+TTime CInstallEntry::Modified() const
+	{
+	return iModified;
+	}
+	
+TCentRepFileType CInstallEntry::FileExt() const
+	{
+	return iFileExt;
+	}
+ 	
+void CInstallEntry::ExternalizeL(RWriteStream& aStream) const
+	{
+ 	aStream << iUid.iUid;
+	aStream << iModified.Int64();
+	TUint32 fileExt=iFileExt;
+	aStream << fileExt;
+ 	}
+ 	
+void CInstallEntry::InternalizeL(RReadStream& aStream)
+	{
+ 	aStream >> iUid.iUid;
+ 	TInt64 time;
+	aStream >> time;
+	iModified=time;
+	TUint32 fileExt;
+	aStream >> fileExt;
+	iFileExt =  static_cast<TCentRepFileType>(fileExt);
+ 	}
+ 		
+
+void CCentRepSWIWatcher::ReadAndInternalizeInstallDirL(const TDesC& aInstallDirFilePath)
+	{
+	RFile file;
+	TInt e=file.Open(TServerResources::iFs,aInstallDirFilePath, EFileRead|EFileShareReadersOnly);
+	if(e == KErrNotFound || e == KErrPathNotFound)
+		{
+		User::Leave(KErrNotFound);
+		}
+	CleanupClosePushL(file);
+
+	CDirectFileStore* store = CDirectFileStore::FromLC (file);
+	if(store->Type()[0] != KDirectFileStoreLayoutUid)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	iInstallEntryArray.ResetAndDestroy();
+
+	// Get the root stream and attempt to read the index from it
+	TStreamId rootStreamId = store->Root() ;
+	RStoreReadStream rootStream ;
+	rootStream.OpenLC(*store, rootStreamId);
+	
+	// Internalize the repository	
+	TUint32 count;
+	rootStream >> count;
+	for(TUint i=0; i<count;i++)
+		{
+		CInstallEntry* installEntry = CInstallEntry::NewL();
+		CleanupStack::PushL(installEntry);
+		rootStream >> *installEntry;
+		User::LeaveIfError(iInstallEntryArray.Append(installEntry));
+		CleanupStack::Pop(installEntry);
+		}
+		
+	CleanupStack::PopAndDestroy(&rootStream);
+	CleanupStack::PopAndDestroy(store);
+	CleanupStack::PopAndDestroy();
+	}
+
+void CCentRepSWIWatcher::GetInstallDirL()
+	{
+	_LIT(KInstallDirFile, "installdir.bin");	
+	HBufC* filePath = HBufC::NewLC(TServerResources::iDataDirectory->Length() + KInstallDirFile().Length());
+	TPtr installDirFilePath(filePath->Des());
+	installDirFilePath.Append(*TServerResources::iDataDirectory);
+	installDirFilePath.Append(KInstallDirFile);
+	
+	TRAPD(err, ReadAndInternalizeInstallDirL(installDirFilePath)); // try to open installdir file and internalize its contents
+	if (err != KErrNone) 
+		{
+		TInt fileDeleteErr = TServerResources::iFs.Delete(installDirFilePath);
+		// If a debug build - record error
+		#ifdef _DEBUG
+			if (fileDeleteErr != KErrNone && err != KErrNotFound)
+				{
+				RDebug::Print(_L("CCentRepSWIWatcher::GetInstallDirL - Failed to delete file. Error = %d"), fileDeleteErr);
+				}
+		#else
+			(void)fileDeleteErr;
+		#endif	
+			
+		// No file saved - read initial contents of directory
+		ReadInstallDirL(iInstallEntryArray);
+		SaveInstallDirL();	
+		}		
+	CleanupStack::PopAndDestroy(filePath);		
+	}
+	
+void CCentRepSWIWatcher::SaveInstallDirL() 
+	{	
+	_LIT(KInstallDirFile, "installdir.bin");
+	_LIT(KInstallDirTmpFile, "installdir.tmp");
+	
+	TBuf<KMaxFileName> installDirTrnsFilePath;
+	installDirTrnsFilePath.Append(*TServerResources::iDataDirectory);
+	installDirTrnsFilePath.Append(KInstallDirTmpFile);
+	
+	// Create file store
+	CDirectFileStore* store = CDirectFileStore::ReplaceLC(TServerResources::iFs, installDirTrnsFilePath,
+		                                                      (EFileWrite | EFileShareExclusive));
+	const TUid uid2  = KNullUid ;	                                                     
+	store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; 
+		
+	// Write the stream index/dictionary as root stream within the store
+	// so we can access it when we do a restore later on
+	RStoreWriteStream rootStream ;
+	TStreamId rootStreamId = rootStream.CreateLC(*store) ;
+	
+	TUint32 count=iInstallEntryArray.Count();
+	rootStream << count;
+	for(TUint i=0; i<count;i++)
+		{
+		rootStream << *iInstallEntryArray[i];
+		}
+		
+	rootStream.CommitL() ;
+		
+	CleanupStack::PopAndDestroy(&rootStream) ;
+	store->SetRootL(rootStreamId);
+	store->CommitL();
+	CleanupStack::PopAndDestroy(store) ; 	
+	
+	TBuf<KMaxFileName> installDirFilePath;
+	installDirFilePath.Append(*TServerResources::iDataDirectory);
+	installDirFilePath.Append(KInstallDirFile);
+
+    User::LeaveIfError(TServerResources::iFs.Replace(installDirTrnsFilePath, installDirFilePath));	
+	}
+
+
+void CInstallEntry::HandleFileDeleteL(TInt aOperation)
+	{
+	// File should only have been deleted if operation was uninstall
+	// or in startup case
+	if((aOperation!=ESASwisNone) && (aOperation!=ESASwisUninstall))
+		User::Leave(KErrAbort);
+					
+	iRepository->HandleSWIDeleteL(Uid(), *iNotifier);
+	}
+	
+void CInstallEntry::HandleFileCreateL(TInt aOperation)
+	{
+	// File should only have been created if operation was install
+	// or in startup case
+	if((aOperation!=ESASwisNone) && (aOperation!=ESASwisInstall))
+		User::Leave(KErrAbort);
+					
+	iRepository->HandleSWIUpdateL(Uid(), Modified(), *iNotifier);
+	}
+	
+void CInstallEntry::HandleFileUpdateL(TInt aOperation)
+	{
+	// File should only have been modified if operation was install
+	// or in startup case
+	if((aOperation!=ESASwisNone) && (aOperation!=ESASwisInstall))
+		User::Leave(KErrAbort);
+					
+	iRepository->HandleSWIUpdateL(Uid(), Modified(), *iNotifier);
+	}