kerneltest/f32test/filesystem/fat/t_fatcorrupt.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/filesystem/fat/t_fatcorrupt.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,815 @@
+// Copyright (c) 2005-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_fatcorrupt.cpp
+//
+//
+
+//! @SYMTestCaseID FSBASE-CR-JHAS-68YPX7
+//! @SYMTestType CT
+//! @SYMREQ CR JHAS-68YPX7
+//! @SYMTestCaseDesc Test functionality of handling corrupt data on disk
+//! @SYMTestStatus Implemented
+//! @SYMTestActions Use fat test extension to test read/write/format
+//! @SYMTestExpectedResults Read bad sector fail, others pass
+//! @SYMTestPriority Medium
+//! @SYMAuthor Ying Shi
+//! @SYMCreationDate 20/05/2005
+//! @See EFat and EFat32 components
+//! @file f32test\server\t_fatcorrupt.cpp
+
+#include <f32file.h>
+#include <e32test.h>
+#include <e32math.h>
+
+#include "t_server.h"
+#include "t_fatext.h"
+
+using namespace Fat_Test_Utils;
+
+GLDEF_D RTest test(_L("T_FATCORRUPT"));
+
+static TInt gDrive;
+static TBuf16<2> gDriveName(2);
+static TFileName gFileSystem;
+static TFullName gExtName;
+static TBool gExtExists=EFalse;
+static TFatBootSector BootSector;
+
+static TInt gBadList[3];
+
+_LIT(KExtName,"FATTEST");
+
+
+void RestoreEnv();
+
+/**
+    Do format steps and print progress
+
+    @param  aFormat     specifies the format object
+    @param  aStepsCnt   format steps counter from RFormat::Open
+
+    @return format completion error code
+*/
+static TInt DoFormatSteps(RFormat& aFormat, TInt aStepsCnt)
+{
+    TInt nRes = KErrNone;
+    TInt prevCnt = aStepsCnt;
+
+    while (aStepsCnt && nRes == KErrNone)
+        {
+         if(prevCnt != aStepsCnt)
+            {
+            test.Printf(_L("."));
+            prevCnt = aStepsCnt;
+            }
+
+        nRes = aFormat.Next(aStepsCnt);
+        }
+
+    test.Printf(_L("\n\r"));
+
+    return nRes;
+}
+
+
+#define TESTL(con) TestL(con,r,__LINE__)
+
+void TestL(TBool aCondition, TInt aError, TInt aLine = 0)
+    {
+    if (!aCondition)
+        {
+        RDebug::Printf("Test fail at line: %d with error code %d",aLine, aError);
+        RestoreEnv();
+        }
+    test(aCondition);
+    }
+
+//-------------------------------------------------------------
+
+void RestoreEnv()
+    {
+    test.Printf(_L("RestoreEnv()\n"));
+
+    TInt r = TheFs.DismountExtension(KExtName, gDrive);
+    test(r==KErrNone);
+    r = TheFs.RemoveExtension(KExtName);
+    test(r==KErrNone);
+
+    if(gExtExists)      // remount existing secondary extension
+        {
+        test(TheFs.MountExtension(gExtName, gDrive)==KErrNone);
+        }
+
+
+    //-- We need a full format, because quick format preserves bad sectors marked in FAT
+    r = FormatFatDrive(TheFs, gDrive, EFalse);
+    test(r == KErrNone);
+
+    }
+
+//-------------------------------------------------------------
+
+// Remount drive with FAT test extension
+TBool PrepareMount()
+    {
+    test.Printf(_L("PrepareMountL(), drive:%d \n"),gDrive);
+
+    TInt r = TheFs.AddExtension(KExtName);
+    test(r==KErrNone || r==KErrAlreadyExists);
+    r = TheFs.ExtensionName(gExtName,gDrive,0);
+    if (r == KErrNone)              // an extension already exists -> dismount it
+        {
+        test.Printf(_L("Drive %d has extension, attempt dismounting it\n"),gDrive);
+        r=TheFs.DismountExtension(gExtName,gDrive);
+        if(r==KErrAccessDenied)     // primary extension
+            {
+            test.Printf(_L("Drive %d has primary extension, skip\n"),gDrive);
+            test(TheFs.RemoveExtension(KExtName) == KErrNone);
+            return EFalse;
+            }
+        test(r==KErrNone);
+        gExtExists=ETrue;
+        }
+    test(r == KErrNone || r==KErrNotFound);
+    r = TheFs.MountExtension(KExtName, gDrive);
+    if (r != KErrNone)
+        test(TheFs.RemoveExtension(KExtName) == KErrNone);
+    test(r==KErrNone);
+    return ETrue;
+    }
+
+//-------------------------------------------------------------
+
+void MarkClustersL()
+    {
+    TInt size = sizeof(gBadList) / sizeof(TInt);
+    for (TInt i=0; i<size; i++)
+        {
+        TInt r = TheFs.ControlIo(gDrive,CFatTestProxyDrive::EMark,(TAny*)gBadList[i],NULL);
+        TESTL(r == KErrNone);
+        }
+    }
+
+//-------------------------------------------------------------
+
+/**
+    Create 3 empty files on the volume
+*/
+void CreateFiles()
+    {
+    TInt r;
+    RFile file;
+    TBuf<10> fileName01;
+    fileName01.Append(_L("?:\\file01"));
+    fileName01[0] = (TUint16)gDriveToTest;
+    r = file.Create(TheFs, fileName01, EFileWrite);
+    TESTL(r==KErrNone||r==KErrAlreadyExists);
+    file.Close();
+
+    TBuf<10> fileName02;
+    fileName02.Append(_L("?:\\file02"));
+    fileName02[0] = (TUint16)gDriveToTest;
+    r = file.Create(TheFs, fileName02, EFileWrite);
+    TESTL(r==KErrNone||r==KErrAlreadyExists);
+    file.Close();
+
+    TBuf<10> fileName03;
+    fileName03.Append(_L("?:\\file03"));
+    fileName03[0] = (TUint16)gDriveToTest;
+    r = file.Create(TheFs, fileName03, EFileWrite);
+    TESTL(r==KErrNone||r==KErrAlreadyExists);
+    file.Close();
+    }
+
+//-------------------------------------------------------------
+
+/**
+    Read/Write to the file with damaged clusters
+*/
+void DoTestReadWriteL()
+    {
+    CreateFiles();
+
+    // Get disk mount information
+    TPckgBuf<TInt> dataPositionBuf;
+    TPckgBuf<TInt> sectorsPerClusterBuf;
+
+    TInt r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EGetDataPosition,dataPositionBuf);
+    TESTL(r==KErrNone);
+
+    //-- media position of the 1st data sector on the volume.
+    //-- for FAT32 this is the 2nd cluster of the data ares, because 1st belongs to the root dir.
+    const TInt dataPosition = dataPositionBuf();
+
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::ESectorsPerCluster,sectorsPerClusterBuf);
+    TESTL(r==KErrNone);
+
+    const TInt sectorsPerCluster = sectorsPerClusterBuf(); //-- FAT sectors per cluster
+
+
+
+    // Calculate file data sectors
+    // For FAT32, first data sector falls under root directory, and current FAT32
+    // file system implementation does not take care of handling bad sectors in
+    // root directory so changing start sector to be the start sector of the file,
+    // instead of first data sector.
+    TInt f01_StartSector;
+    if(Is_Fat32(TheFs,gDrive))
+    {
+        f01_StartSector = (dataPosition >> KDefaultSectorLog2);
+        test.Printf(_L("FAT32, dataPosition: %d, sec:%d, spc:%d\n"), dataPosition, f01_StartSector, sectorsPerCluster);
+    }
+    else
+    {
+        f01_StartSector = (dataPosition >> KDefaultSectorLog2);
+        test.Printf(_L("dataPosition: %d, sec:%d, spc:%d\n"), dataPosition, f01_StartSector, sectorsPerCluster);
+    }
+
+    //TInt f01end = f01beg + sectorsPerCluster - 1;
+    //TInt f02beg = f01end + 1;
+    //TInt f02end = f02beg + sectorsPerCluster - 1;
+    //TInt f03beg = f02end + 1;
+    //TInt f03end = f03beg + sectorsPerCluster - 1;
+
+    test.Next(_L("Test file write"));
+
+    //-- mark the sector that file01 starts with as bad
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EMark,(TAny*)(f01_StartSector),NULL);
+    TESTL(r==KErrNone);
+
+    TBuf<10> fileName01;
+    fileName01.Append(_L("?:\\file01"));
+    fileName01[0] = (TUint16)gDriveToTest;
+
+    RFile file;
+
+    //-- write to the file with bad sector
+    r = file.Open(TheFs, fileName01, EFileWrite);
+    TESTL(r==KErrNone);
+
+    TInt size = 2 * sectorsPerCluster * KDefaultSectorSize;   //-- 2 clusters
+    RBuf8 writeBuf01;
+
+    r = writeBuf01.CreateMax(size);
+    TESTL(r == KErrNone);
+
+    r = file.Write(writeBuf01, size);
+    TESTL(r==KErrNone);
+
+    file.Close();
+
+    test.Next(_L("Test file read"));
+
+    //-- unmark bas sector
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EUnmark,(TAny*)(f01_StartSector),NULL);
+    TESTL(r==KErrNone);
+
+    //-- mark the 2nd cluster in the file as bad
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EMark,(TAny*)(f01_StartSector+sectorsPerCluster),NULL);
+    TESTL(r==KErrNone);
+
+    r = file.Open(TheFs, fileName01, EFileRead);
+    TESTL(r==KErrNone);
+
+    //-- read the file from "corrupted" media
+    r = file.Read(writeBuf01, size);
+    TESTL(r==KErrCorrupt); //-- the file must be corrupted
+
+    file.Close();
+
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EUnmarkAll, NULL, NULL);
+    TESTL(r==KErrNone);
+
+    writeBuf01.Close();
+
+    }
+
+
+//-------------------------------------------------------------------------------------------------------
+
+/**
+    Suggest FAT volume metrics by volume size in sectors. Pay attention to the KMaxSectorsPerCluster constant.
+
+    @param  aVolSizeInSectors   FAT volume size in sectors
+    @param  apSectPerCluster    on return here will be suggested number of sectors per cluster
+    @param  apRootDirEntries    on return here will be suggested max. number of root dir. entries.
+*/
+void SuggestVolMetrics(TUint aVolSizeInSectors, TUint16 *apSectPerCluster, TUint *apRootDirEntries=NULL)
+{
+    const TUint16  KMaxSectorsPerCluster = 32; //-- maximal number sectors per cluster to use
+          TUint16  sectorsPerCluster;
+          TUint    rootDirEntries;
+
+    //-- suggest Sector per Cluster value, most suitable for the given volume size. (taken from CFatFormatCB::InitFormatDataForFixedSizeDiskUser(...))
+    if (aVolSizeInSectors < 4096) // < 2MB
+        {
+        sectorsPerCluster = 1;
+        rootDirEntries    = 128;
+        }
+    else if (aVolSizeInSectors < 8192) // < 4MB
+        {
+        sectorsPerCluster = Min(KMaxSectorsPerCluster, 2);
+        rootDirEntries = 256;
+        }
+    else if (aVolSizeInSectors < 32768) // < 16MB
+        {
+        sectorsPerCluster = Min(KMaxSectorsPerCluster, 4);
+        rootDirEntries = 512;
+        }
+    else if (aVolSizeInSectors < 1048576) // < 512MB
+        {
+        sectorsPerCluster = Min(KMaxSectorsPerCluster, 8);
+        rootDirEntries = 512;
+        }
+    else // FAT32
+        {
+        sectorsPerCluster = KMaxSectorsPerCluster;
+        rootDirEntries = 512;
+        }
+
+    //---------------------------------------
+    if(apSectPerCluster)
+        *apSectPerCluster = sectorsPerCluster;
+
+    if(apRootDirEntries)
+        *apRootDirEntries = rootDirEntries;
+
+}
+
+//-------------------------------------------------------------
+
+/**
+    Test user-specific FAT format. FAT type 12,16 or 32 will depend on disk size.
+    @param  aQuick if not 0 a quick format will be performed.
+*/
+void DoTestUserFormatL(TBool aQuick, TBool aMark)
+    {
+    const TUint32   KKiloByte = 1024;
+
+    TInt r;
+
+    //-- obtain current FAT volume metrics
+    TVolumeInfo volInfo;
+    r = TheFs.Volume(volInfo, gDrive);
+    TESTL(r == KErrNone);
+
+    const TInt64    volSize = volInfo.iSize; //-- volume size in bytes
+    const TUint     volSizeInSectors = TUint(volSize >> KDefaultSectorLog2); //-- sectors per volume
+
+    TUint16   sectorsPerCluster=0;
+    TUint     rootDirEntries = 0;
+    TUint     fatType = 0;
+
+    //-- roughly suggest FAT type for this volume, if FAT type is incorrect, RFormat will fail.
+    //-- suggest Sector per Cluster value, most suitable for this volume size  (taken from CFatFormatCB::InitFormatDataForFixedSizeDiskUser(...))
+    SuggestVolMetrics(volSizeInSectors, &sectorsPerCluster, &rootDirEntries);
+
+    const TUint totVolClusterCnt = volSizeInSectors / sectorsPerCluster; //-- total clusters per this volume
+
+    //-- doesn't count here FAT size, RootDir size and reserved sectors. For rough estimations only, otherwise
+    //-- it will be far too complicated.
+    const TUint dataClusterCnt = totVolClusterCnt;
+
+    //-- magic. see FAT specs for details.
+    if(dataClusterCnt < 4085)
+        fatType = TLDFormatInfo::EFB12;
+    else if(dataClusterCnt < 65525)
+        fatType = TLDFormatInfo::EFB16;
+    else
+        fatType = TLDFormatInfo::EFB32;
+
+    test.Printf(_L("Formatting drive %C:, size=%uKB, SecPerClust=%u, FAT%d\n"), ('A'+gDrive), (TUint32)(volSize/KKiloByte), sectorsPerCluster, fatType);
+
+    //-- formatting the volume
+    TInt formatCnt;
+    TLDFormatInfo formatInfo;
+
+    formatInfo.iSectorsPerCluster = sectorsPerCluster;
+    formatInfo.iFATBits = (TLDFormatInfo::TFATBits)fatType;
+
+    TSpecialFormatInfoBuf formatInfoBuf(formatInfo);
+    RFormat formatUser;
+
+    if (aQuick)
+        {
+        r = formatUser.Open(TheFs, gDriveName, ESpecialFormat|EQuickFormat, formatCnt, formatInfoBuf);
+        TESTL(r == KErrNone);
+        }
+    else
+        {
+        r = formatUser.Open(TheFs, gDriveName, ESpecialFormat, formatCnt, formatInfoBuf);
+        TESTL(r == KErrNone);
+        }
+
+    if(aMark)
+        {
+        MarkClustersL();
+        }
+
+    r = DoFormatSteps(formatUser, formatCnt);
+    TESTL(r == KErrNone || r == KErrNotSupported);
+
+    formatUser.Close();
+
+    if (r == KErrNotSupported)
+        {
+        test.Printf(_L("Media does not support ESpecialFormat"));
+        return;
+        }
+
+    //-- format has finished, Check format validity
+    TPckgBuf<TInt> sbuf;
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::ESectorsPerCluster, sbuf);
+    TESTL(r==KErrNone);
+    const TInt resSectorsPerCluster = sbuf();
+
+    TPckgBuf<TInt64> sizebuf;
+    r = TheFs.ControlIo(gDrive, CTestProxyDrive::EDiskSize, sizebuf);
+    TESTL(r==KErrNone);
+    const TInt64 resVolSize = sizebuf();
+
+    //-- Check fat type
+    TPckgBuf<TInt> tbuf;
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EFatType, tbuf);
+    TESTL(r==KErrNone);
+    const TUint resFatType = tbuf();
+
+    test.Printf(_L("Format result:, size=%uKB, SecPerClust=%u, FAT%d\n"), (TUint32)(resVolSize/KKiloByte), resSectorsPerCluster, resFatType);
+
+    TESTL(resFatType == fatType);
+
+    //-- user-defined format CFatFormatCB::InitFormatDataForFixedSizeDiskUser(TInt aDiskSizeInSectors)
+    //-- can decide decides how many SectorsPerCluster will be on the volume. As the result, requested and resulted values can be different.
+    TESTL(resSectorsPerCluster == sectorsPerCluster);
+
+    //-- check whole drive
+    test.Next(_L("Check Disk"));
+    r = TheFs.CheckDisk(gDriveName);
+    TESTL(r==KErrNone);
+    }
+
+//-------------------------------------------------------------
+
+/** Randomly generate several sector numbers in FAT data area, which will be marked as bad. */
+static void CreateBadList()
+{
+    static TInt64 rndSeed = Math::Random();
+    const TInt size = sizeof(gBadList) / sizeof(TInt);
+
+    //const TUint32 dataStartSector = BootSector.FirstFreeSector(); //-- 1st sector number of the data area (after the root directory for fat12/16)
+
+    //-- 1st sector number of the data area.
+    //-- for fat12/16 it will be 1st sector after the root directory
+    //-- for fat32 it will be the 1st sector of the second cluster after the root directory. At present we don't handle the 1st bad cluster of the root dir.
+    TUint32 dataStartSector;
+
+    if(BootSector.FatType() == EFat32)
+    {
+        dataStartSector = BootSector.RootDirStartSector() + 1*BootSector.SectorsPerCluster();
+    }
+    else
+    {
+        dataStartSector = BootSector.FirstDataSector();
+    }
+
+
+    test.Printf(_L("data start sector:%d, total sectors:%d\n"), dataStartSector, BootSector.VolumeTotalSectorNumber());
+
+     //-- randomly generate bad sectors numbers in the FAT volume data area
+    for(TInt i = 0; i<size; ++i)
+     {
+        const TUint32 rand = ((TUint32)Math::Rand(rndSeed)) % (BootSector.VolumeTotalSectorNumber() - dataStartSector);
+        const TUint32 sectNum = dataStartSector + rand;
+
+        gBadList[i] = sectNum;
+        test.Printf(_L("Value of gBadList[%d] is %d\n"), i, gBadList[i]);
+     }
+
+}
+
+
+//-------------------------------------------------------------
+
+/**
+    Read and validate the boot sector
+*/
+static void ReadBootSector()
+{
+    test.Printf(_L("Reading Boot sector...\n"));
+
+    TInt nRes = ReadBootSector(TheFs, gDrive, KBootSectorNum << KDefaultSectorLog2, BootSector);
+    test(nRes == KErrNone);
+
+    if(!BootSector.IsValid())
+    {
+        test.Printf(_L("The boot sector is invalid! dump:\n"));
+        BootSector.PrintDebugInfo();
+        test(0);
+    }
+
+}
+
+//
+// Write version number to disk using raw disk write
+// For FAT 32 the version number is written to the backup boot sector as well.
+//
+void WriteVersionNumber()
+{
+    //-- boot sector version number is already corrupt in ChangeVersionNumberAndMountL()
+    test.Printf(_L("writing boot sector version number.\n"));
+
+    TInt nRes;
+
+    //-- 1. corrupt a backup boot sector if it is on the volume. This will prevent
+    //-- using a valid backup boot sector instead of corrupted main one.
+    //-- we need to do it before corrupting the main one, because RawWrite causes volume remount.
+    TFatBootSector bs1;
+    const TUint32 KBkBootSecPos = KBkBootSectorNum << KDefaultSectorLog2;
+
+    nRes = ReadBootSector(TheFs, gDrive, KBkBootSecPos, bs1);
+    if(nRes == KErrNone && bs1.IsValid())
+    {//-- write corrupted backup boot sector
+        nRes = WriteBootSector(TheFs, gDrive, KBkBootSecPos, BootSector);
+        test(nRes == KErrNone);
+    }
+
+    //-- write main boot sector from the pos 0
+    nRes = WriteBootSector(TheFs, gDrive, KBootSectorNum << KDefaultSectorLog2, BootSector);
+    test(nRes == KErrNone);
+}
+
+//
+// Root Cluster Number update test
+//
+void DoTestRootClusterUpdate()
+{
+    test.Next(_L("Performing fat32 root cluster number update check\n"));
+
+    //Mark cluster 2 as bad by raw access.
+    RRawDisk rawDisk;
+
+    TInt r=rawDisk.Open(TheFs,gSessionPath[0]-'A');
+    test(r==KErrNone);
+
+    //Mark Cluster 2  & 3 as bad
+    const TInt fatStartPos = BootSector.FirstFatSector() * BootSector.BytesPerSector();
+    TInt64 pos = 8 + fatStartPos;
+
+    TBuf8<4> data(4);
+    data[0] = 0xF7;
+    data[1] = 0xFF;
+    data[2] = 0xFF;
+    data[3] = 0x0F;
+
+    r=rawDisk.Write(pos, data);
+    test(r==KErrNone);
+
+    pos += 4;
+    r = rawDisk.Write(pos, data);
+    test(r==KErrNone);
+
+    rawDisk.Close();
+
+    //-- quick format the drive
+    r = FormatFatDrive(TheFs, gDrive, ETrue);
+    test(r==KErrNone);
+
+    const TUint oldClusterNum = BootSector.RootClusterNum();
+    ReadBootSector();
+
+    test.Printf(_L("Old Rool clNum:%d, new:%d\n"), oldClusterNum, BootSector.RootClusterNum());
+
+    test(BootSector.RootClusterNum() != oldClusterNum);
+
+}
+
+//
+//Make version number invalid and try to mount
+//
+void ChangeVersionNumberAndMountL()
+{
+    test.Printf(_L("Change fat32 version number and remount\n"));
+
+    TFullName name;
+
+    BootSector.SetVersionNumber(0x707); //-- corrupt Version number in the boot sector
+
+    WriteVersionNumber();
+
+    TInt r = TheFs.FileSystemName(name, gDrive);
+    test(r == KErrNone);
+
+    r = DismountFileSystem(TheFs, name, gDrive);
+    test(r == KErrNone);
+
+    r = MountFileSystem(TheFs, name, gDrive);
+
+    test(r == KErrCorrupt);
+
+}
+
+
+//
+// Test version number
+//
+void DoTestVersionNumber()
+{
+    test.Next(_L("Performing fat32 version number check\n"));
+    TFullName name;
+    TInt count;
+
+    ReadBootSector();
+    ChangeVersionNumberAndMountL();
+
+    // Test quick format
+    RFormat formatQuick;
+    TInt r = formatQuick.Open(TheFs, gDriveName, EQuickFormat, count);
+    test(r == KErrNone);
+
+    r = DoFormatSteps(formatQuick, count);
+    test(r == KErrNone);
+
+    formatQuick.Close();
+
+    ReadBootSector();
+    r = TheFs.FileSystemName(name, gDrive);
+    test(r == KErrNone);
+
+    r = DismountFileSystem(TheFs, name, gDrive);
+    test(r == KErrNone);
+
+    r = MountFileSystem(TheFs, name, gDrive);
+    test(r == KErrNone);
+
+}
+
+//
+// Test format disk with bad clusters
+//
+void DoTestFormatL()
+    {
+    test.Next(_L("Test full format\n"));
+
+    // Test full format
+    TInt count;
+    TInt r = KErrNone;
+
+    RFormat formatFull;
+    r = formatFull.Open(TheFs, gDriveName, EFullFormat, count);
+    TESTL(r == KErrNone);
+
+    // Insert bad clusters, based on the boot sector info obtained by the initial format
+    MarkClustersL();
+
+    r = DoFormatSteps(formatFull, count);
+    TESTL(r == KErrNone);
+
+    formatFull.Close();
+
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EUnmarkAll, NULL, NULL);
+    TESTL(r==KErrNone);
+
+    test.Next(_L("Test quick format"));
+
+    // Test quick format
+    RFormat formatQuick;
+    r = formatQuick.Open(TheFs, gDriveName, EQuickFormat, count);
+    TESTL(r == KErrNone);
+
+    r = DoFormatSteps(formatQuick, count);
+    TESTL(r == KErrNone);
+
+    formatQuick.Close();
+
+    test.Next(_L("Test full format"));
+
+    // Test full format
+    RFormat formatFull2;
+    r = formatFull2.Open(TheFs, gDriveName, EFullFormat, count);
+    TESTL(r == KErrNone);
+    MarkClustersL();
+
+    r = DoFormatSteps(formatFull2, count);
+    TESTL(r == KErrNone);
+
+    formatFull2.Close();
+
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EUnmarkAll, NULL, NULL);
+    TESTL(r==KErrNone);
+
+    test.Next(_L("Test user specific format"));
+
+    // Test user specific format
+    DoTestUserFormatL(EFalse, EFalse);
+    ReadBootSector();
+    CreateBadList();
+    DoTestUserFormatL(EFalse, ETrue);
+
+    r = TheFs.ControlIo(gDrive, CFatTestProxyDrive::EUnmarkAll, NULL, NULL);
+    TESTL(r==KErrNone);
+
+    test.Next(_L("Test user specific quick format"));
+
+    // Test user specific quick format
+    DoTestUserFormatL(ETrue, EFalse);
+    }
+
+void DoTestL()
+    {
+    // Make sure the card is formatted, then extract boot sector info
+
+    TInt count;
+    RFormat formatFull;
+
+    //Mini SD cards works properly only with ESpecialFormat. Fix for Defect DEF091659
+    TInt r = formatFull.Open(TheFs, gDriveName, ESpecialFormat, count);
+    test(r == KErrNone);
+
+    r = DoFormatSteps(formatFull, count);
+    test(r == KErrNone);
+
+    formatFull.Close();
+
+    ReadBootSector();
+    //...and create the bad sector list
+    CreateBadList();
+
+    DoTestReadWriteL();
+
+    DoTestFormatL();
+    }
+
+
+//-------------------------------------------------------------
+
+void CallTestsL()
+    {
+#if !(defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE))
+    test.Printf(_L("Tests only run in debug mode"));
+    return;
+#else
+    // Only test FAT filesystem
+    TInt r;
+    r = TheFs.CharToDrive(gDriveToTest, gDrive);
+    test(r == KErrNone);
+    gDriveName[0] = (TText)gDriveToTest;
+    gDriveName[1] = ':';
+
+    //-- set up console output
+    Fat_Test_Utils::SetConsole(test.Console());
+
+    //-- print drive information
+    PrintDrvInfo(TheFs, gDrive);
+
+    if (!Is_Fat(TheFs, gDrive))
+        {
+        test.Printf(_L("Drive %d is not FAT file system\n"),gDrive);
+        return;
+        }
+
+    // No need for variable size disk
+    TDriveInfo info;
+    r = TheFs.Drive(info, gDrive);
+    test(r == KErrNone);
+    if (info.iMediaAtt & KMediaAttVariableSize)
+        {
+        test.Printf(_L("Drive %d is variable-size disk, skip\n"),gDrive);
+        return;
+        }
+
+    //-- perform FAT32 specific tests
+
+    if(Is_Fat32(TheFs, gDrive) && !Is_Automounter(TheFs, gDrive))
+    {//-- these tests tend to corrupt the volume; Automounter can't cope with it easily
+        DoTestVersionNumber();
+        DoTestRootClusterUpdate();
+    }
+
+    //-- install test extension etc.
+    if(!PrepareMount())
+        return;
+
+    //-- perform the rest of the tests
+    DoTestL();
+
+    //-- dismount the extension and format the drive
+    //-- there is an issue here: if one of the tests fail, the extension won't be dismounted, which
+    //-- will cause total crash.
+    RestoreEnv();
+#endif
+    }
+
+
+
+