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