persistentstorage/sql/SRC/Server/SqlBur.cpp
changeset 51 7d4490026038
parent 40 b8bdbc8f59c7
child 55 44f437012c90
equal deleted inserted replaced
40:b8bdbc8f59c7 51:7d4490026038
    21 #endif
    21 #endif
    22 #include "SqlTraceDef.h"
    22 #include "SqlTraceDef.h"
    23 
    23 
    24 #define UNUSED_ARG(arg) arg = arg
    24 #define UNUSED_ARG(arg) arg = arg
    25 
    25 
       
    26 _LIT(KSqlBurBackupExt,  ".bak");
       
    27 _LIT(KSqlBurRestoreDir, "temprestore");
       
    28 _LIT(KSqlBurAllFiles,   "*");
       
    29 
       
    30 const TUint K8to16bitShift = 1;
       
    31 
    26 //Extracts and returns 32-bit integer from aNumBuf buffer.
    32 //Extracts and returns 32-bit integer from aNumBuf buffer.
    27 static TUint32 GetNumUint32L(const TDesC& aNumBuf)
    33 static TUint32 GetNumUint32L(const TDesC& aNumBuf)
    28 	{
    34 	{
    29 	TLex lex(aNumBuf);
    35 	TLex lex(aNumBuf);
    30 	lex.SkipSpace();
    36 	lex.SkipSpace();
    42 	__SQLLEAVE_IF_ERROR2(lex.Val(num, EHex));
    48 	__SQLLEAVE_IF_ERROR2(lex.Val(num, EHex));
    43 	return num;
    49 	return num;
    44 	}
    50 	}
    45 
    51 
    46 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    52 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    47 
    53 ///////////////////////////////   CSqlBurEventMonitor    //////////////////////////////////////////////////////////
    48 // string consts
    54 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    49 _LIT(KRestoreFilter,"*.rst"); // the filter for restore files
    55 
    50 _LIT(KBackupFilter,"*.bak");// the filter for backup files
    56 /** 
    51 _LIT(KRestoreSuffix,".bak.rst"); // the suffix for restore files (a shortcut by using double suffix :)
    57 Standard two phase construction. Creates a CSqlBurEventMonitor instance.
    52 
    58 @param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
    53 const TUint K8to16bitShift = 1;
    59 @return An instance of the backup notifier
    54 
    60 @leave  KErrNoMemory, an out of memory condition has occurred;
    55 /** Standard two phase construction
    61                       Note that the function may also leave with some other system-wide error codes.
    56 	@return an instance of the backup client
    62 */
    57 	@param a pointer to the SQL server which must have implemented the
    63 CSqlBurEventMonitor* CSqlBurEventMonitor::NewL(MSqlSrvBurInterface& aInterface)
    58 			TSqlSrvBurInterface interface
    64 	{
    59 	@leave if no memory
    65 	CSqlBurEventMonitor* self = new (ELeave) CSqlBurEventMonitor(aInterface);
    60 */
       
    61 CSqlBackupClient* CSqlBackupClient::NewLC(MSqlSrvBurInterface *aInterface)
       
    62 	{
       
    63 	CSqlBackupClient *self=(CSqlBackupClient *)new(ELeave) CSqlBackupClient(aInterface);
       
    64 	CleanupStack::PushL(self);
    66 	CleanupStack::PushL(self);
    65 	self->ConstructL();
    67 	self->ConstructL();
    66 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_NEWLC, "0x%X;CSqlBackupClient::NewLC", (TUint)self));
    68 	CleanupStack::Pop(self);
       
    69 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_NEWL, "0x%X;CSqlBurEventMonitor::NewL", (TUint)self));
    67 	return self;
    70 	return self;
    68 	}
    71 	}
    69 
    72 
    70 /** Standard two phase construction
    73 /**
    71 	@return an instance of the backup client
    74 Releases the allocated resources.
    72 	@param a pointer to the SQL server which must have implemented the
    75 */
    73 			TSqlSrvBurInterface interface
    76 CSqlBurEventMonitor::~CSqlBurEventMonitor()
    74 	@leave if no memory
    77 	{
    75 */
    78 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_CSQLBACKUPNOTIFIER2, "0x%X;CSqlBurEventMonitor::~CSqlBurEventMonitor", (TUint)this));
    76 CSqlBackupClient* CSqlBackupClient::NewL(MSqlSrvBurInterface *aInterface)
    79 	Cancel();
    77 	{
    80 	iBurProperty.Close();
    78 	CSqlBackupClient *self=(CSqlBackupClient *) NewLC(aInterface);
    81 	DestroyContent();
    79 	CleanupStack::Pop();
    82 	}
    80 	return self;
    83 
    81 	}
    84 /**
    82 
    85 Initializes data members with their default values. 
    83 /** Standard two phase construction
    86 @param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
    84 	@param a pointer to the SQL server which must have implemented the
       
    85 			TSqlSrvBurInterface interface
       
    86 */		
    87 */		
    87 CSqlBackupClient::CSqlBackupClient(MSqlSrvBurInterface *aInterface)
    88 CSqlBurEventMonitor::CSqlBurEventMonitor(MSqlSrvBurInterface& aInterface) :
    88 : CActive(EPriorityStandard), iInterface(aInterface)
    89 	CActive(EPriorityStandard), 
    89 	{
    90 	iBurInterface(aInterface)
    90 	}
    91 	{
    91 
    92 	}
    92 /** Usual tidy up
    93 
    93 */
    94 /**
    94 CSqlBackupClient::~CSqlBackupClient()
    95 Initializes the created CSqlBurEventMonitor object.  
    95 	{
    96 @leave  KErrNoMemory, an out of memory condition has occurred;
    96 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_CSQLBACKUPCLIENT2, "0x%X;CSqlBackupClient::~CSqlBackupClient;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
    97                       Note that the function may also leave with some other system-wide error codes.
    97 	
       
    98 	// cancel outstanding requests
       
    99 	Cancel();
       
   100 	
       
   101 	// release the pub/sub property
       
   102 	iBurProperty.Close();
       
   103 	
       
   104 	// the file list array
       
   105 	iFileList.Close();
       
   106 	
       
   107 	// close the file
       
   108 	iFile.Close();
       
   109 	
       
   110 	// nuke the active backup client
       
   111     delete iActiveBackupClient;
       
   112 	}
       
   113 
       
   114 /** Standard two phase construction
       
   115 	@leave if non memory or StartL leaves
       
   116 */	
    98 */	
   117 void CSqlBackupClient::ConstructL()
    99 void CSqlBurEventMonitor::ConstructL()
   118 	{
   100 	{
   119 	// attach to backup/restore publish/subscribe property
   101 	__SQLLEAVE_IF_ERROR(iBurProperty.Attach(KSqlBurPropertyCategoryUid, KSqlBurBackupRestoreKey));
   120 	__SQLLEAVE_IF_ERROR(iBurProperty.Attach(KUidSystemCategory,KUidBackupRestoreKey));
       
   121 	
       
   122 	// add us to the scheduler
       
   123 	CActiveScheduler::Add(this);
   102 	CActiveScheduler::Add(this);
   124 
       
   125 	// set active and request notification of changes to backup
       
   126 	// and restore publish/subscribe property
       
   127 	StartL();	
       
   128 	}
       
   129 
       
   130 /** 
       
   131 Cancel the outstanding B&R request
       
   132 */
       
   133 void CSqlBackupClient::DoCancel()
       
   134 	{
       
   135 	iBurProperty.Cancel();
       
   136 	}
       
   137 
       
   138 /** Not implemented
       
   139 	@return a flag indicating whether we actioned the error
       
   140 	@param the error unused
       
   141 */
       
   142 TInt CSqlBackupClient::RunError(TInt aError)
       
   143 	{
       
   144 	UNUSED_ARG(aError);
       
   145 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RUNERROR, "0x%X;CSqlBackupClient::RunError;aError=%d", (TUint)this, aError));
       
   146 	// just satisfy it that we did something!
       
   147 	return KErrNone;
       
   148 	}
       
   149 
       
   150 /**	Kick off the BUR client
       
   151 	@leave if TestBurStatusL leaves
       
   152 */
       
   153 void CSqlBackupClient::StartL()
       
   154 	{
       
   155     TestBurStatusL();
       
   156     NotifyChange();
       
   157 	}
       
   158 
       
   159 /** Resubscribe and wait for events
       
   160 */	
       
   161 void CSqlBackupClient::NotifyChange()
       
   162 	{
       
   163 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_NOTIFYCHANGE, "0x%X;CSqlBackupClient::NotifyChange;iBurProperty.Handle()=0x%X", (TUint)this, (TUint)iBurProperty.Handle()));
       
   164 	iBurProperty.Subscribe(iStatus);
   103 	iBurProperty.Subscribe(iStatus);
   165 	SetActive();
   104 	SetActive();
   166 	}
   105 	}
   167 
   106 
   168 /** Something happened. Find out what.
   107 /** 
   169 	Create an instance of BUR client if required
   108 RunL() is called when the value of the {KUidSystemCategory, KUidBackupRestoreKey} gets changed.
   170 	Delete it if no longer required
   109 That indicates: a backup or a restore is about to begin.
   171 	This is for performance reasons
   110 
   172 	@leave if ConfirmReadyForBURL leaves
   111 How the function works:
   173 */
   112  - When a backup or restore notification is received, the function will subscribe again for notifications from
   174 void CSqlBackupClient::TestBurStatusL()
   113    the backup and restore property and will read the property status;
   175 	{
   114  - If the property status is conn::EBURUnset or conn::EBURNormal, the function will destroy iSqlBurCallback
   176 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL_ENTRY, "Entry;0x%X;CSqlBackupClient::TestBurStatusL", (TUint)this));
   115    and iActiveBackupClient interfaces. No more callbacks will be reseived from the backup and restore server.
       
   116    This is the end of the backup or restore processing;
       
   117  - If the property status is conn::EBURBackupFull, conn::EBURBackupPartial, conn::EBURRestoreFull or 
       
   118    conn::EBURRestorePartial, the function will create iSqlBurCallback and iActiveBackupClient interface
       
   119    (iActiveBackupClient's NewL() receives iSqlBurCallback as an input parameter, registering this way the callback
       
   120    in the backup and restore server to be called later, when sending or retrieving data to/from the server).
       
   121    If the property read and the interface creation operations have been successful, the function will call 
       
   122    ConfirmReadyForBURL(KErrNone) to notify the backup and restore server that the SQL server is ready to send/retrieve 
       
   123    backup/restore data.
       
   124    If the current notification is that a backup is about to begin, after the confirmation the backup and restore server will
       
   125    call CSqlBurCallback::InitialiseGetProxyBackupDataL() once per {client secure id, drive} 
       
   126    followed by CSqlBurCallback::GetBackupDataSectionL() calls to retrieve the backup data. 
       
   127    If the current notification is that a restore is about to begin, after the confirmation the backup and restore server will
       
   128    call CSqlBurCallback::InitialiseRestoreProxyBaseDataL() once per {client secure id, drive} 
       
   129    followed by CSqlBurCallback::RestoreBaseDataSectionL() calls to send the restore data.
       
   130      
       
   131 The current implementation has one design flaw. If a backup or restore notification is received, there are at lest 3
       
   132 places before the ConfirmReadyForBURL() call, where the code may leave: 
       
   133  - the "property get" operation;
       
   134  - the iSqlBurCallback creation;
       
   135  - the iActiveBackupClient creation;
       
   136 If a leave occurs at some of the mentioned places, that leave will be trapped by the current CActiveScheduler object
       
   137 and CSqlBurEventMonitor::RunError() will be called with the leaved error code.
       
   138 Problem #1: CSqlBurEventMonitor::RunError() won't do anything with the error (apart from printing a trace in the OST builds).
       
   139             The error is silently suppressed. The backup or restore won't start. But the client won't see any notification
       
   140             for that problem.
       
   141 Problem #2: ConfirmReadyForBURL() won't be called. According to the backup and restore documentation, if
       
   142             ConfirmReadyForBURL() is called with KErrNone parameter, that's a confirmation for the backup and restore
       
   143             server to start the processing. If ConfirmReadyForBURL() is called with an error different than KErrNone,
       
   144             that's a confirmation for the backup and restore server that the client is not ready. No backup or restore
       
   145             will be started. The remote backup client will be notified about the problem.
       
   146 After an investigation it was found that the same problems do exist in all active backup clients, none of them has 
       
   147 solved the problems. Then, the code here will be kept as it is, it might be too dangerous to do a change right now.
       
   148 
       
   149 @see CSqlBurEventMonitor::RunError()
       
   150 @see CSqlBurCallback
       
   151 @see CActiveBackupClient
       
   152 @see CSqlBurCallback::InitialiseGetProxyBackupDataL()
       
   153 @see CSqlBurCallback::GetBackupDataSectionL()
       
   154 @see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
       
   155 @see CSqlBurCallback::RestoreBaseDataSectionL()
       
   156 
       
   157 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   158                       Note that the function may also leave with some other system-wide error codes.
       
   159 */
       
   160 void CSqlBurEventMonitor::RunL()
       
   161 	{
       
   162 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL_ENTRY, "Entry;0x%X;CSqlBurEventMonitor::RunL", (TUint)this));
       
   163 	iBurProperty.Subscribe(iStatus);
       
   164 	SetActive();
   177 	TInt status;
   165 	TInt status;
   178 	__SQLTRACE_BURVAR(TInt err = KErrNone);
   166 	__SQLLEAVE_IF_ERROR(iBurProperty.Get(status));
   179 	if((__SQLTRACE_BUREXPR(err =) iBurProperty.Get(status)) != KErrNotFound)
   167 	status &= conn::KBURPartTypeMask;
   180 		{
       
   181 		status&=KBURPartTypeMask;
       
   182 #ifdef _SQL_RDEBUG_PRINT
   168 #ifdef _SQL_RDEBUG_PRINT
   183 		SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL1, "0x%X;CSqlBackupClient::TestBurStatusL;status=%d", (TUint)this, status));
   169 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL1, "0x%X;CSqlBurEventMonitor::RunL;status=%d", (TUint)this, status));
   184 #else
   170 #else
   185 		SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL2, "0x%X;CSqlBackupClient::TestBurStatusL;status=%{TBURPartType}", (TUint)this, status));
   171 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL2, "0x%X;CSqlBurEventMonitor::RunL;status=%{TBURPartType}", (TUint)this, status));
   186 #endif	    
   172 #endif	    
   187 		switch(status)
   173 	switch(status)
       
   174 		{
       
   175 		case conn::EBURBackupFull:
       
   176 		case conn::EBURBackupPartial:
       
   177 		case conn::EBURRestoreFull:
       
   178 		case conn::EBURRestorePartial:
   188 			{
   179 			{
   189 			case EBURUnset: // same as EBURNormal
   180 			// we only do full backups and full restores
   190 			case EBURNormal:
   181 			if(!(iSqlBurCallback && iActiveBackupClient))
   191 				delete iActiveBackupClient;
   182 				{
   192 				iActiveBackupClient=NULL;
   183 				DestroyContent();
   193 				break;
   184 				TRAPD(err, CreateContentL());
   194 			case EBURBackupFull:
   185 				if(err != KErrNone)
   195 			case EBURBackupPartial:
   186 					{
   196             case EBURRestoreFull:
   187 					DestroyContent();
   197             case EBURRestorePartial:
   188 					__SQLLEAVE(err);
   198 				// we only do full backups and full restores
   189 					}
   199 				if(!iActiveBackupClient)
   190 				}
   200 					{
   191 			iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
   201 					iActiveBackupClient=CActiveBackupClient::NewL(this);
       
   202 					}
       
   203 				iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
       
   204 				break;
       
   205 			default:
       
   206 				break;
       
   207 			}
   192 			}
       
   193 			break;
       
   194 		//case conn::EBURUnset:
       
   195 		//case conn::EBURNormal:
       
   196 		default:
       
   197 			DestroyContent();
       
   198 			break;
   208 		}
   199 		}
   209 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_TESTBURSTATUSL_EXIT, "Exit;0x%X;CSqlBackupClient::TestBurStatusL;iProperty.Get() err=%d", (TUint)this, err));
   200 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_EXIT, "Exit;0x%X;CSqlBurEventMonitor::RunL", (TUint)this));
   210 	}
   201 	SQL_BUR_TEST_STOP();
   211 
   202 	}
   212 /** Called when BUE notifies a BUR event
   203 
   213 	@leave if TestBurStatusL leaves
   204 /** 
   214 */
   205 Cancels the subscribtion for {KUidSystemCategory, KUidBackupRestoreKey} property changes.
   215 void CSqlBackupClient::RunL()
   206 */
   216 	{
   207 void CSqlBurEventMonitor::DoCancel()
   217 	NotifyChange();
   208 	{
   218 	TestBurStatusL();
   209 	iBurProperty.Cancel();
   219 	}
   210 	}
   220 
   211 
   221 /** This is supposed to allow the BUE to know in advance how much
   212 /**
   222 	data is coming - but unfortunately there is no way to know this
   213 No-op. The method does nothing with the reported from CSqlBurEventMonitor::RunL() error  
   223 	at this stage since we don't even know yet what SID is being processed
   214 (apart from logging a trace in OST builds).
   224 	So we just answer some number to make the BUE happy. It doesn't
   215 Actually, the right action is to return KErrNone (as it is implemented), otherwise the default implementation of 
   225 	actually rely on this number so there is no risk - the aFinishedFlag
   216 CActiveScheduler::Error() will panic the current thread.
   226 	indicates the end of data, not the value returned here. It is
   217 
   227 	supposed to allow the BUE to optimise its behaviour by know up front
   218 @see CActiveScheduler::Error()
   228 	the data volume.
   219 @see CSqlBurEventMonitor::RunL()
   229 	@return an arbitrary number
   220  
   230 	@param TDrive unused
   221 @return The RunL() error, if the RunL() call leaves.
   231 */
   222 @param The RunL() error
   232 TUint CSqlBackupClient::GetExpectedDataSize(TDriveNumber aDrive)
   223 */
       
   224 TInt CSqlBurEventMonitor::RunError(TInt aError)
       
   225 	{
       
   226 	UNUSED_ARG(aError);
       
   227 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RUNERROR, "0x%X;CSqlBurEventMonitor::RunError;aError=%d", (TUint)this, aError));
       
   228 	SQL_BUR_TEST_SET_ERROR(aError); 
       
   229 	SQL_BUR_TEST_STOP();
       
   230 	return KErrNone;
       
   231 	}
       
   232 
       
   233 /**
       
   234 Creates iActiveBackupClient and iSqlBurCallback objects.
       
   235 */
       
   236 void CSqlBurEventMonitor::CreateContentL()
       
   237 	{
       
   238 	iSqlBurCallback = CSqlBurCallback::NewL(iBurInterface);
       
   239 	iActiveBackupClient = conn::CActiveBackupClient::NewL(iSqlBurCallback);
       
   240 	}
       
   241 
       
   242 /**
       
   243 Destroys iActiveBackupClient and iSqlBurCallback objects.
       
   244 */
       
   245 void CSqlBurEventMonitor::DestroyContent()
       
   246 	{
       
   247 	delete iActiveBackupClient;
       
   248 	iActiveBackupClient = NULL;
       
   249 	delete iSqlBurCallback;
       
   250 	iSqlBurCallback = NULL;
       
   251 	}
       
   252 
       
   253 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   254 ///////////////////////////////   CSqlBackupClient    /////////////////////////////////////////////////////////////
       
   255 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   256 
       
   257 
       
   258 /** 
       
   259 Creates new CSqlBurCallback instance.
       
   260 The CSqlBurEventMonitor object monitors the state of the {KUidSystemCategory, KUidBackupRestoreKey} 
       
   261 property. When a backup or a restore is about to begin, the CSqlBurEventMonitor object creates a
       
   262 CSqlBurCallback instance, establishes a connection with the B&R server and passes a pointer to
       
   263 the CSqlBurCallback callback to the BYR conenction.
       
   264 The CSqlBurCallback methods will be called during the backup/restore for sending/retrieving data.
       
   265     
       
   266 @param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
       
   267 @return A pointer to the created CSqlBurCallback instance
       
   268 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   269                       Note that the function may also leave with some other system-wide error codes.
       
   270 */
       
   271 CSqlBurCallback* CSqlBurCallback::NewL(MSqlSrvBurInterface& aInterface)
       
   272 	{
       
   273 	CSqlBurCallback* self = new (ELeave) CSqlBurCallback(aInterface);
       
   274 	SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_NEWLC, "0x%X;CSqlBurCallback::NewL", (TUint)self));
       
   275 	return self;
       
   276 	}
       
   277 
       
   278 /**
       
   279 Initializes CSqlBurCallback data members with their default values. 
       
   280 @param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
       
   281 */		
       
   282 CSqlBurCallback::CSqlBurCallback(MSqlSrvBurInterface& aInterface) :
       
   283 	iInterface(aInterface)
       
   284 	{
       
   285 	}
       
   286 
       
   287 /** 
       
   288 Releases the allocated resources.
       
   289 */
       
   290 CSqlBurCallback::~CSqlBurCallback()
       
   291 	{
       
   292 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_CSQLBACKUPCLIENT2, "0x%X;CSqlBurCallback::~CSqlBurCallback;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
       
   293 	BackupCleanup();
       
   294 	(void)RestoreCleanup();
       
   295 	}
       
   296 
       
   297 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   298 /////////////////////////////////////       Full backup   //////////////////////////////////////////////////////////
       
   299 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   300 
       
   301 /** 
       
   302 This is called to let us know that the given SID is to be backed up.
       
   303 We ask the SQL server (using iInterface, see MSqlSrvBurInterface for more details) 
       
   304 for a list of databases that want to be backed up.
       
   305 
       
   306 The backup is initiated by a notification received in CSqlBurEventMonitor::RunL() method.
       
   307 InitialiseGetProxyBackupDataL() is called once per {client secure id, drive} and each 
       
   308 InitialiseGetProxyBackupDataL() call is followed after that by a set of CSqlBurCallback::GetBackupDataSectionL() calls,
       
   309 made from the backup and restore client dll.
       
   310 
       
   311 During GetBackupDataSectionL() calls the CSqlBurCallback object will read the content of the databases from the list,
       
   312 retrieved from the MSqlSrvBurInterface::GetBackUpListL() call and send the content to the backup and restore server.     
       
   313 
       
   314 @see MSqlSrvBurInterface
       
   315 @see CSqlBurEventMonitor::RunL()
       
   316 @see CSqlBurCallback::GetBackupDataSectionL()
       
   317 @see CSqlServer::GetBackUpListL() 
       
   318 
       
   319 @param aSid the UID of the application to backup
       
   320 @param aDrive the drive to be backed up
       
   321 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   322                       Note that the function may also leave with some other system-wide error codes.
       
   323 */
       
   324 void CSqlBurCallback::InitialiseGetProxyBackupDataL(TSecureId aSid, TDriveNumber aDrive)
       
   325 	{
       
   326 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZEGETPROXYBACKUPDATAL, "0x%X;CSqlBurCallback::InitialiseGetProxyBackupDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
       
   327 	BackupCleanup();
       
   328 	iInterface.GetBackUpListL(aSid, aDrive, iFileList);
       
   329 	iFileIndex = 0;
       
   330 	iState = EBackupNoFileOpen;
       
   331 	iBackupError = KErrNone;
       
   332 	}
       
   333 
       
   334 /** 
       
   335 This is supposed to allow the B&R framework to know in advance how much
       
   336 data is coming - but unfortunately there is no way to know this
       
   337 at this stage since we don't even know yet what SID is being processed
       
   338 So we just answer some number to make the BUE happy. It doesn't
       
   339 actually rely on this number so there is no risk - the aFinishedFlag
       
   340 indicates the end of data, not the value returned here. It is
       
   341 supposed to allow the BUE to optimise its behaviour by know up front
       
   342 the data volume.
       
   343 
       
   344 @see CSqlBurEventMonitor::RunL()
       
   345 @see CSqlBurCallback::InitialiseGetProxyBackupDataL()
       
   346 
       
   347 @param aDrive Unused parameter (the drive number is logged in OST builds).
       
   348 @return an arbitrary number (1024 at the moment)
       
   349 */
       
   350 TUint CSqlBurCallback::GetExpectedDataSize(TDriveNumber aDrive)
   233 	{
   351 	{
   234 	UNUSED_ARG(aDrive);
   352 	UNUSED_ARG(aDrive);
   235 	// we have no idea at this point - we even don't know who is to be backed up yet
   353 	// we have no idea at this point - we even don't know who is to be backed up yet
   236 	const TUint KArbitraryNumber = 1024;
   354 	const TUint KArbitraryNumber = 1024;
   237 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETEXPECTEDDATASIZE, "0x%X;CSqlBackupClient::GetExpectedDataSize;aDrive=%d;rc=%u", (TUint)this, (TInt)aDrive, KArbitraryNumber));
   355 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETEXPECTEDDATASIZE, "0x%X;CSqlBurCallback::GetExpectedDataSize;aDrive=%d;rc=%u", (TUint)this, (TInt)aDrive, KArbitraryNumber));
   238 	return KArbitraryNumber;
   356 	return KArbitraryNumber;
   239 	}
   357 	}
   240 
   358 
   241 /** This is the backup state machine
   359 /** 
   242 	Because the data has to be sent back in sections and the various
   360 This is the backup state machine
   243 	components of the dataflow may straddle chunks, we have to keep
   361 Because the data has to be sent back in sections and the various
   244 	track of where we are between each transfer - a state machine is
   362 components of the dataflow may straddle chunks, we have to keep
   245 	the simplest and most understandable implementation
   363 track of where we are between each transfer - a state machine is
   246 	@param TPtr this is where the data will be put to be passed back
   364 the simplest and most understandable implementation.
   247 	@param TBool set to true when all data has been submitted for backup
   365 
   248 	@leave
   366 Please note how the function processes the errors occuring during the backup.
   249 */
   367 If an error occurs, the error is not propagated back to the B&R server immediatelly.
   250 void CSqlBackupClient::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinishedFlag)
   368 The error is stored in iBurError data member and is reported at the end of the backup process.
   251 	{
   369 The reason for such unusual error reporting poicy is: the SQL server performs full backup of possibly more
   252 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL0, "0x%X;CSqlBackupClient::GetBackupDataSectionL;iState=%d;iFileIndex=%d", (TUint)this, (TInt)iState, iFileIndex));
   370 than one database file. If an error occurs during the backup of the first file for example, the backup
       
   371 process should not stop at that point. All files will be processed and then at the end, the error will be reproted.
       
   372 
       
   373 In details, the function runs a state machine, where:
       
   374  - every file in the list retrieved in InitialiseGetProxyBackupDataL() is opened;
       
   375  - the file is read and 32-bit checksum over the file data - calculated;
       
   376  - a file backup header is prepared, including there the file size, file name, file name length, protocol verison number
       
   377    and the checksum. The header is sent to the backup restore server;
       
   378  - the file data is read and sent to the backup and restore server;
       
   379  - during the described above sequence no leave ever occurs. The error that occurs during the file processing,
       
   380    is stored into a data member of CSqlBurCallback class. At the end, after the last file in the list is processed,
       
   381    the backup and restore server will get a notification (via a User::Leave() call) regarding the error;
       
   382    The used error reporting policy allows all files to be process without interrupting the backup process.
       
   383    For example, if there are 5 files to be sent to the backup and restore server, an error that occurs during the 
       
   384    processing of file #3, won't prevent files #4 and #5 from being sent for backup.       
       
   385 
       
   386 @see CSqlBurEventMonitor::RunL()
       
   387 @see CSqlBurCallback::InitialiseGetProxyBackupDataL()
       
   388 
       
   389 @param aBuffer Output parameter, the buffer where the data will be put to be passed back
       
   390 @param aFinishedFlag Set to true when all data has been submitted for backup
       
   391 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   392                       Note that the function may also leave with some other system-wide error codes.
       
   393 */
       
   394 void CSqlBurCallback::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinishedFlag)
       
   395 	{
   253 	// don't assume they set it to false
   396 	// don't assume they set it to false
   254 	aFinishedFlag=EFalse;
   397 	aFinishedFlag=EFalse;
   255 	// any files to backup
   398 	// any files to backup
   256 	if(iFileList.Count()==0)
   399 	if(iFileList.Count()==0)
   257 		{
   400 		{
   258 		SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL1, "0x%X;CSqlBackupClient::GetBackupDataSectionL;file count is 0", (TUint)this));
   401 		// nothing to backup
   259 		// nothing to backup - just return the finished flag
   402 		SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL1, "0x%X;CSqlBurCallback::GetBackupDataSectionL;file count is 0", (TUint)this));
   260 		aFinishedFlag=ETrue;
   403 		aFinishedFlag = ETrue;
   261 		// clear down the list
   404 		BackupCleanup();
   262 		iFileList.Reset();
       
   263 		// iFileList closed in dtor
       
   264 		return;
   405 		return;
   265 		}
   406 		}
   266 
   407 
   267 	// run the state machine
   408 	// run the state machine
   268 	for(TInt bufFreeSpace=aBuffer.MaxSize()-aBuffer.Size(); bufFreeSpace>0; bufFreeSpace=aBuffer.MaxSize()-aBuffer.Size())
   409 	for(TInt bufFreeSpace=aBuffer.MaxSize()-aBuffer.Size(); bufFreeSpace>0; bufFreeSpace=aBuffer.MaxSize()-aBuffer.Size())
   270 		switch(iState)
   411 		switch(iState)
   271 			{
   412 			{
   272 			case EBackupNoFileOpen: // open a file for processing
   413 			case EBackupNoFileOpen: // open a file for processing
   273 				{
   414 				{
   274 				if(iFileIndex>=iFileList.Count())
   415 				if(iFileIndex>=iFileList.Count())
   275 					{
   416 					{// all files have been processed - send the finished flag
   276 					SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL2, "0x%X;CSqlBackupClient::GetBackupDataSectionL;all files processed", (TUint)this));
   417 					SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL2, "0x%X;CSqlBurCallback::GetBackupDataSectionL;all files processed;iBackupError=%d", (TUint)this, iBackupError));
   277 					// all files have been processed - send the finished flag
   418 					aFinishedFlag = ETrue;
   278 					aFinishedFlag=ETrue;
   419 					BackupCleanup();
   279 					// clear down the filelist
   420 					__SQLLEAVE_IF_ERROR(iBackupError);
   280 					iFileList.Reset();
       
   281 					return;
   421 					return;
   282 					}
   422 					}
   283 				// open the database file to send
   423 				// open the database file to send
   284 				TInt rc=iFile.Open(	iInterface->Fs(), iFileList[iFileIndex].FullName(), EFileRead | EFileShareExclusive);
   424 				TPtrC fname = iFileList[iFileIndex]->Des();
   285 				__SQLTRACE_BUREXPR(TPtrC fname = iFileList[iFileIndex].FullName());
   425 				TInt err = iFile.Open(iInterface.Fs(), fname, EFileRead | EFileShareExclusive);
   286 				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));
   426 				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));
   287 				if(KErrNone!=rc)
   427 				if(KErrNone != err)
   288 					{
   428 					{
   289 					// there's nothing we can do if we can't open the file so we just skip it
   429 					// there's nothing we can do if we can't open the file so we just skip it
       
   430 					SetBackupError(err);
   290 					++iFileIndex;
   431 					++iFileIndex;
   291 					break;
   432 					break;
   292 					}
   433 					}
   293 				iState=EBackupOpenNothingSent;
   434 				iState=EBackupOpenNothingSent;
   294 				break;
   435 				break;
   295 				}
   436 				}
   296 			case EBackupOpenNothingSent: // nothing sent (so far) for this file - send the header info
   437 			case EBackupOpenNothingSent: // nothing sent (so far) for this file - send the header info
   297 				{
   438 				{
   298 				TInt64 fileSize;
   439 				TInt64 fileSize;
   299 				if(KErrNone!=iFile.Size(fileSize) || fileSize==0) // short circuit eval
   440 				TInt err = iFile.Size(fileSize);
   300 					{
   441 				if(KErrNone != err)
   301 					// empty or unreadable - skip this file
   442 					{
   302 					iState=EBackupEndOfFile;
   443 					SetBackupError(err);
       
   444 					iState = EBackupEndOfFile;
   303 					break;
   445 					break;
   304 					}
   446 					}
   305 				
   447 				
   306 				// get the checksum - only grab last 4 bytes - enough to be satisfied that
   448 				TUint64 checksum64 = 0;
   307 				// the backup and restore worked ok
   449 				err = CheckSum(iFile, checksum64);
   308 				TUint32 checksum = CheckSumL(iFile) & KMaxTUint32;
   450 				SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL4, "0x%X;CSqlBurCallback::GetBackupDataSectionL;CheckSum();iFileIndex=%d;err=%d", (TUint)this, iFileIndex, err));
       
   451 				if(err != KErrNone)
       
   452 					{
       
   453 					//An error occured while reading the file (or there was not enough memory for the read buffer)
       
   454 					SetBackupError(err);
       
   455 					iState = EBackupEndOfFile;
       
   456 					break;
       
   457 					}
       
   458 				// Only grab last 4 bytes of the checksum - enough to be satisfied that the backup and restore worked ok
       
   459 				TUint32 checksum32 = checksum64 & KMaxTUint32;
   309 
   460 
   310                 // build the header - this is an instance member because it
   461                 // build the header - this is an instance member because it
   311                 // has to persist over multiple calls to this method
   462                 // has to persist over multiple calls to this method
   312 				const TDesC& fileName = iFileList[iFileIndex].FullName();
   463 				TPtrC fname = iFileList[iFileIndex]->Des();
   313 				iBuffer.Format(_L("%8x%8x%4x%16lx%8x%S"),
   464 				iBuffer.Format(_L("%8x%8x%4x%16lx%8x%S"),
   314 					checksum,					// %8x
   465 					checksum32,					// %8x
   315 					KMagicNum,					// %8x
   466 					KSqlBurMagicNum,			// %8x
   316 					KBackupHeaderVersion,		// %4x
   467 					KSqlBurHeaderVersion,		// %4x
   317 					fileSize,					// %16lx
   468 					fileSize,					// %16lx
   318 					fileName.Length(),			// %8x
   469 					fname.Length(),				// %8x
   319 					&fileName);					// %S
   470 					&fname);					// %S
   320 				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));
   471 				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));
   321 				
   472 				
   322 				// we need it to look like an 8bit buffer
   473 				// we need it to look like an 8bit buffer
   323 				TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size());
   474 				TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size());
   324 							
   475 							
   325 				TInt len = Min(hdrPtr8.Size(), bufFreeSpace);
   476 				TInt len = Min(hdrPtr8.Size(), bufFreeSpace);
   370 				break;
   521 				break;
   371 				}
   522 				}
   372 			case EBackupOpenAllHeaderSent: // need to send some data
   523 			case EBackupOpenAllHeaderSent: // need to send some data
   373 				{
   524 				{
   374 				TPtr8 ptr((TUint8*)aBuffer.Ptr() + aBuffer.Size(), 0, bufFreeSpace);
   525 				TPtr8 ptr((TUint8*)aBuffer.Ptr() + aBuffer.Size(), 0, bufFreeSpace);
   375 				__SQLLEAVE_IF_ERROR(iFile.Read(ptr));
   526 				TInt err = iFile.Read(ptr);
       
   527 				if(err != KErrNone)
       
   528 					{
       
   529 					//An error occured while reading the file 
       
   530 					SetBackupError(err);
       
   531 					iState = EBackupEndOfFile;
       
   532 					SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL6, "0x%X;CSqlBurCallback::GetBackupDataSectionL;File read;iFileIndex=%d;err=%d", (TUint)this, iFileIndex, err));
       
   533 					break;
       
   534 					}
   376 				TInt bytesRead = ptr.Size();
   535 				TInt bytesRead = ptr.Size();
   377 				aBuffer.SetLength(aBuffer.Size() + bytesRead);
   536 				aBuffer.SetLength(aBuffer.Size() + bytesRead);
   378 				// EOF
   537 				// EOF
   379 				if(bytesRead == 0)
   538 				if(bytesRead == 0)
   380 					{
   539 					{
   383 					}
   542 					}
   384 				break;
   543 				break;
   385 				}
   544 				}
   386 			case EBackupEndOfFile:
   545 			case EBackupEndOfFile:
   387 				{
   546 				{
   388 				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));
   547 				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));
   389 				iFile.Close();
   548 				iFile.Close();
   390 				++iFileIndex; // move on to next file
   549 				++iFileIndex; // move on to next file
   391 				iState = EBackupNoFileOpen; // go round again
   550 				iState = EBackupNoFileOpen; // go round again
   392 				break;
   551 				break;
   393 				}
   552 				}
   394 			default:
   553 			default:
   395 				{
   554 				__ASSERT_DEBUG(EFalse, __SQLPANIC(ESqlPanicInternalError));
   396 				break;
   555 				break;
   397 				}
       
   398 			}//end of the "switch" statement
   556 			}//end of the "switch" statement
   399 		}//end of the "for" statement
   557 		}//end of the "for" statement
   400 	}
   558 	}
   401 
   559 
   402 /** This is called by BUE when the restore has completed
   560 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   403 	Nothing to do here except tell the server
   561 /////////////////////////////////////       Full restore   /////////////////////////////////////////////////////////
   404 	@param TDrive the drive that is being restored (unused)
   562 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   405 */
   563 
   406 void CSqlBackupClient::RestoreComplete(TDriveNumber aDrive)
   564 /** 
   407 	{
   565 Called when the BUE wants to start sending data to us.
       
   566 Creates the folder (if the folder does not exist) where the temporary files will be created during the restore process.
       
   567 Deletes all files from the restore folder.
       
   568 
       
   569 The restore is initiated by a notification received in CSqlBurEventMonitor::RunL() method.
       
   570 InitialiseRestoreProxyBaseDataL() is called once per {client secure id, drive} and each 
       
   571 InitialiseRestoreProxyBaseDataLL() call is followed after that by a set of CSqlBurCallback::RestoreBaseDataSectionL() 
       
   572 calls, made from the backup and restore client dll.
       
   573 
       
   574 During RestoreBaseDataSectionLL() calls the CSqlBurCallback object will receive data from the backup and resore server.     
       
   575 
       
   576 @see CSqlBurEventMonitor::RunL()
       
   577 @see CSqlBurCallback::RestoreBaseDataSectionL()
       
   578 
       
   579 @param aSid the UID of the application that is to be restored. Not used (only logged in OST builds).
       
   580 @param aDrive the drive to restore.
       
   581 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   582                       Note that the function may also leave with some other system-wide error codes.
       
   583 */
       
   584 void CSqlBurCallback::InitialiseRestoreProxyBaseDataL(TSecureId aSid, TDriveNumber aDrive)
       
   585 	{
       
   586 	UNUSED_ARG(aSid);
   408 	UNUSED_ARG(aDrive);
   587 	UNUSED_ARG(aDrive);
   409 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTORECOMPLETE, "0x%X;CSqlBackupClient::RestoreComplete;aDrive=%d", (TUint)this, (TInt)aDrive));
   588 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZERESTOREPROXYBASEDATAL, "0x%X;CSqlBurCallback::InitialiseRestoreProxyBaseDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
   410 	}
   589 	iBuffer.Zero();
   411 
   590 	iState = ERestoreExpectChecksum;
   412 /** This is called to let us know that the given SID is to be backed up
   591 	iRestoreDrive = aDrive;
   413 	We ask the SQL server for a list of databases that want to be backed
   592 	iRestoreId = aSid;
   414 	up - this is because the backup flag is an internal metadata object
   593 	//Create the directory for the temporary files created during the restore process.
   415 	in the database, and to decouple we don't want to have to know how
   594 	TFileName privatePath;
   416 	this data is stored.
   595 	__SQLLEAVE_IF_ERROR(iInterface.Fs().PrivatePath(privatePath));
   417 	@param TSecureSid the UID of the application to backup
   596 	TDriveUnit driveUnit(iRestoreDrive);
   418 	@param TDriveNumber the drive to be backed up (unused)
   597 	TDriveName driveName = driveUnit.Name();
   419 	@leave
   598 	privatePath.Insert(0, driveName);
   420 */
   599 	__SQLLEAVE_IF_ERROR(iParse.Set(KSqlBurRestoreDir, &privatePath, 0));
   421 void CSqlBackupClient::InitialiseGetProxyBackupDataL(TSecureId aSid, TDriveNumber aDrive)
   600 	iRestoreDir.Copy(iParse.FullName());
       
   601 	iRestoreDir.Append(KPathDelimiter);
       
   602 	TInt err = iInterface.Fs().MkDirAll(iRestoreDir);
       
   603 	if(err != KErrAlreadyExists)
       
   604 		{
       
   605 		__SQLLEAVE_IF_ERROR(err);
       
   606 		}
       
   607 	//Cleanup the restore directory
       
   608 	err = RestoreCleanup();
       
   609 	if(err != KErrNotFound)
       
   610 		{
       
   611 		__SQLLEAVE_IF_ERROR(err);
       
   612 		}
       
   613 	}
       
   614 
       
   615 /** 
       
   616 This is called by BUE when the restore has completed.
       
   617 
       
   618 @see CSqlBurEventMonitor::RunL()
       
   619 @see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
       
   620 
       
   621 @param aDrive the drive that is being restored. Not used (only logged in OST builds).
       
   622 */
       
   623 void CSqlBurCallback::RestoreComplete(TDriveNumber aDrive)
   422 	{
   624 	{
   423 	UNUSED_ARG(aDrive);
   625 	UNUSED_ARG(aDrive);
   424 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZEGETPROXYBACKUPDATAL, "0x%X;CSqlBackupClient::InitialiseGetProxyBackupDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
   626 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTORECOMPLETE, "0x%X;CSqlBurCallback::RestoreComplete;aDrive=%d", (TUint)this, (TInt)aDrive));
   425 	// get the list of database files to back up - this is provided by the SQL server
   627 	iRestoreDrive = TDriveNumber(-1);
   426 	GetBackupListL(aSid);
   628 	iRestoreId = TSecureId(KNullUid);
   427 	// this is the index of the file being processed - point to the beginning
   629 	}
   428 	iFileIndex=0;
   630 
   429 	// the first state of the backup state machine
   631 /** 
   430 	iState=EBackupNoFileOpen;
   632 This is repeatedly called by the BUE to send us chunks of restore data (for the current SID)
   431 	// save the sid for notifying the server when the backup is complete
   633 Becuase the data is spread over chunks we need to manage the state across mutiple calls
   432 	iSid=aSid;
   634 to this method so we use a state machine.
   433 	}
   635 
   434 
   636 The function runs the state machine and for each file block detected in the coming data, the function does:
   435 /** Called when the BUE wants to start sending data to us
   637  - creates a temporary file in the restore directory (created by InitialiseRestoreProxyBaseDataL());
   436 	@param TSecureId the UID of the application that is to be restored
   638  - stores the file data in the created temporary file;
   437 	@param TDriveNumber the drive to restore (unused)
   639  - During the 2 steps descirbed above, if an error occurs, that erro will be reproted to the backup and restore
   438 	@leave
   640    server (via a User::Leave() call);
   439 */
   641  - When all data is received and stored in temporary files in the restore directory, 
   440 void CSqlBackupClient::InitialiseRestoreProxyBaseDataL(TSecureId aSid, TDriveNumber aDrive)
   642    for each received file the function will:
   441 	{
   643    = move the original database file to the restore directory with a ".bak" extension added to the file name;
   442 	UNUSED_ARG(aDrive);
   644    = move the temporary file, which has the same name as the original database file, to the location of the
   443 	SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZERESTOREPROXYBASEDATAL, "0x%X;CSqlBackupClient::InitialiseRestoreProxyBaseDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
   645      original database file - the SQL server private data cage;
   444 	iBuffer.Zero();
   646    = delete the file with the ".bak" extension;
   445 	// this is the first state of the restore state machine
   647    The three steps described above are implemented as "all or none" operation - if an error occurs during step (2),
   446 	iState=ERestoreExpectChecksum;
   648    the content of the original database file will be restored from the file with the ".bak" extension.   
   447 	iAnyData=EFalse; // to keep track in the state machine whether any data was actually sent
   649 
   448 	// save the sid for notifying the server when the restore is done
   650 @see CSqlBurEventMonitor::RunL()
   449 	iSid=aSid;
   651 @see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
   450 	}
   652 
   451 
   653 @param aInBuffer Buffer with data to be restored
   452 /** This is repeatedly called by the BUE to send us chunks of restore data (for the current SID)
   654 @param aFinishedFlag Set when there is not more data to restore
   453     Becuase the data is spread over chunks we need to manage the state across mutiple calls
   655 @leave  KErrNoMemory, an out of memory condition has occurred;
   454     to this method so we use a state machine
   656                       Note that the function may also leave with some other system-wide error codes.
   455     @leave KErrCorrupt if the data is incomplete or the checksum fails
   657 */
   456     @param TDesc8 the data to be restored
   658 void CSqlBurCallback::RestoreBaseDataSectionL(TDesC8& aInBuffer, TBool aFinishedFlag)
   457     @param TBool set when there is not more data to restore
   659 	{
   458 
       
   459 Attention!!! This function won't work properly if aInBuffer parameter contains odd number of bytes!!!
       
   460 (a legacy problem, if it is a problem at all, because the B&R engine probably sends the data in chunks with even size)
       
   461 */
       
   462 void CSqlBackupClient::RestoreBaseDataSectionL(TDesC8& aInBuffer, TBool aFinishedFlag)
       
   463 	{
       
   464 	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));
       
   465 	// used to walk the buffer
   660 	// used to walk the buffer
   466 	// got a new buffer - because each time this method is called, we have a
   661 	// got a new buffer - because each time this method is called, we have a
   467 	// fresh chunk of data
   662 	// fresh chunk of data
   468 	TInt inBufferPos = 0;
   663 	TInt inBufferPos = 0;
   469 
   664 
   470 	// to mark when the state machine is through
   665 	// to mark when the state machine is through
   471 	TBool done = EFalse;
   666 	TBool done = EFalse;
   472 	
   667 	
   473 	// check whether this is an empty restore
   668 	// check whether this is an empty restore
   474 	if(aFinishedFlag && !iAnyData)
   669 	if(aFinishedFlag && aInBuffer.Size() == 0)
   475 		{
   670 		{
   476 		// we have to do this and not rely on aFinishedFlag alone, becuase
       
   477 		// if aFinished is used, we'll process the last state of the machine
       
   478 		// which does tidyup, except that if there was no data, no tidyup should
       
   479 		// be done
       
   480 		return;
   671 		return;
   481 		}
   672 		}
   482 		
   673 
   483 	// run the machine
   674 	TInt iterations = 0;
       
   675 	
       
   676 	// run the state machine
   484 	do
   677 	do
   485 		{
   678 		{
   486 		// how many bytes are there available in the buffer for processing?
   679 		// how many bytes are there available in the buffer for processing?
   487 		TInt bytesAvailable = aInBuffer.Size() - inBufferPos;
   680 		TInt bytesAvailable = aInBuffer.Size() - inBufferPos;
   488 		// the reason why we are testing finishedFlag is because we must
   681 		// the reason why we are testing finishedFlag is because we must
   491 			{
   684 			{
   492 			// ran out of data in the chunk
   685 			// ran out of data in the chunk
   493 			// so we return and wait for more data to arrive
   686 			// so we return and wait for more data to arrive
   494 			return;
   687 			return;
   495 			}
   688 			}
   496 		if(aFinishedFlag && iState != ERestoreComplete && iState != ERestoreExpectData)
       
   497 			{
       
   498 			// ran out of data early
       
   499 			// will be ERestoreComplete if data not aligned on 128
       
   500 			// will be ERestoreExpectData if data aligned on 128
       
   501 			__SQLLEAVE(KErrCorrupt);
       
   502 			}
       
   503 		// yep there was some data in the chunk if we got here
       
   504 		if(bytesAvailable > 0)
       
   505 			{
       
   506 			iAnyData = ETrue;
       
   507 			}
       
   508 		switch(iState)
   689 		switch(iState)
   509 			{
   690 			{
   510 			case ERestoreExpectChecksum: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for the checksum)
   691 			case ERestoreExpectChecksum: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for the checksum)
   511 				{
   692 				{
   512 				const TInt KCheckSumStrLen = 8;
   693 				const TInt KCheckSumStrLen = 8;
   524 				const TInt KOldFileSizeStrLen = 8;
   705 				const TInt KOldFileSizeStrLen = 8;
   525 				CopyBufData(aInBuffer, inBufferPos, iBuffer, KOldFileSizeStrLen);
   706 				CopyBufData(aInBuffer, inBufferPos, iBuffer, KOldFileSizeStrLen);
   526 				if(iBuffer.Length() == KOldFileSizeStrLen)
   707 				if(iBuffer.Length() == KOldFileSizeStrLen)
   527 					{
   708 					{
   528 					TUint32 oldFileSize = ::GetNumUint32L(iBuffer);
   709 					TUint32 oldFileSize = ::GetNumUint32L(iBuffer);
   529 					if(oldFileSize == KMagicNum)
   710 					if(oldFileSize == KSqlBurMagicNum)
   530 						{
   711 						{
   531 						iState = ERestoreExpectVersion;
   712 						iState = ERestoreExpectVersion;
   532 						}
   713 						}
   533 					else
   714 					else
   534 						{
   715 						{
   560 					{
   741 					{
   561 					iFileSize = GetNumInt64L(iBuffer);	
   742 					iFileSize = GetNumInt64L(iBuffer);	
   562 					iState = ERestoreExpectFileNameSize;
   743 					iState = ERestoreExpectFileNameSize;
   563 					iBuffer.Zero();
   744 					iBuffer.Zero();
   564 					}
   745 					}
   565 				SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL1, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;iFileSize=%lld", (TUint)this, iFileSize));
   746 				SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL1, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;iFileSize=%lld", (TUint)this, iFileSize));
   566 				break;
   747 				break;
   567 				}
   748 				}
   568 			case ERestoreExpectFileNameSize: // the size of the file name to restore
   749 			case ERestoreExpectFileNameSize: // the size of the file name to restore
   569 				{
   750 				{
   570 				const TInt KFileNameLenStrLen = 8;
   751 				const TInt KFileNameLenStrLen = 8;
   578 				break;
   759 				break;
   579 				}
   760 				}
   580 			case ERestoreExpectFileName:  // the name of the file to restore
   761 			case ERestoreExpectFileName:  // the name of the file to restore
   581 				{
   762 				{
   582 				CopyBufData(aInBuffer, inBufferPos, iBuffer, iFileNameSize);
   763 				CopyBufData(aInBuffer, inBufferPos, iBuffer, iFileNameSize);
   583 				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));
   764 				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));
   584 				if(iBuffer.Length() == iFileNameSize)
   765 				if(iBuffer.Length() == iFileNameSize)
   585 					{
   766 					{
   586 					iState = ERestoreExpectData;
   767 					iState = ERestoreExpectData;
   587 					iBuffer.Append(KRestoreSuffix);
   768 					TParse parse;
   588 					// now we start writing the data to the target file
   769 					__SQLLEAVE_IF_ERROR(parse.Set(iBuffer, 0, 0));
   589 					// write to a temp - double disk space potentially
   770 					__SQLLEAVE_IF_ERROR(iParse.Set(parse.NameAndExt(), &iRestoreDir, 0));
   590 					// once all the temp files are created, then they are renamed to the
   771 					TPtrC fname(iParse.FullName());
   591 					// real file names in one fell swoop
   772 					//The database is restored first to a temporary file, in the restore folder, on the same drive.
   592 					__SQLLEAVE_IF_ERROR(iFile.Replace(iInterface->Fs(), iBuffer, EFileWrite | EFileShareExclusive));
   773 					__SQLLEAVE_IF_ERROR(iFile.Replace(iInterface.Fs(), fname, EFileWrite | EFileShareExclusive));
   593 					SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL3, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
   774 					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()));
   594 					iBuffer.Zero();
   775 					iBuffer.Zero();
   595 					}
   776 					}
   596 				break;
   777 				break;
   597 				}
   778 				}
   598 			case ERestoreExpectData: // now for the data
   779 			case ERestoreExpectData: // now for the data
   599 				{
   780 				{
   600 				TInt len = Min((aInBuffer.Size() - inBufferPos), iFileSize);
   781 				TInt len = Min((aInBuffer.Size() - inBufferPos), iFileSize);
   601 				__SQLLEAVE_IF_ERROR(iFile.Write(aInBuffer.Mid(inBufferPos, len)));
   782 				TInt err = iFile.Write(aInBuffer.Mid(inBufferPos, len));
       
   783 				if(err != KErrNone)
       
   784 					{
       
   785 					(void)RestoreCleanup();
       
   786 					__SQLLEAVE(err);
       
   787 					}
   602 				inBufferPos += len;
   788 				inBufferPos += len;
   603 				iFileSize -= len;
   789 				iFileSize -= len;
   604 				if(iFileSize == 0)
   790 				if(iFileSize == 0)
   605 					{
   791 					{
   606 					iState = ERestoreComplete;
   792 					iState = ERestoreComplete;
   607 					}
   793 					}
   608 				break;
   794 				break;
   609 				}
   795 				}
   610 			case ERestoreComplete: // file completely restored
   796 			case ERestoreComplete: // file completely restored
   611 				{
   797 				{
   612 				// calculate the checksum
   798 				TUint64 checkSum64 = 0;
   613 				TUint32 cksum = CheckSumL(iFile) & KMaxTUint32;
   799 			    TInt restoreErr = iFile.Flush();
   614 				
   800 				if(restoreErr == KErrNone)
   615 				// done with the file now - has to follow checksum cos it
   801 					{
   616 				// expects ann open file
   802 					// calculate the checksum
   617 				SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL4, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;END;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
   803 					restoreErr = CheckSum(iFile, checkSum64);
   618 			    __SQLLEAVE_IF_ERROR(iFile.Flush());
   804 					}
   619 				iFile.Close();
   805 				iFile.Close();
   620 
   806 				if(restoreErr != KErrNone)
   621                 // validate that the checksum matches
   807 					{
   622                 if(cksum!=iChecksum)
   808 					(void)RestoreCleanup();
       
   809 					__SQLLEAVE(restoreErr);
       
   810 					}
       
   811 				SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL4, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;END;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
       
   812 				TUint32 checkSum32 = checkSum64 & KMaxTUint32;
       
   813                 if(checkSum32 != iChecksum)
   623                     {
   814                     {
       
   815 					(void)RestoreCleanup();
   624                     __SQLLEAVE(KErrCorrupt);
   816                     __SQLLEAVE(KErrCorrupt);
   625                     }
   817                     }
   626 				
   818 				if((aInBuffer.Size() - inBufferPos) > 0)
   627 				// end of data - or another file to be restored?
   819 					{//There are bytes to be consumed in the input buffer
   628 				if(aFinishedFlag)
   820 					iState = ERestoreExpectChecksum;
   629 					{
   821 					break;
   630 					// we need to rename all the
   822 					}
   631 					// temp rst files to the real database names
   823 				SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL5, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;aFinishedFlag=ETrue", (TUint)this));
   632 					CDir *dir=NULL;
   824 				//End of data. We have all data restored in the restore folder.
   633 					__SQLLEAVE_IF_ERROR(iInterface->Fs().GetDir(KRestoreFilter,KEntryAttNormal,ESortNone,dir));
   825 				//The final step of the "restoring files" process consists of the following sub-steps:
   634 					CleanupStack::PushL(dir);
   826 				// - Rename the database file to be restored to a file with ".bak" extension
   635 					TInt err2 = KErrNone;
   827 				// - Rename the file with the restored data to the database file
   636 					for(TInt a=0;a<dir->Count();++a)
   828 				// - Delete the file with ".bak" extension
       
   829 				//Do not leave during the restore process! Restore as much files as possible.
       
   830 				//The only excpetion is TParse::Set() - if it fails it is a fatal error, the
       
   831 				//restored file path cannot be constructed.
       
   832 				__ASSERT_DEBUG(iRestoreDrive != TDriveNumber(-1), __SQLPANIC(ESqlPanicInternalError));
       
   833 				__ASSERT_DEBUG(iRestoreId != TSecureId(KNullUid), __SQLPANIC(ESqlPanicInternalError));
       
   834 				//Include the aUid and the "*" mask
       
   835 				TUidName uidName = (static_cast <TUid> (iRestoreId)).Name();
       
   836 				TBuf<KMaxUidName + sizeof(KSqlBurAllFiles)> fileNameMask(uidName);
       
   837 				fileNameMask.Append(KSqlBurAllFiles);
       
   838 				__SQLLEAVE_IF_ERROR(iParse.Set(fileNameMask, &iRestoreDir, 0));
       
   839 				CDir* dir = NULL;
       
   840 				TPtrC searchPattern(iParse.FullName());
       
   841 				SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL55, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;search pattern=%S", (TUint)this, __SQLPRNSTR(searchPattern)));
       
   842 				restoreErr = iInterface.Fs().GetDir(searchPattern, KEntryAttNormal, ESortNone, dir);
       
   843 				if(restoreErr == KErrNone)
       
   844 					{
       
   845 					SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL6, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;restored files=%d", (TUint)this, dir->Count()));
       
   846 					for(TInt i=0;i<dir->Count();++i)
   637 						{
   847 						{
   638 						TEntry entry=(*dir)[a];
   848 						const TEntry& entry = (*dir)[i];
   639 						TPtrC rst=entry.iName.Des();
   849 						__SQLLEAVE_IF_ERROR(iParse.Set(entry.iName, &iRestoreDir, 0));
   640 						TInt len=rst.Length();
   850 						TFileName dbName(iParse.FullName());
   641 						// format <filename>.db.bak.rst
   851 						SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL7, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;restored file=%S", (TUint)this, __SQLPRNSTR(dbName)));
   642 						// just a convenience!
   852 						TInt pos = dbName.Find(KSqlBurRestoreDir);
   643 						TPtrC bak(rst.Left(len - 4));//".rst" part excluded
   853 						__ASSERT_DEBUG(pos >= 0, __SQLPANIC(ESqlPanicInternalError));
   644 						TPtrC db(rst.Left(len - 8));//".bak.rst" part excluded
   854 						dbName.Delete(pos, KSqlBurRestoreDir().Length() + 1);//"+1" for the path delimitier
   645 						
   855 						SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL8, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;database=%S", (TUint)this, __SQLPRNSTR(dbName)));
   646 						// first, rename the orig .db as .bak just in case
   856 						TFileName bakDbName(iParse.FullName());
   647 						// ok if not found - might have been deleted.
   857 						bakDbName.Append(KSqlBurBackupExt);
   648 						//the ".bak" file, if exists, will be deleted first.
   858 						SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL9, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;backup file=%S", (TUint)this, __SQLPRNSTR(dbName)));
   649 						(void)iInterface->Fs().Delete(bak);
   859 						//Now, dbName contains the original database (full path), iParse - the restored file,
   650 						TInt err=iInterface->Fs().Rename(db,bak);
   860 						//bakDbName - backup file name
   651 						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));
   861 						TInt err = iInterface.Fs().Rename(dbName, bakDbName);
   652 						if(err == KErrNone || err == KErrNotFound)
   862 						if(err == KErrNone || err == KErrNotFound)
   653 							{
   863 							{
   654 							// now, rename the .rst as .db
   864 							err = iInterface.Fs().Rename(iParse.FullName(), dbName);
   655 							err = iInterface->Fs().Rename(rst,db);
   865 							if(err == KErrNone)
       
   866 								{//commit: delete the backup database file
       
   867 								SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL10, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;Commit;file=%S", (TUint)this, __SQLPRNSTR(dbName)));
       
   868 								(void)iInterface.Fs().Delete(bakDbName);
       
   869 								}
       
   870 							else
       
   871 								{//rollback: restore the original database file
       
   872 								err = iInterface.Fs().Rename(bakDbName, dbName);
       
   873 								SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL11, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;Rollback;file=%S;err=%d", (TUint)this, __SQLPRNSTR(dbName), err));
       
   874 								}
   656 							}
   875 							}
   657 						if(err != KErrNone && err2 == KErrNone)
   876 						if(err != KErrNone && err != KErrNotFound)
   658 							{
   877 							{
   659 							//The idea here is to not report the error immediatelly by calling LeaveIfError().
   878 							if(restoreErr == KErrNone)
   660 							//If we leave here, the next database restore may also fail, for example, if the current database is still open by 
   879 								{
   661 							//its owner. Then "TInt err=iInterface->Fs().Rename(db,bak);" will fail again.
   880 								restoreErr = err;
   662 							err2 = err;
   881 								}
   663 							}
   882 							}
   664 						// if we got here, we have a backup of the original database in .db.bak
   883 						}//for(...)
   665 						// and the new database in .db
   884 					delete dir;
   666 						}//end of for(...)
   885 					}//iInterface.Fs().GetDir(...)
   667 					__SQLLEAVE_IF_ERROR(err2);
   886 				done = ETrue;
   668 					
   887 				(void)RestoreCleanup();
   669 					// clean up dir
   888 				if(restoreErr != KErrNone)
   670 					//delete dir;
   889 					{
   671 					CleanupStack::PopAndDestroy(dir);
   890 					__SQLLEAVE(restoreErr);
   672 					dir=NULL;
   891 					}
   673 					
       
   674 					// now delete all the .bak files
       
   675 					// we do this here and not part of the earlier loop
       
   676 					// because we want to make sure that we have a coherent set of database
       
   677 					// files that belong together and not bits of old and new
       
   678 					__SQLLEAVE_IF_ERROR(iInterface->Fs().GetDir(KBackupFilter,KEntryAttNormal,ESortNone,dir));
       
   679 					CleanupStack::PushL(dir);
       
   680 					SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL6, "0x%X;CSqlBackupClient::RestoreBaseDataSectionL;bak files count=%d", (TUint)this, dir->Count()));
       
   681 					for(TInt a1=0;a1<dir->Count();++a1)
       
   682 						{
       
   683 						TEntry entry=(*dir)[a1];
       
   684 						TPtrC bak=entry.iName.Des();
       
   685 						__SQLLEAVE_IF_ERROR(iInterface->Fs().Delete(bak));
       
   686 						}
       
   687 					
       
   688 					// clean up dir
       
   689 					//delete dir;
       
   690 					CleanupStack::PopAndDestroy(dir);
       
   691 					dir=NULL;
       
   692 					done=ETrue;
       
   693 					}
       
   694 				else
       
   695 					{
       
   696 					iState=ERestoreExpectChecksum;
       
   697 					}
       
   698 					
       
   699 				break;
   892 				break;
   700 				}
   893 				}
   701 			default:
   894 			default:
   702 				break;
   895 				__ASSERT_DEBUG(EFalse, __SQLPANIC(ESqlPanicInternalError));
       
   896 				break;
       
   897 			}//switch(...)
       
   898 		if((aInBuffer.Size() - inBufferPos) == bytesAvailable)
       
   899 			{//No bytes have been consumed from the buffer. 
       
   900 			if(++iterations > 1 && !done)
       
   901 				{//This is the second iteration in the loop where no bytes have been consumed from the input buffer. 
       
   902 				 //But the "done" flag is still false. Corrupted archive.
       
   903 				__SQLLEAVE(KErrCorrupt);
       
   904 				}
   703 			}
   905 			}
   704 		} while(!done);
   906 		} while(!done);
   705 	}
   907 	}
   706 
   908 
   707 /** The operation was terminated - we should tidyup here (as best we can)
   909 /** 
   708 	Nothing needs to be done for a backup. Restore is more
   910 The operation was terminated - we should tidyup here (as best we can)
   709 	complicated in the case of an interruption.
   911 Backup: close the file, free the allocated memory for the file names.
   710 	What we need to do here is move all the backup files
   912 Restore: since the final restore step is a non-leaving one, nothing special needs to be done here - 
   711 	back to being db files....
   913 RestoreCleanup() is called to close the file and delete if there are any temporary files left.
   712 */	
   914 */	
   713 void CSqlBackupClient::TerminateMultiStageOperation()
   915 void CSqlBurCallback::TerminateMultiStageOperation()
   714 	{
   916 	{
   715 	// backup/restore terminated, try to tidy up! Can't leave, can't Panic!!!!!
   917 	BackupCleanup();
   716 	// rename all the .bak files to .db
   918 	(void)RestoreCleanup();
   717 	CDir *dir=NULL;
   919 	}
   718 	TInt rc=iInterface->Fs().GetDir(KBackupFilter,KEntryAttNormal,ESortNone,dir);
   920 
   719 	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));
   921 /** 
   720 	if(KErrNone!=rc)
   922 We do our own checksumming so we don't need this
   721 		{
   923 @return the checksum
   722 		// can't get a file list - can't do anything
   924 @param aDrive the drive affected (unused)
   723 		return;
   925 */
   724 		}
   926 TUint CSqlBurCallback::GetDataChecksum(TDriveNumber /* aDrive */)
   725 	for(TInt a=0;a<dir->Count();++a)
       
   726 		{
       
   727 		TEntry entry=(*dir)[a];
       
   728 		TPtrC bak=entry.iName.Des();
       
   729 		TInt len=bak.Length();
       
   730 		TPtrC db(bak.Left(len-4));//".bak" part excluded
       
   731 		rc=iInterface->Fs().Delete(db); // rename does not overwrite
       
   732 		if(KErrNone == rc)
       
   733 			{
       
   734 	        rc = iInterface->Fs().Rename(bak,db);
       
   735 			}
       
   736         //The function cannot leave or return an error. The only thing which could be done here is to print out something
       
   737 		//and continue with the next file.
       
   738 		if(KErrNone != rc)
       
   739 		    {
       
   740 			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)));
       
   741 		    }
       
   742 		// backup restored ok
       
   743 		}
       
   744 	// cleanup dir
       
   745 	delete dir;
       
   746 	}
       
   747 
       
   748 /** We do our own checksumming so we don't need this
       
   749 	@return the checksum
       
   750 	@param TDriveNumber the drive affected (unused)
       
   751 */
       
   752 TUint CSqlBackupClient::GetDataChecksum(TDriveNumber /* aDrive */)
       
   753 	{
   927 	{
   754 	// not required - not implemented
   928 	// not required - not implemented
   755 	const TUint KArbitraryNumber = 1024;
   929 	const TUint KArbitraryNumber = 1024;
   756 	return KArbitraryNumber;
   930 	return KArbitraryNumber;
   757 	}
   931 	}
   758 
   932 
   759 /** We don't support incremental backup
   933 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   760 */
   934 ///////////////////////////     Incremental backup/restore      ////////////////////////////////////////////////////
   761 void CSqlBackupClient::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */,
   935 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   762 										TBool& /* aFinishedFlag */)
   936 
   763 	{
   937 /** 
   764 	// incremental backup not supported
   938 We don't support incremental backup
       
   939 */
       
   940 void CSqlBurCallback::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */, TBool& /* aFinishedFlag */)
       
   941 	{
   765 	__SQLLEAVE(KErrNotSupported);
   942 	__SQLLEAVE(KErrNotSupported);
   766 	}
   943 	}
   767 
   944 
   768 /** We don't support incremental backup
   945 /** 
   769 */
   946 We don't support incremental backup
   770 void CSqlBackupClient::InitialiseGetBackupDataL(TDriveNumber /* aDrive */)
   947 */
   771 	{
   948 void CSqlBurCallback::InitialiseGetBackupDataL(TDriveNumber /* aDrive */)
   772 	// incremental backup not supported
   949 	{
   773 	__SQLLEAVE(KErrNotSupported);
   950 	__SQLLEAVE(KErrNotSupported);
   774 	}
   951 	}
   775 
   952 
   776 /** We don't support incremental backup
   953 /** 
   777 */
   954 We don't support incremental backup
   778 void CSqlBackupClient::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */)
   955 */
   779 	{
   956 void CSqlBurCallback::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */)
   780 	// incremental backup not supported
   957 	{
   781 	__SQLLEAVE(KErrNotSupported);
   958 	__SQLLEAVE(KErrNotSupported);
   782 	}
   959 	}
   783 
   960 
   784 /** We don't support incremental backup
   961 /** 
   785 */
   962 We don't support incremental backup
   786 void CSqlBackupClient::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */)
   963 */
   787 	{
   964 void CSqlBurCallback::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */)
   788 	// incremental backup not supported
   965 	{
   789 	__SQLLEAVE(KErrNotSupported);
   966 	__SQLLEAVE(KErrNotSupported);
   790 	}
   967 	}
   791 
   968 
   792 /** We don't support incremental backup
   969 /** 
   793 */
   970 We don't support incremental backup
   794 void CSqlBackupClient::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
   971 */
   795 	{
   972 void CSqlBurCallback::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
   796 	// incremental backup not supported
   973 	{
   797 	__SQLLEAVE(KErrNotSupported);
   974 	__SQLLEAVE(KErrNotSupported);
   798 	}
   975 	}
   799 
   976 
   800 /** We don't support incremental backup
   977 /** 
   801 */
   978 We don't support incremental backup
   802 void CSqlBackupClient::AllSnapshotsSuppliedL()
   979 */
   803 	{
   980 void CSqlBurCallback::AllSnapshotsSuppliedL()
   804 	// incremental backup not supported
   981 	{
   805 	// cannot leave or panic!
   982 	}
   806 	}
   983 
   807 
   984 /** 
   808 /** We don't support incremental backup
   985 We don't support incremental backup
   809 */
   986 */
   810 void CSqlBackupClient::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */,
   987 void CSqlBurCallback::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
   811 									TBool /* aFinishedFlag */)
   988 	{
   812 	{
       
   813 	// incremental backup not supported
       
   814 	__SQLLEAVE(KErrNotSupported);
   989 	__SQLLEAVE(KErrNotSupported);
   815 	}
   990 	}
   816 
   991 
   817 /**
   992 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   818 	Get a list of database files that need to be backed up
   993 ///////////////////////////     Helper functions      //////////////////////////////////////////////////////////////
   819 	This is decided by the SQL server on the basis of the UID provided
   994 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   820 	and whether the metadata in the database indicates that this data
   995 
   821 	should be backed up or not. The list of database files is populated
   996 /** 
   822 	into the iFileList array.
   997 A simple checksumming algorithm to allow a degree
   823 	@leave
   998 of trust that the backup and restore worked.
   824 	@param TSecureSid the UID of the data owner
   999 Note the file pointer will be back at the start when the function call completes successfully.
   825 */
  1000 In case of an error, the position of the file pointer is undetermined.
   826 void CSqlBackupClient::GetBackupListL(TSecureId aSid)
  1001 
   827 	{
  1002 @param aOpenFile Already opened database file on which the checksum is calculated.
   828 	SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPLISTL, "0x%X;CSqlBackupClient::GetBackupListL;aSid=0x%X", (TUint)this, (TUint)aSid.iId));
  1003 @param aCheckSum Output parameter. The checksum is returned in this parameter.
   829 	// we own the array - the SQL server just populates it
  1004 @return KErrNoMemory, an out of memory condition has occurred;
   830 	iInterface->GetBackUpListL(aSid,iFileList);
  1005                       Note that the function may also return some other system-wide error codes.
   831 	}
  1006 */
   832 
  1007 TInt CSqlBurCallback::CheckSum(const RFile64& aOpenFile, TUint64& aCheckSum) const
   833 /** A simple checksumming algorithm to allow a degree
       
   834 	of trust that the backup and restore worked
       
   835 	This is visble externally because the test harness
       
   836 	needs to use it - NOTE the file pointer will be back at the
       
   837 	start when this function ends.
       
   838 	@leave
       
   839 	@param RFile64 an OPEN file to checksum
       
   840 */
       
   841 TUint64 CSqlBackupClient::CheckSumL(const RFile64& aOpenFile) const
       
   842 	{
  1008 	{
   843 	// scoot through the database file building the checksum
  1009 	// scoot through the database file building the checksum
   844 	TInt64 seekPos=0; // rewind first
  1010 	aCheckSum = 0;
   845 	__SQLLEAVE_IF_ERROR(aOpenFile.Seek(ESeekStart,seekPos));
  1011 	TInt64 seekPos = 0; // rewind first
   846 	TUint64 total=0;
  1012 	TInt err = aOpenFile.Seek(ESeekStart, seekPos);
       
  1013 	if(err != KErrNone)
       
  1014 		{
       
  1015 		return err;
       
  1016 		}
   847 	const TUint KCheckSumBlockSize = 4 * 1024;
  1017 	const TUint KCheckSumBlockSize = 4 * 1024;
   848 	HBufC8* block=HBufC8::NewLC(KCheckSumBlockSize);
  1018 	HBufC8* buf = HBufC8::New(KCheckSumBlockSize);
   849 	TPtr8 ptr=block->Des();
  1019 	if(!buf)
       
  1020 		{
       
  1021 		return KErrNoMemory;
       
  1022 		}
       
  1023 	TPtr8 ptr = buf->Des();
   850 	for(;;)
  1024 	for(;;)
   851 		{
  1025 		{
   852 		__SQLLEAVE_IF_ERROR(aOpenFile.Read(ptr));
  1026 		err = aOpenFile.Read(ptr);
   853 		TInt len=ptr.Length();
  1027 		if(err != KErrNone)
   854 		if(len==0)
  1028 			{
       
  1029 			delete buf;
       
  1030 			return err;
       
  1031 			}
       
  1032 		TInt len = ptr.Length();
       
  1033 		if(len == 0)
   855 			{
  1034 			{
   856 			break;
  1035 			break;
   857 			}
  1036 			}
   858 		// calculate the checksum
  1037 		// calculate the checksum
   859 		for(TInt i=0;i<len;++i)
  1038 		for(TInt i=0;i<len;++i)
   860 			{
  1039 			{
   861 			total = (total << 1) | (total >> 63);
  1040 			aCheckSum = (aCheckSum << 1) | (aCheckSum >> 63);
   862 			total += ptr[i];
  1041 			aCheckSum += ptr[i];
   863  			}
  1042  			}
   864 		};		
  1043 		};		
   865 	CleanupStack::PopAndDestroy(block);
  1044 	delete buf;
   866 	// restore file position
  1045 	// restore file position
   867 	seekPos=0;
  1046 	seekPos = 0;
   868 	__SQLLEAVE_IF_ERROR(aOpenFile.Seek(ESeekStart,seekPos));
  1047 	err = aOpenFile.Seek(ESeekStart,seekPos);
   869 	return total;
  1048 	return err;
   870 	}
  1049 	}
   871 
  1050 
   872 //Reads the content of aInBuf from position aInBufReadPos and stores the data into aOutBuf.
  1051 /**
   873 //aDataLen is the length of the data. If the input buffer does not contain all the data, then only the
  1052 Reads the content of aInBuf from position aInBufReadPos and stores the data into aOutBuf.
   874 //available data will be copied to the output buffer.
  1053 aDataLen is the length of the data. If the input buffer does not contain all the data, then only the
   875 //
  1054 available data will be copied to the output buffer.
   876 //Attention!!! This function won't work properly if aInBuf parameter contains odd number of bytes!!!
  1055 
   877 //(a legacy problem, if it is a problem at all, because the B&R engine probably sends the data in chunks with even size)
  1056 How the function works. It is called during the restore process and aInBuf parameter contains a block of raw
   878 //
  1057 data sent by the B&R server. The calling function, RestoreBaseDataSectionL(), uses a state 
   879 //How the function works. It is called during the restore process and aInBuf parameter contains a block of raw
  1058 machine to processes the incoming data. At particular moment RestoreBaseDataSectionL() will process the data header 
   880 //data sent by the B&R server. The calling function, RestoreBaseDataSectionL(), uses a state 
  1059 and will have to read "aDataLen" 16-bit characters at position "aInBufReadPos". If there are "aDataLen" characters
   881 //machine to processes the incoming data. At particular moment RestoreBaseDataSectionL() will process the data header 
  1060 at position "aInBufReadPos" and enough free space in "aOutBuf", CopyBufData() will copy all of them,  
   882 //and will have to read "aDataLen" 16-bit characters at position "aInBufReadPos". If there are "aDataLen" characters
  1061 otherwise CopyBufData() will copy as much characters as possible (in which case RestoreBaseDataSectionL() will
   883 //at position "aInBufReadPos" and enough free space in "aOutBuf", CopyBufData() will copy all of them,  
  1062 stay in the same state, waiting for more data from the B&R server).
   884 //otherwise CopyBufData() will copy as much characters as possible (in which case RestoreBaseDataSectionL() will
  1063 
   885 //stay in the same state, waiting for more data from the B&R server).
  1064 @param aInBuf        8-bit buffer with input data
   886 //
  1065 @param aInBufReadPos The position in the buffer from which the read operation starts. 
   887 void CSqlBackupClient::CopyBufData(const TDesC8& aInBuf, TInt& aInBufReadPos, TDes& aOutBuf, TInt aDataLen)
  1066                      When the "buffer read" operatio completes, aInBufReadPos is updated with the 
       
  1067                      number of bytes read from the input buffer. 
       
  1068 @param aOutBuf       16-bit output buffer. The data read from the input buffer is stored in the output buffer.
       
  1069 @param aDataLen      How much bytes to be read from the input buffer. Note that if there is not enough
       
  1070                      data in the input buffer, the function will read as much as possible from the input buffer.
       
  1071                      The aInBufReadPos in/out parameter will be updated with the actual number of bytes read.                     
       
  1072 */
       
  1073 void CSqlBurCallback::CopyBufData(const TDesC8& aInBuf, TInt& aInBufReadPos, TDes& aOutBuf, TInt aDataLen)
   888 	{
  1074 	{
   889     __ASSERT_DEBUG(aInBufReadPos >= 0, __SQLPANIC(ESqlPanicBadArgument));
  1075     __ASSERT_DEBUG(aInBufReadPos >= 0, __SQLPANIC(ESqlPanicBadArgument));
   890     __ASSERT_DEBUG(aDataLen > 0, __SQLPANIC(ESqlPanicBadArgument));
  1076     __ASSERT_DEBUG(aDataLen > 0, __SQLPANIC(ESqlPanicBadArgument));
   891     __ASSERT_DEBUG(!(aInBuf.Length() & 0x01), __SQLPANIC(ESqlPanicInternalError));
       
   892 	
  1077 	
   893 	TInt needed = (aDataLen - aOutBuf.Length()) << K8to16bitShift;
  1078 	TInt needed = (aDataLen - aOutBuf.Length()) << K8to16bitShift;
   894 	TInt available = aInBuf.Size() - aInBufReadPos;
  1079 	TInt available = aInBuf.Size() - aInBufReadPos;
   895 	TInt len = Min(needed, available);
  1080 	TInt len = Min(needed, available);
   896 	TPtrC8 ptr8 = aInBuf.Mid(aInBufReadPos, len);
  1081 	TPtrC8 ptr8 = aInBuf.Mid(aInBufReadPos, len);
   897 	aInBufReadPos += len;
  1082 	aInBufReadPos += len;
   898 	
  1083 	
   899 	len >>= K8to16bitShift;
  1084 	len >>= K8to16bitShift;
   900 	aOutBuf.Append((const TUint16*)ptr8.Ptr(), len);
  1085 	aOutBuf.Append((const TUint16*)ptr8.Ptr(), len);
   901 	}
  1086 	}
       
  1087 
       
  1088 /**
       
  1089 Cleans up the allocated during the backup resources - file handles, buffers allocated for the file names.
       
  1090 */
       
  1091 void CSqlBurCallback::BackupCleanup()
       
  1092 	{
       
  1093 	for(TInt i=0;i<iFileList.Count();++i)
       
  1094 		{
       
  1095 		delete iFileList[i];
       
  1096 		}
       
  1097 	iFileList.Close();
       
  1098 	iFile.Close();
       
  1099 	}
       
  1100 
       
  1101 /**
       
  1102 Deletes created during the restore temporary files.
       
  1103 */
       
  1104 TInt CSqlBurCallback::RestoreCleanup()
       
  1105 	{
       
  1106 	if(iRestoreDir.Find(KSqlBurRestoreDir) < 0)
       
  1107 		{//iRestoreDir is not initialized - that means RestoreCleanup() was called either from the
       
  1108 		 //destructor or from the TerminateMultistageOperation() during a backup.
       
  1109 		return KErrNone;
       
  1110 		}
       
  1111 	iFile.Close();
       
  1112 	CFileMan* fm = NULL;
       
  1113 	TRAPD(err, fm = CFileMan::NewL(iInterface.Fs()));
       
  1114 	if(err == KErrNone)
       
  1115 		{
       
  1116 		TFileName allFiles;
       
  1117 		allFiles.Copy(iRestoreDir);
       
  1118 		allFiles.Append(KSqlBurAllFiles);
       
  1119 		err = fm->Delete(allFiles);
       
  1120 		delete fm;
       
  1121 		}
       
  1122 	return err;
       
  1123 	}
       
  1124 
       
  1125 /**
       
  1126 Stores the error occured during backup for furhter processing.
       
  1127 Please note that the function asserts if the aError parameter is KErrNone.
       
  1128 Call the function only with a real error.
       
  1129 
       
  1130 @param aError The backup error to be stored 
       
  1131 */
       
  1132 void CSqlBurCallback::SetBackupError(TInt aError)
       
  1133 	{
       
  1134 	__ASSERT_DEBUG(aError != KErrNone, __SQLPANIC(ESqlPanicBadArgument));
       
  1135 	if(aError != KErrNotFound && aError != KErrPathNotFound)
       
  1136 		{
       
  1137 		if(iBackupError == KErrNone || aError == KErrDiskFull || aError == KErrCorrupt)
       
  1138 			{
       
  1139 			iBackupError = aError;
       
  1140 			}
       
  1141 		}
       
  1142 	}