15 |
15 |
16 #include "SqlBur.h" |
16 #include "SqlBur.h" |
17 #include "SqlAssert.h" |
17 #include "SqlAssert.h" |
18 #include "SqlPanic.h" |
18 #include "SqlPanic.h" |
19 |
19 |
20 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
21 ////////////// Backup database file header format /////////////////// |
|
22 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
23 |
|
24 ////// No version (Version 0) |
|
25 // 8 chars 8 chars 8 chars up to 256 characters (512 bytes) |
|
26 // <32-bit checksum><32-bit filesize><32-bit filenamelen><filename - UTF16 encoded> |
|
27 |
|
28 ////// Version 2 |
|
29 // 8 chars 8 chars 4 chars 16 chars 8 chars up to 256 characters (512 bytes) |
|
30 // <32-bit checksum><FFFFAA55><Version N#><64-bit filesize><32-bit filenamelen><filename - UTF16 encoded> |
|
31 |
|
32 const TInt KBackupHeaderVersion = 2; //Current backup database file header version |
|
33 |
|
34 const TUint32 KMagicNum = 0xFFFFAA55; //Magic number. If the "old database file size" field in the header |
|
35 //has this value, then the header version is 2+ |
|
36 const TInt KMaxHeaderSize = 256 + KMaxFileName; //The size of the buffer used for the operations on the header |
|
37 |
|
38 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
39 |
|
40 //Extracts and returns 32-bit integer from aNumBuf buffer. |
20 //Extracts and returns 32-bit integer from aNumBuf buffer. |
41 static TUint32 GetNumUint32L(const TDesC& aNumBuf) |
21 static TUint32 GetNumUint32L(const TDesC& aNumBuf) |
42 { |
22 { |
43 TLex lex(aNumBuf); |
23 TLex lex(aNumBuf); |
44 lex.SkipSpace(); |
24 lex.SkipSpace(); |
200 if(iProperty.Get(status)!=KErrNotFound) |
168 if(iProperty.Get(status)!=KErrNotFound) |
201 { |
169 { |
202 status&=KBURPartTypeMask; |
170 status&=KBURPartTypeMask; |
203 switch(status) |
171 switch(status) |
204 { |
172 { |
205 case EBURUnset: |
173 case EBURUnset: // same as EBURNormal |
206 // same as EBURNormal |
|
207 case EBURNormal: |
174 case EBURNormal: |
208 if(iActiveBackupClient) |
175 delete iActiveBackupClient; |
209 { |
176 iActiveBackupClient=NULL; |
210 delete iActiveBackupClient; |
|
211 iActiveBackupClient=NULL; |
|
212 } |
|
213 break; |
177 break; |
214 case EBURBackupFull: |
178 case EBURBackupFull: |
215 case EBURBackupPartial: |
179 case EBURBackupPartial: |
216 // we only do full backups |
180 case EBURRestoreFull: |
217 if(!iActiveBackupClient) |
181 case EBURRestorePartial: |
218 { |
182 // we only do full backups and full restores |
219 iActiveBackupClient=CActiveBackupClient::NewL(this); |
|
220 } |
|
221 iActiveBackupClient->ConfirmReadyForBURL(KErrNone); |
|
222 break; |
|
223 case EBURRestoreFull: |
|
224 case EBURRestorePartial: |
|
225 // we only do full restores |
|
226 if(!iActiveBackupClient) |
183 if(!iActiveBackupClient) |
227 { |
184 { |
228 iActiveBackupClient=CActiveBackupClient::NewL(this); |
185 iActiveBackupClient=CActiveBackupClient::NewL(this); |
229 } |
186 } |
230 iActiveBackupClient->ConfirmReadyForBURL(KErrNone); |
187 iActiveBackupClient->ConfirmReadyForBURL(KErrNone); |
320 // empty or unreadable - skip this file |
277 // empty or unreadable - skip this file |
321 iState=EBackupEndOfFile; |
278 iState=EBackupEndOfFile; |
322 break; |
279 break; |
323 } |
280 } |
324 |
281 |
325 // build the header - this is an instance member because it |
|
326 // has to persist over multiple calls to this method |
|
327 TPtr hdrPtr=iBuffer->Des(); |
|
328 |
|
329 // get the checksum - only grab last 4 bytes - enough to be satisfied that |
282 // get the checksum - only grab last 4 bytes - enough to be satisfied that |
330 // the backup and restore worked ok |
283 // the backup and restore worked ok |
331 TUint32 checksum = CheckSumL(iFile) & 0xFFFFFFFF; |
284 TUint32 checksum = CheckSumL(iFile) & KMaxTUint32; |
332 |
285 |
333 // build the header |
286 // build the header - this is an instance member because it |
|
287 // has to persist over multiple calls to this method |
334 const TDesC& fileName = iFileList[iFileIndex].FullName(); |
288 const TDesC& fileName = iFileList[iFileIndex].FullName(); |
335 hdrPtr.Format(_L("%8x%8x%4x%16lx%8x%S"), |
289 iBuffer.Format(_L("%8x%8x%4x%16lx%8x%S"), |
336 checksum, // %8x |
290 checksum, // %8x |
337 KMagicNum, // %8x |
291 KMagicNum, // %8x |
338 KBackupHeaderVersion, // %4x |
292 KBackupHeaderVersion, // %4x |
339 fileSize, // %16lx |
293 fileSize, // %16lx |
340 fileName.Length(), // %8x |
294 fileName.Length(), // %8x |
341 &fileName); // %S |
295 &fileName); // %S |
342 |
296 |
343 // we need it to look like an 8bit buffer |
297 // we need it to look like an 8bit buffer |
344 TPtr8 hdrPtr8((TUint8*)hdrPtr.Ptr(),hdrPtr.Size(),hdrPtr.Size()); |
298 TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size()); |
345 |
299 |
346 TInt len = Min(hdrPtr8.Size(), bufFreeSpace); |
300 TInt len = Min(hdrPtr8.Size(), bufFreeSpace); |
347 |
301 |
348 // append the header to the buffer (only till it's full) |
302 // append the header to the buffer (only till it's full) |
349 aBuffer.Append(hdrPtr8.Ptr(), len); |
303 aBuffer.Append(hdrPtr8.Ptr(), len); |
366 break; |
320 break; |
367 } |
321 } |
368 case EBackupOpenPartHeaderSent: // need to send the rest of the header |
322 case EBackupOpenPartHeaderSent: // need to send the rest of the header |
369 { |
323 { |
370 // get back the header - this is already loaded with the necessary info |
324 // get back the header - this is already loaded with the necessary info |
371 // from the previous state we were in |
325 // from the previous state we were in - EBackupOpenNothingSent |
372 TPtr hdrPtr = iBuffer->Des(); |
|
373 |
326 |
374 // we need it to look like an 8bit buffer |
327 // we need it to look like an 8bit buffer |
375 TPtr8 hdrPtr8((TUint8*)hdrPtr.Ptr(),hdrPtr.Size(),hdrPtr.Size()); |
328 TPtr8 hdrPtr8((TUint8*)iBuffer.Ptr(), iBuffer.Size(), iBuffer.Size()); |
376 |
329 |
377 // how many bytes have we yet to send? |
330 // how many bytes have we yet to send? |
378 TInt bytesRemaining = hdrPtr.Size() - iHeaderSent; |
331 TInt bytesRemaining = hdrPtr8.Size() - iHeaderSent; |
379 TInt len = Min(bytesRemaining, bufFreeSpace); |
332 TInt len = Min(bytesRemaining, bufFreeSpace); |
380 aBuffer.Append(hdrPtr8.Ptr() + iHeaderSent, len); |
333 aBuffer.Append(hdrPtr8.Ptr() + iHeaderSent, len); |
381 |
334 |
382 if(bytesRemaining <= bufFreeSpace) |
335 if(bytesRemaining <= bufFreeSpace) |
383 { |
336 { |
525 switch(iState) |
475 switch(iState) |
526 { |
476 { |
527 case ERestoreExpectChecksum: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for the checksum) |
477 case ERestoreExpectChecksum: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for the checksum) |
528 { |
478 { |
529 const TInt KCheckSumStrLen = 8; |
479 const TInt KCheckSumStrLen = 8; |
530 CopyBufData(aInBuffer, inBufferPos, outBufPtr, KCheckSumStrLen); |
480 CopyBufData(aInBuffer, inBufferPos, iBuffer, KCheckSumStrLen); |
531 if(outBufPtr.Length() == KCheckSumStrLen) |
481 if(iBuffer.Length() == KCheckSumStrLen) |
532 { |
482 { |
533 iChecksum = ::GetNumUint32L(outBufPtr); |
483 iChecksum = ::GetNumUint32L(iBuffer); |
534 iState = ERestoreExpectOldFileSize; |
484 iState = ERestoreExpectOldFileSize; |
535 outBufPtr.Zero(); |
485 iBuffer.Zero(); |
536 } |
486 } |
537 break; |
487 break; |
538 } |
488 } |
539 case ERestoreExpectOldFileSize: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for 32-bit old file size) |
489 case ERestoreExpectOldFileSize: // 16 bytes (the header is UTF16 encoded, 8 unicode characters for 32-bit old file size) |
540 { |
490 { |
541 const TInt KOldFileSizeStrLen = 8; |
491 const TInt KOldFileSizeStrLen = 8; |
542 CopyBufData(aInBuffer, inBufferPos, outBufPtr, KOldFileSizeStrLen); |
492 CopyBufData(aInBuffer, inBufferPos, iBuffer, KOldFileSizeStrLen); |
543 if(outBufPtr.Length() == KOldFileSizeStrLen) |
493 if(iBuffer.Length() == KOldFileSizeStrLen) |
544 { |
494 { |
545 TUint32 oldFileSize = ::GetNumUint32L(outBufPtr); |
495 TUint32 oldFileSize = ::GetNumUint32L(iBuffer); |
546 if(oldFileSize == KMagicNum) |
496 if(oldFileSize == KMagicNum) |
547 { |
497 { |
548 iState = ERestoreExpectVersion; |
498 iState = ERestoreExpectVersion; |
549 } |
499 } |
550 else |
500 else |
551 { |
501 { |
552 iFileSize = oldFileSize; |
502 iFileSize = oldFileSize; |
553 iState = ERestoreExpectFileNameSize; |
503 iState = ERestoreExpectFileNameSize; |
554 } |
504 } |
555 outBufPtr.Zero(); |
505 iBuffer.Zero(); |
556 } |
506 } |
557 break; |
507 break; |
558 } |
508 } |
559 case ERestoreExpectVersion: |
509 case ERestoreExpectVersion: |
560 { |
510 { |
561 const TInt KVersionStrLen = 4; |
511 const TInt KVersionStrLen = 4; |
562 CopyBufData(aInBuffer, inBufferPos, outBufPtr, KVersionStrLen); |
512 CopyBufData(aInBuffer, inBufferPos, iBuffer, KVersionStrLen); |
563 if(outBufPtr.Length() == KVersionStrLen) |
513 if(iBuffer.Length() == KVersionStrLen) |
564 { |
514 { |
565 //Ignore the version: ::GetNumUint32L(outBufPtr); |
515 //Ignore the version: ::GetNumUint32L(iBuffer); |
566 //At this stage we know that the version is 2+ |
516 //At this stage we know that the version is 2+ |
567 iState = ERestoreExpectFileSize; |
517 iState = ERestoreExpectFileSize; |
568 outBufPtr.Zero(); |
518 iBuffer.Zero(); |
569 } |
519 } |
570 break; |
520 break; |
571 } |
521 } |
572 case ERestoreExpectFileSize: |
522 case ERestoreExpectFileSize: |
573 { |
523 { |
574 const TInt KFileSizeStrLen = 16; |
524 const TInt KFileSizeStrLen = 16; |
575 CopyBufData(aInBuffer, inBufferPos, outBufPtr, KFileSizeStrLen); |
525 CopyBufData(aInBuffer, inBufferPos, iBuffer, KFileSizeStrLen); |
576 if(outBufPtr.Length() == KFileSizeStrLen) |
526 if(iBuffer.Length() == KFileSizeStrLen) |
577 { |
527 { |
578 iFileSize = GetNumInt64L(outBufPtr); |
528 iFileSize = GetNumInt64L(iBuffer); |
579 iState = ERestoreExpectFileNameSize; |
529 iState = ERestoreExpectFileNameSize; |
580 outBufPtr.Zero(); |
530 iBuffer.Zero(); |
581 } |
531 } |
582 break; |
532 break; |
583 } |
533 } |
584 case ERestoreExpectFileNameSize: // the size of the file name to restore |
534 case ERestoreExpectFileNameSize: // the size of the file name to restore |
585 { |
535 { |
586 const TInt KFileNameLenStrLen = 8; |
536 const TInt KFileNameLenStrLen = 8; |
587 CopyBufData(aInBuffer, inBufferPos, outBufPtr, KFileNameLenStrLen); |
537 CopyBufData(aInBuffer, inBufferPos, iBuffer, KFileNameLenStrLen); |
588 if(outBufPtr.Length() == KFileNameLenStrLen) |
538 if(iBuffer.Length() == KFileNameLenStrLen) |
589 { |
539 { |
590 iFileNameSize = GetNumUint32L(outBufPtr); |
540 iFileNameSize = GetNumUint32L(iBuffer); |
591 iState = ERestoreExpectFileName; |
541 iState = ERestoreExpectFileName; |
592 outBufPtr.Zero(); |
542 iBuffer.Zero(); |
593 } |
543 } |
594 break; |
544 break; |
595 } |
545 } |
596 case ERestoreExpectFileName: // the name of the file to restore |
546 case ERestoreExpectFileName: // the name of the file to restore |
597 { |
547 { |
598 CopyBufData(aInBuffer, inBufferPos, outBufPtr, iFileNameSize); |
548 CopyBufData(aInBuffer, inBufferPos, iBuffer, iFileNameSize); |
599 if(outBufPtr.Length() == iFileNameSize) |
549 if(iBuffer.Length() == iFileNameSize) |
600 { |
550 { |
601 iState = ERestoreExpectData; |
551 iState = ERestoreExpectData; |
602 outBufPtr.Append(KRestoreSuffix); |
552 iBuffer.Append(KRestoreSuffix); |
603 // now we start writing the data to the target file |
553 // now we start writing the data to the target file |
604 // write to a temp - double disk space potentially |
554 // write to a temp - double disk space potentially |
605 // once all the temp files are created, then they are renamed to the |
555 // once all the temp files are created, then they are renamed to the |
606 // real file names in one fell swoop |
556 // real file names in one fell swoop |
607 __SQLLEAVE_IF_ERROR(iFile.Replace(iInterface->Fs(), outBufPtr, EFileWrite | EFileShareExclusive)); |
557 __SQLLEAVE_IF_ERROR(iFile.Replace(iInterface->Fs(), iBuffer, EFileWrite | EFileShareExclusive)); |
608 outBufPtr.Zero(); |
558 iBuffer.Zero(); |
609 } |
559 } |
610 break; |
560 break; |
611 } |
561 } |
612 case ERestoreExpectData: // now for the data |
562 case ERestoreExpectData: // now for the data |
613 { |
563 { |
645 __SQLLEAVE_IF_ERROR(iInterface->Fs().GetDir(KRestoreFilter,KEntryAttNormal,ESortNone,dir)); |
596 __SQLLEAVE_IF_ERROR(iInterface->Fs().GetDir(KRestoreFilter,KEntryAttNormal,ESortNone,dir)); |
646 CleanupStack::PushL(dir); |
597 CleanupStack::PushL(dir); |
647 for(TInt a=0;a<dir->Count();++a) |
598 for(TInt a=0;a<dir->Count();++a) |
648 { |
599 { |
649 TEntry entry=(*dir)[a]; |
600 TEntry entry=(*dir)[a]; |
650 TPtr rst=entry.iName.Des(); |
601 TPtrC rst=entry.iName.Des(); |
651 TInt len=rst.Length(); |
602 TInt len=rst.Length(); |
652 // format <filename>.db.bak.rst |
603 // format <filename>.db.bak.rst |
653 // just a convenience! |
604 // just a convenience! |
654 TBufC<KMaxFileName> bak(rst.LeftTPtr(len-4)); |
605 TPtrC bak(rst.Left(len - 4));//".rst" part excluded |
655 TBufC<KMaxFileName> db(rst.LeftTPtr(len-8)); |
606 TPtrC db(rst.Left(len - 8));//".bak.rst" part excluded |
656 |
607 |
657 // first, rename the orig .db as .bak just in case |
608 // first, rename the orig .db as .bak just in case |
658 // ok if not found - might have been deleted. |
609 // ok if not found - might have been deleted. |
659 //the ".bak" file, if exists, will be deleted first. |
610 //the ".bak" file, if exists, will be deleted first. |
660 (void)iInterface->Fs().Delete(bak); |
611 (void)iInterface->Fs().Delete(bak); |
726 return; |
677 return; |
727 } |
678 } |
728 for(TInt a=0;a<dir->Count();++a) |
679 for(TInt a=0;a<dir->Count();++a) |
729 { |
680 { |
730 TEntry entry=(*dir)[a]; |
681 TEntry entry=(*dir)[a]; |
731 TPtr bak=entry.iName.Des(); |
682 TPtrC bak=entry.iName.Des(); |
732 TInt len=bak.Length(); |
683 TInt len=bak.Length(); |
733 TBufC<KMaxFileName> db(bak.LeftTPtr(len-4)); |
684 TPtrC db(bak.Left(len-4));//".bak" part excluded |
734 rc=iInterface->Fs().Delete(db); // rename does not overwrite |
685 rc=iInterface->Fs().Delete(db); // rename does not overwrite |
735 if(KErrNone!=rc) |
686 if(KErrNone == rc) |
736 { |
687 { |
737 // nothing happened, still have bak file (and new db) |
688 rc = iInterface->Fs().Rename(bak,db); |
738 delete dir; |
|
739 return; |
|
740 } |
689 } |
741 rc=iInterface->Fs().Rename(bak,db); |
690 //The function cannot leave or return an error. The only thing which could be done here is to print out something |
742 if(KErrNone!=rc) |
691 //and continue with the next file. |
743 { |
692 if(KErrNone != rc) |
744 // still have bak file, but db is gone! |
693 { |
745 delete dir; |
694 RDebug::Print(_L(" *** CSqlBackupClient::TerminateMultiStageOperation(), file \"%S\", err=%d\r\n"), &db, rc); |
746 return; |
695 } |
747 } |
|
748 // backup restored ok |
696 // backup restored ok |
749 } |
697 } |
750 // cleanup dir |
698 // cleanup dir |
751 delete dir; |
699 delete dir; |
752 } |
700 } |