diff -r 000000000000 -r a41df078684a kerneltest/f32test/concur/t_cfssoakfn.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/concur/t_cfssoakfn.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,903 @@ +// Copyright (c) 2002-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_csfsoakfn.cpp +// +// + +#include +#include +#include +#include +#include "t_server.h" +#include "t_tdebug.h" +#include "t_cfssoak.h" + +/// Time value constants +LOCAL_D const TInt KSecond = 1000000; +LOCAL_D const TInt KTenthSec = KSecond / 10; + +/// Time to wait before session/subsession close, to allow some writes to +/// complete but not all (1 second per write with slow FS) +LOCAL_D const TInt KSessionWaitTime = 25 * KTenthSec; + +/// Number of writes we expect to have completed +LOCAL_D const TInt KSessionNumEnded = KSessionWaitTime / KSecond; + +GLREF_D TExtension gPrimaryExtensions[]; +// ----------------------------------------------------------------- + +void TSoakStats::Print() +/// +/// Print a statistics header. +/// + { + TTest::Printf(_L(" Total Fail\n")); + } + +void TSoakStats::Print(const TDesC& aTitle) +/// +/// Print the statistics for this item (title, total executed, number executed +/// this time, total failures, failures this time) then reset the "this time" +/// values. +/// + { + TTest::Printf(_L(" %-8S %8d %+8d %8d %+8d\n"), + &aTitle, iTotal, iThis, iFail, iThisF); + iThis = 0; + iThisF = 0; + } + +void TSoakStats::Inc() +/// +/// Increment both the total and "this time" execution numbers. +/// + { + iTotal++; + iThis++; + } + +void TSoakStats::Fail() +/// +/// Increment both the total and "this time" failure numbers. +/// + { + iFail++; + iThisF++; + } + + +// ----------------------------------------------------------------- + +TSoakReadOnly::TSoakReadOnly() : iDrive(-1) +/// +/// Initialise the "read only" tests, connect the file session. +/// + { + TInt r = iFs.Connect(); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("iFs connect")); + } + +TSoakReadOnly::TSoakReadOnly(TInt aDriveCh) : iDrive(aDriveCh) +/// +/// Initialise the "read only" tests, connect the file session, setting up +/// a drive to be excluded from the reading. +/// @param aDriveCh Drive letter to be excluded. +/// + { + TInt r = iFs.Connect(); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("iFs connect")); + } + +TSoakReadOnly::~TSoakReadOnly() +/// +/// Destructor -- close the file session. +/// + { + iFs.Close(); + } + +TInt TSoakReadOnly::ReadFile(const TDesC& aName, TInt aSize) +/// +/// Read a file, expecting a certain size. No check is done on the actual +/// data, just that it can be read. +/// @param aName Name of the file. +/// @param aSize Expected file size. +/// + { + TInt r = KErrNone; + RFile f; + iReads.Inc(); + r = f.Open(iFs, aName, EFileStreamText); + if (r == KErrNotFound || r == KErrPathNotFound) + return KErrNone; + TBuf<256> errbuf; + if (r != KErrNone) + { + if (r != KErrInUse) + { + iFiles.Fail(); + TTest::Printf(_L("%S -- open failed %S\n"), &aName, &TTest::ErrStr(r, errbuf)); + } + else + TTest::Printf(_L("Warning: %S -- open failed %S\n"), &aName, &TTest::ErrStr(r, errbuf)); + return r; + } + TBuf8<256> buf; + TInt len = 0; + while ((r = f.Read(buf)) == KErrNone && buf.Length() > 0) + len += buf.Length(); + f.Close(); + if (r != KErrNone && r != KErrEof) + { + iReads.Fail(); + TTest::Printf(_L("ERROR %S -- READ FAILED %S\n"), &aName, &TTest::ErrStr(r, errbuf)); + } + else if (len < aSize) + { + iReads.Fail(); + TTest::Printf(_L("ERROR %S -- %d READ, %d EXPECTED\n"), &aName, len, aSize); + } + else if (len > aSize) + TTest::Printf(_L("Warning: %S -- %d read, %d expected\n"), &aName, len, aSize); + return r; + } + +TInt TSoakReadOnly::ScanDirs(TInt aDriveCh, TInt aReadInterval) +/// +/// Scan directories on a drive, reading a selection of the files found. +/// @param aDriveCh Drive letter to be scanned. +/// @param aReadInterval Approximate number of files to be read (they are +/// read at random, so the actual number read may be +/// less than this number). +/// + { + TInt r = KErrNone; + CDirScan* scanner=NULL; + TRAP(r, scanner=CDirScan::NewL(iFs)); + ScanDirFunc(scanner, aDriveCh, aReadInterval); + delete scanner; + return r; + } + +TInt TSoakReadOnly::ScanDirFunc(CDirScan* aScanner, TInt aDriveCh, TInt aReadInterval) +/// +/// Scan directories on a drive, reading a selection of the files found. +/// @param aDriveCh Drive letter to be scanned. +/// @param aReadInterval Approximate number of files to be read (they are +/// read at random, so the actual number read may be +/// less than this number). +/// + { + TInt r = KErrNone; + TBuf<8> name; + name.Format(_L("%c:\\"), aDriveCh); + // TTest::Printf(_L("Scanning %S\n"), &name); + TParse dirName; + r=iFs.Parse(name, dirName); + if (r != KErrNone) + { + iDrives.Fail(); + return r; + } + CDir* entryList = NULL; + TInt nfiles = 0; + TRAP(r, aScanner->SetScanDataL(dirName.FullName(),KEntryAttDir,ESortByName)); + if (r != KErrNone) + { + TTest::Fail(HERE, r, _L("SetScanData %S"), &dirName.FullName()); + } + TRAP(r, aScanner->NextL(entryList)); + if (r == KErrPathNotFound) + return KErrNone; + if (r != KErrNone) + { + TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName()); + } + while (entryList) + { + for (TInt i = 0; i < entryList->Count(); i++) + { + TEntry e = (*entryList)[i]; + if (!e.IsDir()) + ++nfiles; + } + delete entryList; + TRAP(r, aScanner->NextL(entryList)); + if (r == KErrPathNotFound) + break; + if (r != KErrNone) + { + TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName()); + } + } + TInt prob = (nfiles / aReadInterval) + 1; + TRAP(r, aScanner->SetScanDataL(dirName.FullName(),KEntryAttDir,ESortByName)); + if (r == KErrPathNotFound) + return KErrNone; + if (r != KErrNone) + { + TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName()); + } + for (;;) + { + TRAP(r, aScanner->NextL(entryList)); + if (r == KErrPathNotFound) + return KErrNone; + if (r != KErrNone) + { + TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName()); + } + if (entryList==NULL) + break; + TInt count=entryList->Count(); + while (count--) + { + TEntry e = (*entryList)[count]; + TFileName path=aScanner->FullPath(); + path.Append(e.iName); + TBuf<16> attr; + for (TInt j = 0; j < 16; j++) + { + if ((1 << j) & e.iAtt) + attr.Append(TText("RHSVDA X "[j])); + } + if (e.IsDir()) + { + iDirs.Inc(); + // TTest::Printf(_L("%c:%-50S %S\n"), aDriveCh, &path, &attr); + } + else + { + iFiles.Inc(); + TBool read = (aReadInterval && Math::Rand(iSeed) % prob == 0); + if (read) + { + // TTest::Printf(_L("%-50S %8d %-8S test\n"), &path, e.iSize, &attr); + r = ReadFile(path, e.iSize); + } + else + { + // TTest::Printf(_L("%c:%-50S %8d %S\n"), aDriveCh, &path, e.iSize, &attr); + } + } + } + delete entryList; + entryList=NULL; + } + return r; + } + +TInt TSoakReadOnly::ScanDrives(TBool aScanDirs, TInt aReadInterval) +/// +/// Scan all drives (except the one excluded) for directories and files. +/// @param aScanDirs If true, read subdirectories, if false don't. +/// @param aReadInterval approximate number of files to read. +/// + { + TInt r = KErrNone; + TInt i; + for (i = EDriveA; i <= EDriveZ; i++) + { + TChar drv; + r=iFs.DriveToChar(i, drv); + if (r != KErrNone) + return r; + TDriveInfo info; + r=iFs.Drive(info, i); + if (r != KErrNone) + return r; + if (i != iDrive + && info.iDriveAtt != 0 + && info.iType != EMediaUnknown + && info.iType != EMediaNotPresent) + { + iDrives.Inc(); + // TTest::Printf(_L("Drive %c:"), drv); + if (aScanDirs) + { + iDirs.Inc(); + r = ScanDirs(drv, aReadInterval); + if (r != KErrNone) + return r; + } + } + } + return r; + } + +void +TSoakReadOnly::ExcludeDrive(TInt aDriveCh) +/// +/// Set a drive to be excluded from scanning. +/// @param aDriveCh Drive letter to be excluded. +/// + { + iDrive = aDriveCh; + } + + +// -------------------------------------------------------------------------- + +TSoakFill::TSoakFill() +/// +/// Initialise the fill/clean cycle. +/// + { + iSeed = 186483; + TInt r = iFs.Connect(); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("iFs connect")); + } + +TInt TSoakFill::SetDrive(TInt aDriveCh) +/// +/// Set a drive to be stressed. The test directory is created and then it is +/// cleaned (in case anything was left over from previous tests). Note that +/// other directories on the drive are untouched. +/// @param aDriveCh Drive letter to be used. +/// @leave The drive scanning can cause the function to leave. +/// + { + TInt r = KErrNone; + iDrive = aDriveCh; + if (aDriveCh) + { + iDrvCh = aDriveCh; + iFs.CharToDrive(iDrvCh, iDrive); + r=iFs.Volume(iInfo, iDrive); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("volume info for %C:"), aDriveCh); + iFree = iInfo.iSize; + iName.Format(_L("%c:\\SOAK\\"), iDrvCh); + r = iFs.MkDir(iName); + if (r != KErrNone && r != KErrAlreadyExists) + TTest::Fail(HERE, r, _L("mkdir %S"), &iName); + r = KErrNone; + } + return r; + } + +TInt TSoakFill::FillDrive() +/// +/// Fill the drive with files and directories of random lengths. +/// @param aDriveCh Drive letter to be tested, or zero (absent) to use the one +/// set up with SetDrive(). +/// @leave Setting up a new drive can cause this function to leave. +/// + { + TInt r = KErrNone; + r=iFs.Volume(iInfo, iDrive); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("volume info for %C:"), iDrvCh); + iFree = iInfo.iFree; + r = iFs.MkDir(iName); + if (r != KErrNone && r != KErrAlreadyExists && r != KErrNotSupported) + TTest::Fail(HERE, r, _L("mkdir %S"), &iName); + do + { + r = Fill(iName); + if (r == KErrDiskFull) + { + // TTest::Printf(_L("Disk full on %c:\n"), iDrvCh); + break; + } + if (r != KErrNone) + TTest::Fail(HERE, r, _L("Filling drive %c"), iDrvCh); + r=iFs.Volume(iInfo, iDrive); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("volume info for %c:"), iDrvCh); + } while (iInfo.iFree > 0); + r=iFs.Volume(iInfo, iDrive); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("volume info for %c:"), iDrvCh); + if (iInfo.iFree > 0) + TTest::Printf(_L("Free space on %c: %S %ld KB (out of %ld KB)\n"), + iDrvCh, + &iInfo.iName, + I64LOW(iInfo.iFree / 1024), + I64LOW(iInfo.iSize / 1024)); + return r; + } + +TInt TSoakFill::CleanDrive() +/// +/// Clean the test directory on the selected drive, removing all files and +/// subdirectories. Other directories on the drive are left untouched. +/// @leave Scanning the drive can cause the function to leave. +/// + { + TInt r = KErrNone; + CDirScan* scanner=0; + TRAP(r, scanner=CDirScan::NewL(iFs)); + if (r != KErrNone || !scanner) + TTest::Fail(HERE, r, _L("creating scanner")); + TParse dirName; + r=iFs.Parse(iName, dirName); + if (r != KErrNone) + { + if (r == KErrInUse || r == KErrNotFound || r == KErrPathNotFound) + { + // valid conditions, don't report error + r = KErrNone; + } + else + TTest::Fail(HERE, r, _L("Parse %S"), &iName); + } + else + { + // TTest::Printf(_L("scan %S\n"), &iName); + CDir* entryList = NULL; + TRAP(r, scanner->SetScanDataL(dirName.FullName(),KEntryAttDir,ESortByName,CDirScan::EScanUpTree)); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("SetScanDataL(%S)"), &dirName.FullName()); + TRAP(r, scanner->NextL(entryList)); + if (r != KErrNone && r != KErrPathNotFound) + TTest::Fail(HERE, r, _L("Scan NextL()")); + while (entryList) + { + for (TInt i = 0; i < entryList->Count(); i++) + { + TEntry e = (*entryList)[i]; + TFileName path = iName; + if (path.Right(1) == _L("\\")) + path.SetLength(path.Length()-1); + path.Append(scanner->AbbreviatedPath()); + path.Append(e.iName); + // TTest::Printf(_L("remove %S\n"), &path); + TBuf<256> buf; + TInt maxInUseCount = 120; + do + { + if (e.IsDir()) + { + if (path.Right(1) != _L("\\")) + path.Append(_L("\\")); + r = iFs.RmDir(path); + } + else + r = iFs.Delete(path); + if (r == KErrInUse) + { + TTest::Printf(_L("Warning: %S deleting %S\n"), &TTest::ErrStr(r, buf), &path); + User::After(1*KSecond); + } + } + while (r == KErrInUse && maxInUseCount-- > 0); + if (r != KErrNone) + { + TTest::Printf(_L("ERROR %S deleting %S\n"), &TTest::ErrStr(r, buf), &path); + } + } + delete entryList; + TRAP(r, scanner->NextL(entryList)); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("Scan NextL()")); + } + } + delete scanner; + r = iFs.RmDir(iName); + if (r != KErrNone && r != KErrNotFound && r != KErrPathNotFound) + { + TTest::Fail(HERE, r, _L("volume info for %C:"), iName[0]); + } + r=iFs.Volume(iInfo, iDrive); + if (r != KErrNone) + { + TTest::Fail(HERE, r, _L("volume info for %C:"), iName[0]); + } + if (iInfo.iFree > iFree) + { + TTest::Printf(_L("Warning: %C: changed size -- was %ld now %ld\n"), + iName[0], iFree, iInfo.iFree); + return r; + } + iFree = iInfo.iFree; + return r; + } + +TInt TSoakFill::Fill(TFileName& aName, TInt aNfiles) +/// +/// Recursively create files and subdirectories at random. If a subdirectory +/// is created, the function recurses to fill it. This generates a mixture of +/// directories and files of varying lengths. +/// @param aName Directory in which to create other stuff. +/// @param aNfiles Maximum number of files to create. +/// @return Status of last thing created, KErrDiskFull when out of space. +/// + { + TInt oldlen = aName.Length(); + if (oldlen + 10 > aName.MaxLength()) + return KErrNone; + TInt r=iFs.Volume(iInfo, iDrive); + if (r != KErrNone) + return r; + TInt nfiles = I64LOW(iInfo.iFree/10000) + 5; + if (aNfiles > 0 && nfiles > aNfiles) + nfiles = aNfiles; + nfiles = Math::Rand(iSeed) % nfiles + 5; + TInt filesz = I64LOW(iInfo.iFree/nfiles/256) + 5; + // TTest::Printf(_L("nfiles = %d\n"), nfiles); + TInt i; + for (i = 0; i < nfiles; i++) + { + aName.SetLength(oldlen); + TBool dir = (Math::Rand(iSeed) % 5 == 0); + if (dir && oldlen < 80) + { + aName.Append(_L("d")); + aName.AppendNum(i); + aName.Append(_L("\\")); + r = iFs.MkDir(aName); + TInt busycount = 120; + while (busycount-- > 0) + { + r = iFs.MkDir(aName); + if (r == KErrDiskFull) + TTest::Printf(_L("Disk full creating %S\n"), &aName); + if (r != KErrInUse) + break; + TTest::Printf(_L("Warning: KErrInUse creating %S\n"), &aName); + User::After(1*KSecond); + } + // TTest::Printf(_L("mkdir %S = %d\n"), &aName, r); + if (r == KErrNone || r == KErrAlreadyExists) + { + r = Fill(aName, nfiles - i - 2); + } + if (r != KErrNone) + break; + } + else + { + aName.Append(_L("F")); + aName.AppendNum(i); + RFile f; + TInt busycount = 120; + while (busycount-- > 0) + { + r = f.Replace(iFs, aName, EFileStreamText | EFileWrite); + if (r != KErrInUse) + break; + TTest::Printf(_L("Warning: KErrInUse creating %S\n"), &aName); + User::After(1*KSecond); + } + if (r == KErrNone) + { + // iNames.AppendL(aName); + TInt num = Math::Rand(iSeed) % filesz + 10; + TBuf8<256> buf; + buf.Fill(TText(' '), 256); + TInt wr = 0; + while (num-- > 0 && r == KErrNone) + { + r = f.Write(buf); + if (r == KErrNone) + wr += 256; + else + break; + } + f.Close(); + /* + if (r == KErrDiskFull) + TTest::Printf(_L("Disk full writing %S\n"), &aName); + */ + if (r != KErrNone) + break; + } + else + { + // TTest::Printf(_L("creat %S = %d\n"), &aName, r); + if (r == KErrDiskFull) + TTest::Printf(_L("Disk full creating %S\n"), &aName); + break; + } + } + } + aName.SetLength(oldlen); + return r; + } + + +TSoakRemote::TSoakRemote(TInt aDriveCh) +/// +/// Initialise testing for 'remote' drive (special filesystem). Connects to +/// file session, initialises the drive and timer, sets up the buffers and +/// file name. +/// @param aDriveCh Drive letter for the drive to test. +/// + { + TInt r = iFs.Connect(); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("iFs connect")); + iDrvCh = aDriveCh; + iSync = EFalse; + iFs.CharToDrive(iDrvCh, iDrive); + iTimer.CreateLocal(); + Setup(); + } + +void TSoakRemote::Setup() +/// Set up the buffers and the filename to be used. + { + for (TInt i = 0; i < KSoakNumBuf; i++) + { + iBuff[i].Fill('_', KSoakBufLen); + iStat[i] = KErrNone; + } + iName.Format(_L("%c:\\SOAKTEST.FILE"), iDrvCh); + } + +void TSoakRemote::Remount(TBool aSync) +/// +/// Remount the test drive as (a)synchronous. +/// @param aSync If true, the drive is set as synchronous access, otherwise +/// as asynchronous. +/// + { + TFileName fsname; + iSync = aSync; + TInt r = iFs.FileSystemName(fsname, iDrive); + TEST(r == KErrNone || r == KErrNotFound); + + if (fsname.Length() > 0) + { + r = iFs.ExtensionName(gPrimaryExtensions[iDrive].iName, iDrive, 0); + if (r == KErrNone) + gPrimaryExtensions[iDrive].iExists = ETrue; + + r = iFs.DismountFileSystem(fsname, iDrive); + if(r != KErrNone) + { + TTest::Fail(HERE, r, _L("Dismounting file system %S"), &fsname); + } + } + + TBufC<16> type = _L("asynchronous"); + if (iSync) + type = _L("synchronous"); + TTest::Printf(_L("Remount filesystem %c: %S as %S\n"), iDrvCh, &fsname, &type); + +#ifdef __CONCURRENT_FILE_ACCESS__ + if (gPrimaryExtensions[iDrive].iExists == EFalse) + r=iFs.MountFileSystem(fsname,iDrive,iSync); + else + r=iFs.MountFileSystem(fsname,gPrimaryExtensions[iDrive].iName,iDrive,iSync); +#else + if (gPrimaryExtensions[aDrive].iExists == EFalse) + r=iFs.MountFileSystem(fsname,iDrive); + else + r=iFs.MountFileSystem(fsname,gPrimaryExtensions[iDrive].iName,iDrive); +#endif + TEST(r==KErrNone); + } + +TInt TSoakRemote::TestSubSession() +/// +/// Test what happens when a file is closed in the middle of writing it. Note +/// that this assumes that the filesystem under test takes a second for each +/// write operation (i.e. is the special test filesystem). +/// + { + TInt r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("opening %S for writing"), iName.Ptr()); + TInt i; + for (i = 0; i < KSoakNumBuf; i++) + { + iFile.Write(iBuff[i], iStat[i]); + } + // wait for a couple of writes to complete, then close the file before the + // others finish + User::After(KSessionWaitTime); + TTest::Printf(_L("Wait ended")); + iFile.Close(); + TTest::Printf(_L("Close ended")); + // test what has happened + TBool bad = EFalse; + for (i = 0; i < KSoakNumBuf; i++) + { + User::WaitForRequest(iStat[i]); + r = iStat[i].Int(); + switch (r) + { + case KErrNone: + if (i >= KSessionNumEnded) + { + TTest::Printf(_L("Write %d not cancelled"), i); + bad = ETrue; + } + break; + case KErrCancel: + if (i <= KSessionNumEnded) + { + TTest::Printf(_L("Write %d incorrectly cancelled"), i); + bad = ETrue; + } + TTest::Printf(_L("write %d cancelled\n"), i); + break; + default: + TTest::Fail(HERE, r, _L("incorrect status for write %d"), i); + } + } + iFs.Delete(iName); + TPtrC sbuf(iSync ? _L("sync") : _L("async")); + if (bad) + { + TTest::Printf(_L("TestSubSession %c: %S FAILED\n"), iName[0], &sbuf); + // Commented out for the moment as result is undefined + // TTest::Fail(HERE, _L("TestSubSession %c: %S FAILED\n"), iName[0], &sbuf); + } + TTest::Printf(_L("TestSubSession %c: %S OK\n"), iName[0], &sbuf); + return KErrNone; + } + +TInt TSoakRemote::TestSession() +/// +/// Test what happens when a session is closed in the middle of writing a file. +/// Note that this assumes that the filesystem under test takes a second for +/// each write operation (i.e. is the special test filesystem). +/// + { + TInt r; + TInt i; + TPtrC sbuf(iSync ? _L("sync") : _L("async")); + + r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("opening %S for writing"), iName.Ptr()); + for (i = 0; i < KSoakNumBuf; i++) + { + iFile.Write(iBuff[i], iStat[i]); + } + // wait for a couple of them to complete, then close the session + User::After(KSessionWaitTime); + TTest::Printf(_L("Close FS %S"), &sbuf); + // iFs.SetDebugRegister(KFSYS | KFSERV | KTHRD); + iFs.Close(); + TTest::Printf(_L("FS closed %S"), &sbuf); + // see what has happened to the writes (wait for at most another 10 seconds). + TRequestStatus tstat; + iTimer.After(tstat, 10*KSecond); + TBool busy = ETrue; + TInt file = 0; + while (tstat == KRequestPending && busy) + { + User::WaitForAnyRequest(); + busy = EFalse; + for (i = file; i < KSoakNumBuf; i++) + { + r = iStat[i].Int(); + switch (r) + { + case KRequestPending: + busy = ETrue; + TTest::Printf(_L("write %d pending\n"), i); + break; + case KErrNone: + file = i + 1; + TTest::Printf(_L("write %d finished\n"), i); + break; + case KErrCancel: + file = i + 1; + TTest::Printf(_L("write %d cancelled\n"), i); + break; + default: + file = i + 1; + TTest::Fail(HERE, r, _L("incorrect status for write %d"), i); + } + } + } + TBool bad = EFalse; + if (busy) + { + for (i = 0; i < KSoakNumBuf; i++) + { + TBuf<64> buf; + r = iStat[i].Int(); + if (r != KErrNone) + { + // We expect that the third and subsequent requests will either + // have failed with cancel or be still outstanding. If either + // of the first two have failed or are outstanding, that's an + // error. + if (i < KSessionNumEnded || (r != KErrCancel && r != KRequestPending)) + { + TTest::Fail(HERE, _L("write %d: %S\n"), i, &TTest::ErrStr(r, buf)); + bad = ETrue; + } + } + } + } + iTimer.Cancel(); + // if it's got this far, re-connect the file session + // User::After(100000); + // TTest::Printf(_L("FS closed (%S) yet?"), &sbuf); + r = iFs.Connect(); + iFs.SetDebugRegister(0); + // TTest::Printf(_L("FS opened")); + if (r != KErrNone) + TTest::Fail(HERE, r, _L("iFs connect")); + r = iFs.Delete(iName); + for (TInt nr = 0; r == KErrInUse && nr < 100; nr++) + { + TTest::Printf(_L("Wait for previous session to close")); + User::After(10*KSecond); + r = iFs.Delete(iName); + } + if (r == KErrNotFound) + r = KErrNone; + if (r != KErrNone) + bad = ETrue; + TPtrC obuf(bad ? _L("FAIL") : _L("OK")); + TTest::Printf(_L("TestSession %c: %S %S\n"), iName[0], &sbuf, &obuf); + if (bad) + { + TTest::Printf(_L("Test session close %c: %S FAILED\n"), iName[0], &sbuf); + // Commented out for the moment as result is undefined + // TTest::Fail(HERE, _L("Test session close failed")); + } + return r; + } + +TInt TSoakRemote::TestMount() +/// +/// Test dismounting with a file open (should fail) +/// + { + TFileName fsname; + TInt r = iFs.FileSystemName(fsname, iDrive); + TEST(r == KErrNone || r == KErrNotFound); + + TPtrC sbuf(iSync ? _L("sync") : _L("async")); + + r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite); + for (TInt nr = 0; r == KErrInUse && nr < 100; nr++) + { + TTest::Printf(_L("Warning: KErrInUse opening %S for writing\n"), &iName); + User::After(10*KSecond); + r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite); + } + if (r != KErrNone) + TTest::Fail(HERE, r, _L("opening %S for writing"), &iName); + + if (fsname.Length() > 0) + { + r = iFs.DismountFileSystem(fsname, iDrive); + if (r == KErrNone) + { +#ifdef __CONCURRENT_FILE_ACCESS__ + r = iFs.MountFileSystem(fsname, iDrive, iSync); +#else + r = iFs.MountFileSystem(fsname, iDrive); +#endif + if (r != KErrNone) + TTest::Fail(HERE, r, _L("MountFileSystem(%S, %C:)"), &fsname, iDrvCh); + } + else if (r != KErrInUse) + { + TTest::Fail(HERE, r, _L("DismountFileSystem(%S, %C:)"), &fsname, iDrvCh); + } + } + + iFile.Close(); + iFs.Delete(iName); + + TTest::Printf(_L("TestMount %c: %S OK\n"), iName[0], &sbuf); + + return KErrNone; + } + +