kerneltest/f32test/filesystem/fat/t_scn32dr1.cpp
changeset 0 a41df078684a
child 21 e7d2d738d3c2
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1998-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\scndrv\t_scn32dr1.cpp
       
    15 //
       
    16 //
       
    17 
       
    18 #include <f32file.h>
       
    19 #include <e32test.h>
       
    20 
       
    21 #include "t_server.h"
       
    22 
       
    23 #include "fat_utils.h"
       
    24 using namespace Fat_Test_Utils;
       
    25 
       
    26 #ifdef __VC32__
       
    27     // Solve compilation problem caused by non-English locale
       
    28     #pragma setlocale("english")
       
    29 #endif
       
    30 
       
    31 /*
       
    32 T_testscndrv tests the scandrive utility. Errors in this test will be
       
    33 introduced using the RRawdDisk class.  The correct fixup is tested by rereading
       
    34 the disk.  Drives tested are the default path(epoc) and X: (wins). This test
       
    35 returns immediately if used on the internal ram drive
       
    36 */
       
    37 
       
    38 /*
       
    39   The initial FAT12 directory structure (with cluster number in brackets) is as follows:
       
    40 
       
    41   |
       
    42    - scndrv (2)
       
    43         |
       
    44         - dir1 (3-4)
       
    45         |   |
       
    46         |   <a very long file name (19 entries)> (5)
       
    47         |
       
    48         - dir2 (6)
       
    49             |
       
    50             - full (7)
       
    51             |   |
       
    52             |   |
       
    53             |   - <seven 2*32 bytes entries> (11-17)
       
    54             |
       
    55             - somedirwith3entries (8)
       
    56             |
       
    57             - somedir2with3entries (9)
       
    58             |
       
    59             - almostfull(10)
       
    60                 |
       
    61                 - <two lots of 6*32 bytes entries> (18+19)
       
    62 
       
    63 */
       
    64 
       
    65 /*
       
    66   The initial FAT32 directory structure (with cluster number in brackets is as follows):
       
    67 
       
    68   |
       
    69    - scndrv (3)
       
    70         |
       
    71         - dir1 (4)
       
    72         |   |
       
    73         |   <a very long file name (19 entries)> (5)
       
    74         |
       
    75         - dir2 (6)
       
    76             |
       
    77             - full (7)
       
    78             |   |
       
    79             |   |
       
    80             |   - <seven 2*32 bytes entries> (11-17)
       
    81             |
       
    82             - somedirwith3entries (8)
       
    83             |
       
    84             - somedir2with3entries (9)
       
    85             |
       
    86             - almostfull(10)
       
    87                 |
       
    88                 - <two lots of 6*32 bytes entries> (18+19)
       
    89 
       
    90 */
       
    91 
       
    92 GLDEF_D RTest test(_L("T_SCN32DR1"));
       
    93 
       
    94 LOCAL_D const TInt KMaxFatEntries  = 2048;
       
    95 LOCAL_D const TInt KMaxFatSize     = KMaxFatEntries * 4;
       
    96 
       
    97 LOCAL_D const TInt KDirAttrReadOnly  = 0x01;
       
    98 LOCAL_D const TInt KDirAttrHidden    = 0x02;
       
    99 LOCAL_D const TInt KDirAttrSystem    = 0x04;
       
   100 LOCAL_D const TInt KDirAttrVolumeId  = 0x08;
       
   101 LOCAL_D const TInt KDirAttrDirectory = 0x10;
       
   102 LOCAL_D const TInt KDirAttrArchive   = 0x20;
       
   103 LOCAL_D const TInt KDirAttrLongName  = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId;
       
   104 LOCAL_D const TInt KDirAttrLongMask  = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive;
       
   105 LOCAL_D const TInt KDirLastLongEntry = 0x40;
       
   106 
       
   107 LOCAL_D RRawDisk TheRawDisk;
       
   108 LOCAL_D TFatBootSector BootSector;
       
   109 LOCAL_D TFileName TheDrive=_L("?:\\");
       
   110 LOCAL_D HBufC8* FatBufPtr = NULL;
       
   111 LOCAL_D HBufC8* DirBufPtr = NULL;
       
   112 LOCAL_D HBufC8* ExtBufPtr = NULL;
       
   113 LOCAL_D TInt32  ExtBufAdd = 0;
       
   114 LOCAL_D TInt32  ExtBufLen = 0;
       
   115 LOCAL_D HBufC8* FatDiskPtr = NULL;
       
   116 LOCAL_D HBufC8* DirDiskPtr = NULL;
       
   117 
       
   118 static TFatType gDiskType = EInvalid;
       
   119 
       
   120 LOCAL_D TInt gDriveNumber;
       
   121 
       
   122 LOCAL_D TInt gBytesPerCluster;
       
   123 LOCAL_D TInt gEntriesPerCluster;
       
   124 LOCAL_D TInt gRootDirSectors;
       
   125 LOCAL_D TInt gRootDirEntries;
       
   126 LOCAL_D TInt gRootDirStart;      // in bytes
       
   127 LOCAL_D TInt gRootSector;
       
   128 LOCAL_D TInt gFatStartBytes;
       
   129 LOCAL_D TInt gFatTestSize;       // in bytes
       
   130 LOCAL_D TInt gFatTestEntries;
       
   131 LOCAL_D TInt gFatSizeSectors;
       
   132 LOCAL_D TInt gFirstDataSector;
       
   133 LOCAL_D TInt gMaxDataCluster;
       
   134 LOCAL_D TInt gDataStartBytes;
       
   135 LOCAL_D TInt gEndOfChain;        // for FAT12/16/32
       
   136 
       
   137 // cluster numbers in 1 and >1 sector per cluster modes
       
   138 LOCAL_D TInt gClusterRootDir;        //  2    2
       
   139 LOCAL_D TInt gClusterScnDrv;         //  3    3
       
   140 LOCAL_D TInt gClusterDir1;           //  4    4
       
   141 LOCAL_D TInt gClusterDir1ext;        //  5    4
       
   142 LOCAL_D TInt gClusterDir2;           //  7    6
       
   143 LOCAL_D TInt gClusterDir2_Full;      //  8    7
       
   144 LOCAL_D TInt gClusterDir2_SD3E;      //  9    8
       
   145 LOCAL_D TInt gClusterDir2_SD23E;     // 10    9
       
   146 LOCAL_D TInt gClusterDir2_AFull;     // 11   10
       
   147 LOCAL_D TInt gClusterEndMaxDepth;    // 147   146
       
   148 
       
   149 LOCAL_D TFileName LastInFull;
       
   150 
       
   151 class TEntryInfo
       
   152     {
       
   153 public:
       
   154     TEntryInfo(TInt aBytePos,TInt aLength):iBytePos(aBytePos),iLength(aLength){}
       
   155     TEntryInfo(){}
       
   156 public:
       
   157     TInt iBytePos;
       
   158     TInt iLength;
       
   159     };
       
   160 
       
   161 
       
   162 LOCAL_C TInt DirBufferSize()
       
   163 //
       
   164 // returns size in bytes nec for buffer to store relevant disk data
       
   165 //
       
   166     {
       
   167     return(gMaxDataCluster*gBytesPerCluster);
       
   168     }
       
   169 
       
   170 LOCAL_C TInt PosInBytes(TInt aFatIndex)
       
   171 //
       
   172 // Return number of bytes into the FAT
       
   173 //
       
   174     {
       
   175     TInt fatPosInBytes = -1;
       
   176     switch (gDiskType)
       
   177         {
       
   178         case EFat32:
       
   179             fatPosInBytes=aFatIndex<<2;
       
   180             break;
       
   181         case EFat16:
       
   182             fatPosInBytes=aFatIndex<<1;
       
   183             break;
       
   184         case EFat12:
       
   185             fatPosInBytes=(aFatIndex*3>>1);
       
   186             break;
       
   187         default:
       
   188             test(0);
       
   189         }
       
   190     return(fatPosInBytes);
       
   191     }
       
   192 
       
   193 LOCAL_C TUint32 MaxClusters()
       
   194 //
       
   195 // Return the number of data clusters on the disk
       
   196 //
       
   197     {
       
   198     TUint32 totSec = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors());
       
   199     TUint32 numSec = totSec - gFirstDataSector;
       
   200     return numSec / BootSector.SectorsPerCluster();
       
   201     }
       
   202 
       
   203 LOCAL_C TInt ClusterToByte(TInt aCluster)
       
   204 //
       
   205 // converts cluster number to byte offset on disk
       
   206 //
       
   207     {
       
   208     TInt pos;
       
   209     if (aCluster < 2)
       
   210         pos = gRootDirStart;
       
   211     else
       
   212         pos = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * BootSector.BytesPerSector();
       
   213     return pos;
       
   214     }
       
   215 
       
   216 LOCAL_C TInt ByteToCluster(TInt aBytePos)
       
   217 //
       
   218 // Converts byte offset from root dir buffer to cluster number
       
   219 //
       
   220     {
       
   221     if (aBytePos < gRootDirStart)
       
   222         return -1;
       
   223     if (aBytePos < gDataStartBytes)
       
   224         return 0;
       
   225     return (aBytePos - gDataStartBytes) / gBytesPerCluster + 2;
       
   226     }
       
   227 
       
   228 LOCAL_C TInt ClusterEntryToBytes(TInt aCluster,TInt aEntry)
       
   229 //
       
   230 // converts position in cluster and entry number to byte pos from root directory
       
   231 //
       
   232     {
       
   233     TInt pos;
       
   234     pos = ClusterToByte(aCluster) - gRootDirStart + aEntry*KSizeOfFatDirEntry;
       
   235     return pos;
       
   236     }
       
   237 
       
   238 LOCAL_C TInt FindUnMatch(const TUint8* aBuf, const TUint8* aCmp, TInt aLen, TInt aStart=0)
       
   239 //
       
   240 // Return position in buffers which doesn't match, or -1 if it matches
       
   241 //
       
   242     {
       
   243     for (TInt i = aStart; i < aStart + aLen; i++)
       
   244         if (aBuf[i] != aCmp[i])
       
   245             return i;
       
   246     return -1;
       
   247     }
       
   248 
       
   249 LOCAL_C TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL)
       
   250 //
       
   251 // Read a single FAT entry from disk or FAT copy and return it
       
   252 //
       
   253     {
       
   254     TInt pos = PosInBytes(aIndex);
       
   255 
       
   256     TUint8  data[4];
       
   257     TUint8* ptr = data;
       
   258 
       
   259     if (aFat)
       
   260         ptr = (TUint8*)aFat + pos;
       
   261     else
       
   262         {
       
   263         pos += BootSector.ReservedSectors() * BootSector.BytesPerSector();
       
   264         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
   265         test(r==KErrNone);
       
   266         TPtr8 buf(&data[0], 4);
       
   267         r=TheRawDisk.Read(pos, buf);
       
   268         test(r==KErrNone);
       
   269         TheRawDisk.Close();
       
   270         }
       
   271 
       
   272     TUint32 val = 0;
       
   273     switch (gDiskType)
       
   274         {
       
   275         case EFat32:
       
   276             val = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24);
       
   277             break;
       
   278         case EFat16:
       
   279             val = ptr[0] + (ptr[1] << 8);
       
   280             break;
       
   281         case EFat12:
       
   282             val = ptr[0] + (ptr[1] << 8);
       
   283             if (aIndex & 1)
       
   284                     val >>= 4;
       
   285             val &= 0xFFF;
       
   286             break;
       
   287         default:
       
   288             test(0);
       
   289         }
       
   290     return val;
       
   291     }
       
   292 
       
   293 LOCAL_C void WriteFat(TInt aFatIndex,TInt aValue,const TUint8* aFat)
       
   294 //
       
   295 // Write a value to both fats starting at aFat
       
   296 //
       
   297     {
       
   298     TUint8* p=(TUint8*)(aFat+PosInBytes(aFatIndex));
       
   299     switch (gDiskType)
       
   300         {
       
   301         case EFat32:
       
   302             p[0] = (TUint8) (aValue);
       
   303             p[1] = (TUint8) (aValue >> 8);
       
   304             p[2] = (TUint8) (aValue >> 16);
       
   305             p[3] = (TUint8) (aValue >> 24);
       
   306             break;
       
   307         case EFat16:
       
   308             p[0] = (TUint8) (aValue);
       
   309             p[1] = (TUint8) (aValue >> 8);
       
   310             break;
       
   311         case EFat12:
       
   312             {
       
   313             TUint8 mask=0x0F;
       
   314             TBool odd=(aFatIndex)&1;
       
   315             TUint8 fatVal;
       
   316             TInt value=aValue;
       
   317             if(odd)
       
   318                 {
       
   319                 mask<<=4;
       
   320                 value<<=4;
       
   321                 fatVal=p[0];
       
   322                 fatVal&=~mask;
       
   323                 fatVal|=(TUint8)(value&0xFF);
       
   324                 p[0]=fatVal;
       
   325                 p[1]=(TUint8)(value>>8);
       
   326                 }
       
   327             else
       
   328                 {
       
   329                 p[0]=(TUint8)(value&0xFF);
       
   330                 fatVal=p[1];
       
   331                 fatVal&=~mask;
       
   332                 fatVal|=(TUint8)(value>>8);
       
   333                 p[1]=fatVal;
       
   334                 }
       
   335             }
       
   336             break;
       
   337         default:
       
   338             test(0);
       
   339         }
       
   340     return;
       
   341     }
       
   342 
       
   343 static void DoReadBootSector()
       
   344     {
       
   345 
       
   346     TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, BootSector);
       
   347     test(nRes == KErrNone);
       
   348 
       
   349     if(!BootSector.IsValid())
       
   350         {
       
   351         test.Printf(_L("Wrong bootsector! Dump:\n"));
       
   352         BootSector.PrintDebugInfo();
       
   353         test(0);
       
   354         }
       
   355 
       
   356     // Calculate derived variables (fixed for a particular disk format)
       
   357     if (BootSector.RootDirEntries() == 0)
       
   358         {
       
   359         test.Printf(_L("Disk is FAT32\n"));
       
   360         gDiskType = EFat32;
       
   361         gEndOfChain = 0x0FFFFFFF;
       
   362         }
       
   363     else if (BootSector.FatType() == EFat16)
       
   364         {
       
   365         test.Printf(_L("Disk is FAT16\n"));
       
   366         gDiskType = EFat16;
       
   367         gEndOfChain = 0xFFFF;
       
   368         }
       
   369     else
       
   370         {
       
   371         test.Printf(_L("Disk is FAT12\n"));
       
   372         gDiskType = EFat12;
       
   373         gEndOfChain = 0x0FFF;
       
   374         }
       
   375 
       
   376     gBytesPerCluster   = BootSector.BytesPerSector() * BootSector.SectorsPerCluster();
       
   377     gFatStartBytes     = BootSector.ReservedSectors() * BootSector.BytesPerSector();
       
   378     gEntriesPerCluster = gBytesPerCluster / KSizeOfFatDirEntry;
       
   379 
       
   380     TBool big = (BootSector.SectorsPerCluster() > 1);
       
   381     switch (gDiskType)
       
   382         {
       
   383         case EFat12:
       
   384         case EFat16:
       
   385             gRootDirEntries     = BootSector.RootDirEntries();
       
   386             gRootDirSectors     = ((gRootDirEntries * KSizeOfFatDirEntry + BootSector.BytesPerSector() - 1) / BootSector.BytesPerSector());
       
   387             gFatSizeSectors     = BootSector.FatSectors();
       
   388             gRootSector         = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors;
       
   389             gFirstDataSector    = gRootSector + gRootDirSectors;
       
   390             gDataStartBytes     = gFirstDataSector * BootSector.BytesPerSector();
       
   391             gRootDirStart       = gRootSector * BootSector.BytesPerSector();
       
   392             gClusterRootDir     = (big ?   0 :   0);
       
   393             gClusterScnDrv      = (big ?   2 :   2);
       
   394             gClusterDir1        = (big ?   3 :   3);
       
   395             gClusterDir1ext     = (big ?   3 :   4);
       
   396             gClusterDir2        = (big ?   5 :   6);
       
   397             gClusterDir2_Full   = (big ?   6 :   7);
       
   398             gClusterDir2_SD3E   = (big ?   7 :   8);
       
   399             gClusterDir2_SD23E  = (big ?   8 :   9);
       
   400             gClusterDir2_AFull  = (big ?   9 :  10);
       
   401             gClusterEndMaxDepth = (big ? 145 : 146);
       
   402             break;
       
   403         case EFat32:
       
   404             //
       
   405             // FAT32 will alway pre-allocate a single cluster for the root directory
       
   406             //
       
   407             //  - The following calculations may look wierd (as the spec says that the FAT32 root dir
       
   408             //    is not fixed) but for the purposes of this test we assume that root dir is only
       
   409             //    one cluster in size, so we don't fill up the disk trying to fill up the root dir.
       
   410             //
       
   411             gRootDirEntries     = gBytesPerCluster * 1 / KSizeOfFatDirEntry;    // Maximum entries within default FAT32 root directory (before extension)
       
   412             gRootDirSectors     = 0;                                            // FAT32 has no fixed root directory sectors over which to skip
       
   413             gFatSizeSectors     = BootSector.FatSectors32();
       
   414 
       
   415             gRootSector         = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors;
       
   416             gFirstDataSector    = gRootSector;
       
   417 
       
   418             gDataStartBytes     = gFirstDataSector * BootSector.BytesPerSector();
       
   419             gRootDirStart       = (BootSector.RootClusterNum() - 2) * gBytesPerCluster + gDataStartBytes;
       
   420 
       
   421             gClusterRootDir     = (big ?   2 :   2);
       
   422             gClusterScnDrv      = (big ?   3 :   3);
       
   423             gClusterDir1        = (big ?   4 :   4);
       
   424             gClusterDir1ext     = (big ?   4 :   5);
       
   425             gClusterDir2        = (big ?   6 :   7);
       
   426             gClusterDir2_Full   = (big ?   7 :   8);
       
   427             gClusterDir2_SD3E   = (big ?   8 :   9);
       
   428             gClusterDir2_SD23E  = (big ?   9 :  10);
       
   429             gClusterDir2_AFull  = (big ?  10 :  11);
       
   430             gClusterEndMaxDepth = (big ? 146 : 147);
       
   431             break;
       
   432         default:
       
   433             break;
       
   434         }
       
   435 
       
   436     gMaxDataCluster = gClusterDir2_AFull + 2 + (gFirstDataSector / BootSector.SectorsPerCluster() + 1);
       
   437 
       
   438     gFatTestEntries = MaxClusters();
       
   439     if (gFatTestEntries > KMaxFatSize)
       
   440         gFatTestEntries = KMaxFatSize;
       
   441     }
       
   442 
       
   443 
       
   444 GLDEF_C void DumpBootSector()
       
   445 //
       
   446 // Display (in log) TFatBootSector structure
       
   447 //
       
   448     {
       
   449     RDebug::Print(_L("iBytesPerSector    = %8d"), BootSector.BytesPerSector());
       
   450     RDebug::Print(_L("iSectorsPerCluster = %8d"), BootSector.SectorsPerCluster());
       
   451     RDebug::Print(_L("iReservedSectors   = %8d"), BootSector.ReservedSectors());
       
   452     RDebug::Print(_L("iNumberOfFats      = %8d"), BootSector.NumberOfFats());
       
   453     RDebug::Print(_L("iRootDirEntries    = %8d"), BootSector.RootDirEntries());
       
   454     RDebug::Print(_L("iTotalSectors      = %8d"), BootSector.TotalSectors());
       
   455     RDebug::Print(_L("iMediaDescriptor   = %8d"), BootSector.MediaDescriptor());
       
   456     RDebug::Print(_L("iFatSectors        = %8d"), BootSector.FatSectors());
       
   457     RDebug::Print(_L("iSectorsPerTrack   = %8d"), BootSector.SectorsPerTrack());
       
   458     RDebug::Print(_L("iNumberOfHeads     = %8d"), BootSector.NumberOfHeads());
       
   459     RDebug::Print(_L("iHiddenSectors     = %8d"), BootSector.HiddenSectors());
       
   460     RDebug::Print(_L("iHugeSectors       = %8d"), BootSector.HugeSectors());
       
   461 
       
   462     if (gDiskType == EFat32)
       
   463         {
       
   464         RDebug::Print(_L("iFatSectors32      = %8d"), BootSector.FatSectors32());
       
   465         RDebug::Print(_L("iFATFlags          = %8d"), BootSector.FATFlags());
       
   466         RDebug::Print(_L("iVersionNumber     = %8d"), BootSector.VersionNumber());
       
   467         RDebug::Print(_L("iRootClusterNum    = %8d (0x%08X)"), BootSector.RootClusterNum(), gRootDirStart);
       
   468         RDebug::Print(_L("iFSInfoSectorNum   = %8d (0x%08X)"), BootSector.FSInfoSectorNum(), BootSector.FSInfoSectorNum() * BootSector.BytesPerSector());
       
   469         RDebug::Print(_L("iBkBootRecSector   = %8d (0x%08X)"), BootSector.BkBootRecSector(), BootSector.BkBootRecSector() * BootSector.BytesPerSector());
       
   470         }
       
   471     }
       
   472 
       
   473 GLDEF_C void DumpFat(const TUint8* aFat=NULL)
       
   474 //
       
   475 // Dump to the log all those FAT entries which are non-zero
       
   476 //
       
   477     {
       
   478     TInt32 max = MaxClusters();
       
   479     if (max > KMaxFatEntries)
       
   480         max = KMaxFatEntries;
       
   481     RDebug::Print(_L("---------------- DUMP OF FAT ---------------"));
       
   482     for (TInt32 i = 0; i < max; i++)
       
   483         {
       
   484         TInt32 val = GetFatEntry(i, aFat);
       
   485         TInt32 msk = 0x0FFFFFFF;
       
   486         switch (gDiskType)
       
   487             {
       
   488             case EFat32:
       
   489                 msk = 0x0FFFFFFF;
       
   490                 break;
       
   491             case EFat16:
       
   492                 msk = 0xFFFF;
       
   493                 break;
       
   494             case EFat12:
       
   495                 msk = 0x0FFF;
       
   496                 break;
       
   497             default:
       
   498                 test(0);
       
   499             }
       
   500         if ((val & msk) == (0x0FFFFFFF & msk))
       
   501             RDebug::Print(_L("    %8d -> EOC"), i);
       
   502         else if ((val & msk) == (0x0FFFFFF8 & msk))
       
   503             RDebug::Print(_L("    %8d -> Media"), i);
       
   504         else if ((val & msk) == (0x0FFFFFF7 & msk))
       
   505             RDebug::Print(_L("    %8d -> BAD"), i);
       
   506         else if (val > max)
       
   507             RDebug::Print(_L("    %8d -> 0x%08X"), i, val);
       
   508         else if (val != 0)
       
   509             RDebug::Print(_L("    %8d -> %d"), i, val);
       
   510         }
       
   511     RDebug::Print(_L("--------------------------------------------"));
       
   512     }
       
   513 
       
   514 GLDEF_C TDes* DirAttributes(TInt aAttrib)
       
   515 //
       
   516 // Return a pointer to a local buffer containing the attribute letters.
       
   517 //
       
   518     {
       
   519     LOCAL_D TBuf<6> str;
       
   520     LOCAL_D char*   atr = "RHSVDA";
       
   521     str.Fill(TText('-'), 6);
       
   522     for (TInt i = 0; i < 6; i++)
       
   523         if ((aAttrib >> i) & 1)
       
   524             str[i] = atr[i];
       
   525     return &str;
       
   526     }
       
   527 
       
   528 GLDEF_C TBool IsValidDirEntry(TFatDirEntry* aDir)
       
   529 //
       
   530 // Test whether buffer is a valid normal directory entry
       
   531 //
       
   532     {
       
   533     // first character must be 0x05 or greater than space
       
   534     if (aDir->iData[0] < 0x21 && aDir->iData[0] != 0x05)
       
   535         return EFalse;
       
   536     // other characters must be not less than space
       
   537     for (TInt i = 1; i < 11; i++)
       
   538         if (aDir->iData[i] < 0x20)
       
   539             return EFalse;
       
   540     return ETrue;
       
   541     }
       
   542 
       
   543 GLDEF_C void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength)
       
   544 //
       
   545 // Extract part of a long name entry into the name buffer.
       
   546 //
       
   547 // @param aName   buffer to put name
       
   548 // @param aEntry  directory entry raw data
       
   549 // @param aPos    character in buffer to start name segment
       
   550 // @param aOffset offset in directory entry of the segment
       
   551 // @param aLength number of characters in the segment
       
   552 //
       
   553     {
       
   554     for (TInt i = 0; i < aLength; i++)
       
   555         {
       
   556         TInt at = i * 2 + aOffset;
       
   557         TInt ch = aEntry[at] + aEntry[at+1] * 256;
       
   558         aName[aPos++] = TText(ch);
       
   559         }
       
   560     }
       
   561 
       
   562 GLDEF_C void ExtractNameString(TDes16& aName, const TUint8* aEntry)
       
   563 //
       
   564 // Extract a long name part from a directory entry, truncate it at the first
       
   565 // NUL (0) character and put quotes round it.
       
   566 //
       
   567     {
       
   568     aName.SetLength(15);
       
   569     TInt len = aName.Length() - 1;
       
   570     TText qu = '\'';
       
   571     aName[0] = qu;
       
   572     GetLongNamePart(aName, aEntry,  1,  1, 5);
       
   573     GetLongNamePart(aName, aEntry,  6, 14, 6);
       
   574     GetLongNamePart(aName, aEntry, 12, 28, 2);
       
   575     TInt i;
       
   576     for (i = 0; i < len; i++)
       
   577         if (aName[i] == 0)
       
   578             break;
       
   579     aName[i++] = qu;
       
   580     aName.SetLength(i);
       
   581     }
       
   582 
       
   583 GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
       
   584 //
       
   585 // Dump a single directory entry to the log.  Return false if it was end of
       
   586 // directory or an invalid entry (and don't display it).
       
   587 //
       
   588     {
       
   589     TFatDirEntry* d = (TFatDirEntry*)aEntry;
       
   590     if (d->IsErased())
       
   591         {
       
   592         //RDebug::Print(_L("%5d: ERASED"), aNum);
       
   593         }
       
   594     else if (d->IsEndOfDirectory())
       
   595         {
       
   596         if (aNum > 0)
       
   597             RDebug::Print(_L("%5d: ------------- end of directory"), aNum);
       
   598         return EFalse;
       
   599         }
       
   600     else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName)
       
   601         {
       
   602         TBuf16<15> name;
       
   603         ExtractNameString(name, aEntry);
       
   604         TInt ord = aEntry[0];
       
   605         if (ord & KDirLastLongEntry)
       
   606             RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
       
   607         else
       
   608             RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
       
   609         }
       
   610     else if (!IsValidDirEntry(d))
       
   611         {
       
   612         if (aNum > 0)
       
   613             RDebug::Print(_L("%5d: ============= INVALID ENTRY"), aNum);
       
   614         return EFalse;
       
   615         }
       
   616     else
       
   617         {
       
   618         TBuf<11> name;
       
   619         name.Copy(d->Name());
       
   620         RDebug::Print(_L("%5d: '%S'   %S  start %-5d size %d"),
       
   621                       aNum, &name, DirAttributes(d->Attributes()), d->StartCluster(), d->Size());
       
   622         }
       
   623     return ETrue;
       
   624     }
       
   625 
       
   626 GLDEF_C void DumpDirCluster(const TUint8* aData, TInt aCluster=0)
       
   627 //
       
   628 // Dump directory entries until end of cluster or invalid/end entry found.
       
   629 //
       
   630     {
       
   631     if (aCluster > 2)
       
   632         aData += (aCluster-2) * gBytesPerCluster;
       
   633     for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry)
       
   634         {
       
   635         if (DumpDirEntry(i/KSizeOfFatDirEntry, aData))
       
   636             aData += KSizeOfFatDirEntry;
       
   637         else
       
   638             break;
       
   639         }
       
   640     }
       
   641 
       
   642 GLDEF_C void DumpRootDir(const TUint8* aData)
       
   643 //
       
   644 // Dump the data area buffer, trying to interpret directory clusters (only look
       
   645 // at clusters which are marked as 'used' in the FAT).
       
   646 //
       
   647     {
       
   648     RDebug::Print(_L("Root dir @ 0x%08X:"), gRootDirStart);
       
   649     for (TInt i = 0; i < BootSector.RootDirEntries(); i++)
       
   650         {
       
   651         if (DumpDirEntry(i, aData))
       
   652             aData += KSizeOfFatDirEntry;
       
   653         else
       
   654             break;
       
   655         }
       
   656     }
       
   657 
       
   658 GLDEF_C void DumpData(const TUint8* aFat, const TUint8* aDir)
       
   659 //
       
   660 // Dump the data area buffer, trying to interpret directory clusters (only look
       
   661 // at clusters which are marked as 'used' in the FAT).
       
   662 //
       
   663     {
       
   664     RDebug::Print(_L("--------------- DATA AREA ------------------"));
       
   665     if (gDiskType != EFat32)
       
   666         {
       
   667         DumpRootDir(aDir);
       
   668         }
       
   669     TInt max = (gFatTestEntries < gMaxDataCluster ? gFatTestEntries : gMaxDataCluster);
       
   670     for (TInt cluster = 2; cluster < max; cluster++)
       
   671         {
       
   672         if (GetFatEntry(cluster, aFat) != 0)
       
   673             {
       
   674             RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
       
   675             DumpDirCluster(aDir+gDataStartBytes-gRootDirStart, cluster);
       
   676             }
       
   677         }
       
   678     RDebug::Print(_L("--------------------------------------------"));
       
   679     }
       
   680 
       
   681 GLDEF_C void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd = -1)
       
   682 //
       
   683 // Dump clusters from disk (allows dumping of clusters not in our buffers).
       
   684 // Only look at clusters marked as 'used' in the FAT.  Note that if aFat is
       
   685 // NULL the FAT entries will also be read from disk (slower but allows for ones
       
   686 // outside our copy in memory).
       
   687 //
       
   688     {
       
   689     if (aStart > gFatTestEntries)
       
   690         return;
       
   691     RDebug::Print(_L("--------------- DATA AREA ------------------"));
       
   692     if (aEnd > gFatTestEntries)
       
   693         aEnd = gFatTestEntries;
       
   694     if (aEnd < 0)
       
   695         aEnd = aStart + 1;
       
   696     if (aStart < 2 && gDiskType != EFat32)
       
   697         {
       
   698         HBufC8* buf=HBufC8::New(BootSector.RootDirEntries() * KSizeOfFatDirEntry);
       
   699         test(buf != NULL);
       
   700         TPtr8 ptr=buf->Des();
       
   701         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
   702         test(r==KErrNone);
       
   703         r=TheRawDisk.Read(gRootDirStart, ptr);
       
   704         test(r==KErrNone);
       
   705         TheRawDisk.Close();
       
   706         DumpRootDir(buf->Ptr());
       
   707         delete(buf);
       
   708         aStart = 2;
       
   709         }
       
   710     for (TInt cluster = aStart; cluster < aEnd; cluster++)
       
   711         {
       
   712         if (GetFatEntry(cluster, aFat) != 0)
       
   713             {
       
   714             HBufC8* buf=HBufC8::New(gBytesPerCluster);
       
   715             test(buf!=NULL);
       
   716             TPtr8 ptr=buf->Des();
       
   717             TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
   718             test(r==KErrNone);
       
   719             r=TheRawDisk.Read(ClusterToByte(cluster), ptr);
       
   720             test(r==KErrNone);
       
   721             TheRawDisk.Close();
       
   722             RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
       
   723             DumpDirCluster(ptr.Ptr());
       
   724             delete buf;
       
   725             }
       
   726         }
       
   727     RDebug::Print(_L("--------------------------------------------"));
       
   728     }
       
   729 
       
   730 GLDEF_C void DumpHex(const TUint8* aData, TInt aLen, TInt aBase=0)
       
   731 //
       
   732 // Dump a block of memory to the log in hex.
       
   733 //
       
   734     {
       
   735     for (TInt base = 0; base < aLen; base += 16)
       
   736         {
       
   737         TBuf<16*3+3+16+1> buf;
       
   738         TInt off;
       
   739         for (off = base; off < aLen && off < base + 16; off++)
       
   740             {
       
   741             buf.Append(TText(' '));
       
   742             buf.AppendNumFixedWidth(aData[off], EHex, 2);
       
   743             }
       
   744         buf.Append(_L("  |"));
       
   745         for (off = base; off < aLen && off < base + 16; off++)
       
   746             {
       
   747             TUint8 ch = aData[off];
       
   748             buf.Append(ch < 0x20 || ch > 0x7E ? TText('_') : TText(ch));
       
   749             }
       
   750         buf.Append(_L("|"));
       
   751         RDebug::Print(_L("%04X: %S"), base+aBase, &buf);
       
   752         }
       
   753     }
       
   754 
       
   755 GLDEF_C void DumpHex(const TPtrC8& aData, TInt aLen, TInt aBase=0)
       
   756 //
       
   757 // Dump a block of memory to the log in hex.
       
   758 //
       
   759     {
       
   760     DumpHex(aData.Ptr(), aLen, aBase);
       
   761     }
       
   762 
       
   763 GLDEF_C void DumpHex(TInt aPos, TInt aLen, TInt aBase=0)
       
   764 //
       
   765 // Dump a block of memory to the log in hex.
       
   766 //
       
   767     {
       
   768     TPtr8 dirBuf=DirBufPtr->Des();
       
   769     DumpHex(dirBuf.Ptr()+aPos, aLen, aBase);
       
   770     }
       
   771 
       
   772 GLDEF_C void Dump(TEntryInfo& aEntry)
       
   773 //
       
   774 // Dump an entry description to the log in hex
       
   775 //
       
   776     {
       
   777     RDebug::Print(_L("--- TEntryInfo 0x%08X, %d"), aEntry.iBytePos, aEntry.iLength);
       
   778     TInt len = aEntry.iLength*KSizeOfFatDirEntry;
       
   779     DumpHex(aEntry.iBytePos, len, aEntry.iBytePos);
       
   780     }
       
   781 
       
   782 LOCAL_C TInt GetStartCluster(TInt aCluster, TInt aEntry)
       
   783 //
       
   784 // Get the start cluster pertaining to a directory entry in a specific
       
   785 // directory cluster, return -1 if not available (invalid entry).
       
   786 //
       
   787     {
       
   788     HBufC8* buf=HBufC8::New(gBytesPerCluster*2);
       
   789     test(buf!=NULL);
       
   790     TPtr8 ptr=buf->Des();
       
   791     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
   792     test(r==KErrNone);
       
   793     r=TheRawDisk.Read(ClusterToByte(aCluster), ptr);
       
   794     test(r==KErrNone);
       
   795     TheRawDisk.Close();
       
   796     RDebug::Print(_L("Cluster %d @ 0x%08X:"), aCluster, ClusterToByte(aCluster));
       
   797     TFatDirEntry* d = (TFatDirEntry*)ptr.Ptr() + aEntry;
       
   798     while ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName && aEntry < gEntriesPerCluster)
       
   799         {
       
   800         if (d->IsErased() || d->IsEndOfDirectory())
       
   801             break;
       
   802         ++aEntry;
       
   803         d = (TFatDirEntry*)ptr.Ptr() + aEntry;
       
   804         }
       
   805     TInt start = d->StartCluster();
       
   806     if (d->IsErased())
       
   807         start = -1;
       
   808     else if (d->IsEndOfDirectory())
       
   809         start = -1;
       
   810     else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName)
       
   811         start = -1;
       
   812     else if (!IsValidDirEntry(d))
       
   813         start = -1;
       
   814     delete buf;
       
   815     return start;
       
   816     }
       
   817 
       
   818 LOCAL_C void Format()
       
   819     {
       
   820     TInt nRes;
       
   821 
       
   822 #if 0
       
   823     TFatFormatParam fmt;
       
   824     fmt.iFatType = EFat32;
       
   825     fmt.iSecPerCluster = 1;
       
   826 
       
   827     nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fmt);
       
   828 #else
       
   829     nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue);
       
   830 #endif
       
   831 
       
   832     test(nRes == KErrNone);
       
   833 
       
   834     }
       
   835 
       
   836 LOCAL_C void CreateDeepDir(TFileName& aDir,TInt aDepth)
       
   837 //
       
   838 // Increase directory strucutre by aDepth starting with aDir.
       
   839 //
       
   840     {
       
   841     TFileName num;
       
   842     num.Num(1);
       
   843     num+=_L("\\");
       
   844     TInt r;
       
   845     while(aDepth--)
       
   846         {
       
   847         num[0] = TText(aDepth % 26 + 'A');
       
   848         aDir+=num;
       
   849         r=TheFs.MkDir(aDir);
       
   850         test(r==KErrNone);
       
   851         }
       
   852     }
       
   853 
       
   854 LOCAL_C void DeleteDeepDir(TFileName& aDir,TInt aDepth)
       
   855 //
       
   856 // Delete dir structure.
       
   857 //
       
   858     {
       
   859     TInt r;
       
   860     while(aDepth--)
       
   861         {
       
   862         r=TheFs.RmDir(aDir);
       
   863         test(r==KErrNone);
       
   864         aDir.SetLength(aDir.Length()-2);
       
   865         }
       
   866     }
       
   867 
       
   868 LOCAL_C void CreateMaxDepthDir(TFileName& aDir1,TFileName& aDir2)
       
   869 //
       
   870 // Create directory structure with max possible depth-1.
       
   871 // Achieved by using dir names of one character.
       
   872 //
       
   873     {
       
   874     //create dir structure with depth of 25
       
   875     CreateDeepDir(aDir1,25);
       
   876     // split dir structure
       
   877     aDir2=aDir1;
       
   878     aDir2+=_L("a\\");
       
   879     TInt r=TheFs.MkDir(aDir2);
       
   880     test(r==KErrNone);
       
   881     // create dir with depth of 126 directories - one short of max depth
       
   882     CreateDeepDir(aDir1,101);
       
   883     // create dir with depth of 90
       
   884     CreateDeepDir(aDir2,64);
       
   885     }
       
   886 
       
   887 LOCAL_C void DeleteMaxDepthDir(TFileName&aDir1,TFileName&aDir2)
       
   888 //
       
   889 // Deletes max depth dir structure.
       
   890 //
       
   891     {
       
   892     DeleteDeepDir(aDir2,64);
       
   893     TInt r=TheFs.RmDir(aDir2);
       
   894     test(r==KErrNone);
       
   895     aDir2.SetLength(aDir2.Length()-2);
       
   896     DeleteDeepDir(aDir1,102);
       
   897     DeleteDeepDir(aDir1,24);
       
   898     }
       
   899 
       
   900 LOCAL_C void MakeVeryLongName(TFileName& aLong)
       
   901 //
       
   902 // appends a very long file name to aLong
       
   903 //
       
   904     {
       
   905     // create a name to take up 18 vfat entries - (1 sector + 2 entries)
       
   906     for(TInt i=0;i<234;++i)
       
   907         {
       
   908         TInt c='a'+i%26;
       
   909         aLong.Append(c);
       
   910         }
       
   911     }
       
   912 
       
   913 GLDEF_C void CreateLongNames(TFileName& aLong, TInt aClusters)
       
   914 //
       
   915 // Creates entries to fill up the number of directory clusters
       
   916 //
       
   917     {
       
   918     TInt len = aLong.Length(); // length of directory prefix
       
   919     MakeVeryLongName(aLong);
       
   920     TInt count = 0;
       
   921     RFile temp;
       
   922     for (TInt i = 0; i < aClusters * gEntriesPerCluster; i += 19)
       
   923         {
       
   924         aLong[len+0] = TText(count/26 + 'A');
       
   925         aLong[len+1] = TText(count%26 + 'A');
       
   926         count++;
       
   927         TInt r=temp.Create(TheFs,aLong,EFileShareAny);
       
   928         test(r==KErrNone);
       
   929         temp.Close();
       
   930         }
       
   931     }
       
   932 
       
   933 GLDEF_C void DeleteLongNames(TFileName& aLong, TInt aClusters)
       
   934 //
       
   935 // Deletes entries created by CreateLongNames()
       
   936 //
       
   937     {
       
   938     TInt len = aLong.Length(); // length of directory prefix
       
   939     MakeVeryLongName(aLong);
       
   940     TInt count = 0;
       
   941     for (TInt i = 0; i < aClusters * gEntriesPerCluster; i += 19)
       
   942         {
       
   943         aLong[len+0] = TText(count/26 + 'A');
       
   944         aLong[len+1] = TText(count%26 + 'A');
       
   945         count++;
       
   946         TInt r=TheFs.Delete(aLong);
       
   947         test(r==KErrNone || r==KErrNotFound);
       
   948         }
       
   949     }
       
   950 
       
   951 LOCAL_C void DeleteRootDir(TInt aNum=0)
       
   952 //
       
   953 // Delete all entries in the root directory up to the last - aNum
       
   954 //
       
   955     {
       
   956     test.Next(_L("Delete Root Directory Entries"));
       
   957     TInt maxRootEntries = gRootDirEntries;
       
   958     TFileName name=_L("\\???xxx");
       
   959     TInt count=0;
       
   960     TInt entriesSoFar=2;
       
   961     TInt r;
       
   962     count = 0;
       
   963     for (entriesSoFar=0; entriesSoFar<maxRootEntries - aNum; entriesSoFar+=2)
       
   964         {
       
   965         name[1]=(TUint16)(count/26/26+'a');
       
   966         name[2]=(TUint16)(count/26%26+'a');
       
   967         name[3]=(TUint16)(count%26+'a');
       
   968         r=TheFs.Delete(name);
       
   969         test(r==KErrNone || r==KErrNotFound);
       
   970         ++count;
       
   971         }
       
   972     }
       
   973 
       
   974 LOCAL_C void CreateRootDir()
       
   975 //
       
   976 // fill up root directory to 1 clusters by creating entries and then deleting
       
   977 // them except the last.
       
   978 //
       
   979     {
       
   980     test.Next(_L("Create Root Directory Entries"));
       
   981     TInt maxRootEntries = gRootDirEntries;
       
   982     TFileName name=_L("\\???xxx");
       
   983     TInt count=0;
       
   984     TInt entriesSoFar=2;
       
   985     TInt r;
       
   986     RFile f;
       
   987     for (entriesSoFar=0; entriesSoFar<maxRootEntries; entriesSoFar+=2)
       
   988         {
       
   989         name[1]=(TUint16)(count/26/26+'a');
       
   990         name[2]=(TUint16)(count/26%26+'a');
       
   991         name[3]=(TUint16)(count%26+'a');
       
   992         r=f.Create(TheFs, name, EFileWrite);
       
   993         test(r==KErrNone);
       
   994         f.Close();
       
   995         ++count;
       
   996         }
       
   997     DeleteRootDir(1);
       
   998     }
       
   999 
       
  1000 LOCAL_C void FillUpRootDir(TInt aFree=0)
       
  1001 //
       
  1002 // fill up root directory
       
  1003 //
       
  1004     {
       
  1005     TInt maxRootEntries = gRootDirEntries - aFree;
       
  1006     TFileName dir=_L("\\??\\");
       
  1007     TInt count=0;
       
  1008     TInt entriesSoFar=2;
       
  1009     TInt r;
       
  1010     while(entriesSoFar<maxRootEntries)
       
  1011         {
       
  1012         dir[1]=(TUint16)(count/26+'a');
       
  1013         dir[2]=(TUint16)(count%26+'a');
       
  1014         r=TheFs.MkDir(dir);
       
  1015         test(r==KErrNone);
       
  1016         entriesSoFar+=2;
       
  1017         ++count;
       
  1018         }
       
  1019     }
       
  1020 
       
  1021 LOCAL_C void UnFillUpRootDir(TInt aFree=0)
       
  1022 //
       
  1023 // reverse changes from FillUpRootDir()
       
  1024 //
       
  1025     {
       
  1026     TFileName dir=_L("\\??\\");
       
  1027     TInt entriesSoFar=gRootDirEntries-aFree;
       
  1028     TInt count=0;
       
  1029     TInt r;
       
  1030     while(entriesSoFar>2)
       
  1031         {
       
  1032         dir[1]=TUint16(count/26+'a');
       
  1033         dir[2]=TUint16(count%26+'a');
       
  1034         r=TheFs.RmDir(dir);
       
  1035         test(r==KErrNone);
       
  1036         entriesSoFar-=2;
       
  1037         ++count;
       
  1038         }
       
  1039     }
       
  1040 
       
  1041 LOCAL_C void DeleteDirectoryStructure()
       
  1042 //
       
  1043 // deletes the directory structure
       
  1044 //
       
  1045     {
       
  1046     test.Next(_L("Delete Directory Structure"));
       
  1047     TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\almostfull\\"));
       
  1048     test(r==KErrNone);
       
  1049     TInt entriesNeeded=(gEntriesPerCluster-2) / 2;  //7*2entries + . + .. = full sector
       
  1050     for (TInt i = 0; i < entriesNeeded; i++)
       
  1051         {
       
  1052         TFileName file=_L("\\scndrv\\dir2\\full\\__a");
       
  1053         file.AppendNum(i);
       
  1054         r=TheFs.Delete(file);
       
  1055         test(r==KErrNone||r==KErrNotFound);
       
  1056         }
       
  1057     r=TheFs.RmDir(_L("\\scndrv\\dir2\\full\\"));
       
  1058     test(r==KErrNone);
       
  1059     r=TheFs.RmDir(_L("\\scndrv\\dir2\\"));
       
  1060     test(r==KErrNone);
       
  1061     TFileName veryLongName=(_L("\\scndrv\\dir1\\"));
       
  1062     MakeVeryLongName(veryLongName);
       
  1063     r=TheFs.Delete(veryLongName);
       
  1064     test(r==KErrNone);
       
  1065     r=TheFs.RmDir(_L("\\scndrv\\dir1\\"));
       
  1066     test(r==KErrNone);
       
  1067     r=TheFs.RmDir(_L("\\scndrv\\"));
       
  1068     test(r==KErrNone);
       
  1069     }
       
  1070 
       
  1071 LOCAL_C void CreateDirectoryStructure()
       
  1072 //
       
  1073 // creates the directory structure
       
  1074 //
       
  1075     {
       
  1076     test.Next(_L("Create Directory Structure"));
       
  1077     // cluster 3 (root dir is cluster 2)
       
  1078     TInt r=TheFs.MkDir(_L("\\scndrv\\"));
       
  1079     test(r==KErrNone);
       
  1080     // cluster 4
       
  1081     r=TheFs.MkDir(_L("\\scndrv\\dir1\\"));
       
  1082     test(r==KErrNone);
       
  1083     TFileName veryLongName=(_L("\\scndrv\\dir1\\"));
       
  1084     MakeVeryLongName(veryLongName);
       
  1085     RFile f;
       
  1086     // cluster 5
       
  1087     r=f.Create(TheFs,veryLongName,EFileShareAny);
       
  1088     test(r==KErrNone);
       
  1089     r=f.SetSize(512);
       
  1090     test(r==KErrNone);
       
  1091     f.Close();
       
  1092     // cluster 6
       
  1093     r=TheFs.MkDir(_L("\\scndrv\\dir2\\"));
       
  1094     test(r==KErrNone);
       
  1095     // cluster 7
       
  1096     r=TheFs.MkDir(_L("\\scndrv\\dir2\\full\\"));
       
  1097     test(r==KErrNone);
       
  1098     // cluster 8
       
  1099     r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedirwith3entries\\"));
       
  1100     test(r==KErrNone);
       
  1101     // cluster 9
       
  1102     r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedir2with3entries\\"));
       
  1103     test(r==KErrNone);
       
  1104     // cluster 10
       
  1105     r=TheFs.MkDir(_L("\\scndrv\\dir2\\almostfull\\"));
       
  1106     test(r==KErrNone);
       
  1107     // cluster 11-17
       
  1108     TInt entriesNeeded=(gEntriesPerCluster-2) / 2;  //7*2entries + . + .. = full sector
       
  1109     for (TInt i = 0; i < entriesNeeded; i++)
       
  1110         {
       
  1111         TFileName file=_L("\\scndrv\\dir2\\full\\__a");
       
  1112         file.AppendNum(i);
       
  1113         LastInFull = file;
       
  1114         r=f.Create(TheFs,file,EFileShareAny);
       
  1115         test(r==KErrNone);
       
  1116         if (i < 7)
       
  1117             {
       
  1118             r=f.SetSize(512);
       
  1119             test(r==KErrNone);
       
  1120             }
       
  1121         f.Close();
       
  1122         }
       
  1123     // cluster 18-19
       
  1124     TInt charLength=13*4+1; // name to take up 6 entries
       
  1125     TFileName file1=_L("\\scndrv\\dir2\\almostfull\\");
       
  1126     while(charLength--)
       
  1127         {
       
  1128         TInt c='A'+charLength%26;
       
  1129         file1.Append(c);
       
  1130         }
       
  1131     TFileName file2=file1;
       
  1132     file1.AppendNum(1);
       
  1133     file2.AppendNum(2);
       
  1134     r=f.Create(TheFs,file1,EFileShareAny);
       
  1135     test(r==KErrNone);
       
  1136     r=f.SetSize(512);
       
  1137     test(r==KErrNone);
       
  1138     f.Close();
       
  1139     r=f.Create(TheFs,file2,EFileShareAny);
       
  1140     test(r==KErrNone);
       
  1141     r=f.SetSize(512);
       
  1142     test(r==KErrNone);
       
  1143     f.Close();
       
  1144     }
       
  1145 
       
  1146 LOCAL_C TUint8* DirPtr(TInt aOffset)
       
  1147 //
       
  1148 // Return a pointer to the offset in the dir buffer, or in the special
       
  1149 // extension buffer if the dir buffer isn't large enough.  If the extension
       
  1150 // buffer is needed, it is read from disk when it is created (2 clusters, to
       
  1151 // allow for entries spanning cluster boundaries).  Errors will occur if
       
  1152 // another cluster is needed before the extension has been released.
       
  1153 //
       
  1154 // Note that if an extension buffer is allocated then writing a dir buffer to
       
  1155 // disk will also write the extension buffer and any changes made in it.
       
  1156 //
       
  1157     {
       
  1158     // if the offset is in store, return its byte address
       
  1159     if (aOffset < DirBufPtr->Des().MaxLength())
       
  1160         return (TUint8*)DirBufPtr->Ptr() + aOffset;
       
  1161     // not in main buffer, see if extension is allocated already
       
  1162     if (!ExtBufPtr)
       
  1163         {
       
  1164         // allocate buffer for 2 clusters, starting at the cluster which
       
  1165         // contains aOffset
       
  1166         ExtBufLen = 2 * gBytesPerCluster;
       
  1167         ExtBufPtr = HBufC8::New(ExtBufLen);
       
  1168         test(ExtBufPtr != NULL);
       
  1169         // read the clusters in
       
  1170         ExtBufAdd = aOffset - aOffset % gBytesPerCluster;
       
  1171         TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2;
       
  1172         RDebug::Print(_L("Extension buffer for cluster %d allocated"), clust);
       
  1173         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
  1174         test(r==KErrNone);
       
  1175         TPtr8 des(ExtBufPtr->Des());
       
  1176         r=TheRawDisk.Read(gRootDirStart + ExtBufAdd, des);
       
  1177         test(r==KErrNone);
       
  1178         TheRawDisk.Close();
       
  1179         }
       
  1180     // convert to offset in the extension buffer
       
  1181     aOffset -= ExtBufAdd;
       
  1182     if (aOffset >= ExtBufLen)
       
  1183         {
       
  1184         test.Printf(_L("*** ERROR: tried to access cluster %d not in store\n"),
       
  1185                     (aOffset + ExtBufAdd) / gBytesPerCluster + 2);
       
  1186         test(0);
       
  1187         }
       
  1188     return (TUint8*)ExtBufPtr->Ptr() + aOffset;
       
  1189     }
       
  1190 
       
  1191 LOCAL_C void DirPtrFree()
       
  1192 //
       
  1193 // Free the extension buffer and zero the references to it.
       
  1194 //
       
  1195     {
       
  1196     if (ExtBufPtr)
       
  1197         {
       
  1198         TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2;
       
  1199         RDebug::Print(_L("Extension buffer for cluster %d deleted"), clust);
       
  1200         delete ExtBufPtr;
       
  1201         ExtBufPtr = NULL;
       
  1202         ExtBufAdd = 0;
       
  1203         ExtBufLen = 0;
       
  1204         }
       
  1205     }
       
  1206 
       
  1207 LOCAL_C void ReadDirDisk(TDes8& aDirBuf, TInt aCluster = -1)
       
  1208 //
       
  1209 // reads directory section of disk into buffer
       
  1210 //
       
  1211     {
       
  1212     test(aCluster != 1);
       
  1213 
       
  1214     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
  1215     test(r==KErrNone);
       
  1216 
       
  1217     if (aCluster == -1) // all clusters ?
       
  1218         {
       
  1219         r=TheRawDisk.Read(gRootDirStart, aDirBuf);
       
  1220         }
       
  1221     else if (aCluster == 0) // root directory cluster
       
  1222         {
       
  1223         TPtr8 dirPtr = aDirBuf.MidTPtr(0, gBytesPerCluster);
       
  1224         r=TheRawDisk.Read(gRootDirStart, dirPtr);
       
  1225         }
       
  1226     else
       
  1227         {
       
  1228         // directory buffer starts at root directory, so
       
  1229         // calculate offset from there.
       
  1230         TInt pos = ((aCluster - 2) * gBytesPerCluster) +
       
  1231             (gRootDirSectors * BootSector.BytesPerSector());
       
  1232         TPtr8 dirPtr = aDirBuf.MidTPtr(pos, gBytesPerCluster);
       
  1233         r=TheRawDisk.Read(gRootDirStart + pos, dirPtr);
       
  1234         }
       
  1235 
       
  1236     test(r==KErrNone);
       
  1237     TheRawDisk.Close();
       
  1238     }
       
  1239 
       
  1240 LOCAL_C void ReadFatDisk(TDes8& aFatBuf)
       
  1241 //
       
  1242 // reads fat section of disk info buffer
       
  1243 //
       
  1244     {
       
  1245     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
  1246     test(r==KErrNone);
       
  1247     r=TheRawDisk.Read(gFatStartBytes, aFatBuf);
       
  1248     test(r==KErrNone);
       
  1249     TheRawDisk.Close();
       
  1250     }
       
  1251 
       
  1252 LOCAL_C void WriteDirDisk(TDes8& aDirBuf, TInt aCluster = -1)
       
  1253 //
       
  1254 // writes dir buffer to disk
       
  1255 //
       
  1256     {
       
  1257     test(aCluster != 1);
       
  1258 
       
  1259     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
  1260     test(r==KErrNone);
       
  1261 
       
  1262     if (aCluster == -1)
       
  1263         {
       
  1264         r=TheRawDisk.Write(gRootDirStart, aDirBuf);
       
  1265         }
       
  1266     else if (aCluster == 0) // root directory cluster
       
  1267         {
       
  1268         TPtr8 dirPtr = aDirBuf.MidTPtr(0, gBytesPerCluster);
       
  1269         r=TheRawDisk.Write(gRootDirStart, dirPtr);
       
  1270         }
       
  1271     else
       
  1272         {
       
  1273         // directory buffer starts at root directory, so
       
  1274         // calculate offset from there.
       
  1275         TInt pos = ((aCluster - 2) * gBytesPerCluster) +
       
  1276             (gRootDirSectors * BootSector.BytesPerSector());
       
  1277         TPtr8 dirPtr = aDirBuf.MidTPtr(pos, gBytesPerCluster);
       
  1278         r=TheRawDisk.Write(gRootDirStart + pos, dirPtr);
       
  1279         }
       
  1280 
       
  1281     test(r==KErrNone);
       
  1282     if (ExtBufPtr)
       
  1283         {
       
  1284         TPtr8 des(ExtBufPtr->Des());
       
  1285         r=TheRawDisk.Write(gRootDirStart + ExtBufAdd, des);
       
  1286         test(r==KErrNone);
       
  1287         }
       
  1288     TheRawDisk.Close();
       
  1289     }
       
  1290 
       
  1291 LOCAL_C void WriteFatDisk(TDes8& aFatBuf, TInt aStart=0)
       
  1292 //
       
  1293 // writes fat buffer to disk
       
  1294 //
       
  1295     {
       
  1296     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
  1297     test(r==KErrNone);
       
  1298     TInt fatCount=BootSector.NumberOfFats() - aStart;
       
  1299     TInt pos = gFatStartBytes + aStart * gFatSizeSectors*BootSector.BytesPerSector();
       
  1300     while(fatCount--)
       
  1301         {
       
  1302         r=TheRawDisk.Write(pos, aFatBuf);
       
  1303         test(r==KErrNone);
       
  1304         pos += gFatSizeSectors*BootSector.BytesPerSector();
       
  1305         }
       
  1306     TheRawDisk.Close();
       
  1307     }
       
  1308 
       
  1309 LOCAL_C void WriteReservedId(TInt aBytePos)
       
  1310 //
       
  1311 // write reserved id to byte 19 of entry starting at aBytePos
       
  1312 //
       
  1313     {
       
  1314     TUint8* pEntry=DirPtr(aBytePos);
       
  1315     pEntry[19]=1;
       
  1316     }
       
  1317 
       
  1318 LOCAL_C void WriteEndOfDir(TInt aBytePos)
       
  1319 //
       
  1320 // write end of directory marker to entry starting at aBytePos
       
  1321 //
       
  1322     {
       
  1323     TUint8* pEntry=DirPtr(aBytePos);
       
  1324     Mem::FillZ(pEntry,KFatDirNameSize);
       
  1325     }
       
  1326 
       
  1327 LOCAL_C void WriteDelete(TInt aBytePos,TInt aNum)
       
  1328 //
       
  1329 // writes 0xe5 to entries starting at aBytePos
       
  1330 //
       
  1331     {
       
  1332     TUint8* pEntry=DirPtr(aBytePos);
       
  1333     while(aNum--)
       
  1334         {
       
  1335         pEntry[0]=0xE5;
       
  1336         pEntry+=KSizeOfFatDirEntry;
       
  1337         }
       
  1338     }
       
  1339 
       
  1340 LOCAL_C void WriteCopyDir(TInt aSrc, TInt aDst)
       
  1341 //
       
  1342 // Copy one directory entry over another
       
  1343 //
       
  1344     {
       
  1345     TUint8* pSrc=DirPtr(aSrc);
       
  1346     TUint8* pDst=DirPtr(aDst);
       
  1347     Mem::Copy(pDst, pSrc, KSizeOfFatDirEntry);
       
  1348     }
       
  1349 
       
  1350 LOCAL_C void InitialiseBuffers()
       
  1351 //
       
  1352 // reads disk into buffers
       
  1353 //
       
  1354     {
       
  1355     gFatTestEntries = MaxClusters();
       
  1356     if (gFatTestEntries > KMaxFatSize)
       
  1357         gFatTestEntries = KMaxFatSize;
       
  1358     gFatTestSize = PosInBytes(gFatTestEntries);
       
  1359     FatBufPtr=HBufC8::New(gFatTestSize);
       
  1360     test(FatBufPtr!=NULL);
       
  1361     DirBufPtr=HBufC8::New(DirBufferSize());
       
  1362     test(DirBufPtr!=NULL);
       
  1363 
       
  1364     // Buffers for reading from disk
       
  1365     FatDiskPtr=HBufC8::New(gFatTestSize);
       
  1366     test(FatDiskPtr!=NULL);
       
  1367     DirDiskPtr=HBufC8::New(DirBufferSize());
       
  1368     test(DirDiskPtr!=NULL);
       
  1369     }
       
  1370 
       
  1371 LOCAL_C TBool IsSameAsDrive(const TDes8& aFatBuf,const TDes8& aDirBuf)
       
  1372 //
       
  1373 // compares the two bufs passed in with those on disk
       
  1374 //
       
  1375     {
       
  1376     TPtr8 fatDisk=FatDiskPtr->Des();
       
  1377     TPtr8 dirDisk=DirDiskPtr->Des();
       
  1378     ReadDirDisk(dirDisk);
       
  1379     ReadFatDisk(fatDisk);
       
  1380     TBool fatOk = (aFatBuf.Compare(fatDisk)==0);
       
  1381     TBool dirOk = (aDirBuf.Compare(dirDisk)==0);
       
  1382     if (!fatOk)
       
  1383         {
       
  1384         TInt i = FindUnMatch(aFatBuf.Ptr(), fatDisk.Ptr(), fatDisk.Length());
       
  1385         switch (gDiskType)
       
  1386             {
       
  1387             case EFat32:
       
  1388                 i /= 4;
       
  1389 
       
  1390                 if(i == 1)
       
  1391                 {//-- mismatch in FAT[1] for FAT16/FAT32 it is OK because FAT[1] is used by volume finalisation
       
  1392                  //-- to store Volume Clean Shutdown flag
       
  1393                     fatOk = ETrue;
       
  1394                 }
       
  1395 
       
  1396                 break;
       
  1397 
       
  1398             case EFat16:
       
  1399                 i /= 2;
       
  1400 
       
  1401                 if(i == 1)
       
  1402                 {//-- mismatch in FAT[1] for FAT16/FAT32  it is OK because FAT[1] is used by volume finalisation
       
  1403                  //-- to store Volume Clean Shutdown flag
       
  1404                     fatOk = ETrue;
       
  1405                 }
       
  1406 
       
  1407                 break;
       
  1408 
       
  1409             case EFat12:
       
  1410                 i = i*2 / 3;
       
  1411                 if (GetFatEntry(i, aFatBuf.Ptr()) == GetFatEntry(i, fatDisk.Ptr()))
       
  1412                     ++i;
       
  1413                 break;
       
  1414             default:
       
  1415                 test(0);
       
  1416             }
       
  1417 
       
  1418         if(fatOk && i==1)
       
  1419             {
       
  1420             test.Printf(_L("Skipping FAT[1] entry for FAT16/32 \n"), i);
       
  1421             }
       
  1422         else
       
  1423             {
       
  1424         test.Printf(_L("FAT entry %d different from expected\n"), i);
       
  1425 
       
  1426         RDebug::Print(_L("Expected:\n"));
       
  1427         DumpFat(aFatBuf.Ptr());
       
  1428         RDebug::Print(_L("Actual:\n"));
       
  1429         DumpFat(fatDisk.Ptr());
       
  1430         }
       
  1431         }
       
  1432 
       
  1433     if (!dirOk)
       
  1434         {
       
  1435         TInt i = FindUnMatch(aDirBuf.Ptr(), dirDisk.Ptr(), dirDisk.Length());
       
  1436         TInt clust = ByteToCluster(i);
       
  1437         TInt entry = i % gBytesPerCluster / KSizeOfFatDirEntry;
       
  1438         test.Printf(_L("DIR different from expected\n"));
       
  1439         test.Printf(_L("  at pos %d sector %d cluster %d entry %d:\n"), i, i / BootSector.BytesPerSector(), clust, entry);
       
  1440 
       
  1441 		RDebug::Print(_L("Expected:\n"));
       
  1442 		DumpHex(aDirBuf.Ptr() + i, 32);
       
  1443 		RDebug::Print(_L("-------------"));
       
  1444 		RDebug::Print(_L("Actual:\n"));
       
  1445 		DumpHex(dirDisk.Ptr() + i, 32);
       
  1446 
       
  1447 		RDebug::Print(_L("Expected:\n"));
       
  1448 		DumpData(aFatBuf.Ptr(), aDirBuf.Ptr());
       
  1449 		RDebug::Print(_L("Actual:\n"));
       
  1450 		DumpData(fatDisk.Ptr(), dirDisk.Ptr());
       
  1451         }
       
  1452     else if (ExtBufPtr)
       
  1453         {
       
  1454         HBufC8* extPtr = HBufC8::New(ExtBufLen);
       
  1455         test(extPtr != NULL);
       
  1456         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
       
  1457         test(r==KErrNone);
       
  1458         TPtr8 des(extPtr->Des());
       
  1459         r=TheRawDisk.Read(ExtBufAdd+gRootDirStart, des);
       
  1460         test(r==KErrNone);
       
  1461         TheRawDisk.Close();
       
  1462         TInt i = FindUnMatch(ExtBufPtr->Ptr(), extPtr->Ptr(), ExtBufLen);
       
  1463         if (i >= 0)
       
  1464             {
       
  1465             TInt extcl = (ExtBufAdd - (gDataStartBytes-gRootDirStart)) / gBytesPerCluster + 2;
       
  1466             TInt clust = i / gBytesPerCluster;
       
  1467             TInt entry = i % gBytesPerCluster / KSizeOfFatDirEntry;
       
  1468             test.Printf(_L("DIR different from expected\n"));
       
  1469             test.Printf(_L("  at cluster %d entry %d:\n"), extcl+clust, entry);
       
  1470             DumpHex(ExtBufPtr->Ptr() + clust * gBytesPerCluster + entry * KSizeOfFatDirEntry, 32);
       
  1471             RDebug::Print(_L("-------------"));
       
  1472             DumpHex(extPtr->Ptr() + clust * gBytesPerCluster + entry * KSizeOfFatDirEntry, 32);
       
  1473             // RDebug::Print(_L("Expected:\n"));
       
  1474             // DumpData(aFatBuf.Ptr(), aDirBuf.Ptr());
       
  1475             // RDebug::Print(_L("Actual:\n"));
       
  1476             // DumpData(fatDisk.Ptr(), dirDisk.Ptr());
       
  1477             dirOk = EFalse;
       
  1478             }
       
  1479         delete extPtr;
       
  1480         }
       
  1481 
       
  1482     return(fatOk && dirOk);
       
  1483     }
       
  1484 
       
  1485 LOCAL_C void WriteErased(TEntryInfo aTrg,TInt aToDelete)
       
  1486 //
       
  1487 // writes erased marker, starting at dos entry and working backwards
       
  1488 // used to simulate a part entry40*BootSector.BytesPerSector()
       
  1489 //
       
  1490     {
       
  1491     TInt toStart=aTrg.iBytePos+(aTrg.iLength-1)*KSizeOfFatDirEntry;
       
  1492     TPtr8 dirBuf=DirBufPtr->Des();
       
  1493     while(aToDelete--)
       
  1494         {
       
  1495         dirBuf[toStart]=0xE5;
       
  1496         toStart-=KSizeOfFatDirEntry;
       
  1497         }
       
  1498     }
       
  1499 
       
  1500 LOCAL_C void CreatePartialEntry(TEntryInfo aTrg,TInt aToDelete,TBool aAddEOfDir)
       
  1501 //
       
  1502 // creates a partial entry
       
  1503 //
       
  1504     {
       
  1505     WriteErased(aTrg,aToDelete);
       
  1506     if(aAddEOfDir)
       
  1507         WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry);
       
  1508     TPtr8 dirBuf=DirBufPtr->Des();
       
  1509     WriteDirDisk(dirBuf);
       
  1510     }
       
  1511 
       
  1512 LOCAL_C TBool TestPartialEntry(TEntryInfo aEntry)
       
  1513 //
       
  1514 // tests that scandrive deals with a partial entry and returns the result
       
  1515 //
       
  1516     {
       
  1517     test.Next(_L("TestPartialEntry"));
       
  1518     TInt r=TheFs.ScanDrive(gSessionPath);
       
  1519     test(r==KErrNone);
       
  1520     WriteDelete(aEntry.iBytePos,aEntry.iLength);
       
  1521 
       
  1522     TPtr8 fatBuf=FatBufPtr->Des();
       
  1523     TPtr8 dirBuf=DirBufPtr->Des();
       
  1524 
       
  1525     TBool res=IsSameAsDrive(fatBuf,dirBuf);
       
  1526     return(res);
       
  1527     }
       
  1528 
       
  1529 LOCAL_C void CreateMatchingEntry(TEntryInfo aTrg,TEntryInfo aSrc,TBool aAddEOfDir)
       
  1530 //
       
  1531 // creates matching entry
       
  1532 //
       
  1533     {
       
  1534     test.Next(_L("Create entry with start cluster already used"));
       
  1535     TUint8* src = DirPtr(aSrc.iBytePos);
       
  1536     TUint8* dst = DirPtr(aTrg.iBytePos);
       
  1537     Mem::Copy(dst, src, aSrc.iLength*KSizeOfFatDirEntry);
       
  1538     WriteReservedId(aTrg.iBytePos+(aTrg.iLength-1)*KSizeOfFatDirEntry);
       
  1539     if(aAddEOfDir)
       
  1540         WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry);
       
  1541     TPtr8 dirBuf=DirBufPtr->Des();
       
  1542     WriteDirDisk(dirBuf);
       
  1543     }
       
  1544 
       
  1545 LOCAL_C TBool TestMatchingEntry(TEntryInfo aToDelete)
       
  1546 //
       
  1547 // tests that scandrive deals with matching entries correctly
       
  1548 //
       
  1549     {
       
  1550     test.Next(_L("TestMatchingEntries"));
       
  1551     WriteDelete(aToDelete.iBytePos,aToDelete.iLength);
       
  1552     TInt r=TheFs.ScanDrive(gSessionPath);
       
  1553     test(r==KErrNone);
       
  1554 
       
  1555     TPtr8 fatBuf=FatBufPtr->Des();
       
  1556     TPtr8 dirBuf=DirBufPtr->Des();
       
  1557 
       
  1558     TBool res=IsSameAsDrive(fatBuf,dirBuf);
       
  1559     DirPtrFree();
       
  1560     return(res);
       
  1561     }
       
  1562 
       
  1563 
       
  1564 LOCAL_C void TestExtendedChars()
       
  1565 //
       
  1566 // tests that extended characters corresponding to ISO Latin 1
       
  1567 // characters 128-255 are recognised as valid by scandrive
       
  1568 //
       
  1569     {
       
  1570     test.Next(_L("TestExtendedChars()"));
       
  1571     Format();
       
  1572 
       
  1573     _LIT(KRoot,"\\");
       
  1574     CDir* dirs;
       
  1575     // check no entries in the root directory
       
  1576     TInt r=TheFs.GetDir(KRoot,KEntryAttMaskSupported,ESortNone,dirs);
       
  1577     test(r==KErrNone);
       
  1578     test(dirs->Count()==0);
       
  1579     delete(dirs);
       
  1580     dirs=NULL;
       
  1581 
       
  1582     // create file
       
  1583     _LIT(KOrigShortName,"P_SSI.TXT");
       
  1584 
       
  1585     //_LIT(KTestFile,"\\p\xE4ssi.txt"); //-- this causes problems for VC6 and default locale different from English
       
  1586     TBuf<64> TestFileName(_L("\\p$ssi.txt"));
       
  1587     TestFileName[2] = 0xe4; //-- replace '$' with this code
       
  1588 
       
  1589     //_LIT(KExtShortName,"P\xC4SSI.TXT"); //-- this causes problems for VC6 and default locale different from English
       
  1590     TBuf<64> ExtShortName(_L("P$SSI.TXT"));
       
  1591     ExtShortName[1] = 0xC4; //-- replace '$' with this code
       
  1592 
       
  1593 
       
  1594     RFile file;
       
  1595     r=file.Replace(TheFs,TestFileName,EFileShareExclusive);
       
  1596     test(r==KErrNone);
       
  1597     file.Close();
       
  1598 
       
  1599     // get short name
       
  1600     TFileName shortName;
       
  1601     r=TheFs.GetShortName(TestFileName,shortName);
       
  1602     test(r==KErrNone);
       
  1603     test(shortName==KOrigShortName);
       
  1604 
       
  1605     // must be first entry in root, modify to read like
       
  1606     // a windows-generated short name (ie. contains extended character)
       
  1607     DumpData(NULL, 0, 20);
       
  1608     TInt bytePos=ClusterEntryToBytes(0,1);
       
  1609     RRawDisk raw;
       
  1610     r=raw.Open(TheFs,gSessionPath[0]-'A');
       
  1611     test(r==KErrNone);
       
  1612     TBuf8<1> buf(1);
       
  1613 
       
  1614     //-- change 2nd character in the short name (Fat DOS entry)
       
  1615     buf[0]=(TUint8)'\xC4';
       
  1616     r=raw.Write(gRootDirStart+bytePos+1,buf);
       
  1617     test(r==KErrNone);
       
  1618 
       
  1619     //-- fix the fiddled short name checksum in the corresponding VFat entry
       
  1620     bytePos=ClusterEntryToBytes(0,0);
       
  1621     buf[0]=(TUint8)0x2f;
       
  1622     r=raw.Write(gRootDirStart+bytePos+13,buf);
       
  1623     test(r==KErrNone);
       
  1624 
       
  1625     // retrieve short name from media.
       
  1626     // Note: do not use RFs::GetShortName() as its behaviours are code page dependent.
       
  1627     bytePos=ClusterEntryToBytes(0,1);
       
  1628     TBuf8<11> shortNameBuf8;
       
  1629     r=raw.Read(gRootDirStart+bytePos,shortNameBuf8);
       
  1630     test(r==KErrNone);
       
  1631     shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8);
       
  1632     shortName.Copy(shortNameBuf8);
       
  1633     raw.Close();
       
  1634 
       
  1635 
       
  1636     test(shortName==ExtShortName);
       
  1637     DumpData(NULL, 0, 20);
       
  1638     //TheFs.SetDebugRegister(KFSYS);
       
  1639     r=TheFs.ScanDrive(gSessionPath);
       
  1640     TheFs.SetDebugRegister(0);
       
  1641     test(r==KErrNone);
       
  1642     DumpData(NULL, 0, 20);
       
  1643 
       
  1644     // retrieve short name from media.
       
  1645     r=raw.Open(TheFs,gSessionPath[0]-'A');
       
  1646     test(r==KErrNone);
       
  1647     bytePos=ClusterEntryToBytes(0,1);
       
  1648     r=raw.Read(gRootDirStart+bytePos,shortNameBuf8);
       
  1649     test(r==KErrNone);
       
  1650     shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8);
       
  1651     shortName.Copy(shortNameBuf8);
       
  1652     raw.Close();
       
  1653 
       
  1654     test(shortName==ExtShortName);
       
  1655 
       
  1656     // delete file
       
  1657     r=TheFs.Delete(TestFileName);
       
  1658     test(r==KErrNone);
       
  1659     }
       
  1660 
       
  1661 LOCAL_C void TestMountAndScan()
       
  1662 //
       
  1663 // test MountFileSystemAndScan()
       
  1664 //
       
  1665     {
       
  1666     TFullName extName;
       
  1667     TBool primaryExtensionExists = EFalse;
       
  1668 
       
  1669     test.Next(_L("TestMountAndScan"));
       
  1670     HBufC8* newFat=HBufC8::New(gFatTestSize);
       
  1671     test(newFat!=NULL);
       
  1672     TPtr8 fat=newFat->Des();
       
  1673     TPtr8 origFat=FatBufPtr->Des();
       
  1674     TPtr8 origDir=DirBufPtr->Des();
       
  1675 
       
  1676     // set cluster of \scndrv\dir1\ to a hanging cluster
       
  1677     ReadFatDisk(fat);
       
  1678     WriteFat(gClusterDir1ext,35,fat.Ptr());
       
  1679     WriteFat(35,36,fat.Ptr());
       
  1680     WriteFatDisk(fat);
       
  1681     // set the default path to something other than the current drive
       
  1682     TFileName fsName;
       
  1683     TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A');
       
  1684     test(r==KErrNone);
       
  1685     TFileName origDefPath, newDefPath;
       
  1686     r=TheFs.SessionPath(origDefPath);
       
  1687     test(r==KErrNone);
       
  1688     newDefPath=origDefPath;
       
  1689     newDefPath[0]=(TText)'z';
       
  1690     r=TheFs.SetSessionPath(newDefPath);
       
  1691     test(r==KErrNone);
       
  1692     r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0);
       
  1693     if (r == KErrNone)
       
  1694         {
       
  1695         primaryExtensionExists = ETrue;
       
  1696         }
       
  1697     r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A');
       
  1698     test(r==KErrNone);
       
  1699     // mount file system and check scandrive corrects error
       
  1700     TBool isMount;
       
  1701     if (primaryExtensionExists)
       
  1702         r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount);
       
  1703     else
       
  1704         r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount);
       
  1705     test(isMount && r==KErrNone);
       
  1706     TBool res=IsSameAsDrive(origFat,origDir);
       
  1707     test(res);
       
  1708 
       
  1709     r=TheFs.SetSessionPath(origDefPath);
       
  1710     test(r==KErrNone);
       
  1711     delete newFat;
       
  1712     }
       
  1713 
       
  1714 
       
  1715 LOCAL_C void TestConsecutiveMountAndScans()
       
  1716 //
       
  1717 // test fix for DEF093072: [codebase]MountFileSystemAndScan returns err -21 but ok flag
       
  1718 //
       
  1719     {
       
  1720     TFullName extName;
       
  1721     TBool primaryExtensionExists = EFalse;
       
  1722     TFileName fsName;
       
  1723     TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A');
       
  1724     test(r==KErrNone);
       
  1725     r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0);
       
  1726     if (r == KErrNone)
       
  1727         {
       
  1728         primaryExtensionExists = ETrue;
       
  1729         }
       
  1730     r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A');
       
  1731     test(r==KErrNone);
       
  1732 
       
  1733     // RFs::MountFileSystemAndScan twice consecutively
       
  1734     // first time
       
  1735     TBool isMount;
       
  1736     if (primaryExtensionExists)
       
  1737         r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount);
       
  1738     else
       
  1739         r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount);
       
  1740     test(isMount && r==KErrNone);
       
  1741     // and a second time
       
  1742     if (primaryExtensionExists)
       
  1743         r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount);
       
  1744     else
       
  1745         r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount);
       
  1746     test(!isMount && r==KErrAccessDenied);
       
  1747     }
       
  1748 
       
  1749 LOCAL_C void DoHangingClusters()
       
  1750 //
       
  1751 // Tests that scandrive removes hanging clusters
       
  1752 //
       
  1753     {
       
  1754     test.Next(_L("Check Hanging clusters"));
       
  1755     HBufC8* newFat=HBufC8::New(gFatTestSize);
       
  1756     test(newFat!=NULL);
       
  1757     TPtr8 fat=newFat->Des();
       
  1758     TPtr8 origFat=FatBufPtr->Des();
       
  1759     TPtr8 origDir=DirBufPtr->Des();
       
  1760 
       
  1761     // set cluster of \scndrv\dir1\ to a hanging cluster
       
  1762     test.Start(_L("Test hanging cluster in \\scndrv\\dir1\\"));
       
  1763     ReadFatDisk(fat);
       
  1764     WriteFat(gClusterDir1ext,35,fat.Ptr());
       
  1765     WriteFat(35,36,fat.Ptr());
       
  1766     WriteFatDisk(fat);
       
  1767     TInt r=TheFs.ScanDrive(gSessionPath);
       
  1768     test(r==KErrNone);
       
  1769     TBool res=IsSameAsDrive(origFat,origDir);
       
  1770     test(res);
       
  1771 
       
  1772     // set  cluster chain of first entry of \scndrv\dir1\ to
       
  1773     // larger size than file size
       
  1774     test.Next(_L("Test hanging cluster in first entry"));
       
  1775     ReadFatDisk(fat);
       
  1776     WriteFat(gClusterDir1ext,39,fat.Ptr());
       
  1777     WriteFat(39,500,fat.Ptr());
       
  1778     WriteFat(500,gEndOfChain,fat.Ptr());
       
  1779     WriteFatDisk(fat);
       
  1780     r=TheFs.ScanDrive(gSessionPath);
       
  1781     test(r==KErrNone);
       
  1782     res=IsSameAsDrive(origFat,origDir);
       
  1783     test(res);
       
  1784 
       
  1785     // set cluster of \scndrv\ to a hanging cluster
       
  1786     test.Next(_L("Test hanging cluster of \\scndrv\\"));
       
  1787     ReadFatDisk(fat);
       
  1788     WriteFat(gClusterScnDrv,511,fat.Ptr());
       
  1789     WriteFatDisk(fat);
       
  1790     r=TheFs.ScanDrive(gSessionPath);
       
  1791     test(r==KErrNone);
       
  1792     res=IsSameAsDrive(origFat,origDir);
       
  1793     test(res);
       
  1794 
       
  1795     delete newFat;
       
  1796     test.End();
       
  1797     }
       
  1798 
       
  1799 LOCAL_C void DoLostClusters()
       
  1800 //
       
  1801 // Tests that scandrive removes lost clusters
       
  1802 //
       
  1803     {
       
  1804     test.Next(_L("Check lost clusters"));
       
  1805     HBufC8* newFat=HBufC8::New(gFatTestSize);
       
  1806     test(newFat!=NULL);
       
  1807     TPtr8 fat=newFat->Des();
       
  1808     TPtr8 origFat=FatBufPtr->Des();
       
  1809     TPtr8 origDir=DirBufPtr->Des();
       
  1810     ReadFatDisk(origFat);
       
  1811     ReadDirDisk(origDir);
       
  1812 
       
  1813     // write cluster chain
       
  1814     test.Start(_L("Test removal of lost cluster chain"));
       
  1815     ReadFatDisk(fat);
       
  1816     for(TInt i=25;i<35;++i)
       
  1817         WriteFat(i,i+1,fat.Ptr());
       
  1818     WriteFat(35,gEndOfChain,fat.Ptr());
       
  1819     WriteFatDisk(fat);
       
  1820     TInt r=TheFs.ScanDrive(gSessionPath);
       
  1821     test(r==KErrNone);
       
  1822     TBool res=IsSameAsDrive(origFat,origDir);
       
  1823     test(res);
       
  1824 
       
  1825     // write semi-random changes to first fat
       
  1826     test.Next(_L("Test semi-random changes to first fat"));
       
  1827     for(TInt j=1;j<gFatTestSize/BootSector.BytesPerSector();++j)
       
  1828         {
       
  1829         TInt off = j*BootSector.BytesPerSector()+j*7%512;
       
  1830         fat[off]=1;
       
  1831         }
       
  1832     WriteFatDisk(fat);
       
  1833     r=TheFs.ScanDrive(gSessionPath);
       
  1834     test(r==KErrNone);
       
  1835     res=IsSameAsDrive(origFat,origDir);
       
  1836     test(res);
       
  1837 
       
  1838     // write semi-random changes to second fat
       
  1839     test.Next(_L("Test semi-random changes to second fat"));
       
  1840     WriteFatDisk(fat, 1);
       
  1841     r=TheFs.ScanDrive(gSessionPath);
       
  1842     test(r==KErrNone);
       
  1843     res=IsSameAsDrive(origFat,origDir);
       
  1844     test(res);
       
  1845 
       
  1846     delete newFat;
       
  1847     test.End();
       
  1848     }
       
  1849 
       
  1850 LOCAL_C void DoPartEntries()
       
  1851 //
       
  1852 // Tests that scandrive detects/corrects partial entries
       
  1853 //
       
  1854     {
       
  1855     RFile temp;
       
  1856     TInt last;
       
  1857     TBool res;
       
  1858     test.Start(_L("Check partial entries"));
       
  1859     TPtr8 fatBuf=FatBufPtr->Des();
       
  1860     TPtr8 dirBuf=DirBufPtr->Des();
       
  1861 
       
  1862     TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\"));
       
  1863     test(r==KErrNone || r==KErrNotFound || KErrPathNotFound);
       
  1864     r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\"));
       
  1865     test(r==KErrNone || r==KErrNotFound || KErrPathNotFound);
       
  1866 
       
  1867     if (BootSector.RootDirEntries() != 0)
       
  1868         {
       
  1869         // Can only do this on FAT12/16, FAT32 root directory is extensible
       
  1870         // partial entry that fills up the root dir
       
  1871         test.Next(_L("Partial entry at end of rootdir"));
       
  1872         FillUpRootDir(2);
       
  1873         r=temp.Create(TheFs,_L("\\temp"),EFileShareAny);
       
  1874         test(r==KErrNone);
       
  1875         temp.Close();
       
  1876         ReadDirDisk(dirBuf);
       
  1877         ReadFatDisk(fatBuf);
       
  1878         TEntryInfo partial1(ClusterEntryToBytes(gClusterRootDir,BootSector.RootDirEntries()-2),2);
       
  1879         CreatePartialEntry(partial1,1,EFalse);
       
  1880         res=TestPartialEntry(partial1);
       
  1881         test(res);
       
  1882         UnFillUpRootDir(2);
       
  1883         ReadDirDisk(dirBuf);
       
  1884         ReadFatDisk(fatBuf);
       
  1885         }
       
  1886 
       
  1887     // use first entry \scndrv\dir2\almostfull\ 
       
  1888     test.Next(_L("Partial entry in middle of subdir"));
       
  1889     last = GetStartCluster(gClusterDir2_AFull,7);
       
  1890     TEntryInfo partial2(ClusterEntryToBytes(gClusterDir2_AFull,2),6);
       
  1891     CreatePartialEntry(partial2,3,EFalse);
       
  1892     // entry has been allocated a cluster which scandrive should delete along with partial entry
       
  1893     if (last > 0)
       
  1894         WriteFat(last,0,fatBuf.Ptr());
       
  1895     res=TestPartialEntry(partial2);
       
  1896     test(res);
       
  1897 
       
  1898     // reduce size of \scndrv\dir2\full\ 
       
  1899     test.Next(_L("Test directory reclaim"));
       
  1900     last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-2);
       
  1901     WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2));
       
  1902     WriteDirDisk(dirBuf);
       
  1903     TInt entry = GetFatEntry(gClusterDir2_Full, fatBuf.Ptr());
       
  1904     WriteFat(gClusterDir2_Full,gEndOfChain,fatBuf.Ptr());
       
  1905     while (entry && (entry & gEndOfChain) != gEndOfChain)
       
  1906         {
       
  1907         TInt next = GetFatEntry(entry, fatBuf.Ptr());
       
  1908         WriteFat(entry,0,fatBuf.Ptr());
       
  1909         entry = next;
       
  1910         }
       
  1911     if (last > 0)
       
  1912         WriteFat(last,0,fatBuf.Ptr());
       
  1913     r=TheFs.ScanDrive(gSessionPath);
       
  1914     test(r==KErrNone);
       
  1915     res=IsSameAsDrive(fatBuf,dirBuf);
       
  1916     test(res);
       
  1917 
       
  1918     // use last entry of first cluster in \scndrv\dir2\full\ 
       
  1919     test.Next(_L("Partial entry at end of subdir"));
       
  1920     r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny);
       
  1921     test(r==KErrNone);
       
  1922     temp.Close();
       
  1923     ReadDirDisk(dirBuf);
       
  1924     ReadFatDisk(fatBuf);
       
  1925     TEntryInfo partial3(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),2);
       
  1926     CreatePartialEntry(partial3,1,EFalse);
       
  1927     res=TestPartialEntry(partial3);
       
  1928     test(res);
       
  1929 
       
  1930     // use entry in \scndrv\dir2\almostfull\ 
       
  1931     test.Next(_L("Partial entry preceeding end-of-dir marker"));
       
  1932     last = GetStartCluster(gClusterDir2_AFull,14);
       
  1933     if (last > 0)
       
  1934         WriteFat(last,0,fatBuf.Ptr());
       
  1935     last = GetStartCluster(gClusterDir2_AFull,8);
       
  1936     if (last > 0)
       
  1937         WriteFat(last,0,fatBuf.Ptr());
       
  1938     WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_AFull,14));
       
  1939     WriteDirDisk(dirBuf);
       
  1940     TEntryInfo partial4(ClusterEntryToBytes(gClusterDir2_AFull,8),6);
       
  1941     CreatePartialEntry(partial4,4,EFalse);
       
  1942     res=TestPartialEntry(partial4);
       
  1943     test(res);
       
  1944 
       
  1945 	// NOTE:
       
  1946 	// Following test case is not valid anymore after fixing of
       
  1947 	//	PDEF128576: Unicode name file deleted after Scandrive
       
  1948 	// In the fixes, we decided to discard file name checking in ScanDrive,
       
  1949 	//	as it is impossible for ScanDrive to judge if the illegal byte is part of a legal
       
  1950 	//	DBCS charater.
       
  1951 
       
  1952 	// create entry in \scndrv\dir2\almostfull\ 
       
  1953 //	test.Next(_L("Partial entry with invalid dos name"));
       
  1954 //	r=temp.Create(TheFs,_L("\\scndrv\\dir2\\almostfull\\Dodgy file name"),EFileShareAny);
       
  1955 //	test(r==KErrNone);
       
  1956 //	temp.Close();
       
  1957 //	ReadDirDisk(dirBuf);
       
  1958 //	TInt dosStart=ClusterEntryToBytes(gClusterDir2_AFull,4);
       
  1959 //	dirBuf[dosStart+4]=0x1;
       
  1960 //	WriteDirDisk(dirBuf);
       
  1961 //	r=TheFs.ScanDrive(gSessionPath);
       
  1962 //	test(r==KErrNone);
       
  1963 //	WriteDelete(dosStart-2*32,3);
       
  1964 //	res=IsSameAsDrive(fatBuf,dirBuf);
       
  1965 //	test(res);
       
  1966 
       
  1967     if (BootSector.SectorsPerCluster() == 1)
       
  1968         {
       
  1969         // use entry created in \scndrv\dir2\ 
       
  1970         test.Next(_L("Partial entry spanning more than two clusters"));
       
  1971         last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-1);
       
  1972         WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2));
       
  1973         WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-1));
       
  1974         WriteDirDisk(dirBuf);
       
  1975         TFileName longFile=_L("\\scndrv\\dir2\\full\\");
       
  1976         MakeVeryLongName(longFile);
       
  1977         r=temp.Create(TheFs,longFile,EFileShareAny);
       
  1978         test(r==KErrNone);
       
  1979         temp.Close();
       
  1980         ReadDirDisk(dirBuf);
       
  1981         WriteFat(gClusterDir2_Full,gClusterDir2_SD3E,fatBuf.Ptr());
       
  1982         WriteFat(gClusterDir2_SD3E,gClusterDir2_SD23E,fatBuf.Ptr());
       
  1983         WriteFat(gClusterDir2_SD23E,gEndOfChain,fatBuf.Ptr());
       
  1984         if (last > 0)
       
  1985             WriteFat(last,0,fatBuf.Ptr());
       
  1986         TEntryInfo partial5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19);
       
  1987         CreatePartialEntry(partial5,7,EFalse);
       
  1988         res=TestPartialEntry(partial5);
       
  1989         test(res);
       
  1990         r=TheFs.Delete(longFile);
       
  1991         test(r==KErrNone || r==KErrNotFound);
       
  1992         r=TheFs.Delete(_L("\\temp"));
       
  1993         test(r==KErrNone || r==KErrNotFound);
       
  1994         }
       
  1995     ReadDirDisk(dirBuf);
       
  1996 
       
  1997     test.End();
       
  1998     }
       
  1999 
       
  2000 LOCAL_C void DoMatchingEntries()
       
  2001 //
       
  2002 // Tests that scandrive detects/corrects entries with the same start cluster
       
  2003 // Copies entry to new location - replicates start cluster
       
  2004 //
       
  2005     {
       
  2006     test.Next(_L("Check matching entries"));
       
  2007     TPtr8 fatBuf=FatBufPtr->Des();
       
  2008     TPtr8 dirBuf=DirBufPtr->Des();
       
  2009     ReadDirDisk(dirBuf);
       
  2010     ReadFatDisk(fatBuf);
       
  2011 
       
  2012     // first entry in \scndrv\almostfull\ + root dir
       
  2013     test.Start(_L("matching entries in subdir + root dir"));
       
  2014     TEntryInfo from1(ClusterEntryToBytes(gClusterDir2_AFull,2),6);
       
  2015     TEntryInfo to1(ClusterEntryToBytes(gClusterRootDir,2),6);
       
  2016     CreateMatchingEntry(to1,from1,EFalse);
       
  2017     TBool res=TestMatchingEntry(to1);
       
  2018     test(res);
       
  2019 
       
  2020     // matching entries between 2 subdirs, one which has a full cluster
       
  2021     // first entry in \scndrv\dir2\full\ + end of \scndrv\dir2\almostfull\ 
       
  2022     test.Next(_L("matching entries between 2 subdirs"));
       
  2023     TEntryInfo from2(ClusterEntryToBytes(gClusterDir2_Full,2),2);
       
  2024     TEntryInfo to2(ClusterEntryToBytes(gClusterDir2_AFull,14),2);
       
  2025     CreateMatchingEntry(to2,from2,EFalse);
       
  2026     res=TestMatchingEntry(to2);
       
  2027     test(res);
       
  2028 
       
  2029     // matching entries between two subdirs - one with end of dir marker next
       
  2030     // \scndrv\dir2\somedirwith3entries to \scndrv\ 
       
  2031     test.Next(_L("matching entries between two subdirs"));
       
  2032     TEntryInfo from3(ClusterEntryToBytes(gClusterDir2,4),3);
       
  2033     TEntryInfo to3(ClusterEntryToBytes(gClusterScnDrv,6),3);
       
  2034     CreateMatchingEntry(to3,from3,ETrue);
       
  2035     res=TestMatchingEntry(to3);
       
  2036     test(res);
       
  2037 
       
  2038     // matching entries in same subdir, one in new cluster - irrelevant if matching names
       
  2039     // 1st and last entries in \scndrv\dir2\full\ 
       
  2040     test.Next(_L("matching entries in same subdir"));
       
  2041     // delete entries to allow contiguous clusters in \scndrv\dir2\full directory
       
  2042     TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\"));
       
  2043     test(r==KErrNone);
       
  2044     r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\"));
       
  2045     test(r==KErrNone);
       
  2046     // ensure directory is expanded
       
  2047     RFile temp;
       
  2048     r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny);
       
  2049     test(r==KErrNone);
       
  2050     temp.Close();
       
  2051     r=TheFs.Delete(_L("\\scndrv\\dir2\\full\\temp"));
       
  2052     test(r==KErrNone);
       
  2053     ReadDirDisk(dirBuf);
       
  2054     ReadFatDisk(fatBuf);
       
  2055     TEntryInfo from4(ClusterEntryToBytes(gClusterDir2_Full,4),2);
       
  2056     TEntryInfo to4(ClusterEntryToBytes(gClusterDir2_Full+1,0),2);
       
  2057     CreateMatchingEntry(to4,from4,ETrue);
       
  2058     res=TestMatchingEntry(to4);
       
  2059     test(res);
       
  2060 
       
  2061     // \scndrv\dir1\very long name to \\scndrv\dir2\full\ 
       
  2062     test.Next(_L("matching entries in diff dirs + new cluster"));
       
  2063     // delete last entry in directory
       
  2064     r=TheFs.Delete(LastInFull);
       
  2065     test(r==KErrNone);
       
  2066     TFileName veryLongName=_L("\\scndrv\\dir2\\full\\");
       
  2067     MakeVeryLongName(veryLongName);
       
  2068     r=temp.Create(TheFs,veryLongName,EFileShareAny);
       
  2069     test(r==KErrNone);
       
  2070     temp.Close();
       
  2071     r=TheFs.Delete(veryLongName);
       
  2072     test(r==KErrNone);
       
  2073     ReadDirDisk(dirBuf);
       
  2074     ReadFatDisk(fatBuf);
       
  2075     TEntryInfo from5(ClusterEntryToBytes(gClusterDir1,2),19);
       
  2076     TEntryInfo to5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19);
       
  2077     CreateMatchingEntry(to5,from5,EFalse);
       
  2078     res=TestMatchingEntry(to5);
       
  2079     test(res);
       
  2080 
       
  2081     test.End();
       
  2082     }
       
  2083 
       
  2084 
       
  2085 LOCAL_C void DoMaxDepth()
       
  2086 //
       
  2087 // Test directory structure with max possible depth
       
  2088 //
       
  2089     {
       
  2090     test.Next(_L("Check max directory depth"));
       
  2091     test.Start(_L("Using single character names"));
       
  2092     TPtr8 fatBuf=FatBufPtr->Des();
       
  2093     TPtr8 dirBuf=DirBufPtr->Des();
       
  2094     // Create dir structure
       
  2095     TFileName dir1=_L("\\");
       
  2096     TFileName dir2;
       
  2097     CreateMaxDepthDir(dir1,dir2);
       
  2098     ReadDirDisk(dirBuf);
       
  2099     ReadFatDisk(fatBuf);
       
  2100     // run scandisk and compare
       
  2101     TInt r=TheFs.ScanDrive(gSessionPath);
       
  2102     test(r==KErrNone);
       
  2103     TBool res=IsSameAsDrive(fatBuf,dirBuf);
       
  2104     test(res);
       
  2105     // Create a entry with matching start cluster and check fixed up
       
  2106     TEntryInfo from(ClusterEntryToBytes(gClusterDir2_AFull,2),6);
       
  2107     TEntryInfo to(ClusterEntryToBytes(gClusterEndMaxDepth,2),6);
       
  2108     CreateMatchingEntry(to,from,ETrue);
       
  2109     res=TestMatchingEntry(to);
       
  2110     test(res);
       
  2111     // DeleteMaxDepthStructure
       
  2112     DeleteMaxDepthDir(dir1,dir2);
       
  2113     test.End();
       
  2114     }
       
  2115 
       
  2116 LOCAL_C void DoRootDir()
       
  2117 //
       
  2118 // Check that a full root directory is searched OK
       
  2119 //
       
  2120     {
       
  2121     test.Next(_L("Check a full root directory"));
       
  2122     FillUpRootDir();
       
  2123     TPtr8 fatBuf=FatBufPtr->Des();
       
  2124     TPtr8 dirBuf=DirBufPtr->Des();
       
  2125     ReadDirDisk(dirBuf);
       
  2126     ReadFatDisk(fatBuf);
       
  2127 
       
  2128     TInt r=TheFs.ScanDrive(gSessionPath);
       
  2129     test(r==KErrNone);
       
  2130 
       
  2131     TBool res=IsSameAsDrive(fatBuf,dirBuf);
       
  2132     test(res);
       
  2133     UnFillUpRootDir();
       
  2134     }
       
  2135 
       
  2136 LOCAL_C void TestNonVfatNames(const TPtrC& aDirName, TInt aDirCluster, TInt aEntry=2)
       
  2137 //
       
  2138 // Check that files without 'long' entries are kept intact.  Creates files with
       
  2139 // a DOS type name, and for each one created except the last deletes the VFAT
       
  2140 // entry by copying the DOS entry over it and writing end of directory.  This
       
  2141 // leaves a VFAT entry at the end of the directory, except when there is only
       
  2142 // room for one file.
       
  2143 //
       
  2144 // The layout, for 1 sector per cluster, is thus like:
       
  2145 //    0 .
       
  2146 //    1 ..
       
  2147 //    2 TEMPFILE.000
       
  2148 //    3 TEMPFILE.001
       
  2149 //      ...
       
  2150 //   14 tempfile.012 VFAT
       
  2151 //   15 TEMPFILE.012
       
  2152 //
       
  2153 // or for an almost full directory
       
  2154 //
       
  2155 //    0 .
       
  2156 //    1 ..
       
  2157 //      whatever...
       
  2158 //   14 TEMPFILE.000
       
  2159 //   15 end of directory
       
  2160 //
       
  2161     {
       
  2162     test.Printf(_L("Test cluster %2d, aEntry %d: %S\n"), aDirCluster, aEntry, &aDirName);
       
  2163     TPtr8 fatBuf=FatBufPtr->Des();
       
  2164     TPtr8 dirBuf=DirBufPtr->Des();
       
  2165     TInt cluster = aDirCluster;
       
  2166 
       
  2167     TInt maxEntry = gEntriesPerCluster;
       
  2168     if (aDirName.Compare(_L("\\")) == KErrNone)
       
  2169         maxEntry = Min(gRootDirEntries, gEntriesPerCluster);
       
  2170 
       
  2171     TInt entry = aEntry;
       
  2172     TInt r = KErrNone;
       
  2173     TInt i;
       
  2174 
       
  2175     while (entry > gEntriesPerCluster)
       
  2176         {
       
  2177         entry -= gEntriesPerCluster;
       
  2178         cluster++;
       
  2179         }
       
  2180 
       
  2181     TInt nFiles = maxEntry - entry - 1;
       
  2182     TInt startEntry = entry;
       
  2183 
       
  2184     test.Printf(_L("cluster %d, entry %d maxEntry %d, nFiles %d\n"), cluster, entry, maxEntry, nFiles);
       
  2185 
       
  2186     TBuf8<256> buf;
       
  2187     buf.Fill('*', 256);
       
  2188 
       
  2189     // Set up files, ignoring used slots
       
  2190     TInt filesThisTime = nFiles;
       
  2191     TInt totalFilesCreated = 0;
       
  2192     FOREVER
       
  2193         {
       
  2194         //
       
  2195         // Create a number of VFat entries
       
  2196         //
       
  2197         //  - We create as many as we can fit in the cluster in one go.
       
  2198         //    This is faster than creating a single entry then copying, as writing the
       
  2199         //    entries one at a time using RRawDisk causes a remount of the file system,
       
  2200         //    which can take a very long time on a large disk.
       
  2201         //
       
  2202         filesThisTime = (nFiles - totalFilesCreated) >> 1;
       
  2203         if(filesThisTime == 0)
       
  2204             {
       
  2205             if(nFiles == totalFilesCreated)
       
  2206                 {
       
  2207                 test.Printf(_L("Created all Non-VFAT entries\n"));
       
  2208                 break;
       
  2209                 }
       
  2210 
       
  2211             //...creating the final entry
       
  2212             filesThisTime = 1;
       
  2213             }
       
  2214 
       
  2215         for (i = 0; i < filesThisTime; i++)
       
  2216             {
       
  2217             TFileName name(aDirName);
       
  2218             name.Append(_L("tempfile."));
       
  2219             name.AppendNumFixedWidth(i+totalFilesCreated, EHex, 3);
       
  2220             RFile f;
       
  2221             r = f.Create(TheFs, name, EFileShareAny);
       
  2222             test(r == KErrNone);
       
  2223             r = f.Write(buf);
       
  2224             test(r == KErrNone);
       
  2225             f.Close();
       
  2226             }
       
  2227 
       
  2228         //
       
  2229         // Move DOS FAT entries up using RRawDisk, deleting the original VFAT entries
       
  2230         //
       
  2231         ReadDirDisk(dirBuf, cluster);
       
  2232         TInt dosEntry = entry + 1;
       
  2233         for (i = 0; i < filesThisTime; i++)
       
  2234             {
       
  2235             // Copy VFAT to Non-VFAT entries
       
  2236             if (entry+2 < maxEntry || nFiles < 2)
       
  2237                 {
       
  2238                 TInt posVFAT = ClusterEntryToBytes(cluster, entry);
       
  2239                 TInt posEOD = ClusterEntryToBytes(cluster, entry+1);
       
  2240                 TInt posDOS = ClusterEntryToBytes(cluster, dosEntry);
       
  2241 
       
  2242                 WriteCopyDir(posDOS, posVFAT);  // Copy the DOS entry
       
  2243                 WriteDelete(posDOS,2);          // Delete the original entry
       
  2244                 WriteEndOfDir(posEOD);          // Write End Of Directory
       
  2245 
       
  2246                 entry += 1;
       
  2247                 dosEntry += 2;
       
  2248                 }
       
  2249             else
       
  2250                 {
       
  2251                 // last entry has VFAT intact, to fill cluster
       
  2252                 entry += 2;
       
  2253                 }
       
  2254 
       
  2255             }
       
  2256 
       
  2257         WriteDirDisk(dirBuf, cluster);
       
  2258         totalFilesCreated += filesThisTime;
       
  2259         test.Printf(_L("   created %d entries\n"), totalFilesCreated);
       
  2260         }
       
  2261 
       
  2262     ReadDirDisk(dirBuf);
       
  2263     ReadFatDisk(fatBuf);
       
  2264 
       
  2265     DumpData(NULL, aDirCluster, cluster+1);
       
  2266 
       
  2267     test.Printf(_L("Running ScanDrive\n"), filesThisTime);
       
  2268     r=TheFs.ScanDrive(gSessionPath);
       
  2269     test(r==KErrNone);
       
  2270 
       
  2271     TBool res=IsSameAsDrive(fatBuf,dirBuf);
       
  2272     test(res);
       
  2273 
       
  2274     test.Printf(_L("Deleting %d files\n"), nFiles);
       
  2275     for (i = 0; i < nFiles; i++)
       
  2276         {
       
  2277         TFileName name(aDirName);
       
  2278         name.Append(_L("tempfile."));
       
  2279         name.AppendNumFixedWidth(i, EHex, 3);
       
  2280         r = TheFs.Delete(name);
       
  2281         test(r == KErrNone);
       
  2282         }
       
  2283 
       
  2284     ReadDirDisk(dirBuf);
       
  2285     ReadFatDisk(fatBuf);
       
  2286     WriteEndOfDir(ClusterEntryToBytes(cluster, startEntry));
       
  2287     WriteDirDisk(dirBuf);
       
  2288 
       
  2289     test.Printf(_L("Running ScanDrive\n"), filesThisTime);
       
  2290     r=TheFs.ScanDrive(gSessionPath);
       
  2291     test(r==KErrNone);
       
  2292     res=IsSameAsDrive(fatBuf,dirBuf);
       
  2293     test(res);
       
  2294     }
       
  2295 
       
  2296 LOCAL_C void DoNonVfatNames()
       
  2297 //
       
  2298 // Check that files without 'long' entries are kept intact
       
  2299 //
       
  2300     {
       
  2301     test.Next(_L("Check non-VFAT file names"));
       
  2302     TestNonVfatNames(_L("\\"), gClusterRootDir, 2);
       
  2303     TestNonVfatNames(_L("\\scndrv\\dir1\\"), gClusterDir1, 2+19);
       
  2304     TestNonVfatNames(_L("\\scndrv\\dir2\\somedirwith3entries\\"), gClusterDir2_SD3E, 2);
       
  2305     TestNonVfatNames(_L("\\scndrv\\dir2\\almostfull\\"), gClusterDir2_AFull, 14);
       
  2306     }
       
  2307 
       
  2308 
       
  2309 LOCAL_C void DoTests()
       
  2310     {
       
  2311 
       
  2312     Format();
       
  2313     DoReadBootSector();
       
  2314     DumpBootSector();
       
  2315     InitialiseBuffers();
       
  2316     CreateRootDir();
       
  2317     CreateDirectoryStructure();
       
  2318     TPtr8 fatBuf=FatBufPtr->Des();
       
  2319     TPtr8 dirBuf=DirBufPtr->Des();
       
  2320     ReadDirDisk(dirBuf);
       
  2321     ReadFatDisk(fatBuf);
       
  2322     DumpFat();
       
  2323     DumpData(NULL, DirBufPtr->Ptr());
       
  2324 
       
  2325     DoNonVfatNames();
       
  2326     DoRootDir();
       
  2327     DoMaxDepth();
       
  2328     DoMatchingEntries();
       
  2329     DoPartEntries();
       
  2330     DoLostClusters();
       
  2331     DoHangingClusters();
       
  2332     TestMountAndScan();
       
  2333     TestConsecutiveMountAndScans();
       
  2334     DeleteDirectoryStructure();
       
  2335     DeleteRootDir();
       
  2336     TestExtendedChars();
       
  2337 
       
  2338     DumpBootSector();
       
  2339     DumpFat();
       
  2340     DumpData(NULL, 0, 200);
       
  2341 
       
  2342     delete FatDiskPtr;
       
  2343     delete DirDiskPtr;
       
  2344     delete FatBufPtr;
       
  2345     delete DirBufPtr;
       
  2346     }
       
  2347 
       
  2348 
       
  2349 void CallTestsL()
       
  2350     {
       
  2351     TInt r;
       
  2352     r = TheFs.CharToDrive(gSessionPath[0], gDriveNumber);
       
  2353     test( KErrNone == r );
       
  2354 
       
  2355 
       
  2356     //-- set up console output
       
  2357     Fat_Test_Utils::SetConsole(test.Console());
       
  2358 
       
  2359     //-- print drive information
       
  2360     PrintDrvInfo(TheFs, gDriveNumber);
       
  2361 
       
  2362     if (!Is_Fat(TheFs, gDriveNumber))
       
  2363         {
       
  2364         test.Printf(_L("CallTestsL: Skipped: test requires FAT filesystem\n"));
       
  2365         return;
       
  2366         }
       
  2367 
       
  2368     // check this is not the internal ram drive
       
  2369     TVolumeInfo v;
       
  2370     r=TheFs.Volume(v);
       
  2371     test(r==KErrNone);
       
  2372     if(v.iDrive.iMediaAtt&KMediaAttVariableSize)
       
  2373         {
       
  2374         test.Printf(_L("Error: Internal ram drive not tested\n"));
       
  2375         return;
       
  2376         }
       
  2377 
       
  2378     r=TheFs.SetSessionPath(gSessionPath);
       
  2379     test(r==KErrNone);
       
  2380 
       
  2381     DoTests();
       
  2382 
       
  2383     return;
       
  2384     }
       
  2385 
       
  2386 
       
  2387 
       
  2388 
       
  2389 
       
  2390