1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sql/SRC/Server/SqlBur.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1142 @@
1.4 +// Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "SqlBur.h"
1.20 +#include "SqlAssert.h"
1.21 +#include "OstTraceDefinitions.h"
1.22 +#ifdef OST_TRACE_COMPILER_IN_USE
1.23 +#include "SqlBurTraces.h"
1.24 +#endif
1.25 +#include "SqlTraceDef.h"
1.26 +
1.27 +#define UNUSED_ARG(arg) arg = arg
1.28 +
1.29 +_LIT(KSqlBurBackupExt, ".bak");
1.30 +_LIT(KSqlBurRestoreDir, "temprestore");
1.31 +_LIT(KSqlBurAllFiles, "*");
1.32 +
1.33 +const TUint K8to16bitShift = 1;
1.34 +
1.35 +//Extracts and returns 32-bit integer from aNumBuf buffer.
1.36 +static TUint32 GetNumUint32L(const TDesC& aNumBuf)
1.37 + {
1.38 + TLex lex(aNumBuf);
1.39 + lex.SkipSpace();
1.40 + TUint32 num = 0xFFFFFFFF;
1.41 + __SQLLEAVE_IF_ERROR2(lex.Val(num, EHex));
1.42 + return num;
1.43 + }
1.44 +
1.45 +//Extracts and returns 64-bit integer from aNumBuf buffer.
1.46 +static TInt64 GetNumInt64L(const TDesC& aNumBuf)
1.47 + {
1.48 + TLex lex(aNumBuf);
1.49 + lex.SkipSpace();
1.50 + TInt64 num = -1;
1.51 + __SQLLEAVE_IF_ERROR2(lex.Val(num, EHex));
1.52 + return num;
1.53 + }
1.54 +
1.55 +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.56 +/////////////////////////////// CSqlBurEventMonitor //////////////////////////////////////////////////////////
1.57 +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.58 +
1.59 +/**
1.60 +Standard two phase construction. Creates a CSqlBurEventMonitor instance.
1.61 +@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
1.62 +@return An instance of the backup notifier
1.63 +@leave KErrNoMemory, an out of memory condition has occurred;
1.64 + Note that the function may also leave with some other system-wide error codes.
1.65 +*/
1.66 +CSqlBurEventMonitor* CSqlBurEventMonitor::NewL(MSqlSrvBurInterface& aInterface)
1.67 + {
1.68 + CSqlBurEventMonitor* self = new (ELeave) CSqlBurEventMonitor(aInterface);
1.69 + CleanupStack::PushL(self);
1.70 + self->ConstructL();
1.71 + CleanupStack::Pop(self);
1.72 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_NEWL, "0x%X;CSqlBurEventMonitor::NewL", (TUint)self));
1.73 + return self;
1.74 + }
1.75 +
1.76 +/**
1.77 +Releases the allocated resources.
1.78 +*/
1.79 +CSqlBurEventMonitor::~CSqlBurEventMonitor()
1.80 + {
1.81 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_CSQLBACKUPNOTIFIER2, "0x%X;CSqlBurEventMonitor::~CSqlBurEventMonitor", (TUint)this));
1.82 + Cancel();
1.83 + iBurProperty.Close();
1.84 + DestroyContent();
1.85 + }
1.86 +
1.87 +/**
1.88 +Initializes data members with their default values.
1.89 +@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
1.90 +*/
1.91 +CSqlBurEventMonitor::CSqlBurEventMonitor(MSqlSrvBurInterface& aInterface) :
1.92 + CActive(EPriorityStandard),
1.93 + iBurInterface(aInterface)
1.94 + {
1.95 + }
1.96 +
1.97 +/**
1.98 +Initializes the created CSqlBurEventMonitor object.
1.99 +@leave KErrNoMemory, an out of memory condition has occurred;
1.100 + Note that the function may also leave with some other system-wide error codes.
1.101 +*/
1.102 +void CSqlBurEventMonitor::ConstructL()
1.103 + {
1.104 + __SQLLEAVE_IF_ERROR(iBurProperty.Attach(KSqlBurPropertyCategoryUid, KSqlBurBackupRestoreKey));
1.105 + CActiveScheduler::Add(this);
1.106 + iBurProperty.Subscribe(iStatus);
1.107 + SetActive();
1.108 + }
1.109 +
1.110 +/**
1.111 +RunL() is called when the value of the {KUidSystemCategory, KUidBackupRestoreKey} gets changed.
1.112 +That indicates: a backup or a restore is about to begin.
1.113 +
1.114 +How the function works:
1.115 + - When a backup or restore notification is received, the function will subscribe again for notifications from
1.116 + the backup and restore property and will read the property status;
1.117 + - If the property status is conn::EBURUnset or conn::EBURNormal, the function will destroy iSqlBurCallback
1.118 + and iActiveBackupClient interfaces. No more callbacks will be reseived from the backup and restore server.
1.119 + This is the end of the backup or restore processing;
1.120 + - If the property status is conn::EBURBackupFull, conn::EBURBackupPartial, conn::EBURRestoreFull or
1.121 + conn::EBURRestorePartial, the function will create iSqlBurCallback and iActiveBackupClient interface
1.122 + (iActiveBackupClient's NewL() receives iSqlBurCallback as an input parameter, registering this way the callback
1.123 + in the backup and restore server to be called later, when sending or retrieving data to/from the server).
1.124 + If the property read and the interface creation operations have been successful, the function will call
1.125 + ConfirmReadyForBURL(KErrNone) to notify the backup and restore server that the SQL server is ready to send/retrieve
1.126 + backup/restore data.
1.127 + If the current notification is that a backup is about to begin, after the confirmation the backup and restore server will
1.128 + call CSqlBurCallback::InitialiseGetProxyBackupDataL() once per {client secure id, drive}
1.129 + followed by CSqlBurCallback::GetBackupDataSectionL() calls to retrieve the backup data.
1.130 + If the current notification is that a restore is about to begin, after the confirmation the backup and restore server will
1.131 + call CSqlBurCallback::InitialiseRestoreProxyBaseDataL() once per {client secure id, drive}
1.132 + followed by CSqlBurCallback::RestoreBaseDataSectionL() calls to send the restore data.
1.133 +
1.134 +The current implementation has one design flaw. If a backup or restore notification is received, there are at lest 3
1.135 +places before the ConfirmReadyForBURL() call, where the code may leave:
1.136 + - the "property get" operation;
1.137 + - the iSqlBurCallback creation;
1.138 + - the iActiveBackupClient creation;
1.139 +If a leave occurs at some of the mentioned places, that leave will be trapped by the current CActiveScheduler object
1.140 +and CSqlBurEventMonitor::RunError() will be called with the leaved error code.
1.141 +Problem #1: CSqlBurEventMonitor::RunError() won't do anything with the error (apart from printing a trace in the OST builds).
1.142 + The error is silently suppressed. The backup or restore won't start. But the client won't see any notification
1.143 + for that problem.
1.144 +Problem #2: ConfirmReadyForBURL() won't be called. According to the backup and restore documentation, if
1.145 + ConfirmReadyForBURL() is called with KErrNone parameter, that's a confirmation for the backup and restore
1.146 + server to start the processing. If ConfirmReadyForBURL() is called with an error different than KErrNone,
1.147 + that's a confirmation for the backup and restore server that the client is not ready. No backup or restore
1.148 + will be started. The remote backup client will be notified about the problem.
1.149 +After an investigation it was found that the same problems do exist in all active backup clients, none of them has
1.150 +solved the problems. Then, the code here will be kept as it is, it might be too dangerous to do a change right now.
1.151 +
1.152 +@see CSqlBurEventMonitor::RunError()
1.153 +@see CSqlBurCallback
1.154 +@see CActiveBackupClient
1.155 +@see CSqlBurCallback::InitialiseGetProxyBackupDataL()
1.156 +@see CSqlBurCallback::GetBackupDataSectionL()
1.157 +@see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
1.158 +@see CSqlBurCallback::RestoreBaseDataSectionL()
1.159 +
1.160 +@leave KErrNoMemory, an out of memory condition has occurred;
1.161 + Note that the function may also leave with some other system-wide error codes.
1.162 +*/
1.163 +void CSqlBurEventMonitor::RunL()
1.164 + {
1.165 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL_ENTRY, "Entry;0x%X;CSqlBurEventMonitor::RunL", (TUint)this));
1.166 + iBurProperty.Subscribe(iStatus);
1.167 + SetActive();
1.168 + TInt status;
1.169 + __SQLLEAVE_IF_ERROR(iBurProperty.Get(status));
1.170 + status &= conn::KBURPartTypeMask;
1.171 +#ifdef _SQL_RDEBUG_PRINT
1.172 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL1, "0x%X;CSqlBurEventMonitor::RunL;status=%d", (TUint)this, status));
1.173 +#else
1.174 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_RUNL2, "0x%X;CSqlBurEventMonitor::RunL;status=%{TBURPartType}", (TUint)this, status));
1.175 +#endif
1.176 + switch(status)
1.177 + {
1.178 + case conn::EBURBackupFull:
1.179 + case conn::EBURBackupPartial:
1.180 + case conn::EBURRestoreFull:
1.181 + case conn::EBURRestorePartial:
1.182 + {
1.183 + // we only do full backups and full restores
1.184 + if(!(iSqlBurCallback && iActiveBackupClient))
1.185 + {
1.186 + DestroyContent();
1.187 + TRAPD(err, CreateContentL());
1.188 + if(err != KErrNone)
1.189 + {
1.190 + DestroyContent();
1.191 + __SQLLEAVE(err);
1.192 + }
1.193 + }
1.194 + iActiveBackupClient->ConfirmReadyForBURL(KErrNone);
1.195 + }
1.196 + break;
1.197 + //case conn::EBURUnset:
1.198 + //case conn::EBURNormal:
1.199 + default:
1.200 + DestroyContent();
1.201 + break;
1.202 + }
1.203 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPNOTIFIER_EXIT, "Exit;0x%X;CSqlBurEventMonitor::RunL", (TUint)this));
1.204 + SQL_BUR_TEST_STOP();
1.205 + }
1.206 +
1.207 +/**
1.208 +Cancels the subscribtion for {KUidSystemCategory, KUidBackupRestoreKey} property changes.
1.209 +*/
1.210 +void CSqlBurEventMonitor::DoCancel()
1.211 + {
1.212 + iBurProperty.Cancel();
1.213 + }
1.214 +
1.215 +/**
1.216 +No-op. The method does nothing with the reported from CSqlBurEventMonitor::RunL() error
1.217 +(apart from logging a trace in OST builds).
1.218 +Actually, the right action is to return KErrNone (as it is implemented), otherwise the default implementation of
1.219 +CActiveScheduler::Error() will panic the current thread.
1.220 +
1.221 +@see CActiveScheduler::Error()
1.222 +@see CSqlBurEventMonitor::RunL()
1.223 +
1.224 +@return The RunL() error, if the RunL() call leaves.
1.225 +@param The RunL() error
1.226 +*/
1.227 +TInt CSqlBurEventMonitor::RunError(TInt aError)
1.228 + {
1.229 + UNUSED_ARG(aError);
1.230 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RUNERROR, "0x%X;CSqlBurEventMonitor::RunError;aError=%d", (TUint)this, aError));
1.231 + SQL_BUR_TEST_SET_ERROR(aError);
1.232 + SQL_BUR_TEST_STOP();
1.233 + return KErrNone;
1.234 + }
1.235 +
1.236 +/**
1.237 +Creates iActiveBackupClient and iSqlBurCallback objects.
1.238 +*/
1.239 +void CSqlBurEventMonitor::CreateContentL()
1.240 + {
1.241 + iSqlBurCallback = CSqlBurCallback::NewL(iBurInterface);
1.242 + iActiveBackupClient = conn::CActiveBackupClient::NewL(iSqlBurCallback);
1.243 + }
1.244 +
1.245 +/**
1.246 +Destroys iActiveBackupClient and iSqlBurCallback objects.
1.247 +*/
1.248 +void CSqlBurEventMonitor::DestroyContent()
1.249 + {
1.250 + delete iActiveBackupClient;
1.251 + iActiveBackupClient = NULL;
1.252 + delete iSqlBurCallback;
1.253 + iSqlBurCallback = NULL;
1.254 + }
1.255 +
1.256 +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.257 +/////////////////////////////// CSqlBackupClient /////////////////////////////////////////////////////////////
1.258 +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.259 +
1.260 +
1.261 +/**
1.262 +Creates new CSqlBurCallback instance.
1.263 +The CSqlBurEventMonitor object monitors the state of the {KUidSystemCategory, KUidBackupRestoreKey}
1.264 +property. When a backup or a restore is about to begin, the CSqlBurEventMonitor object creates a
1.265 +CSqlBurCallback instance, establishes a connection with the B&R server and passes a pointer to
1.266 +the CSqlBurCallback callback to the BYR conenction.
1.267 +The CSqlBurCallback methods will be called during the backup/restore for sending/retrieving data.
1.268 +
1.269 +@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
1.270 +@return A pointer to the created CSqlBurCallback instance
1.271 +@leave KErrNoMemory, an out of memory condition has occurred;
1.272 + Note that the function may also leave with some other system-wide error codes.
1.273 +*/
1.274 +CSqlBurCallback* CSqlBurCallback::NewL(MSqlSrvBurInterface& aInterface)
1.275 + {
1.276 + CSqlBurCallback* self = new (ELeave) CSqlBurCallback(aInterface);
1.277 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_NEWLC, "0x%X;CSqlBurCallback::NewL", (TUint)self));
1.278 + return self;
1.279 + }
1.280 +
1.281 +/**
1.282 +Initializes CSqlBurCallback data members with their default values.
1.283 +@param aInterface A reference to an interface that is used for retrieving list of databases to be sent for backup.
1.284 +*/
1.285 +CSqlBurCallback::CSqlBurCallback(MSqlSrvBurInterface& aInterface) :
1.286 + iInterface(aInterface)
1.287 + {
1.288 + }
1.289 +
1.290 +/**
1.291 +Releases the allocated resources.
1.292 +*/
1.293 +CSqlBurCallback::~CSqlBurCallback()
1.294 + {
1.295 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_CSQLBACKUPCLIENT2, "0x%X;CSqlBurCallback::~CSqlBurCallback;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
1.296 + BackupCleanup();
1.297 + (void)RestoreCleanup();
1.298 + }
1.299 +
1.300 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.301 +///////////////////////////////////// Full backup //////////////////////////////////////////////////////////
1.302 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.303 +
1.304 +/**
1.305 +This is called to let us know that the given SID is to be backed up.
1.306 +We ask the SQL server (using iInterface, see MSqlSrvBurInterface for more details)
1.307 +for a list of databases that want to be backed up.
1.308 +
1.309 +The backup is initiated by a notification received in CSqlBurEventMonitor::RunL() method.
1.310 +InitialiseGetProxyBackupDataL() is called once per {client secure id, drive} and each
1.311 +InitialiseGetProxyBackupDataL() call is followed after that by a set of CSqlBurCallback::GetBackupDataSectionL() calls,
1.312 +made from the backup and restore client dll.
1.313 +
1.314 +During GetBackupDataSectionL() calls the CSqlBurCallback object will read the content of the databases from the list,
1.315 +retrieved from the MSqlSrvBurInterface::GetBackUpListL() call and send the content to the backup and restore server.
1.316 +
1.317 +@see MSqlSrvBurInterface
1.318 +@see CSqlBurEventMonitor::RunL()
1.319 +@see CSqlBurCallback::GetBackupDataSectionL()
1.320 +@see CSqlServer::GetBackUpListL()
1.321 +
1.322 +@param aSid the UID of the application to backup
1.323 +@param aDrive the drive to be backed up
1.324 +@leave KErrNoMemory, an out of memory condition has occurred;
1.325 + Note that the function may also leave with some other system-wide error codes.
1.326 +*/
1.327 +void CSqlBurCallback::InitialiseGetProxyBackupDataL(TSecureId aSid, TDriveNumber aDrive)
1.328 + {
1.329 + SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZEGETPROXYBACKUPDATAL, "0x%X;CSqlBurCallback::InitialiseGetProxyBackupDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
1.330 + BackupCleanup();
1.331 + iInterface.GetBackUpListL(aSid, aDrive, iFileList);
1.332 + iFileIndex = 0;
1.333 + iState = EBackupNoFileOpen;
1.334 + iBackupError = KErrNone;
1.335 + }
1.336 +
1.337 +/**
1.338 +This is supposed to allow the B&R framework to know in advance how much
1.339 +data is coming - but unfortunately there is no way to know this
1.340 +at this stage since we don't even know yet what SID is being processed
1.341 +So we just answer some number to make the BUE happy. It doesn't
1.342 +actually rely on this number so there is no risk - the aFinishedFlag
1.343 +indicates the end of data, not the value returned here. It is
1.344 +supposed to allow the BUE to optimise its behaviour by know up front
1.345 +the data volume.
1.346 +
1.347 +@see CSqlBurEventMonitor::RunL()
1.348 +@see CSqlBurCallback::InitialiseGetProxyBackupDataL()
1.349 +
1.350 +@param aDrive Unused parameter (the drive number is logged in OST builds).
1.351 +@return an arbitrary number (1024 at the moment)
1.352 +*/
1.353 +TUint CSqlBurCallback::GetExpectedDataSize(TDriveNumber aDrive)
1.354 + {
1.355 + UNUSED_ARG(aDrive);
1.356 + // we have no idea at this point - we even don't know who is to be backed up yet
1.357 + const TUint KArbitraryNumber = 1024;
1.358 + SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETEXPECTEDDATASIZE, "0x%X;CSqlBurCallback::GetExpectedDataSize;aDrive=%d;rc=%u", (TUint)this, (TInt)aDrive, KArbitraryNumber));
1.359 + return KArbitraryNumber;
1.360 + }
1.361 +
1.362 +/**
1.363 +This is the backup state machine
1.364 +Because the data has to be sent back in sections and the various
1.365 +components of the dataflow may straddle chunks, we have to keep
1.366 +track of where we are between each transfer - a state machine is
1.367 +the simplest and most understandable implementation.
1.368 +
1.369 +Please note how the function processes the errors occuring during the backup.
1.370 +If an error occurs, the error is not propagated back to the B&R server immediatelly.
1.371 +The error is stored in iBurError data member and is reported at the end of the backup process.
1.372 +The reason for such unusual error reporting poicy is: the SQL server performs full backup of possibly more
1.373 +than one database file. If an error occurs during the backup of the first file for example, the backup
1.374 +process should not stop at that point. All files will be processed and then at the end, the error will be reproted.
1.375 +
1.376 +In details, the function runs a state machine, where:
1.377 + - every file in the list retrieved in InitialiseGetProxyBackupDataL() is opened;
1.378 + - the file is read and 32-bit checksum over the file data - calculated;
1.379 + - a file backup header is prepared, including there the file size, file name, file name length, protocol verison number
1.380 + and the checksum. The header is sent to the backup restore server;
1.381 + - the file data is read and sent to the backup and restore server;
1.382 + - during the described above sequence no leave ever occurs. The error that occurs during the file processing,
1.383 + is stored into a data member of CSqlBurCallback class. At the end, after the last file in the list is processed,
1.384 + the backup and restore server will get a notification (via a User::Leave() call) regarding the error;
1.385 + The used error reporting policy allows all files to be process without interrupting the backup process.
1.386 + For example, if there are 5 files to be sent to the backup and restore server, an error that occurs during the
1.387 + processing of file #3, won't prevent files #4 and #5 from being sent for backup.
1.388 +
1.389 +@see CSqlBurEventMonitor::RunL()
1.390 +@see CSqlBurCallback::InitialiseGetProxyBackupDataL()
1.391 +
1.392 +@param aBuffer Output parameter, the buffer where the data will be put to be passed back
1.393 +@param aFinishedFlag Set to true when all data has been submitted for backup
1.394 +@leave KErrNoMemory, an out of memory condition has occurred;
1.395 + Note that the function may also leave with some other system-wide error codes.
1.396 +*/
1.397 +void CSqlBurCallback::GetBackupDataSectionL(TPtr8& aBuffer, TBool& aFinishedFlag)
1.398 + {
1.399 + // don't assume they set it to false
1.400 + aFinishedFlag=EFalse;
1.401 + // any files to backup
1.402 + if(iFileList.Count()==0)
1.403 + {
1.404 + // nothing to backup
1.405 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL1, "0x%X;CSqlBurCallback::GetBackupDataSectionL;file count is 0", (TUint)this));
1.406 + aFinishedFlag = ETrue;
1.407 + BackupCleanup();
1.408 + return;
1.409 + }
1.410 +
1.411 + // run the state machine
1.412 + for(TInt bufFreeSpace=aBuffer.MaxSize()-aBuffer.Size(); bufFreeSpace>0; bufFreeSpace=aBuffer.MaxSize()-aBuffer.Size())
1.413 + {
1.414 + switch(iState)
1.415 + {
1.416 + case EBackupNoFileOpen: // open a file for processing
1.417 + {
1.418 + if(iFileIndex>=iFileList.Count())
1.419 + {// all files have been processed - send the finished flag
1.420 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL2, "0x%X;CSqlBurCallback::GetBackupDataSectionL;all files processed;iBackupError=%d", (TUint)this, iBackupError));
1.421 + aFinishedFlag = ETrue;
1.422 + BackupCleanup();
1.423 + __SQLLEAVE_IF_ERROR(iBackupError);
1.424 + return;
1.425 + }
1.426 + // open the database file to send
1.427 + TPtrC fname = iFileList[iFileIndex]->Des();
1.428 + TInt err = iFile.Open(iInterface.Fs(), fname, EFileRead | EFileShareExclusive);
1.429 + 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));
1.430 + if(KErrNone != err)
1.431 + {
1.432 + // there's nothing we can do if we can't open the file so we just skip it
1.433 + SetBackupError(err);
1.434 + ++iFileIndex;
1.435 + break;
1.436 + }
1.437 + iState=EBackupOpenNothingSent;
1.438 + break;
1.439 + }
1.440 + case EBackupOpenNothingSent: // nothing sent (so far) for this file - send the header info
1.441 + {
1.442 + TInt64 fileSize;
1.443 + TInt err = iFile.Size(fileSize);
1.444 + if(KErrNone != err)
1.445 + {
1.446 + SetBackupError(err);
1.447 + iState = EBackupEndOfFile;
1.448 + break;
1.449 + }
1.450 +
1.451 + TUint64 checksum64 = 0;
1.452 + err = CheckSum(iFile, checksum64);
1.453 + SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL4, "0x%X;CSqlBurCallback::GetBackupDataSectionL;CheckSum();iFileIndex=%d;err=%d", (TUint)this, iFileIndex, err));
1.454 + if(err != KErrNone)
1.455 + {
1.456 + //An error occured while reading the file (or there was not enough memory for the read buffer)
1.457 + SetBackupError(err);
1.458 + iState = EBackupEndOfFile;
1.459 + break;
1.460 + }
1.461 + // Only grab last 4 bytes of the checksum - enough to be satisfied that the backup and restore worked ok
1.462 + TUint32 checksum32 = checksum64 & KMaxTUint32;
1.463 +
1.464 + // build the header - this is an instance member because it
1.465 + // has to persist over multiple calls to this method
1.466 + TPtrC fname = iFileList[iFileIndex]->Des();
1.467 + iBuffer.Format(_L("%8x%8x%4x%16lx%8x%S"),
1.468 + checksum32, // %8x
1.469 + KSqlBurMagicNum, // %8x
1.470 + KSqlBurHeaderVersion, // %4x
1.471 + fileSize, // %16lx
1.472 + fname.Length(), // %8x
1.473 + &fname); // %S
1.474 + 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));
1.475 +
1.476 + // we need it to look like an 8bit buffer
1.477 + TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size());
1.478 +
1.479 + TInt len = Min(hdrPtr8.Size(), bufFreeSpace);
1.480 +
1.481 + // append the header to the buffer (only till it's full)
1.482 + aBuffer.Append(hdrPtr8.Ptr(), len);
1.483 +
1.484 + // decide what needs to happen next
1.485 + // if complete then we need data, otherwise we need to put
1.486 + // the rest of the header in the next chunk
1.487 + if(hdrPtr8.Size() <= bufFreeSpace)
1.488 + {
1.489 + iState = EBackupOpenAllHeaderSent;
1.490 + }
1.491 + else
1.492 + {
1.493 + // we need to keep track of how much of the header has
1.494 + // been sent so that we only send the reminder on the next
1.495 + // iteration
1.496 + iHeaderSent = len;
1.497 + iState = EBackupOpenPartHeaderSent;
1.498 + }
1.499 + break;
1.500 + }
1.501 + case EBackupOpenPartHeaderSent: // need to send the rest of the header
1.502 + {
1.503 + // get back the header - this is already loaded with the necessary info
1.504 + // from the previous state we were in - EBackupOpenNothingSent
1.505 +
1.506 + // we need it to look like an 8bit buffer
1.507 + TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size());
1.508 +
1.509 + // how many bytes have we yet to send?
1.510 + TInt bytesRemaining = hdrPtr8.Size() - iHeaderSent;
1.511 + TInt len = Min(bytesRemaining, bufFreeSpace);
1.512 + aBuffer.Append(hdrPtr8.Ptr() + iHeaderSent, len);
1.513 +
1.514 + if(bytesRemaining <= bufFreeSpace)
1.515 + {
1.516 + iHeaderSent = 0; // ready for next header
1.517 + iState = EBackupOpenAllHeaderSent;
1.518 + }
1.519 + else
1.520 + {
1.521 + iHeaderSent += len; // ready to do round again
1.522 + //iState=EBackupOpenPartHeaderSent; same state as now!
1.523 + }
1.524 + break;
1.525 + }
1.526 + case EBackupOpenAllHeaderSent: // need to send some data
1.527 + {
1.528 + TPtr8 ptr((TUint8*)aBuffer.Ptr() + aBuffer.Size(), 0, bufFreeSpace);
1.529 + TInt err = iFile.Read(ptr);
1.530 + if(err != KErrNone)
1.531 + {
1.532 + //An error occured while reading the file
1.533 + SetBackupError(err);
1.534 + iState = EBackupEndOfFile;
1.535 + SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_GETBACKUPDATASECTIONL6, "0x%X;CSqlBurCallback::GetBackupDataSectionL;File read;iFileIndex=%d;err=%d", (TUint)this, iFileIndex, err));
1.536 + break;
1.537 + }
1.538 + TInt bytesRead = ptr.Size();
1.539 + aBuffer.SetLength(aBuffer.Size() + bytesRead);
1.540 + // EOF
1.541 + if(bytesRead == 0)
1.542 + {
1.543 + iState = EBackupEndOfFile;
1.544 + break;
1.545 + }
1.546 + break;
1.547 + }
1.548 + case EBackupEndOfFile:
1.549 + {
1.550 + 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));
1.551 + iFile.Close();
1.552 + ++iFileIndex; // move on to next file
1.553 + iState = EBackupNoFileOpen; // go round again
1.554 + break;
1.555 + }
1.556 + default:
1.557 + __ASSERT_DEBUG(EFalse, __SQLPANIC(ESqlPanicInternalError));
1.558 + break;
1.559 + }//end of the "switch" statement
1.560 + }//end of the "for" statement
1.561 + }
1.562 +
1.563 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.564 +///////////////////////////////////// Full restore /////////////////////////////////////////////////////////
1.565 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.566 +
1.567 +/**
1.568 +Called when the BUE wants to start sending data to us.
1.569 +Creates the folder (if the folder does not exist) where the temporary files will be created during the restore process.
1.570 +Deletes all files from the restore folder.
1.571 +
1.572 +The restore is initiated by a notification received in CSqlBurEventMonitor::RunL() method.
1.573 +InitialiseRestoreProxyBaseDataL() is called once per {client secure id, drive} and each
1.574 +InitialiseRestoreProxyBaseDataLL() call is followed after that by a set of CSqlBurCallback::RestoreBaseDataSectionL()
1.575 +calls, made from the backup and restore client dll.
1.576 +
1.577 +During RestoreBaseDataSectionLL() calls the CSqlBurCallback object will receive data from the backup and resore server.
1.578 +
1.579 +@see CSqlBurEventMonitor::RunL()
1.580 +@see CSqlBurCallback::RestoreBaseDataSectionL()
1.581 +
1.582 +@param aSid the UID of the application that is to be restored. Not used (only logged in OST builds).
1.583 +@param aDrive the drive to restore.
1.584 +@leave KErrNoMemory, an out of memory condition has occurred;
1.585 + Note that the function may also leave with some other system-wide error codes.
1.586 +*/
1.587 +void CSqlBurCallback::InitialiseRestoreProxyBaseDataL(TSecureId aSid, TDriveNumber aDrive)
1.588 + {
1.589 + UNUSED_ARG(aSid);
1.590 + UNUSED_ARG(aDrive);
1.591 + SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_INITIALIZERESTOREPROXYBASEDATAL, "0x%X;CSqlBurCallback::InitialiseRestoreProxyBaseDataL;aSid=0x%X;aDrive=%d", (TUint)this, (TUint)aSid.iId, (TInt)aDrive));
1.592 + iBuffer.Zero();
1.593 + iState = ERestoreExpectChecksum;
1.594 + iRestoreDrive = aDrive;
1.595 + iRestoreId = aSid;
1.596 + //Create the directory for the temporary files created during the restore process.
1.597 + TFileName privatePath;
1.598 + __SQLLEAVE_IF_ERROR(iInterface.Fs().PrivatePath(privatePath));
1.599 + TDriveUnit driveUnit(iRestoreDrive);
1.600 + TDriveName driveName = driveUnit.Name();
1.601 + privatePath.Insert(0, driveName);
1.602 + __SQLLEAVE_IF_ERROR(iParse.Set(KSqlBurRestoreDir, &privatePath, 0));
1.603 + iRestoreDir.Copy(iParse.FullName());
1.604 + iRestoreDir.Append(KPathDelimiter);
1.605 + TInt err = iInterface.Fs().MkDirAll(iRestoreDir);
1.606 + if(err != KErrAlreadyExists)
1.607 + {
1.608 + __SQLLEAVE_IF_ERROR(err);
1.609 + }
1.610 + //Cleanup the restore directory
1.611 + err = RestoreCleanup();
1.612 + if(err != KErrNotFound)
1.613 + {
1.614 + __SQLLEAVE_IF_ERROR(err);
1.615 + }
1.616 + }
1.617 +
1.618 +/**
1.619 +This is called by BUE when the restore has completed.
1.620 +
1.621 +@see CSqlBurEventMonitor::RunL()
1.622 +@see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
1.623 +
1.624 +@param aDrive the drive that is being restored. Not used (only logged in OST builds).
1.625 +*/
1.626 +void CSqlBurCallback::RestoreComplete(TDriveNumber aDrive)
1.627 + {
1.628 + UNUSED_ARG(aDrive);
1.629 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTORECOMPLETE, "0x%X;CSqlBurCallback::RestoreComplete;aDrive=%d", (TUint)this, (TInt)aDrive));
1.630 + iRestoreDrive = TDriveNumber(-1);
1.631 + iRestoreId = TSecureId(KNullUid);
1.632 + }
1.633 +
1.634 +/**
1.635 +This is repeatedly called by the BUE to send us chunks of restore data (for the current SID)
1.636 +Becuase the data is spread over chunks we need to manage the state across mutiple calls
1.637 +to this method so we use a state machine.
1.638 +
1.639 +The function runs the state machine and for each file block detected in the coming data, the function does:
1.640 + - creates a temporary file in the restore directory (created by InitialiseRestoreProxyBaseDataL());
1.641 + - stores the file data in the created temporary file;
1.642 + - During the 2 steps descirbed above, if an error occurs, that erro will be reproted to the backup and restore
1.643 + server (via a User::Leave() call);
1.644 + - When all data is received and stored in temporary files in the restore directory,
1.645 + for each received file the function will:
1.646 + = move the original database file to the restore directory with a ".bak" extension added to the file name;
1.647 + = move the temporary file, which has the same name as the original database file, to the location of the
1.648 + original database file - the SQL server private data cage;
1.649 + = delete the file with the ".bak" extension;
1.650 + The three steps described above are implemented as "all or none" operation - if an error occurs during step (2),
1.651 + the content of the original database file will be restored from the file with the ".bak" extension.
1.652 +
1.653 +@see CSqlBurEventMonitor::RunL()
1.654 +@see CSqlBurCallback::InitialiseRestoreProxyBaseDataL()
1.655 +
1.656 +@param aInBuffer Buffer with data to be restored
1.657 +@param aFinishedFlag Set when there is not more data to restore
1.658 +@leave KErrNoMemory, an out of memory condition has occurred;
1.659 + Note that the function may also leave with some other system-wide error codes.
1.660 +*/
1.661 +void CSqlBurCallback::RestoreBaseDataSectionL(TDesC8& aInBuffer, TBool aFinishedFlag)
1.662 + {
1.663 + // used to walk the buffer
1.664 + // got a new buffer - because each time this method is called, we have a
1.665 + // fresh chunk of data
1.666 + TInt inBufferPos = 0;
1.667 +
1.668 + // to mark when the state machine is through
1.669 + TBool done = EFalse;
1.670 +
1.671 + // check whether this is an empty restore
1.672 + if(aFinishedFlag && aInBuffer.Size() == 0)
1.673 + {
1.674 + return;
1.675 + }
1.676 +
1.677 + TInt iterations = 0;
1.678 +
1.679 + // run the state machine
1.680 + do
1.681 + {
1.682 + // how many bytes are there available in the buffer for processing?
1.683 + TInt bytesAvailable = aInBuffer.Size() - inBufferPos;
1.684 + // the reason why we are testing finishedFlag is because we must
1.685 + // make sure we re-enter the machine to do the tidyup
1.686 + if(bytesAvailable <= 0 && !aFinishedFlag)
1.687 + {
1.688 + // ran out of data in the chunk
1.689 + // so we return and wait for more data to arrive
1.690 + return;
1.691 + }
1.692 + switch(iState)
1.693 + {
1.694 + case ERestoreExpectChecksum: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for the checksum)
1.695 + {
1.696 + const TInt KCheckSumStrLen = 8;
1.697 + CopyBufData(aInBuffer, inBufferPos, iBuffer, KCheckSumStrLen);
1.698 + if(iBuffer.Length() == KCheckSumStrLen)
1.699 + {
1.700 + iChecksum = ::GetNumUint32L(iBuffer);
1.701 + iState = ERestoreExpectOldFileSize;
1.702 + iBuffer.Zero();
1.703 + }
1.704 + break;
1.705 + }
1.706 + case ERestoreExpectOldFileSize: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for 32-bit old file size)
1.707 + {
1.708 + const TInt KOldFileSizeStrLen = 8;
1.709 + CopyBufData(aInBuffer, inBufferPos, iBuffer, KOldFileSizeStrLen);
1.710 + if(iBuffer.Length() == KOldFileSizeStrLen)
1.711 + {
1.712 + TUint32 oldFileSize = ::GetNumUint32L(iBuffer);
1.713 + if(oldFileSize == KSqlBurMagicNum)
1.714 + {
1.715 + iState = ERestoreExpectVersion;
1.716 + }
1.717 + else
1.718 + {
1.719 + iFileSize = oldFileSize;
1.720 + iState = ERestoreExpectFileNameSize;
1.721 + }
1.722 + iBuffer.Zero();
1.723 + }
1.724 + break;
1.725 + }
1.726 + case ERestoreExpectVersion:
1.727 + {
1.728 + const TInt KVersionStrLen = 4;
1.729 + CopyBufData(aInBuffer, inBufferPos, iBuffer, KVersionStrLen);
1.730 + if(iBuffer.Length() == KVersionStrLen)
1.731 + {
1.732 + //Ignore the version: ::GetNumUint32L(iBuffer);
1.733 + //At this stage we know that the version is 2+
1.734 + iState = ERestoreExpectFileSize;
1.735 + iBuffer.Zero();
1.736 + }
1.737 + break;
1.738 + }
1.739 + case ERestoreExpectFileSize:
1.740 + {
1.741 + const TInt KFileSizeStrLen = 16;
1.742 + CopyBufData(aInBuffer, inBufferPos, iBuffer, KFileSizeStrLen);
1.743 + if(iBuffer.Length() == KFileSizeStrLen)
1.744 + {
1.745 + iFileSize = GetNumInt64L(iBuffer);
1.746 + iState = ERestoreExpectFileNameSize;
1.747 + iBuffer.Zero();
1.748 + }
1.749 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL1, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;iFileSize=%lld", (TUint)this, iFileSize));
1.750 + break;
1.751 + }
1.752 + case ERestoreExpectFileNameSize: // the size of the file name to restore
1.753 + {
1.754 + const TInt KFileNameLenStrLen = 8;
1.755 + CopyBufData(aInBuffer, inBufferPos, iBuffer, KFileNameLenStrLen);
1.756 + if(iBuffer.Length() == KFileNameLenStrLen)
1.757 + {
1.758 + iFileNameSize = GetNumUint32L(iBuffer);
1.759 + iState = ERestoreExpectFileName;
1.760 + iBuffer.Zero();
1.761 + }
1.762 + break;
1.763 + }
1.764 + case ERestoreExpectFileName: // the name of the file to restore
1.765 + {
1.766 + CopyBufData(aInBuffer, inBufferPos, iBuffer, iFileNameSize);
1.767 + 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));
1.768 + if(iBuffer.Length() == iFileNameSize)
1.769 + {
1.770 + iState = ERestoreExpectData;
1.771 + TParse parse;
1.772 + __SQLLEAVE_IF_ERROR(parse.Set(iBuffer, 0, 0));
1.773 + __SQLLEAVE_IF_ERROR(iParse.Set(parse.NameAndExt(), &iRestoreDir, 0));
1.774 + TPtrC fname(iParse.FullName());
1.775 + //The database is restored first to a temporary file, in the restore folder, on the same drive.
1.776 + __SQLLEAVE_IF_ERROR(iFile.Replace(iInterface.Fs(), fname, EFileWrite | EFileShareExclusive));
1.777 + 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()));
1.778 + iBuffer.Zero();
1.779 + }
1.780 + break;
1.781 + }
1.782 + case ERestoreExpectData: // now for the data
1.783 + {
1.784 + TInt len = Min((aInBuffer.Size() - inBufferPos), iFileSize);
1.785 + TInt err = iFile.Write(aInBuffer.Mid(inBufferPos, len));
1.786 + if(err != KErrNone)
1.787 + {
1.788 + (void)RestoreCleanup();
1.789 + __SQLLEAVE(err);
1.790 + }
1.791 + inBufferPos += len;
1.792 + iFileSize -= len;
1.793 + if(iFileSize == 0)
1.794 + {
1.795 + iState = ERestoreComplete;
1.796 + }
1.797 + break;
1.798 + }
1.799 + case ERestoreComplete: // file completely restored
1.800 + {
1.801 + TUint64 checkSum64 = 0;
1.802 + TInt restoreErr = iFile.Flush();
1.803 + if(restoreErr == KErrNone)
1.804 + {
1.805 + // calculate the checksum
1.806 + restoreErr = CheckSum(iFile, checkSum64);
1.807 + }
1.808 + iFile.Close();
1.809 + if(restoreErr != KErrNone)
1.810 + {
1.811 + (void)RestoreCleanup();
1.812 + __SQLLEAVE(restoreErr);
1.813 + }
1.814 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL4, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;END;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
1.815 + TUint32 checkSum32 = checkSum64 & KMaxTUint32;
1.816 + if(checkSum32 != iChecksum)
1.817 + {
1.818 + (void)RestoreCleanup();
1.819 + __SQLLEAVE(KErrCorrupt);
1.820 + }
1.821 + if((aInBuffer.Size() - inBufferPos) > 0)
1.822 + {//There are bytes to be consumed in the input buffer
1.823 + iState = ERestoreExpectChecksum;
1.824 + break;
1.825 + }
1.826 + SQL_TRACE_BUR(OstTrace1(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL5, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;aFinishedFlag=ETrue", (TUint)this));
1.827 + //End of data. We have all data restored in the restore folder.
1.828 + //The final step of the "restoring files" process consists of the following sub-steps:
1.829 + // - Rename the database file to be restored to a file with ".bak" extension
1.830 + // - Rename the file with the restored data to the database file
1.831 + // - Delete the file with ".bak" extension
1.832 + //Do not leave during the restore process! Restore as much files as possible.
1.833 + //The only excpetion is TParse::Set() - if it fails it is a fatal error, the
1.834 + //restored file path cannot be constructed.
1.835 + __ASSERT_DEBUG(iRestoreDrive != TDriveNumber(-1), __SQLPANIC(ESqlPanicInternalError));
1.836 + __ASSERT_DEBUG(iRestoreId != TSecureId(KNullUid), __SQLPANIC(ESqlPanicInternalError));
1.837 + //Include the aUid and the "*" mask
1.838 + TUidName uidName = (static_cast <TUid> (iRestoreId)).Name();
1.839 + TBuf<KMaxUidName + sizeof(KSqlBurAllFiles)> fileNameMask(uidName);
1.840 + fileNameMask.Append(KSqlBurAllFiles);
1.841 + __SQLLEAVE_IF_ERROR(iParse.Set(fileNameMask, &iRestoreDir, 0));
1.842 + CDir* dir = NULL;
1.843 + TPtrC searchPattern(iParse.FullName());
1.844 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL55, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;search pattern=%S", (TUint)this, __SQLPRNSTR(searchPattern)));
1.845 + restoreErr = iInterface.Fs().GetDir(searchPattern, KEntryAttNormal, ESortNone, dir);
1.846 + if(restoreErr == KErrNone)
1.847 + {
1.848 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL6, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;restored files=%d", (TUint)this, dir->Count()));
1.849 + for(TInt i=0;i<dir->Count();++i)
1.850 + {
1.851 + const TEntry& entry = (*dir)[i];
1.852 + __SQLLEAVE_IF_ERROR(iParse.Set(entry.iName, &iRestoreDir, 0));
1.853 + TFileName dbName(iParse.FullName());
1.854 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL7, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;restored file=%S", (TUint)this, __SQLPRNSTR(dbName)));
1.855 + TInt pos = dbName.Find(KSqlBurRestoreDir);
1.856 + __ASSERT_DEBUG(pos >= 0, __SQLPANIC(ESqlPanicInternalError));
1.857 + dbName.Delete(pos, KSqlBurRestoreDir().Length() + 1);//"+1" for the path delimitier
1.858 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL8, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;database=%S", (TUint)this, __SQLPRNSTR(dbName)));
1.859 + TFileName bakDbName(iParse.FullName());
1.860 + bakDbName.Append(KSqlBurBackupExt);
1.861 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL9, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;backup file=%S", (TUint)this, __SQLPRNSTR(dbName)));
1.862 + //Now, dbName contains the original database (full path), iParse - the restored file,
1.863 + //bakDbName - backup file name
1.864 + TInt err = iInterface.Fs().Rename(dbName, bakDbName);
1.865 + if(err == KErrNone || err == KErrNotFound)
1.866 + {
1.867 + err = iInterface.Fs().Rename(iParse.FullName(), dbName);
1.868 + if(err == KErrNone)
1.869 + {//commit: delete the backup database file
1.870 + SQL_TRACE_BUR(OstTraceExt2(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL10, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;Commit;file=%S", (TUint)this, __SQLPRNSTR(dbName)));
1.871 + (void)iInterface.Fs().Delete(bakDbName);
1.872 + }
1.873 + else
1.874 + {//rollback: restore the original database file
1.875 + err = iInterface.Fs().Rename(bakDbName, dbName);
1.876 + SQL_TRACE_BUR(OstTraceExt3(TRACE_INTERNALS, CSQLBACKUPCLIENT_RESTOREBASEDATASECTONL11, "0x%X;CSqlBurCallback::RestoreBaseDataSectionL;Rollback;file=%S;err=%d", (TUint)this, __SQLPRNSTR(dbName), err));
1.877 + }
1.878 + }
1.879 + if(err != KErrNone && err != KErrNotFound)
1.880 + {
1.881 + if(restoreErr == KErrNone)
1.882 + {
1.883 + restoreErr = err;
1.884 + }
1.885 + }
1.886 + }//for(...)
1.887 + delete dir;
1.888 + }//iInterface.Fs().GetDir(...)
1.889 + done = ETrue;
1.890 + (void)RestoreCleanup();
1.891 + if(restoreErr != KErrNone)
1.892 + {
1.893 + __SQLLEAVE(restoreErr);
1.894 + }
1.895 + break;
1.896 + }
1.897 + default:
1.898 + __ASSERT_DEBUG(EFalse, __SQLPANIC(ESqlPanicInternalError));
1.899 + break;
1.900 + }//switch(...)
1.901 + if((aInBuffer.Size() - inBufferPos) == bytesAvailable)
1.902 + {//No bytes have been consumed from the buffer.
1.903 + if(++iterations > 1 && !done)
1.904 + {//This is the second iteration in the loop where no bytes have been consumed from the input buffer.
1.905 + //But the "done" flag is still false. Corrupted archive.
1.906 + __SQLLEAVE(KErrCorrupt);
1.907 + }
1.908 + }
1.909 + } while(!done);
1.910 + }
1.911 +
1.912 +/**
1.913 +The operation was terminated - we should tidyup here (as best we can)
1.914 +Backup: close the file, free the allocated memory for the file names.
1.915 +Restore: since the final restore step is a non-leaving one, nothing special needs to be done here -
1.916 +RestoreCleanup() is called to close the file and delete if there are any temporary files left.
1.917 +*/
1.918 +void CSqlBurCallback::TerminateMultiStageOperation()
1.919 + {
1.920 + BackupCleanup();
1.921 + (void)RestoreCleanup();
1.922 + }
1.923 +
1.924 +/**
1.925 +We do our own checksumming so we don't need this
1.926 +@return the checksum
1.927 +@param aDrive the drive affected (unused)
1.928 +*/
1.929 +TUint CSqlBurCallback::GetDataChecksum(TDriveNumber /* aDrive */)
1.930 + {
1.931 + // not required - not implemented
1.932 + const TUint KArbitraryNumber = 1024;
1.933 + return KArbitraryNumber;
1.934 + }
1.935 +
1.936 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.937 +/////////////////////////// Incremental backup/restore ////////////////////////////////////////////////////
1.938 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.939 +
1.940 +/**
1.941 +We don't support incremental backup
1.942 +*/
1.943 +void CSqlBurCallback::GetSnapshotDataL(TDriveNumber /* aDrive */, TPtr8& /* aBuffer */, TBool& /* aFinishedFlag */)
1.944 + {
1.945 + __SQLLEAVE(KErrNotSupported);
1.946 + }
1.947 +
1.948 +/**
1.949 +We don't support incremental backup
1.950 +*/
1.951 +void CSqlBurCallback::InitialiseGetBackupDataL(TDriveNumber /* aDrive */)
1.952 + {
1.953 + __SQLLEAVE(KErrNotSupported);
1.954 + }
1.955 +
1.956 +/**
1.957 +We don't support incremental backup
1.958 +*/
1.959 +void CSqlBurCallback::InitialiseRestoreBaseDataL(TDriveNumber /* aDrive */)
1.960 + {
1.961 + __SQLLEAVE(KErrNotSupported);
1.962 + }
1.963 +
1.964 +/**
1.965 +We don't support incremental backup
1.966 +*/
1.967 +void CSqlBurCallback::InitialiseRestoreIncrementDataL(TDriveNumber /* aDrive */)
1.968 + {
1.969 + __SQLLEAVE(KErrNotSupported);
1.970 + }
1.971 +
1.972 +/**
1.973 +We don't support incremental backup
1.974 +*/
1.975 +void CSqlBurCallback::RestoreIncrementDataSectionL(TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
1.976 + {
1.977 + __SQLLEAVE(KErrNotSupported);
1.978 + }
1.979 +
1.980 +/**
1.981 +We don't support incremental backup
1.982 +*/
1.983 +void CSqlBurCallback::AllSnapshotsSuppliedL()
1.984 + {
1.985 + }
1.986 +
1.987 +/**
1.988 +We don't support incremental backup
1.989 +*/
1.990 +void CSqlBurCallback::ReceiveSnapshotDataL(TDriveNumber /* aDrive */, TDesC8& /* aBuffer */, TBool /* aFinishedFlag */)
1.991 + {
1.992 + __SQLLEAVE(KErrNotSupported);
1.993 + }
1.994 +
1.995 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.996 +/////////////////////////// Helper functions //////////////////////////////////////////////////////////////
1.997 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.998 +
1.999 +/**
1.1000 +A simple checksumming algorithm to allow a degree
1.1001 +of trust that the backup and restore worked.
1.1002 +Note the file pointer will be back at the start when the function call completes successfully.
1.1003 +In case of an error, the position of the file pointer is undetermined.
1.1004 +
1.1005 +@param aOpenFile Already opened database file on which the checksum is calculated.
1.1006 +@param aCheckSum Output parameter. The checksum is returned in this parameter.
1.1007 +@return KErrNoMemory, an out of memory condition has occurred;
1.1008 + Note that the function may also return some other system-wide error codes.
1.1009 +*/
1.1010 +TInt CSqlBurCallback::CheckSum(const RFile64& aOpenFile, TUint64& aCheckSum) const
1.1011 + {
1.1012 + // scoot through the database file building the checksum
1.1013 + aCheckSum = 0;
1.1014 + TInt64 seekPos = 0; // rewind first
1.1015 + TInt err = aOpenFile.Seek(ESeekStart, seekPos);
1.1016 + if(err != KErrNone)
1.1017 + {
1.1018 + return err;
1.1019 + }
1.1020 + const TUint KCheckSumBlockSize = 4 * 1024;
1.1021 + HBufC8* buf = HBufC8::New(KCheckSumBlockSize);
1.1022 + if(!buf)
1.1023 + {
1.1024 + return KErrNoMemory;
1.1025 + }
1.1026 + TPtr8 ptr = buf->Des();
1.1027 + for(;;)
1.1028 + {
1.1029 + err = aOpenFile.Read(ptr);
1.1030 + if(err != KErrNone)
1.1031 + {
1.1032 + delete buf;
1.1033 + return err;
1.1034 + }
1.1035 + TInt len = ptr.Length();
1.1036 + if(len == 0)
1.1037 + {
1.1038 + break;
1.1039 + }
1.1040 + // calculate the checksum
1.1041 + for(TInt i=0;i<len;++i)
1.1042 + {
1.1043 + aCheckSum = (aCheckSum << 1) | (aCheckSum >> 63);
1.1044 + aCheckSum += ptr[i];
1.1045 + }
1.1046 + };
1.1047 + delete buf;
1.1048 + // restore file position
1.1049 + seekPos = 0;
1.1050 + err = aOpenFile.Seek(ESeekStart,seekPos);
1.1051 + return err;
1.1052 + }
1.1053 +
1.1054 +/**
1.1055 +Reads the content of aInBuf from position aInBufReadPos and stores the data into aOutBuf.
1.1056 +aDataLen is the length of the data. If the input buffer does not contain all the data, then only the
1.1057 +available data will be copied to the output buffer.
1.1058 +
1.1059 +How the function works. It is called during the restore process and aInBuf parameter contains a block of raw
1.1060 +data sent by the B&R server. The calling function, RestoreBaseDataSectionL(), uses a state
1.1061 +machine to processes the incoming data. At particular moment RestoreBaseDataSectionL() will process the data header
1.1062 +and will have to read "aDataLen" 16-bit characters at position "aInBufReadPos". If there are "aDataLen" characters
1.1063 +at position "aInBufReadPos" and enough free space in "aOutBuf", CopyBufData() will copy all of them,
1.1064 +otherwise CopyBufData() will copy as much characters as possible (in which case RestoreBaseDataSectionL() will
1.1065 +stay in the same state, waiting for more data from the B&R server).
1.1066 +
1.1067 +@param aInBuf 8-bit buffer with input data
1.1068 +@param aInBufReadPos The position in the buffer from which the read operation starts.
1.1069 + When the "buffer read" operatio completes, aInBufReadPos is updated with the
1.1070 + number of bytes read from the input buffer.
1.1071 +@param aOutBuf 16-bit output buffer. The data read from the input buffer is stored in the output buffer.
1.1072 +@param aDataLen How much bytes to be read from the input buffer. Note that if there is not enough
1.1073 + data in the input buffer, the function will read as much as possible from the input buffer.
1.1074 + The aInBufReadPos in/out parameter will be updated with the actual number of bytes read.
1.1075 +*/
1.1076 +void CSqlBurCallback::CopyBufData(const TDesC8& aInBuf, TInt& aInBufReadPos, TDes& aOutBuf, TInt aDataLen)
1.1077 + {
1.1078 + __ASSERT_DEBUG(aInBufReadPos >= 0, __SQLPANIC(ESqlPanicBadArgument));
1.1079 + __ASSERT_DEBUG(aDataLen > 0, __SQLPANIC(ESqlPanicBadArgument));
1.1080 +
1.1081 + TInt needed = (aDataLen - aOutBuf.Length()) << K8to16bitShift;
1.1082 + TInt available = aInBuf.Size() - aInBufReadPos;
1.1083 + TInt len = Min(needed, available);
1.1084 + TPtrC8 ptr8 = aInBuf.Mid(aInBufReadPos, len);
1.1085 + aInBufReadPos += len;
1.1086 +
1.1087 + len >>= K8to16bitShift;
1.1088 + aOutBuf.Append((const TUint16*)ptr8.Ptr(), len);
1.1089 + }
1.1090 +
1.1091 +/**
1.1092 +Cleans up the allocated during the backup resources - file handles, buffers allocated for the file names.
1.1093 +*/
1.1094 +void CSqlBurCallback::BackupCleanup()
1.1095 + {
1.1096 + for(TInt i=0;i<iFileList.Count();++i)
1.1097 + {
1.1098 + delete iFileList[i];
1.1099 + }
1.1100 + iFileList.Close();
1.1101 + iFile.Close();
1.1102 + }
1.1103 +
1.1104 +/**
1.1105 +Deletes created during the restore temporary files.
1.1106 +*/
1.1107 +TInt CSqlBurCallback::RestoreCleanup()
1.1108 + {
1.1109 + if(iRestoreDir.Find(KSqlBurRestoreDir) < 0)
1.1110 + {//iRestoreDir is not initialized - that means RestoreCleanup() was called either from the
1.1111 + //destructor or from the TerminateMultistageOperation() during a backup.
1.1112 + return KErrNone;
1.1113 + }
1.1114 + iFile.Close();
1.1115 + CFileMan* fm = NULL;
1.1116 + TRAPD(err, fm = CFileMan::NewL(iInterface.Fs()));
1.1117 + if(err == KErrNone)
1.1118 + {
1.1119 + TFileName allFiles;
1.1120 + allFiles.Copy(iRestoreDir);
1.1121 + allFiles.Append(KSqlBurAllFiles);
1.1122 + err = fm->Delete(allFiles);
1.1123 + delete fm;
1.1124 + }
1.1125 + return err;
1.1126 + }
1.1127 +
1.1128 +/**
1.1129 +Stores the error occured during backup for furhter processing.
1.1130 +Please note that the function asserts if the aError parameter is KErrNone.
1.1131 +Call the function only with a real error.
1.1132 +
1.1133 +@param aError The backup error to be stored
1.1134 +*/
1.1135 +void CSqlBurCallback::SetBackupError(TInt aError)
1.1136 + {
1.1137 + __ASSERT_DEBUG(aError != KErrNone, __SQLPANIC(ESqlPanicBadArgument));
1.1138 + if(aError != KErrNotFound && aError != KErrPathNotFound)
1.1139 + {
1.1140 + if(iBackupError == KErrNone || aError == KErrDiskFull || aError == KErrCorrupt)
1.1141 + {
1.1142 + iBackupError = aError;
1.1143 + }
1.1144 + }
1.1145 + }