diff -r 5cc91383ab1e -r 7333d7932ef7 installationservices/swtransactionservices/source/server/journalfile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installationservices/swtransactionservices/source/server/journalfile.cpp Tue Aug 31 15:21:33 2010 +0300 @@ -0,0 +1,402 @@ +/* +* Copyright (c) 2008-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: +* CJournalFile implementation +* +*/ + + +/** + @file + @released + @internalTechnology +*/ + +#include "journalfile.h" +#include "usiflog.h" + +_LIT(KBackupExt, "bak"); // extension for removed files in backup location + +namespace Usif +{ +CJournalFile* CJournalFile::NewL(RFs& aFs, RLoader& aLoader, const TDesC& aFileName, TInt aDrive) + { + CJournalFile* self = CJournalFile::NewLC(aFs, aLoader, aFileName, aDrive); + CleanupStack::Pop(self); + return self; + } + +CJournalFile* CJournalFile::NewLC(RFs& aFs, RLoader& aLoader, const TDesC& aFileName, TInt aDrive) + { + CJournalFile* self = new(ELeave) CJournalFile(aFs, aLoader, aDrive); + CleanupStack::PushL(self); + self->ConstructL(aFileName); + return self; + } + +CJournalFile::CJournalFile(RFs& aFs, RLoader& aLoader, TInt aDrive) + : iFs(aFs), iLoader(aLoader), iLastEvent(ENone), iDrive(aDrive) + { + } + +CJournalFile::~CJournalFile() + { + iWriteStream.Close(); + delete iTreeRoot; + } + +void CJournalFile::ConstructL(const TDesC& aFileName) + { + DEBUG_PRINTF2(_L("CJournalFile::ConstructL() - aFileName %S"), &aFileName); + iJournalFileName = aFileName; + + TChar drive; + User::LeaveIfError(iFs.DriveToChar(iDrive, drive)); + + TBuf<2> driveSpec; + driveSpec.Append(drive); + driveSpec.Append(KDriveDelimiter); + iTreeRoot = CIntegrityTreeNode::NewL(driveSpec); + + // read any existing entries from this journal + TRAPD(err, ReadL()); + if(err != KErrNone) + { + DEBUG_PRINTF2(_L("CJournalFile::ConstructL() - CJournalFile::ReadL() has left with error %d"), err); + // if necessary create the path + if(err == KErrPathNotFound) + { + User::LeaveIfError(iFs.MkDirAll(iJournalFileName)); + } + else if (err != KErrNotFound) + { + DEBUG_PRINTF2(_L("CJournalFile::ConstructL() - Leaving with error %d"), err); + User::Leave(err); + } + } + // now prepare for writing + PrepareToWriteL(); + } + +void CJournalFile::ReadL() + { + RFileReadStream journalStream; + User::LeaveIfError(journalStream.Open(iFs, iJournalFileName, EFileRead | EFileShareAny)); + CleanupClosePushL(journalStream); + + // we need to check that any filenames read from the journal are on the + // same drive as the journal itself + TDriveUnit journalDrive(iJournalFileName); + + TInt err = KErrNone; + while(err == KErrNone) + { + // read the next journal entry + TRAP(err, ReadEntryL(journalStream, journalDrive)); + if(err != KErrNone && err != KErrEof) + { + DEBUG_PRINTF2(_L("CJournalFile::ReadL() - CJournalFile::ReadEntryL() has left with error %d Leaving with this error!"), err); + User::Leave(err); + } + } + CleanupStack::PopAndDestroy(&journalStream); + } + +void VerifyIsFileEventL(TIntegrityServicesEvent aEvent) + { + if (aEvent != ERemovedFile && + aEvent != ETempFile && aEvent != EAddedFile) + { + User::Leave(KErrCorrupt); + } + } + +void VerifyIsEmptyOrFileEventL(TIntegrityServicesEvent aEvent) + { + if (aEvent == ENone) + return; + + VerifyIsFileEventL(aEvent); + } + +void CJournalFile::ReadEntryL(RFileReadStream& aJournalStream, TInt aDrive) + { + TIntegrityServicesEvent event = static_cast (aJournalStream.ReadInt32L()); + + HBufC* removedFile = NULL; + HBufC* backupFile = NULL; + HBufC* tempFile = NULL; + HBufC* addedFile = NULL; + + switch(event) + { + case ERemovedFile: + { + VerifyIsEmptyOrFileEventL(iLastEvent); + removedFile = HBufC::NewLC(aJournalStream, KMaxFileName); + // should be followed by the backup event + if(aJournalStream.ReadInt32L() != EBackupFile) + { + User::Leave(KErrCorrupt); + } + backupFile = HBufC::NewLC(aJournalStream, KMaxFileName); + // make sure files are located on the same drive as the journal + if(CJournalFile::CheckFileNameL(iFs, *removedFile) != aDrive + || CJournalFile::CheckFileNameL(iFs, *backupFile) != aDrive) + { + User::Leave(KErrCorrupt); + } + + CIntegrityTreeLeaf* removeLeaf = iTreeRoot->AddNodeL(*removedFile, ERemovedFile, iJournalFileName); + CIntegrityTreeLeaf* backupLeaf = iTreeRoot->AddNodeL(*backupFile, EBackupFile, iJournalFileName); + + removeLeaf->SetPeer(backupLeaf); + backupLeaf->SetPeer(removeLeaf); + + CleanupStack::PopAndDestroy(backupFile); + CleanupStack::PopAndDestroy(removedFile); + iBackupFilesCount++; + iLastEvent = ERemovedFile; + } + break; + + case EBackupFile: + // cannot have a backup file on its own + User::Leave(KErrCorrupt); + break; + + case ETempFile: + VerifyIsEmptyOrFileEventL(iLastEvent); + + tempFile = HBufC::NewLC(aJournalStream, KMaxFileName); + // make the file is located on the same drive as the journal + if(CJournalFile::CheckFileNameL(iFs, *tempFile) != aDrive) + { + User::Leave(KErrCorrupt); + } + iTreeRoot->AddNodeL(*tempFile, ETempFile, iJournalFileName); + CleanupStack::PopAndDestroy(tempFile); + iLastEvent = ETempFile; + break; + + case EAddedFile: + VerifyIsEmptyOrFileEventL(iLastEvent); + + addedFile = HBufC::NewLC(aJournalStream, KMaxFileName); + // make the file is located on the same drive as the journal + if(CJournalFile::CheckFileNameL(iFs, *addedFile) != aDrive) + { + User::Leave(KErrCorrupt); + } + iTreeRoot->AddNodeL(*addedFile, EAddedFile, iJournalFileName); + CleanupStack::PopAndDestroy(addedFile); + iLastEvent = EAddedFile; + break; + + case ECommitted: + VerifyIsFileEventL(iLastEvent); + + iLastEvent = ECommitted; + break; + + case EBackupFilesRemoved: + if(iLastEvent != ECommitted) + { + User::Leave(KErrCorrupt); + } + iLastEvent = EBackupFilesRemoved; + break; + + case EAddedFilesRemoved: + if(iLastEvent != ECommitted) + VerifyIsFileEventL(iLastEvent); // The last event can be only a commit, or one of the file events + + iLastEvent = EAddedFilesRemoved; + break; + + case ETempFilesRemoved: + if(iLastEvent != EBackupFilesRemoved && iLastEvent != ERemovedFilesRestored) + { + User::Leave(KErrCorrupt); + } + iLastEvent = ETempFilesRemoved; + break; + + case ERemovedFilesRestored: + if(iLastEvent != EAddedFilesRemoved) + { + User::Leave(KErrCorrupt); + } + iLastEvent = ERemovedFilesRestored; + break; + + default: + User::Leave(KErrCorrupt); + break; + } + } + +void CJournalFile::PrepareToWriteL() + { + DEBUG_PRINTF2(_L("CJournalFile::PrepareToWriteL() iJournalFileName %S"), &iJournalFileName); + RFile file; + CleanupClosePushL(file); + // try opening the journal if it already exists + TEntry entry; + TBool journalFileExists = (iFs.Entry(iJournalFileName, entry) == KErrNone); + if (journalFileExists) + { + User::LeaveIfError(file.Open(iFs, iJournalFileName, EFileWrite | EFileShareAny)); + } + else + { + // journal does not exist, try creating one + User::LeaveIfError(file.Create(iFs, iJournalFileName, EFileWrite | EFileShareAny)); + } + + TInt fileSize; + User::LeaveIfError(file.Size(fileSize)); + + // attach to end of file for writing + iWriteStream.Attach(file, fileSize); + CleanupStack::Pop(&file); // file ownership transfered to stream + } + +void CJournalFile::EventL(TIntegrityServicesEvent aEvent, TBool aSerializeEventToJournal /* = ETrue*/ ) + { + DEBUG_PRINTF2(_L("CJournalFile::EventL() - aEvent %d"), aEvent); + if (aSerializeEventToJournal) + { + iWriteStream.WriteInt32L(static_cast (aEvent)); + iWriteStream.CommitL(); + } + + iLastEvent = aEvent; + } + +void CJournalFile::AddL(const TDesC& aFileName) + { + DEBUG_PRINTF2(_L("CJournalFile::AddL() - aFileName %S"), &aFileName); + iTreeRoot->AddNodeL(aFileName, EAddedFile, iJournalFileName); + + // write filename to journal + iWriteStream.WriteInt32L(static_cast (EAddedFile)); + iWriteStream << aFileName; + iWriteStream.CommitL(); + + iLastEvent = EAddedFile; + } + +void CJournalFile::RemoveL(const TDesC& aFileName, TDes& aBackupFileName) + { + DEBUG_PRINTF2(_L("CJournalFile::RemoveL() - aFileName %S"), &aFileName); + // Only journal removals if the file hasn't been added in the same + // journalfile. + TInt err = iTreeRoot->FindNode(aFileName, EAddedFile); + if (err == KErrNotFound) + { + CIntegrityTreeLeaf* removalNode = iTreeRoot->AddNodeL(aFileName, ERemovedFile, iJournalFileName); + + // generate the next backup filename for this journal + NextBackupFileNameL(aBackupFileName); + + CIntegrityTreeLeaf* backupNode = iTreeRoot->AddNodeL(aBackupFileName, EBackupFile, iJournalFileName); + + // set peers on both nodes + removalNode->SetPeer(backupNode); + backupNode->SetPeer(removalNode); + + // write filenames to journal + iWriteStream.WriteInt32L(static_cast (ERemovedFile)); + iWriteStream << aFileName; + iWriteStream.WriteInt32L(static_cast (EBackupFile)); + iWriteStream << aBackupFileName; + iWriteStream.CommitL(); + + iLastEvent = ERemovedFile; + } + else + { + User::LeaveIfError(err); + } + } + +void CJournalFile::TemporaryL(const TDesC& aFileName) + { + DEBUG_PRINTF2(_L("CJournalFile::TemporaryL() - aFileName %S"), &aFileName); + iTreeRoot->AddNodeL(aFileName, ETempFile, iJournalFileName); + + // write filename to journal + iWriteStream.WriteInt32L(static_cast (ETempFile)); + iWriteStream << aFileName; + iWriteStream.CommitL(); + + iLastEvent = ETempFile; + } + +void CJournalFile::JournalOperationL(TTreeWalkFunctionL aFunc, TIntegrityServicesEvent aTypeFilter, + CIntegrityServices::TFailType aFailType) + { + CFileMan* fileman = CFileMan::NewL(iFs); + CleanupStack::PushL(fileman); + iTreeRoot->WalkTreeL(aFunc, aTypeFilter, iFs, iLoader, *fileman, aFailType); + CleanupStack::PopAndDestroy(fileman); + } + +void CJournalFile::NextBackupFileNameL(TDes& aBackupFileName) + { + TParsePtrC fileNamePtr(iJournalFileName); + aBackupFileName = fileNamePtr.DriveAndPath(); + aBackupFileName.Append(fileNamePtr.Name()); + aBackupFileName.Append(KPathDelimiter); + aBackupFileName.AppendNumUC(iBackupFilesCount, EHex); + aBackupFileName.Append(KExtDelimiter); + aBackupFileName.Append(KBackupExt); + + iBackupFilesCount++; + } + + +TIntegrityServicesEvent CJournalFile::LastEvent() const + { + return iLastEvent; + } + +TInt CJournalFile::Drive() + { + return iDrive; + } + +void CJournalFile::Close() + { + iWriteStream.Close(); + } + +/*static*/ TInt CJournalFile::CheckFileNameL(RFs&, const TDesC& aFileName) + { + TParse parse; + + User::LeaveIfError(parse.Set(aFileName, NULL, NULL)); + + if (!parse.DrivePresent()) + User::Leave(KErrArgument); + + if (!parse.PathPresent()) + User::Leave(KErrArgument); + + TDriveUnit drive(parse.Drive()); + return drive; + } +}//End of namespace Usif +