kerneltest/f32test/server/t_hungfs.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
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) 1998-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\server\t_hungfs.cpp
// this test will either run with a secure mmc or will simulate a
// mmc card.
// 
//


#include <f32file.h>
#include <e32test.h>
#include "t_server.h"

GLDEF_D RTest test(_L("T_HUNGFS"));
GLREF_D RFs TheFs;

LOCAL_D RFile SubFile1;
LOCAL_D TInt HungReturnCodeC;

LOCAL_D RSemaphore HungSemaphoreC;
LOCAL_D TInt HungReturnCodeNC;
LOCAL_D RSemaphore HungSemaphoreNC;

GLREF_C void Format(TInt aDrive);

LOCAL_D const TInt KControlIoLockMount=5;
LOCAL_D const TInt KControlIoClearLockMount=6;
LOCAL_D const TInt KControlIoCNotifier=7;
LOCAL_D const TInt KControlIoClearCNotifier=8;

LOCAL_D const TInt KControlIoCancelNCNotifier=KMaxTInt-1;

LOCAL_D TBool isSecureMmc;
LOCAL_D TFileName gLockedPath;
LOCAL_D TFileName gLockedBase;
LOCAL_D TInt gLockedDrive;
GLREF_D TFileName gSessionPath;
LOCAL_D TInt gSessionDrive;

TBuf8<16> KPassword8=_L8("abc");
TBuf16<8> KPassword=_L("abc");
_LIT(File1,"file1");
_LIT(File2,"file2");
_LIT(Dir1,"\\dir1\\");
_LIT(NotifyDir,"\\not\\");
_LIT(NotifyDir2,"\\abc\\");
_LIT(HungDirNC,"\\hungnc\\");
_LIT(HungDirC,"\\hungc\\");

LOCAL_D const TInt KHeapSize=0x2000;

struct SNonCriticalInfo
	{
	TBool iSameSession;
	TBool iUseRFile;
	};

LOCAL_C TInt ThreadFunctionNC(TAny* aInfo)
//
// Thread entry point to put up non-critical notifier
//
	{
	RFs fs;
	TInt r;

	TBuf8<8> mmcBuf;
	// pad out password if using lockable mmc
	if(isSecureMmc)
		{
		TUint8 pBuf[]={0x61,0x00,0x62,0x00,0x63,00};
		mmcBuf.SetLength(6);
		for(TInt i=0;i<6;++i)
			mmcBuf[i]=pBuf[i];
		}

	SNonCriticalInfo* info=NULL;
	if(aInfo!=NULL)
		info=(SNonCriticalInfo*)aInfo;

	r=fs.Connect();
	
	if(isSecureMmc)
		{
		if(info && info->iSameSession)
			r=TheFs.LockDrive(gLockedDrive,NULL,mmcBuf,EFalse);
		else
			{
			r=fs.LockDrive(gLockedDrive,NULL,mmcBuf,EFalse);
			RDebug::Print(_L("l=%d"),r);
			}
		}
	else
		{
		if(info && info->iSameSession)
			r=TheFs.ControlIo(gLockedDrive,KControlIoLockMount,KPassword8);
		else
			r=fs.ControlIo(gLockedDrive,KControlIoLockMount,KPassword8);
		}
//	UserSvr::ForceRemountMedia(ERemovableMedia0);
	User::After(300000);
	HungSemaphoreNC.Signal();

	TFileName hungDir=gLockedBase;
	hungDir+=HungDirNC;
	if(info && info->iSameSession)
		r=TheFs.RmDir(hungDir);
	else if(info && info->iSameSession && info->iUseRFile)
		{
		TBuf8<16> buf=_L8("abc");
		r=SubFile1.Write(buf);
		}
	else
		{
		r=fs.RmDir(hungDir);
		RDebug::Print(_L("rd=%d"),r);
		}
	HungReturnCodeNC=r;

	if(isSecureMmc)
		{
		r=fs.UnlockDrive(gLockedDrive,mmcBuf,EFalse);
		r=fs.ClearPassword(gLockedDrive,mmcBuf);
		}
	else
		r=fs.ControlIo(gLockedDrive,KControlIoClearLockMount,KPassword8);

	HungSemaphoreNC.Signal();

	fs.Close();

	return(KErrNone);
	}

LOCAL_C TInt ThreadFunctionC(TAny* aDrive)
//
// Thread entry point to put up a critical notifier
//
	{
	RFs fs;
	TInt r=fs.Connect();
	test(r==KErrNone);
	
	TInt drive;
#if defined(__WINS__)
	drive=EDriveY;
#else	
	drive=EDriveC;
#endif
	// can only get critcal notifer up using ControIo
	// assumes fat file system running on one of the drives named below
	r=fs.ControlIo(drive,KControlIoCNotifier);
	
	TBool isRemovable=*(TBool*)aDrive;
	TFileName hungDir=(_L("?:"));
#if defined(__WINS__)
	if(isRemovable)
		hungDir[0]=(TText)('A'+EDriveX);
	else
		hungDir[0]=(TText)('A'+EDriveY);
#else
	if(isRemovable)
		hungDir[0]=(TText)('A'+EDriveD);
	else
		hungDir[0]=(TText)('A'+EDriveC);
#endif
	hungDir+=HungDirC;
	r=fs.RmDir(hungDir);
	r=fs.MkDir(hungDir);
	HungReturnCodeC=r;

	r=fs.ControlIo(drive,KControlIoClearCNotifier);

	HungSemaphoreC.Signal();
	r=fs.RmDir(hungDir);
	fs.Close();
	return(KErrNone);
	}

LOCAL_C void PutNonCriticalNotifier(TAny* aInfo,RThread& aThread)
//
// put up a non-critical notifier on a removable media
//
	{
	TInt r=aThread.Create(_L("ThreadNC"),ThreadFunctionNC,KDefaultStackSize,KMinHeapSize,KMinHeapSize,aInfo);
	test(r==KErrNone);	
	aThread.SetPriority(EPriorityMore);
	aThread.Resume();
	HungSemaphoreNC.Wait();
	User::After(1000000);

	}

LOCAL_C void PutCriticalNotifier(TBool aBool,RThread& aThread)
//
// put up a critical notifier on the specified drive
//
	{
	TInt r=aThread.Create(_L("ThreadC"),ThreadFunctionC,KDefaultStackSize,KMinHeapSize,KMinHeapSize,&aBool);
	test(r==KErrNone);
	aThread.SetPriority(EPriorityMore);
	aThread.Resume();
	User::After(1000000);
	}

void TestNotifiers()
//
// Test non-critical notifier is cancelled when the critical notifier is put up
// Needs to be carried out on platform with password notifier which handles requests
// asynchronously and uses CAtaDisk in fat file system on c: drive ie. not internal ram
// drive
//
	{
	test.Next(_L("TestNotifiers"));
	if(isSecureMmc)
		return;
	RThread threadNC,threadC;
	PutNonCriticalNotifier(NULL,threadNC);
	PutCriticalNotifier(EFalse,threadC);
	// get rid of critical notifier
	test.Printf(_L("Press cancel on for critcal notifier\n"));
	test.Printf(_L("Press any character\n"));
	test.Getch();
	TRequestStatus deathStat;
	threadNC.Logon( deathStat );
	HungSemaphoreC.Wait();
	// test(HungReturnCodeNC==KErrAbort);
	TRequestStatus deathStat2;
	threadC.Logon(deathStat2);
	HungSemaphoreNC.Wait();
	//test(HungReturnCodeNC==KErrLocked);
	User::WaitForRequest(deathStat2);
	threadNC.Close();
	threadC.Close();
	}

void TestCriticalFunctions() 
//
// test that only a subset of functions are supported when the critical notifier is up
//
	{
	test.Next(_L("test functions supported with critical notifier"));
	// used for EFsSubClose
	RFile file;
	TInt r=file.Create(TheFs,File1,EFileShareAny|EFileWrite);
	test(r==KErrNone||KErrAlreadyExists);
	if(r==KErrAlreadyExists)
		{
		r=file.Open(TheFs,File1,EFileShareAny|EFileWrite);
		test(r==KErrNone);
		}
	TBuf8<16> buf=_L8("abcdefghijklmnop");
	r=file.Write(buf);
	test(r==KErrNone);

	r=TheFs.MkDir(NotifyDir);
	test(r==KErrNone);

	RThread thread;
	PutCriticalNotifier(ETrue,thread);

	// test functions that are supported with critical notifier
	// EFsNotifyChange
	test.Next(_L("test functions that are supported with critical notifier"));
	TRequestStatus status;
	TheFs.NotifyChange(ENotifyAll,status);
	test(status==KRequestPending);
	// EFsNotifyChangeCancel
	TheFs.NotifyChangeCancel();
	test(status==KErrCancel);
	// EFsNotifyChangeEx
	TheFs.NotifyChange(ENotifyAll,status,gSessionPath);
	test(status==KRequestPending);
	// EFsNotifyChangeCancelEx
	TheFs.NotifyChangeCancel(status);
	test(status==KErrCancel);
	// EFsSubClose
	// difficult  to test properly because this does not return an error value
	file.Close();

	// test that notifications are not completed when a critical notifier completes
	test.Next(_L("test notifications not completed"));
	TheFs.NotifyChange(ENotifyDisk,status);
	test(status==KRequestPending);
	TRequestStatus status2;
	TheFs.NotifyChange(ENotifyDir,status2,NotifyDir);
	test(status2==KRequestPending);

	// test some functions that are not supported when critcical notifier up
	// EFsFileOpen
	test.Next(_L("test functions that are not supported with critical notifier"));
	r=file.Open(TheFs,File2,EFileShareAny);
	test(r==KErrInUse);
	// EFsFileCreate
	r=file.Create(TheFs,File2,EFileShareAny);
	test(r==KErrInUse);
	// EFsMkDir
	r=TheFs.MkDir(Dir1);
	test(r==KErrInUse);
	// EFsVolume
	TVolumeInfo info;
	r=TheFs.Volume(info,gSessionDrive);
	test(r==KErrInUse);

	// get rid of critical notifier
	test.Printf(_L("Press escape on the critical notifier\n"));
	TRequestStatus deathStat;
	thread.Logon(deathStat);
	HungSemaphoreC.Wait();
	test(HungReturnCodeC==KErrAbort);
	User::WaitForRequest(deathStat);
	thread.Close();

	// test notifiers have not gone off
	test(status==KRequestPending&&status2==KRequestPending);

	// test that notification setup on  default drive has had the drive changed
	// to * since the critical notifier was up
	TFileName notDir=gLockedBase;
	notDir+=NotifyDir;
	r=TheFs.MkDir(notDir);
	test(r==KErrNone);
	test(status==KRequestPending&&status2==KErrNone);
	TheFs.NotifyChangeCancel();
	test(status==KErrCancel);
	r=TheFs.Delete(File1);
	test(r==KErrNone);
	r=TheFs.RmDir(notDir);
	test(r==KErrNone);
	r=TheFs.RmDir(NotifyDir);
	test(r==KErrNone);
	}

void TestParsingFunctions()	
//
// Test functions that use Parse* and Validate* functions with 
// non-critical notifier up
// 
	{
	test.Next(_L("TestParsingFunctions"));
	RThread thread;
	PutNonCriticalNotifier(NULL,thread);
	
	// test on same drive as notifier
	test.Next(_L("test parsing functions on same drive"));
	// Using ParseSubst
	TFileName dir=gLockedBase;
	dir+=Dir1;
	TInt r=TheFs.MkDir(dir);
	test(r==KErrInUse);
	TFileName file=gLockedPath;
	file+=File1;
	RFile f;
	r=f.Create(TheFs,file,EFileShareAny);
	test(r==KErrInUse);
	// Using ParsePathPtr0
	r=TheFs.SetSubst(gLockedPath,EDriveO);
	test(r==KErrInUse);
	// ValidateDrive
	TVolumeInfo info;
	r=TheFs.Volume(info,gLockedDrive);
	test(r==KErrInUse);

	TFileName origSessPath;
	r=TheFs.SessionPath(origSessPath);
	test(r==KErrNone);

	// test these work ok
	r=TheFs.SetSessionPath(gLockedPath);
	test(r==KErrNone);
	r=TheFs.SetSessionPath(origSessPath);
	test(r==KErrNone);

	// test on different drive from notifier - the session path
	test.Next(_L("test parsing functions on a different drive"));
	// Using ParseSubst
	r=TheFs.MkDir(Dir1);
	test(r==KErrNone);
	r=TheFs.RmDir(Dir1);
	test(r==KErrNone);
	r=f.Create(TheFs,File1,EFileShareAny);
	test(r==KErrNone);
	f.Close();
	r=TheFs.Delete(File1);
	test(r==KErrNone);
	// Using ParsePathPtr0
	r=TheFs.SetSubst(gSessionPath,EDriveO);
	test(r==KErrNone);
	r=TheFs.SetSubst(_L(""),EDriveO);
	test(r==KErrNone);
	// ValidateDrive
	r=TheFs.Volume(info,gSessionDrive);
	test(r==KErrNone);

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);

	TRequestStatus deathStat;
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();

//	test.End();
	}
	
void TestTFsFunctions()	
//
// test functions that do not use the Parse* and Validate* functions
//
	{
	test.Next(_L("TestTFsFunctions"));
	TFileName sessName,lockedName;
	TInt r=TheFs.FileSystemName(sessName,gSessionDrive);
	test(r==KErrNone);
	r=TheFs.FileSystemName(lockedName,gLockedDrive);
	test(r==KErrNone);

	RThread thread;
	PutNonCriticalNotifier(NULL,thread);

	// test functions on hung drive - should return KErrInUse
	test.Next(_L("test TFs functions on hung drive"));
	// TFsDismountFileSystem
	r=TheFs.DismountFileSystem(lockedName,gLockedDrive);
	test(r==KErrInUse);
	// TFsMountFileSystem
	r=TheFs.MountFileSystem(lockedName,gLockedDrive);
	test(r==KErrInUse);
	// TFsFileSystemName
	r=TheFs.FileSystemName(lockedName,gLockedDrive);
	test(r==KErrInUse);

	// test functions on drive other than hung drive
	test.Next(_L("test TFs functions on drive that is not hung"));
	// TFsDismountFileSystem
#if defined(__WINS__)
	// bug in TFsMountFileSystem which needs to be fixed before running on EDriveC on WINS
	if(gSessionDrive!=EDriveC)
		{
#endif
	r=TheFs.DismountFileSystem(sessName,gSessionDrive);
	test(r==KErrNone);
	// TFsMountFileSystem
	r=TheFs.MountFileSystem(sessName,gSessionDrive);
	test(r==KErrNone);
#if defined(__WINS__)
		}
#endif
	// TFsFileSystemName
	TFileName fsName;
	r=TheFs.FileSystemName(fsName,gSessionDrive);
	test(r==KErrNone);
	test(fsName==sessName);

	// test functions that fail on all drives
	test.Next(_L("test TFs functions that fail on all drives"));
	// TFsListOpenFiles
	CFileList* list=NULL;
	TOpenFileScan fileScan(TheFs);
	TRAP(r,fileScan.NextL(list));
	test(r==KErrInUse);

	// test functions that should pass on any drive
	test.Next(_L("test TFs functions that pass on all drives"));
	// TFsSetDefaultPath
	// TFsSetSessionPath
	r=TheFs.SetSessionPath(gLockedPath);
	test(r==KErrNone);
	r=TheFs.SetSessionPath(gSessionPath);
	test(r==KErrNone);

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);
	TRequestStatus deathStat;
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();
//	test.End();
	}


void TestSubsessions()	
//
// test subsession functions
//
	{
	test.Next(_L("TestSubsessions"));
	RThread thread;
	PutNonCriticalNotifier(NULL,thread);

	// test that subsessions cannot be opened on a hung drive
	test.Next(_L("test subsessions cannot be opened on a hung drive"));
	// EFsFileCreate
	RFile file;
	TFileName fileName=gLockedPath;
	fileName+=File1;
	TInt r=file.Create(TheFs,fileName,EFileShareAny);
	test(r==KErrInUse);
	// EFsFormatOpen
	RFormat format;
	TInt count;
	r=format.Open(TheFs,gLockedPath,EHighDensity,count);
	test(r==KErrInUse);
	// EFsDirOpen
	RDir dir;
	r=dir.Open(TheFs,gLockedPath,KEntryAttMaskSupported);
	test(r==KErrInUse);
	// EFsRawDiskOpen
	RRawDisk raw;
	r=raw.Open(TheFs,gLockedDrive);
	test(r==KErrInUse);

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);
	TRequestStatus deathStat;
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();

	// now open the subsessions
	r=file.Create(TheFs,fileName,EFileShareAny);
	test(r==KErrNone||KErrAlreadyExists);
	if(r==KErrAlreadyExists)
		{
		r=file.Open(TheFs,fileName,EFileShareAny);
		test(r==KErrNone);
		}
	r=dir.Open(TheFs,gLockedPath,KEntryAttMaskSupported);
	test(r==KErrNone);
	
	// put notifier back up
	PutNonCriticalNotifier(NULL,thread);

	// test subsession operations fail on a hung drive
	test.Next(_L("test subsession operations fail on a hung drive"));
	// EFsFileRead
	TBuf8<16> readBuf;
	r=file.Read(readBuf);
	test(r==KErrInUse);
	// subsession should be able to be closed ok
	file.Close();
	// EFsDelete
	r=TheFs.Delete(fileName);
	test(r==KErrInUse);
	// EFsDirRead
	TEntry entry;
	r=dir.Read(entry);
	test(r==KErrInUse);
	// subsession should be able to be closed ok
	dir.Close();

	// not going to test operations on a drive the is not hung
	// since this will be tested on other tests

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();

	r=TheFs.Delete(fileName);
	test(r==KErrNone);
//	test.End();
	}

void TestSameSession()
//
// Test functions that can and cannot be handled from same session when notifier is up
//
	{
	test.Next(_L("TestSameSession"));

	RFile file;
	TInt r=file.Create(TheFs,File1,EFileWrite);
	test(r==KErrNone);

	// put notifier up using TheFs session
	SNonCriticalInfo info={ETrue,0};
	RThread thread;
	PutNonCriticalNotifier(&info,thread);

	// test critical functions can be handled
	test.Next(_L("test critical functions can be handled"));
	// EFsNotifyChange
	TRequestStatus status;
	TheFs.NotifyChange(ENotifyAll,status);
	test(status==KRequestPending);
	// EFsNotifyChangeCancel
	TheFs.NotifyChangeCancel();
	test(status==KErrCancel);
	// EFsNotifyChange again
	TheFs.NotifyChange(ENotifyAll,status);
	test(status==KRequestPending);
	// EFsNotifyChangeCancelEx
	TheFs.NotifyChangeCancel(status);
	test(status==KErrCancel);
	// not going to test EFsSubClose

	// test other functions are not handled
	test.Next(_L("test other functions cannot be handled"));
	// EFsNotifyChangeEx
	TheFs.NotifyChange(ENotifyAll,status,gSessionPath);
	test(status==KErrInUse);
	TFileName defPath;
	// EFsCheckDisk
	r=TheFs.CheckDisk(gSessionPath);
	test(r==KErrInUse);
	// EFsFileWrite
	_LIT8(buffer,"abc");
	TBuf8<8> buf(buffer);
	r=file.Write(buf);
	test(r==KErrInUse);

	// this file should be able to be closed
	file.Close();

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);
	
	TRequestStatus deathStat;
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();

	r=TheFs.Delete(File1);
	test(r==KErrNone);
//	test.End();
	}

void TestSameSubSession()
// 
// test hung file server with same subsession
//
	{
	_LIT(file1Name,"\\SubFile1");
	_LIT(file2Name,"\\SubFile2");
	_LIT(file3Name,"\\SubFile3");
	_LIT(file4Name,"\\SubFile4");
	TFileName origSession;
	TInt r=TheFs.SessionPath(origSession);
	test(r==KErrNone);
	TFileName file1Path(gLockedBase);
	file1Path+=file1Name;
	TFileName file2Path(file2Name);
	TFileName file3Path(gLockedBase);
	file3Path+=file3Name;
	TFileName file4Path(file4Name);
	// create file that will be used to hang file server
	r=SubFile1.Create(TheFs,file1Path,EFileWrite);
	test(r==KErrNone);
	// create file with same session but on different drive
	RFile subfile2;
	r=subfile2.Create(TheFs,file2Path,EFileWrite);
	test(r==KErrNone);
	// create file on unhung drive and with different session
	RFs fs2;
	r=fs2.Connect();
	test(r==KErrNone);
	r=fs2.SetSessionPath(origSession);
	test(r==KErrNone);
	RFile subfile3;
	r=subfile3.Create(fs2,file3Path,EFileWrite);
	test(r==KErrNone);
	// create file on unhung drive and with different session
	RFile subfile4;
	r=subfile4.Create(fs2,file4Path,EFileWrite);
	test(r==KErrNone);
	// in a different thread cause the server to hang using one of the File1 subsession
	// put notifier up using TheFs session
	SNonCriticalInfo info={ETrue,ETrue};
	RThread thread;
	PutNonCriticalNotifier(&info,thread);
	test.Next(_L("test writing to files with hung file server"));
	// check only file4 can be written to
	_LIT8(buffer,"abc");
	TBuf8<8> buf(buffer);
	// File1 caused hung file server
	r=SubFile1.Write(buf);
	test(r==KErrInUse);
	// file2 is same session as subsession that caused hung file server
	r=subfile2.Write(buf);
	test(r==KErrInUse);
	// file3 is opened on hung drive
	r=subfile3.Write(buf);
	test(r==KErrInUse);
	// file4 should be ok
	r=subfile4.Write(buf);
	test(r==KErrNone);
	// hard to test EFsSubClose since does not return an error value
	test.Next(_L("test closing down the subsessions"));
	subfile4.Close();
	// calling close on the same subsession as is hung will cause this subsession
	// to be closed once the original request is completed
	SubFile1.Close();
	subfile2.Close();

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);
	TRequestStatus deathStat;
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();
	// close remaining files
	subfile3.Close();
	// clean up
	fs2.Close();
	r=TheFs.Delete(file1Path);
	test(r==KErrNone);
	r=TheFs.Delete(file2Path);
	test(r==KErrNone);
	r=TheFs.Delete(file3Path);
	test(r==KErrNone);
	r=TheFs.Delete(file4Path);
	test(r==KErrNone);
	}

void TestExtendedNotifier()
//
//
//
	{
	test.Next(_L("TestExtendedNotifier"));
	// setup a notification on a removable media
	test.Next(_L("test with drive specified"));
	TFileName notDir=gLockedBase;
	notDir+=NotifyDir;
	TRequestStatus status;
	TheFs.NotifyChange(ENotifyAll,status,notDir);
	test(status==KRequestPending);
	// now do an operation on c: and test no notification
	TInt r=TheFs.MkDir(NotifyDir);
	test(r==KErrNone);
	r=TheFs.RmDir(NotifyDir);
	test(r==KErrNone);
	User::After(1000000);
	test(status==KRequestPending);
	TheFs.NotifyChangeCancel(status);
	test(status==KErrCancel);

	// now put up the notifier
	RThread thread;
	PutNonCriticalNotifier(NULL,thread);

	// repeat the above notification
	// setup a notification on a removable media - the drive should be changed
	// to * since notifier is up
	test.Next(_L("test with wildcard for drive"));
	TheFs.NotifyChange(ENotifyAll,status,notDir);
	test(status==KRequestPending);
	// test notification does not go off with wrong path
	r=TheFs.MkDir(NotifyDir2);
	test(r==KErrNone);
	r=TheFs.RmDir(NotifyDir2);
	test(r==KErrNone);
	test(status==KRequestPending);
	// now do an operation on c: and test there has been a notification
	r=TheFs.MkDir(NotifyDir);
	test(r==KErrNone);
	r=TheFs.RmDir(NotifyDir);
	test(r==KErrNone);
	User::After(1000000);
	// request should be completed this time
	test(status==KErrNone);

	// set up a notification on drive that is not removable
	// the path should not be changed
	test.Next(_L("test with non-removable drive"));
	TheFs.NotifyChange(ENotifyAll,status,notDir);
	test(status==KRequestPending);
	TRequestStatus status2;
	TFileName origSession;
	r=TheFs.SessionPath(origSession);
	test(r==KErrNone);
	RFs fs2;
	r=fs2.Connect();
	test(r==KErrNone);
	r=fs2.SetSessionPath(origSession);
	test(r==KErrNone);
	_LIT(notifyDirZ,"z:\\test\\");
	_LIT(notifyDirSess,"\\test\\");
	// notifyDirZ already exists, create test dir in session path
	r=fs2.MkDir(notifyDirSess);
	test(r==KErrNone);
	fs2.NotifyChange(ENotifyDir,status2,notifyDirZ);
	test(status2==KRequestPending);
	TRequestStatus status3;
	fs2.NotifyChange(ENotifyDir,status3,notifyDirSess);
	test(status3==KRequestPending);
	// now delete session dir and test no notification
	r=TheFs.RmDir(notifyDirSess);
	test(r==KErrNone);
	test(status2==KRequestPending && status3==KErrNone);

	// get rid of non-critical notifier
	test.Printf(_L("Enter %S on the notifier\n"),&KPassword);
	TRequestStatus deathStat;
	thread.Logon( deathStat );
	HungSemaphoreNC.Wait();
	test(HungReturnCodeNC==KErrNotFound);
	User::WaitForRequest( deathStat );
	thread.Close();
	test(status==KErrNone&&status2==KErrNone);
	fs2.Close();

	test.Next(_L("test extended notification with critical notifier"));
	RThread threadC;
	// put a a critical notifier
	PutCriticalNotifier(ETrue,threadC);
	// setup extended change notification on session path, drive should be changed to *
	TheFs.NotifyChange(ENotifyAll,status,NotifyDir);
	test(status==KRequestPending);
	// get rid of notifier
	test.Printf(_L("Press cancel on for critcal notifier\n"));
	threadC.Logon(deathStat);
	HungSemaphoreC.Wait();
	User::WaitForRequest(deathStat);
	threadC.Close();
	// test that notification has not gone off
	test(status==KRequestPending);
	// create directory on locked drive
	r=TheFs.MkDir(notDir);
	test(r==KErrNone);
	// test notifier goes off
	test(status==KErrNone);
	r=TheFs.RmDir(notDir);
	test(r==KErrNone);
	// get rid of critical notifier
	}	

LOCAL_C TBool TestSessionPath()
//
// 
//
	{
#if defined(__WINS__)
	TInt r=TheFs.CharToDrive(gSessionPath[0],gSessionDrive);
	test(r==KErrNone);
	if(gSessionDrive==EDriveX)
		return(EFalse);
#else
	TInt r=TheFs.CharToDrive(gSessionPath[0],gSessionDrive);
	test(r==KErrNone);
	TDriveList list;
	r=TheFs.DriveList(list);
	test(r==KErrNone);
	if((list[gSessionDrive])&KDriveAttRemovable)
		return(EFalse);
#endif
	return(ETrue);
	}


GLDEF_C void CallTestsL()
//
// Test a hung file server
//
	{
	if(!IsTestTypeStandard())
		return;

	if(!TestSessionPath())
		{
		test.Printf(_L("Not testing on %S\n"),&gSessionPath);
		return;
		}
#if defined(__WINS__)
	gLockedDrive=EDriveX;
	gLockedPath=_L("?:\\");
	gLockedBase=_L("?:");
	gLockedPath[0]=gLockedBase[0]=(TText)('A'+gLockedDrive);
#else
	gLockedDrive=EDriveD;
	gLockedPath=_L("?:\\");
	gLockedBase=_L("?:");
	gLockedPath[0]=gLockedBase[0]=(TText)('A'+gLockedDrive);
#endif

	test.Printf(_L("Is a secure mmc present? Press y for yes\n"));
	TChar c=test.Getch();
	if(c=='y'||c=='Y')
		isSecureMmc=ETrue;
	else
		isSecureMmc=EFalse;

	TInt r=HungSemaphoreC.CreateLocal(0);
	test(r==KErrNone);
	r=HungSemaphoreNC.CreateLocal(0);
	test(r==KErrNone);

	// create sharable session
	TheFs.ShareAuto();

	TestParsingFunctions();
	TestTFsFunctions();
	TestExtendedNotifier();
	TestSubsessions();
//	TestNotifiers();
	TestCriticalFunctions();
	TestSameSession();
	TestSameSubSession();

	HungSemaphoreC.Close();
	HungSemaphoreNC.Close();
}