Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32test\server\t_CHECKDISK.cpp
//
//
#define __E32TEST_EXTENSION__
#include <f32file.h>
#include <e32test.h>
//#include <e32svr.h>
//#include <f32dbg.h>
#include "t_server.h"
//#include <e32twin.h>
RTest test(_L("T_CHECKDISK"));
RFs TheFs;
TInt gDrive;
TFileName gSessionPath;
TChar gDriveToTest;
HBufC8* gBuf = NULL;
TPtr8 gBufReadPtr(NULL, 0);
HBufC8* gBufSec = NULL;
TPtr8 gBufWritePtr(NULL, 0);
const TInt KOneK = 1024;
const TInt KOneMeg = KOneK * 1024;
const TInt KBlockSize = KOneK * 129 ;
const TInt KWaitRequestsTableSize = 70;
TInt gBigFileSize = 0;
TInt gSmallFileSize = 0;
TInt64 gMediaSize = 0;
TBool gSkip=EFalse;
TInt writeSize = KBlockSize;
TInt seekSize = 0;
TSeek seekType = ESeekAddress;
TInt reduceSize = 0;
TTimeIntervalMicroSeconds32 gTimeTakenBigFile(0);
TBuf16<45> gSmallFile, gBigFile;
LOCAL_D TInt gNextFile=0;
TTime gTime1;
TTime gTime2;
LOCAL_D RSemaphore gSync;
// Concurrent Threads
RThread gBig;
RThread gSmall;
LOCAL_D RSemaphore client;
LOCAL_D const TInt KHeapSize=0x4000;
LOCAL_D const TInt KMaxHeapSize=0x100000;
TRequestStatus gStatus[KWaitRequestsTableSize];
enum TTestState
{
EThreadWait,
EThreadSignal,
ENoThreads
};
//
// Generates a name of the form FFFFF*<aPos>.TXT (aLong.3)
//
GLDEF_C void FileNameGen(TDes16& aBuffer, TInt aLong, TInt aPos)
{
TInt padding;
TInt i=0;
TBuf16<10> tempbuf;
_LIT(KNumber,"%d");
tempbuf.Format(KNumber,aPos);
padding=aLong-tempbuf.Size()/2;
aBuffer=_L("");
while(i<padding)
{
aBuffer.Append('F');
i++;
}
aBuffer.Append(tempbuf);
_LIT(KExtension1, ".TXT");
aBuffer.Append(KExtension1);
}
//
// Expects a drive letter as a parameter
//
LOCAL_C void parseCommandLine()
{
TBuf<0x100> cmd;
User::CommandLine(cmd);
TLex lex(cmd);
TPtrC token=lex.NextToken();
TInt r=0;
if(token.Length()!=0)
{
gDriveToTest=token[0];
gDriveToTest.UpperCase();
}
else
{
gDriveToTest='C';
}
r=TheFs.CharToDrive(gDriveToTest,gDrive);
test_KErrNone(r);
gSessionPath=_L("?:\\F32-TST\\");
gSessionPath[0]=(TText)gDriveToTest;
test.Printf(_L("\nCLP=%S\n"),&token);
}
//
// Fills a buffer with character aC
//
LOCAL_C void FillBuffer(TDes8& aBuffer, TInt aLength, TChar aC)
{
test (aBuffer.MaxLength() >= aLength);
for(TInt i=0; i<aLength; i++)
{
aBuffer.Append(aC);
}
}
//
// Waits for all the TRequestStatus in status[] to complete
//
LOCAL_C void WaitForAll(TRequestStatus status[], TInt aSize)
{
TInt i=0;
while(i<aSize)
{
User::WaitForRequest(status[i++]);
}
}
//
// Writes a file synchronously in blocks of aBlockSize size
// this function can be called from another thread, therefore requires its own RTest instance
LOCAL_C TInt WriteFile(RFs& fs, TDes16& aFile, TInt aSize, TInt aBlockSize, TTestState aState)
{
RTest test(_L(""));
TInt r=0;
RFile fileWrite;
test(aBlockSize>0); // Block size must be greater than 0
if(aState==EThreadWait)
{
gSync.Wait();
}
r=fileWrite.Replace(fs,aFile,EFileShareAny|EFileWrite);
test_KErrNone(r);
TInt j=0;
while(j<aSize)
{
r=fileWrite.Write(gBufWritePtr, writeSize);
test_KErrNone(r);
if(seekType)
{
r=fileWrite.Seek(seekType, seekSize);
test_KErrNone(r);
if (writeSize + reduceSize >= 0)
writeSize += reduceSize;
writeSize = Min(writeSize, gBufWritePtr.Length());
}
if((j==0)&&(aState==EThreadSignal))
{
gSync.Signal();
}
j+=aBlockSize;
}
fileWrite.Close();
return KErrNone;
}
LOCAL_C void IniStatus(TRequestStatus aStatus[], TInt aSize)
{
TInt i=0;
while(i<aSize)
{
aStatus[i++]=KRequestPending;
}
}
//
// Write big file
// This is a thread function, therefore requires its own RTest instance
LOCAL_C TInt WriteBigFile(TAny* )
{
RTest test(_L(""));
RFs fs;
TInt r=fs.Connect(gDriveToTest);
test_KErrNone(r);
r=fs.SetSessionPath(gSessionPath);
test_KErrNone(r);
WriteFile(fs, gBigFile, gBigFileSize, KBlockSize, EThreadSignal);
gTime1.HomeTime();
client.Signal();
return ETrue;
}
//
// Writes a file asynchronously in blocks of aBlockSize size
// this function can be called from another thread, therefore requires its own RTest instance
LOCAL_C void WriteFileAsync(RFs& fs, RFile& aFileWrite, TDes16& aFile, TInt aSize, TInt aBlockSize, TRequestStatus aStatus[])
{
RTest test(_L(""));
TInt r=0;
test(aBlockSize>0); // Block size must be greater than 0
test((aSize%aBlockSize)==0); // Ensure the size of the file is a multiple of the block size
r=aFileWrite.Replace(fs,aFile,EFileShareAny|EFileWrite);
test_KErrNone(r);
TInt j=0,i=0;
while(j<aSize)
{
aFileWrite.Write(gBufWritePtr,aStatus[i++]);
j+=aBlockSize;
}
}
//
// Write big file async
// This is a thread function, therefore requires its own RTest instance
LOCAL_C TInt WriteBigFileAsync(TAny* )
{
RTest test(_L(""));
RFs fs;
TInt r=fs.Connect(gDriveToTest);
test_KErrNone(r);
r=fs.SetSessionPath(gSessionPath);
test_KErrNone(r);
RFile bigFile;
IniStatus(gStatus,KWaitRequestsTableSize);
WriteFileAsync(fs, bigFile, gSmallFile, gBigFileSize, KBlockSize,gStatus);
gSync.Signal();
WaitForAll(gStatus, gBigFileSize/KBlockSize);
return ETrue;
}
static void TestClientDies()
{
test.Next(_L("Client dying unexpectedly"));
TInt r=0;
TBuf<20> unit=_L("?:\\");
unit[0]=(TText)gDriveToTest;
//-------------------------------------------
test.Printf(_L("Sync test\n"));
r=gBig.Create(_L("TEST1"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Async test\n"));
r=gSmall.Create(_L("TEST2"),WriteBigFileAsync,KDefaultStackSize*2,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gSmall.Resume();
gSync.Wait();
gSmall.Kill(-2);
gSmall.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing for size not multiple of blocksize\n"));
writeSize = 5000;
r=gBig.Create(_L("TEST3"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing with seek current and write inside the file boundary\n"));
writeSize = 5000;
seekType = ESeekCurrent;
seekSize = -5000;
reduceSize = -3000;
r=gBig.Create(_L("TEST4"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing with seek current and overwrite entire file\n"));
writeSize = 5000;
seekType = ESeekCurrent;
seekSize = -5000;
reduceSize = 0;
r=gBig.Create(_L("TEST5"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing with seek current and write outside the file boundary\n"));
writeSize = 5000;
seekType = ESeekCurrent;
seekSize = -5000;
reduceSize = 5000;
r=gBig.Create(_L("TEST6"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing with seek current and write within the file boundary\n"));
writeSize = 5000;
seekType = ESeekCurrent;
seekSize = -3000;
reduceSize = -4000;
r=gBig.Create(_L("TEST7"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing with seek current and write exactly to file size\n"));
writeSize = 5000;
seekType = ESeekCurrent;
seekSize = -3000;
reduceSize = -3000;
r=gBig.Create(_L("TEST8"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
//-------------------------------------------
test.Printf(_L("Testing with seek current and write greater than file size\n"));
writeSize = 5000;
seekType = ESeekCurrent;
seekSize = -3000;
reduceSize = 10000;
r=gBig.Create(_L("TEST9"),WriteBigFile,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
test_KErrNone(r);
gBig.Resume();
gSync.Wait();
gBig.Kill(-2);
gBig.Close();
User::After(500000);
r=TheFs.CheckDisk(unit);
test_Value(r, r == KErrNone || r == KErrNotSupported);
TInt retries = 0;
do
{
r=TheFs.ScanDrive(unit);
if (r != KErrNone)
test.Printf(_L("ScanDrive() returned %d\n"), r);
if (r == KErrInUse)
User::After(500000);
}
while (r == KErrInUse && ++retries < 5);
test_Value(r, r == KErrNone || r == KErrNotSupported);
}
//---------------------------------------------------------------------
/**
Test that CheckDisk will not cause stack overflow on very deep directory structure.
*/
void TestCheckDisk_VeryDeepDirectory()
{
test.Next(_L("Testing deep dir structure check"));
TInt nRes;
TBuf<20> unit=_L("?:\\");
unit[0]=(TText)gDriveToTest;
//-- 1. create deep dir structure, like \\0\\1\\2\\...... 90 levels deep
const TInt KMaxDirDepth = 90;
test.Printf(_L("Creating directory with %d subdirs.\n"),KMaxDirDepth);
TFileName fn;
for(TInt i=0; i<KMaxDirDepth; ++i)
{
fn.AppendFormat(_L("\\%d"), i%10);
}
fn.Append(_L("\\"));
nRes = TheFs.MkDirAll(fn);
test_Value(nRes, nRes == KErrNone || nRes == KErrAlreadyExists);
//-- 2. invoke Check Disk and ensure that target doesn't die from stack overflow.
test.Printf(_L("Running Check Disk...\n"));
nRes = TheFs.CheckDisk(unit);
test_Value(nRes, nRes == KErrNone || nRes == KErrTooBig);
}
//---------------------------------------------------------------------
//
// This test tries to read a small file while writing a big one
//
GLDEF_C void CallTestsL()
{
TBuf16<45> dir;
test.Next(_L("Preparing the environmnet\n"));
FileNameGen(gSmallFile, 8, gNextFile++);
FileNameGen(gBigFile, 8, gNextFile++);
dir=gSessionPath;
dir.Append(gSmallFile);
gSmallFile=dir;
dir=gSessionPath;
dir.Append(gBigFile);
gBigFile=dir;
TRAPD(res,gBuf = HBufC8::NewL(KBlockSize+1));
test(res == KErrNone && gBuf != NULL);
gBufWritePtr.Set(gBuf->Des());
FillBuffer(gBufWritePtr, KBlockSize, 'B');
TRAPD(res2,gBufSec = HBufC8::NewL(KBlockSize+1));
test(res2 == KErrNone && gBufSec != NULL);
gBufReadPtr.Set(gBufSec->Des());
//---------------------------
TestClientDies();
TestCheckDisk_VeryDeepDirectory();
delete gBuf;
delete gBufSec;
}
LOCAL_C void DoTests()
{
TInt r=0;
r=client.CreateLocal(0);
test_KErrNone(r);
r=gSync.CreateLocal(0);
test_KErrNone(r);
r=TheFs.SetSessionPath(gSessionPath);
test_KErrNone(r);
r=TheFs.MkDirAll(gSessionPath);
test_Value(r, r == KErrNone || r == KErrAlreadyExists);
TheFs.ResourceCountMarkStart();
TRAP(r,CallTestsL());
test_KErrNone(r);
TheFs.ResourceCountMarkEnd();
}
TBool CheckForDiskSize()
{
TVolumeInfo volInfo;
TInt r = TheFs.Volume(volInfo, gDrive);
test_KErrNone(r);
gMediaSize = volInfo.iSize;
gSmallFileSize = KBlockSize;
gBigFileSize = KBlockSize*20;
while(((2*gBigFileSize)+KOneMeg) > gMediaSize )
{
gBigFileSize -= (2*KBlockSize);
}
if(gBigFileSize< (3*gSmallFileSize))
return EFalse;
else
return ETrue;
}
void Format(TInt aDrive)
{
test.Next(_L("Format"));
TBuf<4> driveBuf=_L("?:\\");
driveBuf[0]=(TText)(aDrive+'A');
RFormat format;
TInt count;
TInt r=format.Open(TheFs,driveBuf,EQuickFormat,count);
test_KErrNone(r);
while(count)
{
TInt r=format.Next(count);
test_KErrNone(r);
}
format.Close();
}
static TBool IsFAT(RFs &aFsSession, TInt aDrive)
{
_LIT(KFatName, "Fat");
TFileName f;
TInt r = aFsSession.FileSystemName(f, aDrive);
test_Value(r, r == KErrNone || r == KErrNotFound);
return (f.CompareF(KFatName) == 0);
}
GLDEF_C TInt E32Main()
{
CTrapCleanup* cleanup;
cleanup=CTrapCleanup::New();
__UHEAP_MARK;
test.Title();
test.Start(_L("Starting tests..."));
parseCommandLine();
TInt r = TheFs.Connect();
test_KErrNone(r);
TDriveInfo info;
TVolumeInfo volInfo;
r=TheFs.Drive(info,gDrive);
test_KErrNone(r);
if(info.iMediaAtt&KMediaAttVariableSize)
{// Not testing in RAM Drives
test.Printf(_L("Tests skipped in RAM drive\n"));
goto out;
}
r = TheFs.Volume(volInfo, gDrive);
if (r == KErrNotReady)
{
if (info.iType == EMediaNotPresent)
test.Printf(_L("%c: Medium not present - cannot perform test.\n"), (TUint)gDriveToTest);
else
test.Printf(_L("%c: medium found (type %d) but drive not ready\nPrevious test may have hung; else, check hardware.\n"), (TUint)gDriveToTest, (TInt)info.iType);
}
else if (r == KErrCorrupt)
{
test.Printf(_L("%c: Media corruption; previous test may have aborted; else, check hardware\n"), (TUint)gDriveToTest);
}
test_KErrNone(r);
if(!IsFAT(TheFs, gDrive))
{
test.Printf(_L("Tests skipped on non-FAT drive\n"));
goto out;
}
if ((volInfo.iDrive.iMediaAtt & KMediaAttFormattable))
Format(gDrive);
if(CheckForDiskSize())
{
DoTests();
if ((volInfo.iDrive.iMediaAtt & KMediaAttFormattable))
Format(gDrive);
}
else
{
test.Printf(_L("Skipping tests due to lack of space to perform them in this unit\n"));
}
out:
test.End();
TheFs.Close();
test.Close();
__UHEAP_MARKEND;
delete cleanup;
return(KErrNone);
}