diff -r 7333d7932ef7 -r 8b7f4e561641 installationservices/swtransactionservices/source/server/integrityservices.cpp --- a/installationservices/swtransactionservices/source/server/integrityservices.cpp Tue Aug 31 15:21:33 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/* -* Copyright (c) 2008-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: -* CIntegrityServices implementation -* -*/ - - -/** - @file - @released - @internalTechnology -*/ - -#include "integrityservices.h" -#include "journal.h" -#include "operationfunctions.h" -#include "usiflog.h" - -#include - -using namespace Usif; - -_LIT(KTransactionPath, "\\sys\\install\\integrityservices\\"); - -CIntegrityServices::TFailType CIntegrityServices::iFailType = EFailNone; -CIntegrityServices::TFailPosition CIntegrityServices::iFailPosition = EBeforeJournal; -TFileName CIntegrityServices::iFailFileName; -TBool CIntegrityServices::iIsFailureTestingEnabled = EFalse; - - -/** - * This is a trivial C class that just encapsulates a TEntryArray object in order to - * facilitate its storage on the heap. - * - * @released - * @internalComponent - */ -class CEntryArray : public CBase - { -public: - inline TEntryArray& operator()(); - -private: - /** - * Container to hold file entries - */ - TEntryArray iEntryArray; - }; - -inline TEntryArray& CEntryArray::operator()() - { - return iEntryArray; - } - - CIntegrityServices* CIntegrityServices::NewL(TStsTransactionId aTransactionID) - { - CIntegrityServices* self = CIntegrityServices::NewLC(aTransactionID); - CleanupStack::Pop(self); - return self; - } - - CIntegrityServices* CIntegrityServices::NewLC(TStsTransactionId aTransactionID) - { - CIntegrityServices* self = new(ELeave) CIntegrityServices(aTransactionID); - CleanupStack::PushL(self); - self->ConstructL(); - return self; - } - - CIntegrityServices::CIntegrityServices(TStsTransactionId aTransactionID) : iTransactionID(aTransactionID) - { - } - - CIntegrityServices::~CIntegrityServices() - { - delete iJournal; - iFs.Close(); - - iLoader.Close(); - } - - void CIntegrityServices::ConstructL() - { - DEBUG_PRINTF2(_L("CIntegrityServices::ConstructL() - Opening session with Session ID %X."), iTransactionID); - - User::LeaveIfError(iFs.Connect()); - User::LeaveIfError(iFs.ShareProtected()); //needed as new RFiles are to be passed back to client's side - User::LeaveIfError(iLoader.Connect()); - - // store the journal path and create the journal - TParsePtrC pathPtr(KTransactionPath); - iJournalPath = pathPtr.Path(); - iJournal = CJournal::NewL(iFs, iLoader, iTransactionID, iJournalPath); - iSystemDrive = ::RFs::GetSystemDrive(); - } - -const TInt KIntegrityServicesSimulatedBatteryFailure=-10205; - -/*static*/ void CIntegrityServices::SimulatePowerFailureL(TFailType aFailType, TFailPosition aFailPosition, const TDesC& aFailFileName) - { - if (!iIsFailureTestingEnabled) - return; - - if(iFailType == aFailType && iFailPosition == aFailPosition && iFailFileName == aFailFileName) - { - User::Leave(KIntegrityServicesSimulatedBatteryFailure); - } - } - -/*static*/ void CIntegrityServices::NormalizeDirectoryName(TDes& aFileName) -{ - // Directories are represented in the integrity tree and integrity journal exactly as files, - // without the trailing slash - TInt lastCharPos = aFileName.Length() - 1; - if ( lastCharPos >= 0 && aFileName[lastCharPos] == KPathDelimiter && - aFileName.Locate(KPathDelimiter) != lastCharPos) // Take care not to remove slash from "c:\" and the like - { - aFileName.Delete(lastCharPos, 1); - } -} - - void CIntegrityServices::RegisterNewL(const TDesC& aFileName) - { - DEBUG_PRINTF3(_L("CIntegrityServices::RegisterNewL() - Session %X, File: %S."), iTransactionID, &aFileName); - - HBufC* localFilenameHeap = aFileName.AllocLC(); - TPtr localFilename = localFilenameHeap->Des(); - NormalizeDirectoryName(localFilename); // If it is a directory name, make sure to normalize it - - // Record the added file or directory in the journal - SimulatePowerFailureL(EFailAddingNewFile, EBeforeJournal, aFileName); - iJournal->AddL(localFilename); - SimulatePowerFailureL(EFailAddingNewFile, EAfterJournal, aFileName); - CleanupStack::PopAndDestroy(localFilenameHeap); - } - - void VerifyMkDirErrorL(TInt err) - { - if(err != KErrNone && err != KErrAlreadyExists) - { - User::Leave(err); - } - } - - void ProcessNewFileRegistrationResultL(TInt err, RFs& aFs, const TDesC& aFileName, RFile& aFile) - { - if(err!= KErrNone) - { - //if we hit this point it means we successfully created the new file however registering with the transaction has failed - //so we have to remove the new file to make the journal and the file system consistent - aFile.Close(); - aFs.Delete(aFileName); - User::Leave(err); - } - } - - void CIntegrityServices::CreateNewL(const TDesC& aFileName, RFile &newFile, TUint aFileMode) - { - DEBUG_PRINTF3(_L("CIntegrityServices::CreateNewL() - Session %X, File: %S."), iTransactionID, &aFileName); - TInt err = iFs.MkDirAll(aFileName); //first we have to create the full directory path to aFileName otherwise RFs::Create will fail - VerifyMkDirErrorL(err); - User::LeaveIfError(newFile.Create(iFs, aFileName, aFileMode)); - TRAPD(regResult, RegisterNewL(aFileName)); - ProcessNewFileRegistrationResultL(regResult, iFs, aFileName, newFile); //checks if the registration failed and cleans up the file in the filesystem if it did - } - - void CIntegrityServices::RemoveL(const TDesC& aFileName) - { - DEBUG_PRINTF3(_L("CIntegrityServices::RemoveL() - Session %X, File: %S."), iTransactionID, &aFileName); - - // before doing anything check that the file or directory exists - TEntry entry; - - TInt res = iFs.Entry(aFileName, entry); - if (res == KErrNotFound || res == KErrPathNotFound) - return; // If the file is not present, do nothing. Returning an error would require the user of the API to do additional checks - User::LeaveIfError(res); - - // We might need to grow this buffer by one byte later - HBufC* localFilenameHeap = HBufC::NewLC(aFileName.Length() + 1); - TPtr localFilename = localFilenameHeap->Des(); - localFilename.Copy(aFileName); - - TBool isFilenameDir = entry.IsDir(); - // The "if" below is not functionally necessary, but it is a slight optimization - - // so that we won't attempt to normalize directory name on files. The optimization is not - // done in AddL or NormalizeDirectoryName itself, since we don't have future use for TEntry there, and the cost for RFs::Entry overweighs the one for NormalizeDirectoryName - if ( isFilenameDir ) - { - NormalizeDirectoryName(localFilename); - } - - RBuf backupFileName; - backupFileName.CreateL(KMaxFileName); - CleanupClosePushL(backupFileName); - SimulatePowerFailureL(EFailRemovingFile, EBeforeJournal, aFileName); - iJournal->RemoveL(localFilename, backupFileName); - - if (backupFileName.Length()) - { - SimulatePowerFailureL(EFailRemovingFile, EAfterJournal, aFileName); - - TInt err = iFs.MkDirAll(backupFileName); - VerifyMkDirErrorL(err); - - SimulatePowerFailureL(EFailRemovingFile, EBeforeAction, aFileName); - err = iFs.Rename(localFilename, backupFileName); - DEBUG_PRINTF4(_L("CIntegrityServices::RemoveL() - Renamed %S as %S error %d"), &localFilename, &backupFileName, err); - User::LeaveIfError(err); - SimulatePowerFailureL(EFailRemovingFile, EAfterAction, aFileName); - } - else - { - DEBUG_PRINTF2(_L("CIntegrityServices::RemoveL() - %S already backed up"), &aFileName); - SimulatePowerFailureL(EFailRemovingFile, EBeforeAction, aFileName); - // If backupFileName is zero-length, the file was added earlier - // in the same journal and doesn't need to be backed up. - if (isFilenameDir) - { - CFileMan* fileman = CFileMan::NewL(iFs); - CleanupStack::PushL(fileman); - // Make sure to append slash before calling RmDir - otherwise it deletes the parent directory - if (localFilename[localFilename.Length()-1] != KPathDelimiter) - { - localFilename.Append(KPathDelimiter); - } - User::LeaveIfError(fileman->RmDir(localFilename)); // A directory cannot be a paged exec., so we don't have to use iLoader - CleanupStack::PopAndDestroy(fileman); - } - else - { - User::LeaveIfError(iLoader.Delete(aFileName)); - } - SimulatePowerFailureL(EFailRemovingFile, EAfterAction, aFileName); - } - - // Don't leave an empty directory structure, try pruning it - RemoveDirectoryTreeL(iFs, aFileName); - - CleanupStack::PopAndDestroy(2, localFilenameHeap); // backupFileName - } - - void CIntegrityServices::RegisterTemporaryL(const TDesC& aFileName) - { - DEBUG_PRINTF3(_L("CIntegrityServices::RegisterTemporaryL() - Session %X, File: %S."), iTransactionID, &aFileName); - - // record the temporary file or directory in the journal - SimulatePowerFailureL(EFailAddingTempFile, EBeforeJournal, aFileName); - iJournal->TemporaryL(aFileName); - SimulatePowerFailureL(EFailAddingTempFile, EAfterJournal, aFileName); - } - - void CIntegrityServices::CreateTemporaryL(const TDesC& aFileName, RFile &newFile, TUint aFileMode) - { - DEBUG_PRINTF3(_L("CIntegrityServices::CreateTemporaryL() - Session %X, File: %S."), iTransactionID, &aFileName); - - TInt err = iFs.MkDirAll(aFileName); //first we have to create the full directory path to aFileName otherwise RFs::Create will fail - VerifyMkDirErrorL(err); - User::LeaveIfError(newFile.Create(iFs, aFileName, aFileMode)); - TRAPD(regResult, RegisterTemporaryL(aFileName)); - ProcessNewFileRegistrationResultL(regResult, iFs, aFileName, newFile); - } - - void CIntegrityServices::OverwriteL(const TDesC& aFileName, RFile &newFile, TUint aFileMode) - { - DEBUG_PRINTF3(_L("CIntegrityServices::OverwriteL() - Session %X, File: %S."), iTransactionID, &aFileName); - - TBool b; - TInt err; - if((err=iFs.IsFileOpen(aFileName, b))== KErrNone) //returned error code shows whether the file exists or not; the bool value is ignored - { - //file exists remove first - RemoveL(aFileName); - } - else - { - if(err != KErrNotFound) - { - User::Leave(err); - } - } - CreateNewL(aFileName, newFile, aFileMode); - } - - void CIntegrityServices::CommitL() - { - DEBUG_PRINTF2(_L("CIntegrityServices::CommitL() - Session %X."), iTransactionID); - iJournal->CommitL(); - } - - void CIntegrityServices::RollBackL(TBool aRecordAllRollbackEvents /* = ETrue */) - { - DEBUG_PRINTF2(_L("CIntegrityServices::RollBackL() - transaction %X"), iTransactionID); - iJournal->RollBackL(aRecordAllRollbackEvents); - } - -/*static*/ void CIntegrityServices::GetListOfTransactionsL(RArray& aIdArray) - { - RFs fs; - User::LeaveIfError(fs.Connect()); - CleanupClosePushL(fs); - TDriveUnit systemDrive(::RFs::GetSystemDrive()); - RBuf fileSpec; - fileSpec.CreateL(systemDrive.Name(), KMaxFileName); - CleanupClosePushL(fileSpec); - fileSpec.Append(KTransactionPath); - fileSpec.Append(KMatchAny); - fileSpec.Append(KExtDelimiter); - fileSpec.Append(KDriveExt); - - RDir dir; - TInt err = dir.Open(fs, fileSpec, KEntryAttNormal); - CleanupStack::PopAndDestroy(&fileSpec); - if (err == KErrPathNotFound || err == KErrNotFound) - { - CleanupStack::PopAndDestroy(&fs); - return; // These errors are not considered fatal - there may be no journals present - } - User::LeaveIfError(err); - CleanupClosePushL(dir); - - CEntryArray* entryArrayContainer = new (ELeave) CEntryArray; - TEntryArray& entryArray = (*entryArrayContainer)(); - err = dir.Read(entryArray); - CleanupStack::PopAndDestroy(&dir); - CleanupStack::PushL(entryArrayContainer); - if (err != KErrNone && err != KErrEof) - { - User::Leave(err); - } - TInt entryCount(entryArray.Count()); - for (TInt index = 0; index < entryCount; ++index) - { - TStsTransactionId transactionID; - if (CJournal::RecoverTransactionIdFromDrvFileName( - entryArray[index].iName, transactionID) == KErrNone) - { - aIdArray.AppendL(transactionID); - } - } - CleanupStack::PopAndDestroy(entryArrayContainer); - CleanupStack::PopAndDestroy(&fs); - } - -/*static*/ void CIntegrityServices::RollbackAllL() - { - RArray transactionIDs; - CleanupClosePushL(transactionIDs); - CIntegrityServices::GetListOfTransactionsL(transactionIDs); - TInt numberOfTransactions(transactionIDs.Count()); - TInt lastError=KErrNone; - DEBUG_PRINTF2(_L("CIntegrityServices::RollbackAllL() %d transactions have been found."), numberOfTransactions ); - for(TInt i=0; iRollBackL(EFalse); // Specify not to record roll back events. If we failed in the middle of a previous roll back, due to lack of resources we shouldn't be trying to record more events - CleanupStack::PopAndDestroy(transactionPtr); - ); //failing to roll back one transaction shouldn't affect the overall rollback all procedure - if(err!=KErrNone) - { - lastError=err; //remember last error and leave with that error code indicating an error in the overall procedure - } - DEBUG_PRINTF2(_L("CIntegrityServices::RollbackAllL() Rolled back transaction %X"), transactionIDs[i]); - } - CleanupStack::PopAndDestroy(&transactionIDs); - User::LeaveIfError(lastError); - }