kerneltest/f32test/demandpaging/t_clamp.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 8 538db54a451d
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2006-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:
// f32test\demandpaging\t_clamp.cpp
// Test suite for file clamping, file clamping is used to prevent files
// (exes or dlls) from being deleted whilst in use.
// 002 GetDriveLetters()
// 003 Test1() Basic clamp operation
// 004 Test2() Invalid clamp requests
// 005 Test3() Denied FS requests when file(s) are clamped
// 006 Test3Operations() Test other RFile, RFs operations
// 007 Test3Operations() Increase number of clamps to MY_N
// 008 Test3Operations() Decrease number of clamps by MY_M
// 009 Test3Operations() Increase number of clamps by MY_M
// 010 TestDeferredDismount() Open and clamp file, register for dismount 
// notification, then issue dismount instruction.
// 011 Test4() Clamp tests for non-writable file system
// 012 Test5() Clamp requests on non-clamping file systems
// 
//

//! @SYMTestCaseID			KBASE-T_CLAMP-0328
//! @SYMTestType			UT
//! @SYMPREQ				PREQ1110
//! @SYMTestCaseDesc		Demand Paging File Clamp tests
//! @SYMTestActions			001 Starting T_CLAMP
//! @SYMTestExpectedResults All tests should pass.
//! @SYMTestPriority        High
//! @SYMTestStatus          Implemented

#define __E32TEST_EXTENSION__

#include <e32test.h>
RTest test(_L("T_CLAMP"));

#if defined(_DEBUG) || defined(_DEBUG_RELEASE)

#include <f32file.h>
#include <f32dbg.h>
#include <e32ldr_private.h>
RFs TheFs;

_LIT(KFATName,"FAT");
//_LIT(KFAT32Name,"FAT32");
_LIT(KROFSName,"ROFS");
_LIT(KLFFSName,"LFFS");
_LIT(KCOMPName,"COMPOSITE"); // Z: name if Composite File System
//#ifdef __WINS__
//_LIT(KROMName,"WIN32");	// Clamping is not supported for non-composite filing system on Z:
//#else
_LIT(KROMName,"ROM");		 // Z: name if ROMFS (on hardware, not emulator)
//#endif

TChar NandFatDrv='?';
TChar RofsDrv='?';
TChar LffsDrv='?';
TChar CompDrv='?';


LOCAL_C void Test1()
	{
// Basic clamp operation
	test.Next(_L("T_Clamp - Test1()"));

	TBuf<256> fileName;	
	TBuf<256> buf(_L("buffer for file used"));

	fileName = _L("clampFile.tst");
	RFile testFile;
	TInt r=testFile.Replace(TheFs,fileName,EFileWrite);
	test(r==KErrNone);
	TPtrC8 pBuf((TUint8*)&buf);
	testFile.Write(pBuf);
	testFile.Flush();

	// Clamp file
	RFileClamp handle;
	r=handle.Clamp(testFile);
	test(r==KErrNone);
	TInt64 storedCookie_0=handle.iCookie[0];
	TInt64 storedCookie_1=handle.iCookie[1];

	// Try to clamp previously-clamped file
	RFileClamp handle1;
	r=handle1.Clamp(testFile);
	test(r==KErrNone);

	// Unclamp file
	r=handle.Close(TheFs);
	test (r==KErrNone);
	// Check cookie content has been re-initialised
	test((0==handle.iCookie[0])&&(0==handle.iCookie[1]));

	// Try to unclamp a file that is not clamped
	handle.iCookie[0]=storedCookie_0;
	handle.iCookie[1]=storedCookie_1;
	r=handle.Close(TheFs);
	test (r==KErrNotFound);

	// Check that attempting to unclamp with a zero-content cookie
	// yields no error
	handle.iCookie[0]=0;
	handle.iCookie[1]=0;
	r=handle.Close(TheFs);
	test (r==KErrNone);

	// Clamp the file (again)
	r=handle.Clamp(testFile);
	test(r==KErrNone);

	// Create and clamp a second file ...
	fileName = _L("clampFile2.tst");
	RFile testFile2;
	r=testFile2.Replace(TheFs,fileName,EFileWrite);
	test(r==KErrNone);
	buf=_L("buffer for file 2");
	testFile2.Write(pBuf);
	testFile2.Flush();
	RFileClamp handle2;
	r=handle2.Clamp(testFile2);
	test(r==KErrNone);

	// Create and clamp a third file ...
	RFileClamp handle3;
	fileName = _L("clampFile3.tst");
	RFile testFile3;
	r=testFile3.Replace(TheFs,fileName,EFileWrite);
	test(r==KErrNone);
	buf=_L("buffer for file 3");
	testFile3.Write(pBuf);
	testFile3.Flush();
	r=handle3.Clamp(testFile3);
	test(r==KErrNone);

	// Test can unclamp then reclamp first file
	// then repeat for the third file
	r=handle.Close(TheFs);
	test (r==KErrNone);
	r=handle.Clamp(testFile);
	test(r==KErrNone);
	r=handle3.Close(TheFs);
	test (r==KErrNone);
	r=handle3.Clamp(testFile3);
	test(r==KErrNone);

	// Tidy up
	r=handle.Close(TheFs);
	test (r==KErrNone);
	r=handle1.Close(TheFs);
	test (r==KErrNone);
	testFile.Close();
	r=TheFs.Delete(_L("clampFile.tst"));
	test (r==KErrNone);

	r=handle2.Close(TheFs);
	test (r==KErrNone);
	testFile2.Close();
	r=TheFs.Delete(_L("clampFile2.tst"));
	test (r==KErrNone);

	r=handle3.Close(TheFs);
	test (r==KErrNone);
	testFile3.Close();
	r=TheFs.Delete(_L("clampFile3.tst"));
	test (r==KErrNone);
	}


LOCAL_C void Test2()
	{
// Invalid clamp requests
	test.Next(_L("T_Clamp - Test2()"));
	
	// Test attempt to clamp empty file is rejected
	RFileClamp handle4;
	TBuf<256> file4Name;	
	file4Name = _L("clampFile4.tst");
	RFile testFile4;
	TInt r=testFile4.Replace(TheFs,file4Name,EFileWrite);
	test(r==KErrNone);
	r=handle4.Clamp(testFile4);
	test(r==KErrEof);

	// Preparation for next test - create a valid clamp handle
	TBuf<256> buf4(_L("buffer for file 4"));
	TPtrC8 pBuf4((TUint8*)&buf4);
	testFile4.Write(pBuf4);
	testFile4.Flush();
	r=handle4.Clamp(testFile4);
	test(r==KErrNone);

	// Try to unclamp non-existant file
	RFileClamp handle5;
	memcpy((TAny*)&handle5,(TAny*)&handle4,sizeof(RFileClamp));
	handle5.iCookie[0] = MAKE_TINT64(-1,-1); // iCookie[0] holds the unique ID
	r=handle5.Close(TheFs);
	test (r==KErrNotFound);

	// Tidy up
	r=handle4.Close(TheFs);
	test (r==KErrNone);
	testFile4.Close();
	r=TheFs.Delete(_L("clampFile4.tst"));
	test (r==KErrNone);
	}



LOCAL_C void TestDeferredDismount(TDesC& aRoot, TDesC& aFileName, RFileClamp* handlePtr)
	{
	// Open and clamp file, register for dismount notification, then issue 
	// dismount instruction.
	// Since there are no other clients registered for dismount notification,
	// this would normally lead too dismount being instigated. However, since
	// the file is clamped, dismount should be deferred
	test.Next(_L("T_Clamp - TestDeferredDismount()"));

	// File system details required for clean-up
	const TInt KMaxFileSystemNameLength=100; // Arbitrary length
	const TInt KMaxFileSystemExtNameLength=100; // Arbitrary length
	TBuf<KMaxFileSystemNameLength> fsName;
	TBuf<KMaxFileSystemExtNameLength> fsExtName_0;
	TBuf<KMaxFileSystemExtNameLength> fsExtName_1;
	TBool fsExt0Present=EFalse;
	TBool fsExt1Present=EFalse;
	TInt driveNo, r;
	r=TheFs.CharToDrive(aRoot[0], driveNo);
	test(r==KErrNone);
	r=TheFs.FileSystemName(fsName, driveNo);
	test(r==KErrNone);
	r=TheFs.ExtensionName(fsExtName_0,driveNo,0);
	if(r==KErrNone)
		fsExt0Present=ETrue;
	r=TheFs.ExtensionName(fsExtName_1,driveNo,1);
	if(r==KErrNone)
		fsExt1Present=ETrue;

	// Create a file & write to it so that we can test whether dismounting works correctly with dirty data
	TDriveInfo driveInfo;
	test(TheFs.Drive(driveInfo, driveNo) == KErrNone);
	TFileName dirtyFileName(_L("dirtyFile.tst"));
	RFile dirtyFile;
	if (!(driveInfo.iMediaAtt & KMediaAttWriteProtected))
		{
		r=dirtyFile.Replace(TheFs, dirtyFileName, EFileWrite);
		test(r==KErrNone);
		r=dirtyFile.Write(_L8("My name is Michael Caine"));
		test(r==KErrNone);
		}


	RFile testFile;
	r=testFile.Open(TheFs,aFileName,EFileRead);
	test(r==KErrNone);
	r=handlePtr->Clamp(testFile);
	test(r==KErrNone);
	testFile.Close();

	TRequestStatus clientNotify=KErrNone;
	TRequestStatus clientDismount=KErrNone;
	TheFs.NotifyDismount(driveNo, clientNotify); // Register for notification
	test(clientNotify == KRequestPending);
	
	TheFs.NotifyDismount(driveNo, clientDismount, EFsDismountNotifyClients);
	test(clientDismount == KRequestPending);
	User::WaitForRequest(clientNotify);
	test(clientNotify == KErrNone);

	r=TheFs.AllowDismount(driveNo);	// Respond to dismount notification
	test(r == KErrNone);
	test(clientDismount == KRequestPending); // Dismount is deferred

	//
	// Now unclamp the file, and check that the deferred dismount is performed.
	r=handlePtr->Close(TheFs);
	test(r==KErrNone);
	User::WaitForRequest(clientDismount);
	test(clientDismount == KErrNone);	

	// Try to write to the opened file: this should return KErrNotReady as there is no drive thread
	if (!(driveInfo.iMediaAtt & KMediaAttWriteProtected))
		{
		r=dirtyFile.Write(_L8("My name isn't really Michael Caine"));
		test(r==KErrNotReady);
		}

	// Re-mount the file system
	if(fsExt0Present)
		{
		r=TheFs.MountFileSystem(fsName,fsExtName_0,driveNo);
		test(r==KErrNone);
		}
	else if(fsExt1Present) // untested !
		{
		r=TheFs.MountFileSystem(fsName,fsExtName_1,driveNo);
		test(r==KErrNone);
		}
	else 
		{
		r=TheFs.MountFileSystem(fsName,driveNo);
		test_KErrNone(r);
		}

	// create some more dirty data to verify that the file server can cope with the drive thread 
	// having gone & come back again
	if (!(driveInfo.iMediaAtt & KMediaAttWriteProtected))
		{
		r=dirtyFile.Write(_L8("My name is Michael Phelps and I'm a fish."));
		test(r==KErrDisMounted);

		dirtyFile.Close();
		r = TheFs.Delete(dirtyFileName);
		test(r == KErrNone);
		}

	// Issue a EFsDismountNotifyClients with no clients but with files clamped
	// & verify that the dismount request completes when clamps are removed
	r=testFile.Open(TheFs,aFileName,EFileRead);
	test(r==KErrNone);
	r=handlePtr->Clamp(testFile);
	test(r==KErrNone);
	testFile.Close();
	TheFs.NotifyDismount(driveNo, clientDismount, EFsDismountNotifyClients);
	
	test(clientDismount == KRequestPending);
	r=handlePtr->Close(TheFs);
	test(r==KErrNone);
	User::WaitForRequest(clientDismount);
	test(clientDismount == KErrNone);	
	// Re-mount the file system again
	if(fsExt0Present)
		{
		r=TheFs.MountFileSystem(fsName,fsExtName_0,driveNo);
		test(r==KErrNone);
		}
	else if(fsExt1Present) // untested !
		{
		r=TheFs.MountFileSystem(fsName,fsExtName_1,driveNo);
		test(r==KErrNone);
		}
	else 
		{
		r=TheFs.MountFileSystem(fsName,driveNo);
		test_KErrNone(r);
		}


	// Issue a EFsDismountForceDismount with no clients but with files clamped
	// & verify that the dismount request completes when clamps are removed
	r=testFile.Open(TheFs,aFileName,EFileRead);
	test(r==KErrNone);
	r=handlePtr->Clamp(testFile);
	test(r==KErrNone);
	testFile.Close();
	TheFs.NotifyDismount(driveNo, clientDismount, EFsDismountForceDismount);
	
	test(clientDismount == KRequestPending);
	r=handlePtr->Close(TheFs);
	test(r==KErrNone);
	User::WaitForRequest(clientDismount);
	test(clientDismount == KErrNone);	
	// Re-mount the file system again
	if(fsExt0Present)
		{
		r=TheFs.MountFileSystem(fsName,fsExtName_0,driveNo);
		test(r==KErrNone);
		}
	else if(fsExt1Present) // untested !
		{
		r=TheFs.MountFileSystem(fsName,fsExtName_1,driveNo);
		test(r==KErrNone);
		}
	else 
		{
		r=TheFs.MountFileSystem(fsName,driveNo);
		test_KErrNone(r);
		}

	}



LOCAL_C void Test3Operations(TDesC& aRoot, TDesC& aFileName)
	{
	test.Next(_L("T_Clamp - Test3Operations()"));
	// RFormat::Open
#ifdef __WINS__
	if (User::UpperCase(aRoot[0]) != 'C')
#endif
		{
		TBuf<4> driveBuf=_L("?:\\");
		driveBuf[0] = aRoot[0];
		RFormat format;
		TInt count;
		TInt r=format.Open(TheFs,driveBuf,EFullFormat,count);
		test(r==KErrInUse);
		format.Close();
		}

	// Dismount: synchronous requests
	// RFs::DismountFileSystem, RFs::SwapFileSystem
	const TInt KMaxFileSystemNameLength=100; // Arbitrary length
	TBuf<KMaxFileSystemNameLength> fileSysName;
	TInt driveNo, r;
	r=TheFs.CharToDrive(aRoot[0], driveNo);
	test(r==KErrNone);
	r=TheFs.FileSystemName(fileSysName,driveNo);
	test(r==KErrNone);

	r=TheFs.DismountFileSystem(fileSysName,driveNo);
	test(r==KErrInUse);
	
	r=TheFs.SwapFileSystem(fileSysName,fileSysName,driveNo);
	test(r==KErrInUse);

#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
	// The cancellation of deferred dismounts requires controlIO 
	// functionality available in debug versions of the code.

	// Dismount: asynchronous requests
	// RFs::NotifyDismount, RFs::AllowDismount
	const TInt KNumClients = 5;
    RFs clientFs[KNumClients];
	TRequestStatus clientNotify[KNumClients];
	TRequestStatus clientComplete;
	TInt i=0;
	for(i=0; i< KNumClients; i++)
		{
   		r=clientFs[i].Connect();
		test(r==KErrNone);
		}
	// Cancel any deferred dismount in preparation for the next test
	r=TheFs.ControlIo(driveNo,KControlIoCancelDeferredDismount);
	test(r==KErrNone);	

	// Use case 1: Orderly dismount
	// All clients register for dismount notification
	for(i=0; i< KNumClients; i++)
		{
		clientNotify[i] = KErrNone;
   		clientFs[i].NotifyDismount(driveNo, clientNotify[i]);
		test(clientNotify[i] == KRequestPending);
		}
	// First client notifies intent to dismount
	clientComplete = KErrNone;
   	clientFs[0].NotifyDismount(driveNo, clientComplete, EFsDismountNotifyClients);
	test(clientComplete == KRequestPending);
	// Check all clients have received the notification
	for(i=0; i< KNumClients; i++)
		{
		test(clientNotify[i] == KErrNone);
		}
	// All clients invoke AllowDismount
	for(i=0; i< KNumClients; i++)
		{
		r=clientFs[i].AllowDismount(driveNo);
		test(r==KErrNone);
		}
	// Dismount is deferred
	test(clientComplete == KRequestPending);


	// Cancel the deferred dismount in preparation for the next test
	clientFs[0].NotifyDismountCancel(clientComplete);
	test(clientComplete == KErrCancel);
	r=TheFs.ControlIo(driveNo,KControlIoCancelDeferredDismount);
	test(r==KErrNone);	
	clientComplete=KErrNone; // Re-initialise the TRequestStatus


	// Use case 2: Forced dismount
	// All clients register for dismount notification
	for(i=0; i< KNumClients; i++)
		{
   		clientFs[i].NotifyDismount(driveNo, clientNotify[i]);
		test(clientNotify[i] == KRequestPending);
		}
	// First client notifies intent to dismount
   	clientFs[0].NotifyDismount(driveNo, clientComplete, EFsDismountNotifyClients);
	test(clientComplete == KRequestPending);
	// Check all clients have received the notification
	for(i=0; i< KNumClients; i++)
		{
		test(clientNotify[i] == KErrNone);
		}
	// Not all other clients invoke AllowDismount
	for(i=0; i< KNumClients-1; i++)
		{
		clientFs[i].AllowDismount(driveNo);
		}
	// First client attempts forced dismount
	test(clientComplete == KRequestPending);
   	clientFs[0].NotifyDismount(driveNo, clientComplete, EFsDismountForceDismount);
	// Dismount is deferred
	test(clientComplete == KRequestPending);

	// Cancel the deferred dismount in preparation for the next test
	// Also cancel the 'un-Allowed' notification request
	clientFs[0].NotifyDismountCancel(clientComplete);
	test(clientComplete == KErrCancel);
	r=TheFs.ControlIo(driveNo,KControlIoCancelDeferredDismount);
	test(r==KErrNone);	
	clientComplete=KErrNone; // Re-initialise the TRequestStatus
#endif

	// RFile::Open with EFileWrite
	RFile testFile;
	r=testFile.Open(TheFs,aFileName,EFileWrite|EFileShareReadersOrWriters);
	test(r==KErrInUse);

	// RFile::Replace
	RFile testFile2;
	r=testFile2.Replace(TheFs,aFileName,EFileRead);
	test(r==KErrInUse);
	testFile2.Close();

	// RFile::Set - this should not be prevented by clamping
	r=testFile.Open(TheFs,aFileName,EFileRead|EFileShareAny);
	test(r == KErrNone);

	TTime origTime;
	TUint origAtt;
	r=testFile.Att(origAtt);
	test(r==KErrNone);
	r=testFile.Modified(origTime);
	test(r==KErrNone);

	TTime time;									// Arbitrary value
	TUint setMask=0xA5A5&~KEntryAttReadOnly;	// Not read-only, otherwise arbitrary value
	TUint clearMask=0x5A5A & KEntryAttReadOnly;	// Not read-only, otherwise arbitrary value
	r=testFile.Set(time,setMask,clearMask);
	test(r==KErrNone);

	r=testFile.Set(origTime,origAtt,~origAtt); // restore original values
	test(r==KErrNone);
	testFile.Close();

	// RFs::Rename - this should not be prevented by clamping
	r=TheFs.Rename(aFileName,_L("aDummyName"));
	test(r==KErrNone);
	r=TheFs.Rename(_L("aDummyName"),aFileName); // restore original name
	test(r==KErrNone);

	// RFs::Replace
	r=TheFs.Replace(aFileName,_L("aDummyName"));
	test(r==KErrInUse);

	// RFs::SetEntry - this should not be prevented by clamping
	r=TheFs.SetEntry(aFileName,time,setMask,clearMask);
	test(r==KErrNone);
	r=TheFs.SetEntry(aFileName,origTime,origAtt,~origAtt); // restore original values
	test(r==KErrNone);

	// RFs::Delete
	r=TheFs.Delete(aFileName);
	test(r==KErrInUse);

	// RRawDisk::Open (*** no longer required ***)
	}

LOCAL_C void Test3(TDesC& aRoot)
	{
// Denied FS requests when file(s) are clamped.
	test.Next(_L("T_Clamp - Test3()"));

// Clamping is reference counted, so we need a test to check that
// a file clamped N times cannot be modified until it has been unclamped N times.
// Should also check
// - Clamp N times
// - Unclamp M times (M<N)
// - Clamp M times.
// - Unclamp N times

#define MY_N 16
#define MY_M 12

	// Create a file for use
	TBuf<256> fileName;	
	TBuf<256> buf(_L("buffer for file used"));
	fileName = _L("clampFile.tst");
	RFile testFile;
	TInt r=testFile.Replace(TheFs,fileName,EFileWrite);
	test(r==KErrNone);
	TPtrC8 pBuf((TUint8*)&buf);
	testFile.Write(pBuf);
	testFile.Flush();
	// Close file,then re-open (to support clamping) in sharable mode
	// (to allow testing of RFile::Open with EFileWrite)
	testFile.Close();
	r=testFile.Open(TheFs,fileName,EFileWrite|EFileShareReadersOrWriters);
	test(r==KErrNone);
	// Show, prior to clamping, that the file can be opened with EFileWrite
	RFile testFile2;
	r=testFile2.Open(TheFs,fileName,EFileWrite|EFileShareReadersOrWriters);
	test(r==KErrNone);
	// Close the second RFile instance
	testFile2.Close();

	// Clamp and unclamp a number of times, and invoke the
	// operations to test
	RFileClamp myHandles[MY_N];
	RFileClamp *handlePtr = myHandles;
	TInt i = 0;

	// Clamp once
	r=handlePtr->Clamp(testFile);
	test(r==KErrNone);
	i++;

	// RFile::SetAtt - this should not be prevented by clamping
	TTime origTime;
	TUint origAtt;
	r=testFile.Att(origAtt);
	test(r==KErrNone);
	r=testFile.Modified(origTime);
	test(r==KErrNone);
	TTime time;									// Arbitrary value
	TUint setMask=0xA5A5&~KEntryAttReadOnly;	// Not read-only, otherwise arbitrary value
	TUint clearMask=0x5A5A & KEntryAttReadOnly;	// Not read-only, otherwise arbitrary value
	r=testFile.Att(origAtt);
	test(r==KErrNone);
	r=testFile.SetAtt(setMask,clearMask);
	test(r==KErrNone);
	r=testFile.Set(origTime,origAtt,~origAtt); // restore original values
	test(r==KErrNone);

	// RFile::SetModified - this should not be prevented by clamping
	r=testFile.Modified(origTime);
	test(r==KErrNone);
	r=testFile.SetModified(time);
	test(r==KErrNone);
	r=testFile.SetModified(origTime); // restore original value
	test(r==KErrNone);

	// RFile::Rename - this should not be prevented by clamping
	// Need file to be opened in EFileShareExclusive sharing mode,
	// so close, unclamp, re-open appropriately and re-clamp
	testFile.Close();
	r=handlePtr->Close(TheFs);
	test(r==KErrNone);
	i--;
	r=testFile.Open(TheFs,fileName,EFileWrite|EFileShareExclusive);
	test(r==KErrNone);
	r=handlePtr->Clamp(testFile);
	test(r==KErrNone);
	i++;
	r=testFile.Rename(_L("aDummyName"));
	test(r==KErrNone);
	r=testFile.Rename(fileName);
	test(r==KErrNone);

	// RFile::SetSize
	r=testFile.SetSize(1000); // Arbitrary value
	test(r==KErrInUse);

	// Test other RFile, RFs operations
	testFile.Close();
	Test3Operations(aRoot,fileName);

	// Increase number of clamps to MY_N
	r=testFile.Open(TheFs,fileName,EFileRead);
	test(r==KErrNone);
	for(; i < MY_N; i++)
		{
		handlePtr++;
		r=handlePtr->Clamp(testFile);
		test(r==KErrNone);
		}
	testFile.Close();
	Test3Operations(aRoot,fileName);

	// Decrease number of clamps by MY_M
	for(;i > (MY_N - MY_M); i--)
		{
		r=handlePtr->Close(TheFs);
		test(r==KErrNone);
		if(handlePtr!=myHandles)
			handlePtr--;
		else
			break;
		}
	Test3Operations(aRoot,fileName);

	// Increase number of clamps by MY_M
	r=testFile.Open(TheFs,fileName,EFileRead);
	test(r == KErrNone);
	TInt j=0;
	for(;j < MY_M; j++)
		{
		handlePtr++;
		r=handlePtr->Clamp(testFile);
		test(r==KErrNone);
		i++;
		}
	testFile.Close();
	Test3Operations(aRoot,fileName);

	// Decrease number of clamps by MY_N
	for(;i > 0; i--)
		{
		r=handlePtr->Close(TheFs);
		test(r==KErrNone);
		if(handlePtr!=myHandles)
			handlePtr--;
		else
			break;
		}

	// Test deferred dismount - use next free handle
	TestDeferredDismount(aRoot,fileName,handlePtr);

	// Re-create the test directory
	r=TheFs.MkDirAll(aRoot);
	test(r==KErrNone || r== KErrAlreadyExists);
	TheFs.SetSessionPath(aRoot);

	// No clamps remain - prove RFile::Open with EFileWrite
	r=testFile2.Open(TheFs,fileName,EFileWrite|EFileShareReadersOrWriters);
	test(r==KErrNone);
	testFile2.Close();

	// No clamps remain - prove that file can now be deleted
	r=TheFs.Delete(_L("clampFile.tst"));
	test (r==KErrNone);
	}


LOCAL_C void Test4(TDesC& aRoot)
	{
// Clamp tests for non-writable file system
	test.Next(_L("T_Clamp - Test4()"));

	// Tests are limited to clamp, unclamp and denied requests
	// when clamps are present.
	TBuf<256> pathName;	
#ifdef __WINS__
	if((aRoot[0]=='Z')||(aRoot[0]=='z'))
		pathName=_L("clean.txt");
	else
		pathName=_L("root.txt");
#else
	if((aRoot[0]=='Z')||(aRoot[0]=='z'))
		pathName=_L("UnicodeData.txt");
	else
		pathName=_L("\\Test\\clamp.txt");	// For (non-composite) ROFS drive
#endif
	RFile testFile;
	TInt r=testFile.Open(TheFs, pathName, EFileRead);
	test(r==KErrNone);

	// Clamp file
	RFileClamp handle;
	r=handle.Clamp(testFile);
	test(r==KErrNone);
	TInt64 storedCookie_0=handle.iCookie[0];
	TInt64 storedCookie_1=handle.iCookie[1];

	// Try to clamp previously-clamped file
	RFileClamp handle1;
	r=handle1.Clamp(testFile);
	test(r==KErrNone);

	// Unclamp file
	r=handle.Close(TheFs);
	test (r==KErrNone);
	// Check cookie content has been re-initialised
	test((0==handle.iCookie[0])&&(0==handle.iCookie[1]));

	// Try to unclamp a file that is not clamped
	handle.iCookie[0]=storedCookie_0;
	handle.iCookie[1]=storedCookie_1;
	r=handle.Close(TheFs);
	test (r==KErrNotFound);
	// Remove remaining clamp
	r=handle1.Close(TheFs);
	test (r==KErrNone);

	testFile.Close();

	if((aRoot[0]!='Z')&&(aRoot[0]!='z'))	// Can not dismount Z:
		TestDeferredDismount(aRoot,pathName,&handle);
	}


LOCAL_C void Test5()
	{
// Clamp requests on non-clamping file systems
	test.Next(_L("T_Clamp - Test5()"));

	TBuf<256> unsuppFile;	
	unsuppFile = _L("unsuppFile.tst");
	RFile testFile;
	TInt r=testFile.Replace(TheFs,unsuppFile,EFileWrite);
	test(r==KErrNone);

	// Try to clamp a file on a file system that does
	// not support clamping
	RFileClamp handle;
	r=handle.Clamp(testFile);
	test(r==KErrNotSupported);

	// Tidy up
	testFile.Close();
	r=TheFs.Delete(_L("unsuppFile.tst"));
	test (r==KErrNone);
	}	


LOCAL_C void GetDriveLetters()
	{
// Assign the first drive that matches the required criteria
	test.Next(_L("T_Clamp - GetDriveLetters()"));

	TDriveList driveList;
	TDriveInfo driveInfo;
	TInt r=TheFs.DriveList(driveList);
	test(r==KErrNone);
	TInt drvNum;
	TBool drivesFound = EFalse;
	for(drvNum=0; (drvNum<KMaxDrives) && !drivesFound; drvNum++)
		{
		TChar drvLetter='?';
		TFileName fileSystem;
		if(!driveList[drvNum])
			continue;
		test(TheFs.Drive(driveInfo, drvNum) == KErrNone);
		test(TheFs.DriveToChar(drvNum,drvLetter) == KErrNone);
		r=TheFs.FileSystemName(fileSystem,drvNum);
		fileSystem.UpperCase();
		test((r==KErrNone)||(r==KErrNotFound));
		if (!(driveInfo.iDriveAtt & KDriveAttInternal))
			continue;
		// Check for FAT on NAND
		if(NandFatDrv=='?')
			{
			if((driveInfo.iType==EMediaNANDFlash) && (fileSystem.Compare(KFATName)==0))
				NandFatDrv=drvLetter;
			}
		// Check for ROFS
		if(RofsDrv=='?')
			{
			if((driveInfo.iType==EMediaNANDFlash) && (fileSystem.Compare(KROFSName)==0))
				RofsDrv=drvLetter;
			}
		// Check for LFFS
		if(LffsDrv=='?')
			{
			if((driveInfo.iType==EMediaFlash) && (fileSystem.Compare(KLFFSName)==0))
				LffsDrv=drvLetter;
			}
		// Check for CompFSys
		if(CompDrv=='?')
			{
			if((driveInfo.iType==EMediaRom) && ((fileSystem.Compare(KROMName)==0)||(fileSystem.Compare(KCOMPName)==0)))
				CompDrv=drvLetter;
			}
		drivesFound=((NandFatDrv!='?')&&(RofsDrv!='?')&&(LffsDrv!='?')&&(CompDrv!='?'));
		}
	if(NandFatDrv!='?')
		test((NandFatDrv!=RofsDrv)&&(NandFatDrv!=LffsDrv)&&(NandFatDrv!=CompDrv));
	if(RofsDrv!='?')
		test((RofsDrv!=LffsDrv)&&(RofsDrv!=CompDrv));
	if(LffsDrv!='?')
		test(LffsDrv!=CompDrv);

	RDebug::Printf("T_CLAMP: FAT drive=%C, ROFS drive=%C, LFFS drive=%C, ROM-COMP drive=%C \n",(TText)NandFatDrv,(TText)RofsDrv,(TText)LffsDrv,(TText)CompDrv);
	return;
	}


//
// E32Main
//

TInt E32Main()
	{
	TInt r;
	test.Title();
	test.Start(_L("Starting T_CLAMP ..."));
	test(TheFs.Connect()==KErrNone);

	GetDriveLetters();
	TBuf<256> pathName;	

	//************************************************************************
	//
	// Test on FAT (writable file system)
	//
	//************************************************************************
	if(NandFatDrv!='?')
		{
		pathName=_L("?:\\CLAMP-TST\\");	// FAT on NAND
		pathName[0]=(TText)NandFatDrv;
		r=TheFs.MkDirAll(pathName);
		test(r==KErrNone || r== KErrAlreadyExists);
		TheFs.SetSessionPath(pathName);
		test.Printf( _L("T_CLAMP: testing FAT drive on %C\n"),(TText)NandFatDrv);

		Test1();		// Basic clamp operation
		Test2();		// Invalid clamp requests
		Test3(pathName);// Denied FS requests when files are clamped

		r=TheFs.RmDir(pathName);
		test(r==KErrNone);
		}
	else
		test.Printf( _L("T_CLAMP: FAT drive not tested\n"));

	//************************************************************************
	//
	// Test on ROFS (non-writable file system) 
	//
	//************************************************************************
	if(RofsDrv!='?')
		{
		pathName=_L("?:\\");
		pathName[0]=(TText)RofsDrv;
		TheFs.SetSessionPath(pathName);
		test.Printf( _L("T_CLAMP: testing ROFS drive on %C\n"),(TText)RofsDrv);

		Test4(pathName);	// Clamp tests for non-writable file system
		}
	else
		test.Printf( _L("T_CLAMP: ROFS drive not tested\n"));

	//************************************************************************
	//
	// Test on Z: - Composite File System, or ROMFS (non-writable file system)
	//
	//************************************************************************
	if(CompDrv!='?')
		{
		pathName=_L("?:\\TEST\\");
		pathName[0]=(TText)CompDrv;
		TheFs.SetSessionPath(pathName);
		test.Printf( _L("T_CLAMP: testing Z drive (on %C)\n"),(TText)CompDrv);

		Test4(pathName);	// Clamp tests for non-writable file system
		}
	else
		test.Printf( _L("T_CLAMP: Z drive not tested\n"));

	//************************************************************************
	//
	// Test on LFFS (non-clampable file system)
	//
	//************************************************************************
	if(LffsDrv!='?')
		{
		TBuf<256> unsuppPath;	
		unsuppPath=_L("?:\\CLAMP-TST\\");
		unsuppPath[0]=(TText)LffsDrv;
		r=TheFs.MkDirAll(unsuppPath);
		test(r==KErrNone || r== KErrAlreadyExists);
		TheFs.SetSessionPath(unsuppPath);
		test.Printf( _L("T_CLAMP: testing LFFS drive on %C\n"),(TText)LffsDrv);

		Test5();		// Clamp requests on non-clamping file systems
		}
	else
		test.Printf( _L("T_CLAMP: LFFS drive not tested\n"));

	test.End();
	return 0;
	}

#else

TInt E32Main()
	{
	test.Title();
	test.Start(_L("Test does not run on UREL builds."));
	test.End();
	return 0;
	}
#endif