kerneltest/f32test/filesystem/fat/t_checkdisk.cpp
changeset 0 a41df078684a
child 245 647ab20fee2e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/filesystem/fat/t_checkdisk.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,677 @@
+// 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);
+    }