--- a/persistentstorage/sql/SRC/Server/SqlBur.cpp Thu Aug 12 11:53:23 2010 +0100
+++ b/persistentstorage/sql/SRC/Server/SqlBur.cpp Mon Sep 27 11:59:56 2010 +0100
@@ -23,6 +23,12 @@
#define UNUSED_ARG(arg) arg = arg
+_LIT(KSqlBurBackupExt, ".bak");
+_LIT(KSqlBurRestoreDir, "temprestore");
+_LIT(KSqlBurAllFiles, "*");
+
+const TUint K8to16bitShift = 1;
+
//Extracts and returns 32-bit integer from aNumBuf buffer.
static TUint32 GetNumUint32L(const TDesC& aNumBuf)
{
@@ -44,223 +50,358 @@
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// string consts
-_LIT(KRestoreFilter,"*.rst"); // the filter for restore files
-_LIT(KBackupFilter,"*.bak");// the filter for backup files
-_LIT(KRestoreSuffix,".bak.rst"); // the suffix for restore files (a shortcut by using double suffix :)
-
-const TUint K8to16bitShift = 1;
+/////////////////////////////// CSqlBurEventMonitor //////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-/** Standard two phase construction
- @return an instance of the backup client
- @param a pointer to the SQL server which must have implemented the
- TSqlSrvBurInterface interface
- @leave if no memory
+/**
+Standard two phase construction. Creates a CSqlBurEventMonitor instance.
+@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
+@return An instance of the backup notifier
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
*/
-CSqlBackupClient* CSqlBackupClient::NewLC(MSqlSrvBurInterface *aInterface)
+CSqlBurEventMonitor* CSqlBurEventMonitor::NewL(MSqlSrvBurInterface& aInterface)
{
- CSqlBackupClient *self=(CSqlBackupClient *)new(ELeave) CSqlBackupClient(aInterface);
+ CSqlBurEventMonitor* self = new (ELeave) CSqlBurEventMonitor(aInterface);
CleanupStack::PushL(self);
self->ConstructL();
- SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_NEWLC, "0x%X;CSqlBackupClient::NewLC", (TUint)self));
- return self;
- }
-
-/** Standard two phase construction
- @return an instance of the backup client
- @param a pointer to the SQL server which must have implemented the
- TSqlSrvBurInterface interface
- @leave if no memory
-*/
-CSqlBackupClient* CSqlBackupClient::NewL(MSqlSrvBurInterface *aInterface)
- {
- CSqlBackupClient *self=(CSqlBackupClient *) NewLC(aInterface);
- CleanupStack::Pop();
+ CleanupStack::Pop(self);
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_NEWL, "0x%X;CSqlBurEventMonitor::NewL", (TUint)self));
return self;
}
-/** Standard two phase construction
- @param a pointer to the SQL server which must have implemented the
- TSqlSrvBurInterface interface
+/**
+Releases the allocated resources.
+*/
+CSqlBurEventMonitor::~CSqlBurEventMonitor()
+ {
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_CSQLBACKUPNOTIFIER2, "0x%X;CSqlBurEventMonitor::~CSqlBurEventMonitor", (TUint)this));
+ Cancel();
+ iBurProperty.Close();
+ DestroyContent();
+ }
+
+/**
+Initializes data members with their default values.
+@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
*/
-CSqlBackupClient::CSqlBackupClient(MSqlSrvBurInterface *aInterface)
-: CActive(EPriorityStandard), iInterface(aInterface)
+CSqlBurEventMonitor::CSqlBurEventMonitor(MSqlSrvBurInterface& aInterface) :
+ CActive(EPriorityStandard),
+ iBurInterface(aInterface)
{
}
-/** Usual tidy up
-*/
-CSqlBackupClient::~CSqlBackupClient()
+/**
+Initializes the created CSqlBurEventMonitor object.
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
+*/
+void CSqlBurEventMonitor::ConstructL()
{
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_CSQLBACKUPCLIENT2, "0x%X;CSqlBackupClient::~CSqlBackupClient;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
-
- // cancel outstanding requests
- Cancel();
-
- // release the pub/sub property
- iBurProperty.Close();
-
- // the file list array
- iFileList.Close();
-
- // close the file
- iFile.Close();
-
- // nuke the active backup client
- delete iActiveBackupClient;
- }
-
-/** Standard two phase construction
- @leave if non memory or StartL leaves
-*/
-void CSqlBackupClient::ConstructL()
- {
- // attach to backup/restore publish/subscribe property
- __SQLLEAVE_IF_ERROR(iBurProperty.Attach(KUidSystemCategory,KUidBackupRestoreKey));
-
- // add us to the scheduler
+ __SQLLEAVE_IF_ERROR(iBurProperty.Attach(KSqlBurPropertyCategoryUid, KSqlBurBackupRestoreKey));
CActiveScheduler::Add(this);
-
- // set active and request notification of changes to backup
- // and restore publish/subscribe property
- StartL();
+ iBurProperty.Subscribe(iStatus);
+ SetActive();
}
/**
-Cancel the outstanding B&R request
+RunL() is called when the value of the {KUidSystemCategory, KUidBackupRestoreKey} gets changed.
+That indicates: a backup or a restore is about to begin.
+
+How the function works:
+ - When a backup or restore notification is received, the function will subscribe again for notifications from
+ the backup and restore property and will read the property status;
+ - If the property status is conn::EBURUnset or conn::EBURNormal, the function will destroy iSqlBurCallback
+ and iActiveBackupClient interfaces. No more callbacks will be reseived from the backup and restore server.
+ This is the end of the backup or restore processing;
+ - If the property status is conn::EBURBackupFull, conn::EBURBackupPartial, conn::EBURRestoreFull or
+ conn::EBURRestorePartial, the function will create iSqlBurCallback and iActiveBackupClient interface
+ (iActiveBackupClient's NewL() receives iSqlBurCallback as an input parameter, registering this way the callback
+ in the backup and restore server to be called later, when sending or retrieving data to/from the server).
+ If the property read and the interface creation operations have been successful, the function will call
+ ConfirmReadyForBURL(KErrNone) to notify the backup and restore server that the SQL server is ready to send/retrieve
+ backup/restore data.
+ If the current notification is that a backup is about to begin, after the confirmation the backup and restore server will
+ call CSqlBurCallback::InitialiseGetProxyBackupDataL() once per {client secure id, drive}
+ followed by CSqlBurCallback::GetBackupDataSectionL() calls to retrieve the backup data.
+ If the current notification is that a restore is about to begin, after the confirmation the backup and restore server will
+ call CSqlBurCallback::InitialiseRestoreProxyBaseDataL() once per {client secure id, drive}
+ followed by CSqlBurCallback::RestoreBaseDataSectionL() calls to send the restore data.
+
+The current implementation has one design flaw. If a backup or restore notification is received, there are at lest 3
+places before the ConfirmReadyForBURL() call, where the code may leave:
+ - the "property get" operation;
+ - the iSqlBurCallback creation;
+ - the iActiveBackupClient creation;
+If a leave occurs at some of the mentioned places, that leave will be trapped by the current CActiveScheduler object
+and CSqlBurEventMonitor::RunError() will be called with the leaved error code.
+Problem #1: CSqlBurEventMonitor::RunError() won't do anything with the error (apart from printing a trace in the OST builds).
+ The error is silently suppressed. The backup or restore won't start. But the client won't see any notification
+ for that problem.
+Problem #2: ConfirmReadyForBURL() won't be called. According to the backup and restore documentation, if
+ ConfirmReadyForBURL() is called with KErrNone parameter, that's a confirmation for the backup and restore
+ server to start the processing. If ConfirmReadyForBURL() is called with an error different than KErrNone,
+ that's a confirmation for the backup and restore server that the client is not ready. No backup or restore
+ will be started. The remote backup client will be notified about the problem.
+After an investigation it was found that the same problems do exist in all active backup clients, none of them has
+solved the problems. Then, the code here will be kept as it is, it might be too dangerous to do a change right now.
+
+@see CSqlBurEventMonitor::RunError()
+@see CSqlBurCallback
+@see CActiveBackupClient
+@see CSqlBurCallback::InitialiseGetProxyBackupDataL()
+@see CSqlBurCallback::GetBackupDataSectionL()
+@see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
+@see CSqlBurCallback::RestoreBaseDataSectionL()
+
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
*/
-void CSqlBackupClient::DoCancel()
+void CSqlBurEventMonitor::RunL()
+ {
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL_ENTRY, "Entry;0x%X;CSqlBurEventMonitor::RunL", (TUint)this));
+ iBurProperty.Subscribe(iStatus);
+ SetActive();
+ TInt status;
+ __SQLLEAVE_IF_ERROR(iBurProperty.Get(status));
+ status &= conn::KBURPartTypeMask;
+#ifdef _SQL_RDEBUG_PRINT
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL1, "0x%X;CSqlBurEventMonitor::RunL;status=%d", (TUint)this, status));
+#else
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL2, "0x%X;CSqlBurEventMonitor::RunL;status=%{TBURPartType}", (TUint)this, status));
+#endif
+ switch(status)
+ {
+ case conn::EBURBackupFull:
+ case conn::EBURBackupPartial:
+ case conn::EBURRestoreFull:
+ case conn::EBURRestorePartial:
+ {
+ // we only do full backups and full restores
+ if(!(iSqlBurCallback && iActiveBackupClient))
+ {
+ DestroyContent();
+ TRAPD(err, CreateContentL());
+ if(err != KErrNone)
+ {
+ DestroyContent();
+ __SQLLEAVE(err);
+ }
+ }
+ iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
+ }
+ break;
+ //case conn::EBURUnset:
+ //case conn::EBURNormal:
+ default:
+ DestroyContent();
+ break;
+ }
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_EXIT, "Exit;0x%X;CSqlBurEventMonitor::RunL", (TUint)this));
+ SQL_BUR_TEST_STOP();
+ }
+
+/**
+Cancels the subscribtion for {KUidSystemCategory, KUidBackupRestoreKey} property changes.
+*/
+void CSqlBurEventMonitor::DoCancel()
{
iBurProperty.Cancel();
}
-/** Not implemented
- @return a flag indicating whether we actioned the error
- @param the error unused
+/**
+No-op. The method does nothing with the reported from CSqlBurEventMonitor::RunL() error
+(apart from logging a trace in OST builds).
+Actually, the right action is to return KErrNone (as it is implemented), otherwise the default implementation of
+CActiveScheduler::Error() will panic the current thread.
+
+@see CActiveScheduler::Error()
+@see CSqlBurEventMonitor::RunL()
+
+@return The RunL() error, if the RunL() call leaves.
+@param The RunL() error
*/
-TInt CSqlBackupClient::RunError(TInt aError)
+TInt CSqlBurEventMonitor::RunError(TInt aError)
{
UNUSED_ARG(aError);
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RUNERROR, "0x%X;CSqlBackupClient::RunError;aError=%d", (TUint)this, aError));
- // just satisfy it that we did something!
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RUNERROR, "0x%X;CSqlBurEventMonitor::RunError;aError=%d", (TUint)this, aError));
+ SQL_BUR_TEST_SET_ERROR(aError);
+ SQL_BUR_TEST_STOP();
return KErrNone;
}
-/** Kick off the BUR client
- @leave if TestBurStatusL leaves
+/**
+Creates iActiveBackupClient and iSqlBurCallback objects.
*/
-void CSqlBackupClient::StartL()
+void CSqlBurEventMonitor::CreateContentL()
{
- TestBurStatusL();
- NotifyChange();
+ iSqlBurCallback = CSqlBurCallback::NewL(iBurInterface);
+ iActiveBackupClient = conn::CActiveBackupClient::NewL(iSqlBurCallback);
+ }
+
+/**
+Destroys iActiveBackupClient and iSqlBurCallback objects.
+*/
+void CSqlBurEventMonitor::DestroyContent()
+ {
+ delete iActiveBackupClient;
+ iActiveBackupClient = NULL;
+ delete iSqlBurCallback;
+ iSqlBurCallback = NULL;
}
-/** Resubscribe and wait for events
-*/
-void CSqlBackupClient::NotifyChange()
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// CSqlBackupClient /////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+Creates new CSqlBurCallback instance.
+The CSqlBurEventMonitor object monitors the state of the {KUidSystemCategory, KUidBackupRestoreKey}
+property. When a backup or a restore is about to begin, the CSqlBurEventMonitor object creates a
+CSqlBurCallback instance, establishes a connection with the B&R server and passes a pointer to
+the CSqlBurCallback callback to the BYR conenction.
+The CSqlBurCallback methods will be called during the backup/restore for sending/retrieving data.
+
+@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
+@return A pointer to the created CSqlBurCallback instance
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
+*/
+CSqlBurCallback* CSqlBurCallback::NewL(MSqlSrvBurInterface& aInterface)
{
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_NOTIFYCHANGE, "0x%X;CSqlBackupClient::NotifyChange;iBurProperty.Handle()=0x%X", (TUint)this, (TUint)iBurProperty.Handle()));
- iBurProperty.Subscribe(iStatus);
- SetActive();
+ CSqlBurCallback* self = new (ELeave) CSqlBurCallback(aInterface);
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_NEWLC, "0x%X;CSqlBurCallback::NewL", (TUint)self));
+ return self;
+ }
+
+/**
+Initializes CSqlBurCallback data members with their default values.
+@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
+*/
+CSqlBurCallback::CSqlBurCallback(MSqlSrvBurInterface& aInterface) :
+ iInterface(aInterface)
+ {
}
-/** Something happened. Find out what.
- Create an instance of BUR client if required
- Delete it if no longer required
- This is for performance reasons
- @leave if ConfirmReadyForBURL leaves
+/**
+Releases the allocated resources.
*/
-void CSqlBackupClient::TestBurStatusL()
+CSqlBurCallback::~CSqlBurCallback()
{
- SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL_ENTRY, "Entry;0x%X;CSqlBackupClient::TestBurStatusL", (TUint)this));
- TInt status;
- __SQLTRACE_BURVAR(TInt err = KErrNone);
- if((__SQLTRACE_BUREXPR(err =) iBurProperty.Get(status)) != KErrNotFound)
- {
- status&=KBURPartTypeMask;
-#ifdef _SQL_RDEBUG_PRINT
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL1, "0x%X;CSqlBackupClient::TestBurStatusL;status=%d", (TUint)this, status));
-#else
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL2, "0x%X;CSqlBackupClient::TestBurStatusL;status=%{TBURPartType}", (TUint)this, status));
-#endif
- switch(status)
- {
- case EBURUnset: // same as EBURNormal
- case EBURNormal:
- delete iActiveBackupClient;
- iActiveBackupClient=NULL;
- break;
- case EBURBackupFull:
- case EBURBackupPartial:
- case EBURRestoreFull:
- case EBURRestorePartial:
- // we only do full backups and full restores
- if(!iActiveBackupClient)
- {
- iActiveBackupClient=CActiveBackupClient::NewL(this);
- }
- iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
- break;
- default:
- break;
- }
- }
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL_EXIT, "Exit;0x%X;CSqlBackupClient::TestBurStatusL;iProperty.Get() err=%d", (TUint)this, err));
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_CSQLBACKUPCLIENT2, "0x%X;CSqlBurCallback::~CSqlBurCallback;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
+ BackupCleanup();
+ (void)RestoreCleanup();
}
-/** Called when BUE notifies a BUR event
- @leave if TestBurStatusL leaves
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////// Full backup //////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+This is called to let us know that the given SID is to be backed up.
+We ask the SQL server (using iInterface, see MSqlSrvBurInterface for more details)
+for a list of databases that want to be backed up.
+
+The backup is initiated by a notification received in CSqlBurEventMonitor::RunL() method.
+InitialiseGetProxyBackupDataL() is called once per {client secure id, drive} and each
+InitialiseGetProxyBackupDataL() call is followed after that by a set of CSqlBurCallback::GetBackupDataSectionL() calls,
+made from the backup and restore client dll.
+
+During GetBackupDataSectionL() calls the CSqlBurCallback object will read the content of the databases from the list,
+retrieved from the MSqlSrvBurInterface::GetBackUpListL() call and send the content to the backup and restore server.
+
+@see MSqlSrvBurInterface
+@see CSqlBurEventMonitor::RunL()
+@see CSqlBurCallback::GetBackupDataSectionL()
+@see CSqlServer::GetBackUpListL()
+
+@param aSid the UID of the application to backup
+@param aDrive the drive to be backed up
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
*/
-void CSqlBackupClient::RunL()
+void CSqlBurCallback::InitialiseGetProxyBackupDataL(TSecureId aSid, TDriveNumber aDrive)
{
- NotifyChange();
- TestBurStatusL();
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZEGETPROXYBACKUPDATAL, "0x%X;CSqlBurCallback::InitialiseGetProxyBackupDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
+ BackupCleanup();
+ iInterface.GetBackUpListL(aSid, aDrive, iFileList);
+ iFileIndex = 0;
+ iState = EBackupNoFileOpen;
+ iBackupError = KErrNone;
}
-/** This is supposed to allow the BUE to know in advance how much
- data is coming - but unfortunately there is no way to know this
- at this stage since we don't even know yet what SID is being processed
- So we just answer some number to make the BUE happy. It doesn't
- actually rely on this number so there is no risk - the aFinishedFlag
- indicates the end of data, not the value returned here. It is
- supposed to allow the BUE to optimise its behaviour by know up front
- the data volume.
- @return an arbitrary number
- @param TDrive unused
+/**
+This is supposed to allow the B&R framework to know in advance how much
+data is coming - but unfortunately there is no way to know this
+at this stage since we don't even know yet what SID is being processed
+So we just answer some number to make the BUE happy. It doesn't
+actually rely on this number so there is no risk - the aFinishedFlag
+indicates the end of data, not the value returned here. It is
+supposed to allow the BUE to optimise its behaviour by know up front
+the data volume.
+
+@see CSqlBurEventMonitor::RunL()
+@see CSqlBurCallback::InitialiseGetProxyBackupDataL()
+
+@param aDrive Unused parameter (the drive number is logged in OST builds).
+@return an arbitrary number (1024 at the moment)
*/
-TUint CSqlBackupClient::GetExpectedDataSize(TDriveNumber aDrive)
+TUint CSqlBurCallback::GetExpectedDataSize(TDriveNumber aDrive)
{
UNUSED_ARG(aDrive);
// we have no idea at this point - we even don't know who is to be backed up yet
const TUint KArbitraryNumber = 1024;
- SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETEXPECTEDDATASIZE, "0x%X;CSqlBackupClient::GetExpectedDataSize;aDrive=%d;rc=%u", (TUint)this, (TInt)aDrive, KArbitraryNumber));
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETEXPECTEDDATASIZE, "0x%X;CSqlBurCallback::GetExpectedDataSize;aDrive=%d;rc=%u", (TUint)this, (TInt)aDrive, KArbitraryNumber));
return KArbitraryNumber;
}
-/** This is the backup state machine
- Because the data has to be sent back in sections and the various
- components of the dataflow may straddle chunks, we have to keep
- track of where we are between each transfer - a state machine is
- the simplest and most understandable implementation
- @param TPtr this is where the data will be put to be passed back
- @param TBool set to true when all data has been submitted for backup
- @leave
+/**
+This is the backup state machine
+Because the data has to be sent back in sections and the various
+components of the dataflow may straddle chunks, we have to keep
+track of where we are between each transfer - a state machine is
+the simplest and most understandable implementation.
+
+Please note how the function processes the errors occuring during the backup.
+If an error occurs, the error is not propagated back to the B&R server immediatelly.
+The error is stored in iBurError data member and is reported at the end of the backup process.
+The reason for such unusual error reporting poicy is: the SQL server performs full backup of possibly more
+than one database file. If an error occurs during the backup of the first file for example, the backup
+process should not stop at that point. All files will be processed and then at the end, the error will be reproted.
+
+In details, the function runs a state machine, where:
+ - every file in the list retrieved in InitialiseGetProxyBackupDataL() is opened;
+ - the file is read and 32-bit checksum over the file data - calculated;
+ - a file backup header is prepared, including there the file size, file name, file name length, protocol verison number
+ and the checksum. The header is sent to the backup restore server;
+ - the file data is read and sent to the backup and restore server;
+ - during the described above sequence no leave ever occurs. The error that occurs during the file processing,
+ is stored into a data member of CSqlBurCallback class. At the end, after the last file in the list is processed,
+ the backup and restore server will get a notification (via a User::Leave() call) regarding the error;
+ The used error reporting policy allows all files to be process without interrupting the backup process.
+ For example, if there are 5 files to be sent to the backup and restore server, an error that occurs during the
+ processing of file #3, won't prevent files #4 and #5 from being sent for backup.
+
+@see CSqlBurEventMonitor::RunL()
+@see CSqlBurCallback::InitialiseGetProxyBackupDataL()
+
+@param aBuffer Output parameter, the buffer where the data will be put to be passed back
+@param aFinishedFlag Set to true when all data has been submitted for backup
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
*/
-void CSqlBackupClient::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinishedFlag)
+void CSqlBurCallback::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinishedFlag)
{
- SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL0, "0x%X;CSqlBackupClient::GetBackupDataSectionL;iState=%d;iFileIndex=%d", (TUint)this, (TInt)iState, iFileIndex));
// don't assume they set it to false
aFinishedFlag=EFalse;
// any files to backup
if(iFileList.Count()==0)
{
- SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL1, "0x%X;CSqlBackupClient::GetBackupDataSectionL;file count is 0", (TUint)this));
- // nothing to backup - just return the finished flag
- aFinishedFlag=ETrue;
- // clear down the list
- iFileList.Reset();
- // iFileList closed in dtor
+ // nothing to backup
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL1, "0x%X;CSqlBurCallback::GetBackupDataSectionL;file count is 0", (TUint)this));
+ aFinishedFlag = ETrue;
+ BackupCleanup();
return;
}
@@ -272,21 +413,21 @@
case EBackupNoFileOpen: // open a file for processing
{
if(iFileIndex>=iFileList.Count())
- {
- SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL2, "0x%X;CSqlBackupClient::GetBackupDataSectionL;all files processed", (TUint)this));
- // all files have been processed - send the finished flag
- aFinishedFlag=ETrue;
- // clear down the filelist
- iFileList.Reset();
+ {// all files have been processed - send the finished flag
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL2, "0x%X;CSqlBurCallback::GetBackupDataSectionL;all files processed;iBackupError=%d", (TUint)this, iBackupError));
+ aFinishedFlag = ETrue;
+ BackupCleanup();
+ __SQLLEAVE_IF_ERROR(iBackupError);
return;
}
// open the database file to send
- TInt rc=iFile.Open( iInterface->Fs(), iFileList[iFileIndex].FullName(), EFileRead | EFileShareExclusive);
- __SQLTRACE_BUREXPR(TPtrC fname = iFileList[iFileIndex].FullName());
- SQL_TRACE_BUR(OstTraceExt5(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL3, "0x%X;CSqlBackupClient::GetBackupDataSectionL;BEGIN;fname=%S;iFileIndex=%d;iFile.SubSessionHandle()=0x%X;rc=%d", (TUint)this, __SQLPRNSTR(fname), iFileIndex, (TUint)iFile.SubSessionHandle(), rc));
- if(KErrNone!=rc)
+ TPtrC fname = iFileList[iFileIndex]->Des();
+ TInt err = iFile.Open(iInterface.Fs(), fname, EFileRead | EFileShareExclusive);
+ SQL_TRACE_BUR(OstTraceExt5(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL3, "0x%X;CSqlBurCallback::GetBackupDataSectionL;BEGIN;fname=%S;iFileIndex=%d;iFile.SubSessionHandle()=0x%X;err=%d", (TUint)this, __SQLPRNSTR(fname), iFileIndex, (TUint)iFile.SubSessionHandle(), err));
+ if(KErrNone != err)
{
// there's nothing we can do if we can't open the file so we just skip it
+ SetBackupError(err);
++iFileIndex;
break;
}
@@ -296,28 +437,38 @@
case EBackupOpenNothingSent: // nothing sent (so far) for this file - send the header info
{
TInt64 fileSize;
- if(KErrNone!=iFile.Size(fileSize) || fileSize==0) // short circuit eval
+ TInt err = iFile.Size(fileSize);
+ if(KErrNone != err)
{
- // empty or unreadable - skip this file
- iState=EBackupEndOfFile;
+ SetBackupError(err);
+ iState = EBackupEndOfFile;
break;
}
- // get the checksum - only grab last 4 bytes - enough to be satisfied that
- // the backup and restore worked ok
- TUint32 checksum = CheckSumL(iFile) & KMaxTUint32;
+ TUint64 checksum64 = 0;
+ err = CheckSum(iFile, checksum64);
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL4, "0x%X;CSqlBurCallback::GetBackupDataSectionL;CheckSum();iFileIndex=%d;err=%d", (TUint)this, iFileIndex, err));
+ if(err != KErrNone)
+ {
+ //An error occured while reading the file (or there was not enough memory for the read buffer)
+ SetBackupError(err);
+ iState = EBackupEndOfFile;
+ break;
+ }
+ // Only grab last 4 bytes of the checksum - enough to be satisfied that the backup and restore worked ok
+ TUint32 checksum32 = checksum64 & KMaxTUint32;
// build the header - this is an instance member because it
// has to persist over multiple calls to this method
- const TDesC& fileName = iFileList[iFileIndex].FullName();
+ TPtrC fname = iFileList[iFileIndex]->Des();
iBuffer.Format(_L("%8x%8x%4x%16lx%8x%S"),
- checksum, // %8x
- KMagicNum, // %8x
- KBackupHeaderVersion, // %4x
+ checksum32, // %8x
+ KSqlBurMagicNum, // %8x
+ KSqlBurHeaderVersion, // %4x
fileSize, // %16lx
- fileName.Length(), // %8x
- &fileName); // %S
- SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL5, "0x%X;CSqlBackupClient::GetBackupDataSectionL;fileName=%S;hdrPtr=|%S|;fileSize=%lld", (TUint)this, __SQLPRNSTR(fileName), __SQLPRNSTR(iBuffer), fileSize));
+ fname.Length(), // %8x
+ &fname); // %S
+ SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL5, "0x%X;CSqlBackupClient::GetBackupDataSectionL;fileName=%S;hdrPtr=|%S|;fileSize=%lld", (TUint)this, __SQLPRNSTR(fname), __SQLPRNSTR(iBuffer), fileSize));
// we need it to look like an 8bit buffer
TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size());
@@ -372,7 +523,15 @@
case EBackupOpenAllHeaderSent: // need to send some data
{
TPtr8 ptr((TUint8*)aBuffer.Ptr() + aBuffer.Size(), 0, bufFreeSpace);
- __SQLLEAVE_IF_ERROR(iFile.Read(ptr));
+ TInt err = iFile.Read(ptr);
+ if(err != KErrNone)
+ {
+ //An error occured while reading the file
+ SetBackupError(err);
+ iState = EBackupEndOfFile;
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL6, "0x%X;CSqlBurCallback::GetBackupDataSectionL;File read;iFileIndex=%d;err=%d", (TUint)this, iFileIndex, err));
+ break;
+ }
TInt bytesRead = ptr.Size();
aBuffer.SetLength(aBuffer.Size() + bytesRead);
// EOF
@@ -385,83 +544,119 @@
}
case EBackupEndOfFile:
{
- SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL4, "0x%X;CSqlBackupClient::GetBackupDataSectionL;END;iFile.SubSessionHandle()=0x%X;iFileIndex=%d", (TUint)this, (TUint)iFile.SubSessionHandle(), iFileIndex));
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL7, "0x%X;CSqlBurCallback::GetBackupDataSectionL;END;iFile.SubSessionHandle()=0x%X;iFileIndex=%d", (TUint)this, (TUint)iFile.SubSessionHandle(), iFileIndex));
iFile.Close();
++iFileIndex; // move on to next file
iState = EBackupNoFileOpen; // go round again
break;
}
default:
- {
+ __ASSERT_DEBUG(EFalse, __SQLPANIC(ESqlPanicInternalError));
break;
- }
}//end of the "switch" statement
}//end of the "for" statement
}
-/** This is called by BUE when the restore has completed
- Nothing to do here except tell the server
- @param TDrive the drive that is being restored (unused)
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////// Full restore /////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Called when the BUE wants to start sending data to us.
+Creates the folder (if the folder does not exist) where the temporary files will be created during the restore process.
+Deletes all files from the restore folder.
+
+The restore is initiated by a notification received in CSqlBurEventMonitor::RunL() method.
+InitialiseRestoreProxyBaseDataL() is called once per {client secure id, drive} and each
+InitialiseRestoreProxyBaseDataLL() call is followed after that by a set of CSqlBurCallback::RestoreBaseDataSectionL()
+calls, made from the backup and restore client dll.
+
+During RestoreBaseDataSectionLL() calls the CSqlBurCallback object will receive data from the backup and resore server.
+
+@see CSqlBurEventMonitor::RunL()
+@see CSqlBurCallback::RestoreBaseDataSectionL()
+
+@param aSid the UID of the application that is to be restored. Not used (only logged in OST builds).
+@param aDrive the drive to restore.
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
*/
-void CSqlBackupClient::RestoreComplete(TDriveNumber aDrive)
+void CSqlBurCallback::InitialiseRestoreProxyBaseDataL(TSecureId aSid, TDriveNumber aDrive)
{
+ UNUSED_ARG(aSid);
UNUSED_ARG(aDrive);
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTORECOMPLETE, "0x%X;CSqlBackupClient::RestoreComplete;aDrive=%d", (TUint)this, (TInt)aDrive));
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZERESTOREPROXYBASEDATAL, "0x%X;CSqlBurCallback::InitialiseRestoreProxyBaseDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
+ iBuffer.Zero();
+ iState = ERestoreExpectChecksum;
+ iRestoreDrive = aDrive;
+ iRestoreId = aSid;
+ //Create the directory for the temporary files created during the restore process.
+ TFileName privatePath;
+ __SQLLEAVE_IF_ERROR(iInterface.Fs().PrivatePath(privatePath));
+ TDriveUnit driveUnit(iRestoreDrive);
+ TDriveName driveName = driveUnit.Name();
+ privatePath.Insert(0, driveName);
+ __SQLLEAVE_IF_ERROR(iParse.Set(KSqlBurRestoreDir, &privatePath, 0));
+ iRestoreDir.Copy(iParse.FullName());
+ iRestoreDir.Append(KPathDelimiter);
+ TInt err = iInterface.Fs().MkDirAll(iRestoreDir);
+ if(err != KErrAlreadyExists)
+ {
+ __SQLLEAVE_IF_ERROR(err);
+ }
+ //Cleanup the restore directory
+ err = RestoreCleanup();
+ if(err != KErrNotFound)
+ {
+ __SQLLEAVE_IF_ERROR(err);
+ }
}
-/** This is called to let us know that the given SID is to be backed up
- We ask the SQL server for a list of databases that want to be backed
- up - this is because the backup flag is an internal metadata object
- in the database, and to decouple we don't want to have to know how
- this data is stored.
- @param TSecureSid the UID of the application to backup
- @param TDriveNumber the drive to be backed up (unused)
- @leave
+/**
+This is called by BUE when the restore has completed.
+
+@see CSqlBurEventMonitor::RunL()
+@see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
+
+@param aDrive the drive that is being restored. Not used (only logged in OST builds).
*/
-void CSqlBackupClient::InitialiseGetProxyBackupDataL(TSecureId aSid, TDriveNumber aDrive)
+void CSqlBurCallback::RestoreComplete(TDriveNumber aDrive)
{
UNUSED_ARG(aDrive);
- SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZEGETPROXYBACKUPDATAL, "0x%X;CSqlBackupClient::InitialiseGetProxyBackupDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
- // get the list of database files to back up - this is provided by the SQL server
- GetBackupListL(aSid);
- // this is the index of the file being processed - point to the beginning
- iFileIndex=0;
- // the first state of the backup state machine
- iState=EBackupNoFileOpen;
- // save the sid for notifying the server when the backup is complete
- iSid=aSid;
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTORECOMPLETE, "0x%X;CSqlBurCallback::RestoreComplete;aDrive=%d", (TUint)this, (TInt)aDrive));
+ iRestoreDrive = TDriveNumber(-1);
+ iRestoreId = TSecureId(KNullUid);
}
-/** Called when the BUE wants to start sending data to us
- @param TSecureId the UID of the application that is to be restored
- @param TDriveNumber the drive to restore (unused)
- @leave
+/**
+This is repeatedly called by the BUE to send us chunks of restore data (for the current SID)
+Becuase the data is spread over chunks we need to manage the state across mutiple calls
+to this method so we use a state machine.
+
+The function runs the state machine and for each file block detected in the coming data, the function does:
+ - creates a temporary file in the restore directory (created by InitialiseRestoreProxyBaseDataL());
+ - stores the file data in the created temporary file;
+ - During the 2 steps descirbed above, if an error occurs, that erro will be reproted to the backup and restore
+ server (via a User::Leave() call);
+ - When all data is received and stored in temporary files in the restore directory,
+ for each received file the function will:
+ = move the original database file to the restore directory with a ".bak" extension added to the file name;
+ = move the temporary file, which has the same name as the original database file, to the location of the
+ original database file - the SQL server private data cage;
+ = delete the file with the ".bak" extension;
+ The three steps described above are implemented as "all or none" operation - if an error occurs during step (2),
+ the content of the original database file will be restored from the file with the ".bak" extension.
+
+@see CSqlBurEventMonitor::RunL()
+@see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
+
+@param aInBuffer Buffer with data to be restored
+@param aFinishedFlag Set when there is not more data to restore
+@leave KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also leave with some other system-wide error codes.
*/
-void CSqlBackupClient::InitialiseRestoreProxyBaseDataL(TSecureId aSid, TDriveNumber aDrive)
+void CSqlBurCallback::RestoreBaseDataSectionL(TDesC8& aInBuffer, TBool aFinishedFlag)
{
- UNUSED_ARG(aDrive);
- SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZERESTOREPROXYBASEDATAL, "0x%X;CSqlBackupClient::InitialiseRestoreProxyBaseDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
- iBuffer.Zero();
- // this is the first state of the restore state machine
- iState=ERestoreExpectChecksum;
- iAnyData=EFalse; // to keep track in the state machine whether any data was actually sent
- // save the sid for notifying the server when the restore is done
- iSid=aSid;
- }
-
-/** This is repeatedly called by the BUE to send us chunks of restore data (for the current SID)
- Becuase the data is spread over chunks we need to manage the state across mutiple calls
- to this method so we use a state machine
- @leave KErrCorrupt if the data is incomplete or the checksum fails
- @param TDesc8 the data to be restored
- @param TBool set when there is not more data to restore
-
-Attention!!! This function won't work properly if aInBuffer parameter contains odd number of bytes!!!
-(a legacy problem, if it is a problem at all, because the B&R engine probably sends the data in chunks with even size)
-*/
-void CSqlBackupClient::RestoreBaseDataSectionL(TDesC8& aInBuffer, TBool aFinishedFlag)
- {
- SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL0, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;iState=%d;aInBuffer.Length()=%d;aFinishedFlag=%d", (TUint)this, (TInt)iState, aInBuffer.Length(), (TInt)aFinishedFlag));
// used to walk the buffer
// got a new buffer - because each time this method is called, we have a
// fresh chunk of data
@@ -471,16 +666,14 @@
TBool done = EFalse;
// check whether this is an empty restore
- if(aFinishedFlag && !iAnyData)
+ if(aFinishedFlag && aInBuffer.Size() == 0)
{
- // we have to do this and not rely on aFinishedFlag alone, becuase
- // if aFinished is used, we'll process the last state of the machine
- // which does tidyup, except that if there was no data, no tidyup should
- // be done
return;
}
-
- // run the machine
+
+ TInt iterations = 0;
+
+ // run the state machine
do
{
// how many bytes are there available in the buffer for processing?
@@ -493,18 +686,6 @@
// so we return and wait for more data to arrive
return;
}
- if(aFinishedFlag && iState != ERestoreComplete && iState != ERestoreExpectData)
- {
- // ran out of data early
- // will be ERestoreComplete if data not aligned on 128
- // will be ERestoreExpectData if data aligned on 128
- __SQLLEAVE(KErrCorrupt);
- }
- // yep there was some data in the chunk if we got here
- if(bytesAvailable > 0)
- {
- iAnyData = ETrue;
- }
switch(iState)
{
case ERestoreExpectChecksum: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for the checksum)
@@ -526,7 +707,7 @@
if(iBuffer.Length() == KOldFileSizeStrLen)
{
TUint32 oldFileSize = ::GetNumUint32L(iBuffer);
- if(oldFileSize == KMagicNum)
+ if(oldFileSize == KSqlBurMagicNum)
{
iState = ERestoreExpectVersion;
}
@@ -562,7 +743,7 @@
iState = ERestoreExpectFileNameSize;
iBuffer.Zero();
}
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL1, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;iFileSize=%lld", (TUint)this, iFileSize));
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL1, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;iFileSize=%lld", (TUint)this, iFileSize));
break;
}
case ERestoreExpectFileNameSize: // the size of the file name to restore
@@ -580,17 +761,17 @@
case ERestoreExpectFileName: // the name of the file to restore
{
CopyBufData(aInBuffer, inBufferPos, iBuffer, iFileNameSize);
- SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL2, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;BEGIN;iBuffer=%S;iBuffer.Length()=%d;iFileNameSize=%d", (TUint)this, __SQLPRNSTR(iBuffer), iBuffer.Length(), iFileNameSize));
+ SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL2, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;BEGIN;iBuffer=%S;iBuffer.Length()=%d;iFileNameSize=%d", (TUint)this, __SQLPRNSTR(iBuffer), iBuffer.Length(), iFileNameSize));
if(iBuffer.Length() == iFileNameSize)
{
iState = ERestoreExpectData;
- iBuffer.Append(KRestoreSuffix);
- // now we start writing the data to the target file
- // write to a temp - double disk space potentially
- // once all the temp files are created, then they are renamed to the
- // real file names in one fell swoop
- __SQLLEAVE_IF_ERROR(iFile.Replace(iInterface->Fs(), iBuffer, EFileWrite | EFileShareExclusive));
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL3, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
+ TParse parse;
+ __SQLLEAVE_IF_ERROR(parse.Set(iBuffer, 0, 0));
+ __SQLLEAVE_IF_ERROR(iParse.Set(parse.NameAndExt(), &iRestoreDir, 0));
+ TPtrC fname(iParse.FullName());
+ //The database is restored first to a temporary file, in the restore folder, on the same drive.
+ __SQLLEAVE_IF_ERROR(iFile.Replace(iInterface.Fs(), fname, EFileWrite | EFileShareExclusive));
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL3, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;fname=%S;iFile.SubSessionHandle()=0x%X", (TUint)this, __SQLPRNSTR(fname), (TUint)iFile.SubSessionHandle()));
iBuffer.Zero();
}
break;
@@ -598,7 +779,12 @@
case ERestoreExpectData: // now for the data
{
TInt len = Min((aInBuffer.Size() - inBufferPos), iFileSize);
- __SQLLEAVE_IF_ERROR(iFile.Write(aInBuffer.Mid(inBufferPos, len)));
+ TInt err = iFile.Write(aInBuffer.Mid(inBufferPos, len));
+ if(err != KErrNone)
+ {
+ (void)RestoreCleanup();
+ __SQLLEAVE(err);
+ }
inBufferPos += len;
iFileSize -= len;
if(iFileSize == 0)
@@ -609,286 +795,285 @@
}
case ERestoreComplete: // file completely restored
{
- // calculate the checksum
- TUint32 cksum = CheckSumL(iFile) & KMaxTUint32;
-
- // done with the file now - has to follow checksum cos it
- // expects ann open file
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL4, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;END;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
- __SQLLEAVE_IF_ERROR(iFile.Flush());
+ TUint64 checkSum64 = 0;
+ TInt restoreErr = iFile.Flush();
+ if(restoreErr == KErrNone)
+ {
+ // calculate the checksum
+ restoreErr = CheckSum(iFile, checkSum64);
+ }
iFile.Close();
-
- // validate that the checksum matches
- if(cksum!=iChecksum)
+ if(restoreErr != KErrNone)
+ {
+ (void)RestoreCleanup();
+ __SQLLEAVE(restoreErr);
+ }
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL4, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;END;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
+ TUint32 checkSum32 = checkSum64 & KMaxTUint32;
+ if(checkSum32 != iChecksum)
{
+ (void)RestoreCleanup();
__SQLLEAVE(KErrCorrupt);
}
-
- // end of data - or another file to be restored?
- if(aFinishedFlag)
+ if((aInBuffer.Size() - inBufferPos) > 0)
+ {//There are bytes to be consumed in the input buffer
+ iState = ERestoreExpectChecksum;
+ break;
+ }
+ SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL5, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;aFinishedFlag=ETrue", (TUint)this));
+ //End of data. We have all data restored in the restore folder.
+ //The final step of the "restoring files" process consists of the following sub-steps:
+ // - Rename the database file to be restored to a file with ".bak" extension
+ // - Rename the file with the restored data to the database file
+ // - Delete the file with ".bak" extension
+ //Do not leave during the restore process! Restore as much files as possible.
+ //The only excpetion is TParse::Set() - if it fails it is a fatal error, the
+ //restored file path cannot be constructed.
+ __ASSERT_DEBUG(iRestoreDrive != TDriveNumber(-1), __SQLPANIC(ESqlPanicInternalError));
+ __ASSERT_DEBUG(iRestoreId != TSecureId(KNullUid), __SQLPANIC(ESqlPanicInternalError));
+ //Include the aUid and the "*" mask
+ TUidName uidName = (static_cast <TUid> (iRestoreId)).Name();
+ TBuf<KMaxUidName + sizeof(KSqlBurAllFiles)> fileNameMask(uidName);
+ fileNameMask.Append(KSqlBurAllFiles);
+ __SQLLEAVE_IF_ERROR(iParse.Set(fileNameMask, &iRestoreDir, 0));
+ CDir* dir = NULL;
+ TPtrC searchPattern(iParse.FullName());
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL55, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;search pattern=%S", (TUint)this, __SQLPRNSTR(searchPattern)));
+ restoreErr = iInterface.Fs().GetDir(searchPattern, KEntryAttNormal, ESortNone, dir);
+ if(restoreErr == KErrNone)
{
- // we need to rename all the
- // temp rst files to the real database names
- CDir *dir=NULL;
- __SQLLEAVE_IF_ERROR(iInterface->Fs().GetDir(KRestoreFilter,KEntryAttNormal,ESortNone,dir));
- CleanupStack::PushL(dir);
- TInt err2 = KErrNone;
- for(TInt a=0;a<dir->Count();++a)
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL6, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;restored files=%d", (TUint)this, dir->Count()));
+ for(TInt i=0;i<dir->Count();++i)
{
- TEntry entry=(*dir)[a];
- TPtrC rst=entry.iName.Des();
- TInt len=rst.Length();
- // format <filename>.db.bak.rst
- // just a convenience!
- TPtrC bak(rst.Left(len - 4));//".rst" part excluded
- TPtrC db(rst.Left(len - 8));//".bak.rst" part excluded
-
- // first, rename the orig .db as .bak just in case
- // ok if not found - might have been deleted.
- //the ".bak" file, if exists, will be deleted first.
- (void)iInterface->Fs().Delete(bak);
- TInt err=iInterface->Fs().Rename(db,bak);
- SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL5, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;END;bak=%S;db=%S;err=%d", (TUint)this, __SQLPRNSTR(bak), __SQLPRNSTR(db), err));
+ const TEntry& entry = (*dir)[i];
+ __SQLLEAVE_IF_ERROR(iParse.Set(entry.iName, &iRestoreDir, 0));
+ TFileName dbName(iParse.FullName());
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL7, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;restored file=%S", (TUint)this, __SQLPRNSTR(dbName)));
+ TInt pos = dbName.Find(KSqlBurRestoreDir);
+ __ASSERT_DEBUG(pos >= 0, __SQLPANIC(ESqlPanicInternalError));
+ dbName.Delete(pos, KSqlBurRestoreDir().Length() + 1);//"+1" for the path delimitier
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL8, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;database=%S", (TUint)this, __SQLPRNSTR(dbName)));
+ TFileName bakDbName(iParse.FullName());
+ bakDbName.Append(KSqlBurBackupExt);
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL9, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;backup file=%S", (TUint)this, __SQLPRNSTR(dbName)));
+ //Now, dbName contains the original database (full path), iParse - the restored file,
+ //bakDbName - backup file name
+ TInt err = iInterface.Fs().Rename(dbName, bakDbName);
if(err == KErrNone || err == KErrNotFound)
{
- // now, rename the .rst as .db
- err = iInterface->Fs().Rename(rst,db);
- }
- if(err != KErrNone && err2 == KErrNone)
- {
- //The idea here is to not report the error immediatelly by calling LeaveIfError().
- //If we leave here, the next database restore may also fail, for example, if the current database is still open by
- //its owner. Then "TInt err=iInterface->Fs().Rename(db,bak);" will fail again.
- err2 = err;
+ err = iInterface.Fs().Rename(iParse.FullName(), dbName);
+ if(err == KErrNone)
+ {//commit: delete the backup database file
+ SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL10, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;Commit;file=%S", (TUint)this, __SQLPRNSTR(dbName)));
+ (void)iInterface.Fs().Delete(bakDbName);
+ }
+ else
+ {//rollback: restore the original database file
+ err = iInterface.Fs().Rename(bakDbName, dbName);
+ SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL11, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;Rollback;file=%S;err=%d", (TUint)this, __SQLPRNSTR(dbName), err));
+ }
}
- // if we got here, we have a backup of the original database in .db.bak
- // and the new database in .db
- }//end of for(...)
- __SQLLEAVE_IF_ERROR(err2);
-
- // clean up dir
- //delete dir;
- CleanupStack::PopAndDestroy(dir);
- dir=NULL;
-
- // now delete all the .bak files
- // we do this here and not part of the earlier loop
- // because we want to make sure that we have a coherent set of database
- // files that belong together and not bits of old and new
- __SQLLEAVE_IF_ERROR(iInterface->Fs().GetDir(KBackupFilter,KEntryAttNormal,ESortNone,dir));
- CleanupStack::PushL(dir);
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL6, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;bak files count=%d", (TUint)this, dir->Count()));
- for(TInt a1=0;a1<dir->Count();++a1)
- {
- TEntry entry=(*dir)[a1];
- TPtrC bak=entry.iName.Des();
- __SQLLEAVE_IF_ERROR(iInterface->Fs().Delete(bak));
- }
-
- // clean up dir
- //delete dir;
- CleanupStack::PopAndDestroy(dir);
- dir=NULL;
- done=ETrue;
+ if(err != KErrNone && err != KErrNotFound)
+ {
+ if(restoreErr == KErrNone)
+ {
+ restoreErr = err;
+ }
+ }
+ }//for(...)
+ delete dir;
+ }//iInterface.Fs().GetDir(...)
+ done = ETrue;
+ (void)RestoreCleanup();
+ if(restoreErr != KErrNone)
+ {
+ __SQLLEAVE(restoreErr);
}
- else
- {
- iState=ERestoreExpectChecksum;
- }
-
break;
}
default:
+ __ASSERT_DEBUG(EFalse, __SQLPANIC(ESqlPanicInternalError));
break;
+ }//switch(...)
+ if((aInBuffer.Size() - inBufferPos) == bytesAvailable)
+ {//No bytes have been consumed from the buffer.
+ if(++iterations > 1 && !done)
+ {//This is the second iteration in the loop where no bytes have been consumed from the input buffer.
+ //But the "done" flag is still false. Corrupted archive.
+ __SQLLEAVE(KErrCorrupt);
+ }
}
} while(!done);
}
-/** The operation was terminated - we should tidyup here (as best we can)
- Nothing needs to be done for a backup. Restore is more
- complicated in the case of an interruption.
- What we need to do here is move all the backup files
- back to being db files....
+/**
+The operation was terminated - we should tidyup here (as best we can)
+Backup: close the file, free the allocated memory for the file names.
+Restore: since the final restore step is a non-leaving one, nothing special needs to be done here -
+RestoreCleanup() is called to close the file and delete if there are any temporary files left.
*/
-void CSqlBackupClient::TerminateMultiStageOperation()
+void CSqlBurCallback::TerminateMultiStageOperation()
{
- // backup/restore terminated, try to tidy up! Can't leave, can't Panic!!!!!
- // rename all the .bak files to .db
- CDir *dir=NULL;
- TInt rc=iInterface->Fs().GetDir(KBackupFilter,KEntryAttNormal,ESortNone,dir);
- SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_TERMINATEMULTISTAGEOPERATION1, "0x%X;CSqlBackupClient::TerminateMultiStageOperation;Fs().GetDir() err=%d;file count=%d", (TUint)this, rc, rc == KErrNone ? dir->Count() : 0));
- if(KErrNone!=rc)
- {
- // can't get a file list - can't do anything
- return;
- }
- for(TInt a=0;a<dir->Count();++a)
- {
- TEntry entry=(*dir)[a];
- TPtrC bak=entry.iName.Des();
- TInt len=bak.Length();
- TPtrC db(bak.Left(len-4));//".bak" part excluded
- rc=iInterface->Fs().Delete(db); // rename does not overwrite
- if(KErrNone == rc)
- {
- rc = iInterface->Fs().Rename(bak,db);
- }
- //The function cannot leave or return an error. The only thing which could be done here is to print out something
- //and continue with the next file.
- if(KErrNone != rc)
- {
- SQL_TRACE_BUR(OstTraceExt4(TRACE_INTERNALS, CSQLBACKUPCLIENT_TERMINATEMULTISTAGEOPERATION2, "0x%X;CSqlBackupClient::TerminateMultiStageOperation;Fs().Rename() err=%d;bak=%S;db=%S", (TUint)this, rc, __SQLPRNSTR(bak), __SQLPRNSTR(db)));
- }
- // backup restored ok
- }
- // cleanup dir
- delete dir;
+ BackupCleanup();
+ (void)RestoreCleanup();
}
-/** We do our own checksumming so we don't need this
- @return the checksum
- @param TDriveNumber the drive affected (unused)
+/**
+We do our own checksumming so we don't need this
+@return the checksum
+@param aDrive the drive affected (unused)
*/
-TUint CSqlBackupClient::GetDataChecksum(TDriveNumber /* aDrive */)
+TUint CSqlBurCallback::GetDataChecksum(TDriveNumber /* aDrive */)
{
// not required - not implemented
const TUint KArbitraryNumber = 1024;
return KArbitraryNumber;
}
-/** We don't support incremental backup
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////// Incremental backup/restore ////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */,
- TBool& /* aFinishedFlag */)
+void CSqlBurCallback::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */, TBool& /* aFinishedFlag */)
{
- // incremental backup not supported
__SQLLEAVE(KErrNotSupported);
}
-/** We don't support incremental backup
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::InitialiseGetBackupDataL(TDriveNumber /* aDrive */)
+void CSqlBurCallback::InitialiseGetBackupDataL(TDriveNumber /* aDrive */)
{
- // incremental backup not supported
__SQLLEAVE(KErrNotSupported);
}
-/** We don't support incremental backup
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */)
+void CSqlBurCallback::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */)
{
- // incremental backup not supported
__SQLLEAVE(KErrNotSupported);
}
-/** We don't support incremental backup
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */)
+void CSqlBurCallback::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */)
{
- // incremental backup not supported
__SQLLEAVE(KErrNotSupported);
}
-/** We don't support incremental backup
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
+void CSqlBurCallback::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
{
- // incremental backup not supported
__SQLLEAVE(KErrNotSupported);
}
-/** We don't support incremental backup
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::AllSnapshotsSuppliedL()
+void CSqlBurCallback::AllSnapshotsSuppliedL()
{
- // incremental backup not supported
- // cannot leave or panic!
}
-/** We don't support incremental backup
+/**
+We don't support incremental backup
*/
-void CSqlBackupClient::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */,
- TBool /* aFinishedFlag */)
+void CSqlBurCallback::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
{
- // incremental backup not supported
__SQLLEAVE(KErrNotSupported);
}
-/**
- Get a list of database files that need to be backed up
- This is decided by the SQL server on the basis of the UID provided
- and whether the metadata in the database indicates that this data
- should be backed up or not. The list of database files is populated
- into the iFileList array.
- @leave
- @param TSecureSid the UID of the data owner
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////// Helper functions //////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+A simple checksumming algorithm to allow a degree
+of trust that the backup and restore worked.
+Note the file pointer will be back at the start when the function call completes successfully.
+In case of an error, the position of the file pointer is undetermined.
+
+@param aOpenFile Already opened database file on which the checksum is calculated.
+@param aCheckSum Output parameter. The checksum is returned in this parameter.
+@return KErrNoMemory, an out of memory condition has occurred;
+ Note that the function may also return some other system-wide error codes.
*/
-void CSqlBackupClient::GetBackupListL(TSecureId aSid)
- {
- SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPLISTL, "0x%X;CSqlBackupClient::GetBackupListL;aSid=0x%X", (TUint)this, (TUint)aSid.iId));
- // we own the array - the SQL server just populates it
- iInterface->GetBackUpListL(aSid,iFileList);
- }
-
-/** A simple checksumming algorithm to allow a degree
- of trust that the backup and restore worked
- This is visble externally because the test harness
- needs to use it - NOTE the file pointer will be back at the
- start when this function ends.
- @leave
- @param RFile64 an OPEN file to checksum
-*/
-TUint64 CSqlBackupClient::CheckSumL(const RFile64& aOpenFile) const
+TInt CSqlBurCallback::CheckSum(const RFile64& aOpenFile, TUint64& aCheckSum) const
{
// scoot through the database file building the checksum
- TInt64 seekPos=0; // rewind first
- __SQLLEAVE_IF_ERROR(aOpenFile.Seek(ESeekStart,seekPos));
- TUint64 total=0;
+ aCheckSum = 0;
+ TInt64 seekPos = 0; // rewind first
+ TInt err = aOpenFile.Seek(ESeekStart, seekPos);
+ if(err != KErrNone)
+ {
+ return err;
+ }
const TUint KCheckSumBlockSize = 4 * 1024;
- HBufC8* block=HBufC8::NewLC(KCheckSumBlockSize);
- TPtr8 ptr=block->Des();
+ HBufC8* buf = HBufC8::New(KCheckSumBlockSize);
+ if(!buf)
+ {
+ return KErrNoMemory;
+ }
+ TPtr8 ptr = buf->Des();
for(;;)
{
- __SQLLEAVE_IF_ERROR(aOpenFile.Read(ptr));
- TInt len=ptr.Length();
- if(len==0)
+ err = aOpenFile.Read(ptr);
+ if(err != KErrNone)
+ {
+ delete buf;
+ return err;
+ }
+ TInt len = ptr.Length();
+ if(len == 0)
{
break;
}
// calculate the checksum
for(TInt i=0;i<len;++i)
{
- total = (total << 1) | (total >> 63);
- total += ptr[i];
+ aCheckSum = (aCheckSum << 1) | (aCheckSum >> 63);
+ aCheckSum += ptr[i];
}
};
- CleanupStack::PopAndDestroy(block);
+ delete buf;
// restore file position
- seekPos=0;
- __SQLLEAVE_IF_ERROR(aOpenFile.Seek(ESeekStart,seekPos));
- return total;
+ seekPos = 0;
+ err = aOpenFile.Seek(ESeekStart,seekPos);
+ return err;
}
-//Reads the content of aInBuf from position aInBufReadPos and stores the data into aOutBuf.
-//aDataLen is the length of the data. If the input buffer does not contain all the data, then only the
-//available data will be copied to the output buffer.
-//
-//Attention!!! This function won't work properly if aInBuf parameter contains odd number of bytes!!!
-//(a legacy problem, if it is a problem at all, because the B&R engine probably sends the data in chunks with even size)
-//
-//How the function works. It is called during the restore process and aInBuf parameter contains a block of raw
-//data sent by the B&R server. The calling function, RestoreBaseDataSectionL(), uses a state
-//machine to processes the incoming data. At particular moment RestoreBaseDataSectionL() will process the data header
-//and will have to read "aDataLen" 16-bit characters at position "aInBufReadPos". If there are "aDataLen" characters
-//at position "aInBufReadPos" and enough free space in "aOutBuf", CopyBufData() will copy all of them,
-//otherwise CopyBufData() will copy as much characters as possible (in which case RestoreBaseDataSectionL() will
-//stay in the same state, waiting for more data from the B&R server).
-//
-void CSqlBackupClient::CopyBufData(const TDesC8& aInBuf, TInt& aInBufReadPos, TDes& aOutBuf, TInt aDataLen)
+/**
+Reads the content of aInBuf from position aInBufReadPos and stores the data into aOutBuf.
+aDataLen is the length of the data. If the input buffer does not contain all the data, then only the
+available data will be copied to the output buffer.
+
+How the function works. It is called during the restore process and aInBuf parameter contains a block of raw
+data sent by the B&R server. The calling function, RestoreBaseDataSectionL(), uses a state
+machine to processes the incoming data. At particular moment RestoreBaseDataSectionL() will process the data header
+and will have to read "aDataLen" 16-bit characters at position "aInBufReadPos". If there are "aDataLen" characters
+at position "aInBufReadPos" and enough free space in "aOutBuf", CopyBufData() will copy all of them,
+otherwise CopyBufData() will copy as much characters as possible (in which case RestoreBaseDataSectionL() will
+stay in the same state, waiting for more data from the B&R server).
+
+@param aInBuf 8-bit buffer with input data
+@param aInBufReadPos The position in the buffer from which the read operation starts.
+ When the "buffer read" operatio completes, aInBufReadPos is updated with the
+ number of bytes read from the input buffer.
+@param aOutBuf 16-bit output buffer. The data read from the input buffer is stored in the output buffer.
+@param aDataLen How much bytes to be read from the input buffer. Note that if there is not enough
+ data in the input buffer, the function will read as much as possible from the input buffer.
+ The aInBufReadPos in/out parameter will be updated with the actual number of bytes read.
+*/
+void CSqlBurCallback::CopyBufData(const TDesC8& aInBuf, TInt& aInBufReadPos, TDes& aOutBuf, TInt aDataLen)
{
__ASSERT_DEBUG(aInBufReadPos >= 0, __SQLPANIC(ESqlPanicBadArgument));
__ASSERT_DEBUG(aDataLen > 0, __SQLPANIC(ESqlPanicBadArgument));
- __ASSERT_DEBUG(!(aInBuf.Length() & 0x01), __SQLPANIC(ESqlPanicInternalError));
TInt needed = (aDataLen - aOutBuf.Length()) << K8to16bitShift;
TInt available = aInBuf.Size() - aInBufReadPos;
@@ -899,3 +1084,59 @@
len >>= K8to16bitShift;
aOutBuf.Append((const TUint16*)ptr8.Ptr(), len);
}
+
+/**
+Cleans up the allocated during the backup resources - file handles, buffers allocated for the file names.
+*/
+void CSqlBurCallback::BackupCleanup()
+ {
+ for(TInt i=0;i<iFileList.Count();++i)
+ {
+ delete iFileList[i];
+ }
+ iFileList.Close();
+ iFile.Close();
+ }
+
+/**
+Deletes created during the restore temporary files.
+*/
+TInt CSqlBurCallback::RestoreCleanup()
+ {
+ if(iRestoreDir.Find(KSqlBurRestoreDir) < 0)
+ {//iRestoreDir is not initialized - that means RestoreCleanup() was called either from the
+ //destructor or from the TerminateMultistageOperation() during a backup.
+ return KErrNone;
+ }
+ iFile.Close();
+ CFileMan* fm = NULL;
+ TRAPD(err, fm = CFileMan::NewL(iInterface.Fs()));
+ if(err == KErrNone)
+ {
+ TFileName allFiles;
+ allFiles.Copy(iRestoreDir);
+ allFiles.Append(KSqlBurAllFiles);
+ err = fm->Delete(allFiles);
+ delete fm;
+ }
+ return err;
+ }
+
+/**
+Stores the error occured during backup for furhter processing.
+Please note that the function asserts if the aError parameter is KErrNone.
+Call the function only with a real error.
+
+@param aError The backup error to be stored
+*/
+void CSqlBurCallback::SetBackupError(TInt aError)
+ {
+ __ASSERT_DEBUG(aError != KErrNone, __SQLPANIC(ESqlPanicBadArgument));
+ if(aError != KErrNotFound && aError != KErrPathNotFound)
+ {
+ if(iBackupError == KErrNone || aError == KErrDiskFull || aError == KErrCorrupt)
+ {
+ iBackupError = aError;
+ }
+ }
+ }