--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swtransactionservices/source/server/journal.cpp Fri Mar 19 09:33:35 2010 +0200
@@ -0,0 +1,646 @@
+/*
+* 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);
+ }
+ }
+ }