--- /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);
+ }