--- /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);
+ }