// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).// All rights reserved.// This component and the accompanying materials are made available// under the terms of "Eclipse Public License v1.0"// which accompanies this distribution, and is available// at the URL "http://www.eclipse.org/legal/epl-v10.html".//// Initial Contributors:// Nokia Corporation - initial contribution.//// Contributors://// Description:// Non-Native application registration functionality for the AppArc server session// // apsnnapps.cpp//#include "apsnnapps.h"#include <bautils.h>#include <f32file.h>#include <s32file.h>#include "APSCLSV.H"#include "apsserv.h"#include "APSSTD.H"#include "../apgrfx/apprivate.h"#include "apsnnappupdates.h"/**KNonNativeApplicationsUpdateLog@internalComponent*/_LIT(KNonNativeApplicationsUpdateLog, ":\\private\\10003a3f\\UpdatedAppsList.bin");/************************************************************************************************************** * CApsNonNativeApplicationsUpdateList **************************************************************************************************************/CApsNonNativeApplicationsUpdateList* CApsNonNativeApplicationsUpdateList::NewL(RFs& aFs) { CApsNonNativeApplicationsUpdateList* self = new(ELeave) CApsNonNativeApplicationsUpdateList(aFs); return self; }void CApsNonNativeApplicationsUpdateList::RecoverFromUpdateLogL(RFs& aFs, RFile& aFile) { CleanupClosePushL(aFile); CApsNonNativeApplicationsUpdateList* self = new(ELeave) CApsNonNativeApplicationsUpdateList(aFs); CleanupStack::PushL(self); self->RecoverFromUpdateLogL(aFile); // consumes aFile CleanupStack::PopAndDestroy(self); CleanupStack::Pop(&aFile); }CApsNonNativeApplicationsUpdateList::CApsNonNativeApplicationsUpdateList(RFs& aFs) : iFs(aFs) { }CApsNonNativeApplicationsUpdateList::~CApsNonNativeApplicationsUpdateList() { CApsNonNativeApplicationsUpdate* update = iUpdateListHead; while(update != NULL) { CApsNonNativeApplicationsUpdate* next = update->Next(); delete update; update = next; } }void CApsNonNativeApplicationsUpdateList::RecoverFromUpdateLogL(RFile& aFile) { RFileReadStream readStream; CleanupClosePushL(readStream); RFile logFileDupe; User::LeaveIfError(logFileDupe.Duplicate(aFile)); readStream.Attach(logFileDupe); // Attach takes ownership of & Nulls the handle passed to it TInt pos = 0; InternalizeL(readStream,pos); CleanupStack::PopAndDestroy(&readStream); /* Great, we've read in all our performed updates and deleted all the ones that were fully rolled back. The next step is to roll back the rest of the updates. We'll need to create an update log as it was before the reboot, so that further rollbacks we successfully perform can also be logged in it */ // pos should point to the end of the last compelte action recorded in the file // remove any invalid or half-written actions by truncating to pos User::LeaveIfError(aFile.SetSize(pos)); RApsUpdateLog updateLog(iFs); updateLog.Open(aFile,pos); // consumes aFile CleanupClosePushL(updateLog); if(iEEndOfUpdateRequiredToFixLog) { updateLog.LogWriteStream().WriteInt8L(CApsNonNativeApplicationsUpdate::EEndOfUpdate); updateLog.LogWriteStream().CommitL(); // puts us back to an alpha stopping point } if(iLogReplayCurrentUpdate != NULL) { switch(iLogReplayCurrentUpdate->iState) { case CApsNonNativeApplicationsUpdate::ENew: /* current update was never performed. Start rollback at the previous one, which will be in EPerformed */ iLogReplayCurrentUpdate = iLogReplayCurrentUpdate->Previous(); ASSERT(iLogReplayCurrentUpdate == NULL || iLogReplayCurrentUpdate->iState == CApsNonNativeApplicationsUpdate::EPerformed); break; case CApsNonNativeApplicationsUpdate::EPerforming: case CApsNonNativeApplicationsUpdate::EPerformed: case CApsNonNativeApplicationsUpdate::ERollingBack: break; case CApsNonNativeApplicationsUpdate::ERolledBack: User::Leave(KErrCorrupt); break; } Rollback(iLogReplayCurrentUpdate, updateLog); } CleanupStack::PopAndDestroy(&updateLog); }void CApsNonNativeApplicationsUpdateList::InternalizeL(RReadStream& aStream, TInt& aPosition) { TInt err = KErrNone; while(err == KErrNone) { TRAP(err,InternalizeActionL(aStream,aPosition)); if(err == KErrNone || err == KErrCorrupt || err == KErrEof) { // We anticipate that the last update we try to read may be not complete or corrupt. // if we get either of these, jsut stop reading in the list of updates. } else { // something really unexpected, e.g. KErrNoMemory User::Leave(err); } } CApsNonNativeApplicationsUpdate* update = iUpdateListHead; while(update) { update->PostInternalizeL(); update = update->Next(); } }void CApsNonNativeApplicationsUpdateList::InternalizeActionL(RReadStream& aStream, TInt& aPosition) { TInt pos = aPosition; CApsNonNativeApplicationsUpdate::TLogActionType action = static_cast<CApsNonNativeApplicationsUpdate::TLogActionType>(aStream.ReadInt8L()); CApsNonNativeApplicationsUpdate::TLogUpdateType type = static_cast<CApsNonNativeApplicationsUpdate::TLogUpdateType>(aStream.ReadInt8L()); TUid appUid; appUid.iUid = aStream.ReadInt32L(); pos += sizeof(TInt8) + sizeof(TInt8) + sizeof(TUint32); switch(action) { case CApsNonNativeApplicationsUpdate::ENewUpdate: // for ENewUpdate, this is not a valid stopping point, // so we don't want to change aPosition unless it completes successfully. InternalizeNewUpdateL(aStream, pos, type, appUid); aPosition = pos; break; case CApsNonNativeApplicationsUpdate::EPerformUpdate: // for EPerformUpdate, this is a beta stopping point, and // InternalizePerformUpdateL will only ever update aPosition to // another stopping point, so we can give it the real aPosition. // Since it's a beta stopping point, we need to set iEEndofUpdateRequiredToFixLog iEEndOfUpdateRequiredToFixLog = ETrue; aPosition = pos; InternalizePerformUpdateL(aStream, aPosition, type, appUid); iEEndOfUpdateRequiredToFixLog = EFalse; break; case CApsNonNativeApplicationsUpdate::ERollbackUpdate: // this action has the same behaviour as EPerformUpdate iEEndOfUpdateRequiredToFixLog = ETrue; aPosition = pos; InternalizeRollbackUpdateL(aStream, aPosition, type, appUid); iEEndOfUpdateRequiredToFixLog = EFalse; break; default: User::Leave(KErrCorrupt); break; } }void CApsNonNativeApplicationsUpdateList::InternalizeNewUpdateL(RReadStream& aStream, TInt& aPosition, CApsNonNativeApplicationsUpdate::TLogUpdateType aType, TUid aUid) { // check that this is the first update or the previous update was performed completely if(iLogReplayCurrentUpdate != NULL && (iLogReplayCurrentUpdate->iState != CApsNonNativeApplicationsUpdate::EPerformed || iLogReplayCurrentUpdate->Next() != NULL)) { User::Leave(KErrCorrupt); } /* create the update object, depending on type */ CApsNonNativeApplicationsUpdate* update = NULL; switch(aType) { case CApsNonNativeApplicationsUpdate::ERegisterApplication: update = CApsRegisterNonNativeApplication::NewL(iFs, aUid, TDriveName(), CApsNonNativeApplicationsUpdate::ENeedsInternalizing); break; case CApsNonNativeApplicationsUpdate::EDeregisterApplication: update = CApsDeregisterNonNativeApplication::NewL(iFs, *CApaAppArcServer::Self(), aUid, CApsNonNativeApplicationsUpdate::ENeedsInternalizing); break;#ifdef _DEBUG case CApsNonNativeApplicationsUpdate::EFail: update = new(ELeave) CApsAlwaysFailUpdate(iFs, CApsNonNativeApplicationsUpdate::ENeedsInternalizing); break; case CApsNonNativeApplicationsUpdate::EPanic: update = new(ELeave) CApsAlwaysPanicUpdate(iFs, CApsNonNativeApplicationsUpdate::ENeedsInternalizing); break; case CApsNonNativeApplicationsUpdate::ERollbackPanic: update = new(ELeave) CApsAlwaysPanicOnRollbackUpdate(iFs, CApsNonNativeApplicationsUpdate::ENeedsInternalizing); break;#endif default: User::Leave(KErrCorrupt); break; } CleanupStack::PushL(update); update->InternalizeNewUpdateL(aStream, aPosition); CleanupStack::Pop(update); /* alpha stopping point. update->iState should be ENew now. */ Append(update); iLogReplayCurrentUpdate = update; }void CApsNonNativeApplicationsUpdateList::InternalizePerformUpdateL(RReadStream& aStream, TInt& aPosition, CApsNonNativeApplicationsUpdate::TLogUpdateType aType, TUid aUid) { if(iLogReplayCurrentUpdate == NULL || iLogReplayCurrentUpdate->iState != CApsNonNativeApplicationsUpdate::ENew) { User::Leave(KErrCorrupt); } if(iLogReplayCurrentUpdate->Uid() != aUid || iLogReplayCurrentUpdate->iType != aType) { User::Leave(KErrCorrupt); } /* tell the update to read in its log */ iLogReplayCurrentUpdate->InternalizePerformUpdateL(aStream, aPosition); // the function above will return iff EEndOfUpdate is reached }void CApsNonNativeApplicationsUpdateList::InternalizeRollbackUpdateL(RReadStream& aStream, TInt& aPosition, CApsNonNativeApplicationsUpdate::TLogUpdateType aType, TUid aUid) { if(iLogReplayCurrentUpdate == NULL) { User::Leave(KErrCorrupt); } if( iLogReplayCurrentUpdate->iState != CApsNonNativeApplicationsUpdate::EPerforming && iLogReplayCurrentUpdate->iState != CApsNonNativeApplicationsUpdate::EPerformed && iLogReplayCurrentUpdate->iState != CApsNonNativeApplicationsUpdate::ERollingBack) { User::Leave(KErrCorrupt); } if(iLogReplayCurrentUpdate->iType != aType || iLogReplayCurrentUpdate->Uid() != aUid) { User::Leave(KErrCorrupt); } iLogReplayCurrentUpdate->InternalizeRollbackUpdateL(aStream, aPosition); // the function above will return iff EEndOfUpdate is reached if(iLogReplayCurrentUpdate->iState == CApsNonNativeApplicationsUpdate::ERolledBack) { iLogReplayCurrentUpdate = iLogReplayCurrentUpdate->Previous(); } }void CApsNonNativeApplicationsUpdateList::Append(CApsNonNativeApplicationsUpdate* aUpdate) { if(iUpdateListHead == NULL) { iUpdateListHead = aUpdate; return; } CApsNonNativeApplicationsUpdate* update = iUpdateListHead; while(update->iNext != NULL) { update = update->iNext; } update->iNext = aUpdate; aUpdate->iPrevious = update; }void CApsNonNativeApplicationsUpdateList::ExecuteL() { RApsUpdateLog updateLog(iFs); updateLog.OpenL(); CleanupClosePushL(updateLog); CApsNonNativeApplicationsUpdate* update = iUpdateListHead; while(update != NULL) { TRAPD(err,update->PerformUpdateL(updateLog)); if(err == KErrNone) { update = update->Next(); } else { // call rollback on everything, including the one that failed // since it may have to clean up half-finished stuff Rollback(update, updateLog); User::Leave(err); } } CleanupStack::PopAndDestroy(&updateLog); }void CApsNonNativeApplicationsUpdateList::Rollback(CApsNonNativeApplicationsUpdate* aStartPoint, RApsUpdateLog& aUpdateLog) { CApsNonNativeApplicationsUpdate* update = aStartPoint; while(update != NULL) { TRAP_IGNORE(update->RollbackUpdateL(aUpdateLog)); update = update->Previous(); } }/**@internalComponent*/RApsUpdateLog::RApsUpdateLog(RFs& aFs) : iFs(aFs), iFilesRegistered(NULL), iDrivesAffected(NULL) { TChar drive = RFs::GetSystemDriveChar(); iLogFileName.Append(drive); iLogFileName.Append(KNonNativeApplicationsUpdateLog); }/**RApsUpdateLog::OpenLOpens a write stream to a log file that keeps track of what updates have been performed.@internalComponent*/void RApsUpdateLog::OpenL() { ASSERT(!iFilesRegistered && !iDrivesAffected); const TInt KArrayGranularity = 128; iFilesRegistered = new (ELeave) CDesCArraySeg(KArrayGranularity); iDrivesAffected = new (ELeave) CDesCArraySeg(KArrayGranularity); User::LeaveIfError(iLogWriteStream.Replace(iFs,iLogFileName,EFileShareExclusive|EFileStream|EFileWrite)); }/**RApsUpdateLog::OpenOpens a write stream to a log file that keeps track of what updates have been performed.@internalComponent*/void RApsUpdateLog::Open(RFile& aFile, TUint aSeekPos) { iLogWriteStream.Attach(aFile, aSeekPos); }/**RApsUpdateLog::CloseCleans up the list of new Registration files created during this set of updatesand deletes the log files created.@internalComponent*/void RApsUpdateLog::Close() { _LIT(KLitPathForTemporaryFiles, "\\private\\10003a3f\\temp\\"); const TInt count = (iDrivesAffected ? iDrivesAffected->Count() : 0); CFileMan* fileman = NULL; TRAPD(err, fileman = CFileMan::NewL(iFs)); if (err == KErrNone) { for(TInt i = 0; i < count; ++i) { TFileName dir((*iDrivesAffected)[i]); dir.Append(KLitPathForTemporaryNonNativeResourceAndIconFiles); fileman->RmDir(dir); // recursive iFs.RmDir(KLitPathForTemporaryFiles); // non-recursive } delete fileman; } delete iFilesRegistered; iFilesRegistered = NULL; delete iDrivesAffected; iDrivesAffected = NULL; iLogWriteStream.Close(); iFs.Delete(iLogFileName); }/**CApsNonNativeApplicationsUpdateList::RApsUpdateLog holds a list of registration files that havebeen written during this transaction. This list is used by the Deregistrationcommand as the forced-updates list.This stops them from being incorrectly hidden from the scan performed to findthe registration file to delete.@internalComponent*/CDesCArray& RApsUpdateLog::NewRegistrationFiles() { return *iFilesRegistered; }/**CApsNonNativeApplicationsUpdateList::RApsUpdateLog holds a list of drives that have been usedin the transaction. This is then used to clean up the temporary file directories@internalComponent*/CDesCArray& RApsUpdateLog::DrivesAffected() { return *iDrivesAffected; }/**Returns the stream that updates should write their recovery log data to@internalComponent*/RWriteStream& RApsUpdateLog::LogWriteStream() { return iLogWriteStream; }/************************************************************************************************************** * CApsNonNativeApplicationsManager **************************************************************************************************************/void CApsNonNativeApplicationsManager::NotifyScanComplete() { //See if the session is intrested in scan complete notification. if (!iNotifyOnScanCompleteMsg.IsNull()) { iNotifyOnScanCompleteMsg.Complete(KErrNone); } } //lint !e1762 Suppress member function could be made constCApsNonNativeApplicationsManager* CApsNonNativeApplicationsManager::NewL(CApaAppArcServer& aServ, RFs& aFs) { CApsNonNativeApplicationsManager* self = new(ELeave)CApsNonNativeApplicationsManager(aServ, aFs); return self; }CApsNonNativeApplicationsManager::~CApsNonNativeApplicationsManager() { delete iUpdateList; }CApsNonNativeApplicationsManager::CApsNonNativeApplicationsManager(CApaAppArcServer& aServ, RFs& aFs) : iServ(aServ), iFs(aFs) { }//void CApsNonNativeApplicationsManager::PrepareNonNativeApplicationsUpdatesL() { if (iServ.AppList().AppScanInProgress()) { iServ.AppList().StopScan(ETrue); //Stop updating applist now, we anyways have to update it when we are commiting these changes } if (iNonNativeApplicationsUpdateAppsLock) { User::Leave(KErrInUse); } ASSERT(iUpdateList == NULL); iUpdateList = CApsNonNativeApplicationsUpdateList::NewL(iFs); iNonNativeApplicationsUpdateAppsLock = ETrue; }void CApsNonNativeApplicationsManager::CheckForUpdateAppsLockL() { if (!iNonNativeApplicationsUpdateAppsLock) { // PrepareNonNativeApplicationsUpdatesL hasn't been called successfully User::Leave(KErrNotReady); } }// void CApsNonNativeApplicationsManager::RegisterNonNativeApplicationL(const RMessage2& aMessage) { CheckForUpdateAppsLockL(); CleanupStack::PushL(TCleanupItem(&StaticAbortNonNativeApplicationsUpdates,this)); DoRegisterNonNativeApplicationL(aMessage); CleanupStack::Pop(this); }void CApsNonNativeApplicationsManager::DoRegisterNonNativeApplicationL(const RMessage2& aMessage) { // an RBuf for creating the file names in. // create it here so it's below ipcParameter0 on the cleanup stack RBuf target; CleanupClosePushL(target); // read in the resource file from aMessage RBuf8 ipcParameter0(HBufC8::NewL(aMessage.GetDesLengthL(0))); CleanupClosePushL(ipcParameter0); aMessage.ReadL(0, ipcParameter0); if (ipcParameter0.Length()<=sizeof(SNonNativeApplicationInfo)+sizeof(TCheckedUid)) { User::Leave(KErrArgument); } // get drivename const SNonNativeApplicationInfo nonNativeApplicationInfo = *reinterpret_cast<const SNonNativeApplicationInfo*>(ipcParameter0.Ptr()); TDriveName driveName = TDriveUnit(nonNativeApplicationInfo.iDrive).Name(); // get uid const TUid applicationUid(TCheckedUid(ipcParameter0.Mid(sizeof(SNonNativeApplicationInfo), sizeof(TCheckedUid))).UidType()[2]); if (applicationUid==TUid::Null()) { User::Leave(KErrArgument); } // construct resource file name target.CreateL(driveName, KMaxFileName); target.Append(KLitPathForNonNativeResourceAndIconFiles); const TInt startOfFileName=target.Length(); // take note of this so we can chop off the file name later target.AppendFormat(KLitFormatForRegistrationResourceFile, applicationUid.iUid); // prepare registrationResourceFileDataPrefix const TUidType uidPrefix(TUid::Uid(KUidPrefixedNonNativeRegistrationResourceFile), nonNativeApplicationInfo.iApplicationType, applicationUid); const TBufC8<sizeof(TCheckedUid)> registrationResourceFileDataPrefix(TCheckedUid(uidPrefix).Des()); // create the object that will actually perform the update CApsRegisterNonNativeApplication* updateObject = CApsRegisterNonNativeApplication::NewL(iFs, applicationUid, driveName); CleanupStack::PushL(updateObject); // write resource file to temp location updateObject->SetResourceFileTargetLocation(target); updateObject->WriteResourceFileL(ipcParameter0.Mid(sizeof(SNonNativeApplicationInfo)), ®istrationResourceFileDataPrefix); if (aMessage.Int1()!=0) // if there is a localisable resource-file { RBuf8 ipcParameter1(HBufC8::NewL(User::LeaveIfError(aMessage.GetDesLength(1)))); CleanupClosePushL(ipcParameter1); aMessage.ReadL(1, ipcParameter1); // construct localisable resoure file name target.SetLength(startOfFileName); target.AppendFormat(KLitFormatForLocalisableResourceFile, applicationUid.iUid); updateObject->SetLocalisableResourceFileTargetLocation(target); // write localisable resource file to temp location updateObject->WriteLocalisableResourceFileL(ipcParameter1, NULL); CleanupStack::PopAndDestroy(&ipcParameter1); if (aMessage.Int2()!=0) // if there is an icon-file { RFile iconFile; CleanupClosePushL(iconFile); User::LeaveIfError(iconFile.AdoptFromClient(aMessage, 2, 3)); RBuf iconFileName; CleanupClosePushL(iconFileName); iconFileName.CreateL(KMaxFileName); User::LeaveIfError(iconFile.Name(iconFileName)); if (startOfFileName+iconFileName.Length()>KMaxFileName) { User::Leave(KErrArgument); } target.SetLength(startOfFileName); target.Append(iconFileName); updateObject->SetIconFileTargetLocation(target); updateObject->CopyIconFileL(iconFile); CleanupStack::PopAndDestroy(2, &iconFile); // iconFileName, iconFile } } CleanupStack::Pop(updateObject); iUpdateList->Append(updateObject); CleanupStack::PopAndDestroy(2, &target); // ipcParameter0, target }//void CApsNonNativeApplicationsManager::DeregisterNonNativeApplicationL(const RMessage2& aMessage) { CheckForUpdateAppsLockL(); CleanupStack::PushL(TCleanupItem(&StaticAbortNonNativeApplicationsUpdates,this)); const TUid applicationUid(TUid::Uid(aMessage.Int0())); iUpdateList->Append(CApsDeregisterNonNativeApplication::NewL(iFs, iServ, applicationUid)); CleanupStack::Pop(this); }//#ifdef _DEBUGvoid CApsNonNativeApplicationsManager::ForceFailInNonNativeApplicationsUpdatesL() { CheckForUpdateAppsLockL(); CleanupStack::PushL(TCleanupItem(&StaticAbortNonNativeApplicationsUpdates,this)); iUpdateList->Append(new(ELeave) CApsAlwaysFailUpdate(iFs)); CleanupStack::Pop(this); }void CApsNonNativeApplicationsManager::ForcePanicInNonNativeApplicationsUpdatesL() { CheckForUpdateAppsLockL(); CleanupStack::PushL(TCleanupItem(&StaticAbortNonNativeApplicationsUpdates,this)); iUpdateList->Append(new(ELeave) CApsAlwaysPanicUpdate(iFs)); CleanupStack::Pop(this); }void CApsNonNativeApplicationsManager::ForcePanicInNonNativeApplicationsRollbackL() { CheckForUpdateAppsLockL(); CleanupStack::PushL(TCleanupItem(&StaticAbortNonNativeApplicationsUpdates,this)); iUpdateList->Append(new(ELeave) CApsAlwaysPanicOnRollbackUpdate(iFs)); CleanupStack::Pop(this); }#endif // _DEBUG//void CApsNonNativeApplicationsManager::CommitNonNativeApplicationsUpdatesL(const RMessage2& aMessage) { CheckForUpdateAppsLockL(); TRAPD(err,iUpdateList->ExecuteL()); // Failure or success, we can't be hanging on to the lock after this function completes delete iUpdateList; iUpdateList = NULL; iNonNativeApplicationsUpdateAppsLock = EFalse; if (KErrNone != err) { if(iServ.AppList().AppListUpdatePending()) { // Trigger a rescan iServ.UpdateApps(); } User::Leave(err); // bail out at this point if things didn't go to plan } if(aMessage.Int0()==(TInt) ETrue) //The request is completed without waiting till completion application list preparation. aMessage.Complete(KErrNone); else //The request is not completed till completion application list preparation. iNotifyOnScanCompleteMsg=aMessage; // Trigger a rescan iServ.UpdateApps(); }/**This function has the word "Rollback" in it because it used to actually roll back theupdates that had been preformed but whose effects were hidden from the public APIs until commit.The real updates no longer happen until commit-time, so there's no real rolling back to be done here.The real rolling back is done automatically by iUpdateList, during the commit call, if neccessary.*/void CApsNonNativeApplicationsManager::RollbackNonNativeApplicationsUpdates() { AbortNonNativeApplicationsUpdates(); }void CApsNonNativeApplicationsManager::AbortNonNativeApplicationsUpdates() { if (!iNonNativeApplicationsUpdateAppsLock) { // It is always ok to call this function but if we haven't called PrepareNonNativeApplicationsUpdatesL() // there isn't anything to do return; } if(iServ.AppList().AppListUpdatePending()) { // Trigger a rescan iServ.UpdateApps(); } delete iUpdateList; iUpdateList = NULL; iNonNativeApplicationsUpdateAppsLock = EFalse; }void CApsNonNativeApplicationsManager::StaticAbortNonNativeApplicationsUpdates(TAny* aSelf) { static_cast<CApsNonNativeApplicationsManager*>(aSelf)->AbortNonNativeApplicationsUpdates(); }void CApsNonNativeApplicationsManager::RecoverFromUpdateLogL(RFs& aFs) { TChar drive = RFs::GetSystemDriveChar(); TFileName logPath; logPath.Append(drive); logPath.Append(KNonNativeApplicationsUpdateLog); RFile logFile; TInt err = logFile.Open(aFs,logPath,EFileShareExclusive|EFileStream|EFileWrite); if(err == KErrNotFound || err == KErrPathNotFound) { // no log file, nothing to do. return; } User::LeaveIfError(err); // this function takes over ownership of logFile TRAP(err,CApsNonNativeApplicationsUpdateList::RecoverFromUpdateLogL(aFs, logFile)); if(err != KErrNone) { // there's nothing we can do, just delete it and move on aFs.Delete(logPath); } }