diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/store/TSTOR/t_stortoc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/persistentdata/persistentstorage/store/TSTOR/t_stortoc.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,651 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include <e32test.h> +#include <s32file.h> +#include <s32fileiter.h> + +RTest TheTest(_L("t_storetoc test")); +RFs TheFs; + +TBuf<KMaxFileName> TheFileName; + +CPermanentFileStore* TheStore = NULL; + +void DeleteTestFiles() + { + delete TheStore; + TheStore = NULL; + (void)TheFs.Delete(TheFileName); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Test macros and functions +void Check(TInt aValue, TInt aLine) + { + if(!aValue) + { + DeleteTestFiles(); + TheTest(EFalse, aLine); + } + } +void Check(TInt aValue, TInt aExpected, TInt aLine) + { + if(aValue != aExpected) + { + DeleteTestFiles(); + TheTest.Printf(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue); + TheTest(EFalse, aLine); + } + } +#define TEST(arg) ::Check((arg), __LINE__) +#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__) + +/////////////////////////////////////////////////////////////////////////////////////// + +void CreateTestEnv(TInt aDriveNo) + { + TChar ch; + TInt err = TheFs.DriveToChar(aDriveNo, ch); + TEST2(err, KErrNone); + TBuf<2> drvName; + drvName.SetLength(2); + drvName[0] = ch; + drvName[1] = TChar(':'); + + _LIT(KTestFile, "c:\\stor-tst\\t_storetoc.dat"); + + TParse parse; + parse.Set(drvName, &KTestFile, 0); + const TDesC& dbFilePath = parse.FullName(); + TheFileName.Copy(dbFilePath); + + err = TheFs.MkDir(parse.DriveAndPath()); + TEST(err == KErrNone || err == KErrAlreadyExists); + } + +/////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TTocTestBase /////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Base TOC test class. +//It offers the folowing functions: Prepare(), Test() and Verify(). +//The test algorithm is: +// ================================= +// void TestFunc(TTocTestBase& aTestObj) +// { +// aTestObj.Prepare(); +// [simulate file system error]; +// TInt err = aTestObj.Test(); +// [clear file system error]; +// aTestObj.Verify(err); +// } +// ================================= +//The class has two private pure virtual methods, which have to be overriden in derived classes: +// DoPrepareL() - instance specific test preparation; +// DoVerify() - instance specific test verification; +class TTocTestBase + { +public: + TTocTestBase() + { + TheStore = NULL; + } + void Prepare() + { + TEST(TheStore == NULL); + TRAPD(err, DoPrepareL()); + TEST2(err, KErrNone); + } + TInt Test() + { + TEST(TheStore != NULL); + TRAPD(err, {TheStore->CompactL(); TheStore->CommitL();}); + delete TheStore; + TheStore = NULL; + return err; + } + void Verify(TInt aTestErr) + { + TEST(TheStore == NULL); + TRAPD(err, DoVerifyL(aTestErr)); + TEST2(err, KErrNone); + } + +protected: + TStreamId WriteNewStreamL(const TDesC8& aStreamData) + { + TEST(TheStore != NULL); + RStoreWriteStream stream; + TStreamId streamId = stream.CreateLC(*TheStore); + stream.WriteL(aStreamData); + stream.CommitL(); + TheStore->CommitL(); + CleanupStack::PopAndDestroy(&stream); + return streamId; + } + +private: + virtual void DoPrepareL() = 0; + virtual void DoVerifyL(TInt aTestErr) = 0; + + }; + +/////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TBaseTocEntryTest //////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +//Do not change/shift the next lines, because "new line/space" characters will be inserted in the string! +_LIT8(KStreamData1, "-01-ABCD-02-ABCD-03-ABCD-04-ABCD-05-ABCD-06-ABCD-07-ABCD-08-ABCD"); +_LIT8(KStreamData1_2, "ABCDEFGH-41-ABCD-42-ABCD-43-A\ +-33-ABCD-34-ABCD-35-ABCD-36-ABCD-37-ABCD-38-ABCD-39-ABCD-40-ABCD\ +-25-ABCD-26-ABCD-27-ABCD-28-ABCD-29-ABCD-30-ABCD-31-ABCD-32-ABCD\ +-17-ABCD-18-ABCD-19-ABCD-20-ABCD-21-ABCD-22-ABCD-23-ABCD-24-ABCD\ +-09-ABCD-10-ABCD-11-ABCD-12-ABCD-13-ABCD-14-ABCD-15-ABCD-16-ABCD"); +_LIT8(KStreamData1_3, "0123456789"); + +//"Base TOC entry" test. +//When a stream is relocated, its base TOC entry needs 2 "file write" (for "atomic block write" media) operations, because +//the TOC entry is split over a block boundary. +//This test class uses a set of test data, which puts the TOC entry of the relocated stream at position +//510 in the file (TOC entry length - 5 bytes). +class TBaseTocEntryTest : public TTocTestBase + { +public: + TBaseTocEntryTest() : + iStreamId1(KNullStreamIdValue), + iStreamId2(KNullStreamIdValue), + iStreamId3(KNullStreamIdValue) + { + } + +private: + void DoPrepareL() + { + TheStore = CPermanentFileStore::ReplaceLC(TheFs, TheFileName, EFileWrite); + TheStore->SetTypeL(TheStore->Layout()); + TheStore->CommitL(); + + iStreamId1 = WriteNewStreamL(KStreamData1); + TheStore->SetRootL(iStreamId1); + TheStore->CommitL(); + iStreamId2 = WriteNewStreamL(KStreamData1_2); + iStreamId3 = WriteNewStreamL(KStreamData1_3); + + TheStore->DeleteL(iStreamId2); + TheStore->CommitL(); + + CleanupStack::Pop(TheStore); + } + + virtual void DoVerifyL(TInt) + { + TEST(TheStore == NULL); + TheStore = CPermanentFileStore::OpenLC(TheFs, TheFileName, EFileWrite); + RPermanentFileStoreIter iter; + iter.ResetLC(*TheStore); + //Stream 1 + TStreamId streamId = iter.NextL(); + TEST(streamId == iStreamId1); + RStoreReadStream strm; + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData1().Length()); + TBuf8<sizeof(KStreamData1)> buf; + strm.ReadL(buf, KStreamData1().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData1().Ptr(), KStreamData1().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 2 + streamId = iter.NextL(); + TEST(streamId == iStreamId3); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData1_3().Length()); + strm.ReadL(buf, KStreamData1_3().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData1_3().Ptr(), KStreamData1_3().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //No more streams + streamId = iter.NextL(); + TEST(streamId == KNullStreamIdValue); + //Cleanup + CleanupStack::PopAndDestroy(&iter); + CleanupStack::PopAndDestroy(TheStore); + TheStore = NULL; + } + +private: + TStreamId iStreamId1; + TStreamId iStreamId2; + TStreamId iStreamId3; + + }; + +/////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TDeltaTocEntryTest ///////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +//Do not change/shift the next lines, because "new line/space" characters will be inserted in the string! +_LIT8(KStreamData2, "\ +-01-ABCD-02-ABCD-03-ABCD-04-ABCD-05-ABCD-06-ABCD-07-ABCD-08-ABCD\ +-09-ABCD-10-ABCD-11-ABCD-12"); +_LIT8(KStreamData2_2, "ABC"); +_LIT8(KStreamData2_3, "012345678"); + +//"Delta TOC entry" test +//When a stream is relocated, its delta TOC entry needs 2 "file write" (for "atomic block write" media) operations, because +//the TOC entry is split over a block boundary. +//This test class uses a set of test data, which puts the TOC entry of the relocated stream at position +//507 in the file (TOC entry length - 8 bytes), so the last 4 bytes (stream offset) are split. +class TDeltaTocEntryTest : public TTocTestBase + { +public: + TDeltaTocEntryTest() : + iStreamId1(KNullStreamIdValue), + iStreamId2(KNullStreamIdValue), + iStreamId3(KNullStreamIdValue), + iStreamId4(KNullStreamIdValue), + iStreamId5(KNullStreamIdValue) + { + } + +protected: + virtual void DoPrepareL() + { + TheStore = CPermanentFileStore::ReplaceLC(TheFs, TheFileName, EFileWrite); + TheStore->SetTypeL(TheStore->Layout()); + TheStore->CommitL(); + + iStreamId1 = WriteNewStreamL(KStreamData2); + TheStore->SetRootL(iStreamId1); + TheStore->CommitL(); + iStreamId2 = WriteNewStreamL(KStreamData2); + iStreamId3 = WriteNewStreamL(KStreamData2().Left(KStreamData2().Length() - 1)); + iStreamId4 = WriteNewStreamL(KStreamData2_2); + iStreamId5 = WriteNewStreamL(KStreamData2_3); + + TheStore->DeleteL(iStreamId4); + TheStore->CommitL(); + + CleanupStack::Pop(TheStore); + } + + virtual void DoVerifyL(TInt) + { + TEST(TheStore == NULL); + TheStore = CPermanentFileStore::OpenLC(TheFs, TheFileName, EFileWrite); + RPermanentFileStoreIter iter; + iter.ResetLC(*TheStore); + //Stream 1 + TStreamId streamId = iter.NextL(); + TEST(streamId == iStreamId1); + RStoreReadStream strm; + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData2().Length()); + TBuf8<sizeof(KStreamData2)> buf; + strm.ReadL(buf, KStreamData2().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2().Ptr(), KStreamData2().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 2 + streamId = iter.NextL(); + TEST(streamId == iStreamId2); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData2().Length()); + strm.ReadL(buf, KStreamData2().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2().Ptr(), KStreamData2().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 3 + streamId = iter.NextL(); + TEST(streamId == iStreamId3); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData2().Length() - 1); + strm.ReadL(buf, KStreamData2().Length() - 1); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2().Ptr(), KStreamData2().Length() - 1), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 4 + streamId = iter.NextL(); + TEST(streamId == iStreamId5); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData2_3().Length()); + strm.ReadL(buf, KStreamData2_3().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2_3().Ptr(), KStreamData2_3().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //No more streams + streamId = iter.NextL(); + TEST(streamId == KNullStreamIdValue); + //Cleanup + CleanupStack::PopAndDestroy(&iter); + CleanupStack::PopAndDestroy(TheStore); + TheStore = NULL; + } + +private: + TStreamId iStreamId1; + TStreamId iStreamId2; + TStreamId iStreamId3; + TStreamId iStreamId4; + TStreamId iStreamId5; + + }; + +/////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TBaseTocReferenceTest ////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +//Do not change/shift the next lines, because "new line/space" characters will be inserted in the string! +_LIT8(KStreamData3, "\ +-01-ABCD-02-ABCD-03-ABCD-04-ABCD-05-ABCD-06-ABCD-07-ABCD-08-ABCD\ +-09-ABCD-10-ABCD-11-ABCD-12-ABCD"); +_LIT8(KStreamData3_2, "ABCDEFGH"); +_LIT8(KStreamData3_3, "0123456789"); + +//"Base TOC reference" test. +//When the base TOC is relocated, the delta TOC reference to the base TOC has to be updated with +// 2 "file write" operations (for "atomic block write" media), because the reference is split over a block boundary. +//This test class uses a set of test data, which puts the delta TOC reference to the base TOC +//at position 511 in the file (reference length - 4 bytes) +class TBaseTocReferenceTest : public TTocTestBase + { +public: + TBaseTocReferenceTest() : + iStreamId1(KNullStreamIdValue), + iStreamId2(KNullStreamIdValue), + iStreamId3(KNullStreamIdValue), + iStreamId4(KNullStreamIdValue), + iStreamId5(KNullStreamIdValue) + { + } + +protected: + virtual void DoPrepareL() + { + TheStore = CPermanentFileStore::ReplaceLC(TheFs, TheFileName, EFileWrite); + TheStore->SetTypeL(TheStore->Layout()); + TheStore->CommitL(); + + iStreamId1 = WriteNewStreamL(KStreamData3); + TheStore->SetRootL(iStreamId1); + TheStore->CommitL(); + iStreamId2 = WriteNewStreamL(KStreamData3); + iStreamId3 = WriteNewStreamL(KStreamData3().Left(KStreamData3().Length() - 3)); + iStreamId4 = WriteNewStreamL(KStreamData3_2); + iStreamId5 = WriteNewStreamL(KStreamData3_3); + + TheStore->DeleteL(iStreamId4); + TheStore->CommitL(); + + CleanupStack::Pop(TheStore); + } + + virtual void DoVerifyL(TInt) + { + TEST(TheStore == NULL); + TheStore = CPermanentFileStore::OpenLC(TheFs, TheFileName, EFileWrite); + RPermanentFileStoreIter iter; + iter.ResetLC(*TheStore); + //Stream 1 + TStreamId streamId = iter.NextL(); + TEST(streamId == iStreamId1); + RStoreReadStream strm; + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData3().Length()); + TBuf8<sizeof(KStreamData3)> buf; + strm.ReadL(buf, KStreamData3().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3().Ptr(), KStreamData3().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 2 + streamId = iter.NextL(); + TEST(streamId == iStreamId2); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData3().Length()); + strm.ReadL(buf, KStreamData3().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3().Ptr(), KStreamData3().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 3 + streamId = iter.NextL(); + TEST(streamId == iStreamId3); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData3().Length() - 3); + strm.ReadL(buf, KStreamData3().Length() - 3); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3().Ptr(), KStreamData3().Length() - 3), 0); + CleanupStack::PopAndDestroy(&strm); + //Stream 4 + streamId = iter.NextL(); + TEST(streamId == iStreamId5); + strm.OpenLC(*TheStore, streamId); + TEST2(strm.Source()->SizeL(), KStreamData3_3().Length()); + strm.ReadL(buf, KStreamData3_3().Length()); + TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3_3().Ptr(), KStreamData3_3().Length()), 0); + CleanupStack::PopAndDestroy(&strm); + //No more streams + streamId = iter.NextL(); + TEST(streamId == KNullStreamIdValue); + //Cleanup + CleanupStack::PopAndDestroy(&iter); + CleanupStack::PopAndDestroy(TheStore); + TheStore = NULL; + } + +private: + TStreamId iStreamId1; + TStreamId iStreamId2; + TStreamId iStreamId3; + TStreamId iStreamId4; + TStreamId iStreamId5; + + }; + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +void TocTest(TTocTestBase& aTestObj) + { + TInt err = KErrGeneral; + for(TInt cnt=1;err!=KErrNone;++cnt) + { + TheTest.Printf(_L("%d\r"), cnt); + aTestObj.Prepare(); + (void)TheFs.SetErrorCondition(KErrGeneral, cnt); + err = aTestObj.Test(); + (void)TheFs.SetErrorCondition(KErrNone); + aTestObj.Verify(err); + } + TheTest.Printf(_L("\n")); + TEST2(err, KErrNone); + aTestObj.Verify(err); + } + +/** +@SYMTestCaseID SYSLIB-STORE-CT-3481 +@SYMTestCaseDesc The test is performed on media, where atomic "block write" operations are guaranteed. + In a "file I/O error" simulation loop: + - Creates a CPermanentStoreFile object, stores there carefully selected set of test data, + such that a base TOC entry is split over the block boundary; + - Compacts the store; + - Commits; +@SYMTestPriority High +@SYMTestActions Creates a CPermanentStoreFile object, stores there carefully selected set of test data, + such that a base TOC entry is split over the block boundary. When the store is compacted + and the used media supports atomic "block write" operations, the STORE will update + the base TOC entry, which requires a "file write" operation crossing the block boundary. +@SYMTestExpectedResults The test should not fail or panic. +@SYMREQ REQ0000 +*/ +void BaseTocEntryTest() + { + TBaseTocEntryTest baseTocEntryTestObj; + TocTest(baseTocEntryTestObj); + } + +/** +@SYMTestCaseID SYSLIB-STORE-CT-3482 +@SYMTestCaseDesc The test is performed on media, where atomic "block write" operations are guaranteed. + In a "file I/O error" simulation loop: + - Creates a CPermanentStoreFile object, stores there carefully selected set of test data, + such that a delta TOC entry is split over the block boundary; + - Compacts the store; + - Commits; +@SYMTestPriority High +@SYMTestActions Creates a CPermanentStoreFile object, stores there carefully selected set of test data, + such that a delta TOC entry is split over the block boundary. When the store is compacted + and the used media supports atomic "block write" operations, the STORE will update + the delta TOC entry, which requires a "file write" operation crossing the block boundary. +@SYMTestExpectedResults The test should not fail or panic. +@SYMREQ REQ0000 +*/ +void DeltaTocEntryTest() + { + TDeltaTocEntryTest deltaTocEntryTestObj; + TocTest(deltaTocEntryTestObj); + } + +/** +@SYMTestCaseID SYSLIB-STORE-CT-3483 +@SYMTestCaseDesc The test is performed on media, where atomic "block write" operations are guaranteed. + In a "file I/O error" simulation loop: + - Creates a CPermanentStoreFile object, stores there carefully selected set of test data, + such that a base TOC reference is split over the block boundary; + - Compacts the store; + - Commits; +@SYMTestPriority High +@SYMTestActions Creates a CPermanentStoreFile object, stores there carefully selected set of test data, + such that a base TOC reference is split over the block boundary. When the store is compacted + and the used media supports atomic "block write" operations, the STORE will update + the base TOC reference, which requires a "file write" operation crossing the block boundary. +@SYMTestExpectedResults The test should not fail or panic. +@SYMREQ REQ0000 +*/ +void BaseTocReferenceTest() + { + TBaseTocReferenceTest baseTocReferenceTestObj; + TocTest(baseTocReferenceTestObj); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +void DoTests() + { + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-STORE-CT-3481 Base TOC entry test ")); + BaseTocEntryTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-STORE-CT-3482 Delta TOC entry test ")); + DeltaTocEntryTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-STORE-CT-3483 Base TOC reference test ")); + BaseTocReferenceTest(); + } + +//The function returns true, if the file system guarantees atomic "block write" operations on aDriveNo. +TBool IsBlockAtomic(TInt aDriveNo) + { + __ASSERT_DEBUG(aDriveNo >= EDriveA && aDriveNo <= EDriveZ, User::Invariant()); + + TVolumeIOParamInfo volInfo; + TInt err = TheFs.VolumeIOParam(aDriveNo, volInfo); + //If VolumeIOParam() succeeds, the media block size is >= 512 bytes and the media block size is power of two - report + //that the media supports atomic "block write" operations. + const TInt KDefaultMediaBlockSize = 512; + return err == KErrNone && volInfo.iBlockSize >= KDefaultMediaBlockSize && (volInfo.iBlockSize & (volInfo.iBlockSize - 1)) == 0; + } + +//Returns the number of the drive on which atomic "block write" operations are supported. +TInt GetBlockAtomicDriveNo() + { + //Uncomment, if you want to do the test on drive C: + //(but you will need also to uncomment 2 lines in CPermanentStoreCoord::FileQoSL()) + //return EDriveC; + // + for(TInt driveNo=EDriveA;driveNo<=EDriveZ;++driveNo) + { + TDriveInfo driveInfo; + TInt err = TheFs.Drive(driveInfo, driveNo); + if(err == KErrNone) + { + if(!(driveInfo.iDriveAtt & KDriveAttTransaction)) + { +#ifdef __X86GCC__ + TFSName thefsname; + err = TheFs.FileSystemName (thefsname, driveNo); + + if ((err == KErrNone) && (!(thefsname.MatchF(_L("NTFS"))))) // X86GCC doesn't (yet) support write operations on NTFS partitions +#endif + if(IsBlockAtomic(driveNo)) + { + return driveNo; + } + } + } + } + return -1; + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// If you want to check that the atomic "block write" optimisation works and the code change is robust, then you +// have to: +// 1) Prove that if the the "file write" operations over a sector boundary are not done properly, the current test will crash +// 2) Prove that if the the "file write" operations over a sector boundary are done properly, the current test won't crash +// How this could be done: +// For (1) - Simulate that the file system for drive C: on the Emulator is transactional. +// In order to do that: +// - uncomment the "return EDriveC;" statement in the function above (GetBlockAtomicDriveNo()); +// - go to CPermanentStoreCoord::FileQoSL() function and uncomment the first two lines: +// "iFileQos = ETransactional;" +// "return iFileQos;" +// So, the result of your changes will be: STORE will try to optimize the "file write" operations on drive C:, +// because drive C: will be reported as a "transactional" drive. Since the drive C: does not really support "transactional" +// operations, the optimization will cause some failures in the current test, if the data block which has to be written, +// is split across a sector boundary. In order to make sure that the split will hapen - do step (2). +// 2) Declare SYSLIBS_TEST macro in the related variant.hrh file. This change will cause RFileBuf to split the "file write" +// operations in two separate operations, if the data block to be written has to be split over a sector boundary. +// After the changes, build STORE and run the current test. You must see that the test crashes. +// +// Then, for (2) (a) restore the original code in GetBlockAtomicDriveNo() and (b) CPermanentStoreCoord::FileQoSL() and rebuild STORE. +// Rerun the current test and the test must pass. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TInt E32Main() + { + TheTest.Title(); + + CTrapCleanup* tc = CTrapCleanup::New(); + + __UHEAP_MARK; + + TInt err = TheFs.Connect(); + TheTest(err == KErrNone); + + TheTest.Start(_L("Check for \"block atomic write\" drives")); + TInt driveNo = GetBlockAtomicDriveNo(); + if(driveNo != -1) + { + TheTest.Printf(_L("Test drive - %c:\r\n"), 'A' + driveNo); + TheTest.Printf(_L("The test expects that STORE component is built with SYSLIBS_TEST macro defined\r\n")); + CreateTestEnv(driveNo); + DoTests(); + DeleteTestFiles(); + } + else + { + TheTest.Printf(_L("!!! No \"block atomic write\" drive found!\r\n")); + } + TheFs.Close(); + + __UHEAP_MARKEND; + + TheTest.End(); + TheTest.Close(); + + delete tc; + + User::Heap().Check(); + return KErrNone; + }