--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/sisregistry/server_legacy/sisregistrycache.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,2488 @@
+/*
+* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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:
+* CSisRegistryCache class implementation
+*
+*/
+
+
+/**
+ @file
+ @released
+ @internalComponent
+*/
+#include "log.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "swi/sisregistrylogversion.h"
+#endif //SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "arrayutils.h"
+#include "sisregistrycache.h"
+#include "sisregistrypackage.h"
+#include "sisregistryserverconst.h"
+#include "sisregistryfile.h"
+#include "sisregistryobject.h"
+
+#include "integrityservices.h"
+#include "installtypes.h"
+#include "dessisdataprovider.h"
+#include "filesisdataprovider.h"
+#include "controllerinfo.h"
+#include "hashcontainer.h"
+#include "sisregistryfiledescription.h"
+#include "siscontroller.h"
+#include "sistruststatus.h"
+#include "sisregistryserver.h"
+#include "sisregistrytoken.h"
+#include "siscertificatechain.h"
+#include "cleanuputils.h"
+#include "sisregistryutil.h"
+#include "swispubsubdefs.h"
+#include <sacls.h>
+#include <connect/sbdefs.h>
+#include "securitypolicy.h"
+#include "sislangchangemonitor.h"
+
+using namespace Swi;
+
+_LIT(KTempLog,"\\sys\\install\\templog.txt");
+
+const TInt KUidHexLength = 8;
+
+TUint CSisRegistryCache::iSubsessionId = 0;
+
+CSisRegistryCache* CSisRegistryCache::NewL()
+ {
+ CSisRegistryCache* self = NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CSisRegistryCache* CSisRegistryCache::NewLC()
+ {
+ CSisRegistryCache* self = new(ELeave) CSisRegistryCache;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+CSisRegistryCache::~CSisRegistryCache()
+ {
+ TInt res;
+ // General note: trap the error because this is not a leaving function
+ // and generating an error will not help
+
+ // store the backup file out
+ TRAP(res, StoreBackupL());
+ if (res != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Failed to store backup (failure code: %d.)"), res);
+ }
+
+ // integrity service operation committing point
+ TRAP(res, iIntegrityService->CommitL());
+ if (res != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Failed to commit integrity services changes (failure code %d.)"), res);
+ }
+
+ delete iBackupFile;
+
+ delete iIntegrityService;
+ delete iSisRegLangMonitor;
+ CleanUp();
+ iFs.Close();
+
+ }
+
+void CSisRegistryCache::ConstructL()
+ //
+ // 2nd phase construct
+ //
+ {
+ User::LeaveIfError(iFs.Connect());
+
+ RBuf backupFile;
+ backupFile.CreateL(KMaxFileName);
+ backupFile.CleanupClosePushL();
+ backupFile.Append(KSysBackupFile);
+ backupFile[0] = iFs.GetSystemDriveChar();
+ iBackupFile = backupFile.AllocL();
+
+ CleanupStack::PopAndDestroy(&backupFile); //backupFile
+
+ iSystemDrive = iFs.GetSystemDrive();
+ iUseIntegServices = ETrue;
+
+ // private integrity service initialized by time
+ TTime currentTime;
+ currentTime.UniversalTime();
+ iIntegrityService = CIntegrityServices::NewL(currentTime.Int64(), KIntegrityServicesPath);
+
+ // if backup file exists, read it and delete file - the short cut
+ // otherwise revert to reading from registry directories and building registry from scratch
+ TInt res = KErrNone;
+ TRAP(res , res = IsFirmwareUpdatedL());
+ if ( !res )
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - No Firware upgrade detected. Trying to intialize from cache "));
+ TRAP(res, InitFromBackupL());
+ isFwUpdated = EFalse;
+ }
+ else
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - Firware upgrade detected. Initializing from registry/stub entries"));
+ res = KErrGeneral;
+ isFwUpdated = ETrue;
+ }
+
+ // if the backup file has not been found or it was garbled or else
+ if (res != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Construction from backup failed (Error code %d). Proceeding with re-init."),
+ res);
+
+ // InitFromBackupL() failed, there might have some entries left on the cache
+ CleanUp();
+
+ InitStartUpL();
+ UpdateLocalizedNamesL();
+ }
+ //Start language change monitor.
+ iSisRegLangMonitor = CSisLangChangeMonitor::NewL(*this);
+ }
+
+void CSisRegistryCache::CleanUp()
+ {
+ iTokens.ResetAndDestroy();
+ iFiles.ResetAndDestroy();
+ }
+
+void CSisRegistryCache::UidListL(RArray<TUid>& aUids) const
+ {
+ aUids.Reset();
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ TInt err = aUids.InsertInUnsignedKeyOrder((iTokens[i])->Uid());
+ if ((err != KErrNone) && (err != KErrAlreadyExists))
+ {
+ User::Leave(err);
+ }
+ }
+ }
+
+void CSisRegistryCache::PackageListL(RPointerArray<CSisRegistryPackage>& aPackages) const
+ {
+ aPackages.ResetAndDestroy();
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ CSisRegistryPackage *package = CSisRegistryPackage::NewLC(*iTokens[i]);
+ aPackages.AppendL(package);
+ CleanupStack::Pop(package);
+ }
+ }
+
+RFs& CSisRegistryCache::RFsHandle()
+ {
+ return iFs;
+ }
+
+void CSisRegistryCache::BuildRomListL()
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - Registering In-Rom controllers."));
+
+ TDriveUnit romDrive(SystemRomDrive());
+ RBuf romRegistryPath;
+ romRegistryPath.CreateL(romDrive.Name(), KMaxPath);
+ CleanupClosePushL(romRegistryPath);
+ romRegistryPath.Append(KPreInstalledPath);
+ // open the directory
+ CDir* dir;
+ TInt err = iFs.GetDir(romRegistryPath, KEntryAttMatchExclude | KEntryAttDir, ESortNone, dir);
+ // check that all is correct but make sure to handle missing directory
+
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Reading ROM stub directory returned %d."), err);
+
+ if (err == KErrNone)
+ {
+ CleanupStack::PushL(dir);
+
+ TInt count(dir->Count());
+ RBuf controllerFileName;
+ controllerFileName.CreateL(KMaxFileName);
+ CleanupClosePushL(controllerFileName);
+ for (TInt index = 0; index < count; ++index)
+ {
+ controllerFileName = romRegistryPath;
+ controllerFileName.Append((*dir)[index].iName);
+ TRAPD(res, RegisterInRomControllerL(controllerFileName));
+ if (res != KErrNone)
+ {
+ // log it only, we cannot stop as the next might be ok
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Failed to register in ROM controller. Error code %d."), res);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2, dir); // controllerFileName
+ }
+ else if(err != KErrPathNotFound)
+ {
+ User::Leave(err);
+ }
+
+ CleanupStack::PopAndDestroy(&romRegistryPath);
+ }
+
+void CSisRegistryCache::RegisterInRomControllerL(const TDesC& aFileName)
+ {
+ DEBUG_PRINTF2(_L("Sis Registry Server - Registering In-ROM controller file '%S'."), &aFileName);
+
+ RFile romController;
+ CleanupClosePushL(romController);
+ // open file and read the data
+ User::LeaveIfError(romController.Open(iFs, aFileName, EFileRead | EFileShareReadersOnly));
+ // read the data from the file
+ TInt fileSize;
+ romController.Size(fileSize);
+ HBufC8* controllerData = HBufC8::NewLC(fileSize);
+ TPtr8 ptr(controllerData->Des());
+ romController.Read(0, ptr, fileSize);
+
+ CDesDataProvider* desProvider = CDesDataProvider::NewLC(*controllerData);
+ // read the controller
+ Swi::Sis::CController* controller = Swi::Sis::CController::NewLC(*desProvider);
+
+ // create an object from the controller
+ CSisRegistryObject* object = CSisRegistryObject::NewLC();
+
+ // Discard the 4 byte type field for consistency with
+ // all other registry entries
+ TPtrC8 assumedTypeController(controllerData->Mid(4));
+ object->ProcessInRomControllerL(*controller, assumedTypeController);
+
+ TBool overwriteRegEntry = EFalse;
+
+ TBool isStubRegistered = IsRegistered(*object);
+ if ( isFwUpdated && isStubRegistered )
+ {
+ CSisRegistryObject* tmpObj = ObjectL(object->Uid(),object->Index());
+ CleanupStack::PushL(tmpObj);
+ TSisPackageTrust trustStatus = tmpObj->Trust();
+ if ( ESisPackageBuiltIntoRom == trustStatus )
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Attempting to delete registry entry 0x%08x as a firmware update detected"), object->Uid().iUid);
+ overwriteRegEntry = ETrue;
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(tmpObj->Uid(), tmpObj->Index());
+ //Delete in memory copy of Registry token as it is no longer valid
+ // Before deleting the reg entry. Otherwise there may inconsistency
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if (!(*iTokens[i] == *tmpObj))
+ continue;
+
+ // remove this token from the array
+ CleanupStack::PushL(iTokens[i]);
+ iTokens.Remove(i);
+ CleanupStack::PopAndDestroy(1); // iTokens[i]
+ break;
+ }
+ TEntry entry;
+ TInt err = iFs.Entry(*name, entry);
+ if ( err==KErrNone )
+ {
+ iFs.Delete(*name);
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Successfully deleted registry entry 0x%08x. "), object->Uid().iUid);
+ }
+ CleanupStack::PopAndDestroy();
+ }
+ CleanupStack::PopAndDestroy();
+ }
+
+
+ // we cannot guess whether it is registered without opening it
+ if (!isStubRegistered || overwriteRegEntry )
+ {
+ // update cache or just call refresh
+ AddEntryL(*object, *iIntegrityService);
+
+ // store a copy of the controller
+ HBufC* name = SisRegistryUtil::BuildControllerFileNameLC(object->Uid(), object->Index(),
+ 0);
+
+ SisRegistryUtil::EnsureDirExistsL(iFs, *name);
+ RFile newController;
+
+ // If stray .ctl files exist (for example, after phone was rebooted in the middle of registration), calling RFile::Create() will result a Leave.
+ // Therefore, RFile::Replace() is rather ideal.
+ User::LeaveIfError(newController.Replace(iFs, *name, EFileWrite | EFileShareExclusive));
+ CleanupStack::PopAndDestroy(name);
+ CleanupClosePushL(newController);
+
+ // Write the controller, minus the 4 byte type field for consistency with
+ // all other registry entries
+ newController.Write(assumedTypeController);
+ CleanupStack::PopAndDestroy(&newController);
+ }
+
+ CleanupStack::PopAndDestroy(5, &romController); //controller, object, desProvider, controllerData
+ }
+
+void CSisRegistryCache::BuildUidListL()
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - Reading registry files from disk."));
+
+ TDriveUnit drive(iSystemDrive);
+ RBuf registryPath;
+ registryPath.CreateL(drive.Name(), KMaxPath);
+ CleanupClosePushL(registryPath);
+ registryPath.Append(KRegistryPath);
+ CDir* dir;
+ TInt err = iFs.GetDir(registryPath, KEntryAttDir, ESortNone, dir);
+
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Reading registry directory returned %d"), err);
+ if(err == KErrNone)
+ {
+
+ CleanupStack::PushL(dir);
+
+ TInt count(dir->Count());
+ RBuf uidPath;
+ uidPath.CreateL(KMaxFileName);
+ CleanupClosePushL(uidPath);
+ for (TInt index = 0; index < count; ++index)
+ {
+
+ const TEntry& entry = (*dir)[index];
+ TPtrC ptr(entry.iName);
+ // we expect uid directories to be 8 characters long, ignore others
+ if (ptr.Length() == KUidHexLength)
+ {
+ TLex lex(ptr);
+ TUint32 uid;
+
+ // Convert the filename to a Uint32.
+ User::LeaveIfError(lex.Val(uid, EHex));
+ uidPath = registryPath;
+ uidPath.Append(entry.iName);
+ uidPath.Append(KPathDelimiter);
+ //for this uid
+ TRAPD(res, BuildFileListL(TUid::Uid(uid), uidPath););
+ if (res != KErrNone )
+ {
+ // log it only, we cannot stop as the next might be ok
+ DEBUG_PRINTF3(_L8("Sis Registry Server - Failed to read from registry entry 0x%08x. Error code %d"),
+ uid, res);
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2, dir); // uidPath
+
+ }
+ else
+ {
+ if (err != KErrPathNotFound)
+ {
+ User::Leave(err);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(®istryPath);
+ }
+
+void CSisRegistryCache::BuildFileListL(TUid aUid, const TDesC& aPath)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Attempting to read registry entry 0x%08x."), aUid.iUid);
+
+ RBuf registryFileSpec;
+ registryFileSpec.CreateL(aPath, KMaxFileName);
+ CleanupClosePushL(registryFileSpec);
+ registryFileSpec.Append(KRegFileFilter);
+
+ CDir* dir;
+ User::LeaveIfError(iFs.GetDir(registryFileSpec, KEntryAttMatchExclude | KEntryAttDir, ESortNone, dir));
+ CleanupStack::PushL(dir);
+
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Registry entry contains %d registry files."), dir->Count());
+
+ TInt count(dir->Count());
+ RBuf fileName;
+ fileName.CreateL(KMaxFileName);
+ CleanupClosePushL(fileName);
+ for (TInt index = 0; index < count; ++index)
+ {
+ fileName = aPath;
+ fileName.Append((*dir)[index].iName);
+ RFileReadStream fileStream;
+ // open the file
+ User::LeaveIfError(fileStream.Open(iFs, fileName, EFileRead));
+ CleanupClosePushL(fileStream);
+ CSisRegistryToken* token = CSisRegistryToken::NewLC(fileStream);
+
+ DEBUG_PRINTF5(_L("Sis Registry Server - Entry at index %d, UID: 0x%08x, Name: %S, Vendor: %S."),
+ index, token->Uid().iUid, &(token->Name()), &(token->Vendor()));
+
+ if (token->Uid() != aUid)
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - Registry file does not match entry directory. Corrupt."));
+ User::Leave(KErrCorrupt);
+ }
+
+ iTokens.Append(token);
+ CleanupStack::Pop(token);
+ CleanupStack::PopAndDestroy(&fileStream);
+
+ }
+
+ CleanupStack::PopAndDestroy(3, ®istryFileSpec); // dir, filename
+ }
+
+void CSisRegistryCache::InitFromBackupL()
+ {
+ // cleanup the list
+ iTokens.ResetAndDestroy();
+
+ RBuf backupFile;
+ backupFile.CreateL(KMaxFileName);
+ backupFile.CleanupClosePushL();
+ backupFile.Append(KSysBackupFileBackup);
+ backupFile[0] = iFs.GetSystemDriveChar();
+
+ // if the backup of the cache backup file exists, the cache backup file may
+ // be corrupt. Delete it and return immediately. The cache will be regenerated.
+ TInt err = iFs.Delete(backupFile);
+
+ if (err == KErrNone)
+ {
+ DEBUG_PRINTF2(_L("CSisRegistryCache::InitFromBackupL deleted %S. Corrupt file?"), &backupFile);
+ User::LeaveIfError(KErrNotFound);
+ }
+ else if (err != KErrNotFound)
+ {
+ User::LeaveIfError(err);
+ }
+
+ User::LeaveIfError(iFs.Rename(*iBackupFile, backupFile));
+
+ // open file as a read stream and read data as a stream
+ RFileReadStream stream;
+
+ User::LeaveIfError(stream.Open(iFs, backupFile, EFileRead | EFileShareReadersOnly));
+
+ CleanupClosePushL(stream);
+ TLanguage currentLanguage = User::Language();
+ TLanguage storedLanguage = static_cast<TLanguage>(stream.ReadUint32L());
+ // Stored Language can't be greater than ELangMaximum
+ // Hence Leave as the backupfile may be corrupted
+ if ( storedLanguage > ELangMaximum)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ InternalizePointerArrayL(iTokens, stream);
+ if ( currentLanguage != storedLanguage)
+ {
+ UpdateLocalizedNamesL();
+ }
+ CleanupStack::PopAndDestroy(&stream);
+
+ // in the unlikely event that the CommitL() fails in ConstructL()
+ // when we remove this file, it needs to be the same as the original name.
+ User::LeaveIfError(iFs.Rename(backupFile, *iBackupFile));
+
+ CleanupStack::PopAndDestroy(&backupFile);
+
+ // remove the file, all the information is in RAM
+ // no need to maintain and syncronise the information in two places
+ // so integrity services a scheduled to remove the file at next call to commit
+ iIntegrityService->RemoveL(*iBackupFile);
+
+ iIntegrityService->CommitL();
+
+ // only when all is processed one can check the package state
+ UpdatePackagePresentStateL();
+ }
+
+void CSisRegistryCache::InitStartUpL()
+ {
+ TRAPD(res, UpdateRecentFWVersionL(););
+ if (res != KErrNone)
+ {
+ // log that
+ DEBUG_PRINTF2(_L8("Updating recent Firmware Version failed with error code = %d."), res);
+ }
+
+ // else reinit lists- initial settings, esp at the first reboot
+ BuildUidListL();
+ iUseIntegServices = EFalse; // temporarily "turn off" integrity services. It is not needed to process ROM stubs
+ BuildRomListL();
+ iUseIntegServices = ETrue;
+
+ // While building the UIDs and the ROM list, new files could've been generated, so we should commit the changes to the FS.
+ iIntegrityService->CommitL();
+
+ // only when all is processed one can check the package state
+ UpdatePackagePresentStateL();
+ }
+
+void CSisRegistryCache::StoreBackupL()
+ {
+ SisRegistryUtil::EnsureDirExistsL(iFs, *iBackupFile);
+ iIntegrityService->AddL(*iBackupFile);
+ RFileWriteStream stream;
+ CleanupClosePushL(stream);
+ User::LeaveIfError(stream.Replace(iFs, *iBackupFile, EFileWrite | EFileShareExclusive));
+ // Append the currently running language ID onto backup file
+ // This will be used during initialization from backup to decide
+ // whether to update the vendor and packages names during initialization.
+ stream.WriteUint32L(User::Language());
+ ExternalizePointerArrayL(iTokens, stream);
+ stream.CommitL();
+ CleanupStack::PopAndDestroy(&stream);
+ }
+
+TBool CSisRegistryCache::IsRegistered(const CSisRegistryPackage& aPackage) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if ((aPackage.Uid() == iTokens[i]->Uid()) &&
+ (aPackage.Name() == iTokens[i]->Name()) &&
+ (aPackage.Index() == iTokens[i]->Index()))
+
+ {
+ return ETrue;
+ }
+ }
+ // if we are here it is false
+ return EFalse;
+ }
+
+TBool CSisRegistryCache::IsRegistered(const TUid aUid) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if (iTokens[i]->Uid() == aUid)
+ {
+ return ETrue;
+ }
+ }
+
+ // if we are here it is not registered
+ return EFalse;
+ }
+
+TBool CSisRegistryCache::IsRegistered(const CHashContainer& aHashContainer) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ for (TInt j = 0; j < iTokens[i]->ControllerInfo().Count(); j++)
+ {
+ if (aHashContainer == iTokens[i]->ControllerInfo()[j]->HashContainer())
+ {
+ return ETrue;
+ }
+ }
+ }
+
+ // if we are here it is not registered
+ return EFalse;
+ }
+
+
+CSisRegistryPackage& CSisRegistryCache::PackageL(const TUid aUid) const
+ {
+ // when requesting a package by UID make sure we return the base
+ // package (index = 0) and not an augmentation (index > 0)
+ return CSisRegistryCache::PackageL( aUid, CSisRegistryPackage::PrimaryIndex);
+ }
+
+CSisRegistryPackage& CSisRegistryCache::PackageL(const TUid aUid, TInt aIndex) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if ((iTokens[i]->Uid() == aUid) && (iTokens[i]->Index() == aIndex))
+
+ {
+ return *iTokens[i];
+ }
+ }
+ User::Leave(KErrNotFound);
+ // to keep compiler happy, in reality if cannot find an entry leave above
+ return *iTokens[0];
+ }
+
+CSisRegistryPackage& CSisRegistryCache::PackageL(const TDesC& aName, const TDesC& aVendor) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if ((iTokens[i]->Name() == aName) &&
+ (iTokens[i]->Vendor() == aVendor))
+ {
+ return *iTokens[i];
+ }
+ }
+ User::Leave(KErrNotFound);
+ // to keep compiler happy, in reality if cannot find an entry leave above
+ return *iTokens[0];
+ }
+
+
+CSisRegistryToken& CSisRegistryCache::TokenL(const TUid aUid, TInt aIndex) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if ((iTokens[i]->Uid() == aUid) &&
+ (iTokens[i]->Index() == aIndex))
+ {
+ return *iTokens[i];
+ }
+ }
+
+ User::Leave(KErrNotFound);
+ // to keep compiler happy, in reality if cannot find an entry leave above
+ return *iTokens[0];
+ }
+
+CSisRegistryToken& CSisRegistryCache::TokenL(const TUid aUid, const TDesC& aName, const TDesC& aVendor) const
+ {
+ // Note - vendor not checked as the package Uid is enough to identify
+ // the package.
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if ((iTokens[i]->Uid() == aUid) &&
+ (aName == KNullDesC || (iTokens[i]->Name() == aName)) &&
+ (iTokens[i]->Vendor() == aVendor))
+ {
+ return *iTokens[i];
+ }
+ }
+
+ User::Leave(KErrNotFound);
+ // to keep compiler happy, in reality if cannot find an entry leave above
+ return *iTokens[0];
+ }
+
+CSisRegistryObject* CSisRegistryCache::ObjectL(TUid aUid, TInt aIndex)
+ {
+ const CSisRegistryToken& token = TokenL(aUid, aIndex);
+ return ObjectL(token);
+ }
+
+CSisRegistryObject* CSisRegistryCache::ObjectL(TUid aUid, const TDesC& aName, const TDesC& aVendor)
+ {
+ const CSisRegistryToken& token = TokenL(aUid, aName, aVendor);
+ return ObjectL(token);
+ }
+
+CSisRegistryObject* CSisRegistryCache::ObjectL(const CSisRegistryToken& aToken)
+ {
+ HBufC* name= SisRegistryUtil::BuildEntryFileNameLC(aToken.Uid(), aToken.Index());
+
+ RFileReadStream stream;
+ User::LeaveIfError(stream.Open(iFs, *name, EFileRead | EFileShareReadersOnly));
+ CleanupStack::PopAndDestroy(name);
+ CleanupClosePushL(stream);
+
+ // open entry
+ CSisRegistryObject *object = CSisRegistryObject::NewL(stream);
+ CleanupStack::PopAndDestroy(&stream);
+ return object;
+ }
+
+CSisRegistryPackage& CSisRegistryCache::SidToPackageL(const TUid aSid) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if (iTokens[i]->SidPresent(aSid))
+ {
+ return *iTokens[i];
+ }
+ }
+
+ User::Leave(KErrNotFound);
+ // to keep compiler happy, in reality if cannot find an entry leave above
+ return *iTokens[0];
+ }
+
+void CSisRegistryCache::SidToPackageL(const TUid aSid, RArray<CSisRegistryPackage>& aListMatchingPackages) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if (iTokens[i]->SidPresent(aSid))
+ {
+ aListMatchingPackages.AppendL(*iTokens[i]);
+ }
+ }
+
+ DEBUG_PRINTF2(_L("SidToPackageL ListMatchingPackages->Count = %d"), aListMatchingPackages.Count());
+ if(aListMatchingPackages.Count() == 0 )
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+
+TBool CSisRegistryCache::ModifiableL(const TDesC& aFileName)
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ // Create the object using the token we're looking at.
+ CSisRegistryObject* object = ObjectL(iTokens[i]->Uid(),
+ iTokens[i]->Name(),
+ iTokens[i]->Vendor());
+ CleanupStack::PushL(object);
+
+ // This (FileDescriptionL()) will confirm whether or not the object contains
+ // our filename. If it doesn't, then the function will leave with KErrNotFound.
+ TInt error;
+ TRAP(error, object->FileDescriptionL(aFileName));
+ if (error == KErrNone)
+ {
+ const CSisRegistryFileDescription& d = object->FileDescriptionL(aFileName);
+
+ // Since we got this far, it must mean that this object contains our filename and
+ // we now can safely find out if the file is modifiable, and return an appropriate
+ // Boolean value. If the expression below is True, then the file is modifiable.
+ TBool isModifiable = (d.OperationOptions() & Sis::EInstVerifyOnRestore) ? EFalse : ETrue;
+
+ // Files under \sys or \resource are never modifiable
+ _LIT(KSys, "\\sys\\");
+ _LIT(KResource, "\\resource\\");
+ if (d.Target().FindF(KSys) == 2 || d.Target().FindF(KResource) == 2)
+ {
+ isModifiable = EFalse;
+ }
+
+ CleanupStack::PopAndDestroy(object);
+ return isModifiable;
+ }
+ else if (error == KErrNotFound)
+ {
+ // This means that the object doesn't contain our filename.
+ // Destroy the object so we can continue onto the next iteration.
+ CleanupStack::PopAndDestroy(object);
+ }
+ else
+ {
+ // If FileDescriptionL() has returned any other error, then leave.
+ User::Leave(error);
+ }
+ }
+
+ User::Leave(KErrNotFound);
+
+ // This is only to keep the compiler happy. In reality, if it cannot find
+ // the appropriate entry, then it leaves above.
+ return EFalse;
+ }
+
+CHashContainer* CSisRegistryCache::HashL(const TDesC& aFileName)
+ {
+ CHashContainer* dummyHashContainer = NULL;
+
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ // Create the object using the token we're looking at.
+ CSisRegistryObject* object = ObjectL(iTokens[i]->Uid(),
+ iTokens[i]->Name(),
+ iTokens[i]->Vendor());
+ CleanupStack::PushL(object);
+
+ // This (FileDescriptionL()) will confirm whether or not the object contains
+ // our filename. If it doesn't, then the function will leave with KErrNotFound.
+ TInt error;
+ TRAP(error, object->FileDescriptionL(aFileName));
+ if (error == KErrNone)
+ {
+ const CHashContainer& hashContainer = object->FileDescriptionL(aFileName).Hash();
+
+ // The caller (ie, Swi::CSisRegistrySession::RequestHashL()) needs to take ownership of this.
+ CHashContainer* tempHashContainer = CHashContainer::NewL(hashContainer.Algorithm(), hashContainer.Data());
+
+ CleanupStack::PopAndDestroy(object);
+
+ // Since we got this far, it must mean that this object contains our filename
+ // and we now can safely return its hash.
+ return tempHashContainer;
+ }
+ else if (error == KErrNotFound)
+ {
+ // This means that the object doesn't contain our filename.
+ // Destroy the object so we can continue onto the next iteration.
+ CleanupStack::PopAndDestroy(object);
+ }
+ else
+ {
+ // If FileDescriptionL() has returned any other error, then leave.
+ User::Leave(error);
+ }
+ }
+
+ User::Leave(KErrNotFound);
+
+ // This is only to keep the compiler happy. In reality, if
+ // it cannot find the appropriate entry, then it leaves above.
+ return dummyHashContainer;
+ }
+
+void CSisRegistryCache::PackageAugmentationsL(const TUid aUid, RPointerArray<CSisRegistryPackage>& aPackages) const
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if ((iTokens[i]->Uid() == aUid) && (iTokens[i]->Index() != CSisRegistryPackage::PrimaryIndex))
+ {
+ CSisRegistryPackage* tmp = CSisRegistryPackage::NewLC(*iTokens[i]);
+ aPackages.AppendL(tmp);
+ CleanupStack::Pop(tmp);
+ }
+ }
+ }
+
+TInt CSisRegistryCache::PackageAugmentationsNumber(const TUid aUid) const
+ {
+ TInt num = 0;
+ TInt count = iTokens.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ if ((iTokens[i]->Uid() == aUid) && (iTokens[i]->Index() != CSisRegistryPackage::PrimaryIndex))
+ {
+ num++;
+ }
+ }
+ return num;
+ }
+
+void CSisRegistryCache::AddEntryL(CSisRegistryObject& aObject,
+ CIntegrityServices& aIntegrityService)
+ {
+ // set the index
+ if (aObject.InstallType() == Sis::EInstAugmentation ||
+ aObject.InstallType() == Sis::EInstPreInstalledPatch)
+ {
+ aObject.SetIndex(SisRegistryUtil::NextAvailableIndexL(iFs, aObject.Uid()));
+ }
+
+ // resolve the embedded packages index values
+ TInt embeddedIndex = 0;
+ CSisRegistryPackage* embeddedPackage = NULL;
+ while ((embeddedPackage = aObject.EmbeddedPackage(embeddedIndex++)) != NULL)
+ {
+ ResolveEmbeddedPackage(embeddedPackage);
+ }
+
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(aObject.Uid(), aObject.Index());
+
+ DEBUG_PRINTF2(_L("Sis Registry Server - Adding registry entry at location '%S'"), name);
+
+ if (aObject.InstallType() != Sis::EInstAugmentation &&
+ aObject.InstallType() != Sis::EInstPreInstalledPatch)
+ {
+ SisRegistryUtil::EnsureDirExistsL(iFs, *name);
+ }
+
+ if (UseIntegrityServices())
+ {
+ // add registry entry to integrity services log
+ aIntegrityService.AddL(*name);
+ }
+
+ // store
+ RFileWriteStream fileStream;
+ User::LeaveIfError(fileStream.Create(iFs, *name, EFileWrite | EFileShareExclusive));
+ CleanupStack::PopAndDestroy(name);
+ CleanupClosePushL(fileStream);
+
+ aObject.ExternalizeL(fileStream);
+
+ // commit and close file
+ CleanupStack::PopAndDestroy(&fileStream);
+
+ // add to token array
+ CSisRegistryToken* token = CSisRegistryToken::NewLC(aObject);
+ // initialise the token to have all drives listed marked as present
+ // (after all, we've just installed it so they must be)
+ token->SetFixedDrives(token->Drives());
+ User::LeaveIfError(iTokens.Append(token));
+ CleanupStack::Pop(token);
+ }
+
+void CSisRegistryCache::ResolveEmbeddedPackage(CSisRegistryPackage* aPackage)
+ {
+ TInt count(iTokens.Count());
+ for (TInt i = 0; i < count; ++i)
+ {
+ if (*aPackage == *iTokens[i])
+ {
+ aPackage->SetIndex(iTokens[i]->Index());
+ break;
+ }
+ }
+ }
+
+void CSisRegistryCache::RemoveEntryL(const CSisRegistryPackage& aPackage,
+ CIntegrityServices& aIntegrityService)
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ if (!(*iTokens[i] == aPackage))
+ continue;
+
+ // remove this token from the array
+ CleanupStack::PushL(iTokens[i]);
+ iTokens.Remove(i);
+ CleanupStack::PopAndDestroy(1); // iTokens[i]
+
+ // close existing file handles (if needed) before removing the file
+ CloseAllHandlesForUid(aPackage.Uid());
+ // remove the corresponding registry file
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(aPackage.Uid(), aPackage.Index());
+ aIntegrityService.RemoveL(*name);
+ CleanupStack::PopAndDestroy(name);
+
+ // as there should be only one matching entry we can return
+ break;
+ }
+ }
+
+void CSisRegistryCache::OpenReadHandleL(const CSisRegistryPackage& aPackage, TUint& aId)
+ {
+ CSisRegistryFile* fileHandler = CSisRegistryFile::NewLC(aPackage, *this);
+ iFiles.AppendL(fileHandler);
+ CleanupStack::Pop(fileHandler);
+ aId = fileHandler->SubsessionId();
+ }
+
+void CSisRegistryCache::CloseReadHandleL(TUint aId)
+ {
+ // find the entry
+ TInt i = FindReadHandleIndx(aId);
+ User::LeaveIfError(i);
+
+ CSisRegistryFile* fileHandler = iFiles[i];
+ CleanupStack::PushL(fileHandler);
+ iFiles.Remove(i);
+ CleanupStack::PopAndDestroy(fileHandler);
+ }
+
+CSisRegistryObject& CSisRegistryCache::EntryObjectL(TUint aId)
+ {
+ TInt i = FindReadHandleIndx(aId);
+
+ User::LeaveIfError(i);
+ return iFiles[i]->RegistryObject();
+ }
+
+CSisRegistryFile& CSisRegistryCache::HandleEntryL(TUint aId)
+ {
+ TInt i = FindReadHandleIndx(aId);
+
+ User::LeaveIfError(i);
+ return *iFiles[i];
+ }
+
+
+TInt CSisRegistryCache::FindReadHandleIndx(TUint aId)
+ {
+ for (TInt i=0; i<iFiles.Count(); i++)
+ {
+ if (iFiles[i]->SubsessionId() == aId)
+ {
+ return i;
+ }
+ }
+ return KErrNotFound;
+ }
+
+void CSisRegistryCache::DependentsPackagesL(
+ const CSisRegistryObject& aObject,
+ RPointerArray<CSisRegistryPackage>& aDependents
+ )
+ {
+ aDependents.ResetAndDestroy();
+ // if it is an augmentation - nothing depends on it
+ if (aObject.InstallType() == Sis::EInstAugmentation ||
+ aObject.InstallType() == Sis::EInstPreInstalledPatch)
+ {
+ return;
+ }
+
+ TUid matchingUid = aObject.Uid();
+
+ // for all entries in the list
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ // add all augmentations
+ if (iTokens[i]->Uid() == matchingUid)
+ {
+ if (iTokens[i]->Index() != CSisRegistryPackage::PrimaryIndex)
+ {
+ CSisRegistryPackage* tmp = CSisRegistryPackage::NewLC(*iTokens[i]);
+ aDependents.AppendL(tmp);
+ CleanupStack::Pop(tmp);
+ }
+ }
+ else
+ {
+ // have to open to open the file
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(iTokens[i]->Uid(), iTokens[i]->Index());
+
+ RFileReadStream stream;
+ TInt retVal = stream.Open(iFs, *name, EFileRead | EFileShareReadersOnly);
+ CleanupStack::PopAndDestroy(name);
+
+ if(retVal != KErrNone)
+ {//don't halt the process if a registry file is missing or corrupted
+ if(retVal == KErrNotFound)
+ {
+ continue;
+ }
+ else
+ {//Leave if the error is different
+ User::Leave(retVal);
+ }
+ }
+ CleanupClosePushL(stream);
+ // open entry
+ CSisRegistryObject *tmpObject = CSisRegistryObject::NewLC(stream);
+ if (tmpObject->DependsOnObject(aObject))
+ {
+ CSisRegistryPackage* tmp = CSisRegistryPackage::NewLC(*tmpObject);
+ aDependents.AppendL(tmp);
+ CleanupStack::Pop(tmp);
+ }
+ // delete entry & stream
+ CleanupStack::PopAndDestroy(2, &stream);// &stream, tmpObject
+ }
+ }
+ }
+
+void CSisRegistryCache::EmbeddingPackagesL(const CSisRegistryObject& aObject,
+ RPointerArray<CSisRegistryPackage>& aEmbeddingPackages)
+ {
+ aEmbeddingPackages.ResetAndDestroy();
+
+ TUid matchingUid = aObject.Uid();
+
+ // for all entries in the list
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(iTokens[i]->Uid(), iTokens[i]->Index());
+
+ RFileReadStream stream;
+ User::LeaveIfError(stream.Open(iFs, *name, EFileRead | EFileShareReadersOnly));
+ CleanupStack::PopAndDestroy(name);
+ CleanupClosePushL(stream);
+
+ // open entry
+ CSisRegistryObject *tmpObject = CSisRegistryObject::NewLC(stream);
+ if (tmpObject->EmbedsPackage(aObject))
+ {
+ CSisRegistryPackage* tmpPackage = CSisRegistryPackage::NewLC(*iTokens[i]) ;
+ aEmbeddingPackages.AppendL(tmpPackage);
+ CleanupStack::Pop(tmpPackage);
+ }
+ // delete entry & stream
+ CleanupStack::PopAndDestroy(2, &stream);// &stream, tmpObject
+ }
+ }
+
+void CSisRegistryCache::GenerateChainListL(const CSisRegistryObject& aObject,
+ RPointerArray<HBufC8>& aChainList)
+ {
+ aChainList.ResetAndDestroy();
+ // read the controller for every member of the list
+ for (TInt i = 0; i < aObject.ControllerInfo().Count(); i++)
+ {
+ // open every controller to extract the information
+ // construct the name using the package and offset
+ HBufC* name = SisRegistryUtil::BuildControllerFileNameLC(aObject.Uid(), aObject.Index(), aObject.ControllerInfo()[i]->Offset());
+ // open the file
+ CFileSisDataProvider* fileProvider = CFileSisDataProvider::NewLC(iFs, *name);
+ // read the controller
+ Swi::Sis::CController* controller = Swi::Sis::CController::NewLC(*fileProvider, Swi::Sis::EAssumeType);
+ // add the data to the list of certificate Chains
+ for (TInt j = 0; j < controller->SignatureCertificateChains().Count(); j++)
+ {
+ HBufC8* tmp= controller->SignatureCertificateChains()[j]->CertificateChain().Data().AllocLC();
+ aChainList.AppendL(tmp);
+ CleanupStack::Pop(tmp);
+ }
+ // release the data
+ CleanupStack::PopAndDestroy(3, name); // fileProvider, controller
+ }
+ }
+
+HBufC8* CSisRegistryCache::LoadControllerLC(const CSisRegistryObject& aObject, TUint aIndex)
+ {
+ // construct the name using the package and offset
+ HBufC* fileName = SisRegistryUtil::BuildControllerFileNameLC(aObject.Uid(), aObject.Index(), aObject.ControllerInfo()[aIndex]->Offset());
+ // open the file
+ RFile file;
+ // open file and read the data
+ User::LeaveIfError(file.Open(iFs, *fileName, EFileRead | EFileShareReadersOnly));
+ CleanupStack::PopAndDestroy(fileName);
+ CleanupClosePushL(file);
+ // read the data from the file
+ TInt fileSize;
+ User::LeaveIfError(file.Size(fileSize));
+ // create a buffer according to file size and load it with data
+ HBufC8* buffer = HBufC8::NewLC(fileSize);
+ TPtr8 ptr(buffer->Des());
+ User::LeaveIfError(file.Read(0, ptr, fileSize));
+ CleanupStack::Pop(buffer);
+ // cleanup
+ CleanupStack::PopAndDestroy(&file);
+ CleanupStack::PushL(buffer);
+ return buffer;
+ }
+
+void CSisRegistryCache::GenerateControllersArrayL(const CSisRegistryObject& aObject,
+ RPointerArray<HBufC8>& aControllers)
+ {
+ aControllers.ResetAndDestroy();
+
+ // read the controller for every member of the list
+ TInt count = aObject.ControllerInfo().Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ HBufC8* buffer = LoadControllerLC(aObject, i);
+ // add it to the list
+ aControllers.AppendL(buffer);
+ CleanupStack::Pop(buffer);
+ }
+ }
+
+void CSisRegistryCache::AddControllerL(const CSisRegistryObject& aObject,
+ CIntegrityServices& aIntegrityService,
+ const TDesC8& aBuffer, const TInt aDrive)
+ {
+ HBufC* name = SisRegistryUtil::BuildControllerFileNameLC(aObject.Uid(), aObject.Index(), aObject.ControllerInfo().Count()-1, aDrive);
+ DEBUG_PRINTF2(_L("Sis Registry Server - Installing controller file to '%S'."), name);
+
+ TEntry entry;
+ if (KErrNone == iFs.Entry(*name, entry))
+ {
+ // Remove any existing file with the same name
+ aIntegrityService.RemoveL(*name);
+ }
+
+ // add controller to integrity services log
+ aIntegrityService.AddL(*name);
+
+ // store
+ SisRegistryUtil::EnsureDirExistsL(iFs, *name);
+
+ RFileWriteStream fileStream;
+ User::LeaveIfError(fileStream.Create(iFs, *name, EFileWrite|EFileShareExclusive));
+ CleanupStack::PopAndDestroy(name);
+ CleanupClosePushL(fileStream);
+ fileStream.WriteL(aBuffer);
+
+ // commit and close file
+ CleanupStack::PopAndDestroy(&fileStream);
+
+ }
+
+void CSisRegistryCache::AddCleanupInfrastructureL(CSisRegistryObject& aObject, CIntegrityServices& aIntegrityServices, const TDesC8& aControllerBuffer)
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - Adding Cleanup Infrastructure."));
+
+ RArray<TInt> driveArray;
+ CleanupClosePushL(driveArray);
+ ControllerDriveListL(aObject, driveArray);
+ TInt driveCount(driveArray.Count());
+ for (TInt i = 0; i < driveCount; ++i)
+ {
+ TInt drive = driveArray[i];
+ // Skip drives which are not present. Note that this will only be
+ // valid for filenull operations, but we will otherwise have failed
+ // earlier in installation planning so we don't need to check
+ // the operation again.
+ TVolumeInfo volInfo;
+ if (KErrNone != iFs.Volume(volInfo, drive))
+ {
+ continue;
+ }
+
+ // Create a flagging controller on the drive in question
+ AddControllerL(aObject, aIntegrityServices, aControllerBuffer, drive);
+
+ // There is no need to create uninstall logs on the system drive; all
+ // other drives in the list should be removable.
+ // We can also skip writing uninstall logs if the object is in ROM,
+ // since uninstallation should never be possible.
+ if (drive == iSystemDrive || aObject.InRom())
+ {
+ continue;
+ }
+
+ TChar driveLetter;
+ User::LeaveIfError(iFs.DriveToChar(driveArray[i], driveLetter));
+ driveLetter.Fold();
+
+ HBufC* name = SisRegistryUtil::BuildUninstallLogPathLC(aObject.Uid(), aObject.Index(), driveLetter);
+ DEBUG_PRINTF2(_L("Sis Registry Server - Adding cleanup infrastructure uninstall log '%S'."), name);
+
+ TEntry entry;
+ if (KErrNone == iFs.Entry(*name, entry))
+ {
+ // Remove any uninstall logs with this path
+ aIntegrityServices.RemoveL(*name);
+ }
+
+ // Make sure the journal is cleaned up if we abort this install
+ aIntegrityServices.AddL(*name);
+
+ // Also cover the uninstall log path on the target drive with
+ // integrityservices.
+ TPtr namePtr(name->Des());
+ namePtr[0] = driveLetter;
+ if (KErrNone == iFs.Entry(*name, entry))
+ {
+ aIntegrityServices.RemoveL(*name);
+ }
+
+ aIntegrityServices.AddL(*name);
+
+ // Create the journal
+ TTime currentTime;
+ currentTime.UniversalTime();
+ CIntegrityServices* uninstallLog = CIntegrityServices::NewLC(currentTime.Int64(), *name);
+
+ // Register the flagging controller and any files on this drive for cleanup
+ HBufC* controller = SisRegistryUtil::BuildControllerFileNameLC(aObject.Uid(), aObject.Index(), aObject.ControllerInfo().Count()-1, drive);
+
+ uninstallLog->AddL(*controller);
+ TInt filesCount(aObject.FileDescriptions().Count());
+
+ TInt j;
+ for (j = 0; j < filesCount; ++j)
+ {
+ const TDesC& target = aObject.FileDescriptions()[j]->Target();
+ TChar targetDrive = target[0];
+ targetDrive.Fold();
+
+ if (driveLetter == targetDrive)
+ {
+ DEBUG_PRINTF2(_L("Sis Registry Server - Adding file '%S' cleanup uninstall log"), &target);
+ uninstallLog->AddL(target);
+ }
+ }
+
+ // Add any potential private paths as targets for cleanup operations
+
+ _LIT(KPrivatePath, "?:\\private\\");
+ TInt sidCount(aObject.Sids().Count());
+ RBuf privatePath;
+ privatePath.CreateL(KMaxFileName);
+ CleanupClosePushL(privatePath);
+ for (j = 0; j < sidCount; ++j)
+ {
+ privatePath = KPrivatePath;
+ privatePath[0] = driveLetter;
+ privatePath.AppendNumFixedWidthUC(aObject.Sids()[j].iUid, EHex, KUidHexLength);
+ privatePath.Append(KPathDelimiter);
+
+ DEBUG_PRINTF2(_L("Sis Registry Server - Adding (potential) private path '%S' to cleanup uninstall log"), &privatePath);
+ uninstallLog->AddL(privatePath);
+ }
+
+ CleanupStack::PopAndDestroy(4, name); //uninstallLog, controller, privatePath
+ }
+
+ CleanupStack::PopAndDestroy(&driveArray);
+
+ }
+
+void CSisRegistryCache::RemoveCleanupInfrastructureL(const CSisRegistryObject& aObject, CIntegrityServices& aIntegrityServices)
+ {
+ DEBUG_PRINTF(_L8("Sis Registry Server - Removing cleanup infrastructure."));
+
+ RArray<TInt> driveArray;
+ CleanupClosePushL(driveArray);
+ ControllerDriveListL(aObject, driveArray);
+ TInt count(driveArray.Count());
+ for (TInt i = 0; i < count; ++i)
+ {
+
+ TChar drive;
+ User::LeaveIfError(RFs::DriveToChar(driveArray[i], drive));
+
+ // Check if the drive exists before trying to do anything with it,
+ // otherwise ignore it and continue to the next drive.
+ // Also skip write-protected media for pre-installed packages.
+ // An entry registered as a preinstalled package should only have a
+ // drive in this array when it is a package installed from a removable
+ // media stub (also known as a propagation) and the swipolicy indicates
+ // that such packages are deletable.
+ TVolumeInfo volInfo;
+ if (KErrNone == iFs.Volume(volInfo, driveArray[i]) &&
+ (!aObject.PreInstalled() ||
+ !(volInfo.iDrive.iMediaAtt & KMediaAttWriteProtected)))
+ {
+
+ // remove the controller(s) for this registry entry and drive
+ if (RemoveControllerL(aObject, aIntegrityServices, driveArray[i]))
+ {
+ // if the controller was sucessfully removed
+ // remove the uninstall logs both for this drive, and the system drive
+ HBufC* name = SisRegistryUtil::BuildUninstallLogPathLC(aObject.Uid(), aObject.Index(), drive);
+
+ DEBUG_PRINTF2(_L("Sis Registry Server - Attempting to remove cleanup infrastructure uninstall log '%S'."),
+ name);
+
+ TRAPD(err, aIntegrityServices.RemoveL(*name));
+ if (err != KErrNotFound && err != KErrNone && err != KErrPathNotFound && err != KErrCorrupt)
+ {
+ DEBUG_PRINTF2(_L("Sis Registry Server - Failed to remove uninstall log (unexpected error: %d.)"), err);
+ User::Leave(err);
+ }
+
+ TPtr namePtr(name->Des());
+ namePtr[0] = drive;
+ TRAP(err, aIntegrityServices.RemoveL(*name));
+ if (err != KErrNotFound && err != KErrNone && err != KErrPathNotFound && err != KErrCorrupt)
+ {
+ User::Leave(err);
+ }
+ CleanupStack::PopAndDestroy(name);
+ }
+ }
+
+ }
+
+ CleanupStack::PopAndDestroy(&driveArray);
+
+ }
+
+TBool CSisRegistryCache::RemoveControllerL(const CSisRegistryObject& aObject,
+ CIntegrityServices& aIntegrityServices, TInt aDrive)
+ {
+ TInt count(aObject.ControllerInfo().Count());
+ TBool removed = ETrue;
+ for (TInt i = 0; i < count; i++)
+ {
+ HBufC* name = SisRegistryUtil::BuildControllerFileNameLC(aObject.Uid(), aObject.Index(), aObject.ControllerInfo()[i]->Offset(), aDrive);
+ DEBUG_PRINTF2(_L("Sis Registry Server - Removing flagging controller '%S'."), name);
+
+ TRAPD(err, aIntegrityServices.RemoveL(*name));
+ if (err != KErrNone && err != KErrNotFound && err != KErrPathNotFound && err != KErrCorrupt)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Removal of flagging controller failed (Unexpected error %d.)"), err);
+ User::Leave(err);
+ }
+ else if (err != KErrNone)
+ {
+ removed = EFalse;
+ }
+ CleanupStack::PopAndDestroy(name);
+ }
+ return removed;
+ }
+
+// creates a compacted array using a token
+void CSisRegistryCache::ControllerDriveListL(const CSisRegistryObject& aObject,
+ RArray<TInt>& aDriveList)
+ {
+ aDriveList.Reset();
+ // a copy of the controller is always kept on drive C
+ aDriveList.Append(iSystemDrive);
+
+ // only controllers will be written to removable media and
+ // we have now to check for those
+ TUint installationDrives = aObject.Drives();
+ TUint fixedDrives = FixedDrives();
+ TUint remainingDrives = installationDrives & ~fixedDrives;
+
+ if (remainingDrives)
+ {
+ TInt index = 0;
+ // reuse the path but change drive letter
+ while (remainingDrives)
+ {
+ // compare a single drive digit
+ if (remainingDrives & 0x00000001)
+ {
+ User::LeaveIfError(aDriveList.Append(index));
+ }
+ remainingDrives>>=1;
+ index++;
+ }
+ }
+ }
+
+
+void CSisRegistryCache::InitDrivesL()
+ {
+ // reset the permenant drive bitmap
+ iPermDrives = 0;
+
+ TDriveList driveList;
+ if(iFs.DriveList(driveList) != KErrNone)
+ {
+ return; // Can not get drive list so abort drive scan.
+ }
+
+ TInt err;
+ for (TInt drive = 0; drive < KMaxDrives; drive++)
+ {
+ if (driveList[drive] == 0)
+ {
+ continue;
+ }
+
+ TDriveInfo info;
+
+ // Ignore errors since the next drive might work
+ if (KErrNone != (err = iFs.Drive(info, drive)))
+ {
+ continue;
+ }
+
+ if (info.iDriveAtt & KDriveAttInternal)
+ {
+ // add it to our store of known fixed drives
+ iPermDrives |= (1 << drive);
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Fixed drive %d detected."), drive);
+ }
+ else if (info.iDriveAtt & KDriveAttRemovable)
+ {
+ // check if volume is present
+ TVolumeInfo volumeInfo;
+ err = iFs.Volume(volumeInfo, drive);
+ if (err == KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Removable drive %d detected."), drive);
+ // Find flagging controllers for non-preinstalled packages on
+ // this drive.
+ DiscoverUidsL(drive);
+ // Find stub sis files on this drive - needed for preinstalled
+ // packages which won't have flagging controllers.
+ DiscoverStubsL(drive);
+ }
+ }
+ }
+
+ TInt tokenCount(iTokens.Count());
+ for (TInt i = 0; i < tokenCount; i++)
+ {
+ iTokens[i]->SetFixedDrives(iPermDrives);
+ }
+
+
+ }
+
+void CSisRegistryCache::DiscoverUidsL(TInt aDrive)
+ {
+ TDriveUnit drive(aDrive);
+ // create directory path
+ RBuf regPath;
+ regPath.CreateL(drive.Name(), KMaxFileName);
+ CleanupClosePushL(regPath);
+ regPath.Append(KRegistryPath);
+
+ CDir* dir;
+ TInt err = iFs.GetDir(regPath, KEntryAttDir, ESortNone, dir);
+ CleanupStack::PushL(dir);
+ if(err == KErrNone)
+ {
+ TInt count(dir->Count());
+ for (TInt i = 0; i < count; ++i)
+ {
+ // want to be able to trap the failure, log it and process the next controller
+ // in this way a corrupt controler would not hog the processing
+ TRAPD(res, DiscoverControllersL(regPath, (*dir)[i].iName));
+ if (res != KErrNone)
+ {
+ // log that
+ DEBUG_PRINTF2(_L8("Sis Registry Server - DiscoverController failed with error %d."), res);
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2, ®Path); // dir
+ }
+
+TUid CSisRegistryCache::IdentifyUidFromSisFileL(TDesC& aFilename)
+ {
+ // Returns the package UID read from the symbian header in the specified
+ // file. Note that there is no check to ensure that it is a valid sisx
+ // file, but it will leave if the file is too short.
+ RFile file;
+ User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileStream));
+ CleanupClosePushL(file);
+ TUid packageUid;
+ TUid uid1;
+ TUid uid2;
+ ReadSymbianHeaderL(file, uid1, uid2, packageUid);
+ CleanupStack::PopAndDestroy(&file);
+ return packageUid;
+ }
+
+void CSisRegistryCache::DiscoverStubsL(TInt aDrive)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Attempting to discover stub sis files on drive %d"), aDrive);
+
+ // Find stub sis files on this drive, read package UIDs from files and
+ // tag this drive as present for any pre-installed packages which match
+ // the UIDs.
+ TDriveUnit drive(aDrive);
+ // create path for swidaemon's private directory.
+ RBuf stubPath;
+ stubPath.CreateL(drive.Name(), KMaxPath);
+ CleanupClosePushL(stubPath);
+ stubPath.Append(KSwiDaemonPrivateDirectory);
+
+ CDir* dir;
+ TInt err = iFs.GetDir(stubPath, KEntryAttMatchExclude | KEntryAttDir, ESortNone, dir);
+ if(err != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Reading stub directory failed (Error code: %d.)"), err);
+ CleanupStack::PopAndDestroy(&stubPath);
+ return;
+ }
+ CleanupStack::PushL(dir);
+
+ TInt count(dir->Count());
+ RBuf filename;
+ filename.CreateL(KMaxFileName);
+ CleanupClosePushL(filename);
+ for (TInt i = 0; i < count; ++i)
+ {
+ filename = stubPath;
+ filename.Append((*dir)[i].iName);
+ TUid packageUid;
+ // Trap so that invalid sisx files don't cause a problem.
+ TRAP(err, packageUid = IdentifyUidFromSisFileL(filename));
+
+ if (err != KErrNone)
+ {
+ continue;
+ }
+
+ DEBUG_PRINTF2(_L("Sis Registry Server - Identified stub '%S'."), &filename);
+ TInt tokenCount = iTokens.Count();
+ for (TInt i = 0; i < tokenCount; i++)
+ {
+ if (iTokens[i]->Uid() == packageUid)
+ {
+ // Create the object using the token we're looking at.
+ // We only want to add this drive for preinstalled
+ // apps/patches, since non-preinstalled ones should
+ // be detected by controller discovery, and this
+ // limits false positives.
+ CSisRegistryObject* object = 0;
+ TRAP(err, object = ObjectL(iTokens[i]->Uid(),
+ iTokens[i]->Name(),
+ iTokens[i]->Vendor()));
+ if(err != KErrNone)
+ {
+ continue;
+ }
+ if (object->PreInstalled())
+ {
+ iTokens[i]->AddRemovableDrive(aDrive);
+ }
+ delete object;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(3, &stubPath); // dir, filename
+ }
+
+void CSisRegistryCache::ReadSymbianHeaderL(RFile& aFile, TUid& aUid1, TUid& aUid2, TUid& aUid3)
+ {
+ // Read the first 3 32-bit values from the file as UIDs 1 to 3, leave with
+ // KErrUnderflow if the file is too short.
+ TInt uidLen = sizeof(TInt32);
+
+ TPckg<TInt32> uid1(aUid1.iUid);
+ User::LeaveIfError(aFile.Read(uid1, uidLen));
+ if (uid1.Length() != uidLen)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ TPckg<TInt32> uid2(aUid2.iUid);
+ User::LeaveIfError(aFile.Read(uid2, uidLen));
+ if (uid1.Length() != uidLen)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ TPckg<TInt32> uid3(aUid3.iUid);
+ User::LeaveIfError(aFile.Read(uid3, uidLen));
+ if (uid1.Length() != uidLen)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ }
+
+void CSisRegistryCache::DiscoverControllersL(const TDesC& aRegistryPath, const TDesC& aDirectoryName)
+ {
+ DEBUG_PRINTF2(_L("Sis Registry Server - Attempting to discover controllers we can clean up (Directory '%S')"),
+ &aDirectoryName);
+
+ // we expect uid directories to be 8 characters long, ignore others
+ if (aDirectoryName.Length() == KUidHexLength)
+ {
+ // Determine the uid from the directory name
+ TLex lex(aDirectoryName);
+ TUint uidValue;
+ User::LeaveIfError(lex.Val(uidValue, EHex));
+
+ TUid uid = TUid::Uid(uidValue);
+ RBuf controllerPath;
+ controllerPath.CreateL(aRegistryPath, KMaxFileName);
+ CleanupClosePushL(controllerPath);
+ controllerPath.Append(aDirectoryName);
+ controllerPath.Append(KPathDelimiter);
+ controllerPath.Append(KControllerFileFilter);
+
+ CDir* dir;
+ // List the directory contents, excluding directories, system and hidden files.
+ // i.e. just normal files
+ TInt err = iFs.GetDir(controllerPath, KEntryAttMatchExclude | KEntryAttDir, ESortNone, dir);
+ DEBUG_PRINTF2(_L8("Sis Registry Server - Flagging controller directory, read returned code %d."), err);
+
+ if (err == KErrNone)
+ {
+ CleanupStack::PushL(dir);
+
+ TParsePtrC parse(controllerPath);
+ RBuf filename;
+ filename.CreateL(KMaxFileName);
+ CleanupClosePushL(filename);
+
+ TInt count(dir->Count());
+ for (TInt i = 0; i < count; ++i)
+ {
+ const TEntry& entry = (*dir)[i];
+
+ // Determine the augmentation index
+ TLex parser(entry.iName);
+ TUint augmentationIndex = 0;
+ if (parser.Val(augmentationIndex, EHex) != KErrNone)
+ {
+ continue;
+ }
+
+ filename = parse.DriveAndPath();
+ filename.Append(entry.iName);
+
+ // controller present, see if is still installed on this device
+ if(IdentifyControllerL(uid, augmentationIndex, filename))
+ {
+ continue; // Controller identified, move on to next one
+ }
+ // execute the uninstall log (if present)
+ // Note: will only do nothing unless we have a corresponding
+ // uninstall log on the device indicating it was originally
+ // installed on this device.
+ HBufC* name = SisRegistryUtil::BuildUninstallLogPathLC(uid, augmentationIndex, aRegistryPath[0]);
+ TParsePtrC pathPtr(*name);
+ DEBUG_PRINTF2(_L("Sis Registry Server - App no longer on device, executing uninstall log '%S'."), name);
+
+ // use a transactionid of 0 since actual value unknown
+ CIntegrityServices* uninstallLog = CIntegrityServices::NewLC(0, pathPtr.Path());
+ uninstallLog->RollBackL(ETrue); // roll back all transactions
+ CleanupStack::PopAndDestroy(2, name); // uninstallLog
+ }
+ CleanupStack::PopAndDestroy(2, dir); // filename
+ }
+ CleanupStack::PopAndDestroy(&controllerPath);
+ }
+ }
+
+TBool CSisRegistryCache::IdentifyControllerL(TUid aUid, TInt aAugmentationIndex, const TDesC& aFileName)
+ {
+ TBool found = EFalse;
+
+ for (TInt i = 0; i < iTokens.Count() && !found; i++)
+ {
+ if (iTokens[i]->Uid() == aUid &&
+ iTokens[i]->Index() == aAugmentationIndex)
+ {
+ RFile file;
+ User::LeaveIfError(file.Open(iFs, aFileName, EFileRead | EFileShareReadersOnly));
+ CleanupClosePushL(file);
+ TInt fileSize;
+ User::LeaveIfError(file.Size(fileSize));
+ HBufC8* buffer = HBufC8::NewLC(fileSize);
+ TPtr8 ptr(buffer->Des());
+ User::LeaveIfError(file.Read(0, ptr, fileSize));
+
+ // Read the controller
+ CDesDataProvider* desProvider = CDesDataProvider::NewLC(*buffer);
+ Sis::CController* controller = Sis::CController::NewLC(*desProvider, Sis::EAssumeType);
+ CMessageDigest* msgDigest = controller->GenerateControllerHashLC(*buffer);
+ TPtrC8 hash = msgDigest->Final();
+
+ for (TInt j = 0; j < iTokens[i]->ControllerInfo().Count(); j++)
+ {
+ if (iTokens[i]->ControllerInfo()[j]->HashContainer().Data() == hash)
+ {
+ found = ETrue;
+ // if fine just update the relevant token
+ TDriveUnit drive(aFileName);
+ iTokens[i]->AddRemovableDrive(drive);
+ }
+ }
+ CleanupStack::PopAndDestroy(5, &file); // file, buffer, desProvider, controller, msgDigest
+ }
+ }
+ return found;
+ }
+
+void CSisRegistryCache::AddDriveAndRefreshL(TInt aDrive)
+ {
+ // Find flagging controllers for non-preinstalled packages on
+ // this drive.
+ DiscoverUidsL(aDrive);
+ // Find stub sis files on this drive - needed for preinstalled
+ // packages which won't have flagging controllers.
+ DiscoverStubsL(aDrive);
+ }
+
+void CSisRegistryCache::RemoveDriveAndRefresh(TInt aDrive)
+ {
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ iTokens[i]->RemoveRemovableDrive(aDrive);
+ }
+ }
+
+void CSisRegistryCache::UpdatePackagePresentStateL()
+ {
+ InitDrivesL();
+ }
+
+void CSisRegistryCache::RemoveRegistryEntryL(const CSisRegistryObject& aObject, CIntegrityServices& aIntegrityService)
+ {
+ RemoveEntryL(aObject, aIntegrityService);
+ RemoveCleanupInfrastructureL(aObject, aIntegrityService);
+ }
+
+void CSisRegistryCache::RemoveRegistryFilesL(const CSisRegistryObject& aObject, CIntegrityServices& aIntegrityService)
+ {
+ RemoveEntryL(aObject, aIntegrityService);
+ }
+
+void CSisRegistryCache::AddRegistryEntryL(CSisRegistryObject& aObject, CIntegrityServices& aIntegrityService, const TDesC8& aController)
+ {
+ AddEntryL(aObject, aIntegrityService);
+
+ // If swipolicy.ini sets false to DeletePreinstalledFilesOnUninstall
+ // we don't need to create an uninstall log because we don't want cleanup activity to happen.
+ // Just add the controller for preinstalled app in system drive.
+ if(aObject.PreInstalled() && !aObject.DeletablePreInstalled())
+ {
+ // Create a controller on system drive for preinstalled application
+ AddControllerL(aObject, aIntegrityService, aController, iSystemDrive);
+ }
+ else
+ {
+ // Add cleanup infrastructure if required
+ AddCleanupInfrastructureL(aObject, aIntegrityService, aController);
+ }
+ }
+
+void CSisRegistryCache::RegenerateCacheL()
+ {
+ CleanUp();
+
+ InitStartUpL();
+ }
+
+TUint CSisRegistryCache::UpdateTrustStatusL(const TUid& uid, const TSisTrustStatus& status )
+ {
+ CSisRegistryObject* obj = 0;
+
+ // find all file entries that hold the desired file and close them
+ CloseAllHandlesForUid(uid);
+
+ TUint id;
+
+ // load the object, doing this separately protects open sessions from intermediate changes.
+ OpenReadHandleL(PackageL(uid),id);
+ obj = &EntryObjectL(id);
+ HandleEntryL(id).ReadStream().Close();
+
+ // update the object
+ obj->SetTrustStatus(status);
+
+ // and write it to file using the rollback facilities.
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(uid, obj->Index());
+
+ TTime currentTime;
+ currentTime.UniversalTime();
+
+ CIntegrityServices* integrityServices =
+ CIntegrityServices::NewLC(currentTime.Int64(),
+ KIntegrityServicesPath);
+
+ integrityServices->RemoveL(*name);
+ integrityServices->AddL(*name);
+
+ TRAPD(err, UpdateRegistryFileL(*name, *obj));
+
+
+ if (err == KErrNone)
+ {
+ // commit file changes...
+ integrityServices->CommitL();
+ }
+ else
+ {
+ // rollback file changes and return error;
+ integrityServices->RollBackL(EFalse);
+ }
+
+ // ...and reload any open subsessions
+ ReloadAllHandlesForUidL(uid, name);
+
+ // can close the temporary file handle now the object is no longer required
+ CloseReadHandleL(id);
+
+ CleanupStack::PopAndDestroy(2, name); // integrityServices
+
+ User::LeaveIfError(err);
+
+ return KErrNone;
+ }
+
+
+void CSisRegistryCache::UpdateRegistryFileL(const TFileName& filename,
+ const CSisRegistryObject& obj)
+ {
+ RFileWriteStream writeStream;
+ CleanupClosePushL(writeStream);
+ User::LeaveIfError(writeStream.Create(iFs, filename, EFileWrite | EFileShareExclusive));
+
+ obj.ExternalizeL(writeStream);
+
+ writeStream.CommitL();
+ writeStream.Close();
+
+ CleanupStack::Pop(&writeStream);
+
+ }
+
+TBool CSisRegistryCache::IsSidPresent(const TUid aSid) const
+/**
+ Used by RSisRegistrySession::IsSidPresentL to determine
+ if the supplied SID is present in any registered package.
+
+ @param aSid Executable SID to search for.
+ @return Whether the executable with the supplied
+ SID is present in any registered package.
+ */
+ {
+ for (TInt i = iTokens.Count() - 1; i >= 0; --i)
+ {
+ if (iTokens[i]->SidPresent(aSid))
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+TUint CSisRegistryCache::SetRemoveWithLastDependentL(const TUid& uid)
+ {
+ CSisRegistryObject* obj = 0;
+
+ // find all file entries that hold the desired file and close them
+ CloseAllHandlesForUid(uid);
+
+ TUint id;
+
+ // load the object, doing this separately protects open sessions from intermediate changes.
+ OpenReadHandleL(PackageL(uid),id);
+ obj = &EntryObjectL(id);
+ HandleEntryL(id).ReadStream().Close();
+
+ // update the object
+ obj->SetRemoveWithLastDependent();
+
+ // and write it to file using the rollback facilities.
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(uid, obj->Index());
+
+ TTime currentTime;
+ currentTime.UniversalTime();
+
+ CIntegrityServices* integrityServices =
+ CIntegrityServices::NewLC(currentTime.Int64(),
+ KIntegrityServicesPath);
+
+ integrityServices->RemoveL(*name);
+ integrityServices->AddL(*name);
+
+ TRAPD(err, UpdateRegistryFileL(*name, *obj));
+
+
+ if (err == KErrNone)
+ {
+ // commit file changes...
+ integrityServices->CommitL();
+ }
+ else
+ {
+ // rollback file changes and return error;
+ integrityServices->RollBackL(EFalse);
+ }
+
+
+ // ...and reload any open subsessions
+ ReloadAllHandlesForUidL(uid, name);
+
+ // can close the temporary file handle now the object is no longer required
+ CloseReadHandleL(id);
+
+ CleanupStack::PopAndDestroy(2, name); // integrityServices
+
+ User::LeaveIfError(err);
+
+ return KErrNone;
+ }
+
+void CSisRegistryCache::UpdateLocalizedNamesL()
+ {
+ TInt count = iTokens.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ HBufC* name = SisRegistryUtil::BuildEntryFileNameLC(iTokens[i]->Uid(), iTokens[i]->Index());
+
+ RFileReadStream stream;
+ User::LeaveIfError(stream.Open(iFs, *name, EFileRead | EFileShareReadersOnly));
+ CleanupStack::PopAndDestroy(name);
+ CleanupClosePushL(stream);
+
+ // open entry
+ CSisRegistryObject *sisRegObject = CSisRegistryObject::NewLC(stream);
+ // update the localized pkg name to CSisRegistryPackage object
+ iTokens[i]->SetNameL(sisRegObject->Name());
+
+ // delete entry & stream
+ CleanupStack::PopAndDestroy(2, &stream);// &stream, sisRegObject
+ }
+ }
+//
+// Class CSisLangChangeMonitor
+//
+
+CSisRegistryCache::CSisLangChangeMonitor::~CSisLangChangeMonitor()
+ {
+ Cancel();
+ iLangNotifier.Close();
+ }
+
+CSisRegistryCache::CSisLangChangeMonitor* CSisRegistryCache::CSisLangChangeMonitor::NewL(CSisRegistryCache& aSisRegCache)
+ { // static
+ CSisLangChangeMonitor* self=new(ELeave) CSisLangChangeMonitor(aSisRegCache);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+CSisRegistryCache::CSisLangChangeMonitor::CSisLangChangeMonitor(CSisRegistryCache& aSisRegCache)
+ : CActive(EPriorityLess),
+ iSisRegistryCache(aSisRegCache)
+ {
+ iPrevLanguage = User::Language();
+ CActiveScheduler::Add(this);
+ }
+
+void CSisRegistryCache::CSisLangChangeMonitor::ConstructL()
+ {
+ User::LeaveIfError(iLangNotifier.Create());
+ Start();
+ }
+
+void CSisRegistryCache::CSisLangChangeMonitor::Start()
+ {
+ iLangNotifier.Logon(iStatus);
+ SetActive();
+ }
+
+void CSisRegistryCache::CSisLangChangeMonitor::DoCancel()
+ {
+ iLangNotifier.LogonCancel();
+ }
+
+void CSisRegistryCache::CSisLangChangeMonitor::RunL()
+ {
+ // Logon to get further events before handling current request.
+ TRequestStatus status = iStatus;
+ Start();
+
+ // if it is a language change event, start a rescan on app-list.
+ if (status.Int() == EChangesLocale && iPrevLanguage != User::Language())
+ {
+ iPrevLanguage = User::Language();
+ // Invoke API on SISRegistry to updated the information
+ // based on the current locale
+ iSisRegistryCache.UpdateLocalizedNamesL();
+ }
+ }
+
+TInt CSisRegistryCache::CSisLangChangeMonitor::RunError(TInt /*aError*/)
+ {
+ iPrevLanguage = ELangNone;
+ return KErrNone;
+ }
+
+void CSisRegistryCache::RemovablePackageListL(RPointerArray<CSisRegistryPackage>& aPackages)
+ {
+ CSisRegistryObject* obj = 0;
+ TUint id = 0;
+
+ aPackages.ResetAndDestroy();
+ for (TInt i = 0; i < iTokens.Count(); i++)
+ {
+ // load the object.
+ OpenReadHandleL(PackageL(iTokens[i]->Uid() ,iTokens[i]->Index()), id);
+ obj = &EntryObjectL(id);
+ HandleEntryL(id).ReadStream().Close();
+ if (obj->IsRemovable())
+ {
+ CSisRegistryPackage *package = CSisRegistryPackage::NewLC(*iTokens[i]);
+ aPackages.AppendL(package);
+ CleanupStack::Pop(package);
+ }
+
+ CloseReadHandleL(id);
+ }
+ }
+
+void CSisRegistryCache::RecoverL()
+ {
+ // Check to see if SWI is in use (install/uninstall/restore)
+ TInt swisState = 0;
+ User::LeaveIfError(RProperty::Get(KUidSystemCategory,KUidSoftwareInstallKey,swisState));
+
+ // Check to see if a backup is in progress...
+ TInt backup = 0;
+ User::LeaveIfError(RProperty::Get(KUidSystemCategory,conn::KUidBackupRestoreKey,backup));
+
+ if (swisState == ESwisNone && (backup == conn::EBURUnset || backup & (conn::EBURNormal | conn::ENoBackup)))
+ {
+ // Attempt to recover all previously failed installations
+ TRAP_IGNORE(iIntegrityService->RollBackL(ETrue));
+
+ if (iIntegrityService->StartedJournalRollback())
+ {
+ // At least one journal file started being rolled back. In case any
+ // registry entries were removed and then re-added, the cache must be regenerated.
+ RegenerateCacheL();
+ }
+ //Start SWI Observer so that it can process the log files left from the previous session.
+ RSwiObserverSession swiObserver;
+ swiObserver.ProcessLogsL(RFsHandle());
+ swiObserver.Close();
+ }
+ }
+
+void CSisRegistryCache::CloseAllHandlesForUid(const TUid& aUId)
+ {
+ for (TUint i = 0 ; i < iFiles.Count() ; ++i)
+ {
+ if (iFiles[i]->RegistryObject().Uid() == aUId)
+ {
+ iFiles[i]->ReadStream().Close();
+ }
+ }
+ }
+
+void CSisRegistryCache::ReloadAllHandlesForUidL(const TUid& aUId, const HBufC *aRegistryFilename)
+ {
+ for (TUint i = 0 ; i < iFiles.Count() ; ++i)
+ {
+ if (iFiles[i]->RegistryObject().Uid() == aUId)
+ {
+ iFiles[i]->ReloadL(*aRegistryFilename, *this);
+ }
+ }
+ }
+
+
+void CSisRegistryCache::AddLogEntryL(const CSisRegistryObject& aObject, TSwiLogTypes aInstallInfo)
+ {
+ CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
+ TInt numOfEntries = securityPolicy->MaxNumOfLogEntries();
+
+ if(numOfEntries)
+ {
+ CLogEntry* logObject = CLogEntry::NewL(aObject,aInstallInfo);
+ CleanupStack::PushL(logObject);
+
+ RFile file;
+ RFileWriteStream stream;
+ CleanupClosePushL(file);
+ CleanupClosePushL(stream);
+
+ HBufC* logName = SisRegistryUtil::BuildLogFileNameLC();
+
+ TInt err = file.Open(iFs,*logName,EFileRead|EFileWrite| EFileShareExclusive| EFileStream);
+ // If it's the first entry in file then append FileMajorVersion FileMinorVersion
+ // followed by package entries else log the package entries only
+ if(err == KErrNotFound)
+ {
+ User::LeaveIfError(file.Create(iFs,*logName, EFileWrite | EFileShareExclusive| EFileStream));
+ stream.Attach(file);
+ CLogFileVersion lofFileVersionObject;
+ lofFileVersionObject.ExternalizeL(stream);
+ }
+ else if( err == KErrNone )
+ {
+
+ RFileWriteStream writeStream;
+ CleanupClosePushL(writeStream);
+
+ TInt fileCount = 0;
+
+ RFileReadStream readStream(file);
+ CleanupClosePushL(readStream);
+ CLogEntry* log = NULL;
+ TInt err;
+ file.Close();
+
+ CLogFileVersion* logVer = CLogFileVersion::NewL(readStream);
+ CleanupStack::PushL(logVer);
+
+ do
+ {
+ TRAP(err,log = CLogEntry::NewL(readStream));
+ if(err == KErrEof)
+ {
+ break;
+ }
+ else if(err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ delete log;
+ ++fileCount;
+ }
+ while(err == KErrNone);
+
+ CleanupStack::PopAndDestroy(logVer);
+ readStream.Release();
+
+ //Check If the entries in log file is equal to maximum
+ //number of entries
+ if (fileCount >= numOfEntries)
+ {
+ TTime time;
+ time.HomeTime();
+ TInt64 transactionID = time.Int64();
+
+ // coverity[leave_without_push]
+ CIntegrityServices* integrityService = CIntegrityServices::NewLC(transactionID, KIntegrityServicesPath);
+
+ //Create a temporary file and read the log file in that
+ //oldest entry will be removed in the temporary log file
+ RFile tempLogFile;
+
+ TDriveUnit sysDrive(iFs.GetSystemDrive());
+ TBuf<128> tempLogName = sysDrive.Name();
+ tempLogName.Append(KTempLog);
+
+ User::LeaveIfError(tempLogFile.Replace(iFs,tempLogName,EFileWrite| EFileShareExclusive |EFileStream));
+
+ writeStream.Attach(tempLogFile);
+ TInt err = file.Open(iFs,*logName,EFileRead| EFileShareExclusive| EFileStream);
+ CleanupClosePushL(file);
+ readStream.Attach(file);
+ CLogFileVersion* logFileVersion = CLogFileVersion::NewL(readStream);
+ CleanupStack::PushL(logFileVersion);
+
+ writeStream << *logFileVersion;
+ err = 0;
+
+ for (TInt i = 0; i < fileCount; ++i)
+ {
+ TRAP(err, log = CLogEntry::NewL(readStream));
+ if(err == KErrEof)
+ {
+ break;
+ }
+ else if(err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ if(i)
+ {
+ CleanupStack::PushL(log);
+ writeStream << *log;
+ CleanupStack::PopAndDestroy(log);
+ }
+ else
+ {
+ delete log;
+ }
+ }
+ writeStream.CommitL();
+ tempLogFile.Close();
+ writeStream.Release();
+ readStream.Release();
+ CleanupStack::PopAndDestroy(2,&file);//file,logFileVersion
+
+
+ if( SisRegistryUtil::FileExistsL(iFs,*logName))
+ {
+ integrityService->RemoveL(*logName);
+ }
+ integrityService->AddL(*logName);
+
+ TInt renameErr =iFs.Rename(tempLogName,*logName);
+
+ if (renameErr == KErrNone)
+ {
+ // commit file changes...
+ integrityService->CommitL();
+ }
+ else
+ {
+ // rollback file changes and return error;
+ iFs.Delete(tempLogName);
+ integrityService->RollBackL(EFalse);
+ }
+ CleanupStack::PopAndDestroy(integrityService); //integrityService
+
+ logVer = NULL;
+ log = NULL;
+ }
+ CleanupStack::PopAndDestroy(2,&writeStream); //writeStream,readStream
+ User::LeaveIfError(file.Open(iFs,*logName,EFileRead|EFileWrite| EFileShareExclusive| EFileStream));
+ TInt pos = 0;
+ User::LeaveIfError(file.Seek(ESeekEnd, pos));
+
+ stream.Attach(file,pos);
+ }
+ else
+ {
+ User::Leave(err);
+ }
+
+ logObject->ExternalizeL(stream);
+ stream.CommitL();
+
+ CleanupStack::PopAndDestroy(4,logObject);//logObject,file,stream,logName
+ }
+ }
+
+
+_LIT( KSWVersionFileName, "Z:\\resource\\versions\\sw.txt" );
+const TInt KSysUtilVersionTextLength = 64;
+_LIT( KNewLinePattern, "\\n" );
+_LIT( KNewline, "\n" );
+/**
+Fetch text from specified files.
+Copied from /common/generic/syslibs/bafl/sysutil/src/sysutil.cpp
+*/
+static TInt GetTextFromFile(
+ const TDesC& aFilename,
+ TDes& aValue,
+ TBool aRemoveNewLines )
+ {
+ RFs fs;
+ TInt err;
+ err = fs.Connect();
+ if (err != KErrNone)
+ return err;
+
+ RFile file;
+ err = file.Open( fs, aFilename,
+ EFileRead | EFileStreamText | EFileShareReadersOnly );
+ if (err != KErrNone)
+ {
+ fs.Close();
+ return err;
+ }
+
+ TBuf8<2> characters;
+ err = file.Read(characters);
+
+ if (err == KErrNone || err == KErrTooBig)
+ {
+ // This means that we have an ANSI file (without the header bytes)
+ if( characters.Length() == 0 || characters.Length() == 1 )
+ {
+ file.Close();
+ fs.Close();
+ return KErrCorrupt;
+ }
+ else
+ {
+ TUint8 firstByte = characters[0];
+ TUint8 secondByte = characters[1];
+
+ // Heading byte values for unicode files
+ const TInt KFFByte = 255;
+ const TInt KFEByte = 254;
+
+ // If file isn't unicode KErrCorrupt is returned
+ if( (firstByte!=KFFByte && secondByte!=KFEByte) && (secondByte!=KFFByte && firstByte!=KFEByte) )
+ {
+ file.Close();
+ fs.Close();
+ return KErrCorrupt;
+ }
+ }
+ }
+
+ TFileText tf;
+ tf.Set(file);
+ err = tf.Read(aValue);
+ // If the maximum length of the descriptor is insufficient to hold the record,
+ // the Read() function returns KErrTooBig and the descriptor is filled to its maximum length.
+ //
+ // If Read() is called when the current position is the end of the file (that is, after
+ // the last line delimiter in the file), KErrEof is returned, and the length of the buffer
+ // is set to zero. In this case, this would mean an empty file, as this code always reads
+ // from the beginning of the file.
+
+ if (err == KErrNone || err == KErrTooBig)
+ {
+ if (aValue.Length() > KSysUtilVersionTextLength)
+ {
+ // File content is larger than 64 characters. Truncate to 64 characters.
+ aValue.Delete(KSysUtilVersionTextLength,aValue.Length() - KSysUtilVersionTextLength);
+ err = KErrTooBig;
+ }
+
+ if (aRemoveNewLines)
+ {
+ // Replace new-line patterns with real ones
+ TInt error = aValue.Find(KNewLinePattern);
+ while (error != KErrNotFound)
+ {
+ // error is a position
+ aValue.Replace(error, KNewLinePattern().Length(), KNewline );
+ error = aValue.Find(KNewLinePattern);
+ }
+ }
+ }
+
+ file.Close();
+ fs.Close();
+
+ return err;
+ }
+// GetSWVersion. Read sw.txt and return concatenated to single line
+// Copied from /common/generic/syslibs/bafl/sysutil/src/sysutil.cpp but without caching functionality
+static TInt GetSWVersion(TDes& aValue)
+ {
+ TInt err = GetTextFromFile( KSWVersionFileName, aValue, ETrue );
+
+
+ if ( err != KErrNone )
+ {
+ DEBUG_PRINTF3(_L8("Error: %d, while processing: %S"),err, &KSWVersionFileName);
+ }
+
+ return err;
+ }
+
+const TInt KInfoBufLength=KSysUtilVersionTextLength;
+_LIT(KROMVersionStringCacheDir, ":\\sys\\install\\sisregistry\\");
+_LIT(KROMVersionStringCacheFileName, "ROMVersionStringCache_localSysUtil.bin");
+
+
+TBool CSisRegistryCache::IsFirmwareUpdatedL()
+ {
+ TChar sysDrive = RFs::GetSystemDriveChar();
+ TInt maxSizeofFileName = KROMVersionStringCacheDir().Length() + KROMVersionStringCacheFileName().Length() + 1;
+ RBuf romVersionCacheFileName;
+ romVersionCacheFileName.CreateL(maxSizeofFileName);
+ romVersionCacheFileName.CleanupClosePushL();
+ romVersionCacheFileName.Append(sysDrive);
+ romVersionCacheFileName.Append(KROMVersionStringCacheDir());
+ romVersionCacheFileName.Append(KROMVersionStringCacheFileName());
+
+ //Read the length & value from it, if any.
+ RFileReadStream romVerStream;
+ TInt err = romVerStream.Open(iFs,romVersionCacheFileName,EFileRead);
+ if ( err != KErrNone )
+ {
+ CleanupStack::PopAndDestroy(1);
+ return ETrue;
+ }
+ CleanupClosePushL(romVerStream);
+ TBuf<KInfoBufLength> version;
+ TUint32 length = romVerStream.ReadUint32L();
+ if (length>KInfoBufLength)
+ {
+ //File must be corrupt, an attempt to read will panic
+ //User::Leave(KErrCorrupt);
+ CleanupStack::PopAndDestroy(2);
+ return ETrue;
+ }
+ romVerStream.ReadL(version, length);
+
+ //the persisted version has been successfully read
+ //read the actual current version string
+ TBuf<KInfoBufLength> actualVersion;
+
+ err = GetSWVersion(actualVersion); //use the local implementation of the SysUtil::GetSWVersion function
+
+ if(err == KErrNone)
+ {
+ if (version.Compare(actualVersion) != 0)
+ {
+ //Leave if the current version is different from the previous stored version and recreate applist.
+ DEBUG_PRINTF(_L8("!!Firmware update detected!! Rebuilding AppList"));
+ CleanupStack::PopAndDestroy(2);
+ return ETrue;
+ }
+ }
+ else
+ {
+ //Leave if any error reading the version information, except if file is not present
+ if (err != KErrPathNotFound && err != KErrNotFound)
+ {
+ DEBUG_PRINTF2(_L8("!!Error %d reading Firmware version. Rebuilding AppList"),err);
+ CleanupStack::PopAndDestroy(2);
+ return ETrue;
+ }
+ }
+ CleanupStack::PopAndDestroy(2); //romVerStream, romVersionCacheFileName
+ return EFalse;
+ }
+
+void CSisRegistryCache::UpdateRecentFWVersionL()
+ {
+ //Write a cache of the ROM version to a separate stream
+ //Build the filename for the cache file
+ TChar sysDrive = RFs::GetSystemDriveChar();
+ TInt maxSizeofFileName = KROMVersionStringCacheDir().Length() + KROMVersionStringCacheFileName().Length() + 1;
+ RBuf romVersionCacheFileName;
+ romVersionCacheFileName.CreateL(maxSizeofFileName);
+ romVersionCacheFileName.CleanupClosePushL();
+ romVersionCacheFileName.Append(sysDrive);
+ romVersionCacheFileName.Append(KROMVersionStringCacheDir());
+ romVersionCacheFileName.Append(KROMVersionStringCacheFileName());
+
+ //Read the length & value from it, if any.
+ RFileWriteStream romVerStream;
+ User::LeaveIfError(romVerStream.Replace(iFs,romVersionCacheFileName,EFileWrite));
+ CleanupClosePushL(romVerStream);
+ TBuf<KInfoBufLength> version;
+ GetSWVersion(version);
+
+ // Write even if SysUtil returns err since all conditions are taken care during restore.
+ romVerStream.WriteUint32L(version.Length());
+ romVerStream.WriteL(version);
+ CleanupStack::PopAndDestroy(2); //romVerStream, romVersionCacheFileName
+ }
+