// 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 the License "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:
// e32test\demandpaging\t_tbus_datapaging.cpp
// Functional tests for data paging.
// 002 ???
// 003 ???
//

//! @SYMTestCaseID			KBASE-T_TBUS_DATAPAGING
//! @SYMTestType			UT
//! @SYMPREQ				???
//! @SYMTestCaseDesc		Data Paging functional tests with TBusLocalDrive.
//! @SYMTestActions			001 ???
//! @SYMTestExpectedResults All tests should pass.
//! @SYMTestPriority        High
//! @SYMTestStatus          Implementation on-going

#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <dptest.h>
#include <e32hal.h>
#include <u32exec.h>
#include <e32svr.h>
#include <e32panic.h>
#include "u32std.h"

#include <f32file.h>
#include <f32dbg.h>
#include <f32fsys.h>

#include "t_dpcmn.h"
#include "../secure/d_sldd.h"
#include "../mmu/mmudetect.h"

const TInt KMaxLengthOfStoreMapping = 16 + sizeof(TInt32) + KMaxMediaPassword;
const TInt KMaxPersistentStore(TPasswordStore::EMaxPasswordLength+KMaxLengthOfStoreMapping);
typedef TBuf8<KMaxPersistentStore> TPersistentStore;

RChunk gMyChunk;
TUint gOffset = 0;
TUint8* gData = NULL;
const TUint8 KClearValue = 0xed;
const TUint  KChunkSizeInPages = 64;	// 64 * 4096 = 256K
const TInt KTestBufLen=256;


#define __DECLARE_VAR_IN_CHUNK(type, varRef)											\
									type varRef = *(type*) (gData+gOffset);				\
									gOffset += Max(gPageSize, sizeof(type));			\
									test(gOffset <= gPageSize * KChunkSizeInPages);

#define __DECLARE_AND_INIT_VAR_IN_CHUNK(type, var)										\
									type &var = *(type*) (gData+gOffset);				\
									var = type();										\
									gOffset += Max(gPageSize, sizeof(type));			\
									test(gOffset <= gPageSize * KChunkSizeInPages);	


#define __DECLARE_ARRAY_IN_CHUNK(type, var, size)										\
									type *var = (type*) (gData+gOffset);				\
									gOffset += Max(gPageSize, (sizeof(type) * size));	\
									test(gOffset <= gPageSize * KChunkSizeInPages);
									
#define __FLUSH_AND_CALL_API_METHOD(return, function)									\
											DPTest::FlushCache(); 						\
											return = function;
											

LOCAL_D RFs TheFs;
TInt gFsDriveNumber	= -1;
	
RTest test(_L("T_TBUS_DATAPAGING"));
_LIT(KChunkName, "t_datapaging chunk");

const TUint KDriveAttMask = KDriveAttLocal | KDriveAttRom | KDriveAttInternal | KDriveAttRemovable | KDriveAttRemote;
const TUint KMediaAttMask = KMediaAttVariableSize | KMediaAttDualDensity | KMediaAttLockable | KMediaAttLocked | KMediaAttHasPassword  | KMediaAttReadWhileWrite;

void CreatePagedChunk(TInt aSizeInPages, TInt aWipeByte = -1)
	{
	test_Equal(0,gMyChunk.Handle());
	
	TChunkCreateInfo createInfo;
	TInt size = aSizeInPages * gPageSize;
	createInfo.SetNormal(size, size);
	createInfo.SetPaging(TChunkCreateInfo::EPaged);
	createInfo.SetOwner(EOwnerProcess);
	createInfo.SetGlobal(KChunkName);
	if (aWipeByte != -1)
		createInfo.SetClearByte(aWipeByte);
	test_KErrNone(gMyChunk.Create(createInfo));
	test(gMyChunk.IsPaged()); // this is only ever called if data paging is supported
	
	gData = gMyChunk.Base();
	}
	
TInt TestDriveConnectAndCaps(TBusLocalDrive &aDrive, TInt &aLocalDriveNumber)
	{

	test.Next(_L("Test Drive Connect And Caps"));

	__DECLARE_VAR_IN_CHUNK(TInt, &r);
	
	test.Printf(_L("changeFlag...\n"));
	__DECLARE_VAR_IN_CHUNK(TBool, &changeFlag);
	changeFlag = EFalse;
	
	test.Printf(_L("call aDrive.Connect()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Connect(aLocalDriveNumber,changeFlag));
	
	test.Printf(_L("r:%d\n"),r);	
	test_Equal(KErrNone, r);
	
	test.Printf(_L("call aDrive.Caps()...\n"));	
	__DECLARE_VAR_IN_CHUNK(TLocalDriveCapsV5, &driveCaps);
	
	TPckg<TLocalDriveCapsV5> capsPckg(driveCaps); 
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Caps(capsPckg));
	
	test_Equal(KErrNone, r);
	test.Printf(_L("r:%d\n"),r);
	test.Printf(_L("driveCaps.iDriveAtt			:0x%08x\n"), driveCaps.iDriveAtt);
	test.Printf(_L("driveCaps.iSize    			:%ld\n"), driveCaps.iSize);
	test.Printf(_L("driveCaps.iSerialNumLength  :%d\n"), driveCaps.iSerialNumLength);
	
	return I64LOW(driveCaps.iSize);
	}

void TestDriveSizeRelatedMethods(TBusLocalDrive &aDrive, TInt aNewSize, TInt aOldSize)
	{
	TInt r;
	
	test.Next(_L("Test Drive Size Related Methods"));
	test.Printf(_L("newDriveSize...\n"));
	__DECLARE_VAR_IN_CHUNK(TInt, &newDriveSize);
	newDriveSize = aNewSize;	
	
	test.Printf(_L("call aDrive.Enlarge()...\n"));
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Enlarge(newDriveSize));
	test.Printf(_L("r:%d\n"),r);
	test((KErrNone == r) || (KErrNotSupported == r) || (KErrNotReady == r));
	if(r != KErrNone )
		{
		test.Printf(_L("errInfo...\n"));
		__DECLARE_ARRAY_IN_CHUNK(TUint8, errInfo, KTestBufLen);
		
		TPtr8 pErrInfoBuff(errInfo, KTestBufLen);
		
		__FLUSH_AND_CALL_API_METHOD(r, aDrive.GetLastErrorInfo(pErrInfoBuff));
		test.Printf(_L("r:%d\n"),r);
		test((KErrNone == r) || (KErrNotSupported == r));
		}
	
	
	test.Printf(_L("call aDrive.ReduceSize()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.ReduceSize(0, aOldSize));
	test((KErrNone == r) || (KErrNotSupported == r) || (KErrNotReady == r)); 

	}

void TestWriteReadRelatedMethods(TBusLocalDrive &aDrive)
	{
	
	test.Next(_L("Test Write & Read Related Methods"));
		
	__DECLARE_VAR_IN_CHUNK(TInt, &r);
	
	test.Printf(_L("msgHandle...\n"));
	__DECLARE_VAR_IN_CHUNK(TInt, &msgHandle);
	msgHandle = KLocalMessageHandle;
		

	__DECLARE_VAR_IN_CHUNK(TUint, &i);
	test.Printf(_L("wrBuf...\n"));	
	TBuf8<KTestBufLen> wrBuf(KTestBufLen);
	for (i=0 ; i<(TUint)KTestBufLen ; i++)
		wrBuf[i]=(TUint8)i;
	
	
	test.Printf(_L("wrBuf2...\n"));
	__DECLARE_ARRAY_IN_CHUNK(TUint8, wrBuf2, KTestBufLen);
			
	test.Printf(_L("fill wrBuf2...\n"));
	for (i=0 ; i<(TUint)KTestBufLen ; i++)
		wrBuf2[i]=(TUint8)i;
	
	TPtr8 pWrBuf2(wrBuf2, KTestBufLen, KTestBufLen);
	
	test.Printf(_L("rdBuf...\n"));
	TBuf8<KTestBufLen> rdBuf(KTestBufLen);
	
	
	test.Printf(_L("rdBuf2...\n"));
	__DECLARE_ARRAY_IN_CHUNK(TUint8, rdBuf2, KTestBufLen);
	
	TPtr8 pRdBuf2(rdBuf2, KTestBufLen);
	
	test.Printf(_L("call aDrive.Write()...\n"));	
	rdBuf.Fill(0,KTestBufLen);
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Write(0,KTestBufLen,&wrBuf,msgHandle,0));
	test_Equal(KErrNone, r);
	
	
	test.Printf(_L("call aDrive.Read()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Read(0,KTestBufLen,&rdBuf,msgHandle,0));
	test_Equal(KErrNone, r);
	
	for (i=0 ; i<(TUint)KTestBufLen ; i++)
		test_Equal(wrBuf[i], rdBuf[i]);
	
	test.Printf(_L("call aDrive.Write()...\n"));	
	pRdBuf2.Fill(0,KTestBufLen);
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Write(0,pWrBuf2));
	test_Equal(KErrNone, r);
	
	
	test.Printf(_L("call aDrive.Read()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Read(0,KTestBufLen, pRdBuf2));
	test_Equal(KErrNone, r);
	
	for (i=0 ; i<(TUint)KTestBufLen ; i++)
		test_Equal(wrBuf2[i], rdBuf2[i]);
	
	}

void TestPasswordRelatedMethods(TBusLocalDrive &aDrive)
	{
	TInt r;
	
	test.Next(_L("Test Password Related Methods"));
	//__DECLARE_VAR_IN_CHUNK(TPersistentStore, &wStore);
	
	TPersistentStore* pstoreAB;
	test((pstoreAB = new TPersistentStore) != 0);
	TPersistentStore& wStore = *pstoreAB;

	//__DECLARE_AND_INIT_VAR_IN_CHUNK(TPersistentStore, wStore);
	
	// Password related API methods call
	test.Printf(_L("call aDrive.WritePasswordData() to clear passwords...\n"));	
	__DECLARE_VAR_IN_CHUNK(TInt, &passwordStoreLength);
	
	TBuf8<1> nulSt;
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.WritePasswordData(nulSt));
	test( r == KErrNone);// empty
	
	test.Printf(_L("call aDrive.PasswordStoreLengthInBytes()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(passwordStoreLength, aDrive.PasswordStoreLengthInBytes());
	
	test.Printf(_L("passwordStoreLength:%d\n"), passwordStoreLength);
	test_Equal(0, passwordStoreLength);


	test.Printf(_L("call aDrive.ErasePassword()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.ErasePassword());
	test.Printf(_L("r:%d\n"),r);
	

	test.Printf(_L("wStore.Size():%d\n"),wStore.Size());
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.WritePasswordData(wStore));
	
	test.Printf(_L("r:%d\n"),r);
	test((KErrNone == r)); // || (KErrCorrupt == r));		// TO-DO Why Corrupt???
	
	__FLUSH_AND_CALL_API_METHOD(passwordStoreLength, aDrive.PasswordStoreLengthInBytes());
	
	test.Printf(_L("passwordStoreLength:%d\n"), passwordStoreLength);
	test((r == KErrNone ?  (wStore.Size() == passwordStoreLength) : (0 == passwordStoreLength) ));
	


	test.Printf(_L("Set and store a password...\n"));		
	TDes8 &st = wStore;
	TMediaPassword a((const TUint8*) "CID0ccccccccccc#");
	TUint8 passLen[sizeof(TInt32)];
	passLen[0] = 0;
	passLen[1] = 0;
	passLen[2] = 0;
	passLen[3] = 16;
	
	//test.Printf(_L("Password3:'%S'\n"), &a);
	
	st.Append(a);
	st.Append(passLen, sizeof(TInt32));
	st.Append(a);
	
	test.Printf(_L("wStore.Size():%d\n"),wStore.Size());
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.WritePasswordData(wStore));
	
	test.Printf(_L("r:%d\n"),r);
	test((KErrNone == r));
	
	__FLUSH_AND_CALL_API_METHOD(passwordStoreLength, aDrive.PasswordStoreLengthInBytes());
	
	test.Printf(_L("passwordStoreLength:%d\n"), passwordStoreLength);
	test((r == KErrNone ?  (wStore.Size() == passwordStoreLength) : (0 == passwordStoreLength) ));
	
	test.Printf(_L("call aDrive.ErasePassword()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.ErasePassword());
	test.Printf(_L("r:%d\n"),r);
	
	test.Printf(_L("call aDrive.WritePasswordData() to set password again...\n"));	
	test.Printf(_L("wStore.Size():%d\n"),wStore.Size());
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.WritePasswordData(wStore));
	
	test.Printf(_L("r:%d\n"),r);
	test((KErrNone == r));
	
	__FLUSH_AND_CALL_API_METHOD(passwordStoreLength, aDrive.PasswordStoreLengthInBytes());
	
	test.Printf(_L("passwordStoreLength:%d\n"), passwordStoreLength);
	test((r == KErrNone ?  (wStore.Size() == passwordStoreLength) : (0 == passwordStoreLength) ));
	
	
	// Finally erase password
	test.Printf(_L("call aDrive.WritePasswordData() to erase password...\n"));		
	wStore.Zero();	// empty password store
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.WritePasswordData(wStore))
	test( r == KErrNone);// Clear
	
	__FLUSH_AND_CALL_API_METHOD(passwordStoreLength, aDrive.PasswordStoreLengthInBytes());
	
	test.Printf(_L("passwordStoreLength:%d\n"), passwordStoreLength);
	test((r == KErrNone ?  (wStore.Size() == passwordStoreLength) : (0 == passwordStoreLength) ));
	
	
	
	// Test SetPassword
	TMediaPassword nul(nulSt);
	
	test.Printf(_L("call aDrive.SetPassword()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.SetPassword(nul, a, EFalse));
	test.Printf(_L("r:%d\n"),r);
	test_Equal(KErrNone, r);
	
	// Erase Password
	test.Printf(_L("call aDrive.ErasePassword()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.ErasePassword());
	test.Printf(_L("r:%d\n"),r);
	

	test.Printf(_L("call aDrive.SetPassword()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.SetPassword(nul, a, EFalse));
	test.Printf(_L("r:%d\n"),r);
	test_Equal(KErrNone, r);
	
	// Erase Clear
	test.Printf(_L("call aDrive.Clear()...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.Clear(a));
	test.Printf(_L("r:%d\n"),r);
	
	
	test.Printf(_L("call aDrive.SetPassword() to clear again...\n"));	
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.SetPassword(a, nul, EFalse));
	test.Printf(_L("r:%d\n"),r);
	test_Equal(KErrAccessDenied, r);
	
	
	// Finally erase password
	test.Printf(_L("call aDrive.WritePasswordData() to erase password...\n"));		
	wStore.Zero();	// empty password store
	__FLUSH_AND_CALL_API_METHOD(r, aDrive.WritePasswordData(wStore))
	test( r == KErrNone);// Clear
	
	__FLUSH_AND_CALL_API_METHOD(passwordStoreLength, aDrive.PasswordStoreLengthInBytes());
	
	test.Printf(_L("passwordStoreLength:%d\n"), passwordStoreLength);
	test((r == KErrNone ?  (wStore.Size() == passwordStoreLength) : (0 == passwordStoreLength) ));
		
	}

void TestFormatRelatedMethods(TBusLocalDrive &aDrive, TInt aSize )
	{
	test.Next(_L("Test Format Related Methods"));	
	
	test.Printf(_L("call aDrive.Format(TFormatInfo)...\n"));	
	__DECLARE_AND_INIT_VAR_IN_CHUNK(TFormatInfo, fi);
	__DECLARE_VAR_IN_CHUNK(TInt, &ret);
	__DECLARE_VAR_IN_CHUNK(TInt, &attempt);
	
	__FLUSH_AND_CALL_API_METHOD(ret, aDrive.Format(fi));
	test.Printf(_L("ret:%d\n"),ret);
	while(ret!=KErrEof)
		{
		if( ret == KErrNotReady )
			{
			attempt = 100;
			while( (ret= aDrive.Format(fi)) == KErrNotReady && --attempt)
				{
				test.Printf(_L("attempt:%d\n"),attempt);
				User::After(1000000);
				}	
			test(attempt);
			}
		else
			{
			test(ret==KErrNone);
			ret= aDrive.Format(fi);	
			}		
		}
	
	
	test.Printf(_L("call aDrive.Format(pos, length)...\n"));	
	User::After(1000000);
	
	__DECLARE_VAR_IN_CHUNK(TInt64, &pos);
	pos = 0;
	__DECLARE_VAR_IN_CHUNK(TInt, &length);
	length = aSize;
	
	attempt = 100;
	__FLUSH_AND_CALL_API_METHOD(ret, aDrive.Format(pos, length));
	while( ret == KErrNotReady && --attempt)
		{
		User::After(1000000);
		ret= aDrive.Format(pos, length);
		}	
	test(attempt);
	test_Equal(KErrNone, ret);

	test.Printf(_L("End of TestFormatRelatedMethods)...\n"));
	}

void RestoreDriveState(void)
	{
	TBuf<3> bfDrv;

	const TText KDrvLtr = 'A' + gFsDriveNumber;

	bfDrv.Append(KDrvLtr);
	_LIT(KBP, ":\\");
	bfDrv.Append(KBP);


	TheFs.Connect();
	RFormat fmt;
	TInt count;
	
	test(fmt.Open(TheFs, bfDrv, EHighDensity, count) == KErrNone);
	while (count > 0)
		{
		test.Printf(_L("\rfmt:%d  "), count);
		test(fmt.Next(count) == KErrNone);
		}
	test.Printf(_L("\n"));
	fmt.Close();
	
	TheFs.Close();
	}


TInt FindDataPagingDrive()
/** 
Find the drive containing a swap partition.

@return		Local drive identifier.
*/
	{
	TInt drive = KErrNotFound;
	
	test.Printf(_L("Searching for data paging drive:\n"));
	
	for(TInt i = 0; i < KMaxLocalDrives && drive < 0; ++i)
		{
		RLocalDrive	d;
		TBool change = EFalse;
		
		if(d.Connect(i, change) == KErrNone)
			{
			TLocalDriveCapsV4			dc;
			TPckg<TLocalDriveCapsV4>	capsPack(dc);
			
			if(d.Caps(capsPack) == KErrNone)
				{
				if ((dc.iMediaAtt & KMediaAttPageable) &&
					(dc.iPartitionType == KPartitionTypePagedData))
					{
					test.Printf(_L("Found swap partition on local drive %d\n"), i);
					drive = i;

					TPageDeviceInfo pageDeviceInfo;

					TPtr8 pageDeviceInfoBuf((TUint8*) &pageDeviceInfo, sizeof(pageDeviceInfo));
					pageDeviceInfoBuf.FillZ();

					TInt r = d.QueryDevice(RLocalDrive::EQueryPageDeviceInfo, pageDeviceInfoBuf);

					test.Printf(_L("EQueryPageDeviceInfo on local drive %d returned %d\n"), i, r);
					}
				}
			d.Close();
			}
		}
	return drive;
	}

TDes& GetSerialNumber(TLocalDriveCapsV5& aCaps)
	{
	static TBuf16<80> serialNumBuf;

	serialNumBuf.SetLength(0);

	for (TUint n=0; n<aCaps.iSerialNumLength; n+=16)
		{
		for (TUint m=n; m<n+16; m++)
			{
			TBuf16<3> hexBuf;
			hexBuf.Format(_L("%02X "), aCaps.iSerialNum[m]);
			serialNumBuf.Append(hexBuf);
			}
		}

	return serialNumBuf;
	}

TDes& GetSerialNumber(TMediaSerialNumber& aSerialNum)
	{
	static TBuf16<80> serialNumBuf;

	serialNumBuf.SetLength(0);

	TInt len = aSerialNum.Length();
	for (TInt n=0; n<len; n+=16)
		{
		for (TInt m=n; m<n+16; m++)
			{
			TBuf16<3> hexBuf;
			hexBuf.Format(_L("%02X "), aSerialNum[m]);
			serialNumBuf.Append(hexBuf);
			}
		}

	return serialNumBuf;
	}

TPtrC GetMediaType(TMediaType aType)
	{
	switch(aType)
		{
		case EMediaNotPresent: return _L("NotPresent");
		case EMediaUnknown: return _L("Unknown");
		case EMediaFloppy: return _L("Floppy");
		case EMediaHardDisk: return _L("HardDisk");
		case EMediaCdRom: return _L("CdRom");
		case EMediaRam: return _L("Ram");
		case EMediaFlash: return _L("Flash");
		case EMediaRom: return _L("Rom");
		case EMediaRemote: return _L("Remote");
		case EMediaNANDFlash: return _L("NANDFlash");
		case EMediaRotatingMedia : return _L("RotatingMedia ");
		default:return _L("Unrecognised");
		}
	}

TPtrC GetFileSystemId(TUint aFileSystemId)
	{
	switch(aFileSystemId)
		{
		case KDriveFileSysFAT: return _L("FAT");
		case KDriveFileSysROM: return _L("ROM");
		case KDriveFileSysLFFS: return _L("LFFS");
		case KDriveFileSysROFS: return _L("ROFS");
		case KDriveFileNone: return _L("None");
		default:return _L("Unrecognised");
		}
	}



// Find a drive which contains the swap partition; if this succeeds, find and return the FAT drive on the same media.
// This isn't fool-proof as it works by comparing media types/drive attributes/media attributes/serial numbers
TInt FindFatDriveOnDataPagingMedia()
	{
	TInt dataPagingDrive = FindDataPagingDrive();
	if (dataPagingDrive == KErrNotFound)
		return KErrNotFound;

	TInt fatDriveNumber = KErrNotFound;
		
	test.Printf(_L("Finding Fat drive on datapaging media...\n"));
	
	RLocalDrive	dpDrive;
	TBool change = EFalse;

	TInt r = dpDrive.Connect(dataPagingDrive, change);
	test(r == KErrNone);
	TLocalDriveCapsV5 dpDriveCaps;
	TPckg<TLocalDriveCapsV5> capsPack(dpDriveCaps);
	r = dpDrive.Caps(capsPack);
	test(r == KErrNone);
	TPtrC8 dpDriveSerialNum(dpDriveCaps.iSerialNum, dpDriveCaps.iSerialNumLength);
	dpDrive.Close();

	TPtrC mediaType = GetMediaType(dpDriveCaps.iType);
	TPtrC fileSystemId = GetFileSystemId(dpDriveCaps.iFileSystemId);
	test.Printf(_L("Swap Drive %2d Type %S DriveAtt 0x%x MediaAtt 0x%x FileSysId %S SerialNum %S\n"), 
		dataPagingDrive, &mediaType, dpDriveCaps.iDriveAtt, dpDriveCaps.iMediaAtt, &fileSystemId, &GetSerialNumber(dpDriveCaps));

	// swap partition should be hidden 
	test (dpDriveCaps.iDriveAtt & KDriveAttHidden);

	// search for a FAT drive on the same media by searching for a drive which has
	// 'similar' drive & media attributes as the the swap drive

	dpDriveCaps.iDriveAtt&= KDriveAttMask;
	dpDriveCaps.iMediaAtt&= KMediaAttMask;

	for (TInt i = 0; i < KMaxLocalDrives /*&& fatDriveNumber == KErrNotFound*/; ++i)
		{
		RLocalDrive	d;
		TBool change = EFalse;
		
		if(d.Connect(i, change) == KErrNone)
			{
			TLocalDriveCapsV5			caps;
			TPckg<TLocalDriveCapsV5>	capsPack(caps);

			r = d.Caps(capsPack);
			if (r != KErrNone)
				continue;

			TPtrC8 localSerialNum(caps.iSerialNum, caps.iSerialNumLength);
			TPtrC mediaType = GetMediaType(caps.iType);
			TPtrC fileSystemId = GetFileSystemId(caps.iFileSystemId);
			test.Printf(_L("Drive %2d Type %S DriveAtt 0x%x MediaAtt 0x%x FileSysId %S SerialNum %S\n"), 
				i, &mediaType, caps.iDriveAtt, caps.iMediaAtt, &fileSystemId, &GetSerialNumber(caps));

			// Turn off bits which may be different
			caps.iDriveAtt&= KDriveAttMask;
			caps.iMediaAtt&= KMediaAttMask;

			if ((caps.iType == dpDriveCaps.iType) &&
				(caps.iDriveAtt == dpDriveCaps.iDriveAtt) && 
				(caps.iMediaAtt == dpDriveCaps.iMediaAtt) && 
				(localSerialNum.Compare(dpDriveSerialNum) == 0) &&
				(caps.iFileSystemId == KDriveFileSysFAT))
				{
				if (fatDriveNumber == KErrNotFound)
					fatDriveNumber = i;
				}
			d.Close();
			}
		}


	return fatDriveNumber;
	}


// Find and return the File Server drive number (0-25) corresponing to the passed local drive number
// This isn't fool-proof as it works by comparing media types/drive attributes/media attributes/serial numbers
TInt FindFsDriveNumber(TInt aLocalDriveNumber)
	{
	TInt fsDriveNumber = KErrNotFound;

	RLocalDrive	dpDrive;
	TBool change = EFalse;

	TInt r = dpDrive.Connect(aLocalDriveNumber, change);
	test(r == KErrNone);
	TLocalDriveCapsV5 dpDriveCaps;
	TPckg<TLocalDriveCapsV5> capsPack(dpDriveCaps);
	r = dpDrive.Caps(capsPack);
	test(r == KErrNone);
	TPtrC8 dpDriveSerialNum(dpDriveCaps.iSerialNum, dpDriveCaps.iSerialNumLength);
	dpDrive.Close();

	dpDriveCaps.iDriveAtt&= KDriveAttMask;
	dpDriveCaps.iMediaAtt&= KMediaAttMask;

	RFs fs;
	r = fs.Connect();
	test(r == KErrNone);

	TDriveInfo di;

	for (TInt n=0; n<KMaxDrives /* && fsDriveNumber == KErrNotFound*/; n++)
		{
		r = fs.Drive(di, n);

		TMediaSerialNumber serialNum;
		fs.GetMediaSerialNumber(serialNum, n);

		TFSName fsName;
		fs.FileSystemName(fsName, n);

		if (r != KErrNone )
			continue;

		TPtrC mediaType = GetMediaType(di.iType);
		test.Printf(_L("Drive %C Type %S DriveAtt 0x%x MediaAtt 0x%x FileSysId %S SerialNum %S\n"), 
			'A' + n, &mediaType, di.iDriveAtt, di.iMediaAtt, &fsName, &GetSerialNumber(serialNum));

		di.iDriveAtt&= KDriveAttMask;
		di.iMediaAtt&= KMediaAttMask;

		if ((di.iType == dpDriveCaps.iType) &&
			(di.iDriveAtt == dpDriveCaps.iDriveAtt) && 
			(di.iMediaAtt == dpDriveCaps.iMediaAtt) && 
			(serialNum.Compare(dpDriveSerialNum) == 0))
			{
			if (fsDriveNumber == KErrNotFound)
				fsDriveNumber = n;
			}
		}

	fs.Close();

	return fsDriveNumber;
	}

TInt E32Main()
	{
	
	// To use in command line
   	TBool callPasswordRelated = EFalse;

    TBuf<256> cmdline;
	User::CommandLine(cmdline);
	TLex lex(cmdline);

	FOREVER
		{
		TPtrC token=lex.NextToken();
		if(token.Length() != 0)
			{
			if (token == _L("-p"))
				{
				callPasswordRelated = ETrue;			
				}
			else
				test.Printf(_L("Unknown argument '%S' was ignored.\n"), &token);
			}
		else
			break;
		
		}

	test.Title();
	TInt r;

	test.Start(_L("Verify the global and this process's data paging attributes"));
	test_KErrNone(GetGlobalPolicies());

	if (IsDataPagingSupported())
		{
		test.Printf(_L("Data paging supported\n"));
		}
	else
		{// The system doesn't support data paging so this process shouldn't be
		// data paged.
		test.Printf(_L("Data paging not supported\n"));
		test_Equal(EFalse, gProcessPaged);
		test.End();
		return 0;
		}

	r = UserHal::PageSizeInBytes(gPageSize);
	test_KErrNone(r);

	TInt fatDriveNumber = FindFatDriveOnDataPagingMedia();
	if (fatDriveNumber == KErrNotFound)
		{
		test.Printf(_L("Could not find FAT partition on data paging media\n"));
		test(0);
		}
	gFsDriveNumber = FindFsDriveNumber(fatDriveNumber);
	if (gFsDriveNumber == KErrNotFound)
		{
		test.Printf(_L("Could not File Server drive\n"));
		test(0);
		}

	test.Printf(_L("Found FAT drive on %C: (local drive #%d) on data paging media\n"), 'A'+gFsDriveNumber, fatDriveNumber);

//	User::SetDebugMask(0x10000000);		//KMMU2
//	User::SetDebugMask(0x40000000, 1);	//KPAGING
	
	test.Next(_L("Create a paged chunk"));
	CreatePagedChunk(KChunkSizeInPages, KClearValue);

	test.Next(_L("Chunk created, declare variables"));
	
	__DECLARE_VAR_IN_CHUNK(TBusLocalDrive, &drive)
	TInt driveSize = TestDriveConnectAndCaps(drive, fatDriveNumber);
	
	TestDriveSizeRelatedMethods(drive, 0x00001000, driveSize);
	
	TestWriteReadRelatedMethods(drive);
	
	TestFormatRelatedMethods(drive, driveSize);
	
	if(callPasswordRelated)
		{
		TestPasswordRelatedMethods(drive);	
		}
	
	//Disconnect drive
	test.Next(_L("call aDrive.Disconnect()..."));		
	DPTest::FlushCache();
	drive.Disconnect();
		
	gMyChunk.Close();
	
	RestoreDriveState();
	
	test.End();
	
	User::SetDebugMask(0x00000000);		// No debug info
	User::SetDebugMask(0x00000000, 1);	//No KPAGING
	return 0;
	}
