kerneltest/f32test/filesystem/fat/t_tscan32.cpp
changeset 0 a41df078684a
child 21 e7d2d738d3c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/filesystem/fat/t_tscan32.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2055 @@
+// 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\scndrv\t_tscan32.cpp
+// 
+//
+
+#include <f32file.h>
+#include <e32test.h>
+
+#include "t_server.h"
+
+#include "fat_utils.h"
+using namespace Fat_Test_Utils;
+
+/*
+Series of tests to check that the combination of a ruggedised fat file
+system and scandisk prevents the file system from becoming corrupt in the
+event of a power failure. CheckDisk is used to test that directory
+structure is not corrupt. This test is only suitable with a drive that uses
+the fat file system but not the internal ram drive (due to the indirection)
+table. Only works with debug builds due to RFs::ControlIo only debug function
+*/
+
+GLDEF_D TFileName StartupExeName=_L(""); // initialised at run time
+
+#ifdef _DEBUG
+GLREF_D RTest test;
+GLDEF_D TInt TheFunctionNumber;
+GLDEF_D TInt TheOpNumber;
+GLDEF_D TInt TheFailCount;
+GLDEF_D TBool IsReset;
+GLDEF_D TFileName TestExeName=_L("?:\\T_SCANDR.EXE"); //Renaming it to fit in one root dir entry.
+GLDEF_D TFileName LogFileName=_L("?:\\T_SCANDR.LOG"); //Renaming it to fit in one root dir entry.
+
+const TInt KControlIoWriteFailOn=0;		// commands to pass into RFs::ControlIo
+const TInt KControlIoWriteFailOff=1;
+const TInt KMaxFatEntries  = 2048;
+const TInt KDirAttrReadOnly  = 0x01;
+const TInt KDirAttrHidden    = 0x02;
+const TInt KDirAttrSystem    = 0x04;
+const TInt KDirAttrVolumeId  = 0x08;
+const TInt KDirAttrDirectory = 0x10;
+const TInt KDirAttrArchive   = 0x20;
+const TInt KDirAttrLongName  = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId;
+const TInt KDirAttrLongMask  = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive;
+const TInt KDirLastLongEntry = 0x40;
+
+GLDEF_D TInt WriteFailValue;
+
+LOCAL_C TFatBootSector BootSector;	
+LOCAL_D RRawDisk TheRawDisk;
+
+static TFatType gDiskType = EInvalid;
+
+LOCAL_D TInt gTotalSectors;
+LOCAL_D TInt gBytesPerCluster;
+LOCAL_D TInt gRootDirSectors;
+LOCAL_D TInt gRootDirEntries;
+LOCAL_D TInt gRootDirStart;
+LOCAL_D TInt gRootSector;
+LOCAL_D TInt gFatStartBytes;
+LOCAL_D TInt gFatTestEntries;
+LOCAL_D TInt gFatSizeSectors;
+LOCAL_D TInt gFirstDataSector;
+LOCAL_D TInt gDataStartBytes;
+LOCAL_D TInt gClusterCount;
+
+LOCAL_D HBufC8* gFatBuf  = NULL;
+LOCAL_D TInt    gFatAddr = -1;
+
+enum TFatChain {EChainStd,EChainAlternate,EChainBackwards,EChainForwards};
+
+LOCAL_C TBool IsInternalRam()
+//
+// Returns true if the selected drive is variable size (i.e. RAM drive)
+//
+	{
+	TVolumeInfo v;
+	TInt r=TheFs.Volume(v,gSessionPath[0]-'A');
+	test(r==KErrNone);
+	return(v.iDrive.iMediaAtt&KMediaAttVariableSize);
+	}
+
+LOCAL_C void WriteLogFile()
+//
+// Writes state of test to end of LogFileName
+//
+	{
+	test.Printf(_L("Writelogfile()\n"));
+	RFile log;
+	TInt r=log.Open(TheFs,LogFileName,EFileShareExclusive|EFileWrite);
+	if(r!=KErrNone)
+		test.Printf(_L("error=%d\n"),r);
+	test(r==KErrNone);
+	TInt size;
+	r=log.Size(size);
+	test(r==KErrNone);
+	TBuf8<16> buf;
+	buf.SetLength(4);
+	buf[0]=(TUint8)TheFunctionNumber;
+	buf[1]=(TUint8)TheOpNumber;
+	buf[2]=(TUint8)TheFailCount;
+	buf[3]='\n';
+	r=log.Write(size,buf,buf.Length());
+	test(r==KErrNone);
+	test.Printf(_L("Written func=%d,op=%d,fail=%d\n"),TheFunctionNumber,TheOpNumber,TheFailCount);
+	log.Close();
+	}
+
+LOCAL_C TInt SetWriteFailOn(TInt aFailCount)
+//
+// Sets write to metadata to fail on aFailCount with WriteFailValue
+//
+	{
+	TInt16 args[2];
+	TPtr8 des((TUint8*)args,4,4);
+	args[0]=(TUint16)aFailCount;
+	args[1]=(TUint16)WriteFailValue;
+	TInt r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOn,des);
+	return(r);
+	}
+
+GLDEF_C void ReadLogFile()
+//
+// Reads state of test from end of LogFileName and sets global variables
+//
+	{
+	test.Next(_L("ReadLogFile"));
+	RFile log;
+	TInt r=log.Open(TheFs,LogFileName,EFileShareExclusive);
+	if(r!=KErrNone)
+		test.Printf(_L("error in ReadLogFile()=%d\n"),r);
+	test(r==KErrNone);
+	test(r==KErrNone);
+	TInt fileSize;
+	r=log.Size(fileSize);
+	if(fileSize==0)
+		{
+		TheFunctionNumber=0;
+		TheOpNumber=0;
+		TheFailCount=0;
+		}
+	else
+		{
+		TBuf8<4> buf;
+		r=log.Read(fileSize-4,buf,4);
+		TheFunctionNumber=buf[0];
+		TheOpNumber=buf[1];
+		TheFailCount=buf[2];
+		}
+	log.Close();
+	test.Printf(_L("func=%d,op=%d,fail=%d\n"),TheFunctionNumber,TheOpNumber,TheFailCount);
+	}
+
+LOCAL_C TUint32 MaxClusters()
+	//
+	// Return the number of data clusters on the disk
+	//
+	{
+	TUint32 totSec = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors());
+	TUint32 numSec = totSec - gFirstDataSector;
+	return numSec / BootSector.SectorsPerCluster();
+	}
+
+LOCAL_C TInt ClusterToByte(TInt aCluster)
+	//
+	// converts cluster number to byte offset on disk
+	//
+	{
+	TInt sector = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * BootSector.BytesPerSector();
+	return sector;
+	}
+
+/**
+    Fill media with zeroes from aStartPos to aEndPos
+*/
+static void DoZeroFillMedia(TInt64 aStartPos, TInt64 aEndPos, RRawDisk& aWriter)
+{
+    test(aStartPos >=0 && aEndPos >=0 && aStartPos < aEndPos);
+    
+    if(aStartPos == aEndPos)
+        return;
+
+    RBuf8 buf;
+    TInt  nRes;  
+
+    const TUint32 KBufSz=65536*2; //-- buffer with zeroes
+    
+    nRes = buf.CreateMax(KBufSz);
+    test(nRes == KErrNone);
+
+    buf.FillZ();
+
+    TUint32 rem = (TUint32)(aEndPos - aStartPos);
+    while(rem)
+    {
+        const TUint32 bytesToWrite=Min(rem, KBufSz);
+    
+        TPtrC8 ptr(buf.Ptr(), bytesToWrite);
+        nRes = aWriter.Write(aStartPos, ptr);
+        test(nRes == KErrNone || nRes == KErrDiskFull);
+
+        aStartPos+=bytesToWrite;
+        rem-=bytesToWrite;
+    }
+
+
+    buf.Close();
+}
+
+//
+// Clear the disk data area to a known value which won't be confused with
+// directory entries etc.
+//
+LOCAL_C void ClearDiskData()
+	{
+
+	TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
+	test(r==KErrNone);
+
+	TUint32 startPos = gDataStartBytes;
+	if (gDiskType == EFat32)
+		startPos += gBytesPerCluster;
+
+    const TUint32 endPos = startPos + gFatTestEntries*gBytesPerCluster;
+
+    test.Printf(_L("ClearDiskData() from pos:%u to pos:%u\n"), startPos, endPos);
+
+    DoZeroFillMedia(startPos, endPos, TheRawDisk);
+
+	TheRawDisk.Close();
+	}
+
+LOCAL_C TInt PosInBytes(TInt aFatIndex)
+//
+// Return number of bytes into the FAT
+//
+	{
+	TInt fatPosInBytes = -1;
+	switch (gDiskType)
+		{
+		case EFat32:
+			fatPosInBytes=aFatIndex<<2;
+			break;
+		case EFat16:
+			fatPosInBytes=aFatIndex<<1;
+			break;
+		case EFat12:
+			fatPosInBytes=(aFatIndex*3>>1);
+			break;
+		default:
+			test(0);
+		}
+	return(fatPosInBytes);
+	}
+
+static void DoReadBootSector()
+	{
+	
+    TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, BootSector);
+    test(nRes == KErrNone);
+
+    if(!BootSector.IsValid())
+        {
+        test.Printf(_L("Wrong bootsector! Dump:\n"));
+        BootSector.PrintDebugInfo();
+        test(0);
+        }
+	// Calculate derived variables (fixed for a particular disk format)
+	gBytesPerCluster   = BootSector.BytesPerSector() * BootSector.SectorsPerCluster();
+	gRootDirSectors    = ((BootSector.RootDirEntries() * KSizeOfFatDirEntry + BootSector.BytesPerSector() - 1) / BootSector.BytesPerSector());
+	gFatStartBytes     = BootSector.ReservedSectors() * BootSector.BytesPerSector();
+	gFatSizeSectors    = (BootSector.FatSectors() ? BootSector.FatSectors() : BootSector.FatSectors32());
+	gRootSector        = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors;
+	gRootDirStart      = gRootSector * BootSector.BytesPerSector();
+	gFirstDataSector   = gRootSector + gRootDirSectors;
+
+	gFatTestEntries = MaxClusters();
+	if (gFatTestEntries > KMaxFatEntries)
+		gFatTestEntries = KMaxFatEntries;
+
+	if (BootSector.RootDirEntries() == 0)
+		{
+		test.Printf(_L("**** Is Fat32\n"));
+		gDiskType = EFat32;
+		gRootDirEntries = BootSector.RootDirEntries();
+		}
+	else if (BootSector.FatType() == EFat16)
+		{
+		test.Printf(_L("**** Is Fat16\n"));
+		gDiskType = EFat16;
+		gRootDirEntries = BootSector.RootDirEntries();
+		}
+	else
+		{
+		test.Printf(_L("**** Is Fat12\n"));
+		gDiskType = EFat12;
+		gRootDirEntries = gBytesPerCluster * 1 / KSizeOfFatDirEntry;
+		}
+	gTotalSectors   = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors());
+	gClusterCount   = (gTotalSectors - gFirstDataSector) / BootSector.SectorsPerCluster();
+	gDataStartBytes = gFirstDataSector * BootSector.BytesPerSector();
+	}
+
+GLDEF_C TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL)
+//
+// Read a single FAT entry from disk or FAT copy and return it
+//
+	{
+
+
+	if (!gFatBuf)
+		{
+		gFatBuf=HBufC8::New(gBytesPerCluster);
+		test(gFatBuf!=NULL);
+		gFatAddr = -1;
+		}
+
+	const TUint8* ptr;
+
+	if (aFat)
+		{
+		ptr = (TUint8*)aFat + PosInBytes(aIndex);
+		}
+	else
+		{
+		TInt pos = PosInBytes(aIndex) + gFatStartBytes;
+		if (gFatAddr < 0 || pos < gFatAddr || pos >= gFatAddr + gBytesPerCluster)
+			{
+			TPtr8 ptr=gFatBuf->Des();
+		TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
+			test(r==KErrNone);
+			r=TheRawDisk.Read(pos, ptr);
+			test(r==KErrNone);
+			TheRawDisk.Close();
+			gFatAddr = pos;
+			}
+		ptr = gFatBuf->Ptr() + pos-gFatAddr;
+		}
+
+	TUint32 val = 0;
+	switch (gDiskType)
+		{
+		case EFat32:
+			val = *(TUint32*)ptr;
+			break;
+		case EFat16:
+			val = *(TUint16*)ptr;
+			break;
+		case EFat12:
+			val = *(TUint16*)ptr;
+			if (aIndex & 1)
+				val >>= 4;
+			val &= 0xFFF;
+			break;
+		default:
+			test(0);
+		}
+	return val;
+	}
+
+GLDEF_C void DumpBootSector()
+//
+// Display (in log) TFatBootSector structure
+//
+	{
+	RDebug::Print(_L("iBytesPerSector    = %8d"), BootSector.BytesPerSector());
+	RDebug::Print(_L("iSectorsPerCluster = %8d"), BootSector.SectorsPerCluster());
+	RDebug::Print(_L("iReservedSectors   = %8d"), BootSector.ReservedSectors());
+	RDebug::Print(_L("iNumberOfFats      = %8d"), BootSector.NumberOfFats());
+	RDebug::Print(_L("iRootDirEntries    = %8d"), BootSector.RootDirEntries());
+	RDebug::Print(_L("iTotalSectors      = %8d"), BootSector.TotalSectors());
+	RDebug::Print(_L("iMediaDescriptor   = %8d"), BootSector.MediaDescriptor());
+	RDebug::Print(_L("iFatSectors        = %8d"), BootSector.FatSectors());
+	RDebug::Print(_L("iSectorsPerTrack   = %8d"), BootSector.SectorsPerTrack());
+	RDebug::Print(_L("iNumberOfHeads     = %8d"), BootSector.NumberOfHeads());
+	RDebug::Print(_L("iHiddenSectors     = %8d"), BootSector.HiddenSectors());
+	RDebug::Print(_L("iHugeSectors       = %8d"), BootSector.HugeSectors());
+
+	//New for FAT32
+
+	if(BootSector.RootDirEntries() == 0)	//indicates we have FAT32 volume
+		{
+		RDebug::Print(_L("FatSectors32      = %8d"), BootSector.FatSectors32());
+		RDebug::Print(_L("FATFlags          = %8d"), BootSector.FATFlags());
+		RDebug::Print(_L("VersionNumber     = %8d"), BootSector.VersionNumber());
+		RDebug::Print(_L("RootClusterNum    = %8d (0x%08X)"), BootSector.RootClusterNum(), gRootDirStart);
+		RDebug::Print(_L("FSInfoSectorNum   = %8d (0x%08X)"), BootSector.FSInfoSectorNum(), BootSector.FSInfoSectorNum() * BootSector.BytesPerSector());
+		RDebug::Print(_L("BkBootRecSector   = %8d (0x%08X)"), BootSector.BkBootRecSector(), BootSector.BkBootRecSector() * BootSector.BytesPerSector());
+		}
+	TInt fatEntries = gFatSizeSectors*BootSector.BytesPerSector();
+	switch (gDiskType)
+		{
+		case EFat32:
+			fatEntries /= 4;
+			break;
+		case EFat16:
+			fatEntries /= 2;
+			break;
+		case EFat12:
+			fatEntries *= 3;
+			fatEntries /= 2;
+			break;
+		default:
+			test(0);
+		}
+	RDebug::Print(_L("ClusterCount      = %8d (%d bytes)"), gClusterCount, gClusterCount*gBytesPerCluster);
+	RDebug::Print(_L("FatEntries        = %8d (%d sectors)"), fatEntries, gFatSizeSectors);
+	RDebug::Print(_L("RootSector        = %8d (0x%08X)"), gRootSector, gRootDirStart);
+	RDebug::Print(_L("FirstDataSector   = %8d (0x%08X)"), gFirstDataSector, gDataStartBytes);
+	}
+
+GLDEF_C void DumpFat(const TUint8* aFat=NULL)
+// 
+// Dump to the log all those FAT entries which are non-zero
+//
+	{
+	TInt32 max = MaxClusters();
+	if (max > KMaxFatEntries)
+		max = KMaxFatEntries;
+	RDebug::Print(_L("---------------- DUMP OF FAT ---------------"));
+	for (TInt32 i = 0; i < max; i++)
+		{
+		TInt32 val = GetFatEntry(i, aFat);
+		TInt32 msk = 0x0FFFFFFF;
+		switch (gDiskType)
+			{
+			case EFat32:
+				msk = 0x0FFFFFFF;
+				break;
+			case EFat16:
+				msk = 0xFFFF;
+				break;
+			case EFat12:
+				msk = 0x0FFF;
+				break;
+			default:
+				test(0);
+			}
+		if ((val & msk) == (0x0FFFFFFF & msk))
+			RDebug::Print(_L("    %8d -> EOC"), i);
+		else if ((val & msk) == (0x0FFFFFF8 & msk))
+			RDebug::Print(_L("    %8d -> Media"), i);
+		else if ((val & msk) == (0x0FFFFFF7 & msk))
+			RDebug::Print(_L("    %8d -> BAD"), i);
+		else if (val > max)
+			RDebug::Print(_L("    %8d -> 0x%08X"), i, val);
+		else if (val != 0)
+			RDebug::Print(_L("    %8d -> %d"), i, val);
+		}
+	RDebug::Print(_L("--------------------------------------------"));
+	}
+
+GLDEF_C TDes* DirAttributes(TInt aAttrib)
+// 
+// Return a pointer to a local buffer containing the attribute letters.
+//
+	{
+	LOCAL_D TBuf<6> str(_L("------"));
+	LOCAL_D char*   atr = "RHSVDA";
+	for (TInt i = 0; i < 6; i++)
+		if ((aAttrib >> i) & 1)
+			str[i] = atr[i];
+	return &str;
+	}
+
+GLDEF_C TBool IsValidDirChar(TUint8 aChar, TUint8 aMin=0x20)
+//
+// Test whether a character is valid as part of a short filename, aMin is to
+// distinguish between first character (which can't be space) and later ones
+// which can include space but nothing less.  Note that E5 is a valid character
+// in any position, even though it means 'erased' in the first character.
+//
+	{
+	const TUint8* inval = (TUint8*)"\x22\x2A\x2B\x2C\x2E\x2F\x3A\x3B\x3C\x3D\x3E\x3F\x5B\x5C\x5D\x7C";
+	if (aChar < aMin)
+		return EFalse;
+	for (const TUint8* p = inval; *p; p++)
+		if (aChar == *p)
+			return EFalse;
+	return ETrue;
+	}
+
+GLDEF_C TBool IsValidDirEntry(TFatDirEntry* aDir)
+// 
+// Test whether buffer is a valid normal directory entry
+//
+	{
+	// top two bits of attributes must be zero
+	if (aDir->iData[11] & 0xC0)
+		return EFalse;
+	// first character must be 0x05 or greater than space
+	if (!IsValidDirChar(aDir->iData[0], 0x21) && aDir->iData[0] != 0x05)
+		return EFalse;
+	// other characters in name must be not less than space
+	for (TInt i = 1; i < 11; i++)
+		if (!IsValidDirChar(aDir->iData[i]))
+			return EFalse;
+	return ETrue;
+	}
+
+GLDEF_C void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength)
+// 
+// Extract part of a long name entry into the name buffer.
+//
+// @param aName   buffer to put name
+// @param aEntry  directory entry raw data
+// @param aPos    character in buffer to start name segment
+// @param aOffset offset in directory entry of the segment
+// @param aLength number of characters in the segment
+// 
+	{
+	for (TInt i = 0; i < aLength; i++)
+		{
+		TInt at = i * 2 + aOffset;
+		TInt ch = aEntry[at] + aEntry[at+1] * 256;
+		aName[aPos++] = TText(ch);
+		}
+	}
+
+GLDEF_C void ExtractNameString(TDes16& aName, const TUint8* aEntry)
+//
+// Extract a long name part from a directory entry, truncate it at the first
+// NUL (0) character and put quotes round it.
+//
+	{
+	aName.SetLength(15);
+	TInt len = aName.Length() - 1;
+	TText qu = '\'';
+	aName[0] = qu;
+	GetLongNamePart(aName, aEntry,  1,  1, 5);
+	GetLongNamePart(aName, aEntry,  6, 14, 6);
+	GetLongNamePart(aName, aEntry, 12, 28, 2);
+	TInt i;
+	for (i = 0; i < len; i++)
+		if (aName[i] == 0)
+			break;
+	aName[i++] = qu;
+	aName.SetLength(i);
+	}
+
+GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
+// 
+// Dump a single directory entry to the log.  Return false if it was end of
+// directory or an invalid entry (and don't display it).
+// 
+	{
+	TFatDirEntry* d = (TFatDirEntry*)aEntry;
+	if (d->IsErased())
+		{
+		// RDebug::Print(_L("%5d: ERASED"), aNum);
+		}
+	else if (d->IsEndOfDirectory())
+		return EFalse;
+	else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName)
+		{
+		TBuf16<15> name;
+		ExtractNameString(name, aEntry);
+		TInt ord = aEntry[0];
+		if (ord & KDirLastLongEntry)
+			RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
+		else
+			RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
+		}
+	else if (!IsValidDirEntry(d))
+		return EFalse;
+	else
+		{
+		TBuf<11> name;
+		name.Copy(d->Name());
+		RDebug::Print(_L("%5d: '%S'  %S  cluster %d"),
+					  aNum, &name, DirAttributes(d->Attributes()), d->StartCluster());
+		}
+	return ETrue;
+	}
+
+GLDEF_C void DumpDirCluster(const TUint8* aData, TInt aCluster=0)
+//
+// Dump directory entries until end of cluster or invalid/end entry found.
+//
+	{
+	if (aCluster > 2)
+		aData += (aCluster-2) * gBytesPerCluster;
+	for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry)
+		{
+		if (DumpDirEntry(i/KSizeOfFatDirEntry, aData))
+			aData += KSizeOfFatDirEntry;
+		else
+			break;
+		}
+	}
+
+GLDEF_C void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd)
+//
+// Dump clusters from disk (allows dumping of clusters not in our buffers).
+// Only look at clusters marked as 'used' in the FAT.  Note that if aFat is
+// NULL the FAT entries will also be read from disk (slower but allows for ones
+// outside our copy in memory).
+//
+	{
+	if (aStart > gFatTestEntries)
+		return;
+	RDebug::Print(_L("--------------- DATA AREA ------------------"));
+	if (aEnd > gFatTestEntries)
+		aEnd = gFatTestEntries;
+	for (TInt cluster = aStart; cluster < aEnd; cluster++)
+		{
+		if (GetFatEntry(cluster, aFat) != 0)
+			{
+			HBufC8* buf=HBufC8::New(gBytesPerCluster);
+			test(buf!=NULL);
+			TPtr8 ptr=buf->Des();
+			TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
+			test(r==KErrNone);
+			r=TheRawDisk.Read(ClusterToByte(cluster), ptr);
+			test(r==KErrNone);
+			TheRawDisk.Close();
+			RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
+			DumpDirCluster(ptr.Ptr());
+			delete buf;
+			}
+		}
+	RDebug::Print(_L("--------------------------------------------"));
+	}
+
+GLDEF_C void DumpHex(const TUint8* aData, TInt aLen)
+//
+// Dump a block of memory to the log in hex.
+//
+	{
+	for (TInt base = 0; base < aLen; base += 16)
+		{
+		TBuf<16*3> buf;
+		TInt off;
+		for (off = base; off < aLen && off < base + 16; off++)
+			{
+			buf.Append(TText(' '));
+			buf.AppendNumFixedWidth(aData[off], EHex, 2);
+			}
+		RDebug::Print(_L("%04X: %S"), off, &buf);
+		}
+	}
+
+static void QuickFormat()
+    {
+        /*
+        TFatFormatParam fmt;
+        fmt.iFatType = EFat32;
+        fmt.iSecPerCluster =1;
+        FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fmt);
+        */
+        FormatFatDrive(TheFs, CurrentDrive(), ETrue);
+    }
+
+
+LOCAL_C void MakeVeryLongName(TFileName& aLong)
+//
+// appends a very long file name to aLong
+//
+	{
+	// create a name to take up 18 vfat entries - (1 sector + 2 entries)
+	for(TInt i=0;i<234;++i)
+		{
+		TInt c='a'+i%26;
+		aLong.Append(c);
+		}
+	}
+
+LOCAL_C void MakeEntryName(TFileName& aName,TInt aLength)
+//
+// Appends aLength characters to aName
+//
+	{
+	for(TInt i=0;i<aLength;++i)
+		{
+		TInt c='A'+i%26;
+		aName.Append(c);
+		}
+	}
+
+LOCAL_C void FillUpRootDir(TInt aFree=0)
+//
+// Fill up root directory
+//
+	{
+	TInt maxRootEntries = gRootDirEntries -aFree;
+	TFileName dir=_L("\\??\\");
+	TInt count=0;
+	TInt entriesSoFar;
+	if(IsReset)
+		entriesSoFar=2+2+2+2; // \\t_scn32dr3.exe + \\sys + \\t_scn32dr3.log + \\f32-tst
+	else
+		entriesSoFar=0;
+	TInt r;
+	while(entriesSoFar<maxRootEntries)
+		{
+		dir[1]=TUint16(count/26+'a');
+		dir[2]=TUint16(count%26+'a');
+		r=TheFs.MkDir(dir);
+		test(r==KErrNone);
+		entriesSoFar+=2;
+		++count;
+		}
+	}
+
+LOCAL_C void UnFillUpRootDir(TInt aFree=0)
+//
+// Reverse changes from FillUpRootDir()
+//
+	{
+	TFileName dir=_L("\\??\\");
+	TInt entriesSoFar=gRootDirEntries -aFree;
+	TInt count=0;
+	TInt r;
+	TInt existing;
+	if(IsReset)
+		existing=2+2+2+2; // \\t_scn32dr3.exe + \\sys + \\t_scn32dr3.log + \\f32-tst
+	else
+		existing=0;
+	while(entriesSoFar>existing)
+		{
+		dir[1]=TUint16(count/26+'a');
+		dir[2]=TUint16(count%26+'a');
+		r=TheFs.RmDir(dir);
+		test(r==KErrNone);
+		entriesSoFar-=2;
+		++count;
+		}
+	}
+
+void InitialiseWriteBuffer(TDes8& buf)
+//
+//
+//
+	{
+	for(TInt i=0;i<buf.Length();++i)
+		buf[i]=(TUint8)('a'+i%26);
+	}
+
+LOCAL_C TBool EntryExists(const TDesC& aName)	
+//
+// Returns ETrue if aName is found
+//
+	{
+	TEntry entry;
+	TInt r=TheFs.Entry(aName,entry);
+	test(r==KErrNone||r==KErrNotFound);
+	return(r==KErrNone?(TBool)ETrue:(TBool)EFalse);
+	}
+
+LOCAL_C TInt EntriesPerFatSector()
+//
+// Returns number of entries in one fat table sector
+//
+	{
+	switch (gDiskType)
+		{
+		case EFat32:
+			return(BootSector.BytesPerSector()/4);
+		case EFat16:
+			return(BootSector.BytesPerSector()/2);
+		case EFat12:
+			return(BootSector.BytesPerSector()*2/3);
+		default:
+			test(0);
+		}
+	return -1;
+	}
+
+LOCAL_C TBool OneEntryExists(const TDesC& aOldName,const TDesC& aNewName)
+//
+// Returns ETrue if only one of two entries exists
+//
+	{
+	TBool oldExists=EntryExists(aOldName);
+	TBool newExists=EntryExists(aNewName);
+	return((!oldExists&&newExists)||(oldExists&&!newExists));
+	}
+
+LOCAL_C void GetEntryDetails(const TDesC& aName,TEntry& aEntry)
+//
+// returns entry details for the entry with aName
+//
+	{
+	TInt r=TheFs.Entry(aName,aEntry);
+	test(r==KErrNone);
+	}
+
+LOCAL_C TBool IsSameEntryDetails(TEntry aOldEntry,TEntry aNewEntry)
+//
+// 
+//
+	{
+	return(aOldEntry.iAtt==aNewEntry.iAtt&&aOldEntry.iSize==aNewEntry.iSize&&aOldEntry.iModified==aNewEntry.iModified);
+	}
+
+LOCAL_C void CreateAlternate(const TDesC& aNameOne,const TDesC& aNameTwo)
+//
+// Creates altenate entries which take up one sector of fat table.
+// By subsequently deleting  one of these entries a new entry can be made 
+// with cluster chain that is not contiguous.
+//
+	{
+	TInt entries=EntriesPerFatSector();
+	RFile file1,file2;
+	TInt size1,size2;
+	size1=size2=0;
+	TInt r=file1.Create(TheFs,aNameOne,EFileShareAny);
+	test(r==KErrNone);
+	r=file2.Create(TheFs,aNameTwo,EFileShareAny);
+	test(r==KErrNone);
+	// one entry for file1 for every 40 entries for file2
+	// if file 1 subseqently deleted then 7 entries available
+	// in that fat sector - ~3.5kb file size - for fat16
+	TInt ratio=40;
+	TBool first=ETrue;
+	while(entries>0)
+		{
+		if(first)
+			{
+			size1+=gBytesPerCluster;
+			r=file1.SetSize(size1);
+			test(r==KErrNone);
+			first=EFalse;
+			--entries;
+			}
+		else
+			{
+			size2+=gBytesPerCluster*ratio;
+			r=file1.SetSize(size1);
+			test(r==KErrNone);
+			first=ETrue;
+			entries-=ratio;
+			}
+		}
+	file1.Close();
+	file2.Close();
+	}
+
+LOCAL_C TInt ThrottleDirEntries(TInt aDirEntries)
+	{
+	// throttle the number of entries needed, since for large cluster
+	// sizes, this can take forever (eg 2GB card -> a cluster size of 32K
+	// -> 1024 entries per cluster
+	const TInt KMaxDirEntries = 2048;
+	if (aDirEntries > KMaxDirEntries)
+		{
+		RDebug::Print(_L("Reducing directory entries from %d to %d"), 
+			aDirEntries, KMaxDirEntries);
+		aDirEntries = KMaxDirEntries;
+		}
+	return aDirEntries;
+	}
+
+
+LOCAL_C void CleanDirectory(const TDesC& aName,TInt aClusters)
+//
+// Removes entries in the directory
+//
+	{
+	if (aClusters < 1)
+		return;
+	TInt entriesPerCluster=gBytesPerCluster/32;
+	TInt entriesNeeded = entriesPerCluster * aClusters;
+
+	entriesNeeded = ThrottleDirEntries(entriesNeeded);
+
+	TInt maxFileNameLen = 250 - aName.Length();
+	TInt nameEntries = 1 + (maxFileNameLen+12) / 13;
+	TInt namesNeeded = (entriesNeeded + nameEntries-1) / nameEntries;
+	TInt entry = 0;
+	for(TInt i = 0; i < namesNeeded; ++i)
+		{
+		if (entriesNeeded - entry < nameEntries)
+			maxFileNameLen = (entriesNeeded - entry - 1) * 13;
+		TFileName fn;
+		fn.AppendNum(entry);
+		fn.Append('_');
+		while (fn.Length() < maxFileNameLen)
+			fn.Append('0');
+		TFileName fullName(aName);
+		fullName.Append(fn);
+		TInt r = TheFs.Delete(fullName);
+		test(r == KErrNone);
+		entry += 1 + (fn.Length() + 12) / 13;
+		}
+	RDebug::Print(_L("CleanDirectory(%S, %d)"), &aName, aClusters);
+	}
+
+LOCAL_C void ExpandDirectory(const TDesC& aName,TInt aClusters)
+//
+// Expands the directory by aClusters
+//
+	{
+	if (aClusters < 1)
+		return;
+	TInt entriesPerCluster=gBytesPerCluster/32;
+	TInt entriesNeeded = entriesPerCluster * aClusters;
+
+	entriesNeeded = ThrottleDirEntries(entriesNeeded);
+
+	TInt maxFileNameLen = 250 - aName.Length();
+	TInt nameEntries = 1 + (maxFileNameLen+12) / 13;
+	TInt namesNeeded = (entriesNeeded + nameEntries-1) / nameEntries;
+	TInt entry = 0;
+	for(TInt i = 0; i < namesNeeded; ++i)
+		{
+		if (entriesNeeded - entry < nameEntries)
+			maxFileNameLen = (entriesNeeded - entry - 1) * 13;
+		TFileName fn;
+		fn.AppendNum(entry);
+		fn.Append('_');
+		while (fn.Length() < maxFileNameLen)
+			fn.Append('0');
+		TFileName fullName(aName);
+		fullName.Append(fn);
+		RFile file;
+		TInt r = file.Create(TheFs,fullName,EFileShareAny);
+		test(r == KErrNone);
+		file.Close();
+		entry += 1 + (fn.Length() + 12) / 13;
+		}
+	// to leave a directory expanded by aClusters but with no additional entries
+	RDebug::Print(_L("ExpandDirectory(%S, %d)"), &aName, aClusters);
+	CleanDirectory(aName,aClusters);
+	}
+
+LOCAL_C TInt DeleteAlternateEntry(const TDesC& aName,TBool aIsDir)
+//
+// Deletes entry aName and corresponding entries created for EChainAlternate
+//
+	{
+	TInt r=TheFs.Delete(_L("\\fat\\file2"));
+	test(r==KErrNone||KErrNotFound);
+	if(aIsDir)
+		return(TheFs.RmDir(aName));
+	else
+		return(TheFs.Delete(aName));
+	}
+
+LOCAL_C TInt CreateAlternateEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
+//
+// Creates entry with aName where cluster chain grows forward but not contiguously.
+// Assumes that no holes in fat clusters.
+//
+	{
+	TInt r=DeleteAlternateEntry(aName,aIsDir);
+	test(r==KErrNone||r==KErrNotFound);
+	RFile file;
+	if(aIsDir)
+		{
+		r=TheFs.MkDir(aName);
+		if(r!=KErrNone)
+			return(r);
+		}
+	else
+		{
+		r=file.Create(TheFs,aName,EFileShareAny);
+		if(r!=KErrNone)
+			return(r);
+		r=file.SetSize(1); //ensure file allocated a start cluster
+		test(r==KErrNone);
+		}
+	CreateAlternate(_L("\\fat\\file1"),_L("\\fat\\file2"));
+	r=TheFs.Delete(_L("\\fat\\file1"));
+	test(r==KErrNone);
+	if(aIsDir)
+		ExpandDirectory(aName,aSize);
+	else
+		{
+		r=file.SetSize(aSize);
+		test(r==KErrNone);
+		file.Close();
+		}
+	return(KErrNone);
+	}
+
+LOCAL_C TInt DeleteForwardEntry(const TDesC& aName,TBool aIsDir)
+//
+// Deletes entry with aName and corresponding entries created for EChainForward
+//
+	{
+	TInt r=TheFs.Delete(_L("\\fat\\file2"));
+	test(r==KErrNone||r==KErrNotFound);
+	r=TheFs.Delete(_L("\\fat\\file4"));
+	test(r==KErrNone||r==KErrNotFound);
+	r=TheFs.Delete(_L("\\fat\\file5"));
+	test(r==KErrNone||r==KErrNotFound);
+	if(aIsDir)
+		r=TheFs.RmDir(aName);
+	else
+		r=TheFs.Delete(aName);
+	return r;
+	}
+	
+LOCAL_C TInt CreateForwardEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
+//
+// Creates an entry whose cluster chain first goes forward (upto 3.5kb for fat16 file)
+// and then backwards
+//	
+	{
+	TInt r=DeleteForwardEntry(aName,aIsDir);
+	test(r==KErrNone||r==KErrNotFound);
+	RFile file1,file2,entry;
+	r=file1.Create(TheFs,_L("\\fat\\file1"),EFileShareAny);
+	test(r==KErrNone);
+	r=file1.SetSize(EntriesPerFatSector()*gBytesPerCluster);
+	test(r==KErrNone);
+	r=file2.Create(TheFs,_L("\\fat\\file2"),EFileShareAny);
+	test(r==KErrNone);
+	r=file2.SetSize(EntriesPerFatSector()*gBytesPerCluster);
+	test(r==KErrNone);
+	if(aIsDir)
+		{
+		r=TheFs.MkDir(aName);
+		if(r!=KErrNone)
+			return(r);
+		}
+	else
+		{
+		r=entry.Create(TheFs,aName,EFileShareAny);
+		if(r!=KErrNone)
+			return(r);
+		r=entry.SetSize(1);	// ensure entry has start cluster allocated
+		test(r==KErrNone);
+		}
+	CreateAlternate(_L("\\fat\\file3"),_L("\\fat\\file4"));
+	RFile file5;
+	r=file5.Create(TheFs,_L("\\fat\\file5"),EFileShareAny);
+	test(r==KErrNone);
+	r=file5.SetSize(EntriesPerFatSector()*gBytesPerCluster*2);
+	test(r==KErrNone);
+	file1.Close();
+	file2.Close();
+	file5.Close();
+	r=TheFs.Delete(_L("\\fat\\file1"));
+	test(r==KErrNone);
+	r=TheFs.Delete(_L("\\fat\\file3"));
+	test(r==KErrNone);
+	if(aIsDir)
+		ExpandDirectory(aName,aSize);
+	else
+		{
+		r=entry.SetSize(aSize);
+		test(r==KErrNone);
+		entry.Close();
+		}
+	return(KErrNone);
+	}
+
+LOCAL_C TInt DeleteBackwardEntry(const TDesC& aName,TBool aIsDir)
+//
+// Deletes entry with aName and corresponding entries created for EChainBackwards
+//
+	{
+	TInt r=TheFs.Delete(_L("\\fat\\file2"));
+	test(r==KErrNone||r==KErrNotFound);
+	r=TheFs.Delete(_L("\\fat\\file3"));
+	test(r==KErrNone||r==KErrNotFound);
+	if(aIsDir)
+		r=TheFs.RmDir(aName);
+	else
+		r=TheFs.Delete(aName);
+	return r;
+	}
+
+LOCAL_C TInt CreateBackwardEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
+//
+// Creates an entry whose fat cluster chain first goes backwards(upto 3.5kb for fat16 file)
+// and then forwards
+//
+	{
+	TInt r=DeleteBackwardEntry(aName,aIsDir);
+	test(r==KErrNone||r==KErrNotFound);
+	CreateAlternate(_L("\\fat\\file1"),_L("\\fat\\file2"));
+	RFile entry;
+	if(aIsDir)
+		{
+		r=TheFs.MkDir(aName);
+		if(r!=KErrNone)
+			return(r);
+		}
+	else
+		{
+		r=entry.Create(TheFs,aName,EFileShareAny);
+		if(r!=KErrNone)
+			return(r);
+		r=entry.SetSize(1);
+		test(r==KErrNone);
+		}
+	RFile file3;
+	r=file3.Create(TheFs,_L("\\fat\\file3"),EFileShareAny);
+	test(r==KErrNone);
+	r=file3.SetSize(EntriesPerFatSector()*gBytesPerCluster);
+	test(r==KErrNone);
+	r=TheFs.Delete(_L("\\fat\\file1"));
+	test(r==KErrNone);
+	file3.Close();
+	if(aIsDir)
+		ExpandDirectory(aName,aSize);
+	else
+		{
+		r=entry.SetSize(aSize);
+		test(r==KErrNone);
+		entry.Close();
+		}
+	return(KErrNone);	
+	}
+
+LOCAL_C TInt DeleteStdEntry(const TDesC& aName,TBool aIsDir)
+//
+// Deletes entry with aName
+//
+	{
+	if(aIsDir)
+		return(TheFs.RmDir(aName));
+	else
+		return(TheFs.Delete(aName));
+	}
+
+LOCAL_C TInt CreateStdEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
+//
+// Creates entry with aName where the cluster chain grows contiguously
+//
+	{
+	TInt r=DeleteStdEntry(aName,aIsDir);
+	test(r==KErrNone||r==KErrNotFound);
+	if(aIsDir)
+		{
+		r=TheFs.MkDir(aName);
+		if(r==KErrNone)
+			ExpandDirectory(aName,aSize);
+		return(r);
+		}
+	else
+		{
+		RFile file;
+		r=file.Create(TheFs,aName,EFileShareAny);
+		if(r==KErrNone)
+			{
+			r=file.SetSize(aSize);
+			test(r==KErrNone);
+			}
+		else if(r==KErrAlreadyExists)
+			{
+			TInt res =file.Open(TheFs,aName,EFileShareAny);
+			test(res==KErrNone);
+			}
+		else
+			return(r);
+		file.Close();
+		return(r);
+		}
+	}
+
+LOCAL_C TInt CreateEntry(const TDesC& aName,TBool aIsDir,TFatChain aChain,TInt aSize)
+//
+// Creates entry with aName whose fat cluster chain characteristics determined by aChain
+//
+	{
+	switch(aChain)
+		{
+		case(EChainStd):return(CreateStdEntry(aName,aIsDir,aSize));
+		case(EChainAlternate):return(CreateAlternateEntry(aName,aIsDir,aSize));
+		case(EChainBackwards):return(CreateBackwardEntry(aName,aIsDir,aSize));
+		case(EChainForwards):return(CreateForwardEntry(aName,aIsDir,aSize));
+		default:return(KErrGeneral);
+		}
+	}
+
+LOCAL_C TInt DeleteEntry(const TDesC& aName,TBool aIsDir,TFatChain aChain)
+//
+// Delete entry with aName
+//
+	{
+	switch(aChain)
+		{
+		case(EChainStd):return(DeleteStdEntry(aName,aIsDir));
+		case(EChainAlternate):return(DeleteAlternateEntry(aName,aIsDir));
+		case(EChainBackwards):return(DeleteBackwardEntry(aName,aIsDir));
+		case(EChainForwards):return(DeleteForwardEntry(aName,aIsDir));
+		default:return(KErrGeneral);
+		}
+	}
+
+LOCAL_C void TestRFsDelete(const TDesC& aName,TFatChain aChain,TInt aFileSize)
+//
+// test RFs::Delete
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Start(_L("TestRFsDelete"));
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aName,EFalse,aChain,aFileSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		r=TheFs.Delete(aName);
+		if(r==KErrNone)
+			break;
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		++failCount;
+		}
+	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+	test(r==KErrNone);
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(!EntryExists(aName));
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFsRmDir(const TDesC& aName,TFatChain aChain,TInt aDirSize)
+//
+// test RFs::RmDir
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFsRmDir"));
+	switch (aChain)
+		{
+		case EChainStd:
+			RDebug::Print(_L("Chain Std %S size %d"), &aName, aDirSize);
+			break;
+		case EChainAlternate:
+			RDebug::Print(_L("Chain Alternate %S size %d"), &aName, aDirSize);
+			break;
+		case EChainBackwards:
+			RDebug::Print(_L("Chain Backwards %S size %d"), &aName, aDirSize);
+			break;
+		case EChainForwards:
+			RDebug::Print(_L("Chain Forwards %S size %d"), &aName, aDirSize);
+			break;
+		default:
+			break;
+		}
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aName,ETrue,aChain,aDirSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		r=TheFs.RmDir(aName);
+		if(r==KErrNone)
+			break;
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		RDebug::Print(_L("%6d: ScanDrive = %d"), __LINE__, r);
+		if (r != KErrNone)
+		{
+			RDebug::Print(_L("ScanDrive fail %d"), r);
+			DumpFat();
+			DumpData(NULL, 0, 200);
+		}
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		RDebug::Print(_L("%6d: CheckDisk = %d"), __LINE__, r);
+		test(r==KErrNone);
+		++failCount;
+		}
+	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+	test(r==KErrNone);
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(!EntryExists(aName));
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFsMkDir(const TDesC& aName)
+//
+// test RFs::MkDir
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFsMkDir"));
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=DeleteEntry(aName,ETrue,EChainStd);
+		test(r==KErrNone||r==KErrNotFound);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		r=TheFs.MkDir(aName);
+		if(r==KErrNone)
+			break;
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		++failCount;
+		}
+	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+	test(r==KErrNone);
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(aName));
+	r=DeleteEntry(aName,ETrue,EChainStd);
+	test(r==KErrNone);
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFsRename(const TDesC& aOldName,const TDesC& aNewName,TBool aIsDir,TFatChain aChain,TInt aSize)
+//
+// test RFs::Rename
+//
+	{
+	test.Next(_L("TestRFsRename"));
+	TInt failCount=TheFailCount;
+	TInt r;
+	TEntry oldEntryInfo,newEntryInfo;
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aOldName,aIsDir,aChain,aSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		r=DeleteEntry(aNewName,aIsDir,aChain);
+		test(r==KErrNone||r==KErrNotFound);
+		GetEntryDetails(aOldName,oldEntryInfo);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		r=TheFs.Rename(aOldName,aNewName);
+		if(r==KErrNone)
+			break;
+		if(r!=WriteFailValue)
+			{
+			test.Printf(_L("r=%d\n"),r);
+			test(EFalse);
+			}
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		// no start cluster if aSize==0
+		if(aSize!=0)
+			test(OneEntryExists(aOldName,aNewName));
+		++failCount;
+		}
+	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+	test(r==KErrNone);
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(aNewName) && !EntryExists(aOldName));
+	GetEntryDetails(aNewName,newEntryInfo);
+	test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
+	r=DeleteEntry(aNewName,aIsDir,aChain);
+	test(r==KErrNone);
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFsReplace(const TDesC& aOldName, const TDesC& aNewName,TBool aBothExist,TFatChain aChain,TInt aFileSize)
+//
+// test RFs::Replace
+//
+	{
+	
+	TInt failCount=TheFailCount;
+	TInt r;
+	if(aBothExist)
+		test.Next(_L("TestRFsReplace with new name existing"));
+	else
+		test.Next(_L("TestRFsReplace with new name not existing"));
+	TEntry oldEntryInfo,newEntryInfo;
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aOldName,EFalse,aChain,aFileSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		if(aBothExist)
+			{
+			r=CreateEntry(aNewName,EFalse,aChain,aFileSize);
+			test(r==KErrNone||r==KErrAlreadyExists);
+			}
+		else
+			{
+			r=DeleteEntry(aNewName,EFalse,aChain);
+			test(r==KErrNone||r==KErrNotFound);
+			}
+		GetEntryDetails(aOldName,oldEntryInfo);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		r=TheFs.Replace(aOldName,aNewName);
+		if(r==KErrNone)
+			break;
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		if(!aBothExist && aFileSize!=0)
+			test(OneEntryExists(aOldName,aNewName));
+		else if(aBothExist)
+			test(EntryExists(aOldName)||EntryExists(aNewName));
+		++failCount;
+		}
+	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+	test(r==KErrNone);
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(aNewName) && !EntryExists(aOldName));
+	GetEntryDetails(aNewName,newEntryInfo);
+	test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
+	r=DeleteEntry(aNewName,EFalse,aChain);
+	test(r==KErrNone);
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFileCreate(const TDesC& aName)
+//
+// test RFile::Create
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFileCreate"));
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=DeleteEntry(aName,EFalse,EChainStd);
+		test(r==KErrNone||r==KErrNotFound);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		RFile file;
+		r=file.Create(TheFs,aName,EFileShareAny);
+		if(r==KErrNone)
+			{
+			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+			test(r==KErrNone);
+			file.Close();
+			break;
+			}
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		++failCount;
+		}
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(aName));
+	r=DeleteEntry(aName,EFalse,EChainStd);
+	test(r==KErrNone);
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFileTemp(const TDesC& aPath)
+//
+// test RFile::Temp
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFileTemp"));
+	TFileName temp;
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		RFile file;
+ 		r=file.Temp(TheFs,aPath,temp,EFileShareAny);
+		if(r==KErrNone)
+			{
+			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+			test(r==KErrNone);
+			file.Close();
+			break;
+			}
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		++failCount;
+		}
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(temp));
+	r=DeleteEntry(temp,EFalse,EChainStd);
+	test(r==KErrNone);
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFileRename(const TDesC& aOldName, const TDesC& aNewName,TFatChain aChain,TInt aFileSize)
+//
+// test RFile::Rename
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFileRename"));
+	TEntry oldEntryInfo,newEntryInfo;
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aOldName,EFalse,aChain,aFileSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		r=DeleteEntry(aNewName,EFalse,aChain);
+		test(r==KErrNone||r==KErrNotFound);
+		GetEntryDetails(aOldName,oldEntryInfo);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		RFile file;
+		r=file.Open(TheFs,aOldName,EFileShareExclusive|EFileWrite);
+		test(r==KErrNone);
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		r=file.Rename(aNewName);
+		if(r==KErrNone)
+			{
+			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+			test(r==KErrNone);
+			file.Close();
+			break;
+			}
+		test(r==WriteFailValue);
+		file.Close();
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		if(aFileSize)
+			test(OneEntryExists(aOldName,aNewName));
+		++failCount;
+		}
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(aNewName) && !EntryExists(aOldName));
+	GetEntryDetails(aNewName,newEntryInfo);
+	test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
+	r=DeleteEntry(aNewName,EFalse,aChain);
+	test(r==KErrNone);
+	++TheOpNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFileReplace(const TDesC& aName,TBool aAlreadyExists,TFatChain aChain,TInt aFileSize)
+//
+// test RFile::Replace
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFileReplace"));
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		if(aAlreadyExists)
+			{
+			r=CreateEntry(aName,EFalse,aChain,aFileSize);
+			test(r==KErrNone||r==KErrAlreadyExists);
+			}
+		else
+			{
+			r=DeleteEntry(aName,EFalse,aChain);
+			test(r==KErrNone||r==KErrNotFound);
+			}
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		RFile file;
+		r=file.Replace(TheFs,aName,EFileShareAny);
+		if(r==KErrNone)
+			{
+			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+			test(r==KErrNone);
+			file.Close();
+			break;
+			}
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		++failCount;
+		}
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	test(EntryExists(aName));
+	r=DeleteEntry(aName,EFalse,aChain);
+	test(r==KErrNone);
+	if(!aAlreadyExists)
+		{
+		++TheOpNumber;
+		TheFailCount=0;
+		}
+	else
+		{
+		++TheFunctionNumber;
+		TheOpNumber=TheFailCount=0;
+		}
+	}
+
+LOCAL_C void TestRFileSetSize(const TDesC& aName,TFatChain aChain,TInt aOldFileSize,TInt aNewFileSize)
+//
+// test RFile::SetSize
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFileSetSize"));
+	test.Printf(_L("old size=%d new size=%d\n"),aOldFileSize,aNewFileSize);
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aName,EFalse,aChain,aOldFileSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		RFile file;
+		r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
+		test(r==KErrNone);
+		r=file.SetSize(aNewFileSize);
+		// close the file before testing the return value!
+		file.Close();
+		if(r==KErrNone)
+			{
+			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+			test(r==KErrNone);
+			file.Close();
+			break;
+			}
+		file.Close();
+		test(r==WriteFailValue);
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
+		test(r==KErrNone);
+		TInt size;
+		r=file.Size(size);
+		test(r==KErrNone);
+		test(size==aNewFileSize||size==aOldFileSize);
+		file.Close();
+		++failCount;
+		}
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	RFile file;
+	r=file.Open(TheFs,aName,EFileShareAny);
+	test(r==KErrNone);
+	TInt fileSize;
+	r=file.Size(fileSize);
+	test(r==KErrNone);
+	test(aNewFileSize==fileSize);
+	file.Close();
+	r=DeleteEntry(aName,EFalse,aChain);
+	test(r==KErrNone);
+	++TheFunctionNumber;
+	TheFailCount=0;
+	}
+
+LOCAL_C void TestRFileWrite(const TDesC& aName,TFatChain aChain,TInt aFileSize,TInt aPos,TInt aLength)
+//
+// test RFile::Write
+//
+	{
+	TInt failCount=TheFailCount;
+	TInt r;
+	test.Next(_L("TestRFileWrite"));
+	test.Printf(_L("aFileSize=%d,aPos=%d,aLength=%d\n"),aFileSize,aPos,aLength);
+	TInt newSize=(aFileSize>=aPos+aLength)?aFileSize:aPos+aLength;
+	HBufC8* desPtr;
+	desPtr=HBufC8::New(aLength);
+	test(desPtr!=NULL);
+	TPtr8 des=desPtr->Des();
+	des.SetLength(aLength);
+	InitialiseWriteBuffer(des);
+	FOREVER
+		{
+		test.Printf(_L("failCount=%d\n"),failCount);
+		r=CreateEntry(aName,EFalse,aChain,aFileSize);
+		test(r==KErrNone||r==KErrAlreadyExists);
+		if(IsReset)
+			{
+			++TheFailCount;
+			WriteLogFile();
+			}
+		r=SetWriteFailOn(failCount);
+		test(r==KErrNone);
+		RFile file;
+		r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
+		test(r==KErrNone);
+		r=file.Write(aPos,des,aLength);
+		if(r==KErrNone)
+			{
+			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
+			test(r==KErrNone);
+			file.Close();
+			break;
+			}
+		test(r==WriteFailValue);
+		file.Close();
+		r=TheFs.ScanDrive(gSessionPath);
+		test(r==KErrNone);
+		r=TheFs.CheckDisk(gSessionPath);
+		test(r==KErrNone);
+		file.Open(TheFs,aName,EFileShareAny);
+		test(r==KErrNone);
+		TInt fileSize;
+		r=file.Size(fileSize);
+		// with fair scheduling enabled it's possible for the file 
+		// size to grow even if the write appears to have failed...
+//		test(fileSize==aFileSize||fileSize==newSize);
+		test(fileSize>=aFileSize && fileSize <= newSize);
+
+		file.Close();
+		++failCount;
+		}
+	r=TheFs.CheckDisk(gSessionPath);
+	test(r==KErrNone);
+	RFile file;
+	r=file.Open(TheFs,aName,EFileShareAny);
+	test(r==KErrNone);
+	TInt fileSize;
+	r=file.Size(fileSize);
+	test(r==KErrNone);
+	test(newSize==fileSize);
+	HBufC8* desPtr2;
+	desPtr2=HBufC8::New(aLength);
+	test(desPtr2!=NULL);
+	TPtr8 des2=desPtr2->Des();
+	des2.SetLength(aLength);
+	r=file.Read(aPos,des2,des2.Length());
+	test(r==KErrNone);
+	r=des2.Compare(des);
+	test(r==0);
+	file.Close();
+	r=DeleteEntry(aName,EFalse,aChain);
+	test(r==KErrNone);
+	delete desPtr;
+	delete desPtr2;
+	++TheFunctionNumber;
+	TheFailCount=0;
+	}
+
+
+LOCAL_C void TestOperations(const TDesC& aOldName,const TDesC& aNewName,TFatChain aChain,TInt aFileSize, TInt aDirClusters)
+//
+// Tests the specified operations
+//
+	{
+	TFileName oldDirName=aOldName;
+	TFileName newDirName=aNewName;
+	// create directory for directory operations
+	oldDirName+=_L("\\");
+	newDirName+=_L("\\");
+	// locate path for RFile::Temp
+	TInt pathPos=aOldName.LocateReverse('\\')+1;
+	TFileName tempPath=aOldName.Left(pathPos);
+	test.Printf(_L("aOldName=%S\n"),&aOldName);
+	test.Printf(_L("aNewName=%S\n"),&aNewName);
+	test.Printf(_L("tempPath=%S\n"),&tempPath);
+	switch(TheOpNumber)
+		{
+		case(0):TestRFsDelete(aOldName,aChain,aFileSize);
+		case(1):TestRFsRmDir(oldDirName,aChain,aDirClusters);
+		case(2):TestRFsMkDir(oldDirName);
+		case(3):TestRFsRename(aOldName,aNewName,EFalse,aChain,aFileSize);
+		case(4):TestRFsRename(oldDirName,newDirName,ETrue,aChain,aDirClusters);
+		case(5):TestRFsReplace(aOldName,aNewName,EFalse,aChain,aFileSize);
+		case(6):TestRFsReplace(aOldName,aNewName,ETrue,aChain,aFileSize);
+		case(7):TestRFileCreate(aOldName);
+		case(8):TestRFileTemp(tempPath);
+		case(9):TestRFileRename(aOldName,aNewName,aChain,aFileSize);
+		case(10):TestRFileReplace(aOldName,EFalse,aChain,aFileSize);
+		case(11):TestRFileReplace(aOldName,ETrue,aChain,aFileSize);break;
+		default:test(EFalse);
+		}
+	test.End();
+	}
+
+LOCAL_C void TestOperation0()
+//
+//
+//
+	{
+	// tests entries in root directory
+	test.Next(_L("TestOperation0"));
+	TestOperations(_L("\\entryWithTwoVfats"),_L("\\anotherEntryWithTwo"),EChainStd,0,0);
+	}
+	
+LOCAL_C void TestOperation1()
+//
+//
+//
+	{
+	// tests entries in a full root directory
+	test.Next(_L("TestOperation1"));
+	if(TheFailCount==0)
+		FillUpRootDir(4);
+	TestOperations(_L("\\entryOne"),_L("\\entryTwo"),EChainStd,512,0);
+	UnFillUpRootDir(4);
+	}
+
+LOCAL_C void TestOperation2()
+//
+//
+//
+	{
+	// tests entries in same subdir
+	test.Next(_L("TestOperation2"));
+	TestOperations(_L("\\test\\subdir1\\NameWithFourVFatEntriesWaffle"),_L("\\test\\subdir1\\aEntry"),EChainAlternate,5120,1);
+	}
+
+
+LOCAL_C void TestOperation3()
+//
+//
+//
+	{
+	// tests entries in different subdir
+	test.Next(_L("TestOperation3"));
+	TestOperations(_L("\\test\\subdir1\\NameWithThreeEntries"),_L("\\ANother\\aEntrytwo"),EChainAlternate,15000,10);
+	}
+
+
+LOCAL_C void TestOperation4()
+//
+//
+//
+	{
+	// tests entries with cluster chain of EChainForwards
+	test.Next(_L("TestOperation4"));
+	TestOperations(_L("\\test\\subdir1\\aEntry"),_L("\\aEntry"),EChainForwards,12799,25);
+	}
+
+
+LOCAL_C void TestOperation5()
+//
+//
+//
+	{
+	// tests entries with cluster chain of EChainBackwards
+	test.Next(_L("TestOperation5"));
+	TestOperations(_L("\\test\\subdir1\\aEntry"),_L("\\ANother\\EntrywithThree"),EChainBackwards,51199,10);
+	}
+
+LOCAL_C void TestOperation6()
+//
+//
+//
+	{
+	// tests entries where old name has a very long name
+	test.Next(_L("TestOperation6"));
+	TFileName longName=_L("\\test\\subdir1\\");
+	MakeVeryLongName(longName);
+	TestOperations(longName,_L("\\ANother\\e1"),EChainAlternate,5100,0);
+	}
+
+LOCAL_C void TestOperation7()
+//
+//
+//
+	{
+	// tests entries where new name fills up subdir cluster
+	test.Next(_L("TestOperation7"));
+	TFileName name=_L("\\test\\subdir2\\");
+	// add entry with 7 vfat entries
+	MakeEntryName(name,80);
+	if(TheFailCount==0)
+		CreateEntry(name,EFalse,EChainStd,1);
+	TestOperations(_L("\\test\\subdir2\\EntryWithThree"),_L("\\test\\subdir2\\EntryWithThree-"),EChainStd,512,0);
+	DeleteEntry(name,EFalse,EChainStd);
+	}
+
+LOCAL_C void TestOperation8()
+//
+//
+//
+	{
+	// tests entries where new name is first entry in new subdir cluster
+	test.Next(_L("TestOperation8"));
+	TFileName name=_L("\\test\\subdir2\\");
+	// add entry with 10 vfat entries
+	MakeEntryName(name,125);
+	if(TheFailCount==0)
+		CreateEntry(name,EFalse,EChainStd,175000);
+	TestOperations(_L("\\test\\subdir2\\Entrywith3three"),_L("\\test\\subdir2\\entrywiththree-"),EChainStd,512,1);
+	DeleteEntry(name,EFalse,EChainStd);
+	}
+
+GLDEF_C void DoTests()
+	{
+	TInt r;
+	if(!IsReset && IsInternalRam())
+		{
+		test.Printf(_L("Error: Internal ram drive not tested\n"));
+		return;
+		}
+	if(!IsReset)
+		QuickFormat();
+
+	DoReadBootSector();
+	DumpBootSector();
+	ClearDiskData();
+
+	r=TheFs.SetSessionPath(gSessionPath);
+	test(r==KErrNone);
+
+	switch(TheFunctionNumber)
+		{
+		case(0):TestOperation0();
+		case(1):{
+				TestOperation1();
+				r=TheFs.MkDir(_L("\\fat\\"));
+				test(r==KErrNone);
+				r=TheFs.MkDir(_L("\\test\\"));
+				test(r==KErrNone);
+				r=TheFs.MkDir(_L("\\ANother\\"));
+				test(r==KErrNone);
+				r=TheFs.MkDir(_L("\\test\\subdir1\\"));
+				test(r==KErrNone);
+				r=TheFs.MkDir(_L("\\test\\subdir2\\"));
+				test(r==KErrNone);}
+		case(2):{
+				TestOperation2();
+				// add some filler files
+				CreateEntry(_L("\\test\\subdir1\\FillerOne"),EFalse,EChainStd,512);
+				CreateEntry(_L("\\test\\subdir1\\FillerTwo"),EFalse,EChainStd,1024);}
+		case(3):TestOperation3();
+		case(4):{
+				TestOperation4();
+				// add some filler files
+				CreateEntry(_L("\\ANother\\FillerThree"),EFalse,EChainStd,1536);
+				CreateEntry(_L("\\test\\subdir1\\FillerFour"),EFalse,EChainStd,2048);}
+		case(5):TestOperation5();
+		case(6):TestOperation6();
+		case(7):TestOperation7();
+		case(8):TestOperation8();
+		// increase size of file
+		case(9):TestRFileSetSize(_L("\\entry1"),EChainStd,0,512);
+		case(10):TestRFileSetSize(_L("\\entry1"),EChainAlternate,0,1025);
+		case(11):TestRFileSetSize(_L("\\entry1"),EChainStd,1,512);
+		// seek index (of CFatFileCB) resized
+		case(12):TestRFileSetSize(_L("\\entry1"),EChainForwards,512,66666);
+		// seek index resized
+		case(13):TestRFileSetSize(_L("\\entry1"),EChainBackwards,32779,131074);
+		// decrease size of file
+		// seek index resized
+		case(14):TestRFileSetSize(_L("\\entry1"),EChainForwards,133000,32768);
+		// seek index resized
+		case(15):TestRFileSetSize(_L("\\entry1"),EChainBackwards,65536,1);
+		// seek index resized
+		case(16):TestRFileSetSize(_L("\\entry1"),EChainAlternate,66554,0);
+		case(17):TestRFileSetSize(_L("\\entry1"),EChainStd,1024,1);
+		case(18):TestRFileSetSize(_L("\\entry1"),EChainAlternate,512,0);
+		case(19):TestRFileWrite(_L("\\entry2"),EChainStd,0,0,512);
+		case(20):TestRFileWrite(_L("\\entry2"),EChainAlternate,5120,512,1024);
+		case(21):TestRFileWrite(_L("\\entry2"),EChainForwards,3584,3584,5000);
+		case(22):TestRFileWrite(_L("\\entry2"),EChainBackwards,3000,2999,2000);
+		// seek index resized
+		case(23):TestRFileWrite(_L("\\entry2"),EChainBackwards,64000,64000,3000);
+		// seek index resized
+		case(24):TestRFileWrite(_L("\\entry2"),EChainForwards,131072,2,4000);break;
+		default:test(EFalse);
+		}
+	DeleteEntry(_L("\\test\\subdir1\\FillerFour"),EFalse,EChainStd);
+	DeleteEntry(_L("\\ANother\\FillerThree"),EFalse,EChainStd);
+	DeleteEntry(_L("\\test\\subdir1\\FillerTwo"),EFalse,EChainStd);
+	DeleteEntry(_L("\\test\\subdir1\\FillerOne"),EFalse,EChainStd);
+	r=TheFs.RmDir(_L("\\test\\subdir2\\"));
+	test(r==KErrNone);
+	r=TheFs.RmDir(_L("\\test\\subdir1\\"));
+	test(r==KErrNone);
+	r=TheFs.RmDir(_L("\\ANother\\"));
+	test(r==KErrNone);
+	r=TheFs.RmDir(_L("\\test\\"));
+	test(r==KErrNone);
+	r=TheFs.RmDir(_L("\\fat\\"));
+	test(r==KErrNone);
+	if (gFatBuf)
+		{
+		delete gFatBuf;
+		gFatBuf = NULL;
+		}
+	}
+#endif