--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/appfw/apparchitecture/apserv/apsnnappupdates.cpp Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1231 @@
+// 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
+//
+// apsnnappupdates.cpp
+//
+
+#include "apsnnappupdates.h"
+
+#include <bautils.h>
+#include <f32file.h>
+#include <s32file.h>
+
+#include "APAID.H"
+#include "../aplist/aplapplistitem.h"
+#include "apsserv.h"
+#include "APSSTD.H"
+#include "../aplist/aplappregfinder.h"
+#include "../apgrfx/apprivate.h"
+#include "apsnnapps.h"
+
+
+/**************************************************************************************************************
+ * TFilePositionReset
+ **************************************************************************************************************/
+
+/**
+This class is used to ensure that a RFile's read/write position is reset to its original value
+if a leave occurs.
+
+@internalComponent
+*/
+NONSHARABLE_CLASS(TFilePositionReset)
+ {
+public:
+ TFilePositionReset(RFile& aFile) :
+ iFile(aFile),
+ iOriginalFilePosition(-1)
+ {
+ }
+
+ void RewindToStartLC()
+ {
+ TInt originalFilePosition=0;
+ User::LeaveIfError(iFile.Seek(ESeekCurrent, originalFilePosition)); // retrieves the current file-position
+ TInt newFilePosition=0;
+ User::LeaveIfError(iFile.Seek(ESeekStart, newFilePosition)); // RFile::Seek(ESeekStart,..) will not modify the TInt, but needs a reference.
+ iOriginalFilePosition=originalFilePosition;
+ CleanupStack::PushL(TCleanupItem(&StaticReset, this));
+ }
+
+ TInt Reset()
+ {
+ __ASSERT_DEBUG(iOriginalFilePosition>=0, Panic(ENonNativeAppsNegativeStoredFilePosition));
+ const TInt error = iFile.Seek(ESeekStart, iOriginalFilePosition);
+ iOriginalFilePosition=-1;
+ return error;
+ }
+
+private:
+ static void StaticReset(TAny* aThis)
+ {
+ // ignore the error code from this, we can't do anything about it
+ static_cast<TFilePositionReset*>(aThis)->Reset();
+ }
+
+private:
+ RFile& iFile;
+ TInt iOriginalFilePosition;
+ };
+
+
+/**************************************************************************************************************
+ * TFileDetails
+ **************************************************************************************************************/
+
+TFileDetails::TFileDetails() :
+ iState(EStateNull)
+ {
+ }
+
+/*
+Returns the real path, (aka the target location) of this file
+*/
+const TDesC& TFileDetails::Path()
+ {
+ __ASSERT_DEBUG(iPath != KNullDesC, Panic(ENonNativeAppsTFileDetailsPathNotSet));
+ return iPath;
+ }
+
+
+/*
+Sets the real path, (aka the target location) of this file
+*/
+void TFileDetails::SetPath(const TDesC& aPath)
+ {
+ __ASSERT_DEBUG(iPath == KNullDesC, Panic(ENonNativeAppsTFileDetailsPathAlreadySet));
+ iPath = aPath;
+ }
+
+
+/*
+Determines whether this TFileDetails has a real path set.
+If thie object doesn't have a real path set, it is assumed to not be in use
+*/
+TBool TFileDetails::Exists() const
+ {
+ return (iPath != KNullDesC);
+ }
+
+
+/*
+Releases whatever file handle is currently held, whether it is on the real file,
+temporary file, or none at all
+*/
+void TFileDetails::CloseHandle()
+ {
+ iHandle.Close();
+ }
+
+
+/*
+Opens a handle on a real file
+*/
+void TFileDetails::OpenL(RFs& aFs, const TFileName& aFileName)
+ {
+ __ASSERT_DEBUG(iState == EStateNull, Panic(ENonNativeAppsTFileDetailsOpenInBadState));
+ __ASSERT_DEBUG(iPath == KNullDesC, Panic(ENonNativeAppsTFileDetailsOpenWithRealPathSet));
+ __ASSERT_DEBUG(iTempPath == KNullDesC, Panic(ENonNativeAppsTFileDetailsOpenWithTempPathSet));
+
+ User::LeaveIfError(iHandle.Open(aFs, aFileName, EFileShareExclusive|EFileStream|EFileWrite));
+ iPath = aFileName;
+ iState = EStateReal;
+ }
+
+/*
+Creates a new, temporary file to write new data into
+Used in the preparation of a register-application update to create new resource
+and icon files before they are moved into their target locations.
+*/
+void TFileDetails::CreateTemporaryL(RFs& aFs, const TFileName& aDir)
+ {
+ __ASSERT_DEBUG(iState == EStateNull, Panic(ENonNativeAppsTFileDetailsCreateTempInBadState));
+ __ASSERT_DEBUG(iTempPath == KNullDesC, Panic(ENonNativeAppsTFileDetailsCreateTempWithTempPathSet));
+ RFile file;
+ CleanupClosePushL(file);
+ // NOTE: remove this workaround if/when RFile::Temp is fixed by base
+ TInt tempErr = KErrAlreadyExists;
+ /* RFile::Temp is a bit dodgy, at least on Winscw with the proxy FS */
+ for(TInt tries = 0; tempErr == KErrAlreadyExists && tries < 50; ++tries)
+ {
+ tempErr = file.Temp(aFs, aDir, iTempPath, EFileShareExclusive|EFileStream|EFileWrite);
+ }
+ User::LeaveIfError(tempErr);
+ CleanupStack::Pop(&file);
+ iHandle = file;
+ iState = EStateTemporary;
+ }
+
+/*
+Makes aFile a duplicates of the file handle owned by this class.
+Used to write to a file created by CreateTemporaryL()
+*/
+void TFileDetails::GetDuplicateHandleL(RFile& aFile)
+ {
+ User::LeaveIfError(aFile.Duplicate(iHandle));
+ }
+
+
+/*
+RenameToRealL
+
+Used to perform a register-appliction update
+This uses the same code as the non-leaving
+RenameToReal().
+*/
+void TFileDetails::RenameToRealL(RFs& aFs)
+ {
+ User::LeaveIfError(RenameToReal(aFs));
+ }
+
+/*
+RenameToReal
+
+Used by RenameToRealL() and RestoreReal()
+@see RenameToRealL
+@see RestoreReal
+*/
+TInt TFileDetails::RenameToReal(RFs& aFs)
+ {
+ __ASSERT_DEBUG(iState == EStateTemporary, Panic(ENonNativeAppsTFileDetailsRenameToRealInBadState));
+ __ASSERT_DEBUG(iTempPath != KNullDesC, Panic(ENonNativeAppsTFileDetailsRenameToRealWithoutTempPath));
+ __ASSERT_DEBUG(iPath != KNullDesC, Panic(ENonNativeAppsTFileDetailsRenameToRealWithoutRealPath));
+ TParse parse;
+ parse.SetNoWild(iPath,NULL,NULL);
+ if(!BaflUtils::FolderExists(aFs,parse.DriveAndPath()))
+ {
+ TInt err = aFs.MkDirAll(parse.DriveAndPath());
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ }
+ //Check if file already exists, if it exists delete it because we might be trying to register an upgrade
+ if(BaflUtils::FileExists(aFs, iPath))
+ {
+ TInt err = BaflUtils::DeleteFile(aFs, iPath);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+ }
+ TInt err = iHandle.Rename(iPath);
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ iTempPath.Zero();
+ iState = EStateReal;
+ return KErrNone;
+ }
+
+/*
+RenameToTemporaryL
+
+Used to perform a deregister-application update
+*/
+void TFileDetails::RenameToTemporaryL(RFs& aFs, const TFileName& aDir)
+ {
+ __ASSERT_DEBUG(iState == EStateReal, Panic(ENonNativeAppsTFileDetailsRenameToTempInBadState));
+ __ASSERT_DEBUG(iPath != KNullDesC, Panic(ENonNativeAppsTFileDetailsRenameToTempWithoutRealPathSet));
+ __ASSERT_DEBUG(iTempPath == KNullDesC, Panic(ENonNativeAppsTFileDetailsRenameToTempWithTempPathSet));
+ /* create a temp file and delete it to get an unused filename */
+ RFile file;
+ CleanupClosePushL(file);
+ // NOTE: remove this workaround if/when RFile::Temp is fixed by base
+ TInt tempErr = KErrAlreadyExists;
+ /* RFile::Temp is a bit dodgy, at least on Winscw with the proxy FS */
+ for(TInt tries = 0; tempErr == KErrAlreadyExists && tries < 50; ++tries)
+ {
+ tempErr = file.Temp(aFs, aDir, iTempPath, EFileShareExclusive|EFileStream|EFileWrite);
+ }
+ User::LeaveIfError(tempErr);
+ CleanupStack::PopAndDestroy(&file); // close the file handle
+ const TInt err = aFs.Delete(iTempPath);
+ if(err != KErrNone && err != KErrNotFound)
+ {
+ User::Leave(err);
+ }
+
+ User::LeaveIfError(iHandle.Rename(iTempPath));
+ iState = EStateTemporary;
+ }
+
+
+/*
+Delete
+
+Whatever the state, real or temporary, delete it.
+Used in the rollback phase of a register-application update.
+
+This function releases the handle (if any) and sets the state back to EStateNull
+*/
+TInt TFileDetails::Delete(RFs& aFs)
+ {
+ __ASSERT_DEBUG(iState == EStateNull || iState == EStateReal || iState == EStateTemporary,
+ Panic(ENonNativeAppsTFileDetailsDeleteInBadState));
+ if(iState == EStateNull)
+ {
+ return KErrNone;
+ }
+
+ iHandle.Close();
+ TInt err;
+ if(iState == EStateReal)
+ {
+ err = aFs.Delete(iPath);
+ }
+ else if(iState == EStateTemporary)
+ {
+ err = aFs.Delete(iTempPath);
+ }
+ else
+ {
+ err = KErrGeneral;
+ ASSERT(EFalse);
+ }
+ iPath.Zero();
+ iTempPath.Zero();
+ iState = EStateNull;
+ return err;
+ }
+
+
+/*
+DeleteTemporary
+
+Check that the state is EStateTemporary, and delete it.
+This function is used by the destructor of a deregister-application update
+
+This function releases the handle (if any) and sets the state back to EStateNull
+*/
+TInt TFileDetails::DeleteTemporary(RFs& aFs)
+ {
+ __ASSERT_DEBUG(iState == EStateNull || iState == EStateTemporary,
+ Panic(ENonNativeAppsTFileDetailsDeleteTemporaryInBadState));
+ if(iState == EStateNull || iState == EStateTemporary)
+ {
+ return Delete(aFs);
+ }
+ return KErrGeneral;
+ }
+
+
+/*
+RestoreReal
+
+Whatever the state, real or temporary, try to move it back to the real location.
+Used in the rollback phase of a deregister-application update.
+
+This function releases the handle (if any) and sets the state back to EStateNull
+*/
+TInt TFileDetails::RestoreReal(RFs& aFs)
+ {
+ __ASSERT_DEBUG(iState == EStateNull || iState == EStateReal || iState == EStateTemporary,
+ Panic(ENonNativeAppsTFileDetailsRestoreRealInBadState));
+ if(iState == EStateNull)
+ {
+ return KErrNone;
+ }
+
+ TInt err = KErrNone;
+ if(iState == EStateReal)
+ {
+ iHandle.Close();
+ }
+ else if(iState == EStateTemporary)
+ {
+ err = RenameToReal(aFs);
+ iHandle.Close();
+ }
+ else
+ {
+ ASSERT(EFalse);
+ }
+ iPath.Zero();
+ iTempPath.Zero();
+ iState = EStateNull;
+ return err;
+ }
+
+
+void TFileDetails::ExternalizeL(RWriteStream& aStream)
+ {
+ aStream.WriteUint8L(iState);
+ aStream.WriteUint32L(iPath.Length());
+ aStream.WriteL(iPath);
+ aStream.WriteUint32L(iTempPath.Length());
+ aStream.WriteL(iTempPath);
+ }
+
+void TFileDetails::ExternalizeContinuationL(RWriteStream& aStream, TInt aTag)
+ {
+ aStream.WriteInt8L(CApsNonNativeApplicationsUpdate::EContinuationOfUpdate);
+ aStream.WriteInt8L(aTag);
+ ExternalizeL(aStream);
+ aStream.CommitL(); // beta stopping point
+ }
+
+TInt TFileDetails::ExternalizeContinuation(RWriteStream& aStream, TInt aTag)
+ {
+ TRAPD(err,ExternalizeContinuationL(aStream,aTag));
+ return err;
+ }
+
+void TFileDetails::InternalizeL(RReadStream& aStream, TInt& aPosition)
+ {
+ TState state = static_cast<TState>(aStream.ReadUint8L());
+ TUint pathLen = aStream.ReadUint32L();
+ if(pathLen > KMaxFileName)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ TFileName path;
+ aStream.ReadL(path, pathLen);
+ TUint tempPathLen = aStream.ReadUint32L();
+ if(tempPathLen > KMaxFileName)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ TFileName tempPath;
+ aStream.ReadL(tempPath, tempPathLen);
+
+ /* all dangerous operations are now out of the way */
+ iState = state;
+ iPath = path;
+ iTempPath = tempPath;
+ // state, length, path, length, temppath
+ aPosition += sizeof(TUint8) + sizeof(TUint32) + (pathLen * sizeof(TText)) + sizeof(TUint32) + (tempPathLen * sizeof(TText));
+ }
+
+/*
+Works out what file we had a handle on when the log was written, and try to regain it.
+*/
+void TFileDetails::PostInternalizeL(RFs& aFs)
+ {
+ TInt err;
+ switch(iState)
+ {
+ case EStateNull:
+ if(iTempPath != KNullDesC)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ break;
+ case EStateTemporary:
+ if(iTempPath == KNullDesC)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ err = iHandle.Open(aFs, iTempPath, EFileShareExclusive|EFileStream|EFileWrite);
+ if(err == KErrNotFound || err == KErrPathNotFound)
+ {
+ iTempPath.Zero();
+ iPath.Zero();
+ iState = EStateNull;
+ }
+ else
+ {
+ User::LeaveIfError(err);
+ }
+ break;
+ case EStateReal:
+ if(iPath == KNullDesC)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ err = iHandle.Open(aFs, iPath, EFileShareExclusive|EFileStream|EFileWrite);
+ if(err == KErrNotFound || err == KErrPathNotFound)
+ {
+ iTempPath.Zero();
+ iPath.Zero();
+ iState = EStateNull;
+ }
+ else
+ {
+ User::LeaveIfError(err);
+ }
+ break;
+ default:
+ User::Leave(KErrCorrupt);
+ break;
+ }
+ }
+
+/**************************************************************************************************************
+ * CApsNonNativeApplicationsUpdate
+ **************************************************************************************************************/
+
+CApsNonNativeApplicationsUpdate::CApsNonNativeApplicationsUpdate(RFs& aFs, TUid aUid, TState aState, TLogUpdateType aType) :
+ iState(aState),
+ iFs(aFs),
+ iType(aType),
+ iUid(aUid)
+ {
+ }
+
+CApsNonNativeApplicationsUpdate::~CApsNonNativeApplicationsUpdate()
+ {
+ }
+
+CApsNonNativeApplicationsUpdate* CApsNonNativeApplicationsUpdate::Previous() const
+ {
+ return iPrevious;
+ }
+
+CApsNonNativeApplicationsUpdate* CApsNonNativeApplicationsUpdate::Next() const
+ {
+ return iNext;
+ }
+
+TUid CApsNonNativeApplicationsUpdate::Uid()
+ {
+ return iUid;
+ }
+
+void CApsNonNativeApplicationsUpdate::PerformUpdateL(RApsUpdateLog& aUpdateLog)
+ {
+ ASSERT(iState == ENew);
+ RWriteStream& stream = aUpdateLog.LogWriteStream();
+
+ /* NewUpdateSection */
+ stream.WriteInt8L(ENewUpdate);
+ stream.WriteInt8L(iType);
+ stream.WriteInt32L(iUid.iUid);
+ ExternalizeL(stream);
+ stream.CommitL(); // alpha stopping point
+
+ /* PerformUpdateSection */
+ stream.WriteInt8L(EPerformUpdate);
+ stream.WriteInt8L(iType);
+ stream.WriteInt32L(iUid.iUid); // beta stopping points
+ StateChangeL(EPerforming, stream); // ...
+ DoPerformUpdateL(aUpdateLog); // ...
+ StateChangeL(EPerformed, stream); // ...
+ stream.WriteInt8L(EEndOfUpdate);
+ stream.CommitL(); // alpha stopping point
+ }
+
+void CApsNonNativeApplicationsUpdate::RollbackUpdateL(RApsUpdateLog& aUpdateLog)
+ {
+ ASSERT(iState == EPerforming || iState == EPerformed || iState == ERollingBack);
+ RWriteStream& stream = aUpdateLog.LogWriteStream();
+ stream.WriteInt8L(ERollbackUpdate);
+ stream.WriteInt8L(iType);
+ stream.WriteInt32L(iUid.iUid);
+ stream.CommitL(); // beta stopping point
+ // even if we're already in ERollingBack because we crashed and are reattempting it,
+ // it's harmless to write a duplicate statechange to the log
+ StateChangeL(ERollingBack, stream); // beta stopping points
+ DoRollbackUpdate(aUpdateLog); // ...
+ StateChangeL(ERolledBack, stream); // ...
+ stream.WriteInt8L(EEndOfUpdate);
+ stream.CommitL(); // alpha stopping point
+ }
+
+TFileName CApsNonNativeApplicationsUpdate::TemporaryFilePathL(TDriveName& aDrive)
+ {
+ TFileName dir(aDrive);
+
+ // this is safe since KMaxFileName >= (KMaxDriveName + length(KLitPathForTemporaryNonNativeResourceAndIconFiles))
+ dir.Append(KLitPathForTemporaryNonNativeResourceAndIconFiles);
+
+ if(!BaflUtils::FolderExists(iFs,dir))
+ {
+ User::LeaveIfError(iFs.MkDirAll(dir));
+ }
+ return dir;
+ }
+
+void CApsNonNativeApplicationsUpdate::StateChangeL(TState aState, RWriteStream& aStream)
+ {
+ iState = aState;
+ aStream.WriteInt8L(EChangeOfUpdateState);
+ aStream.WriteInt8L(iState);
+ aStream.CommitL(); // beta stopping point
+ }
+
+void CApsNonNativeApplicationsUpdate::InternalizeStateChangeL(RReadStream& aStream, TInt& aPosition)
+ {
+ TState state = static_cast<TState>(aStream.ReadInt8L());
+ ++aPosition;
+ iState = state;
+ }
+
+void CApsNonNativeApplicationsUpdate::InternalizeNewUpdateL(RReadStream& aStream, TInt& aPosition)
+ {
+ __ASSERT_DEBUG(iState == ENeedsInternalizing, Panic(ENonNativeAppsNonNativeApplicationsUpdateInternalizeNewUpdateInBadState));
+ /*
+ internalize all member variables to how they were before any updates were performed.
+ */
+ InternalizeL(aStream, aPosition);
+
+ iState = ENew; /* the update is now OK to add to the list */
+ }
+
+void CApsNonNativeApplicationsUpdate::InternalizePerformUpdateL(RReadStream& aStream, TInt& aPosition)
+ {
+ /*
+ internalize any state changes and update-specific continuations, until EEndOfUpdate
+ */
+ SharedInternalizeLoopL(aStream, aPosition);
+ }
+
+void CApsNonNativeApplicationsUpdate::InternalizeRollbackUpdateL(RReadStream& aStream, TInt& aPosition)
+ {
+ /*
+ internalize any state changes and update-specific continuations, until EEndOfUpdate
+ */
+ SharedInternalizeLoopL(aStream, aPosition);
+ }
+
+void CApsNonNativeApplicationsUpdate::SharedInternalizeLoopL(RReadStream& aStream, TInt& aPosition)
+ {
+ while (ETrue)
+ {
+ TInt pos = aPosition;
+ TLogActionType action = static_cast<TLogActionType>(aStream.ReadInt8L());
+ pos += sizeof(TInt8);
+ /* we are at a beta stopping point at the start of each loop iteration,
+ so don't update aPosition until we have reached the end of the loop.
+ give the funcitons a copy to stop them updating aPosition direclty and
+ then leaving */
+ switch(action)
+ {
+ case EChangeOfUpdateState:
+ InternalizeStateChangeL(aStream, pos);
+ break;
+ case EContinuationOfUpdate:
+ InternalizeUpdateContinuationL(aStream, pos);
+ break;
+ case EEndOfUpdate:
+ aPosition = pos;
+ return;
+ default:
+ User::Leave(KErrCorrupt);
+ break;
+ }
+ aPosition = pos;
+ }
+ }
+
+/*
+ Default implemenation of a virtual function. does nothing.
+
+ In this method, subclasses should write out all important, subclass-specific data.
+ It will be called before DoPerformUpdateL.
+ */
+void CApsNonNativeApplicationsUpdate::ExternalizeL(RWriteStream& /*aStream*/)
+ {
+ }
+
+/*
+ Default implemenation of a virtual function. does nothing.
+
+ In this method, subclasses read in any subclass-specific data that was written out
+ by ExternalizeL().
+ */
+void CApsNonNativeApplicationsUpdate::InternalizeL(RReadStream& /*aStream*/, TInt& /*aPosition*/)
+ {
+ }
+
+/*
+ Default implemenation of a virtual function. does nothing.
+
+ In this method, subclasses should handle any EContinuationOfUpdate messages that
+ they might have written to the log during DoPerformUpdateL or DoRollbackUpdate
+ */
+void CApsNonNativeApplicationsUpdate::InternalizeUpdateContinuationL(RReadStream& /*aStream*/, TInt& /*aPosition*/)
+ {
+ }
+
+/*
+ Default implemenation of a virtual function. does nothing.
+
+ In this method, subclasses should do any internal initialization that is dependent on
+ data that may be changed by InternalizeUpdateContinuationL().
+
+ InternalizeUpdateContinuationL() may be called many times over and its implementation
+ may change the same member variable many times.
+ This function will only be called once, and it will be called after the entire log has
+ been read and InternalizeUpdateContinuationL() has been called for the last time.
+ */
+void CApsNonNativeApplicationsUpdate::PostInternalizeL()
+ {
+ }
+
+/**************************************************************************************************************
+ * CApsRegisterNonNativeApplication
+ **************************************************************************************************************/
+
+CApsRegisterNonNativeApplication* CApsRegisterNonNativeApplication::NewL(RFs& aFs, TUid aUid, const TDriveName& aDrive, TState aState)
+ {
+ return new(ELeave) CApsRegisterNonNativeApplication(aFs, aUid, aDrive, aState);
+ }
+
+CApsRegisterNonNativeApplication::CApsRegisterNonNativeApplication(RFs& aFs, TUid aUid, const TDriveName& aDrive, TState aState) :
+ CApsNonNativeApplicationsUpdate(aFs, aUid, aState, ERegisterApplication),
+ iDrive(aDrive)
+ {
+ }
+
+void CApsRegisterNonNativeApplication::SetResourceFileTargetLocation(const TDesC& aLocation)
+ {
+ iResourceFile.SetPath(aLocation);
+ }
+
+void CApsRegisterNonNativeApplication::SetLocalisableResourceFileTargetLocation(const TDesC& aLocation)
+ {
+ iLocalisableResourceFile.SetPath(aLocation);
+ }
+
+void CApsRegisterNonNativeApplication::SetIconFileTargetLocation(const TDesC& aLocation)
+ {
+ iIconFile.SetPath(aLocation);
+ }
+
+void CApsRegisterNonNativeApplication::WriteResourceFileL(const TDesC8& aData, const TDesC8* aDataPrefix)
+ {
+ WriteResourceFileL(iResourceFile, aData, aDataPrefix);
+ }
+
+void CApsRegisterNonNativeApplication::WriteLocalisableResourceFileL(const TDesC8& aData, const TDesC8* aDataPrefix)
+ {
+ WriteResourceFileL(iLocalisableResourceFile, aData, aDataPrefix);
+ }
+
+//
+
+/**
+Create a new file in a designated temporary-files directory
+*/
+void CApsRegisterNonNativeApplication::NewTemporaryFileL(TFileDetails& aFile)
+ {
+ TFileName path(TemporaryFilePathL(iDrive));
+ aFile.CreateTemporaryL(iFs,path);
+ }
+
+/**
+Writes a resource file to a new temporary file
+ */
+void CApsRegisterNonNativeApplication::WriteResourceFileL(TFileDetails& aFile, const TDesC8& aData, const TDesC8* aDataPrefix)
+ {
+ // create temp file, put stuff on the cleanup stack
+ NewTemporaryFileL(aFile);
+ RFileWriteStream targetStream;
+ CleanupClosePushL(targetStream);
+
+ // the stream takes ownership of the file handle and closes it, so make a copy
+ RFile targetFile;
+ aFile.GetDuplicateHandleL(targetFile);
+ targetStream.Attach(targetFile); // will take ownership of the handle and set targetFile to a Null handle
+
+ if (aDataPrefix!=NULL)
+ {
+ targetStream.WriteL(*aDataPrefix);
+ }
+ targetStream.WriteL(aData);
+ targetStream.CommitL();
+
+ CleanupStack::PopAndDestroy(&targetStream);
+ }
+
+/**
+This function will copy the file provided to a new temporary file.
+Upon success or failure, the read/write position of aSourceFile should remain unchanged.
+ */
+void CApsRegisterNonNativeApplication::CopyIconFileL(RFile& aSourceFile)
+ {
+ NewTemporaryFileL(iIconFile);
+
+ // RFile*Stream::Attach will take ownership of the handle we give it, but we want to hold
+ // on to the handles we have. To achieve this, we give Attach a copy of the file handle,
+ // for both streams.
+ RFileWriteStream targetStream;
+ CleanupClosePushL(targetStream);
+ RFile targetFile;
+ iIconFile.GetDuplicateHandleL(targetFile);
+ targetStream.Attach(targetFile);
+
+ // rewind to start, but restore original position if a leave occurs
+ TFilePositionReset filePositionReset(aSourceFile);
+ filePositionReset.RewindToStartLC();
+
+ RFileReadStream sourceStream;
+ CleanupClosePushL(sourceStream);
+ RFile sourceFile;
+ User::LeaveIfError(sourceFile.Duplicate(aSourceFile));
+ sourceStream.Attach(sourceFile);
+
+ targetStream.WriteL(sourceStream);
+ targetStream.CommitL();
+ CleanupStack::PopAndDestroy(&sourceStream);
+
+ // perform these seperately so we can leave if Reset fails
+ CleanupStack::Pop(&filePositionReset);
+ User::LeaveIfError(filePositionReset.Reset());
+
+ CleanupStack::PopAndDestroy(&targetStream);
+ }
+
+void CApsRegisterNonNativeApplication::DoPerformUpdateL(RApsUpdateLog& aUpdateLog)
+ {
+ TRAPD(err,aUpdateLog.DrivesAffected().InsertIsqL(iDrive, ECmpFolded));
+ if (err != KErrAlreadyExists) // We silently ignore attempts to insert duplicates
+ User::LeaveIfError(err);
+
+ RWriteStream& stream = aUpdateLog.LogWriteStream();
+
+ iResourceFile.RenameToRealL(iFs);
+
+ /* make a note of what's changed */
+ iResourceFile.ExternalizeContinuationL(stream, EResourceFileUpdate);
+
+ if(iLocalisableResourceFile.Exists())
+ {
+ iLocalisableResourceFile.RenameToRealL(iFs);
+ iResourceFile.ExternalizeContinuationL(stream, ELocalisableResourceFileUpdate);
+ }
+
+ if(iIconFile.Exists())
+ {
+ iIconFile.RenameToRealL(iFs);
+ iResourceFile.ExternalizeContinuationL(stream, EIconFileUpdate);
+ }
+
+ TRAP(err,aUpdateLog.NewRegistrationFiles().InsertIsqL(iResourceFile.Path(), ECmpFolded));
+ if (err != KErrAlreadyExists) // We silently ignore attempts to insert duplicates
+ User::LeaveIfError(err);
+ }
+
+void CApsRegisterNonNativeApplication::DoRollbackUpdate(RApsUpdateLog& aUpdateLog)
+ {
+ RWriteStream& stream = aUpdateLog.LogWriteStream();
+
+ /* TFileDetails::Delete() is safe to call whatever state the object is in.
+
+ if it was never opened, it'll do nothing, otherwise it'll delete whichever
+ file (real/temp) it has a handle on.
+
+ ignore the return codes since we can't do anything about it if they fail */
+ iResourceFile.Delete(iFs);
+ iResourceFile.ExternalizeContinuation(stream, EResourceFileUpdate);
+
+ iLocalisableResourceFile.Delete(iFs);
+ iResourceFile.ExternalizeContinuation(stream, ELocalisableResourceFileUpdate);
+
+ iIconFile.Delete(iFs);
+ iResourceFile.ExternalizeContinuation(stream, EIconFileUpdate);
+ }
+
+
+//
+
+void CApsRegisterNonNativeApplication::ExternalizeL(RWriteStream& aStream)
+ {
+ /* write our initial state to the log stream */
+ aStream.WriteUint32L(iDrive.Length());
+ aStream.WriteL(iDrive);
+ iResourceFile.ExternalizeL(aStream);
+ iLocalisableResourceFile.ExternalizeL(aStream);
+ iIconFile.ExternalizeL(aStream);
+ }
+
+void CApsRegisterNonNativeApplication::InternalizeL(RReadStream& aStream, TInt& aPosition)
+ {
+ // we can update aPosition whenever we like in this function since we're protected
+ // from it being left at a bad value by the copy taken by CApsNonNativeApplicationsUpdateList::InternalizeActionL
+ TUint driveLen = aStream.ReadUint32L();
+ aPosition += sizeof(TUint32);
+ if(driveLen > KMaxDriveName)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ iDrive.Zero();
+ aStream.ReadL(iDrive, driveLen);
+ aPosition += driveLen * sizeof(TText);
+
+ iResourceFile.InternalizeL(aStream, aPosition);
+ iLocalisableResourceFile.InternalizeL(aStream, aPosition);
+ iIconFile.InternalizeL(aStream, aPosition);
+ }
+
+void CApsRegisterNonNativeApplication::InternalizeUpdateContinuationL(RReadStream& aStream, TInt& aPosition)
+ {
+ // we can update aPosition whenever we like in this function since we're protected
+ // from it being left at a bad value by the copy taken by CApsNonNativeApplicationsUpdate::SharedInternalizeLoopL
+
+ TLogContinuationType type = static_cast<TLogContinuationType>(aStream.ReadInt8L());
+ aPosition += sizeof(TInt8);
+
+ switch(type)
+ {
+ case EResourceFileUpdate:
+ iResourceFile.InternalizeL(aStream, aPosition);
+ break;
+ case ELocalisableResourceFileUpdate:
+ iLocalisableResourceFile.InternalizeL(aStream, aPosition);
+ break;
+ case EIconFileUpdate:
+ iIconFile.InternalizeL(aStream, aPosition);
+ break;
+ default:
+ User::Leave(KErrCorrupt);
+ break;
+ }
+ }
+
+void CApsRegisterNonNativeApplication::PostInternalizeL()
+ {
+ iResourceFile.PostInternalizeL(iFs);
+ iLocalisableResourceFile.PostInternalizeL(iFs);
+ iIconFile.PostInternalizeL(iFs);
+ }
+
+CApsRegisterNonNativeApplication::~CApsRegisterNonNativeApplication()
+ {
+ /*
+ if we performed the update successfully, just close the handles and leave
+ the reg files in place.
+
+ in all other cases, just delete everything that still exists
+ */
+ if(iState == EPerformed)
+ {
+ iResourceFile.CloseHandle();
+ iLocalisableResourceFile.CloseHandle();
+ iIconFile.CloseHandle();
+ }
+ else
+ {
+ iResourceFile.Delete(iFs);
+ iLocalisableResourceFile.Delete(iFs);
+ iIconFile.Delete(iFs);
+ }
+ }
+
+
+/**************************************************************************************************************
+ * CApsDeregisterNonNativeApplication
+ **************************************************************************************************************/
+
+CApsDeregisterNonNativeApplication* CApsDeregisterNonNativeApplication::NewL(RFs& aFs, CApaAppArcServer& aServ, TUid aUid, TState aState)
+ {
+ return new(ELeave)CApsDeregisterNonNativeApplication(aFs, aServ, aUid, aState);
+ }
+
+CApsDeregisterNonNativeApplication::CApsDeregisterNonNativeApplication(RFs& aFs, CApaAppArcServer& aServ, TUid aUid, TState aState) :
+ CApsNonNativeApplicationsUpdate(aFs, aUid, aState, EDeregisterApplication),
+ iServ(aServ)
+ {
+ }
+
+//
+
+
+CApaAppData* CApsDeregisterNonNativeApplication::FindAppDataLC(RApsUpdateLog& aUpdateLog)
+ {
+ /* search back through the list for a an update concerning the same Uid */
+ CApsNonNativeApplicationsUpdate* prev = Previous();
+ while(prev != NULL)
+ {
+ if(prev->Uid() == Uid())
+ break;
+ prev = prev->Previous();
+ }
+
+ /* if none found, use apparc's app list as a shortcut */
+ CApaAppData* appData = NULL;
+ if(prev == NULL)
+ {
+ appData = iServ.AppList().AppDataByUid(Uid());
+
+ if(appData != NULL)
+ {
+ // create a new AppData so we can put it on the cleanup stack.
+ // if the NewL fails for whatever reson, fall back to the search code below
+
+ // this is a bit tricky because we need to create the appdata from a
+ // TApaAppEntry for the reg file, but using appData->AppEntry() will give us
+ // one for the dll.
+ TApaAppEntry entry;
+ entry.iFullName = appData->RegistrationFileName();
+ TEntry fsEntry;
+
+ User::LeaveIfError(iFs.Entry(entry.iFullName,fsEntry));
+ entry.iUidType = fsEntry.iType;
+
+ appData = NULL;
+ TRAP_IGNORE(appData = CApaAppData::NewL(entry,iFs));
+ if(appData != NULL)
+ {
+ CleanupStack::PushL(appData);
+ return appData;
+ }
+ }
+ }
+
+ /*
+ * If the appData wasn't found or we can't trust the app list because of previous updates,
+ * attempt to find and load the appData manually
+ */
+ CApaAppRegFinder* regFinder = CApaAppRegFinder::NewLC(iFs);
+ TBool found = EFalse;
+ TApaAppEntry appEntry;
+
+ regFinder->FindAllAppsL(CApaAppRegFinder::EScanAllDrives);
+ const CDesCArray& forcedRegs = aUpdateLog.NewRegistrationFiles();
+
+ while(regFinder->NextL(appEntry, forcedRegs))
+ {
+ if (appEntry.iUidType[2] == Uid())
+ {
+ found = ETrue;
+ break;
+ }
+ }
+ CleanupStack::PopAndDestroy(regFinder);
+
+ if(found)
+ {
+ appData = CApaAppData::NewL(appEntry, iFs);
+ CleanupStack::PushL(appData);
+ return appData;
+ }
+
+ CleanupStack::PushL(static_cast<CApaAppData*>(NULL));
+ return NULL;
+ }
+
+void CApsDeregisterNonNativeApplication::RenameToTemporaryL(TFileDetails& aFile, RApsUpdateLog& aUpdateLog)
+ {
+ /* get the drive */
+ TParse parse;
+ parse.SetNoWild(aFile.Path(), NULL, NULL);
+ if(!parse.DrivePresent())
+ {
+ // should really never happen
+ User::Leave(KErrPathNotFound);
+ }
+ TDriveName drive(parse.Drive());
+ TRAPD(err, aUpdateLog.DrivesAffected().InsertIsqL(drive, ECmpFolded));
+ if (err != KErrAlreadyExists) // We silently ignore attempts to insert duplicates
+ User::LeaveIfError(err);
+
+ const TFileName path(TemporaryFilePathL(drive));
+ aFile.RenameToTemporaryL(iFs, path);
+ }
+
+void CApsDeregisterNonNativeApplication::DoPerformUpdateL(RApsUpdateLog& aUpdateLog)
+ {
+ CApaAppData* appData = FindAppDataLC(aUpdateLog);
+ if(appData == NULL)
+ {
+ /*
+ * App not found.
+ * Behavioural backwards compatibility says we shouldn't raise an error here,
+ * instead just let it go and carry on.
+ */
+ CleanupStack::Pop(appData);
+ return;
+ }
+
+ /*
+ for each of the 3 files, open a handle on the real file if it exists
+ the first one (iResourceFile) is mandatory
+ */
+ TRAPD(err,iResourceFile.OpenL(iFs, appData->RegistrationFileName()));
+ if(err != KErrNone && err != KErrNotFound)
+ {
+ User::Leave(err);
+ }
+
+ if(appData->LocalisableResourceFileName() != KNullDesC)
+ {
+ TRAP(err,iLocalisableResourceFile.OpenL(iFs, appData->LocalisableResourceFileName()));
+ if(err != KErrNone && err != KErrNotFound)
+ {
+ User::Leave(err);
+ }
+ }
+
+ if(appData->IconFileName() != KNullDesC)
+ {
+ TRAP(err,iIconFile.OpenL(iFs, appData->IconFileName()));
+ if(err != KErrNone && err != KErrNotFound)
+ {
+ User::Leave(err);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(appData);
+
+ /*
+ perform the actual updates
+ */
+ RWriteStream& stream = aUpdateLog.LogWriteStream();
+
+ if(iIconFile.Exists())
+ {
+ RenameToTemporaryL(iIconFile, aUpdateLog);
+ iIconFile.ExternalizeContinuationL(stream, EIconFileUpdate);
+ }
+
+ if(iLocalisableResourceFile.Exists())
+ {
+ RenameToTemporaryL(iLocalisableResourceFile, aUpdateLog);
+ iLocalisableResourceFile.ExternalizeContinuationL(stream, ELocalisableResourceFileUpdate);
+ }
+
+ RenameToTemporaryL(iResourceFile, aUpdateLog);
+ iResourceFile.ExternalizeContinuationL(stream, EResourceFileUpdate);
+ }
+
+void CApsDeregisterNonNativeApplication::DoRollbackUpdate(RApsUpdateLog& aUpdateLog)
+ {
+ RWriteStream& stream = aUpdateLog.LogWriteStream();
+
+ iResourceFile.RestoreReal(iFs);
+ iResourceFile.ExternalizeContinuation(stream, EResourceFileUpdate);
+
+ iLocalisableResourceFile.RestoreReal(iFs);
+ iLocalisableResourceFile.ExternalizeContinuation(stream, ELocalisableResourceFileUpdate);
+
+ iIconFile.RestoreReal(iFs);
+ iIconFile.ExternalizeContinuation(stream, EIconFileUpdate);
+ }
+
+void CApsDeregisterNonNativeApplication::ExternalizeL(RWriteStream& aStream)
+ {
+ iResourceFile.ExternalizeL(aStream);
+ iLocalisableResourceFile.ExternalizeL(aStream);
+ iIconFile.ExternalizeL(aStream);
+ }
+
+void CApsDeregisterNonNativeApplication::InternalizeL(RReadStream& aStream, TInt& aPosition)
+ {
+ // we can update aPosition whenever we like in this function since we're protected
+ // from it being left at a bad value by the copy taken by CApsNonNativeApplicationsUpdateList::InternalizeActionL
+ iResourceFile.InternalizeL(aStream, aPosition);
+ iLocalisableResourceFile.InternalizeL(aStream, aPosition);
+ iIconFile.InternalizeL(aStream, aPosition);
+ }
+
+void CApsDeregisterNonNativeApplication::InternalizeUpdateContinuationL(RReadStream& aStream, TInt& aPosition)
+ {
+ // we can update aPosition whenever we like in this function since we're protected
+ // from it being left at a bad value by the copy taken by CApsNonNativeApplicationsUpdate::SharedInternalizeLoopL
+
+ TLogContinuationType type = static_cast<TLogContinuationType>(aStream.ReadInt8L());
+ aPosition += sizeof(TInt8);
+
+ switch(type)
+ {
+ case EResourceFileUpdate:
+ iResourceFile.InternalizeL(aStream, aPosition);
+ break;
+ case ELocalisableResourceFileUpdate:
+ iLocalisableResourceFile.InternalizeL(aStream, aPosition);
+ break;
+ case EIconFileUpdate:
+ iIconFile.InternalizeL(aStream, aPosition);
+ break;
+ default:
+ User::Leave(KErrCorrupt);
+ break;
+ }
+ }
+
+void CApsDeregisterNonNativeApplication::PostInternalizeL()
+ {
+ iResourceFile.PostInternalizeL(iFs);
+ iLocalisableResourceFile.PostInternalizeL(iFs);
+ iIconFile.PostInternalizeL(iFs);
+ }
+
+CApsDeregisterNonNativeApplication::~CApsDeregisterNonNativeApplication()
+ {
+ /*
+ if we performed the update successfully, we need to delete the temporary
+
+ in all other cases, just delete everything that still exists
+ */
+ if(iState == EPerformed)
+ {
+ // in this state we know that Perform has completed successfully.
+ iResourceFile.DeleteTemporary(iFs);
+ iLocalisableResourceFile.DeleteTemporary(iFs);
+ iIconFile.DeleteTemporary(iFs);
+ }
+ else
+ {
+ // Hopefully these are now (back) in their target locations.
+ // if they're not, there's nothing we can do now, so abandon them either way
+ iResourceFile.CloseHandle();
+ iLocalisableResourceFile.CloseHandle();
+ iIconFile.CloseHandle();
+ }
+ }
+
+#ifdef _DEBUG
+/**************************************************************************************************************
+ * CApsAlwaysFailUpdate
+ **************************************************************************************************************/
+
+CApsAlwaysFailUpdate::CApsAlwaysFailUpdate(RFs& aFs, TState aState) :
+ CApsNonNativeApplicationsUpdate(aFs,TUid::Uid(0xDEADBEEF),aState,EFail)
+ {
+ }
+
+void CApsAlwaysFailUpdate::DoPerformUpdateL(RApsUpdateLog& /*aUpdateLog*/)
+ {
+ User::Leave(KErrGeneral);
+ }
+
+/**************************************************************************************************************
+ * CApsAlwaysPanicUpdate
+ **************************************************************************************************************/
+
+CApsAlwaysPanicUpdate::CApsAlwaysPanicUpdate(RFs& aFs, TState aState) :
+ CApsNonNativeApplicationsUpdate(aFs,TUid::Uid(0xCAFEBABE),aState,EPanic)
+ {
+ }
+
+void CApsAlwaysPanicUpdate::DoPerformUpdateL(RApsUpdateLog& /*aUpdateLog*/)
+ {
+ TBool jit = User::JustInTime();
+ User::SetJustInTime(EFalse);
+ Panic(ENonNativeAppsTestHandlingPanicDuringUpdate);
+ User::SetJustInTime(jit);
+ }
+
+/**************************************************************************************************************
+ * CApsAlwaysPanicOnRollbackUpdate
+ **************************************************************************************************************/
+
+CApsAlwaysPanicOnRollbackUpdate::CApsAlwaysPanicOnRollbackUpdate(RFs& aFs, TState aState) :
+ CApsNonNativeApplicationsUpdate(aFs,TUid::Uid(0x1337D00D),aState,ERollbackPanic)
+ {
+ }
+
+void CApsAlwaysPanicOnRollbackUpdate::DoRollbackUpdate(RApsUpdateLog& /*aUpdateLog*/)
+ {
+ TBool jit = User::JustInTime();
+ User::SetJustInTime(EFalse);
+ Panic(ENonNativeAppsTestHandlingPanicDuringRollback);
+ User::SetJustInTime(jit);
+ }
+
+#endif // _DEBUG