sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // This test tests reading and writing to the protected & unprotected area of an SD card sl@0: // & verifies that mounting & dismounting the protected area does not disrupt reads and/or sl@0: // writes to the unprotected area. sl@0: // NB For test to work, a valid key which matches the SD card under test needs to be put sl@0: // into the byte array testDeviceKeyRawData[]. sl@0: // ********* IMPORTANT NOTE TO SYMBIAN ENGINEERS WORKING WITH THIS TEST ********* sl@0: // The key MUST NOT BE CHECKED INTO PERFORCE as this would contravene the license agreement sl@0: // we have with the SD Card Association. sl@0: // ********* IMPORTANT NOTE TO SYMBIAN ENGINEERS WORKING WITH THIS TEST ********* sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: const TUint32 KDriveNumProt = EDriveG; sl@0: const TUint32 KDriveNumUnprot = EDriveF; sl@0: TChar gDriveLetterProt; sl@0: TChar gDriveLetterUnprot; sl@0: TBool gMountProtectedArea = EFalse; sl@0: sl@0: GLDEF_D RTest test(_L("T_SETKEY")); sl@0: sl@0: // flags stolen from locmedia.h sl@0: //const TInt KForceMediaChangeReOpenAllMediaDrivers = 0; sl@0: const TUint KForceMediaChangeReOpenMediaDriver = 0x80000000UL; sl@0: const TUint KMediaRemountForceMediaChange = 0x00000001UL; sl@0: sl@0: class TSDCardSecureMountInfo sl@0: { sl@0: public: sl@0: TUid iUid; sl@0: const TDesC8* iEncryptedDeviceKey; sl@0: const TDesC8* iRamMKBData; sl@0: TInt iMKBNumber; sl@0: }; sl@0: typedef TPckgBuf TSDCardSecureMountInfoPckg; sl@0: sl@0: typedef enum sl@0: { sl@0: EClearMountInfo=0, sl@0: ESetMountInfo=1 sl@0: } TMountInfoAction; sl@0: sl@0: sl@0: // Standard boilerplate for creating a console window //////////////////////// sl@0: void StartAppL(); sl@0: void SetupConsoleL(); sl@0: sl@0: GLDEF_C TInt E32Main() // main function called by E32 sl@0: { sl@0: CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack sl@0: TRAPD(error,SetupConsoleL()); // more initialization, then do example sl@0: __ASSERT_DEBUG(!error,User::Panic(_L("BossTextUi"),error)); sl@0: delete cleanup; // destroy clean-up stack sl@0: return 0; // and return sl@0: } sl@0: sl@0: // Determine whether we should run the full test or just mount the protected area sl@0: void ParseCommandLine() sl@0: { sl@0: TBuf<32> args; sl@0: User::CommandLine(args); sl@0: sl@0: if (args == _L("-m")) sl@0: { sl@0: gMountProtectedArea = ETrue; sl@0: } sl@0: else if (args == _L("-?")) sl@0: { sl@0: test.Printf(_L("usage: t_setkey [-m]\n")); sl@0: test.Printf(_L("-m => mount proteced area and exit\n")); sl@0: } sl@0: } sl@0: sl@0: void SetupConsoleL() // initialize and call example code under cleanup stack sl@0: { sl@0: test.Title(); sl@0: test.Start(_L("Starting tests...")); sl@0: sl@0: ParseCommandLine(); sl@0: TRAPD(error,StartAppL()); // perform example function sl@0: if (error) sl@0: test.Printf(_L("failed: leave code=%d\n"), error); sl@0: else sl@0: test.Printf(_L("ok\n")); sl@0: sl@0: test.Printf(_L(" [press any key]\n")); sl@0: test.Getch(); sl@0: sl@0: test.End(); sl@0: test.Close(); sl@0: sl@0: } sl@0: sl@0: // End of standard boilerplate /////////////////////////////////////////////// sl@0: sl@0: sl@0: static const TUint8 testDeviceKeyRawData[160] = sl@0: { sl@0: sl@0: // Symbian test key : sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, sl@0: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 sl@0: sl@0: sl@0: }; sl@0: sl@0: TInt WriteThreadEntryPoint( TAny* aParam ) sl@0: { sl@0: (void)aParam; sl@0: sl@0: RTest test(_L("WriteThread")); sl@0: sl@0: test.Title(); sl@0: sl@0: test.Start(_L("Starting WriteThread ...")); sl@0: sl@0: TInt r; sl@0: RFs fs; sl@0: sl@0: r = fs.Connect(); sl@0: if(r != KErrNone) sl@0: { sl@0: test.Printf(_L("WT Connect err %d\n"), r); sl@0: } sl@0: sl@0: RFile file; sl@0: sl@0: TFileName fileNameUnprot = _L("?:\\TESTTHRD.TXT"); sl@0: fileNameUnprot[0] = (TText) gDriveLetterUnprot; sl@0: sl@0: //Open file on the user area drive sl@0: r = file.Replace(fs, fileNameUnprot, EFileWrite); sl@0: if(r != KErrNone) sl@0: { sl@0: test.Printf(_L("WT File Replace err %d\n\n"), r); sl@0: test(0); sl@0: } sl@0: sl@0: TPtrC8 data(testDeviceKeyRawData, 8); sl@0: sl@0: RThread().Rendezvous(KErrNone); sl@0: sl@0: for(TInt iter=0; iter < KMaxTInt;iter++) // keep sending write requests to the user area for ever sl@0: { sl@0: sl@0: r = file.Write(data); sl@0: //test.Printf(_L("WT File Write err %d iter %d\r"), r, iter); sl@0: sl@0: if(r != KErrNone) sl@0: { sl@0: test.Printf(_L("WT File Write err %d\n"), r); sl@0: test(0); sl@0: } sl@0: } sl@0: sl@0: file.Close(); sl@0: fs.Close(); sl@0: sl@0: test.End(); sl@0: test.Close(); sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: sl@0: GLDEF_C void StartAppL() sl@0: { sl@0: sl@0: // Exit if no key defined sl@0: if (testDeviceKeyRawData[0] == 0 && testDeviceKeyRawData[1] == 0) sl@0: { sl@0: test.Printf(_L("This test needs to be recompiled with a valid key\n")); sl@0: test(0); sl@0: } sl@0: sl@0: RFs fs; sl@0: TInt r; sl@0: sl@0: sl@0: test.Printf(_L("Starting Setkey\n")); sl@0: if(fs.Connect()!=KErrNone) sl@0: return; sl@0: sl@0: test.Printf(_L("Connected to fileserver OK\n")); sl@0: TBuf8<160> mkBData; sl@0: sl@0: mkBData.SetLength(160); sl@0: TInt i; sl@0: for (i = 0; i < 160; i++) sl@0: { sl@0: mkBData[i] = testDeviceKeyRawData[i]; sl@0: } sl@0: sl@0: TSDCardSecureMountInfoPckg pckg; sl@0: sl@0: sl@0: pckg().iRamMKBData=(const TDesC8*)0x01; //Unused for now. sl@0: pckg().iMKBNumber = 0; sl@0: // pckg().iMKBNumber = 11; // for SD Binding ? sl@0: static TPtrC8 encryptedDeviceKey(testDeviceKeyRawData, sizeof(testDeviceKeyRawData)); sl@0: pckg().iEncryptedDeviceKey = &encryptedDeviceKey; sl@0: sl@0: sl@0: r = fs.DriveToChar(KDriveNumProt, gDriveLetterProt); sl@0: r = fs.DriveToChar(KDriveNumUnprot, gDriveLetterUnprot); sl@0: TFileName fileNameUnprot = _L("?:\\TEST.TXT"); sl@0: TFileName fileNameProt = _L("?:\\TEST.TXT"); sl@0: fileNameUnprot[0] = (TText) gDriveLetterUnprot; sl@0: fileNameProt[0] = (TText) gDriveLetterProt; sl@0: sl@0: TVolumeInfo v; sl@0: sl@0: r = fs.Volume(v, KDriveNumProt); //Check sl@0: test.Printf(_L("Volume() returned %d\n"), r); sl@0: test(r == KErrNotReady || r == KErrNone); sl@0: sl@0: sl@0: if (gMountProtectedArea) sl@0: { sl@0: test.Next(_L("test remount with KForceMediaChangeReOpenMediaDriver flag")); sl@0: // verify that the unprotected area does not get a change notification sl@0: TFileName filePathUnprot = _L("?:\\"); sl@0: filePathUnprot[0] = (TText) gDriveLetterUnprot; sl@0: TRequestStatus changeStatus; sl@0: fs.NotifyChange(ENotifyAll, changeStatus, filePathUnprot); sl@0: sl@0: r = fs.RemountDrive(KDriveNumProt, &pckg, (TUint) KForceMediaChangeReOpenMediaDriver); sl@0: test(r == KErrNone); sl@0: r = fs.Volume(v, KDriveNumProt); //Check sl@0: test.Printf(_L("Volume() returned %d\n"), r); sl@0: test(r == KErrNone || r == KErrCorrupt); sl@0: sl@0: test.Next(_L("test this causes no change to unprotected drive")); sl@0: test.Printf(_L("changeStatus %d\n"), changeStatus.Int()); sl@0: test (changeStatus.Int() == KRequestPending); sl@0: fs.NotifyChangeCancel(changeStatus); sl@0: sl@0: test.Printf(_L("Remount Drive suceeded. Secure area is now unlocked\n")); sl@0: fs.Close(); sl@0: return; sl@0: } sl@0: sl@0: // Set the mount info for the secure area using KMediaRemountForceMediaChange flag sl@0: // This is asynchronous in behaviour i.e. we need to wait for (two) media change notifications sl@0: // before the drive is ready for use sl@0: test.Next(_L("test remount with KMediaRemountForceMediaChange flag")); sl@0: TRequestStatus changeStatus; sl@0: fs.NotifyChange(ENotifyAll, changeStatus); sl@0: r = fs.RemountDrive(KDriveNumProt, &pckg, (TUint) KMediaRemountForceMediaChange); sl@0: test.Printf(_L("RemountDrive() returned %d\n"), r); sl@0: test(r == KErrNotReady || r == KErrNone); sl@0: sl@0: test.Printf(_L("Waiting for media change...\n")); sl@0: User::WaitForRequest(changeStatus); sl@0: sl@0: do sl@0: { sl@0: sl@0: sl@0: r = fs.Volume(v, KDriveNumProt); //Check sl@0: test.Printf(_L("Volume() returned %d\n"), r); sl@0: sl@0: fs.NotifyChange(ENotifyAll, changeStatus); sl@0: } sl@0: while (r == KErrNotReady); sl@0: fs.NotifyChangeCancel(changeStatus); sl@0: sl@0: sl@0: sl@0: // Set the mount info for the secure area using KForceMediaChangeReOpenMediaDriver flag sl@0: // This should be synchronous in behaviour sl@0: test.Next(_L("test remount with KForceMediaChangeReOpenMediaDriver flag")); sl@0: r = fs.RemountDrive(KDriveNumProt, NULL, (TUint) KForceMediaChangeReOpenMediaDriver); sl@0: test(r == KErrNone); sl@0: r = fs.RemountDrive(KDriveNumProt, &pckg, (TUint) KForceMediaChangeReOpenMediaDriver); sl@0: test(r == KErrNone); sl@0: r = fs.Volume(v, KDriveNumProt); //Check sl@0: test.Printf(_L("Volume() returned %d\n"), r); sl@0: test(r == KErrNone); sl@0: sl@0: test.Printf(_L("Remount Drive suceeded. Secure area is now unlocked\n")); sl@0: test.Printf(_L("Press any key to continue...\n")); sl@0: sl@0: sl@0: test.Next(_L("test writing to protected & unprotected areas")); sl@0: sl@0: RFile f1,f2; sl@0: TRequestStatus req1, req2, req3, req4; sl@0: sl@0: const TInt KBufSize = 32 * 1024; sl@0: LOCAL_D TBuf8 gBuf; sl@0: sl@0: sl@0: test.Printf(_L("Opening files...\n")); sl@0: test.Printf(_L("Opening %S...\n"), &fileNameUnprot); sl@0: r = f1.Replace(fs, fileNameUnprot,EFileStreamText|EFileWrite); sl@0: test (r == KErrNone); sl@0: sl@0: test.Printf(_L("Opening %S...\n"), &fileNameProt); sl@0: r = f2.Replace(fs, fileNameProt,EFileStreamText|EFileWrite); sl@0: test (r == KErrNone); sl@0: sl@0: sl@0: // test.Printf(_L("Wait 10 secs for stack to power down...\n")); sl@0: // User::After(10 * 1000000); sl@0: // test.Printf(_L("done\n")); sl@0: sl@0: gBuf.SetLength(KBufSize); sl@0: sl@0: test.Printf(_L("Writing files...\n")); sl@0: sl@0: req1 = KRequestPending; sl@0: req2 = KRequestPending; sl@0: req3 = KRequestPending; sl@0: req4 = KRequestPending; sl@0: sl@0: f1.Write(gBuf, req1); sl@0: r = fs.RemountDrive(KDriveNumProt, &pckg, (TUint) KForceMediaChangeReOpenMediaDriver); sl@0: test (r == KErrNone); sl@0: f2.Write(gBuf, req2); sl@0: sl@0: test.Printf(_L("req1 %d, req2 %d\n"), req1.Int(), req2.Int()); sl@0: test (req1 == KRequestPending || req1 == KErrNone); sl@0: test (req2 == KRequestPending || req2 == KErrNone); sl@0: sl@0: // force a remount to test whether a write to the unprotected area sl@0: // is disrupted.... sl@0: // NB Should set aFlags to KForceMediaChangeReOpenMediaDriver, otherwise a media change will occur which WILL sl@0: // prematurely complete any pending writes sl@0: r = fs.RemountDrive(KDriveNumProt, &pckg, (TUint) KForceMediaChangeReOpenMediaDriver); sl@0: test (r == KErrNone); sl@0: sl@0: //r = fs.RemountDrive(KDriveNumProt, &pckg, 1); sl@0: test.Printf(_L("RemountDrive() returned %d\n"), r); sl@0: sl@0: f1.Write(gBuf, req3); sl@0: f2.Write(gBuf, req4); sl@0: sl@0: test.Printf(_L("WaitForRequests...\n")); sl@0: User::WaitForRequest(req1); sl@0: User::WaitForRequest(req2); sl@0: User::WaitForRequest(req3); sl@0: User::WaitForRequest(req4); sl@0: sl@0: test.Printf(_L("req1 %d, req2 %d req3 %d, req4 %d\n"), req1.Int(), req2.Int(), req3.Int(), req4.Int()); sl@0: test (req1 == KErrNone); sl@0: test (req2 == KErrNone); sl@0: test (req3 == KErrNone); sl@0: test (req4 == KErrNone); sl@0: sl@0: f1.Close(); sl@0: f2.Close(); sl@0: sl@0: sl@0: // create a thread which continuously writes to the unprotected area sl@0: // whilst continually remounting protected area in this thread. sl@0: sl@0: test.Next(_L("test writing to protected & unprotected areas using different threads")); sl@0: sl@0: test.Printf(_L("Opening %S for read access...\n"), &fileNameUnprot); sl@0: r = f2.Open(fs, fileNameProt, EFileShareReadersOnly); sl@0: test (r == KErrNone); sl@0: sl@0: sl@0: test (r == KErrNone); sl@0: RThread thread; sl@0: r = thread.Create( _L("Write Thread"), WriteThreadEntryPoint, KDefaultStackSize, NULL, NULL); sl@0: if(r !=KErrNone) sl@0: { sl@0: test.Printf(_L("MT Thread Create 1 ret = %d\n"),r); sl@0: return; sl@0: } sl@0: TRequestStatus writeThreadStat; sl@0: sl@0: thread.Rendezvous(writeThreadStat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(writeThreadStat); sl@0: // thread.Close(); //close handle to thread sl@0: if(writeThreadStat.Int() != KErrNone) sl@0: { sl@0: test.Printf(_L("MT Thread Create 2 ret = %d\n"),writeThreadStat.Int()); sl@0: test(0); sl@0: } sl@0: sl@0: TBuf8<14> buf; sl@0: sl@0: sl@0: const TInt KMaxIterations = 1000; sl@0: for(TInt n=0; n