kerneltest/f32test/filesystem/fat/b_fat32.cpp
changeset 0 a41df078684a
child 81 e7d2d738d3c2
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32test\server\b_fat32.cpp
       
    15 //
       
    16 //
       
    17 
       
    18 #include <f32file.h>
       
    19 #include <e32test.h>
       
    20 #include <e32math.h>
       
    21 
       
    22 #include "fat_utils.h"
       
    23 #include "t_server.h"
       
    24 
       
    25 using namespace Fat_Test_Utils;
       
    26 
       
    27 
       
    28 RTest test(_L("B_FAT32"));
       
    29 
       
    30 static RRawDisk TheDisk;
       
    31 static RFile TheFile;
       
    32 static RDir TheDir;
       
    33 static TEntry TheEntry;
       
    34 static TFileName TheFileName;
       
    35 static TBuf<16> TheDrive;
       
    36 
       
    37 static HBufC8* pBuffer1=NULL;
       
    38 static HBufC8* pBuffer2=NULL;
       
    39 static TBuf8<0x800> TheBuffer;
       
    40 static TEntry TheFileInfo;
       
    41 static TVolumeInfo TheVolumeInfo;
       
    42 static TBuf<8> ThePddName;
       
    43 static TFatBootSector TheBootSector;
       
    44 
       
    45 static  TInt64  rndSeed;
       
    46 static  TFatType gDiskType = EInvalid;
       
    47 
       
    48 static TInt gFatBits  = 0;
       
    49 static TInt gBytesPerCluster;
       
    50 static TInt gEntriesPerCluster;
       
    51 static TInt gDataStartBytes;
       
    52 static TInt gRootDirSectors;
       
    53 static TInt gTotalSectors;
       
    54 static TInt gRootDirStart;
       
    55 static TInt gRootSector;
       
    56 static TInt gRootCluster;
       
    57 static TInt gFatTestEntries;
       
    58 static TInt gFatSizeSectors;
       
    59 static TInt gFirstDataSector;
       
    60 static TInt gFirstDataCluster;
       
    61 static TInt gClusterCount;
       
    62 static TInt gEndOfChain;        // for FAT12/16/32
       
    63 
       
    64 const TInt KMaxFatEntries  = 2048;
       
    65 const TInt KMaxFatSize     = KMaxFatEntries * 4;
       
    66 const TInt KDirAttrReadOnly  = 0x01;
       
    67 const TInt KDirAttrHidden    = 0x02;
       
    68 const TInt KDirAttrSystem    = 0x04;
       
    69 const TInt KDirAttrVolumeId  = 0x08;
       
    70 const TInt KDirAttrDirectory = 0x10;
       
    71 const TInt KDirAttrArchive   = 0x20;
       
    72 const TInt KDirAttrLongName  = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId;
       
    73 const TInt KDirAttrLongMask  = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive;
       
    74 const TInt KDirLastLongEntry = 0x40;
       
    75 
       
    76 void CreateFatEntry(const TDesC& aDir, TBool aVFatEntry, TDes *apFileName=NULL);
       
    77 
       
    78 #define Error(aMess,aErr)  PutError(__FILE__, __LINE__, aMess,aErr)
       
    79 static void PutError(const char* aFile, TInt aLine, const TDesC& aMessage,TInt anErr)
       
    80     {
       
    81     TFileName buf;
       
    82     TPtrC8 ptr((const TUint8*)aFile);
       
    83     buf.Copy(ptr);
       
    84     test.Printf(_L("%S failed - %d\n"), &aMessage,anErr);
       
    85     test.Printf(_L("In %S line %d\n"), &buf, aLine);
       
    86     test(0);
       
    87     }
       
    88 
       
    89 
       
    90 //
       
    91 // Position calculation and disk reading routines
       
    92 // Return number of bytes into the FAT
       
    93 static  TInt PosInBytes(TInt aFatIndex)
       
    94     {
       
    95     TInt fatPosInBytes = -1;
       
    96     switch (gDiskType)
       
    97         {
       
    98         case EFat32:
       
    99             fatPosInBytes=aFatIndex<<2;
       
   100             break;
       
   101         case EFat16:
       
   102             fatPosInBytes=aFatIndex<<1;
       
   103             break;
       
   104         case EFat12:
       
   105             fatPosInBytes=(aFatIndex*3>>1);
       
   106             break;
       
   107         default:
       
   108             test(0);
       
   109         }
       
   110     return(fatPosInBytes);
       
   111     }
       
   112 
       
   113 static  TUint32 MaxClusters()
       
   114     //
       
   115     // Return the number of data clusters on the disk
       
   116     //
       
   117     {
       
   118     TUint32 totSec = (TheBootSector.TotalSectors() ? TheBootSector.TotalSectors() : TheBootSector.HugeSectors());
       
   119     TUint32 numSec = totSec - gFirstDataSector;
       
   120     return numSec / TheBootSector.SectorsPerCluster();
       
   121     }
       
   122 
       
   123 static  TInt ClusterToByte(TInt aCluster)
       
   124     //
       
   125     // converts cluster number to byte offset on disk
       
   126     //
       
   127     {
       
   128     if (aCluster < 2)
       
   129         return gRootDirStart;
       
   130     TInt sector = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * TheBootSector.BytesPerSector();
       
   131     return sector;
       
   132     }
       
   133 
       
   134  TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL)
       
   135 //
       
   136 // Read a single FAT entry from disk or FAT copy and return it
       
   137 //
       
   138     {
       
   139     TInt pos = PosInBytes(aIndex);
       
   140 
       
   141     TUint8  data[4];
       
   142     TUint8* ptr = data;
       
   143 
       
   144     if (aFat)
       
   145         ptr = (TUint8*)aFat + pos;
       
   146     else
       
   147         {
       
   148         pos += TheBootSector.ReservedSectors() * TheBootSector.BytesPerSector();
       
   149         TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
       
   150         test(r==KErrNone);
       
   151         TPtr8 buf(&data[0], 4);
       
   152         r=TheDisk.Read(pos, buf);
       
   153         test(r==KErrNone);
       
   154         TheDisk.Close();
       
   155         }
       
   156 
       
   157     TUint32 val = 0;
       
   158     switch (gDiskType)
       
   159         {
       
   160         case EFat32:
       
   161             val = *(TUint32*)ptr;
       
   162             break;
       
   163         case EFat16:
       
   164             val = *(TUint16*)ptr;
       
   165             break;
       
   166         case EFat12:
       
   167             val = *(TUint16*)ptr;
       
   168             if (aIndex & 1)
       
   169                 val >>= 4;
       
   170             val &= 0xFFF;
       
   171             break;
       
   172         default:
       
   173             test(0);
       
   174         }
       
   175     return val;
       
   176     }
       
   177 
       
   178  void MarkFatEntry(TUint32 aIndex)
       
   179 //
       
   180 // Marks a single FAT entry by modifying it's top 4 bits to
       
   181 //
       
   182     {
       
   183     TInt pos = PosInBytes(aIndex);
       
   184     pos += TheBootSector.ReservedSectors() * TheBootSector.BytesPerSector();
       
   185 
       
   186     TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
       
   187     test(r==KErrNone);
       
   188     TUint8  data[4];
       
   189     TPtr8 buf(&data[0], 4);
       
   190     r=TheDisk.Read(pos, buf);
       
   191     test(r==KErrNone);
       
   192     data[3] &= 0x0F;
       
   193     data[3] |= 0xA0;
       
   194     r=TheDisk.Write(pos, buf);
       
   195     test(r==KErrNone);
       
   196     TheDisk.Close();
       
   197         }
       
   198 
       
   199  void DumpBootSector()
       
   200 //
       
   201 // Display (in log) TFatBootSector structure
       
   202 //
       
   203     {
       
   204     RDebug::Print(_L("BytesPerSector    = %8d"), TheBootSector.BytesPerSector());
       
   205     RDebug::Print(_L("SectorsPerCluster = %8d (%d bytes)"),
       
   206                   TheBootSector.SectorsPerCluster(), gBytesPerCluster);
       
   207     RDebug::Print(_L("ReservedSectors   = %8d"), TheBootSector.ReservedSectors());
       
   208     RDebug::Print(_L("NumberOfFats      = %8d"), TheBootSector.NumberOfFats());
       
   209     RDebug::Print(_L("RootDirEntries    = %8d"), TheBootSector.RootDirEntries());
       
   210     RDebug::Print(_L("TotalSectors      = %8d"), TheBootSector.TotalSectors());
       
   211     RDebug::Print(_L("MediaDescriptor   = %8d"), TheBootSector.MediaDescriptor());
       
   212     RDebug::Print(_L("FatSectors        = %8d"), TheBootSector.FatSectors());
       
   213     RDebug::Print(_L("SectorsPerTrack   = %8d"), TheBootSector.SectorsPerTrack());
       
   214     RDebug::Print(_L("NumberOfHeads     = %8d"), TheBootSector.NumberOfHeads());
       
   215     RDebug::Print(_L("HiddenSectors     = %8d"), TheBootSector.HiddenSectors());
       
   216     RDebug::Print(_L("HugeSectors       = %8d"), TheBootSector.HugeSectors());
       
   217 
       
   218     //New for FAT32
       
   219 
       
   220     if(TheBootSector.RootDirEntries() == 0) //indicates we have FAT32 volume
       
   221         {
       
   222         RDebug::Print(_L("FatSectors32      = %8d"), TheBootSector.FatSectors32());
       
   223         RDebug::Print(_L("FATFlags          = %8d"), TheBootSector.FATFlags());
       
   224         RDebug::Print(_L("VersionNumber     = %8d"), TheBootSector.VersionNumber());
       
   225         RDebug::Print(_L("RootClusterNum    = %8d (0x%08X)"),
       
   226                       TheBootSector.RootClusterNum(),
       
   227                       gRootDirStart);
       
   228         RDebug::Print(_L("FSInfoSectorNum   = %8d (0x%08X)"),
       
   229                       TheBootSector.FSInfoSectorNum(),
       
   230                       TheBootSector.FSInfoSectorNum() * TheBootSector.BytesPerSector());
       
   231         RDebug::Print(_L("BkBootRecSector   = %8d (0x%08X)"),
       
   232                       TheBootSector.BkBootRecSector(),
       
   233                       TheBootSector.BkBootRecSector() * TheBootSector.BytesPerSector());
       
   234         }
       
   235 
       
   236     TInt fatEntries = gFatSizeSectors*TheBootSector.BytesPerSector();
       
   237     switch (gDiskType)
       
   238     {
       
   239     case EFat32:
       
   240         fatEntries /= 4;
       
   241         break;
       
   242     case EFat16:
       
   243         fatEntries /= 2;
       
   244         break;
       
   245     case EFat12:
       
   246         fatEntries *= 3;
       
   247         fatEntries /= 2;
       
   248         break;
       
   249     default:
       
   250         test(0);
       
   251     }
       
   252 
       
   253     RDebug::Print(_L("ClusterCount      = %8d (%ld bytes)"), gClusterCount, ((TInt64)gClusterCount)*gBytesPerCluster);
       
   254     RDebug::Print(_L("FatEntries        = %8d (%d sectors)"), fatEntries, gFatSizeSectors);
       
   255     RDebug::Print(_L("RootSector        = %8d (0x%08X)"), gRootSector, gRootDirStart);
       
   256     RDebug::Print(_L("FirstDataSector   = %8d (0x%08X)"), gFirstDataSector, gDataStartBytes);
       
   257     }
       
   258 
       
   259  void DumpFat(const TUint8* aFat=NULL)
       
   260 //
       
   261 // Dump to the log all those FAT entries which are non-zero
       
   262 //
       
   263     {
       
   264     TInt32 max = MaxClusters();
       
   265     if (max > KMaxFatEntries)
       
   266         max = KMaxFatEntries;
       
   267     RDebug::Print(_L("---------------- DUMP OF FAT ---------------"));
       
   268     for (TInt32 i = 0; i < max; i++)
       
   269         {
       
   270         TInt32 val = GetFatEntry(i, aFat);
       
   271         TInt32 msk = 0x0FFFFFFF;
       
   272         switch (gDiskType)
       
   273             {
       
   274             case EFat32:
       
   275                 msk = 0x0FFFFFFF;
       
   276                 break;
       
   277             case EFat16:
       
   278                 msk = 0xFFFF;
       
   279                 break;
       
   280             case EFat12:
       
   281                 msk = 0x0FFF;
       
   282                 break;
       
   283             default:
       
   284                 test(0);
       
   285             }
       
   286         if ((val & msk) == (0x0FFFFFFF & msk))
       
   287             RDebug::Print(_L("    %8d -> EOC"), i);
       
   288         else if ((val & msk) == (0x0FFFFFF8 & msk))
       
   289             RDebug::Print(_L("    %8d -> Media"), i);
       
   290         else if ((val & msk) == (0x0FFFFFF7 & msk))
       
   291             RDebug::Print(_L("    %8d -> BAD"), i);
       
   292         else if (val > max)
       
   293             RDebug::Print(_L("    %8d -> 0x%08X"), i, val);
       
   294         else if (val != 0)
       
   295             RDebug::Print(_L("    %8d -> %d"), i, val);
       
   296         }
       
   297     RDebug::Print(_L("--------------------------------------------"));
       
   298     }
       
   299 
       
   300  TDes* DirAttributes(TInt aAttrib)
       
   301 //
       
   302 // Return a pointer to a local buffer containing the attribute letters.
       
   303 //
       
   304     {
       
   305     static TBuf<6> str(_L("------"));
       
   306     static char*   atr = "RHSVDA";
       
   307     for (TInt i = 0; i < 6; i++)
       
   308         if ((aAttrib >> i) & 1)
       
   309             str[i] = atr[i];
       
   310     return &str;
       
   311     }
       
   312 
       
   313  TBool IsValidDirChar(TUint8 aChar, TUint8 aMin=0x20)
       
   314 //
       
   315 // Test whether a character is valid as part of a short filename, aMin is to
       
   316 // distinguish between first character (which can't be space) and later ones
       
   317 // which can include space but nothing less.  Note that E5 is a valid character
       
   318 // in any position, even though it means 'erased' in the first character.
       
   319 //
       
   320     {
       
   321     const TUint8* inval = (TUint8*)"\x22\x2A\x2B\x2C\x2F\x3A\x3B\x3C\x3D\x3E\x3F\x5B\x5C\x5D\x7C";
       
   322     if (aChar < aMin)
       
   323         return EFalse;
       
   324     for (const TUint8* p = inval; *p; p++)
       
   325         if (aChar == *p)
       
   326             return EFalse;
       
   327     return ETrue;
       
   328     }
       
   329 
       
   330  TBool IsValidDirEntry(TFatDirEntry* aDir)
       
   331 //
       
   332 // Test whether buffer is a valid normal directory entry
       
   333 //
       
   334     {
       
   335     // top two bits of attributes must be zero
       
   336     if (aDir->iData[11] & 0xC0)
       
   337         return EFalse;
       
   338     // first character must be 0x05 or greater than space
       
   339     if (!IsValidDirChar(aDir->iData[0], 0x21) && aDir->iData[0] != 0x05)
       
   340         return EFalse;
       
   341     // other characters in name must be not less than space
       
   342     for (TInt i = 1; i < 11; i++)
       
   343         if (!IsValidDirChar(aDir->iData[i]))
       
   344             return EFalse;
       
   345     return ETrue;
       
   346     }
       
   347 
       
   348  void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength)
       
   349 //
       
   350 // Extract part of a long name entry into the name buffer.
       
   351 //
       
   352 // @param aName   buffer to put name
       
   353 // @param aEntry  directory entry raw data
       
   354 // @param aPos    character in buffer to start name segment
       
   355 // @param aOffset offset in directory entry of the segment
       
   356 // @param aLength number of characters in the segment
       
   357 //
       
   358     {
       
   359     for (TInt i = 0; i < aLength; i++)
       
   360         {
       
   361         TInt at = i * 2 + aOffset;
       
   362         TInt ch = aEntry[at] + aEntry[at+1] * 256;
       
   363         aName[aPos++] = TText(ch);
       
   364         }
       
   365     }
       
   366 
       
   367  void ExtractNameString(TDes16& aName, const TUint8* aEntry)
       
   368 //
       
   369 // Extract a long name part from a directory entry, truncate it at the first
       
   370 // NUL (0) character and put quotes round it.
       
   371 //
       
   372     {
       
   373     aName.SetLength(15);
       
   374     TInt len = aName.Length() - 1;
       
   375     TText qu = '\'';
       
   376     aName[0] = qu;
       
   377     GetLongNamePart(aName, aEntry,  1,  1, 5);
       
   378     GetLongNamePart(aName, aEntry,  6, 14, 6);
       
   379     GetLongNamePart(aName, aEntry, 12, 28, 2);
       
   380     TInt i;
       
   381     for (i = 0; i < len; i++)
       
   382         if (aName[i] == 0)
       
   383             break;
       
   384     aName[i++] = qu;
       
   385     aName.SetLength(i);
       
   386     }
       
   387 
       
   388  TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
       
   389 //
       
   390 // Dump a single directory entry to the log.  Return false if it was end of
       
   391 // directory or an invalid entry (and don't display it).
       
   392 //
       
   393     {
       
   394     TFatDirEntry* d = (TFatDirEntry*)aEntry;
       
   395     if (d->IsErased())
       
   396         {
       
   397         // RDebug::Print(_L("%5d: ERASED"), aNum);
       
   398         }
       
   399     else if (d->IsEndOfDirectory())
       
   400         {
       
   401         RDebug::Print(_L("%5d: END-OF-DIRECTORY"), aNum);
       
   402         return EFalse;
       
   403         }
       
   404     else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName)
       
   405         {
       
   406         TBuf16<15> name;
       
   407         ExtractNameString(name, aEntry);
       
   408         TInt ord = aEntry[0];
       
   409         if (ord & KDirLastLongEntry)
       
   410             RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
       
   411         else
       
   412             RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
       
   413         }
       
   414     else if (!IsValidDirEntry(d))
       
   415         {
       
   416         RDebug::Print(_L("%5d: not valid"), aNum);
       
   417         return EFalse;
       
   418         }
       
   419     else
       
   420         {
       
   421         TBuf<11> name;
       
   422         name.Copy(d->Name());
       
   423         RDebug::Print(_L("%5d: '%S'  %S  cluster %d"),
       
   424                       aNum, &name, DirAttributes(d->Attributes()), d->StartCluster());
       
   425         }
       
   426     return ETrue;
       
   427     }
       
   428 
       
   429  void DumpDirCluster(const TUint8* aData, TInt aCluster=0)
       
   430 //
       
   431 // Dump directory entries until end of cluster or invalid/end entry found.
       
   432 //
       
   433     {
       
   434     if (aCluster > 2)
       
   435         aData += (aCluster-2) * gBytesPerCluster;
       
   436     for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry)
       
   437         {
       
   438         if (DumpDirEntry(i/KSizeOfFatDirEntry, aData))
       
   439             aData += KSizeOfFatDirEntry;
       
   440         else
       
   441             break;
       
   442         }
       
   443     }
       
   444 
       
   445  void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd=-1)
       
   446 //
       
   447 // Dump clusters from disk (allows dumping of clusters not in our buffers).
       
   448 // Only look at clusters marked as 'used' in the FAT.  Note that if aFat is
       
   449 // NULL the FAT entries will also be read from disk (slower but allows for ones
       
   450 // outside our copy in memory).
       
   451 //
       
   452     {
       
   453     if (aStart > gFatTestEntries)
       
   454         return;
       
   455     if (aEnd > gFatTestEntries)
       
   456         aEnd = gFatTestEntries;
       
   457     if (aEnd <= 0)
       
   458         aEnd = aStart + 1;
       
   459     RDebug::Print(_L("--------------- DATA AREA ------------------"));
       
   460     if (aEnd > gFatTestEntries)
       
   461         aEnd = gFatTestEntries;
       
   462     for (TInt cluster = aStart; cluster < aEnd; cluster++)
       
   463         {
       
   464         if (GetFatEntry(cluster, aFat) != 0)
       
   465             {
       
   466             HBufC8* buf=HBufC8::New(gBytesPerCluster);
       
   467             test(buf!=NULL);
       
   468             TPtr8 ptr=buf->Des();
       
   469             TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
       
   470             test(r==KErrNone);
       
   471             r=TheDisk.Read(ClusterToByte(cluster), ptr);
       
   472             test(r==KErrNone);
       
   473             TheDisk.Close();
       
   474             RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
       
   475             DumpDirCluster(ptr.Ptr());
       
   476             delete buf;
       
   477             }
       
   478         }
       
   479     RDebug::Print(_L("--------------------------------------------"));
       
   480     }
       
   481 
       
   482  void DumpData(TInt aStart=0, TInt aEnd=0)
       
   483 //
       
   484 // Dump clusters from disk (allows dumping of clusters not in our buffers).
       
   485 // Only look at clusters marked as 'used' in the FAT.  Note that if aFat is
       
   486 // NULL the FAT entries will also be read from disk (slower but allows for ones
       
   487 // outside our copy in memory).
       
   488 //
       
   489     {
       
   490     if (aStart == 0)
       
   491         {
       
   492         if (aEnd <= 0)
       
   493             aEnd = 1;
       
   494         TInt num = (gDiskType == EFat32 ? aEnd*gEntriesPerCluster : TheBootSector.RootDirEntries());
       
   495         TInt pos = gRootDirStart;
       
   496         TInt ent = 0;
       
   497         HBufC8* buf=HBufC8::New(KSizeOfFatDirEntry);
       
   498         test(buf!=NULL);
       
   499         TPtr8 ptr=buf->Des();
       
   500         TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
       
   501         test(r==KErrNone);
       
   502         RDebug::Print(_L("--------------- ROOT DIR ------------------"));
       
   503         for (TInt i = 0; i < num; i++)
       
   504             {
       
   505             r=TheDisk.Read(pos, ptr);
       
   506             test(r==KErrNone);
       
   507             if (!DumpDirEntry(ent, ptr.Ptr()))
       
   508                 break;
       
   509             pos += KSizeOfFatDirEntry;
       
   510             }
       
   511         RDebug::Print(_L("-------------------------------------------"));
       
   512         TheDisk.Close();
       
   513         delete buf;
       
   514         }
       
   515     else if (aStart == 1)
       
   516         {
       
   517         DumpData(0, 1);
       
   518         DumpData(NULL, gFirstDataCluster, aEnd);
       
   519         }
       
   520     else
       
   521         {
       
   522         DumpData(NULL, aStart, aEnd);
       
   523         }
       
   524     }
       
   525 
       
   526  void DumpHex(const TUint8* aData, TInt aLen)
       
   527 //
       
   528 // Dump a block of memory to the log in hex.
       
   529 //
       
   530     {
       
   531     for (TInt base = 0; base < aLen; base += 16)
       
   532         {
       
   533         TBuf<16*3> buf;
       
   534         TInt off;
       
   535         for (off = base; off < aLen && off < base + 16; off++)
       
   536             {
       
   537             buf.Append(TText(' '));
       
   538             buf.AppendNumFixedWidth(aData[off], EHex, 2);
       
   539             }
       
   540         RDebug::Print(_L("%04X: %S"), base, &buf);
       
   541         }
       
   542     }
       
   543 
       
   544 
       
   545 //---------------------------------------------------------------------------------------------------------------
       
   546 
       
   547 static void DoReadBootSector(TFatBootSector& aBootSector)
       
   548 {
       
   549     TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, aBootSector);
       
   550     test(nRes == KErrNone);
       
   551 
       
   552     if(!aBootSector.IsValid())
       
   553         {
       
   554         test.Printf(_L("Wrong bootsector! Dump:\n"));
       
   555         aBootSector.PrintDebugInfo();
       
   556         test(0);
       
   557         }
       
   558 
       
   559     // Calculate derived variables (fixed for a particular disk format)
       
   560 
       
   561     if (TheBootSector.FatType() == EFat32)
       
   562         {
       
   563         gDiskType = EFat32;
       
   564         gFatBits  = 32;
       
   565         gEndOfChain = 0x0FFFFFFF;
       
   566         }
       
   567     else if (TheBootSector.FatType() == EFat16)
       
   568         {
       
   569         gDiskType = EFat16;
       
   570         gFatBits  = 16;
       
   571         gEndOfChain = 0xFFFF;
       
   572         }
       
   573     else
       
   574         {
       
   575         gDiskType = EFat12;
       
   576         gFatBits  = 12;
       
   577         gEndOfChain = 0x0FFF;
       
   578         }
       
   579 
       
   580     gBytesPerCluster   = TheBootSector.BytesPerSector() * TheBootSector.SectorsPerCluster();
       
   581     gRootDirSectors    = ((TheBootSector.RootDirEntries() * KSizeOfFatDirEntry + TheBootSector.BytesPerSector() - 1) /
       
   582                           TheBootSector.BytesPerSector());
       
   583     gEntriesPerCluster = gBytesPerCluster / KSizeOfFatDirEntry;
       
   584     gTotalSectors      = (TheBootSector.TotalSectors() ? TheBootSector.TotalSectors() : TheBootSector.HugeSectors());
       
   585 
       
   586     switch (gDiskType)
       
   587         {
       
   588         case EFat12:
       
   589         case EFat16:
       
   590             gFatSizeSectors   = TheBootSector.FatSectors();
       
   591             gRootSector       = TheBootSector.ReservedSectors() + TheBootSector.NumberOfFats() * gFatSizeSectors;
       
   592             gFirstDataSector  = gRootSector + gRootDirSectors;
       
   593             gRootCluster      = 0;
       
   594             gFirstDataCluster = 2;
       
   595             gDataStartBytes   = gFirstDataSector * TheBootSector.BytesPerSector();
       
   596             gRootDirStart     = gRootSector * TheBootSector.BytesPerSector();
       
   597             break;
       
   598         case EFat32:
       
   599             gFatSizeSectors   = TheBootSector.FatSectors32();
       
   600             gRootSector       = TheBootSector.ReservedSectors() + TheBootSector.NumberOfFats() * gFatSizeSectors;
       
   601             gFirstDataSector  = gRootSector + gRootDirSectors;
       
   602             gRootCluster      = 2;
       
   603             gFirstDataCluster = 3;
       
   604             gDataStartBytes   = gFirstDataSector * TheBootSector.BytesPerSector();
       
   605             gRootDirStart     = (TheBootSector.RootClusterNum() - 2) * gBytesPerCluster + gDataStartBytes;
       
   606             break;
       
   607         default:
       
   608             break;
       
   609         }
       
   610 
       
   611     gClusterCount   = (gTotalSectors - gFirstDataSector) / TheBootSector.SectorsPerCluster();
       
   612 
       
   613     gFatTestEntries = MaxClusters();
       
   614     if (gFatTestEntries > KMaxFatSize)
       
   615         gFatTestEntries = KMaxFatSize;
       
   616     }
       
   617 
       
   618 
       
   619 static  TInt CalcShifts(TInt aSize)
       
   620 //
       
   621 // Calculate the number of shifts to get >= aSize (aSize should be a power of 2
       
   622 // anyway).
       
   623 //
       
   624     {
       
   625     TInt x=0;
       
   626     while (aSize>>=1)
       
   627         x++;
       
   628     return(x);
       
   629     }
       
   630 
       
   631 static  TInt SectorShifts()
       
   632 //
       
   633 // Calculate number of shifts for sector size.
       
   634 //
       
   635     {
       
   636     return(CalcShifts(TheBootSector.BytesPerSector()));
       
   637     }
       
   638 
       
   639 static  TInt ClusterShifts()
       
   640 //
       
   641 // Calculate number of shifts for cluster size.
       
   642 //
       
   643     {
       
   644     return(CalcShifts(TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()));
       
   645     }
       
   646 
       
   647 
       
   648 //
       
   649 // Quick Format the disk
       
   650 //
       
   651 static void FormatPack()
       
   652     {
       
   653 
       
   654     #if 0
       
   655     //-- FAT32 SPC:1; for the FAT32 testing on the emulator
       
   656     TFatFormatParam fp;
       
   657     fp.iFatType = EFat32;
       
   658     fp.iSecPerCluster = 1;
       
   659     FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fp);
       
   660     #else
       
   661 
       
   662     FormatFatDrive(TheFs, CurrentDrive(), ETrue);
       
   663 
       
   664     #endif
       
   665 
       
   666     DoReadBootSector(TheBootSector);
       
   667 
       
   668     }
       
   669 
       
   670 
       
   671 
       
   672 static  void TestReadWrite(TInt64 aPos,TInt aLen,TInt anErr)
       
   673 //
       
   674 // Read and write to the disk
       
   675 //
       
   676     {
       
   677     TPtr8 buffer((TUint8*)pBuffer1->Ptr(),aLen);
       
   678     test.Printf(_L("TestReadWrite pos=0x%lx,len=%d\n"),aPos,aLen);
       
   679     TInt r;
       
   680     if ((r=TheDisk.Read(aPos,buffer))!=anErr)
       
   681         {
       
   682         test.Printf(_L("ERROR: anErr=%d ret=%d\n"),anErr,r);
       
   683         test(EFalse);
       
   684         }
       
   685     buffer.SetLength(aLen);
       
   686     if ((r=TheDisk.Write(aPos,buffer))!=anErr)
       
   687         {
       
   688         test.Printf(_L("ERROR: anErr=%d ret=%d\n"),anErr,r);
       
   689         test(EFalse);
       
   690         }
       
   691     }
       
   692 
       
   693 static  TInt ReadWriteWord(TInt64 aPos,TInt aMask,TInt aValue)
       
   694 //
       
   695 // Read 2 bytes from aPos and Write over masked bits with aValue
       
   696 //
       
   697     {
       
   698     TUint16 word;
       
   699     TPtr8 buffer((TUint8*)&word,sizeof(word));
       
   700 
       
   701     TInt r=TheDisk.Read(aPos,buffer);
       
   702     if (r!=KErrNone)
       
   703         return(r);
       
   704 
       
   705     word&=((aValue&aMask)|~aMask);
       
   706     word|=(aValue&aMask);
       
   707 
       
   708     r=TheDisk.Write(aPos,buffer);
       
   709     return(r);
       
   710     }
       
   711 
       
   712 static  TInt ReadWriteDWord(TInt64 aPos,TInt aMask,TInt aValue)
       
   713 //
       
   714 // Read 4 bytes from aPos and Write over masked bits with aValue
       
   715 //
       
   716     {
       
   717     TUint32 word;
       
   718     TPtr8 buffer((TUint8*)&word,sizeof(word));
       
   719 
       
   720     TInt r=TheDisk.Read(aPos,buffer);
       
   721     if (r!=KErrNone)
       
   722         return(r);
       
   723 
       
   724     word&=((aValue&aMask)|~aMask);
       
   725     word|=(aValue&aMask);
       
   726 
       
   727     r=TheDisk.Write(aPos,buffer);
       
   728     return(r);
       
   729     }
       
   730 
       
   731 static  void FatWrite(TInt aCluster,TInt aValue)
       
   732 //
       
   733 //
       
   734 //
       
   735     {
       
   736     TInt pos=0;
       
   737     TInt mask=0;
       
   738 
       
   739     const TUint32  KFirstFatSectorPos = TheBootSector.FirstFatSector() * TheBootSector.BytesPerSector();
       
   740 
       
   741     switch (gDiskType)
       
   742         {
       
   743         case EFat32:
       
   744             mask=0xffffffff;
       
   745             pos=KFirstFatSectorPos+(aCluster<<2);
       
   746             break;
       
   747         case EFat16:
       
   748             mask=0xffff;
       
   749             pos=KFirstFatSectorPos+(aCluster<<1);
       
   750             break;
       
   751         case EFat12:
       
   752             mask=0x0fff;
       
   753             pos=KFirstFatSectorPos+aCluster+(aCluster>>1);
       
   754             if (aCluster & 1)
       
   755                 {
       
   756                 mask=0xfff0;
       
   757                 aValue<<=4;
       
   758                 }
       
   759             break;
       
   760         default:
       
   761             test(0);
       
   762         }
       
   763 
       
   764     TInt r=TheDisk.Open(TheFs,CurrentDrive());
       
   765     test(r==KErrNone);
       
   766     test(ReadWriteDWord(pos,mask,aValue)==KErrNone);
       
   767     TheDisk.Close();
       
   768     }
       
   769 
       
   770 static  void TestRwWord(TInt64 aPos,TInt anErr)
       
   771 //
       
   772 //
       
   773 //
       
   774     {
       
   775     TInt r;
       
   776     TUint16 wBuf;
       
   777     TUint16 rBuf;
       
   778     TUint16 mask=0;
       
   779     TUint16 value=0;
       
   780 
       
   781     test.Printf(_L("Test read and write value to 0x%lx\n"),aPos);
       
   782 
       
   783     if ((r=ReadWriteWord(aPos,mask,value))!=anErr)
       
   784         {
       
   785         test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   786         test(EFalse);
       
   787         }
       
   788 
       
   789     if (anErr==KErrNone && aPos==0)
       
   790         {
       
   791         wBuf=0xff00;
       
   792         TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
       
   793         test(TheDisk.Write(aPos,writebuf)==KErrNone);
       
   794 
       
   795         mask=0x0505;
       
   796         value=0xa4a4;
       
   797         test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
       
   798         if ((r=ReadWriteWord(aPos,mask,value))!=anErr)
       
   799             {
       
   800             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   801             test(EFalse);
       
   802             }
       
   803 
       
   804         TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
       
   805         if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
       
   806             {
       
   807             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   808             test(EFalse);
       
   809             }
       
   810         test(rBuf==0xfe04);
       
   811         }
       
   812 
       
   813     if (anErr==KErrNone && aPos==1)
       
   814         {
       
   815         wBuf=0xff00;
       
   816         TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
       
   817         test(TheDisk.Write(aPos,writebuf)==KErrNone);
       
   818 
       
   819         mask=0xffff;
       
   820         value=0xa3a3;
       
   821         test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
       
   822         if ((r=ReadWriteWord(aPos,mask,value))!=anErr)
       
   823             {
       
   824             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   825             test(EFalse);
       
   826             }
       
   827 
       
   828         TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
       
   829         if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
       
   830             {
       
   831             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   832             test(EFalse);
       
   833             }
       
   834         test(rBuf==0xa3a3);
       
   835         }
       
   836     }
       
   837 
       
   838 static  void TestRwDWord(TInt64 aPos,TInt anErr)
       
   839 //
       
   840 //
       
   841 //
       
   842     {
       
   843     TInt r;
       
   844     TUint32 wBuf;
       
   845     TUint32 rBuf;
       
   846     TUint32 mask=0;
       
   847     TUint32 value=0;
       
   848 
       
   849     test.Printf(_L("Test read and write value to 0x%lx\n"),aPos);
       
   850 
       
   851     if ((r=ReadWriteDWord(aPos,mask,value))!=anErr)
       
   852         {
       
   853         test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   854         test(EFalse);
       
   855         }
       
   856 
       
   857     if (anErr==KErrNone && aPos==0)
       
   858         {
       
   859         wBuf=0xff00ff00;
       
   860         TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
       
   861         test(TheDisk.Write(aPos,writebuf)==KErrNone);
       
   862 
       
   863         mask  = 0x0505195c;
       
   864         value = 0xa4a4c634;
       
   865         test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
       
   866         if ((r=ReadWriteDWord(aPos,mask,value))!=anErr)
       
   867             {
       
   868             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   869             test(EFalse);
       
   870             }
       
   871 
       
   872         TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
       
   873         if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
       
   874             {
       
   875             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   876             test(EFalse);
       
   877             }
       
   878         test(rBuf==0xfe04e614);
       
   879         }
       
   880 
       
   881     if (anErr==KErrNone && aPos==1)
       
   882         {
       
   883         wBuf=0xff0000ff;
       
   884         TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
       
   885         test(TheDisk.Write(aPos,writebuf)==KErrNone);
       
   886 
       
   887         mask=0xffffffff;
       
   888         value=0xa3a3dead;
       
   889         test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
       
   890         if ((r=ReadWriteDWord(aPos,mask,value))!=anErr)
       
   891             {
       
   892             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   893             test(EFalse);
       
   894             }
       
   895 
       
   896         TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
       
   897         if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
       
   898             {
       
   899             test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
       
   900             test(EFalse);
       
   901             }
       
   902         test(rBuf==0xa3a3dead);
       
   903         }
       
   904     }
       
   905 
       
   906 
       
   907 static  TInt ThrottleDirEntries(TInt aDirEntries, TInt aRemainder)
       
   908     {
       
   909     // throttle the number of entries needed, since for large cluster
       
   910     // sizes, this can take forever (eg 2GB card -> a cluster size of 32K
       
   911     // -> 1024 entries per cluster
       
   912     const TInt KMaxDirEntries = 2048;
       
   913     test(aRemainder < KMaxDirEntries);
       
   914     TInt maxDirEntries = KMaxDirEntries - aRemainder;
       
   915 
       
   916     if (aDirEntries > maxDirEntries)
       
   917         {
       
   918         RDebug::Print(_L("Reducing directory entries from %d to %d"), aDirEntries, maxDirEntries);
       
   919         aDirEntries = maxDirEntries;
       
   920         }
       
   921 
       
   922     return aDirEntries;
       
   923     }
       
   924 
       
   925 static  void TestLoopedSubDir()
       
   926 //
       
   927 //
       
   928     {
       
   929     test.Printf(_L("Test looped sub-dir\n"));
       
   930     FormatPack();
       
   931     TInt r=TheFs.MkDir(_L("\\D\\"));
       
   932     if (r!=KErrNone && r!=KErrAlreadyExists)
       
   933         Error(_L("Failed to make directory"),r);
       
   934     TheFileName=_L("\\D\\");
       
   935 
       
   936     TInt i=0;
       
   937     TInt dirEntriesNeeded = ((TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()/KSizeOfFatDirEntry)-2);
       
   938     dirEntriesNeeded = ThrottleDirEntries(dirEntriesNeeded, 2);
       
   939 
       
   940 
       
   941     //-- generate some number of VFAT dir. entries by creating  8.3 temp. files in a lower case
       
   942     for (i=0;i<dirEntriesNeeded;i++)
       
   943         {
       
   944         CreateFatEntry(TheFileName, ETrue);
       
   945         }
       
   946 
       
   947     test.Printf(_L("Test dir with no match\n"));
       
   948     FatWrite(gFirstDataCluster,gFirstDataCluster);
       
   949     if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
       
   950         Error(_L("Failed Directory open"),r);
       
   951     if ((r=TheDir.Read(TheEntry))!=KErrCorrupt)
       
   952         Error(_L("Failed Directory read"),r);
       
   953     TheDir.Close();
       
   954 
       
   955     test.Printf(_L("Test dir with match\n"));
       
   956     if ((r=TheDir.Open(TheFs,_L("\\D\\*.*"),KEntryAttMaskSupported))!=KErrNone)
       
   957         Error(_L("Failed Directory open"),r);
       
   958     if ((r=TheDir.Read(TheEntry))!=KErrNone)
       
   959         Error(_L("Failed Directory read"),r);
       
   960     TheDir.Close();
       
   961 
       
   962     test.Printf(_L("Test dir without loop\n"));
       
   963     FatWrite(gFirstDataCluster,gEndOfChain);
       
   964     if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
       
   965         Error(_L("Directory open"),r);
       
   966     if ((r=TheDir.Read(TheEntry))!=KErrEof)
       
   967         Error(_L("Reading empty dir returned"),r);
       
   968     TheDir.Close();
       
   969 
       
   970     test.Printf(_L("Test dir with long filenames\n"));
       
   971 
       
   972     FormatPack();
       
   973     r=TheFs.MkDir(_L("\\D\\"));
       
   974     if (r!=KErrNone && r!=KErrAlreadyExists)
       
   975         Error(_L("Failed to make directory"),r);
       
   976     TheFileName=_L("\\D\\");
       
   977 
       
   978     dirEntriesNeeded = ((TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()/KSizeOfFatDirEntry)-3);
       
   979     dirEntriesNeeded = ThrottleDirEntries(dirEntriesNeeded, 3);
       
   980 
       
   981     //-- generate some number of VFAT dir. entries by creating  8.3 temp. files in a lower case
       
   982     for (i=0;i<dirEntriesNeeded;i++)
       
   983         {
       
   984         CreateFatEntry(TheFileName, ETrue);
       
   985         }
       
   986 
       
   987     MakeFile(_L("\\D\\longfileName.Long"));
       
   988 
       
   989     test.Printf(_L("Test dir with no match\n"));
       
   990     FatWrite(gFirstDataCluster,gFirstDataCluster);
       
   991     if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
       
   992         Error(_L("Failed Directory open"),r);
       
   993     if ((r=TheDir.Read(TheEntry))!=KErrCorrupt)
       
   994         Error(_L("Failed Directory read"),r);
       
   995     TheDir.Close();
       
   996 
       
   997     test.Printf(_L("Test dir with match\n"));
       
   998     if ((r=TheDir.Open(TheFs,_L("\\D\\*.*"),KEntryAttMaskSupported))!=KErrNone)
       
   999         Error(_L("Failed Directory open"),r);
       
  1000     if ((r=TheDir.Read(TheEntry))!=KErrNone)
       
  1001         Error(_L("Failed Directory read"),r);
       
  1002     TheDir.Close();
       
  1003 
       
  1004     test.Printf(_L("Test dir without loop\n"));
       
  1005     FatWrite(gFirstDataCluster,gEndOfChain);
       
  1006     if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
       
  1007         Error(_L("Directory open"),r);
       
  1008 
       
  1009 #if !defined _UNICODE
       
  1010     if ((r=TheDir.Read(TheEntry))!=KErrCorrupt)
       
  1011         Error(_L("Reading empty dir returned"),r);
       
  1012 #endif
       
  1013     TheDir.Close();
       
  1014     }
       
  1015 
       
  1016 static  void TestLoopedFile()
       
  1017 //
       
  1018 // Test Looped file
       
  1019 //
       
  1020     {
       
  1021     test.Printf(_L("Test looped file\n"));
       
  1022     FormatPack();
       
  1023     TInt r;
       
  1024 
       
  1025 
       
  1026 
       
  1027     test.Next(_L("CreateFile"));
       
  1028     test(TheFile.Replace(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite)==KErrNone);
       
  1029     TPtr8 buf=pBuffer1->Des();
       
  1030 
       
  1031     test(TheFile.Write(buf,TheBootSector.BytesPerSector()-1)==KErrNone);
       
  1032     TheFile.Close();
       
  1033 
       
  1034     test.Next(_L("Write 1 cluster loop"));
       
  1035     FatWrite(gFirstDataCluster,gFirstDataCluster);              /* tiny loop */
       
  1036     if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
       
  1037         Error(_L("Error opening corrupt file"),r);
       
  1038     FatWrite(gFirstDataCluster,0);
       
  1039     if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
       
  1040         Error(_L("Error opening corrupt file"),r);
       
  1041     FatWrite(gFirstDataCluster,gEndOfChain);
       
  1042     if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrNone)
       
  1043         Error(_L("Error opening file"),r);
       
  1044     if ((r=TheFile.Write(buf,TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()*2-1))!=0)
       
  1045         Error(_L("Error writing to file"),r);
       
  1046     TheFile.Close();
       
  1047 
       
  1048     test.Next(_L("Write 2 cluster loop"));
       
  1049     FatWrite(gFirstDataCluster+1,gFirstDataCluster);             /* 2 cluster loop */
       
  1050     if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
       
  1051         Error(_L("Error opening corrupt file"),r);
       
  1052     FatWrite(gFirstDataCluster+1,gEndOfChain);
       
  1053     if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrNone)
       
  1054         Error(_L("Error opening file"),r);
       
  1055 
       
  1056     TInt len=16384;
       
  1057     TInt size=0L;
       
  1058     while (size < gBytesPerCluster * 500)
       
  1059         {
       
  1060         test.Printf(_L("\rWriting %d      "),size);
       
  1061         if ((r=TheFile.Write(buf,len))!=KErrNone)
       
  1062             {
       
  1063             if (r!=KErrDiskFull)
       
  1064                 Error(_L("File write error"),r);
       
  1065             len>>=1;
       
  1066             if (len==0)
       
  1067                 break;
       
  1068             }
       
  1069         else
       
  1070         size+=len;
       
  1071         }
       
  1072     test.Printf(_L("\n"));
       
  1073     TheFile.Close();
       
  1074 
       
  1075     RDebug::Print(_L("File created size %d"), size);
       
  1076     TInt clust=((size-1)>>ClusterShifts())+gFirstDataCluster;
       
  1077     FatWrite(clust,gFirstDataCluster);
       
  1078     if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
       
  1079         Error(_L("Error opening corrupt file"),r);
       
  1080     FatWrite(clust,gEndOfChain);
       
  1081     if ((r=TheFs.Delete(_L("\\LOOPED1.TMP")))!=KErrNone)
       
  1082         Error(_L("Error deleting file"),r);
       
  1083     RDebug::Print(_L("File removed"));
       
  1084     r=TheFs.CheckDisk(gSessionPath);
       
  1085     test(r==KErrNone);
       
  1086     }
       
  1087 
       
  1088 static  void TestFatEntry(TUint16 aFileSize,TInt aCorruptFatCluster)
       
  1089 //
       
  1090 // Test fat entry
       
  1091 //
       
  1092     {
       
  1093     TInt r;
       
  1094     test.Printf(_L("File size=%d, cluster value=0x%x\n"),aFileSize,aCorruptFatCluster);
       
  1095     FormatPack();
       
  1096 
       
  1097     r=TheFile.Replace(TheFs,_L("\\CORRUPT2.TMP"),EFileRead|EFileWrite);
       
  1098     test(r==KErrNone);
       
  1099     TheBuffer.SetLength(aFileSize);
       
  1100     Mem::Fill(&TheBuffer[0],aFileSize,'A');
       
  1101     r=TheFile.Write(TheBuffer);
       
  1102     test(r==KErrNone);
       
  1103     TheFile.Close();
       
  1104 
       
  1105     FatWrite(gFirstDataCluster,aCorruptFatCluster);
       
  1106 
       
  1107     TInt pos=0;
       
  1108     r=TheFile.Open(TheFs,_L("\\CORRUPT2.TMP"),EFileRead|EFileWrite);
       
  1109     test(r==KErrNone || r==KErrCorrupt);
       
  1110     if (r==KErrNone)
       
  1111         {
       
  1112         r=TheFile.Seek(ESeekStart,pos);
       
  1113         test(r==KErrNone);
       
  1114         r=TheFile.Write(TheBuffer);
       
  1115 
       
  1116         if ((gDriveCacheFlags & EFileCacheWriteOn) && (r == KErrNone))
       
  1117             r = TheFile.Flush();
       
  1118 
       
  1119         if (r != KErrCorrupt)
       
  1120             {
       
  1121             test.Printf(_L("Predicted error %d Actual error %d\n"),KErrCorrupt,r);
       
  1122             Error(_L("Failed write"),r);
       
  1123             }
       
  1124         TheFile.Close();
       
  1125         }
       
  1126 
       
  1127     FatWrite(gFirstDataCluster,gEndOfChain);
       
  1128 
       
  1129     pos=0;
       
  1130     r=TheFile.Open(TheFs,_L("\\CORRUPT2.TMP"),EFileRead|EFileWrite);
       
  1131     test(r==KErrNone);
       
  1132     r=TheFile.Seek(ESeekStart,pos);
       
  1133     test(r==KErrNone);
       
  1134     r=TheFile.Write(TheBuffer);
       
  1135 
       
  1136     if ((gDriveCacheFlags & EFileCacheWriteOn) && (r == KErrNone))
       
  1137             r = TheFile.Flush();
       
  1138 
       
  1139     // if the file size <= cluster size then writing last cluster marker to
       
  1140     // cluster 2 should have no effect
       
  1141     if(aFileSize>TheBootSector.SectorsPerCluster()<<SectorShifts())
       
  1142         {
       
  1143         if (r!=KErrCorrupt)
       
  1144             {
       
  1145             test.Printf(_L("Predicted error %d Actual error %d\n"),KErrCorrupt,r);
       
  1146             Error(_L("Failed write"),r);
       
  1147             }
       
  1148         }
       
  1149     else
       
  1150         {
       
  1151         if (r!=KErrNone)
       
  1152             {
       
  1153             test.Printf(_L("Predicted error %d Actual error %d\n"),KErrNone,r);
       
  1154             Error(_L("Failed write"),r);
       
  1155             }
       
  1156         }
       
  1157     TheFile.Close();
       
  1158     }
       
  1159 
       
  1160 static  void TestDirEntry(TInt anInitialSize,TInt aWriteLen,TInt aCorruptStartCluster)
       
  1161 //
       
  1162 // Test directory entry
       
  1163 //
       
  1164     {
       
  1165     test.Printf(_L("Initial size=%d, len=%d, start cluster=0x%x\n"),anInitialSize,aWriteLen,aCorruptStartCluster);
       
  1166     FormatPack();
       
  1167     TInt r;
       
  1168 
       
  1169     test(TheFile.Create(TheFs,_L("\\CORRUPT1.TMP"),EFileRead|EFileWrite)==KErrNone);
       
  1170     TheBuffer.SetLength(anInitialSize);
       
  1171     Mem::Fill(&TheBuffer[0],anInitialSize,'A');
       
  1172     r=TheFile.Write(TheBuffer);
       
  1173     test(r==KErrNone);
       
  1174     TheFile.Close();
       
  1175 
       
  1176     r=TheDisk.Open(TheFs,CurrentDrive());
       
  1177     test(r==KErrNone);
       
  1178     TPtr8 sectorBuf((TUint8*)pBuffer1->Ptr(),TheBootSector.BytesPerSector());
       
  1179     TInt pos = gRootDirStart;
       
  1180     r=TheDisk.Read(pos,sectorBuf);
       
  1181     test(r==KErrNone);
       
  1182     TFatDirEntry* pE=(TFatDirEntry*)pBuffer1->Ptr();
       
  1183     while (pE->IsVFatEntry())   //  UNICODE entries are VFat by definition
       
  1184         pE++;
       
  1185 
       
  1186     pE->SetStartCluster(aCorruptStartCluster);
       
  1187     test(TheDisk.Write(pos,sectorBuf)==KErrNone);
       
  1188 
       
  1189 
       
  1190     //-- a small hack to avoid problems with the fact that FAT[1] entry
       
  1191     //-- is now used for marking volume as clean.  TheDisk.Close() cause volume remout and
       
  1192     //-- the data
       
  1193     TheDisk.Close();
       
  1194     r=TheDisk.Open(TheFs,CurrentDrive());
       
  1195     test(r==KErrNone);
       
  1196 
       
  1197 
       
  1198     pos=0;
       
  1199     TPtr8 buffer1(pBuffer1->Des());
       
  1200     r=TheDisk.Read(pos,buffer1);
       
  1201     test(r==KErrNone);
       
  1202     TheDisk.Close();
       
  1203     r=TheFs.Entry(_L("\\CORRUPT1.TMP"),TheEntry);
       
  1204     test(r==KErrNone || r==KErrCorrupt);
       
  1205     TTime saveTime=TheEntry.iModified;
       
  1206     if (r!=KErrNone)
       
  1207         saveTime.HomeTime();
       
  1208 
       
  1209     r=TheFile.Open(TheFs,_L("\\CORRUPT1.TMP"),EFileRead|EFileWrite);
       
  1210     if (r==KErrNone)
       
  1211         {
       
  1212         TheBuffer.SetLength(aWriteLen);
       
  1213         Mem::Fill(&TheBuffer[0],aWriteLen,'B');
       
  1214         if ((r=TheFile.Write(TheBuffer))!=KErrCorrupt)
       
  1215                 {
       
  1216                 test.Printf(_L("Predicted error %d Actual error %d\n"),KErrCorrupt,r);
       
  1217                 Error(_L("Failed write"),r);
       
  1218                 }
       
  1219         TheFile.Close();
       
  1220         }
       
  1221 
       
  1222     r=TheDisk.Open(TheFs,CurrentDrive());
       
  1223     test(r==KErrNone);
       
  1224     pos=0;
       
  1225     TPtr8 buffer2(pBuffer2->Des());
       
  1226     r=TheDisk.Read(pos,buffer2);
       
  1227     test(r==KErrNone);
       
  1228 
       
  1229     //-- this bit is dodgy. The buffers may differ because of volume finalisation stuff
       
  1230     //-- FAT[1] and FSInfo sectors
       
  1231     test(buffer1==buffer2);
       
  1232     TheDisk.Close();
       
  1233 
       
  1234     r=TheFs.SetModified(_L("\\CORRUPT1.TMP"),saveTime);
       
  1235     test(r==KErrNone || r==KErrCorrupt);
       
  1236     r=TheFs.Entry(_L("\\CORRUPT1.TMP"),TheEntry);
       
  1237     test(r==KErrNone || r==KErrCorrupt);
       
  1238     }
       
  1239 
       
  1240 static  void TestBounds()
       
  1241 //
       
  1242 // Test reading/writing past the end of a drive
       
  1243 //
       
  1244     {
       
  1245     test.Next(_L("Test read/write past boundaries"));
       
  1246     test(TheFs.Volume(TheVolumeInfo,CurrentDrive())==KErrNone);
       
  1247     TInt64 size=TheVolumeInfo.iSize;
       
  1248     TInt r=TheDisk.Open(TheFs,CurrentDrive());
       
  1249     test(r==KErrNone);
       
  1250     TPtr8 buffer(pBuffer1->Des());
       
  1251     TInt64 pos=size - 2*buffer.MaxLength();
       
  1252     TInt inc=buffer.MaxLength();
       
  1253     FOREVER
       
  1254         {
       
  1255         TPtr8 tempbuf((TUint8*)pBuffer1->Ptr(),inc);
       
  1256         r=TheDisk.Read(pos,tempbuf);
       
  1257         test.Printf(_L("Read %08X:%08X len %d r %d\r"), I64HIGH(pos),I64LOW(pos), inc, r);
       
  1258         test(r==KErrNone || r==KErrCorrupt);
       
  1259         if (r==KErrNone)
       
  1260             pos+=inc;
       
  1261         else
       
  1262             {
       
  1263             inc>>=1;
       
  1264             if (inc==0)
       
  1265                 break;
       
  1266             }
       
  1267         test(pos<2*size);
       
  1268         }
       
  1269 
       
  1270     TInt64 maxcalc= TInt64(gTotalSectors) * TInt64(TheBootSector.BytesPerSector());
       
  1271 
       
  1272     test.Printf(_L("\n"));
       
  1273     test.Printf(_L("Volume size = %ld\n"), size);
       
  1274     test.Printf(_L("RawDiskSize = %ld\n"), maxcalc);
       
  1275     test.Printf(_L("MaxReadPos  = %ld\n"), pos);
       
  1276 
       
  1277     TInt64 maxpos = pos;
       
  1278 
       
  1279     // check that the calculated raw size of the disk is equal to the MaxReadPos that
       
  1280     // has just been discovered by trial and error
       
  1281     test(maxcalc == maxpos);
       
  1282 
       
  1283     for (TInt64 bsize = 1; bsize < 8; bsize++)
       
  1284         {
       
  1285         test.Printf(_L("\n"));
       
  1286         test.Printf(_L("Buffer size %d\n"), bsize);
       
  1287         for (TInt64 bpos = MAKE_TINT64(0, 0x1000); bpos < MAKE_TINT64(0x3FFFFFFF,0); bpos<<=1)
       
  1288             {
       
  1289             TInt64 endPos = (bpos + 1);
       
  1290             for (TInt64 lpos = bpos - bsize; lpos <= endPos; lpos++)
       
  1291                 {
       
  1292                 TPtr8 temp((TUint8*) (pBuffer1->Ptr()), (TInt) bsize);
       
  1293                 TInt expect = (lpos+bsize-1 < maxpos ? KErrNone : KErrCorrupt);
       
  1294                 r=TheDisk.Read(lpos, temp);
       
  1295                 RDebug::Print(_L("Read %08X:%08X result %d     \r"), I64HIGH(lpos), I64LOW(lpos), r);
       
  1296                 test(r==expect);
       
  1297                 }
       
  1298             }
       
  1299         }
       
  1300 
       
  1301     RDebug::Print(_L("\n"));
       
  1302 
       
  1303     TestReadWrite(0L,0,0);
       
  1304     TestReadWrite(0L,1,0);
       
  1305     TestReadWrite(pos-1,1,0);
       
  1306     TestReadWrite(pos-0x100,0x100,0);
       
  1307     TestReadWrite(pos-1,2,KErrCorrupt);
       
  1308     TestReadWrite(pos-0x100,0x101,KErrCorrupt);
       
  1309     TestReadWrite(pos-0xff,0x100,KErrCorrupt);
       
  1310     TestReadWrite(pos,0,0);
       
  1311     TestReadWrite(pos,1,KErrCorrupt);
       
  1312 
       
  1313     TestReadWrite(pos-16384,16384,0);
       
  1314     TestReadWrite(pos-16384,16385,KErrCorrupt);
       
  1315 
       
  1316     TInt errVal=(pos>32768+0x100) ? KErrNone : KErrCorrupt;
       
  1317     TestReadWrite(32768L,0x100,errVal);
       
  1318     errVal=(pos>32768+0x101) ? KErrNone : KErrCorrupt;
       
  1319     TestReadWrite(32768L,0x101,errVal);
       
  1320     errVal=(pos>32768+0x1ff) ? KErrNone : KErrCorrupt;
       
  1321     TestReadWrite(32768L,0xff,errVal);
       
  1322     errVal=(pos>65000+0x100) ? KErrNone : KErrCorrupt;
       
  1323     TestReadWrite(65000L,0x100,errVal);
       
  1324 
       
  1325     errVal=(pos>0x2000000+1) ? KErrNone : KErrCorrupt;
       
  1326     TestReadWrite(0x2000000L,1,errVal);
       
  1327 
       
  1328     TestRwWord(0L,0);
       
  1329     TestRwWord(1L,0);
       
  1330     TestRwWord(pos-2,0);
       
  1331     TestRwWord(pos-1,KErrCorrupt);
       
  1332     TestRwWord(pos,KErrCorrupt);
       
  1333     TestRwWord(pos+1,KErrCorrupt);
       
  1334 
       
  1335     TestRwDWord(0L,0);
       
  1336     TestRwDWord(1L,0);
       
  1337     TestRwDWord(2L,0);
       
  1338     TestRwDWord(3L,0);
       
  1339     TestRwDWord(pos-4,0);
       
  1340     TestRwDWord(pos-3,KErrCorrupt);
       
  1341     TestRwDWord(pos-2,KErrCorrupt);
       
  1342     TestRwDWord(pos-1,KErrCorrupt);
       
  1343     TestRwDWord(pos,KErrCorrupt);
       
  1344     TestRwDWord(pos+1,KErrCorrupt);
       
  1345 
       
  1346     TheDisk.Close();
       
  1347     }
       
  1348 
       
  1349 static  void TestClusters()
       
  1350     {
       
  1351     test.Next(_L("Test corrupt start cluster"));
       
  1352     //          Initial  Write  Corrupt
       
  1353     //           Size     Len   Cluster
       
  1354     TestDirEntry(1024,    513,      0);
       
  1355     TestDirEntry( 512,    512,      0);
       
  1356     TestDirEntry(1024,    513,      1);
       
  1357     TestDirEntry( 512,    512,      1);
       
  1358     TestDirEntry(1024,    513,  0xff0);
       
  1359 
       
  1360     test.Printf(_L("Test corrupt chain\n"));
       
  1361     TestFatEntry(1536,0);
       
  1362     TestFatEntry(1536,1);
       
  1363 
       
  1364 //  TInt fatCacheSize=FatCacheSize();
       
  1365 //  TUint16 cluster16=(TUint16)(fatCacheSize/2);
       
  1366 //  TUint16 cluster12=(TUint16)((fatCacheSize/3)*2);
       
  1367 //  TestFatEntry(1536,cluster12);
       
  1368 //  TestFatEntry(1536,cluster16);
       
  1369     TestFatEntry(1536,0xff0);
       
  1370     // don't test when only one cluster for the file
       
  1371     if(1536>gBytesPerCluster)
       
  1372         TestFatEntry(1536,gEndOfChain);
       
  1373 
       
  1374     TestLoopedFile();
       
  1375     TestLoopedSubDir();
       
  1376     }
       
  1377 
       
  1378 
       
  1379 static  void TestClusterAllocation()
       
  1380 //
       
  1381 // Test number of clusters allocated
       
  1382 //
       
  1383     {
       
  1384     test.Next(_L("Test number of clusters allocated is correct"));
       
  1385 
       
  1386     FormatPack();
       
  1387 
       
  1388     RFile f;
       
  1389     TInt r;
       
  1390 
       
  1391     r=f.Replace(TheFs,_L("\\GOBLIN.TMP"),EFileRead|EFileWrite);
       
  1392     test(r==KErrNone);
       
  1393     f.SetSize(4*gBytesPerCluster); // 4 Clusters
       
  1394     f.Close();
       
  1395 
       
  1396     r=f.Replace(TheFs,_L("\\WIZARD.TMP"),EFileRead|EFileWrite);
       
  1397     test(r==KErrNone);
       
  1398     f.SetSize(5*gBytesPerCluster); // 5 Clusters
       
  1399     f.Close();
       
  1400 
       
  1401     r=f.Replace(TheFs,_L("\\TROLL.TMP"),EFileRead|EFileWrite);
       
  1402     test(r==KErrNone);
       
  1403     f.SetSize(3*gBytesPerCluster); // 3 Clusters
       
  1404     f.Close();
       
  1405 
       
  1406     r=f.Replace(TheFs,_L("\\GNOME.TMP"),EFileRead|EFileWrite);
       
  1407     test(r==KErrNone);
       
  1408     f.SetSize(10*gBytesPerCluster); // 10 Clusters
       
  1409     f.Close();
       
  1410 
       
  1411     r=f.Replace(TheFs,_L("\\CYCLOPS.TMP"),EFileRead|EFileWrite);
       
  1412     test(r==KErrNone);
       
  1413     f.SetSize(gBytesPerCluster); // 1 Cluster
       
  1414     f.Close();
       
  1415 
       
  1416     r=f.Replace(TheFs,_L("\\PIXIE.TMP"),EFileRead|EFileWrite);
       
  1417     test(r==KErrNone);
       
  1418     f.SetSize(gBytesPerCluster); // 1 Cluster
       
  1419     f.Close();
       
  1420 
       
  1421     r=TheDisk.Open(TheFs,CurrentDrive());
       
  1422     test(r==KErrNone);
       
  1423     TPtr8 sectorBuf((TUint8*)pBuffer1->Ptr(),TheBootSector.BytesPerSector());
       
  1424     TInt pos = gRootDirStart;
       
  1425     test(TheDisk.Read(pos,sectorBuf)==KErrNone);
       
  1426     TheDisk.Close();
       
  1427 
       
  1428     TFatDirEntry* pE=(TFatDirEntry*)pBuffer1->Ptr();
       
  1429     while (pE->IsVFatEntry())   //  UNICODE 8.3 filenames are VFAT by definition
       
  1430         pE++;
       
  1431 
       
  1432     TInt cluster=pE->StartCluster();
       
  1433     TBuf8<15> name=pE->Name();
       
  1434     test(name==_L8("GOBLIN  TMP"));
       
  1435 
       
  1436     pE++;
       
  1437     while (pE->IsVFatEntry())
       
  1438         pE++;
       
  1439 
       
  1440     test((pE->StartCluster()-cluster)==4);
       
  1441     cluster=pE->StartCluster();
       
  1442     name=pE->Name();
       
  1443     test(name==_L8("WIZARD  TMP"));
       
  1444 
       
  1445     pE++;
       
  1446     while (pE->IsVFatEntry())
       
  1447         pE++;
       
  1448 
       
  1449     test((pE->StartCluster()-cluster)==5);
       
  1450     cluster=pE->StartCluster();
       
  1451     name=pE->Name();
       
  1452     test(name==_L8("TROLL   TMP"));
       
  1453 
       
  1454     pE++;
       
  1455     while (pE->IsVFatEntry())
       
  1456         pE++;
       
  1457 
       
  1458     test((pE->StartCluster()-cluster)==3);
       
  1459     cluster=pE->StartCluster();
       
  1460     name=pE->Name();
       
  1461     test(name==_L8("GNOME   TMP"));
       
  1462 
       
  1463     pE++;
       
  1464     while (pE->IsVFatEntry())
       
  1465         pE++;
       
  1466 
       
  1467     test ((pE->StartCluster()-cluster)==10);
       
  1468     cluster=pE->StartCluster();
       
  1469     name=pE->Name();
       
  1470     test(name==_L8("CYCLOPS TMP"));
       
  1471 
       
  1472     pE++;
       
  1473     while (pE->IsVFatEntry())
       
  1474         pE++;
       
  1475 
       
  1476     test((pE->StartCluster()-cluster)==1);
       
  1477     name=pE->Name();
       
  1478     test(name==_L8("PIXIE   TMP"));
       
  1479 
       
  1480     r=TheFs.Delete(_L("\\GOBLIN.TMP"));
       
  1481     test(r==KErrNone);
       
  1482     r=TheFs.Delete(_L("\\WIZARD.TMP"));
       
  1483     test(r==KErrNone);
       
  1484     r=TheFs.Delete(_L("\\TROLL.TMP"));
       
  1485     test(r==KErrNone);
       
  1486     r=TheFs.Delete(_L("\\GNOME.TMP"));
       
  1487     test(r==KErrNone);
       
  1488     r=TheFs.Delete(_L("\\CYCLOPS.TMP"));
       
  1489     test(r==KErrNone);
       
  1490     r=TheFs.Delete(_L("\\PIXIE.TMP"));
       
  1491     test(r==KErrNone);
       
  1492 
       
  1493     FormatPack();
       
  1494 
       
  1495     }
       
  1496 
       
  1497 
       
  1498 static  void TestMakeDir(const TDesC& aName,TInt aNewClust,TInt aParentClust)
       
  1499 //
       
  1500 // Test make dir
       
  1501 //
       
  1502     {
       
  1503     test.Printf(_L("Checking cluster %02d, parent %d: \"%S\"\n"), aNewClust, aParentClust, &aName);
       
  1504 
       
  1505     TInt r=TheFs.MkDir(aName);
       
  1506     test(r==KErrNone || r==KErrAlreadyExists);
       
  1507 
       
  1508     TInt pos=ClusterToByte(aNewClust);
       
  1509     TPtr8 sectorBuf((TUint8*)pBuffer1->Ptr(),gBytesPerCluster);
       
  1510 
       
  1511     r=TheDisk.Open(TheFs,CurrentDrive());
       
  1512     if ((r=TheDisk.Read(pos,sectorBuf))!=KErrNone)
       
  1513         Error(_L("Reading data"),r);
       
  1514     TheDisk.Close();
       
  1515 
       
  1516     TFatDirEntry* pE=(TFatDirEntry*)pBuffer1->Ptr();
       
  1517     if (pE->Name()[0]!='.' || pE->Name()[1]!=' ')
       
  1518         {
       
  1519         while (pE->IsVFatEntry())
       
  1520             pE++;
       
  1521         if (pE->Name()[0]!='.' || pE->Name()[1]!=' ')
       
  1522             Error(_L("Failed to find '.' entry"),KErrNone);
       
  1523         }
       
  1524     if (pE->StartCluster()!=aNewClust)
       
  1525         Error(_L("Bad directory start cluster"),KErrNone);
       
  1526     pE++;
       
  1527     if (pE->Name()[0]!='.' || pE->Name()[1]!='.')
       
  1528         Error(_L("Second entry is not '..'"),KErrNone);
       
  1529     if (pE->StartCluster() != ((aParentClust==gRootCluster)?0:aParentClust))
       
  1530         Error(_L("Start cluster of .. is not parent directory"),KErrNone);
       
  1531     }
       
  1532 
       
  1533 
       
  1534 
       
  1535 static  void TestParentDir(TBool aUseVfat)
       
  1536     {
       
  1537 
       
  1538     test.Next(_L("TestParentDir()"));
       
  1539 
       
  1540     TInt root = gRootCluster;
       
  1541     TInt cl   = gFirstDataCluster;
       
  1542     TInt p1   = cl;
       
  1543 
       
  1544     FormatPack();
       
  1545 
       
  1546     TestMakeDir(_L("\\P1\\"), cl++, root);
       
  1547 
       
  1548 
       
  1549     const TInt nDirEntries= gBytesPerCluster / KSizeOfFatDirEntry; //-- number of dir. entries to fill 1 cluster
       
  1550     const TInt nFiles =  aUseVfat ? nDirEntries/2 : nDirEntries;   //-- number of 8.3 files to fill 1 cluster
       
  1551 
       
  1552     cl++;
       
  1553     for (TInt i=0;i<nFiles;i++)
       
  1554         {
       
  1555         CreateFatEntry(_L("\\P1\\"), aUseVfat);
       
  1556         }
       
  1557 
       
  1558 
       
  1559     TInt p1p2 = cl;
       
  1560     if(aUseVfat)
       
  1561         {
       
  1562         TestMakeDir(_L("\\p1\\p2\\"),       cl++, p1);
       
  1563         TestMakeDir(_L("\\p1\\p21\\"),      cl++, p1);
       
  1564         TestMakeDir(_L("\\p1\\p2\\p3\\"),   cl++, p1p2);
       
  1565         TestMakeDir(_L("\\p1\\p2\\p33\\"),  cl++, p1p2);
       
  1566         TestMakeDir(_L("\\p1\\p2\\p34\\"),  cl++, p1p2);
       
  1567         TestMakeDir(_L("\\p1\\p2\\p35\\"),  cl++, p1p2);
       
  1568         TestMakeDir(_L("\\p1\\p2\\p36\\"),  cl++, p1p2);
       
  1569         TestMakeDir(_L("\\p1\\p2\\p37\\"),  cl++, p1p2);
       
  1570         TestMakeDir(_L("\\p1\\p2\\p38\\"),  cl++, p1p2);
       
  1571         }
       
  1572     else
       
  1573         {
       
  1574         TestMakeDir(_L("\\P1\\P2\\"),       cl++, p1);
       
  1575         TestMakeDir(_L("\\P1\\P21\\"),      cl++, p1);
       
  1576         TestMakeDir(_L("\\P1\\P2\\P3\\"),   cl++, p1p2);
       
  1577         TestMakeDir(_L("\\P1\\P2\\P33\\"),  cl++, p1p2);
       
  1578         TestMakeDir(_L("\\P1\\P2\\P34\\"),  cl++, p1p2);
       
  1579         TestMakeDir(_L("\\P1\\P2\\P35\\"),  cl++, p1p2);
       
  1580         TestMakeDir(_L("\\P1\\P2\\P36\\"),  cl++, p1p2);
       
  1581         TestMakeDir(_L("\\P1\\P2\\P37\\"),  cl++, p1p2);
       
  1582         TestMakeDir(_L("\\P1\\P2\\P38\\"),  cl++, p1p2);
       
  1583 
       
  1584         TestMakeDir(_L("\\P1\\P2\\P39\\"),  cl++, p1p2);
       
  1585         TestMakeDir(_L("\\P1\\P2\\P40\\"),  cl++, p1p2);
       
  1586         TestMakeDir(_L("\\P1\\P2\\P41\\"),  cl++, p1p2);
       
  1587         TestMakeDir(_L("\\P1\\P2\\P42\\"),  cl++, p1p2);
       
  1588         TestMakeDir(_L("\\P1\\P2\\P43\\"),  cl++, p1p2);
       
  1589         TestMakeDir(_L("\\P1\\P2\\P44\\"),  cl++, p1p2);
       
  1590         TestMakeDir(_L("\\P1\\P2\\P45\\"),  cl++, p1p2);
       
  1591         }
       
  1592 
       
  1593     // if sectors/cluster == 1 then the directory \p1\p2\ will now have to
       
  1594     // allocate another cluster
       
  1595     if(TheBootSector.SectorsPerCluster()==1)
       
  1596         ++cl;
       
  1597     if(aUseVfat)
       
  1598         {
       
  1599         TestMakeDir(_L("\\p1\\p2\\p310\\"), cl++, p1p2);
       
  1600         TestMakeDir(_L("\\p1\\p2\\p311\\"), cl++, p1p2);
       
  1601         TestMakeDir(_L("\\p1\\p2\\p312\\"), cl++, p1p2);
       
  1602         TestMakeDir(_L("\\p1\\p2\\p313\\"), cl++, p1p2);
       
  1603         TestMakeDir(_L("\\p1\\p2\\p314\\"), cl++, p1p2);
       
  1604         TestMakeDir(_L("\\p1\\p2\\p315\\"), cl++, p1p2);
       
  1605         TestMakeDir(_L("\\p1\\p2\\p316\\"), cl++, p1p2);
       
  1606         TestMakeDir(_L("\\p1\\p2\\p317\\"), cl++, p1p2);
       
  1607         }
       
  1608     else
       
  1609         {
       
  1610         TestMakeDir(_L("\\P1\\P2\\P310\\"),  cl++, p1p2);
       
  1611         TestMakeDir(_L("\\P1\\P2\\P311\\"),  cl++, p1p2);
       
  1612         TestMakeDir(_L("\\P1\\P2\\P312\\"),  cl++, p1p2);
       
  1613         TestMakeDir(_L("\\P1\\P2\\P313\\"),  cl++, p1p2);
       
  1614         TestMakeDir(_L("\\P1\\P2\\P314\\"),  cl++, p1p2);
       
  1615         TestMakeDir(_L("\\P1\\P2\\P315\\"),  cl++, p1p2);
       
  1616         TestMakeDir(_L("\\P1\\P2\\P316\\"),  cl++, p1p2);
       
  1617         TestMakeDir(_L("\\P1\\P2\\P317\\"), cl++, p1p2);
       
  1618 
       
  1619         TestMakeDir(_L("\\P1\\P2\\P318\\"), cl++, p1p2);
       
  1620         TestMakeDir(_L("\\P1\\P2\\P319\\"), cl++, p1p2);
       
  1621         TestMakeDir(_L("\\P1\\P2\\P320\\"), cl++, p1p2);
       
  1622         TestMakeDir(_L("\\P1\\P2\\P321\\"), cl++, p1p2);
       
  1623         TestMakeDir(_L("\\P1\\P2\\P322\\"), cl++, p1p2);
       
  1624         TestMakeDir(_L("\\P1\\P2\\P323\\"), cl++, p1p2);
       
  1625         TestMakeDir(_L("\\P1\\P2\\P324\\"), cl++, p1p2);
       
  1626         TestMakeDir(_L("\\P1\\P2\\P325\\"), cl++, p1p2);
       
  1627         }
       
  1628 
       
  1629     // if sectors/cluster <= 2 then the directory \p1\p2\ will have to
       
  1630     // allocate another cluster
       
  1631     if(TheBootSector.SectorsPerCluster()<=2)
       
  1632         ++cl;
       
  1633     TestMakeDir(_L("\\P1\\P2\\P330\\"),  cl++, p1p2);
       
  1634     TestMakeDir(_L("\\P11\\"),           cl++, root);
       
  1635     }
       
  1636 
       
  1637 static const TInt KMaxFiles=5;
       
  1638 
       
  1639 //
       
  1640 // Test root dir size
       
  1641 //
       
  1642 static  void TestRoot()
       
  1643     {
       
  1644     test.Next(_L("Test root dir size"));
       
  1645 
       
  1646     if (gDiskType == EFat32)
       
  1647         {
       
  1648         test.Printf(_L("Not possible on FAT32 filesystem\n"));
       
  1649         return;
       
  1650         }
       
  1651 
       
  1652     FormatPack();
       
  1653     TInt rootEntries=TheBootSector.RootDirEntries();
       
  1654     test.Printf(_L("Total root entries allowed = %d\n"),rootEntries);
       
  1655     TFileName fileName[KMaxFiles];  //  KMaxFiles=5 in this test
       
  1656     TFileName tempName;
       
  1657     TInt numberOfEntries=rootEntries;
       
  1658     TInt r;
       
  1659     RFile f;
       
  1660 
       
  1661     //-- generate 8.3 FAT entries, temp files created in upper-case, otherwise it will be 2 vFAT entries
       
  1662     while(numberOfEntries--)
       
  1663         {
       
  1664         if (numberOfEntries<KMaxFiles)
       
  1665             CreateFatEntry(_L("\\"), EFalse, &fileName[numberOfEntries]);
       
  1666         else
       
  1667             CreateFatEntry(_L("\\"), EFalse);
       
  1668 
       
  1669         }
       
  1670 
       
  1671     r = f.Create(TheFs, _L("\\123456.78"), EFileRead|EFileWrite);
       
  1672     test(r==KErrDirFull);
       
  1673     f.Close();
       
  1674 
       
  1675 
       
  1676     TInt i=0;
       
  1677     for (i=0;i<KMaxFiles;i++)
       
  1678         {
       
  1679         r=TheFs.Delete(fileName[i]);
       
  1680         test(r==KErrNone);
       
  1681         }
       
  1682 
       
  1683     r=TheFs.SetSessionPath(_L("\\"));
       
  1684     test(r==KErrNone);
       
  1685 
       
  1686     TInt nameLength=(KMaxFiles-1)*13;   // -1 for zero terminator
       
  1687     CreateLongName(tempName,gSeed,nameLength*2);
       
  1688     r=f.Create(TheFs,tempName,0);       //  Needs 9 free entries - there are only 5 available
       
  1689     test(r==KErrDirFull);
       
  1690     tempName.SetLength(nameLength+1);
       
  1691     r=f.Create(TheFs,tempName,0);       //  Needs 6 free entries - there are only 5 available
       
  1692     test(r==KErrDirFull);
       
  1693     tempName.SetLength(nameLength);
       
  1694     r=f.Create(TheFs,tempName,0);       //  Needs 5 free entries - there are 5 available
       
  1695     test(r==KErrNone);
       
  1696     f.Close();
       
  1697 
       
  1698 #if 0       // This is the old test that assumed UNICODE builds
       
  1699             // which created VFAT entries even for uppercase 8.3 file names
       
  1700     TInt i=0;
       
  1701     for (i=0;i<KMaxFiles-2;i++)
       
  1702         {
       
  1703         r=TheFs.Delete(fileName[i]);    //  UNICODE build - free 6 entries (delete 3 files)
       
  1704         test(r==KErrNone);
       
  1705         }
       
  1706 
       
  1707     r=TheFs.SetSessionPath(_L("\\"));
       
  1708     test(r==KErrNone);
       
  1709 
       
  1710     TInt vFatUnitNameSize=13;
       
  1711     TInt nameLength=(KMaxFiles-1)*vFatUnitNameSize-1;   //
       
  1712     CreateLongName(tempName,gSeed,nameLength*2);
       
  1713     r=f.Create(TheFs,tempName,0);                       //  Needs 9 free entries
       
  1714     test(r==KErrDirFull);
       
  1715 
       
  1716     nameLength=(KMaxFiles)*vFatUnitNameSize;
       
  1717     tempName.SetLength(nameLength+1);
       
  1718     r=f.Create(TheFs,tempName,0);                       //  Needs 7 free entries
       
  1719     test(r==KErrDirFull);
       
  1720     tempName.SetLength(nameLength);
       
  1721     r=f.Create(TheFs,tempName,0);                       //  Needs 6 free entries
       
  1722     test(r==KErrNone);
       
  1723     f.Close();
       
  1724 #endif
       
  1725 
       
  1726     TheFs.Delete(tempName);
       
  1727     tempName.SetLength(nameLength-7);
       
  1728     r=f.Create(TheFs,tempName,0);
       
  1729     test(r==KErrNone);
       
  1730     f.Close();
       
  1731 
       
  1732     r=f.Create(TheFs,_L("ASDF"),0);
       
  1733     test(r==KErrDirFull);
       
  1734 
       
  1735     TheFs.Delete(tempName);
       
  1736     tempName.SetLength(nameLength-15);
       
  1737     r=f.Create(TheFs,tempName,0);
       
  1738     test(r==KErrNone);
       
  1739     f.Close();
       
  1740 
       
  1741     tempName=_L("testname");
       
  1742     r=f.Create(TheFs,tempName,0);
       
  1743     test(r==KErrDirFull);
       
  1744     tempName.UpperCase();
       
  1745     r=f.Create(TheFs,tempName,0);
       
  1746     test(r==KErrNone);
       
  1747     f.Close();
       
  1748 
       
  1749 
       
  1750     r=TheFs.SetSessionPath(gSessionPath);
       
  1751     test(r==KErrNone);
       
  1752     }
       
  1753 
       
  1754 static  void TestVolumeSize()
       
  1755 //
       
  1756 // Test the volume size is zero when empty
       
  1757 //
       
  1758     {
       
  1759     test.Next(_L("Test the volume size"));
       
  1760     FormatPack();
       
  1761 
       
  1762     TVolumeInfo volInfo;
       
  1763     TInt r=TheFs.Volume(volInfo);
       
  1764     test(r==KErrNone);
       
  1765     TInt64 calcsize = MAKE_TINT64(0, gClusterCount)*gBytesPerCluster;
       
  1766     if (volInfo.iSize > calcsize)
       
  1767         {
       
  1768         test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
       
  1769         test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
       
  1770         test.Printf(_L("calculated    = %ld\n"), calcsize);
       
  1771         TInt diff = I64LOW(volInfo.iSize-calcsize);
       
  1772         test.Printf(_L("difference    = %d (%d clusters)\n"), diff, diff/gBytesPerCluster);
       
  1773         test(0);
       
  1774         }
       
  1775     if (gDiskType == EFat32)
       
  1776         volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
       
  1777     if (volInfo.iSize != volInfo.iFree)
       
  1778         {
       
  1779         test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
       
  1780         test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
       
  1781         TInt diff = I64LOW(volInfo.iSize-volInfo.iFree);
       
  1782         test.Printf(_L("difference    = %d (%d clusters)\n"), diff, diff/gBytesPerCluster);
       
  1783         DumpData();
       
  1784         DumpFat();
       
  1785         test(0);
       
  1786         }
       
  1787 
       
  1788     RFile f[KMaxFiles];
       
  1789     TFileName fileName;
       
  1790     TInt i=0;
       
  1791     for (i=0;i<KMaxFiles;i++)
       
  1792         {
       
  1793         fileName=_L("\\File");
       
  1794         fileName.AppendNum(i);
       
  1795         r=f[i].Create(TheFs,fileName,0);
       
  1796         test(r==KErrNone);
       
  1797         }
       
  1798 
       
  1799     TInt maxTotalSize=1048576;
       
  1800     TInt maxFileSize=maxTotalSize/KMaxFiles;
       
  1801     TInt maxIterations=20;
       
  1802 
       
  1803     while(maxIterations--)
       
  1804         {
       
  1805         for (i=0;i<KMaxFiles;i++)
       
  1806             {
       
  1807             TInt randSize=Math::Rand(gSeed)%maxFileSize;
       
  1808             r=f[i].SetSize(randSize);
       
  1809             test(r==KErrNone);
       
  1810             }
       
  1811         test.Printf(_L("Countdown .. %d   \r"),maxIterations);
       
  1812         }
       
  1813 
       
  1814     test.Printf(_L("\n"));
       
  1815 
       
  1816     TInt totalSize=0;
       
  1817 
       
  1818     for (i=0;i<KMaxFiles;i++)
       
  1819         {
       
  1820         TInt size=0;
       
  1821         r=f[i].Size(size);
       
  1822         test(r==KErrNone);
       
  1823         totalSize+=((size+gBytesPerCluster-1)/gBytesPerCluster)*gBytesPerCluster;
       
  1824         }
       
  1825 
       
  1826     r=TheFs.Volume(volInfo);
       
  1827     test(r==KErrNone);
       
  1828     if (gDiskType == EFat32)
       
  1829         volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
       
  1830     if (volInfo.iSize-volInfo.iFree!=totalSize)
       
  1831         {
       
  1832         test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
       
  1833         test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
       
  1834         test.Printf(_L("totalSize     = %ld\n"), totalSize);
       
  1835         TInt diff = I64LOW(volInfo.iSize-volInfo.iFree) - totalSize;
       
  1836         test.Printf(_L("difference    = %d (%d clusters)\n"), diff, diff/gBytesPerCluster);
       
  1837         }
       
  1838     test(volInfo.iSize-volInfo.iFree==totalSize);
       
  1839 
       
  1840     for (i=0;i<KMaxFiles;i++)
       
  1841         f[i].Close();
       
  1842 
       
  1843     for (i=0;i<KMaxFiles;i++)
       
  1844         {
       
  1845         fileName=_L("\\File");
       
  1846         fileName.AppendNum(i);
       
  1847         r=TheFs.Delete(fileName);
       
  1848         test(r==KErrNone);
       
  1849         }
       
  1850 
       
  1851     r=TheFs.Volume(volInfo);
       
  1852     if (gDiskType == EFat32)
       
  1853         volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
       
  1854     test(r==KErrNone);
       
  1855     test(volInfo.iSize-volInfo.iFree==0);
       
  1856 
       
  1857     MakeDir(gSessionPath);
       
  1858 
       
  1859     TInt entries=(gBytesPerCluster/KSizeOfFatDirEntry)*5-2;
       
  1860     entries = ThrottleDirEntries(entries, 2);
       
  1861 
       
  1862     TInt clusters = ((entries * KSizeOfFatDirEntry) + gBytesPerCluster-1) / gBytesPerCluster;
       
  1863 
       
  1864     //-- create "entries" FAT dir. entries by creating 8.3 files in upper case
       
  1865     while(entries--)
       
  1866         {
       
  1867         CreateFatEntry(gSessionPath, EFalse);
       
  1868         }
       
  1869 
       
  1870 
       
  1871     r=TheFs.Volume(volInfo);
       
  1872     test(r==KErrNone);
       
  1873     if (gDiskType == EFat32)
       
  1874         volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
       
  1875     test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
       
  1876     test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
       
  1877     if (volInfo.iSize-volInfo.iFree!=clusters*gBytesPerCluster)
       
  1878         {
       
  1879         DumpFat();
       
  1880         DumpData(1, 200);
       
  1881         }
       
  1882     test(volInfo.iSize-volInfo.iFree==clusters*gBytesPerCluster);
       
  1883 
       
  1884     //-- create 1 FAT dir. entry
       
  1885     CreateFatEntry(gSessionPath, EFalse);
       
  1886 
       
  1887     r=TheFs.Volume(volInfo);
       
  1888     test(r==KErrNone);
       
  1889     if (gDiskType == EFat32)
       
  1890         volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
       
  1891     test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
       
  1892     test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
       
  1893     if (volInfo.iSize-volInfo.iFree!=(clusters+1)*gBytesPerCluster)
       
  1894         {
       
  1895         DumpFat();
       
  1896         DumpData(1, 200);
       
  1897         }
       
  1898     test(volInfo.iSize-volInfo.iFree==(clusters+1)*gBytesPerCluster);
       
  1899 
       
  1900     CFileMan* fMan=CFileMan::NewL(TheFs);
       
  1901     r=fMan->RmDir(gSessionPath);
       
  1902     test(r==KErrNone);
       
  1903     delete fMan;
       
  1904     r=TheFs.Volume(volInfo);
       
  1905     test(r==KErrNone);
       
  1906     if (gDiskType == EFat32)
       
  1907         volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
       
  1908     if (volInfo.iSize-volInfo.iFree!=0)
       
  1909         {
       
  1910         DumpFat();
       
  1911         DumpData(1, 200);
       
  1912         }
       
  1913     test(volInfo.iSize-volInfo.iFree==0);
       
  1914     }
       
  1915 
       
  1916 
       
  1917 //
       
  1918 // Writes a standard dos entry to the disk and checks that this can be read
       
  1919 // (in Unicode build)
       
  1920 //
       
  1921 static  void TestUnicodeEntry()
       
  1922     {
       
  1923     test.Next(_L("Test Unicode entry"));
       
  1924 
       
  1925     const TInt KDirEntrySize=32;
       
  1926 
       
  1927     FormatPack();
       
  1928     DoReadBootSector(TheBootSector);
       
  1929     TInt pos=gRootDirStart;
       
  1930 
       
  1931     TBuf8<KDirEntrySize> buffer;
       
  1932     buffer.SetLength(KDirEntrySize);
       
  1933     buffer.FillZ();
       
  1934     buffer.Replace(0,11,_L8("TEST1      "));
       
  1935 
       
  1936     TInt r=TheDisk.Open(TheFs,CurrentDrive());
       
  1937     test(r==KErrNone);
       
  1938     r=TheDisk.Write(pos,buffer);
       
  1939     test(r==KErrNone);
       
  1940     TheDisk.Close();
       
  1941 
       
  1942     r=TheDir.Open(TheFs,_L("\\"),KEntryAttMaskSupported);
       
  1943     test(r==KErrNone);
       
  1944     r=TheDir.Read(TheEntry);
       
  1945     test(r==KErrNone);
       
  1946     test(TheEntry.iName==_L("TEST1"));
       
  1947     r=TheDir.Read(TheEntry);
       
  1948     test(r==KErrEof);
       
  1949     TheDir.Close();
       
  1950 
       
  1951     r=TheFs.SetSessionPath(_L("\\"));
       
  1952     test(r==KErrNone);
       
  1953     TEntry e;
       
  1954     r=TheFs.Entry(_L("TEST1"),e);
       
  1955     if(e.iName!=_L("TEST1"))
       
  1956         {
       
  1957         test.Printf(_L("e.iName = %S\n"),&e.iName);
       
  1958         test(EFalse);
       
  1959         }
       
  1960     }
       
  1961 
       
  1962 static  TUint32 GetValue(const TPtrC8& aData, TInt aOffset, TInt aLength)
       
  1963     {
       
  1964     TUint32 val = 0;
       
  1965     while (aLength-- > 0)
       
  1966         val = val * 256 + aData[aOffset+aLength];
       
  1967     return val;
       
  1968     }
       
  1969 
       
  1970 static  void TestDiskIntegrity(TBool aTestOnly=EFalse)
       
  1971 //
       
  1972 // Does 'sanity checking' on the BPB and other areas
       
  1973 //
       
  1974     {
       
  1975     if (!aTestOnly)
       
  1976         test.Next(_L("Test disk boot area integrity"));
       
  1977     TInt seclen = TheBootSector.BytesPerSector();
       
  1978     HBufC8 *bootp = HBufC8::NewL(seclen);
       
  1979     TPtr8   boot((TUint8*)bootp, seclen);
       
  1980     HBufC8 *backp = HBufC8::NewL(seclen);
       
  1981     TPtr8   back((TUint8*)backp, seclen);
       
  1982     HBufC8 *infop = HBufC8::NewL(seclen);
       
  1983     TPtr8   info((TUint8*)bootp, seclen);
       
  1984     TInt r=TheDisk.Open(TheFs,CurrentDrive());
       
  1985     if (r != KErrNone)
       
  1986         test.Printf(_L("Error %d opening on %C"), r, (TUint)gDriveToTest);
       
  1987     test(r==KErrNone);
       
  1988     r=TheDisk.Read(0, boot);
       
  1989     test(r==KErrNone);
       
  1990     TUint32 val = GetValue(boot, 510, 2);
       
  1991     RDebug::Print(_L("BPB magic number = 0x%X\n"), val);
       
  1992     test(aTestOnly || val == 0xAA55);
       
  1993     switch (boot[0])
       
  1994         {
       
  1995         case 0xEB:
       
  1996             RDebug::Print(_L("Jump %02X 0x%02X\n"), boot[0], boot[1]);
       
  1997             test(aTestOnly || boot[2] == 0x90);
       
  1998             break;
       
  1999         case 0xE9:
       
  2000             RDebug::Print(_L("Jump %02X 0x%02X%02X\n"), boot[0], boot[2], boot[1]);
       
  2001             break;
       
  2002         default:
       
  2003             RDebug::Print(_L("Invalid boot start: %02X %02X %02X\n"), boot[0], boot[1], boot[2]);
       
  2004             test(aTestOnly);
       
  2005         }
       
  2006     switch (gDiskType)
       
  2007         {
       
  2008         case EFat12:
       
  2009             test(aTestOnly || TheBootSector.ReservedSectors() >= 1);
       
  2010             test.Printf(_L("BPB sector OK\n"));
       
  2011             break;
       
  2012         case EFat16:
       
  2013             test(aTestOnly || TheBootSector.ReservedSectors() >= 1);
       
  2014             test.Printf(_L("BPB sector OK\n"));
       
  2015             break;
       
  2016         default:
       
  2017             test(aTestOnly || TheBootSector.ReservedSectors() >= 1);
       
  2018             test(aTestOnly || TheBootSector.ReservedSectors() > TheBootSector.BkBootRecSector());
       
  2019             test(aTestOnly || TheBootSector.ReservedSectors() > TheBootSector.FSInfoSectorNum());
       
  2020             test.Printf(_L("BPB sector OK\n"));
       
  2021             if (TheBootSector.BkBootRecSector() > 0)
       
  2022                 {
       
  2023                 r=TheDisk.Read(TheBootSector.BkBootRecSector()*seclen, back);
       
  2024                 test(aTestOnly || r==KErrNone);
       
  2025                 if (boot != back)
       
  2026                     {
       
  2027                     RDebug::Print(_L("Boot sector != backup\n"));
       
  2028                     RDebug::Print(_L("Sector 0: Boot sector\n"));
       
  2029                     DumpHex(boot.Ptr(), seclen);
       
  2030                     RDebug::Print(_L("Sector %d: Backup sector\n"), TheBootSector.BkBootRecSector());
       
  2031                     DumpHex(back.Ptr(), seclen);
       
  2032                     test(aTestOnly);
       
  2033                     }
       
  2034                 test.Printf(_L("Backup BPB sector OK\n"));
       
  2035                 }
       
  2036             else
       
  2037                 test.Printf(_L("Backup BPB not present\n"));
       
  2038             if (TheBootSector.FSInfoSectorNum() > 0)
       
  2039                 {
       
  2040                 r=TheDisk.Read(TheBootSector.FSInfoSectorNum()*seclen, info);
       
  2041                 test(aTestOnly || r==KErrNone);
       
  2042                 // Test the 'magic numbers' (signatures) as specified
       
  2043                 val = GetValue(info, 0, 4);
       
  2044                 RDebug::Print(_L("FSI signature 1  = 0x%X\n"), val);
       
  2045                 test(aTestOnly || val == 0x41615252);
       
  2046                 val = GetValue(info, 484, 4);
       
  2047                 RDebug::Print(_L("FSI signature 2  = 0x%X\n"), val);
       
  2048                 test(aTestOnly || val == 0x61417272);
       
  2049                 val = GetValue(info, 508, 4);
       
  2050                 RDebug::Print(_L("FSI magic number = 0x%X\n"), val);
       
  2051                 test(aTestOnly || val == 0xAA550000);
       
  2052                 // Check the last known free count and the next free cluster value.  If
       
  2053                 // they are not calculated they should be 0xFFFFFFFF, otherwise must be
       
  2054                 // less than the number of clusters.
       
  2055                 val = GetValue(info, 488, 4);
       
  2056                 RDebug::Print(_L("FSI last free #  = 0x%X\n"), val);
       
  2057                 test(aTestOnly || val == 0xFFFFFFFF || val <= (TUint32)gClusterCount);
       
  2058                 val = GetValue(info, 492, 4);
       
  2059                 RDebug::Print(_L("FSI next free #  = 0x%X\n"), val);
       
  2060                 test(aTestOnly || val == 0xFFFFFFFF || val < (TUint32)gClusterCount);
       
  2061                 test.Printf(_L("FSInfo sector OK\n"));
       
  2062                 }
       
  2063             break;
       
  2064         }
       
  2065     TheDisk.Close();
       
  2066     delete bootp;
       
  2067     delete backp;
       
  2068     delete infop;
       
  2069     }
       
  2070 
       
  2071 static  void TestFATTableEntries()
       
  2072 //
       
  2073 // Test that reading/writing FAT table entries preserves the upper 4 bits of data.
       
  2074 //
       
  2075     {
       
  2076     test.Next(_L("Test reading/writing FAT table entries"));
       
  2077     FormatPack();
       
  2078 
       
  2079     TUint32 buf[16];
       
  2080     TInt i=0;
       
  2081     TInt r=KErrNone;
       
  2082 
       
  2083     for (i=0; i <=7; i++)
       
  2084         {
       
  2085         buf[i] = GetFatEntry(i);
       
  2086         }
       
  2087 
       
  2088     test.Printf(_L("First 8 FAT Entries before signature: \n"));
       
  2089     test.Printf(_L("%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n"),
       
  2090                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
       
  2091 
       
  2092     for (i=0; i <=7; i++)
       
  2093         {
       
  2094         MarkFatEntry(i);
       
  2095         }
       
  2096 
       
  2097     for (i=0; i <=7; i++)
       
  2098         {
       
  2099         buf[i] = GetFatEntry(i);
       
  2100         }
       
  2101 
       
  2102     test.Printf(_L("First 8 FAT Entries after signature: \n"));
       
  2103     test.Printf(_L("%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n"),
       
  2104                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
       
  2105 
       
  2106 
       
  2107     test(TheFile.Create(TheFs,_L("\\CORRUPT1.TMP"),EFileRead|EFileWrite)==KErrNone);
       
  2108 
       
  2109     TheBuffer.SetLength(2048);
       
  2110     Mem::Fill(&TheBuffer[0],2048,'X');
       
  2111 
       
  2112     for(i=0; i<=20; i++)
       
  2113         {
       
  2114         r = TheFile.Write(TheBuffer);
       
  2115         test(r==KErrNone);
       
  2116         }
       
  2117 
       
  2118     TheFile.Close();
       
  2119 
       
  2120     for (i=8; i <=15; i++)
       
  2121         {
       
  2122         buf[i] = GetFatEntry(i-8);
       
  2123         }
       
  2124 
       
  2125     test.Printf(_L("First 8 FAT Entries after file write: \n"));
       
  2126     test.Printf(_L("%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n"),
       
  2127                 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
       
  2128 
       
  2129     for (i=0; i<=7; i++)
       
  2130         {
       
  2131         test((buf[i] & 0xF0000000) == (buf[i+8] & 0xF0000000));
       
  2132         }
       
  2133 
       
  2134     test.Printf(_L("Top 4 bits of first 8 FAT Entries have been preserved.\n"));
       
  2135     }
       
  2136 
       
  2137 
       
  2138 //-----------------------------------------------------------------------------
       
  2139 /**
       
  2140     Test that FAT[0] and FAT[1] just after formatting are compliant to FAT specs.
       
  2141     So that this test step shall be called just after the volume formatted.
       
  2142 */
       
  2143 static void TestFirst2FatEntries()
       
  2144 {
       
  2145     test.Next(_L("Test FAT[0] and FAT[1] after formatting"));
       
  2146 
       
  2147     TInt nRes;
       
  2148     TBuf8<8> fat1Buf; //-- buffer for FAT[0] & FAT[1] read from 1st FAT copy
       
  2149     TBuf8<8> fatBufCurr;
       
  2150 
       
  2151     //-- read first several FAT entries from FAT1
       
  2152     const TUint32 posFat1Start = TheBootSector.FirstFatSector() * TheBootSector.BytesPerSector();
       
  2153     const TUint32 fatSize = TheBootSector.TotalFatSectors() * TheBootSector.BytesPerSector();
       
  2154     const TInt numFATs = TheBootSector.NumberOfFats();
       
  2155 
       
  2156 
       
  2157     nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start, 8, fat1Buf);
       
  2158     test(nRes==KErrNone);
       
  2159 
       
  2160     switch(gDiskType)
       
  2161     {
       
  2162      //----------- FAT12 ---------------------
       
  2163      case EFat12:
       
  2164      {
       
  2165         fat1Buf.SetLength(3); //-- FAT12 entry occupies 1.5 bytes
       
  2166         test.Printf(_L("FAT12, first 2 entries: %x %x %x\n"), fat1Buf[0], fat1Buf[1], fat1Buf[2]);
       
  2167 
       
  2168         test(fat1Buf[0]==0xF8 && fat1Buf[1]==0xFF && fat1Buf[2]==0xFF); //-- see FAT specs, these are first 2 entries
       
  2169 
       
  2170         //-- test that all copies of FAT have the same values in FAT[0] & FAT[1]
       
  2171         for(TInt i=1; i<numFATs; ++i)
       
  2172         {
       
  2173             nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start + i*fatSize, 8, fatBufCurr);
       
  2174             test(nRes==KErrNone);
       
  2175 
       
  2176             fatBufCurr.SetLength(3);
       
  2177 
       
  2178             if(fatBufCurr != fat1Buf)
       
  2179             {
       
  2180                 test.Printf(_L("1st 2 FAT entries in FAT#%d are different from FAT1!\n"), i);
       
  2181                 test(0);
       
  2182             }
       
  2183         }
       
  2184 
       
  2185 
       
  2186      }
       
  2187      break;
       
  2188 
       
  2189      //----------- FAT16 ---------------------
       
  2190      case EFat16:
       
  2191      {
       
  2192         typedef TUint16 TFat16Entry;
       
  2193 
       
  2194         fat1Buf.SetLength(2*sizeof(TFat16Entry));
       
  2195         const TFat16Entry* pFat = (const TFat16Entry*)fat1Buf.Ptr();
       
  2196 
       
  2197         const TFat16Entry fatEntry_0 = pFat[0]; //-- do not mask entries
       
  2198         const TFat16Entry fatEntry_1 = pFat[1]; //-- do not mask entries
       
  2199 
       
  2200         test.Printf(_L("FAT16[0]=0x%x, FAT16[1]=0x%x\n"), fatEntry_0, fatEntry_1);
       
  2201 
       
  2202         test(fatEntry_0 == 0xFFF8); //-- see FAT specs
       
  2203         test(fatEntry_1 == 0xFFFF); //-- the volume shall be clean just after the formatting. It can be 0x7FFF if a write to the volume occured.
       
  2204 
       
  2205         //-- test that all copies of FAT have the same values in FAT[0] & FAT[1]
       
  2206         for(TInt i=1; i<numFATs; ++i)
       
  2207         {
       
  2208             nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start + i*fatSize, 8, fatBufCurr);
       
  2209             test(nRes==KErrNone);
       
  2210 
       
  2211             fatBufCurr.SetLength(2*sizeof(TFat16Entry));
       
  2212 
       
  2213             if(fatBufCurr != fat1Buf)
       
  2214             {
       
  2215                 test.Printf(_L("1st 2 FAT entries in FAT#%d are different from FAT1!\n"), i);
       
  2216                 test(0);
       
  2217             }
       
  2218         }
       
  2219 
       
  2220      }
       
  2221      break;
       
  2222 
       
  2223      //----------- FAT32 ---------------------
       
  2224      case EFat32:
       
  2225      {
       
  2226         typedef TUint32 TFat32Entry;
       
  2227 
       
  2228         fat1Buf.SetLength(2*sizeof(TFat32Entry));
       
  2229         const TFat32Entry* pFat = (const TFat32Entry*)fat1Buf.Ptr();
       
  2230 
       
  2231         const TFat32Entry fatEntry_0 = pFat[0]; //-- do not mask entries
       
  2232         const TFat32Entry fatEntry_1 = pFat[1]; //-- do not mask entries
       
  2233 
       
  2234         test.Printf(_L("FAT32[0]=0x%x, FAT32[1]=0x%x\n"), fatEntry_0, fatEntry_1);
       
  2235 
       
  2236         test(fatEntry_0 == 0x0FFFFFF8); //-- see FAT specs
       
  2237         test(fatEntry_1 == 0x0FFFFFFF); //-- the volume shall be clean just after the formatting. It can be 0x07FFFFFF if a write to the volume occured.
       
  2238 
       
  2239         //-- test that all copies of FAT have the same values in FAT[0] & FAT[1]
       
  2240         for(TInt i=1; i<numFATs; ++i)
       
  2241         {
       
  2242             nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start + i*fatSize, 8, fatBufCurr);
       
  2243             test(nRes==KErrNone);
       
  2244 
       
  2245             fatBufCurr.SetLength(2*sizeof(TFat32Entry));
       
  2246 
       
  2247             if(fatBufCurr != fat1Buf)
       
  2248             {
       
  2249                 test.Printf(_L("1st 2 FAT entries in FAT#%d are different from FAT1!\n"), i);
       
  2250                 test(0);
       
  2251             }
       
  2252         }
       
  2253      }
       
  2254      break;
       
  2255 
       
  2256      default:
       
  2257         test(0);
       
  2258      break;
       
  2259 
       
  2260     };//switch(gDiskType)
       
  2261 
       
  2262 
       
  2263 
       
  2264 }
       
  2265 
       
  2266 
       
  2267 /**
       
  2268 Exhaustive test of Data alignmemnt calculation
       
  2269 in this code the function
       
  2270     TInt TFatAlignment::AdjustFirstDataSectorAlignment(TInt aBlockSize)
       
  2271 should be exactly the same as
       
  2272     TInt CFatFormatCB::AdjustFirstDataSectorAlignment(TInt aBlockSize)
       
  2273 */
       
  2274 class TFatAlignment
       
  2275     {
       
  2276 public:
       
  2277     enum {KDefFatResvdSec = 1, KDefFat32ResvdSec = 32}; ///< default number of FAT32 reserved sectors
       
  2278 public:
       
  2279     TFatAlignment();
       
  2280     void Init(TBool aFat32, TInt aNumberOfFats, TInt aMaxDiskSectors, TInt aSectorsPerCluster, TInt aRootDirEntries);
       
  2281     TUint32 MaxFat32Sectors() const;
       
  2282     TInt MaxFat16Sectors() const;
       
  2283     TInt MaxFat12Sectors() const;
       
  2284     TUint32 RootDirSectors() const;
       
  2285     TInt FirstDataSector() const;
       
  2286     TBool Is32BitFat() const;
       
  2287     TBool Is16BitFat() const;
       
  2288 
       
  2289     TInt AdjustFirstDataSectorAlignment(TInt aBlockSize);
       
  2290     void Display();
       
  2291 public:
       
  2292     TInt iBytesPerSector;
       
  2293     TInt iNumberOfFats;
       
  2294     TInt iMaxDiskSectors;
       
  2295     TInt iSectorsPerCluster;
       
  2296     TInt iReservedSectors;
       
  2297     TInt iSectorsPerFat;
       
  2298     TInt iRootDirEntries;
       
  2299 
       
  2300     TBool iFat32;   // 0 = FAT16, 1 = FAT32
       
  2301     TInt iMaxIterations;
       
  2302     };
       
  2303 
       
  2304 TFatAlignment::TFatAlignment()
       
  2305     {
       
  2306     iMaxIterations = 0;
       
  2307     }
       
  2308 
       
  2309 void TFatAlignment::Init(TBool aFat32, TInt aNumberOfFats, TInt aMaxDiskSectors, TInt aSectorsPerCluster, TInt aRootDirEntries)
       
  2310     {
       
  2311     iBytesPerSector = 512;
       
  2312     iFat32 = aFat32;
       
  2313     iNumberOfFats = aNumberOfFats;
       
  2314     iMaxDiskSectors = aMaxDiskSectors;
       
  2315     iSectorsPerCluster = aSectorsPerCluster;
       
  2316     iRootDirEntries = aRootDirEntries;
       
  2317 
       
  2318     iReservedSectors = iFat32 ? KDefFat32ResvdSec : KDefFatResvdSec;
       
  2319     iSectorsPerFat = iFat32 ? MaxFat32Sectors() : MaxFat16Sectors();
       
  2320     }
       
  2321 
       
  2322 void TFatAlignment::Display()
       
  2323     {
       
  2324     RDebug::Print(_L("iFat32 %u iNumberOfFats %u,iMaxDiskSectors %u,iSectorsPerCluster %u,iReservedSectors %u,iSectorsPerFat %u, iRootDirEntries %u, FirstDataSector %08X"),
       
  2325         iFat32,
       
  2326         iNumberOfFats,
       
  2327         iMaxDiskSectors,
       
  2328         iSectorsPerCluster,
       
  2329         iReservedSectors,
       
  2330         iSectorsPerFat,
       
  2331         iRootDirEntries,
       
  2332         FirstDataSector());
       
  2333     }
       
  2334 
       
  2335 TInt TFatAlignment::MaxFat16Sectors() const
       
  2336     {
       
  2337 
       
  2338     TInt fatSizeInBytes=(2*iMaxDiskSectors)/iSectorsPerCluster+(iBytesPerSector-1);
       
  2339     return(fatSizeInBytes/iBytesPerSector);
       
  2340     }
       
  2341 
       
  2342 
       
  2343 TInt TFatAlignment::MaxFat12Sectors() const
       
  2344     {
       
  2345     TInt maxDiskClusters=iMaxDiskSectors/iSectorsPerCluster;
       
  2346     TInt fatSizeInBytes=maxDiskClusters+(maxDiskClusters>>1)+(iBytesPerSector-1);
       
  2347     return(fatSizeInBytes/iBytesPerSector);
       
  2348     }
       
  2349 
       
  2350 
       
  2351 TUint32 TFatAlignment::MaxFat32Sectors() const
       
  2352     {
       
  2353     TUint32 calc1 = iMaxDiskSectors - iReservedSectors;
       
  2354     TUint32 calc2 = (256 * iSectorsPerCluster) + iNumberOfFats;
       
  2355     calc2 = calc2 >> 1;
       
  2356     return (calc1 + (calc2 - 1))/calc2;
       
  2357     }
       
  2358 
       
  2359 
       
  2360 /**
       
  2361     @return Number of sectors in root directory. 0 for FAT32
       
  2362 */
       
  2363 TUint32 TFatAlignment::RootDirSectors() const
       
  2364     {
       
  2365     const TInt KSizeOfFatDirEntry       =32;    ///< Size in bytes of a Fat directry entry
       
  2366 
       
  2367     return ( (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector );
       
  2368     }
       
  2369 
       
  2370 TInt TFatAlignment::FirstDataSector() const
       
  2371     {
       
  2372     return( iReservedSectors + iNumberOfFats * iSectorsPerFat + RootDirSectors());
       
  2373     }
       
  2374 
       
  2375 TBool TFatAlignment::Is32BitFat() const
       
  2376     {
       
  2377     return iFat32;
       
  2378     }
       
  2379 
       
  2380 TBool TFatAlignment::Is16BitFat() const
       
  2381     {
       
  2382     return !iFat32;
       
  2383     }
       
  2384 
       
  2385 #define __PRINT1
       
  2386 
       
  2387 
       
  2388 // AdjustFirstDataSectorAlignment()
       
  2389 // Attempts to align the first data sector on an erase block boundary by modifying the
       
  2390 // number of reserved sectors.
       
  2391 TInt TFatAlignment::AdjustFirstDataSectorAlignment(TInt aEraseBlockSizeInSectors)
       
  2392     {
       
  2393     const TBool bFat16 = Is16BitFat();
       
  2394     const TBool bFat32 = Is32BitFat();
       
  2395 
       
  2396     // Save these 2 values in the event of a convergence failure; this should
       
  2397     // hopefully never happen, but we will cater for this in release mode to be safe,
       
  2398     TInt reservedSectorsSaved = iReservedSectors;
       
  2399     TInt sectorsPerFatSaved = iSectorsPerFat;
       
  2400 
       
  2401     TInt reservedSectorsOld = 0;
       
  2402 
       
  2403     // zero for FAT32
       
  2404     TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector;
       
  2405     TInt fatSectors = 0;
       
  2406 
       
  2407     TInt KMaxIterations = 10;
       
  2408     TInt n;
       
  2409     for (n=0; n<KMaxIterations && reservedSectorsOld != iReservedSectors; n++)
       
  2410         {
       
  2411         reservedSectorsOld = iReservedSectors;
       
  2412 
       
  2413         iSectorsPerFat = bFat32 ? MaxFat32Sectors() : bFat16 ? MaxFat16Sectors() : MaxFat12Sectors();
       
  2414 
       
  2415         fatSectors = iSectorsPerFat * iNumberOfFats;
       
  2416 
       
  2417         // calculate number of blocks
       
  2418         TInt  nBlocks = (iReservedSectors + fatSectors + rootDirSectors + aEraseBlockSizeInSectors-1) / aEraseBlockSizeInSectors;
       
  2419 
       
  2420         iReservedSectors = (nBlocks * aEraseBlockSizeInSectors) - rootDirSectors - fatSectors;
       
  2421         }
       
  2422 
       
  2423     ASSERT(iReservedSectors >= (TInt) (bFat32 ? KDefFat32ResvdSec : KDefFatResvdSec));
       
  2424 
       
  2425     if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0)
       
  2426         {
       
  2427         return KErrNone;
       
  2428         }
       
  2429     else
       
  2430         {
       
  2431         iReservedSectors = reservedSectorsSaved;
       
  2432         iSectorsPerFat = sectorsPerFatSaved;
       
  2433         return KErrGeneral;
       
  2434         }
       
  2435     }
       
  2436 
       
  2437 
       
  2438 void TestFirstDataSectorAlignment()
       
  2439     {
       
  2440     test.Start(_L("Exhaustive test of data alignment calculation"));
       
  2441 
       
  2442     typedef struct
       
  2443         {
       
  2444         TInt iNumberOfFats;
       
  2445         TInt iMaxDiskSectors;
       
  2446         TInt iSectorsPerCluster;
       
  2447         TInt iBlockSize;
       
  2448         TInt iRootDirEntries;
       
  2449         } STestVal;
       
  2450     STestVal testVals[] =
       
  2451         {
       
  2452             {2, 15720448, 32, 16*1024, 0},  // 4GB MoviNand, cluster size = 16K
       
  2453             {2, 106496, 2, 2048, 512},  // diskSize = 54MB,  = block size = 1MB
       
  2454             {2, 1048576, 8, 2048, 0},   // diskSize = 512 MB
       
  2455             {2, 1048578, 8, 2048, 0},   // Doesn't converge with original algorithm
       
  2456         };
       
  2457 
       
  2458     TFatAlignment fatAlignment;
       
  2459     TInt numOfTests = sizeof(testVals) / sizeof(STestVal);
       
  2460     for (TInt n=0; n<numOfTests; n++)
       
  2461         {
       
  2462         STestVal& testVal = testVals[n];
       
  2463         TBool fat32 = testVal.iMaxDiskSectors >= 1048576;
       
  2464 
       
  2465         fatAlignment.Init(
       
  2466             fat32,
       
  2467             testVal.iNumberOfFats,
       
  2468             testVal.iMaxDiskSectors,
       
  2469             testVal.iSectorsPerCluster,
       
  2470             testVal.iRootDirEntries);
       
  2471         TInt r = fatAlignment.AdjustFirstDataSectorAlignment(testVal.iBlockSize);
       
  2472         test (r == KErrNone);
       
  2473         fatAlignment.Display();
       
  2474         }
       
  2475 
       
  2476     const TInt64 KOneMByte = 1024*1024;
       
  2477     const TInt64 KOneGByte = 1024*KOneMByte;
       
  2478     const TInt64 KLastSizeToTest = 32*KOneGByte;
       
  2479     TInt iteration=0;
       
  2480     TInt64 diskSize;
       
  2481 
       
  2482 
       
  2483 
       
  2484     TInt successes = 0;
       
  2485     TInt failures = 0;
       
  2486 
       
  2487     for (iteration=0, diskSize = 16*KOneMByte; diskSize < KLastSizeToTest; iteration++, diskSize+=512)
       
  2488         {
       
  2489         TInt diskSizeInSectors = (TInt) (diskSize >> 9);
       
  2490 
       
  2491         const TInt KMaxFAT16Entries=0xFFF0;     ///< Maximum number of clusters in a Fat16 Fat table, 65520
       
  2492 
       
  2493         TBool fat32 = EFalse;
       
  2494         TInt numberOfFats = 2;
       
  2495         TInt rootDirEntries;
       
  2496         TInt sectorsPerCluster;
       
  2497         TInt blockSizeInSectors = 32;   // 16K for FAT16
       
  2498 
       
  2499         if (diskSizeInSectors<4096) // < 2MB
       
  2500             {
       
  2501             rootDirEntries=128;
       
  2502             sectorsPerCluster=1;
       
  2503             }
       
  2504         else if (diskSizeInSectors<8400) // < 4MB
       
  2505             {
       
  2506             rootDirEntries=256;
       
  2507             sectorsPerCluster=2;
       
  2508             }
       
  2509         else if (diskSizeInSectors<16384) // < 8MB
       
  2510             {
       
  2511             rootDirEntries=512;
       
  2512             sectorsPerCluster=4;
       
  2513             }
       
  2514         else if (diskSizeInSectors<32680) // < 16MB
       
  2515             {
       
  2516             rootDirEntries=512;
       
  2517             sectorsPerCluster=8;
       
  2518             }
       
  2519         else if(diskSizeInSectors<1048576) // >= 16Mb - FAT16   < (1048576) 512MB
       
  2520             {
       
  2521             TInt minSectorsPerCluster=(diskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries;
       
  2522             rootDirEntries=512;
       
  2523             sectorsPerCluster=1;
       
  2524             while (minSectorsPerCluster>sectorsPerCluster)
       
  2525                 sectorsPerCluster<<=1;
       
  2526             }
       
  2527         else    //use FAT32
       
  2528             {
       
  2529             rootDirEntries=0;                       //this is always the case for fat32
       
  2530             if(diskSizeInSectors < 16777216)        //8GB in 512byte sectors
       
  2531                 sectorsPerCluster=8;
       
  2532             else if(diskSizeInSectors < 33554432)   //16GB in 512byte sectors
       
  2533                 sectorsPerCluster=16;
       
  2534             else if(diskSizeInSectors < 67108864)   //32GB in 512byte sectors
       
  2535                 sectorsPerCluster=32;
       
  2536             else
       
  2537                 sectorsPerCluster=64;               //Anything >= 32GB uses a 32K cluster size
       
  2538             blockSizeInSectors = 2048;          // 1MB for FAT32
       
  2539             fat32 = ETrue;
       
  2540             }
       
  2541 
       
  2542 
       
  2543         fatAlignment.Init(
       
  2544             fat32,
       
  2545             numberOfFats,
       
  2546             diskSizeInSectors,
       
  2547             sectorsPerCluster,
       
  2548             rootDirEntries);
       
  2549         TInt r = fatAlignment.AdjustFirstDataSectorAlignment(blockSizeInSectors);
       
  2550         if (r == KErrNone)
       
  2551             successes++;
       
  2552         else
       
  2553             failures++;
       
  2554 
       
  2555 
       
  2556 //      if (diskSize % 0x08000000 == 0)
       
  2557 //          {
       
  2558 //          RDebug::Print(_L("Iter %10lX of %10lX"), diskSize, KLastSizeToTest);
       
  2559 //          fatAlignment.Display();
       
  2560 //          }
       
  2561         }
       
  2562     RDebug::Print(_L("Total iterations %u"), iteration);
       
  2563     RDebug::Print(_L("Max loop count %u"), fatAlignment.iMaxIterations);
       
  2564     RDebug::Print(_L("successes %d failures %d, success rate %ld"),
       
  2565         successes, failures, (TInt64(successes) * 100) / TInt64(successes + failures));
       
  2566     test (failures == 0);
       
  2567 
       
  2568     }
       
  2569 
       
  2570 
       
  2571 static void TestZeroLengthFile()
       
  2572 //
       
  2573 // Test what happens if you write more to a zero length file than
       
  2574 // will fit in the filesystem.
       
  2575 //
       
  2576     {
       
  2577     test.Next(_L("Test behaviour of extending a zero length file"));
       
  2578 
       
  2579     FormatPack();
       
  2580 
       
  2581     TInt r;
       
  2582 
       
  2583     TVolumeInfo volInfo;
       
  2584     r=TheFs.Volume(volInfo);
       
  2585     test(r==KErrNone);
       
  2586 
       
  2587     TInt64 spaceToUse = volInfo.iFree - gBytesPerCluster; // whole disk except 1 cluster
       
  2588 
       
  2589     test.Printf(_L("spaceToUse %ld gClusterCount %d gBytesPerCluster %d\n"), spaceToUse, gClusterCount, gBytesPerCluster);
       
  2590     test.Printf(_L("Before fill, volInfo.iSize %ld volInfo.iFree %ld\n"), volInfo.iSize, volInfo.iFree);
       
  2591 
       
  2592     RFile f;
       
  2593 
       
  2594     TInt tempfiles = 0;
       
  2595     while (spaceToUse > K1GigaByte)
       
  2596         {
       
  2597         TFileName tempName;
       
  2598         r=f.Temp(TheFs,_L("\\"),tempName,EFileRead|EFileWrite);
       
  2599         test(r==KErrNone);
       
  2600         r=f.SetSize(K1GigaByte);
       
  2601         test(r==KErrNone);
       
  2602         f.Close();
       
  2603         spaceToUse -= K1GigaByte;
       
  2604         tempfiles++;
       
  2605         }
       
  2606 
       
  2607     r=f.Replace(TheFs,_L("\\USESPACE.TMP"),EFileRead|EFileWrite);
       
  2608     test(r==KErrNone);
       
  2609     r=f.SetSize((TInt)spaceToUse);
       
  2610     test(r==KErrNone);
       
  2611     f.Close();
       
  2612 
       
  2613     r=TheFs.Volume(volInfo);
       
  2614     test(r==KErrNone);
       
  2615     test.Printf(_L("After fill, volInfo.iSize %ld volInfo.iFree %ld\n"), volInfo.iSize, volInfo.iFree);
       
  2616 
       
  2617     test(volInfo.iFree==gBytesPerCluster); // check we have 1 cluster free
       
  2618 
       
  2619     r=f.Replace(TheFs,_L("\\FILE.TMP"),EFileRead|EFileWrite);
       
  2620     test(r==KErrNone);
       
  2621     r=f.SetSize(2*gBytesPerCluster); // 2 clusters (will fail since there's not space)
       
  2622     test(r==KErrDiskFull);
       
  2623     f.Close();
       
  2624 
       
  2625     r=TheFs.Volume(volInfo);
       
  2626     test(r==KErrNone);
       
  2627     test(volInfo.iFree==gBytesPerCluster); // check we still have 1 cluster free
       
  2628 
       
  2629     r=f.Replace(TheFs,_L("\\USESPACE.TMP"),EFileRead|EFileWrite); // truncate file to 0
       
  2630     test(r==KErrNone);
       
  2631     f.Close();
       
  2632 
       
  2633     r=TheFs.Volume(volInfo);
       
  2634     test(r==KErrNone);
       
  2635     test(volInfo.iFree==(spaceToUse+gBytesPerCluster)); // check we've freed up the space from USESPACE plus one cluster
       
  2636 
       
  2637     
       
  2638     test(TheBootSector.IsValid()); //-- TheBootSector is read after formatting
       
  2639     TInt64 rootDirpos = gRootDirStart;
       
  2640 
       
  2641     
       
  2642     //-- read 1 sector of the root dir.
       
  2643     r = MediaRawRead(TheFs, CurrentDrive(), rootDirpos, TheBootSector.BytesPerSector(), TheBuffer);
       
  2644     test(r == KErrNone);
       
  2645 
       
  2646     const TFatDirEntry* pE=(TFatDirEntry*)TheBuffer.Ptr();
       
  2647     while (tempfiles-- > 0)
       
  2648         {
       
  2649         while (pE->IsVFatEntry())
       
  2650             pE++;
       
  2651         test(pE->Size()==(TUint)K1GigaByte);
       
  2652         pE++;
       
  2653         }
       
  2654 
       
  2655     while (pE->IsVFatEntry())
       
  2656         pE++;
       
  2657 
       
  2658     TBuf8<15> name=pE->Name();
       
  2659     test(name==_L8("USESPACETMP"));
       
  2660     test(pE->StartCluster()==0);
       
  2661 
       
  2662     pE++;
       
  2663     while (pE->IsVFatEntry())
       
  2664         pE++;
       
  2665 
       
  2666     name=pE->Name();
       
  2667     test(name==_L8("FILE    TMP"));
       
  2668     test(pE->StartCluster()==0);
       
  2669 
       
  2670     FormatPack();
       
  2671 
       
  2672     }
       
  2673 
       
  2674 
       
  2675 //
       
  2676 // Call tests that may leave
       
  2677 //
       
  2678 void CallTestsL()
       
  2679     {
       
  2680 
       
  2681     //-- init random generator
       
  2682     rndSeed = Math::Random();
       
  2683 
       
  2684     //-- set up console output
       
  2685     Fat_Test_Utils::SetConsole(test.Console());
       
  2686 
       
  2687 
       
  2688 
       
  2689     TInt drvNum;
       
  2690     TInt r=TheFs.CharToDrive(gDriveToTest,drvNum);
       
  2691     test(r==KErrNone);
       
  2692 
       
  2693     if (!Is_Fat(TheFs,drvNum))
       
  2694         {
       
  2695         test.Printf(_L("CallTestsL: Skipped: test requires FAT filesystem\n"));
       
  2696         return;
       
  2697         }
       
  2698 
       
  2699 
       
  2700     //-- print drive information
       
  2701     PrintDrvInfo(TheFs, drvNum);
       
  2702 
       
  2703     // check this is not the internal ram drive
       
  2704     TVolumeInfo v;
       
  2705     r=TheFs.Volume(v, drvNum);
       
  2706     test(r==KErrNone);
       
  2707     TBool isRamDrive = v.iDrive.iMediaAtt&KMediaAttVariableSize;
       
  2708 
       
  2709     gSessionPath[0] = (TText)gDriveToTest;
       
  2710      // verify that the drive is large enough for proper testing
       
  2711     if (v.iSize<512*1024)
       
  2712         {
       
  2713         test.Printf(_L("CallTestsL: Skipped: test not supported on drives smaller than 512 KB\n"));
       
  2714         return;
       
  2715         }
       
  2716 
       
  2717     FormatPack();
       
  2718     DumpBootSector();
       
  2719 
       
  2720     test.Printf(_L("TotalSectors = %u (%u bytes)\n"),gTotalSectors,gTotalSectors*TheBootSector.BytesPerSector());
       
  2721     test.Printf(_L("Sector size  = %u\n"),TheBootSector.BytesPerSector());
       
  2722     test.Printf(_L("Cluster size = %u sectors\n"),TheBootSector.SectorsPerCluster());
       
  2723     test.Printf(_L("Alloc unit   = %u\n"), gBytesPerCluster);
       
  2724     test.Printf(_L("Fat is %u bit\n"), gFatBits);
       
  2725     User::After(200000); // 1/5 secs
       
  2726 
       
  2727     // set up buffers
       
  2728     TInt bufLen = 16*gBytesPerCluster;
       
  2729     if (bufLen < 16*1024)
       
  2730         bufLen = 16*1024;
       
  2731     pBuffer1=HBufC8::NewL(bufLen);
       
  2732     pBuffer2=HBufC8::NewL(bufLen);
       
  2733 
       
  2734     if (pBuffer1==NULL || pBuffer2==NULL)
       
  2735         Error(_L("OOM"),KErrNoMemory);
       
  2736 
       
  2737 
       
  2738     pBuffer1->Des().Zero();
       
  2739     pBuffer1->Des().SetLength(bufLen);
       
  2740 
       
  2741     pBuffer2->Des().Zero();
       
  2742     pBuffer2->Des().SetLength(bufLen);
       
  2743 
       
  2744     if (isRamDrive)
       
  2745         {
       
  2746         User::After(200000); // 1/5 secs
       
  2747         test.Printf(_L("*** Tests not valid on internal ram drive %C:\n"), (TUint)gDriveToTest);
       
  2748         User::After(200000); // 1/5 secs
       
  2749         }
       
  2750     else
       
  2751         {
       
  2752         TestZeroLengthFile();
       
  2753 
       
  2754 #if defined(__WINS__)
       
  2755         TestFirstDataSectorAlignment();
       
  2756 #endif
       
  2757 
       
  2758         TestFirst2FatEntries();
       
  2759 
       
  2760         TestDiskIntegrity();
       
  2761 
       
  2762         TestBounds();
       
  2763         TestUnicodeEntry();
       
  2764 
       
  2765         TestClusters();
       
  2766 
       
  2767         TestClusterAllocation();
       
  2768 
       
  2769 
       
  2770         TestParentDir(EFalse);  // Test without VFAT entries
       
  2771         TestParentDir(ETrue);   // Test with VFAT entries
       
  2772 
       
  2773         TestRoot();
       
  2774         TestVolumeSize();
       
  2775         TestFATTableEntries();
       
  2776 
       
  2777         FormatPack();
       
  2778 
       
  2779         }
       
  2780     delete pBuffer1;
       
  2781     delete pBuffer2;
       
  2782     }
       
  2783 
       
  2784 
       
  2785 /**
       
  2786     Generate unique temp file name in upper (FAT entry) or lower case (2 VFAT entries)
       
  2787     @param  aFN         descriptor for the file name
       
  2788     @param  aUpperCase  if ETrue, the file name will be in upper case, in a lower case otherwise.
       
  2789 
       
  2790 */
       
  2791 void GenerateTmpFileName(TDes& aFN, TBool aUpperCase)
       
  2792 {
       
  2793     const TInt rnd = Math::Rand(rndSeed);
       
  2794 
       
  2795     aFN.Format(_L("%08x.tmp"), rnd);
       
  2796 
       
  2797     if(aUpperCase)
       
  2798         aFN.UpperCase();
       
  2799     else
       
  2800         aFN.LowerCase();
       
  2801 
       
  2802 }
       
  2803 
       
  2804 /**
       
  2805     Create FAT or VFAT entry in a speciified directory
       
  2806 
       
  2807     @param  aDir        specifies the directory where enntry will be created
       
  2808     @param  aVFatEntry  if true, VFAT entry will be created (2 FAT entries, actually), otherwise - FAT entry
       
  2809     @param  apFileName  in !=NULL there will be placed the name of the file created
       
  2810 */
       
  2811 void CreateFatEntry(const TDesC& aDir, TBool aVFatEntry, TDes *apFileName/*=NULL*/)
       
  2812 {
       
  2813     TFileName tmpFN;
       
  2814     RFile     file;
       
  2815     TInt      nRes;
       
  2816 
       
  2817     do
       
  2818     {
       
  2819         GenerateTmpFileName(tmpFN, !aVFatEntry); //-- generates 8.3 file name FAT (1 entry) or VFAT (2 entries)
       
  2820         tmpFN.Insert(0, aDir);
       
  2821 
       
  2822         nRes = file.Create(TheFs, tmpFN, EFileRead|EFileWrite);
       
  2823 
       
  2824         if(nRes == KErrAlreadyExists)
       
  2825             continue; //-- current random name generator isn't perfect...
       
  2826 
       
  2827         if(nRes != KErrNone)
       
  2828             Error(_L("Error creating a file"),nRes);
       
  2829 
       
  2830         file.Close();
       
  2831 
       
  2832     }while(nRes != KErrNone);
       
  2833 
       
  2834     if(apFileName)
       
  2835         *apFileName = tmpFN;
       
  2836 
       
  2837 }
       
  2838 
       
  2839