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\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