diff -r 000000000000 -r a41df078684a kerneltest/f32test/server/t_dspace.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/server/t_dspace.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,1763 @@ +// 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\server\t_dspace.cpp +// +// + +#include +#include +#include "t_server.h" +#include "t_chlffs.h" + + +/* This tests disk space notification. Using RFs::NotifyDiskSpace a client can request +to be notified if the free disk space crosses a specified threshold. This test requires +a card to be present in d: */ + +GLDEF_D RTest test(_L("T_DSPACE")); + +const TInt KMaxBufSize=512; +#if defined(__WINS__) +TInt KFileSize1=2048; +TInt KFileSize2=4096; +TInt KFileSize3=8192; +#else +TInt KFileSize1=512; +TInt KFileSize2=1024; +TInt KFileSize3=4096; +#endif + +const TInt KHeapSize=0x2000; +const TInt KStackSize=0x4000; + +TInt gMinFileSize; + +TBool LffsDrive = EFalse; + +TBuf8 TheBuffer; +TInt64 TheDiskSize; +TInt RemovableDrive; +TBuf<4> RemovableDriveBuf=_L("?:\\"); + +_LIT(KTestFile1, "\\F32-TST\\testfile1"); +_LIT(KTestFile2, "\\F32-TST\\testFile2"); +_LIT(KTestDir1, "\\F32-TST\\testDir1\\"); +_LIT(KTestDir2, "\\F32-TST\\testDir2\\"); +_LIT(KFileFiller, "\\F32-TST\\fileFiller"); + +// functions that may cause change in free disk space +// not all of them of tested since some require knowledge of file system +// to ensure change in free disk space +enum TThreadTask + { + ETaskSetVolume, + ETaskMkDir, + ETaskRmDir, + ETaskDelete, // test + ETaskRename, + ETaskReplace, // test + ETaskFileCreate, + ETaskFileReplace, // test + ETaskFileTemp, + ETaskFileWrite, // test + ETaskFileWrite4KB, + ETaskFileWrite64KB, + ETaskFileSetSize, // test + ETaskFileRename, + ETaskNoChange1, + ETaskNoChange2, + ETaskFileCreateLffs,// test + ETaskSpin + }; + + +LOCAL_C TBool IsWinsCDrive(TInt aDrive) +// +// +// + { +#if defined(__WINS__) + if(aDrive==KDefaultDrive) + return(gSessionPath[0]==(TText)'C'); + else + return(aDrive==EDriveC); +#else + return(EFalse); +#endif + } + +LOCAL_C TInt64 FreeDiskSpace(TInt aDrive) +// +// +// + { + TVolumeInfo v; + TInt r=TheFs.Volume(v,aDrive); + test(r==KErrNone); + return(v.iFree); + } + +LOCAL_C TInt64 DiskSize(TInt aDrive) +// +// +// + { + TVolumeInfo v; + TInt r=TheFs.Volume(v,aDrive); + test(r==KErrNone); + return(v.iSize); + } + +// MinimumFileSize() - +// Deduces the minimum space occupied by a file by creating a file of one byte +// in length. This should equal the cluster size on FAT volumes. +// +LOCAL_C TInt MinimumFileSize(TInt aDrive) + { + TInt r = TheFs.Delete(KTestFile1); + test(r==KErrNone || r==KErrNotFound); + + TInt64 freeSpace = FreeDiskSpace(aDrive); + + RFile file; + + + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + + r = file.Write(TheBuffer,1); + test(r==KErrNone); + file.Close(); + TInt64 newSpace = FreeDiskSpace(aDrive); + + r = TheFs.Delete(KTestFile1); + test(r==KErrNone); + + + TInt64 minFileSize = freeSpace - newSpace; + test (minFileSize >= 0); + minFileSize = Max(minFileSize, 512); + test (minFileSize < KMaxTInt); + + TInt minFileSizeLow = I64LOW(minFileSize); + + RDebug::Print(_L("minFileSize %u"), minFileSizeLow); + +#if defined(__WINS__) + KFileSize1 = minFileSizeLow << 2; // 512 * 2^2 = 512 * 4 = 2048; + KFileSize2 = minFileSizeLow << 3; // 512 * 2^3 = 512 * 8 = 4096; + KFileSize3 = minFileSizeLow << 4; // 512 * 2^4 = 512 * 16 = 8192; +#else + KFileSize1 = minFileSizeLow; // 512; + KFileSize2 = minFileSizeLow << 1; // 512 * 2^1 = 512 * 2 = 1024; + KFileSize3 = minFileSizeLow << 3; // 512 * 2^3 = 512 * 8 = 4096; +#endif + + + return (TInt) minFileSizeLow; + } + +LOCAL_C void Initialise() +// +// do any initialisation before starting tests +// + { + if(TheBuffer.Length()!=KMaxBufSize) + { + TheBuffer.SetLength(KMaxBufSize); + Mem::Fill((void*)TheBuffer.Ptr(),KMaxBufSize,0xab); + } + TheDiskSize=DiskSize(KDefaultDrive); +#if defined(__WINS__) + RemovableDrive=EDriveX; +#else + TDriveList drvList; + if(KErrNone == TheFs.DriveList(drvList)) + { + TInt i; + //should be successful, otherwise it means a system w/o any drive!!! + for(i=0;i\n\n\n")); + test.Printf(_L("RemovableDrive = %d\n"),RemovableDrive); + // initialise removable drive descriptor + TChar c; + TInt r=RFs::DriveToChar(RemovableDrive,c); + test(r==KErrNone); + RemovableDriveBuf[0]=(TText)c; + + if( !LffsDrive ) + { + // and create the default directory + TFileName d=gSessionPath; + d[0]=RemovableDriveBuf[0]; + MakeDir(d); + } + + // better format the default drive as long as not WINS c drive + TInt drive; + r= RFs::CharToDrive(gSessionPath[0],drive); + test(r==KErrNone); +#if defined(__WINS__) + if(drive!=EDriveC) + Format(drive); +#else + Format(drive); + // test not run on c: drive but does use it + Format(EDriveC); +#endif + // and set the default directory + r=TheFs.MkDirAll(gSessionPath); + test(r==KErrNone || r==KErrAlreadyExists); + + r=TheFs.Delete(KFileFiller); + test(r==KErrNone || r==KErrNotFound); + r=TheFs.Delete(KTestFile1); + test(r==KErrNone || r==KErrNotFound); + r=TheFs.Delete(KTestFile2); + test(r==KErrNone || r==KErrNotFound); + r=TheFs.RmDir(KTestDir1); + test(r==KErrNone || r==KErrNotFound); + r=TheFs.RmDir(KTestDir2); + test(r==KErrNone || r==KErrNotFound); + + gMinFileSize = MinimumFileSize(drive); + } + +LOCAL_C TInt64 FillDisk(RFile& aFile,TInt64 aNewSpace,TInt aDrive) +// +// fill a file until free disk space equals aFreeSpace +// + { + TInt64 space=FreeDiskSpace(aDrive); + test(space>aNewSpace); + while(space>aNewSpace) + { + TInt s=Min(KMaxBufSize, I64INT(space-aNewSpace)); + TInt r=aFile.Write(TheBuffer,s); + if( !LffsDrive ) + { + test(r==KErrNone); + } + else + { + // + // LFFS is less predictable than a normal drive because of the logging + // and metadata arrangement + // + test( (KErrNone==r) || (KErrDiskFull==r) ); + if( KErrDiskFull == r ) + { + // shrink the file back down again to give the requested free space + TInt fileSize; + r=aFile.Size( fileSize ); + test( KErrNone == r ); + test( TInt64(fileSize) > aNewSpace ); + fileSize -= I64LOW(aNewSpace); + r=aFile.SetSize( fileSize ); + test( KErrNone == r ); + + space=FreeDiskSpace(aDrive); + while( space < aNewSpace ) + { + fileSize -= I64LOW(aNewSpace - space); + test( fileSize > 0 ); + r=aFile.SetSize( fileSize ); + test( KErrNone == r ); + space=FreeDiskSpace(aDrive); + } + break; + } + } + + space=FreeDiskSpace(aDrive); + } + return(space); + } + +LOCAL_C void WriteToFile(RFile& aFile,TInt aSize) +// +// +// + { + while(aSize>0) + { + TInt s=Min(KMaxBufSize,aSize); + TInt r=aFile.Write(TheBuffer,s); + aSize-=s; + + // Flush if write caching enabled to ensure we get disk space notifications + if ((gDriveCacheFlags & EFileCacheWriteOn) && (r == KErrNone)) + r = aFile.Flush(); + + if( !LffsDrive ) + { + test(r==KErrNone); + } + else + { + // we can't accurately predict the amount of data we can actually get + // on an LFFS drive, so it's posible we could exceed the available + // space even though we are writing less that the reported free space + test( (KErrNone==r) || (KErrDiskFull==r) ); + if( KErrDiskFull == r ) + { + break; // just stop + } + } + } + } + + +LOCAL_C void CleanupForThread(TInt aTask) +// +// +// + { + TInt r; + switch(aTask) + { + case ETaskMkDir: + r=TheFs.RmDir(KTestDir1); + test(r==KErrNone); + break; + case ETaskRmDir: break; + case ETaskDelete: break; + case ETaskReplace: + r=TheFs.Delete(KTestFile2); + test(r==KErrNone); + break; + case ETaskFileReplace: + r=TheFs.Delete(KTestFile1); + test(r==KErrNone); + break; + case ETaskFileWrite: + case ETaskFileWrite4KB: + case ETaskFileWrite64KB: + case ETaskFileSetSize: + case ETaskFileCreateLffs: + case ETaskNoChange1: + case ETaskNoChange2: + r=TheFs.Delete(KTestFile1); + if(r!=KErrNone) + { + test.Printf(_L("r=%d"),r); + test(EFalse); + } + break; + case ETaskSpin: + default:break; + } + } + +LOCAL_C void InitialiseForThread(TInt aTask) +// +// +// + { + TInt r; + RFile file,file2; + switch(aTask) + { + case ETaskMkDir: break; + case ETaskRmDir: + r=TheFs.MkDir(KTestDir1); + test(r==KErrNone); + break; + case ETaskDelete: + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + if( !LffsDrive ) + { + r=file.SetSize(KFileSize1); + test(r==KErrNone); + } + else + { + // LFFS supports sparse files, so we have to write real data + // into the file to ensure that it uses up disk space + WriteToFile( file, KFileSize1 ); + } + file.Close(); + break; + case ETaskReplace: + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + if( !LffsDrive ) + { + r=file.SetSize(KFileSize1); + test(r==KErrNone); + } + else + { + WriteToFile( file, KFileSize2 ); + } + file.Close(); + r=file2.Create(TheFs,KTestFile2,EFileShareAny|EFileWrite); + test(r==KErrNone); + if( !LffsDrive ) + { + r=file2.SetSize(KFileSize3); + test(r==KErrNone); + } + else + { + WriteToFile( file2, gMinFileSize << 4); // 512 * 16 = 8K + } + file2.Close(); + break; + case ETaskFileReplace: + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + if( !LffsDrive ) + { + r=file.SetSize(KFileSize3*2); + } + else + { + WriteToFile( file, KFileSize3 ); + } + test(r==KErrNone); + file.Close(); + break; + case ETaskFileWrite: + case ETaskFileWrite4KB: + case ETaskFileWrite64KB: + case ETaskFileSetSize: + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + file.Close(); + break; + case ETaskNoChange1: + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + if( !LffsDrive ) + { + r=file.SetSize(KFileSize1); + test(r==KErrNone); + } + else + { + WriteToFile( file, KFileSize1 ); + } + file.Close(); + break; + case ETaskNoChange2: + r=file.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + file.Close(); + break; + case ETaskFileCreateLffs: + r = TheFs.Delete(KTestFile1); + break; + case ETaskSpin: + default:break; + } + } + +LOCAL_C TInt ThreadFunction(TAny* aThreadTask) +// +// +// + { + RTest test(_L("T_DSPACE_ThreadFunction")); + RFs fs; + TInt r=fs.Connect(); + test(r==KErrNone); + r=fs.SetSessionPath(gSessionPath); + test(r==KErrNone); + TThreadTask task=*(TThreadTask*)&aThreadTask; + RFile file; + switch(task) + { + case ETaskMkDir: + r=fs.MkDir(KTestDir1); + test(r==KErrNone); + break; + case ETaskRmDir: + r=fs.RmDir(KTestDir1); + test(r==KErrNone); + break; + case ETaskDelete: + r=fs.Delete(KTestFile1); + test(r==KErrNone); + break; + case ETaskReplace: + r=fs.Replace(KTestFile1,KTestFile2); + test(r==KErrNone); + break; + case ETaskFileReplace: + r=file.Replace(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + file.Close(); + break; + case ETaskFileWrite: + r=file.Open(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); +#if defined(__WINS__) + WriteToFile( file, gMinFileSize << 4); // 512 * 16 = 8K +#else + WriteToFile( file, gMinFileSize << 1); // 512 * 2 = 1K +#endif + file.Close(); + break; + case ETaskFileWrite4KB: + r=file.Open(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + WriteToFile(file,gMinFileSize << 3); // 512 * 2^3 = 512 * 8 = 4K + file.Close(); + break; + case ETaskFileWrite64KB: + r=file.Open(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + WriteToFile(file,gMinFileSize<<7); // 512 * 2^7 = 512 * 128 = 64K + file.Close(); + break; + case ETaskFileSetSize: + r=file.Open(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + r=file.SetSize(KFileSize3); + file.Close(); + break; + case ETaskFileCreateLffs: + r=file.Create(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + file.Close(); + break; + case ETaskNoChange1: + { + r=file.Open(fs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + TTime time; + time.HomeTime(); + r=file.SetModified(time); + test(r==KErrNone); + file.Close(); + break; + } + case ETaskNoChange2: + { + TEntry e; + r=fs.Entry(KTestFile1,e); + test(r==KErrNone); + break; + } + case ETaskSpin: + for(;;) {}; + + default:break; + } + fs.Close(); + return(KErrNone); + } + + +void TestCancellation() +// +// test error disk space notification requests can be cancelled +// + { + test.Next(_L("test disk space cancellation")); + const TInt ThresholdSize=500; + // test a cancellation + // Up the priority of this thread so that we can cancel the request before the drive thread + // runs, to test whether cancelling still works. + RThread().SetPriority(EPriorityRealTime); + TRequestStatus stat1; + TheFs.NotifyDiskSpace(ThresholdSize,KDefaultDrive,stat1); + test(stat1==KRequestPending); + TheFs.NotifyDiskSpaceCancel(stat1); + test(stat1==KErrCancel); + RThread().SetPriority(EPriorityNormal); + // test no affect if already cancelled + stat1=KErrNone; + TheFs.NotifyDiskSpaceCancel(stat1); + test(stat1==KErrNone); + // set up two requests, cancel 1 + TRequestStatus stat2; + TheFs.NotifyDiskSpace(ThresholdSize,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(ThresholdSize,KDefaultDrive,stat2); + test(stat1==KRequestPending && stat2==KRequestPending); + TheFs.NotifyDiskSpaceCancel(stat2); + test(stat1==KRequestPending && stat2==KErrCancel); + TheFs.NotifyDiskSpaceCancel(stat1); + test(stat1==KErrCancel); + + if( !LffsDrive) + { + // now repeat with c: and removable drive + TheFs.NotifyDiskSpace(ThresholdSize,EDriveC,stat1); + TheFs.NotifyDiskSpace(ThresholdSize,RemovableDrive,stat2); + test(stat1==KRequestPending && stat2==KRequestPending); + TheFs.NotifyDiskSpaceCancel(stat1); + test(stat2==KRequestPending && stat1==KErrCancel); + TheFs.NotifyDiskSpaceCancel(stat2); + test(stat2==KErrCancel); + } + } + +void TestErrorConditions() +// +// test disk space notification requests return correct error value +// + { + test.Next(_L("test error conditions")); + // attempt to set up disk space notification with a threshold of zero + TRequestStatus status; + TheFs.NotifyDiskSpace(0,KDefaultDrive,status); + test(status==KErrArgument); + // test on an empty drive + TheFs.NotifyDiskSpace(100,EDriveO,status); + test(status==KErrNotReady); + // test on a drive out of rance + TheFs.NotifyDiskSpace(100,27,status); + test(status==KErrBadName); + // new setup with threshold of one + TheFs.NotifyDiskSpace(1,KDefaultDrive,status); + test(status==KRequestPending); + TheFs.NotifyDiskSpaceCancel(status); + test(status==KErrCancel); + // and with a threshold > disk size + TheFs.NotifyDiskSpace(TheDiskSize+10,KDefaultDrive,status); + test(status==KErrArgument); + // now with a size of max size -1 + TheFs.NotifyDiskSpace(TheDiskSize-1,KDefaultDrive,status); + test(status==KRequestPending); + TheFs.NotifyDiskSpaceCancel(status); + test(status==KErrCancel); + // set up mutiple requests and cancel one + TRequestStatus status2,status3; + TheFs.NotifyDiskSpace(TheDiskSize-10,KDefaultDrive,status); + TheFs.NotifyDiskSpace(TheDiskSize-10,KDefaultDrive,status2); + TheFs.NotifyDiskSpace(TheDiskSize-10,KDefaultDrive,status3); + test(status==KRequestPending&&status2==KRequestPending&&status3==KRequestPending); + TheFs.NotifyDiskSpaceCancel(status3); + test(status==KRequestPending&&status2==KRequestPending&&status3==KErrCancel); + // cancel the remaining ones + TheFs.NotifyDiskSpaceCancel(); + test(status==KErrCancel&&status2==KErrCancel&&status3==KErrCancel); + } + +TInt GenerateMediaChange() + { + RLocalDrive d; + TBool flag=EFalse; + //Find the local drive number corresponding to removabledrive + TMediaSerialNumber serialNum; + TInt r = TheFs.GetMediaSerialNumber(serialNum, RemovableDrive); + if(r!= KErrNone) + return r; + + TInt len = serialNum.Length(); + test.Printf(_L("Serial number (len %d) :"), len); + + TInt localDriveNum = -1; + for (TInt n=0; nthreshold); + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + + // check for replace with threshold too high + test.Next(_L("check RFs::Replace with threshold too high")); + + if( LffsDrive ) + { + test.Printf( _L("Skipped.... test isn't consistent on LFFS drive\n") ); + } + else + { + task=ETaskReplace; + InitialiseForThread(task); + free=FreeDiskSpace(KDefaultDrive); + #if defined(__WINS__) + threshold=free + gMinFileSize * 16 + 2048; // 512 * 16 + 2K = 10K + #else + if(LffsDrive ) + threshold=free + (gMinFileSize << 4) + 2048; // 512 * 16 + 2K = 10K + else + threshold=free + gMinFileSize * 9 + 392; // 512 * 9 + 392 = 5000; + #endif + + TheFs.NotifyDiskSpace(threshold,KDefaultDrive,stat1); + test(stat1==KRequestPending); + + r=thread.Create(_L("thread5"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.Resume(); + + User::After(1000000); + test(stat1==KRequestPending); + newFree=FreeDiskSpace(KDefaultDrive); + test(newFreethreshold); + } + + // check that CSessionFS::iTheDrive is set in subsession calls + test.Next(_L("Check iTheDrive and subsessions")); + if( LffsDrive ) + { + test.Printf( _L("Skipped.... test not done on LFFS drive\n") ); + } + else + { + RFile f2; +#if defined(__WINS__) + _LIT(someFile,"X:\\abcdef"); +#else + TBuf<10> someFile=_L("?:\\abcdef"); + TChar c; + TInt r=RFs::DriveToChar(RemovableDrive,c); + test(r==KErrNone); + someFile[0]=(TText)c; +#endif + _LIT(someDir,"C:\\1234\\"); + + r=f2.Create(TheFs,someFile,EFileShareAny|EFileWrite); + test(r==KErrNone); + r=TheFs.MkDir(someDir); + test(r==KErrNone); + TRequestStatus stat2; + TInt64 freeC=FreeDiskSpace(EDriveC); + TInt64 freeD=FreeDiskSpace(RemovableDrive); + TheFs.NotifyDiskSpace(freeC-4097,EDriveC,stat1); + TheFs.NotifyDiskSpace(freeD-4097,RemovableDrive,stat2); + test(stat1==KRequestPending && stat2==KRequestPending); + // before fix this would result in iTheDrive not being updated in next subsession call + // therefore this could would not result in a disk space notification + r=f2.SetSize(8192); + test(r==KErrNone); + User::After(1000000); + User::WaitForRequest(stat2); + + if (stat2!=KErrNone) + test.Printf(_L("stat2=%d\n"),stat2.Int()); + test(stat2==KErrNone); + if (stat1!=KRequestPending) + test.Printf(_L("stat1=%d\n"),stat1.Int()); + test(stat1==KRequestPending); + + f2.Close(); + TheFs.NotifyDiskSpaceCancel(); + test(stat1==KErrCancel); + r=TheFs.Delete(someFile); + test(r==KErrNone); + r=TheFs.RmDir(someDir); + test(r==KErrNone); + } + + file.Close(); + r=TheFs.Delete(KFileFiller); + test(r==KErrNone); + } + + + +void TestLffsFunctions() +// +// LFFS-specific tests for some functions which may cause a disk +// space change +// +// + { + test.Next(_L("test LFFS disk space functions")); + // create the filler file + RFile file; + TInt r=file.Create(TheFs,KFileFiller,EFileShareAny|EFileWrite|EFileWriteDirectIO); + test(r==KErrNone); + TInt64 newSpace = FreeDiskSpace(KDefaultDrive)-8192; + FillDisk(file,newSpace,KDefaultDrive); + + + // check file create + // Creating a file will always allocate space for the inode + test.Next(_L("check RFile:Create")); + TThreadTask task=ETaskFileCreateLffs; + InitialiseForThread(task); + TInt64 free=FreeDiskSpace(KDefaultDrive); + TInt64 threshold1=free-64; + TInt64 threshold2=free-KFileSize3; + TRequestStatus stat1, stat2; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + test(stat1==KRequestPending && stat2==KRequestPending); + RThread thread; + r=thread.Create(_L("thread7"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + TRequestStatus deathStat; + thread.Logon( deathStat ); + thread.Resume(); + User::WaitForRequest(stat1); + test(stat1==KErrNone); + free=FreeDiskSpace(KDefaultDrive); + test(freethreshold2); + TheFs.NotifyDiskSpaceCancel(stat2); + User::WaitForRequest(stat2); + test(stat2==KErrCancel); + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + + TInt64 threshold3; + TRequestStatus stat3; + RFile file2; + // don't test for wins urel since cant use RFs::ControlIo +#if defined(_DEBUG) + // check background thread notification + test.Next(_L("check Background thread notification")); + task=ETaskSpin; // create thread to block background thread + InitialiseForThread(task); + free=FreeDiskSpace(KDefaultDrive); + threshold1=free-64; // this should occur when we create test file + threshold2=free+9750; // some impossible value + threshold3=free+10000; // some other impossible value that will never happen + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + TheFs.NotifyDiskSpace(threshold3,KDefaultDrive,stat3); + test(stat1==KRequestPending && stat2==KRequestPending && stat3==KRequestPending); + r=thread.Create(_L("thread8"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.SetPriority( EPriorityLess ); + thread.Resume(); // start spinning, blocks background thread + // request background thread to notify a daft value + TPckgBuf cBuf; + cBuf() = threshold2; + // Hard code the value of ECioBackgroundNotifyDiskSize. + // Although the value is enumerated in f32\slffs\lffs_controlio.h this header file is being + // removed from the release codeline but retained in the base team development codeline. + #define ECioBackgroundNotifyDiskSize 10016 + r = TheFs.ControlIo(GetDriveLFFS(), ECioBackgroundNotifyDiskSize, cBuf); + test( KErrNone==r ); + // create a file to force some roll-forward + r=file2.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + User::WaitForRequest(stat1); + test(stat1==KErrNone); + test(stat2==KRequestPending); + test(stat3==KRequestPending); + // kill the spinner thread to allow the background thread to execute + thread.Kill(KErrNone); + User::WaitForRequest( deathStat ); + thread.Close(); + // wait for the notifier + User::WaitForRequest(stat2); + test( stat2==KErrNone ); + test( stat3==KRequestPending); + TheFs.NotifyDiskSpaceCancel(stat3); + User::WaitForRequest(stat3); + test(stat3==KErrCancel); + CleanupForThread(task); + file2.Close(); + TheFs.Delete( KTestFile1 ); +#endif + + // check background thread notification again, this time we won't request + // a special value - check that it notifies normally + test.Next(_L("check Background thread notification again")); + task=ETaskSpin; // create thread to block background thread + InitialiseForThread(task); + free=FreeDiskSpace(KDefaultDrive); + threshold1=free-64; // this should occur when we create test file + threshold2=free+9750; // some impossible value + threshold3=free+10000; // some other impossible value that will never happen + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + TheFs.NotifyDiskSpace(threshold3,KDefaultDrive,stat3); + test(stat1==KRequestPending && stat2==KRequestPending && stat3==KRequestPending); + r=thread.Create(_L("thread9"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.SetPriority( EPriorityLess ); + thread.Resume(); // start spinning, blocks background thread + // create a file to force some roll-forward + r=file2.Create(TheFs,KTestFile1,EFileShareAny|EFileWrite); + test(r==KErrNone); + User::WaitForRequest(stat1); + test(stat1==KErrNone); + test(stat2==KRequestPending); + test(stat3==KRequestPending); + // kill the spinner thread to allow the background thread to execute + thread.Kill(KErrNone); + User::WaitForRequest( deathStat ); + thread.Close(); + // wait for the notifier + test( stat2==KRequestPending ); + test( stat3==KRequestPending); + TheFs.NotifyDiskSpaceCancel(stat2); + User::WaitForRequest(stat2); + test(stat2==KErrCancel); + TheFs.NotifyDiskSpaceCancel(stat3); + User::WaitForRequest(stat3); + test(stat3==KErrCancel); + CleanupForThread(task); + file2.Close(); + TheFs.Delete( KTestFile1 ); + + + file.Close(); + r=TheFs.Delete(KFileFiller); + test(r==KErrNone); + } + + +void TestMultiple() +// +// test muliple requests and multiple sessions +// + { + // create the filler file + RFile file; + TInt r=file.Create(TheFs,KFileFiller,EFileShareAny|EFileWrite|EFileWriteDirectIO); + test(r==KErrNone); + TInt64 free=FreeDiskSpace(KDefaultDrive); + TInt64 freeSpaceLeft = gMinFileSize << 4; // 512 * 2^4 = 512 * 16 = 8K + FillDisk(file,free-freeSpaceLeft,KDefaultDrive); + TInt size; + r=file.Size(size); + test(r==KErrNone); + test(size>1024); + test.Printf(_L("filler file size=0x%x\n"),size); + + // test multiple requests + test.Next(_L("test multiple requests")); + TThreadTask task = ETaskFileWrite4KB; + InitialiseForThread(task); + free=FreeDiskSpace(KDefaultDrive); + TInt64 threshold1=free-gMinFileSize; // 512; + TInt64 threshold2=free - (gMinFileSize << 2); // 512 * 4 = 2048; +#if defined(__WINS__) + TInt64 threshold3=free-70000; //NTFS over-allocates then reduces when file closed +#else + TInt64 threshold3=free - (gMinFileSize << 5); // 512 * 2^5 = 512 * 32 = 16K +#endif + TRequestStatus stat1,stat2,stat3; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + TheFs.NotifyDiskSpace(threshold3,KDefaultDrive,stat3); + test(stat1==KRequestPending&&stat2==KRequestPending&&stat3==KRequestPending); + RThread thread; + r=thread.Create(_L("thread1"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + TRequestStatus deathStat; + thread.Logon( deathStat ); + thread.Resume(); + User::After(1000000); + User::WaitForRequest(stat1); + User::WaitForRequest(stat2); + test(stat1==KErrNone && stat2==KErrNone); + test(stat3==KRequestPending); + free=FreeDiskSpace(KDefaultDrive); + test(freethreshold3); + TheFs.NotifyDiskSpaceCancel(stat3); + test(stat3==KErrCancel); + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + + // test multiple requests again + test.Next(_L("test multiple requests again")); + if( LffsDrive ) + { + // SetSize doesn't use disk space on LFFS + test.Printf( _L("test skipped on LFFS drive\n") ); + } + else + { + task=ETaskFileSetSize; + InitialiseForThread(task); // this also does initialisation for task2 + free=FreeDiskSpace(KDefaultDrive); + threshold1 = free + (gMinFileSize << 1); // 512 * 2 = 1024 + threshold2 = free + (gMinFileSize * 12); // 512 * 12 = 6144 + threshold3 = free - (gMinFileSize << 1); // 512 * 2 = 1024; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + TheFs.NotifyDiskSpace(threshold3,KDefaultDrive,stat3); + test(stat1==KRequestPending&&stat2==KRequestPending&&stat3==KRequestPending); + r=thread.Create(_L("thread2"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.Resume(); + User::After(10000); + User::WaitForRequest(stat3); + test(stat3==KErrNone && stat1==KRequestPending && stat2==KRequestPending); + free=FreeDiskSpace(KDefaultDrive); + test(freethreshold1 && freethreshold1 && free>threshold2 && free>threshold3); + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + + // test NotifyDiskSpaceCancel() + test.Next(_L("test RFs:NotifyDiskSpaceCancel")); + free=FreeDiskSpace(KDefaultDrive); + TheFs.NotifyDiskSpace(free-100,KDefaultDrive,stat1); + ses2.NotifyDiskSpace(free-100,KDefaultDrive,stat2); + ses3.NotifyDiskSpace(free-100,KDefaultDrive,stat3); + test(stat1==KRequestPending&&stat2==KRequestPending&&stat3==KRequestPending); + TheFs.NotifyDiskSpaceCancel(); + test(stat1==KErrCancel&&stat2==KRequestPending&&stat3==KRequestPending); + ses2.NotifyDiskSpaceCancel(stat2); + test(stat2==KErrCancel&&stat3==KRequestPending); + ses3.NotifyDiskSpaceCancel(); + test(stat3==KErrCancel); + + if( !LffsDrive ) + { + TInt sessionDrive; + r=RFs::CharToDrive(gSessionPath[0],sessionDrive); + test(r==KErrNone); + if(sessionDrive!=RemovableDrive) + { + // first create a file on the removable drive + RFile file2; + TFileName file2name=RemovableDriveBuf; + file2name+=_L("F32-TST\\testfile1"); + TheFs.Delete(file2name); + r=file2.Create(TheFs,file2name,EFileShareAny|EFileWrite); + test(r==KErrNone); + r=file2.SetSize(KFileSize3); + test(r==KErrNone); + // test multiple sessions not notified on disk space change on wrong drive + test.Next(_L("test multiple sessions on different drives")); + task=ETaskFileReplace; + InitialiseForThread(task); + TInt64 freeDef=FreeDiskSpace(KDefaultDrive); + TInt64 freeRem=FreeDiskSpace(RemovableDrive); + threshold1=freeDef + (gMinFileSize << 1); // 1024; + threshold2=freeRem + (gMinFileSize << 1); // 1024; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + ses2.NotifyDiskSpace(threshold2,RemovableDrive,stat2); + test(stat1==KRequestPending&&stat2==KRequestPending); + r=thread.Create(_L("thread4"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.Resume(); + User::After(1000000); + User::WaitForRequest(stat1); + test(stat1==KErrNone && stat2==KRequestPending); + free=FreeDiskSpace(KDefaultDrive); + test(free>threshold1); + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + TheFs.NotifyDiskSpaceCancel(stat2); + test(stat2==KRequestPending); + ses2.NotifyDiskSpaceCancel(stat2); + test(stat2==KErrCancel); + file2.Close(); + r=TheFs.Delete(file2name); + test(r==KErrNone); + } + } + + ses2.Close(); + ses3.Close(); + + + file.Close(); + r=TheFs.Delete(KFileFiller); + test(r==KErrNone); + + } + + +void TestLffsMultiple() +// +// test muliple requests and multiple sessions speicifcally for LFFS drive +// + { + // create the filler file + RFile file; + TInt r=file.Create(TheFs,KFileFiller,EFileShareAny|EFileWrite|EFileWriteDirectIO); + test(r==KErrNone); + TInt64 free=FreeDiskSpace(KDefaultDrive); + FillDisk(file,free-8192,KDefaultDrive); + TInt size; + r=file.Size(size); + test(r==KErrNone); + test.Printf(_L("filler file size=0x%x\n"),size); + + + // test multiple requests again + test.Next(_L("test multiple requests on LFFS") ); + + TThreadTask task=ETaskFileCreateLffs; + InitialiseForThread(task); // this also does initialisation for task2 + free=FreeDiskSpace(KDefaultDrive); + TInt64 threshold1=free+8192; + TInt64 threshold2=free+700; //increased threshold as LFFS, unpredicatably, can release drive space + TInt64 threshold3=free-64; + TRequestStatus stat1, stat2, stat3; +//test.Printf(_L("set up notifiers")); + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + TheFs.NotifyDiskSpace(threshold3,KDefaultDrive,stat3); + test(stat1==KRequestPending&&stat2==KRequestPending&&stat3==KRequestPending); + RThread thread; + r=thread.Create(_L("thread10"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + TRequestStatus deathStat; + thread.Logon( deathStat ); +// test.Printf(_L("Resuming other thread")); + thread.Resume(); + User::After(10000); + User::WaitForRequest(stat3); + test(stat3==KErrNone && stat1==KRequestPending && stat2==KRequestPending); + free=FreeDiskSpace(KDefaultDrive); + test(freethreshold2); + TheFs.NotifyDiskSpaceCancel(); + User::WaitForRequest( stat1 ); + test(stat1==KErrCancel); + + + + TInt sessionDrive; + r=RFs::CharToDrive(gSessionPath[0],sessionDrive); + test(r==KErrNone); + if(sessionDrive!=EDriveC) + { + // test multiple sessions not notified on disk space change on wrong drive + test.Next(_L("test multiple sessions on different drives")); + + RFs ses2,ses3; + r=ses2.Connect(); + test(r==KErrNone); + r=ses3.Connect(); + test(r==KErrNone); + r=ses2.SetSessionPath(gSessionPath); + test(r==KErrNone); + r=ses3.SetSessionPath(gSessionPath); + test(r==KErrNone); + + // first create a file on the C:\ drive + RFile file2; + TFileName file2name=_L("C:\\"); + file2name+=_L("F32-TST\\"); + r=TheFs.MkDir(file2name); + test( KErrNone==r || KErrAlreadyExists==r ); + file2name+=_L("testfile1"); + TheFs.Delete(file2name); + r=file2.Create(TheFs,file2name,EFileShareAny|EFileWrite); + test(r==KErrNone); + WriteToFile( file2, KFileSize3 ); + + task=ETaskFileReplace; + InitialiseForThread(task); + TInt64 freeLffs=FreeDiskSpace(KDefaultDrive); + TInt64 freeD=FreeDiskSpace(EDriveC); + threshold1=freeLffs+1024; + threshold2=freeD+1024; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + ses2.NotifyDiskSpace(threshold2,EDriveC,stat2); + test(stat1==KRequestPending&&stat2==KRequestPending); + r=thread.Create(_L("thread11"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.Resume(); + User::After(1000000); + User::WaitForRequest(stat1); + test(stat1==KErrNone && stat2==KRequestPending); + free=FreeDiskSpace(KDefaultDrive); + test(free>threshold1); + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + TheFs.NotifyDiskSpaceCancel(stat2); + test(stat2==KRequestPending); + ses2.NotifyDiskSpaceCancel(stat2); + User::WaitForRequest( stat2 ); + test(stat2==KErrCancel); + file2.Close(); + r=TheFs.Delete(file2name); + test(r==KErrNone); + ses2.Close(); + ses3.Close(); + } + + + + file.Close(); + r=TheFs.Delete(KFileFiller); + test(r==KErrNone); + + } + + +void TestChangeNotification() +// +// test that disk space notification works with (extended) change notification +// + { + // create a filler file + RFile file; + TInt r=file.Create(TheFs,KFileFiller,EFileShareAny|EFileWrite|EFileWriteDirectIO); + test(r==KErrNone); + TInt64 free=FreeDiskSpace(KDefaultDrive); + // use 8KB in filler file + FillDisk(file,free-8192,KDefaultDrive); + + // test change notification when no disk space change + test.Next(_L("test change notification")); + TThreadTask task = ETaskNoChange1; + InitialiseForThread(task); + free=FreeDiskSpace(KDefaultDrive); + TInt64 threshold1=free+gMinFileSize; + TInt64 threshold2=free-gMinFileSize; + TRequestStatus stat1,stat2,stat3; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); //more free space becoming available + TheFs.NotifyDiskSpace(threshold2,KDefaultDrive,stat2); + TheFs.NotifyChange(ENotifyAll,stat3); + test(stat1==KRequestPending&&stat2==KRequestPending&&stat3==KRequestPending); + RThread thread; + r=thread.Create(_L("thread1"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + TRequestStatus deathStat; + thread.Logon( deathStat ); + thread.Resume(); + User::After(1000000); + User::WaitForRequest(stat3); + if(!LffsDrive) + test(stat1==KRequestPending && stat2==KRequestPending && stat3==KErrNone); + else + test(stat2==KRequestPending && stat3==KErrNone); //As below + + TheFs.NotifyDiskSpaceCancel(); + if(!LffsDrive) + test(stat1==KErrCancel && stat2==KErrCancel); + else + test(stat2==KErrCancel); //is invalid for LFFS as can free up space un expectedly + + User::WaitForRequest( deathStat ); + thread.Close(); + CleanupForThread(task); + + // Have three different sessions + // do an operation that will cause the change notification + // and disk change notification to be signalled + test.Next(_L(" test change notification and disk space notification")); + RFs session2,session3; + r=session2.Connect(); + test(r==KErrNone); + r=session3.Connect(); + test(r==KErrNone); + r=session2.SetSessionPath(gSessionPath); + test(r==KErrNone); + r=session3.SetSessionPath(gSessionPath); + test(r==KErrNone); + task=ETaskFileWrite; + InitialiseForThread(task); + free=FreeDiskSpace(KDefaultDrive); + threshold1=free-400; + TheFs.NotifyDiskSpace(threshold1,KDefaultDrive,stat1); + session2.NotifyChange(ENotifyAll,stat2); + session3.NotifyChange(ENotifyAll,stat3,KTestFile1); + test(stat1==KRequestPending&&stat2==KRequestPending&&stat3==KRequestPending); + r=thread.Create(_L("thread2"),ThreadFunction,KStackSize,KHeapSize,KHeapSize,(TAny*)task); + test(r==KErrNone); + thread.Logon( deathStat ); + thread.Resume(); + User::After(1000000); + User::WaitForRequest(stat1); + User::WaitForRequest(stat2); + User::WaitForRequest(stat3); + test(stat1==KErrNone && stat2==KErrNone && stat3==KErrNone); + free=FreeDiskSpace(KDefaultDrive); + test(free