/*
* Copyright (c) 2004-2010 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
if (iIntegrityService)
{
// 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
{
CleanupResetAndDestroyPushL(aPackages);
aPackages.ResetAndDestroy();
for (TInt i = 0; i < iTokens.Count(); i++)
{
CSisRegistryPackage *package = CSisRegistryPackage::NewLC(*iTokens[i]);
aPackages.AppendL(package);
CleanupStack::Pop(package);
}
CleanupStack::Pop(&aPackages);
}
const RPointerArray<CSisRegistryToken>& CSisRegistryCache::TokenList() const
{
return iTokens;
}
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.AppendL(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
{
CleanupClosePushL(aListMatchingPackages);
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);
}
CleanupStack::Pop(&aListMatchingPackages);
}
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
{
CleanupResetAndDestroyPushL(aPackages);
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);
}
}
CleanupStack::Pop(&aPackages);
}
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
)
{
CleanupResetAndDestroyPushL(aDependents);
aDependents.ResetAndDestroy();
// if it is an augmentation - nothing depends on it
if (aObject.InstallType() == Sis::EInstAugmentation ||
aObject.InstallType() == Sis::EInstPreInstalledPatch)
{
CleanupStack::Pop(&aDependents);
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
}
}
CleanupStack::Pop(&aDependents);
}
void CSisRegistryCache::EmbeddingPackagesL(const CSisRegistryObject& aObject,
RPointerArray<CSisRegistryPackage>& aEmbeddingPackages)
{
CleanupResetAndDestroyPushL(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
}
CleanupStack::Pop(&aEmbeddingPackages);
}
void CSisRegistryCache::GenerateChainListL(const CSisRegistryObject& aObject,
RPointerArray<HBufC8>& aChainList)
{
CleanupResetAndDestroyPushL(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
}
CleanupStack::Pop(&aChainList);
}
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)
{
CleanupResetAndDestroyPushL(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);
}
CleanupStack::Pop(&aControllers);
}
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)
{
CleanupClosePushL(aDriveList);
aDriveList.Reset();
// a copy of the controller is always kept on drive C
aDriveList.AppendL(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++;
}
}
CleanupStack::Pop(&aDriveList);
}
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;
CleanupResetAndDestroyPushL(aPackages);
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);
}
CleanupStack::Pop(&aPackages);
}
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
}