--- a/installationservices/swtransactionservices/source/server/journal.cpp Tue Aug 31 15:21:33 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,646 +0,0 @@
-/*
-* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of the License "Eclipse Public License v1.0"
-* which accompanies this distribution, and is available
-* at the URL "http://www.eclipse.org/legal/epl-v10.html".
-*
-* Initial Contributors:
-* Nokia Corporation - initial contribution.
-*
-* Contributors:
-*
-* Description:
-* CJournal implementation
-*
-*/
-
-
-/**
- @file
- @released
- @internalTechnology
-*/
-
-#include "journal.h"
-#include "journalfile.h"
-#include "operationfunctions.h"
-#include "usiflog.h"
-#include <f32file.h>
-
-using namespace Usif;
-
-CJournal* CJournal::NewL(RFs& aFs, RLoader& aLoader, TStsTransactionId aTransactionID, const TDesC& aPath)
- {
- CJournal* self = CJournal::NewLC(aFs, aLoader, aTransactionID, aPath);
- CleanupStack::Pop(self);
- return self;
- }
-
-CJournal* CJournal::NewLC(RFs& aFs, RLoader& aLoader, TStsTransactionId aTransactionID, const TDesC& aPath)
- {
- CJournal* self = new(ELeave) CJournal(aFs, aLoader);
- CleanupStack::PushL(self);
- self->ConstructL(aTransactionID, aPath);
- return self;
- }
-
-CJournal::~CJournal()
- {
- iCompletedDrives.Reset();
- iAllDrives.Reset();
- iJournalFiles.ResetAndDestroy();
- }
-
-CJournal::CJournal(RFs& aFs, RLoader& aLoader) : iFs(aFs), iLoader(aLoader)
- {
- }
-
-void CJournal::ConstructL(TStsTransactionId aTransactionID, const TDesC& aPath)
- {
- // construct the generic journal filename (does not include a drive)
- CJournal::CreateJournalFileNameL(aTransactionID, aPath, iJournalFileName);
- // construct the filename for the drives journal (located on the system drive)
- CJournal::CreateDrvFileNameL(aTransactionID, aPath, iDriveArrayFileName);
- InitJournalsL();
- }
-
-void CJournal::InitJournalsL()
- {
- RefreshDrivesArrayL();
-
- // attempt to read the journals from all drives
-
- TInt drivesCount(iAllDrives.Count());
- RBuf journal;
- journal.CreateL(KMaxFileName);
- CleanupClosePushL(journal);
- for (TInt i = 0; i < drivesCount; ++i)
- {
- TDriveUnit drive(iAllDrives[i]);
- journal = drive.Name();
- journal.Append(iJournalFileName);
-
- // do not load completed drives
- if (iCompletedDrives.Find(drive) != KErrNotFound)
- {
- continue;
- }
-
- CJournalFile* journalFile = NULL;
- TRAPD(err, journalFile = CJournalFile::NewL(iFs, iLoader, journal, iAllDrives[i]));
-
- // ignore error'd drives. These will either not be rolled back,
- // or the user will find out later we can't write or commit to them.
-
- if (err == KErrNone)
- {
- CleanupStack::PushL(journalFile);
- iJournalFiles.AppendL(journalFile);
- CleanupStack::Pop(journalFile);
- }
- }
- CleanupStack::PopAndDestroy(&journal);
- }
-
-TInt CJournal::FindJournalFileIndexL(TInt aDrive) const
- {
- for(TInt index = 0; index < iJournalFiles.Count(); ++index)
- if (iJournalFiles[index]->Drive() == aDrive)
- return index;
-
- return KErrNotFound;
- }
-
-void CJournal::DeleteJournalFilesL()
- {
- // delete all journal files
- for(TInt drive = 0; drive < iJournalFiles.Count(); drive++)
- {
- DeleteJournalFileL(iJournalFiles[drive]->Drive());
- }
- iJournalFiles.ResetAndDestroy();
-
- // delete the drive array only after all journals have been completed
- // (committed or rolled back)
- if (iAllDrives.Count() == iCompletedDrives.Count())
- {
- DeleteDrivesFileL();
- }
- }
-
-void VerifyDirectoryDeletionErrorL(TInt err)
- {
- if(err != KErrNone && err != KErrNotFound && err != KErrPathNotFound && err != KErrInUse && err != KErrAccessDenied)
- {
- User::Leave(err);
- }
- }
-
-
-void CJournal::DeleteJournalFileL(TInt aDrive, TBool aRecordAllRollbackEvents /* = ETrue */)
- {
- TInt index = FindJournalFileIndexL(aDrive);
- iJournalFiles[index]->Close();
- TDriveUnit journalDrive(aDrive);
- RBuf journal;
- journal.CreateL(journalDrive.Name(), KMaxFileName);
- CleanupClosePushL(journal);
- journal.Append(iJournalFileName);
-
- User::LeaveIfError(iFs.Delete(journal));
-
- // record that we have completed this drive
- if (aRecordAllRollbackEvents)
- UpdateDrivesFileL(aDrive);
-
- iCompletedDrives.InsertInOrder(aDrive);
-
- VerifyDirectoryDeletionErrorL(iFs.RmDir(journal));
-
- CleanupStack::PopAndDestroy(&journal);
- }
-
-void CJournal::DeleteDrivesFileL()
- {
- iCompletedDrives.Reset();
- TInt err = KErrNone;
-
- err = iFs.Delete(iDriveArrayFileName);
-
- if(err != KErrNone && err != KErrPathNotFound && err != KErrNotFound)
- {
- User::Leave(err);
- }
-
- // try removing the journal path
- TParse directory;
- User::LeaveIfError(directory.SetNoWild(iDriveArrayFileName, NULL, NULL));
- while(!directory.IsRoot())
- {
- // try to remove this directory
- TInt err = iFs.RmDir(directory.DriveAndPath());
- if(err != KErrNone)
- {
- VerifyDirectoryDeletionErrorL(err);
- break;
- }
- User::LeaveIfError(directory.PopDir());
- }
- }
-
-// This function parses all the drives registered in the main drive file for this transaction.
-// This function also checks which drives have been completed.
-// As a result, two main drive sets: iCompletedDrives and iAllDrives are populated.
-void CJournal::RefreshDrivesArrayL()
- {
- // clear existing journal drive arrays prior to reloading them from file
- iCompletedDrives.Reset();
- iAllDrives.Reset();
-
- RFileReadStream journalStream;
- TInt err = journalStream.Open(iFs, iDriveArrayFileName, EFileStream);
- if (err == KErrNotFound || err == KErrPathNotFound)
- return;
- User::LeaveIfError(err);
-
- CleanupClosePushL(journalStream);
- while(ETrue)
- {
- // read the next entry in the drives' file
- TInt drive = 0;
- TRAP(err, drive = journalStream.ReadInt32L());
- if (err == KErrEof)
- break;
-
- User::LeaveIfError(err);
-
- if(iAllDrives.Find(drive) == KErrNotFound)
- {
- // first instance indicates this drive was part of this
- // transaction
- iAllDrives.InsertInOrder(drive);
- }
- else
- {
- // second instance indicates this drive has been committed
- // or rolled back
- iCompletedDrives.InsertInOrder(drive);
- }
- }
- CleanupStack::PopAndDestroy(&journalStream);
- }
-
-void CJournal::UpdateDrivesFileL(TInt aDrive)
- {
- RFile file;
- CleanupClosePushL(file);
- // try opening the file if it already exists
- TInt err = file.Open(iFs, iDriveArrayFileName, EFileWrite);
- if (err != KErrNone)
- {
- if (err == KErrNotFound || err == KErrPathNotFound)
- {
- err = iFs.MkDirAll(iDriveArrayFileName);
- if(err != KErrNone && err != KErrAlreadyExists)
- {
- User::Leave(err);
- }
- // journal does not exist, try creating one
- User::LeaveIfError(file.Create(iFs, iDriveArrayFileName, EFileWrite));
- }
- else
- {
- User::Leave(err);
- }
- }
-
- TInt fileSize;
- User::LeaveIfError(file.Size(fileSize));
-
- // attach to end of file for writing
- RFileWriteStream stream;
- stream.Attach(file, fileSize);
- CleanupStack::Pop(&file); // file ownership
- CleanupClosePushL(stream);// transfered to stream
- stream.WriteInt32L(aDrive);
- CleanupStack::PopAndDestroy(&stream);
- }
-
-void CJournal::StartCommitL()
- {
- DEBUG_PRINTF3(_L("CJournal::StartCommitL() - iJournalFileName %S iDriveArrayFileName %S"), &iJournalFileName, &iDriveArrayFileName);
- // To commit, all drives must exist. No exceptions.
- if (iJournalFiles.Count() != iAllDrives.Count())
- {
- User::Leave(KErrNotReady);
- }
-
- // none of the drives must yet be completed...
- if (iCompletedDrives.Count() != 0)
- {
- User::Leave(KErrNotSupported);
- }
-
- // synch up all the drives
- TInt drivesCount(iJournalFiles.Count());
- for (TInt i = 0; i < drivesCount; ++i)
- {
- //Check if Journal drives are present.
- TDriveInfo info;
- if (iFs.Drive(info, iJournalFiles[i]->Drive())!=KErrNone || info.iType==EMediaNotPresent)
- {
- User::Leave(KErrNotReady);
- }
- }
- }
-
-void CJournal::FinishCommitL()
- {
- DEBUG_PRINTF3(_L("CJournal::FinishCommitL() - iJournalFileName %S iDriveArrayFileName %S"), &iJournalFileName, &iDriveArrayFileName);
- DeleteJournalFilesL();
-
- // return the journal to a state where it can be used again,
- // in the insane event that someone wants to...
- // (I'm looking at you sisregistry)
- iCompletedDrives.Reset();
- iAllDrives.Reset();
- }
-
-void CJournal::FinishRollbackL(TInt aDrive, TBool aRecordAllRollbackEvents /* = ETrue */)
- {
- DEBUG_PRINTF4(_L("CJournal::FinishRollbackL() - iJournalFileName %S iDriveArrayFileName %S aDrive %d"), &iJournalFileName, &iDriveArrayFileName, aDrive);
- DeleteJournalFileL(aDrive, aRecordAllRollbackEvents);
-
- if (iCompletedDrives.Count() == iAllDrives.Count())
- {
- DeleteDrivesFileL();
- }
- }
-
-// This function verifies whether a journal exists for this drive in this transaction.
-// If it doesn't, then the journal file is created and added to iJournalFiles
-TInt CJournal::PrepareToWriteL(TInt aDrive)
- {
- TInt index = FindJournalFileIndexL(aDrive);
- if (index >= 0) // The journal already exists
- {
- return index;
- }
-
- __ASSERT_ALWAYS(index == KErrNotFound, User::Invariant());
- // The journal does not exist - we need to create one
-
- TDriveUnit drive(aDrive);
- RBuf journalPath;
- journalPath.CreateL(drive.Name(), KMaxFileName);
- CleanupClosePushL(journalPath);
- journalPath.Append(iJournalFileName);
-
- CJournalFile* journalFile = CJournalFile::NewLC(iFs, iLoader, journalPath, aDrive);
- iJournalFiles.AppendL(journalFile);
- CleanupStack::Pop(journalFile);
- CleanupStack::PopAndDestroy(&journalPath);
-
- UpdateDrivesFileL(aDrive);
-
- User::LeaveIfError(iAllDrives.InsertInOrder(aDrive));
-
- return iJournalFiles.Count() - 1; // Since we appended the entry, we return the last index
- }
-
-void CJournal::DeleteFilesL(TIntegrityServicesEvent aTypeFilter)
- {
- TInt journalsCount(iJournalFiles.Count());
- for (TInt i = 0; i < journalsCount; ++i)
- {
- iJournalFiles[i]->JournalOperationL(IntegrityDeleteFileL, aTypeFilter, CIntegrityServices::EFailDeletingFile);
- }
- }
-
-void CJournal::RestoreFilesL(TInt aDrive)
- {
- TInt index = FindJournalFileIndexL(aDrive);
- User::LeaveIfError(index);
- iJournalFiles[index]->JournalOperationL(IntegrityRestoreFileL, ERemovedFile, CIntegrityServices::EFailRestoringFile);
- }
-
-void CJournal::DeleteFilesL(TIntegrityServicesEvent aTypeFilter, TInt aDrive)
- {
- TInt index = FindJournalFileIndexL(aDrive);
- User::LeaveIfError(index);
- iJournalFiles[index]->JournalOperationL(IntegrityDeleteFileL, aTypeFilter, CIntegrityServices::EFailDeletingFile);
- }
-
-void CJournal::WriteJournalEventL(TIntegrityServicesEvent aEvent)
- {
- // write the event to each journal file
- for(TInt index = 0; index < iJournalFiles.Count(); index++)
- {
- iJournalFiles[index]->EventL(aEvent);
- }
- }
-
-void CJournal::WriteJournalEventL(TIntegrityServicesEvent aEvent, TInt aDrive, TBool aSerializeEventToJournal)
- {
- TInt index = FindJournalFileIndexL(aDrive);
- User::LeaveIfError(index);
- iJournalFiles[index]->EventL(aEvent, aSerializeEventToJournal);
- }
-
-void CJournal::AddL(const TDesC& aFileName)
- {
- DEBUG_PRINTF2(_L("CJournal::AddL() - aFileName %S"), &aFileName);
- // write the filename to the journal on the same drive
- TInt drive = CJournalFile::CheckFileNameL(iFs, aFileName);
- TInt index = PrepareToWriteL(drive);
- iJournalFiles[index]->AddL(aFileName);
- }
-
-void CJournal::RemoveL(const TDesC& aFileName, TDes& backupFileName)
- {
- DEBUG_PRINTF2(_L("CJournal::RemoveL() - aFileName %S"), &aFileName);
- // write the filename to the journal on the same drive
- TInt drive = CJournalFile::CheckFileNameL(iFs, aFileName);
- TInt index = PrepareToWriteL(drive);
- iJournalFiles[index]->RemoveL(aFileName, backupFileName);
- }
-
-void CJournal::TemporaryL(const TDesC& aFileName)
- {
- DEBUG_PRINTF2(_L("CJournal::TemporaryL() - aFileName %S"), &aFileName);
- // write the filename to the journal on the same drive
- TInt drive = CJournalFile::CheckFileNameL(iFs, aFileName);
- TInt index = PrepareToWriteL(drive);
- iJournalFiles[index]->TemporaryL(aFileName);
- }
-
-TIntegrityServicesEvent CJournal::LastEventL() const
- {
- TIntegrityServicesEvent lastEvent = ENone;
- // work out the "real" last event
- // journals states may be at different since they cannot all be written
- // to simultaneously
- for(TInt index = 0; index < iJournalFiles.Count(); index++)
- {
- TInt position = iCompletedDrives.Find(iJournalFiles[index]->Drive());
-
- if(position!=KErrNotFound)
- continue; //don't check completed drives
-
- TIntegrityServicesEvent currentJournalLastEvent = iJournalFiles[index]->LastEvent();
- if (currentJournalLastEvent >= lastEvent)
- lastEvent = currentJournalLastEvent;
- }//for
- return lastEvent;
- }
-
-TIntegrityServicesEvent CJournal::LastEventL(TInt aDrive) const
- {
- DEBUG_PRINTF2(_L("CJournal::LastEventL() - aDrive %d"), aDrive);
- TInt index = FindJournalFileIndexL(aDrive);
- User::LeaveIfError(index);
-
- return iJournalFiles[index]->LastEvent();
- }
-
-/*static*/ void CJournal::CreateDrvFileNameL(TStsTransactionId aTransactionID, const TDesC& aPath, TDes& aDrvFileName)
- {
- DEBUG_PRINTF3(_L("CJournal::CreateDrvFileNameL() - aTransactionID %X aPath %S"), aTransactionID, &aPath);
- aDrvFileName = TDriveUnit(::RFs::GetSystemDrive()).Name();
- aDrvFileName.Append(aPath);
- aDrvFileName.AppendNumUC(static_cast<TUint32>(aTransactionID), EHex);
- aDrvFileName.Append(KExtDelimiter);
- aDrvFileName.Append(KDriveExt);
- }
-
-/*static*/ void CJournal::CreateJournalFileNameL(TStsTransactionId aTransactionID, const TDesC& aPath, TDes& aJournalFileName)
- {
- aJournalFileName.Append(aPath);
- aJournalFileName.AppendNumUC(static_cast<TUint32>(aTransactionID), EHex);
- aJournalFileName.Append(KExtDelimiter);
- aJournalFileName.Append(KJournalExt);
- }
-
-/*static*/ TInt CJournal::RecoverTransactionIdFromDrvFileName(const TDesC& aDrvFileName, TStsTransactionId& aTransactionID)
- {
- TLex lex(aDrvFileName);
- TUint32 tmp;
- TInt result = lex.Val(tmp, EHex);
- aTransactionID = static_cast<TStsTransactionId>(tmp);
- return result;
- }
-
-void CJournal::RollBackDriveL(TInt aDrive, TBool aRecordAllRollbackEvents)
- {
- switch (LastEventL())
- {
- // Transaction did not complete, rollback required
- case ERemovedFile:
- case EBackupFile:
- case ETempFile:
- case EAddedFile:
- case EAddedFilesRemoved:
- case ERemovedFilesRestored:
- // rollback this individual journal from where it last got to.
- switch (LastEventL(aDrive))
- {
- case ERemovedFile:
- case EBackupFile:
- case ETempFile:
- case EAddedFile:
- DeleteFilesL(EAddedFile, aDrive);
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailNewFilesRemoved, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(EAddedFilesRemoved, aDrive, aRecordAllRollbackEvents);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailNewFilesRemoved, CIntegrityServices::EAfterJournal, KNullDesC);
-
- // fall-through - automatically proceed to the next state, we'll start from EAddedFilesRemoved in case the RestoreFileL has failed
- case EAddedFilesRemoved:
- RestoreFilesL(aDrive);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailOldFilesRestored, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(ERemovedFilesRestored, aDrive, aRecordAllRollbackEvents);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailOldFilesRestored, CIntegrityServices::EAfterJournal, KNullDesC);
-
- // fall-through - automatically proceed to the next state
- case ERemovedFilesRestored:
- DeleteFilesL(ETempFile, aDrive);
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailTempFilesRemoved, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(ETempFilesRemoved, aDrive, aRecordAllRollbackEvents);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailTempFilesRemoved, CIntegrityServices::EAfterJournal, KNullDesC);
- break;
-
- case ETempFilesRemoved:
- break;
-
- // nothing was done, just delete the journal file
- case ENone:
- break;
-
- // Erk! Bad state, bad state!
- default:
- User::Leave(KErrCorrupt);
- break;
- }
- break;
-
- // Transaction complete, just need to remove the backup
- case ECommitted:
- case EBackupFilesRemoved:
- switch (LastEventL(aDrive))
- {
- // At least one journal had a complete transaction...
- // roll forwards all journal files.
- case ERemovedFile:
- case EBackupFile:
- case ETempFile:
- case EAddedFile:
- case ECommitted:
- DeleteFilesL(EBackupFile, aDrive);
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailBackupFilesRemoved, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(EBackupFilesRemoved, aDrive, aRecordAllRollbackEvents);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailBackupFilesRemoved, CIntegrityServices::EAfterJournal, KNullDesC);
-
- //fall-through - automatically proceed to the next state
- case EBackupFilesRemoved:
- DeleteFilesL(ETempFile, aDrive);
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailTempFilesRemoved, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(ETempFilesRemoved, aDrive, aRecordAllRollbackEvents);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailTempFilesRemoved, CIntegrityServices::EAfterJournal, KNullDesC);
- break;
-
- case ETempFilesRemoved:
- break;
-
- // nothing was done, just delete the journal file
- case ENone:
- break;
-
- // unknown state
- default:
- User::Leave(KErrCorrupt);
- break;
- }
- break;
-
- case ETempFilesRemoved:
- break;
-
- // nothing was done, just delete the journal file
- case ENone:
- break;
-
- // unknown state
- default:
- User::Leave(KErrCorrupt);
- break;
- }
-
- FinishRollbackL(aDrive, aRecordAllRollbackEvents);
- }
-
-void CJournal::CommitL()
- {
- StartCommitL();
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailInstallComplete, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(ECommitted);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailInstallComplete, CIntegrityServices::EAfterJournal, KNullDesC);
-
- DeleteFilesL(EBackupFile);
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailBackupFilesRemoved, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(EBackupFilesRemoved);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailBackupFilesRemoved, CIntegrityServices::EAfterJournal, KNullDesC);
-
- DeleteFilesL(ETempFile);
-
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailTempFilesRemoved, CIntegrityServices::EBeforeJournal, KNullDesC);
- WriteJournalEventL(ETempFilesRemoved);
- CIntegrityServices::SimulatePowerFailureL(CIntegrityServices::EFailTempFilesRemoved, CIntegrityServices::EAfterJournal, KNullDesC);
-
- FinishCommitL();
- }
-
-void CJournal::RollBackL(TBool aRecordAllRollbackEvents /*= ETrue*/)
- {
-#ifdef __WINSCW__
- // For 2 minutes after initial boot, DLLs are not unloaded. If we are doing a
- // rollback, we need to make sure any pending unloadeds are actioned, otherwise a
- // previously loaded DLL could cause the rollback to fail on windows (on arm it is legal to
- // delete a loaded DLL/EXE, whilst on windows it is not).
- RLoader loader;
- TInt r = loader.Connect();
- if(r == KErrNone)
- {
- (void)loader.CancelLazyDllUnload();
- loader.Close();
- }
-#endif
-
- for(TInt index = 0; index < iJournalFiles.Count(); index++)
- {
- TDriveUnit drive = iJournalFiles[index]->Drive();
- // check to see if this drive has already been completed
- if(iCompletedDrives.Find(drive) != KErrNotFound)
- continue;
-
- // only attempt to recover writeable drives that are present
- TDriveInfo info;
- User::LeaveIfError(iFs.Drive(info, drive));
- if (info.iMediaAtt & KMediaAttWriteProtected || info.iType==EMediaNotPresent)
- continue;
-
- TRAPD(err, RollBackDriveL(drive, aRecordAllRollbackEvents));
- if(err != KErrNone && err != KErrPathNotFound && err != KErrNotFound
- && err != KErrNotReady)
- {
- // unexpected error
- User::Leave(err);
- }
- }
- }