os/kernelhwsrv/kerneltest/f32test/filesystem/fat/b_fat32.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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