--- /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<TIntegrityServicesEvent> (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<TInt> (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<TInt> (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<TInt> (ERemovedFile));
+ iWriteStream << aFileName;
+ iWriteStream.WriteInt32L(static_cast<TInt> (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<TInt> (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
+