os/kernelhwsrv/userlibandfileserver/fileserver/sfat/fat_table.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) 1996-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
// f32\sfat\fat_table.cpp
sl@0
    15
// FAT12/16 File Allocation Table classes implementation
sl@0
    16
// 
sl@0
    17
//
sl@0
    18
sl@0
    19
/**
sl@0
    20
 @file
sl@0
    21
 @internalTechnology
sl@0
    22
*/
sl@0
    23
sl@0
    24
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    25
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    26
//!!
sl@0
    27
//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
sl@0
    28
//!!
sl@0
    29
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    30
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    31
sl@0
    32
sl@0
    33
#include "sl_std.h"
sl@0
    34
#include "sl_fatcache.h"
sl@0
    35
#include "fat_table.h"
sl@0
    36
sl@0
    37
sl@0
    38
//#######################################################################################################################################
sl@0
    39
//#     CFatTable class implementation 
sl@0
    40
//#######################################################################################################################################
sl@0
    41
sl@0
    42
/**
sl@0
    43
    FAT object factory method.
sl@0
    44
    Constructs either CAtaFatTable or CRamFatTable depending on the media type parameter
sl@0
    45
sl@0
    46
    @param aOwner Pointer to the owning mount
sl@0
    47
    @param aLocDrvCaps local drive attributes
sl@0
    48
    @leave KErrNoMemory
sl@0
    49
    @return Pointer to the Fat table
sl@0
    50
*/
sl@0
    51
CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps)
sl@0
    52
    {
sl@0
    53
    CFatTable* pFatTable=NULL;
sl@0
    54
sl@0
    55
    
sl@0
    56
    switch(aLocDrvCaps.iType)
sl@0
    57
        {
sl@0
    58
        case EMediaRam:
sl@0
    59
            {//-- this is RAM media, try to create CRamFatTable instance.
sl@0
    60
            const TFatType fatType = aOwner.FatType();
sl@0
    61
            
sl@0
    62
            if(fatType != EFat16 )
sl@0
    63
                {//-- CRamFatTable doesn't support FAT12; FAT16 only.
sl@0
    64
                __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType);
sl@0
    65
                ASSERT(0);
sl@0
    66
                return NULL;
sl@0
    67
                }
sl@0
    68
            
sl@0
    69
                pFatTable = CRamFatTable::NewL(aOwner);            
sl@0
    70
            }
sl@0
    71
        break;
sl@0
    72
sl@0
    73
        default:
sl@0
    74
            //-- other media
sl@0
    75
            pFatTable = CAtaFatTable::NewL(aOwner);
sl@0
    76
        break;
sl@0
    77
        };
sl@0
    78
sl@0
    79
    return pFatTable;
sl@0
    80
    }
sl@0
    81
sl@0
    82
CFatTable::CFatTable(CFatMountCB& aOwner)
sl@0
    83
{
sl@0
    84
    iOwner = &aOwner;
sl@0
    85
    ASSERT(iOwner);
sl@0
    86
}
sl@0
    87
sl@0
    88
CFatTable::~CFatTable()
sl@0
    89
{
sl@0
    90
    //-- destroy cache ignoring dirty data in cache
sl@0
    91
    //-- the destructor isn't an appropriate place to flush the data.
sl@0
    92
    Dismount(ETrue); 
sl@0
    93
}
sl@0
    94
sl@0
    95
//-----------------------------------------------------------------------------
sl@0
    96
sl@0
    97
/**
sl@0
    98
    Initialise the object, get data from the owning CFatMountCB
sl@0
    99
*/
sl@0
   100
void CFatTable::InitializeL()
sl@0
   101
    {
sl@0
   102
    ASSERT(iOwner);
sl@0
   103
sl@0
   104
    //-- get FAT type from the owner
sl@0
   105
    iFatType = iOwner->FatType();
sl@0
   106
    ASSERT(IsFat12() || IsFat16());
sl@0
   107
sl@0
   108
    iFreeClusterHint = KFatFirstSearchCluster;
sl@0
   109
sl@0
   110
    //-- cache the media attributes
sl@0
   111
    TLocalDriveCapsV2 caps;
sl@0
   112
    TPckg<TLocalDriveCapsV2> capsPckg(caps);
sl@0
   113
    User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
sl@0
   114
    iMediaAtt = caps.iMediaAtt;
sl@0
   115
    
sl@0
   116
    //-- obtain maximal number of entries in the table
sl@0
   117
    iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use
sl@0
   118
sl@0
   119
    __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries);
sl@0
   120
    }
sl@0
   121
sl@0
   122
//-----------------------------------------------------------------------------
sl@0
   123
sl@0
   124
/** 
sl@0
   125
    Decrements the free cluster count.
sl@0
   126
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   127
    cluster of a large file. Use more than one cluster granularity.
sl@0
   128
     
sl@0
   129
    @param  aCount a number of clusters 
sl@0
   130
*/
sl@0
   131
void CFatTable::DecrementFreeClusterCount(TUint32 aCount)
sl@0
   132
{
sl@0
   133
    __ASSERT_DEBUG(iFreeClusters >= aCount, Fault(EFatCorrupt));
sl@0
   134
    iFreeClusters -= aCount;
sl@0
   135
}
sl@0
   136
sl@0
   137
/** 
sl@0
   138
    Increments the free cluster count.
sl@0
   139
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   140
    cluster of a large file. Use more than one cluster granularity.
sl@0
   141
sl@0
   142
    @param  aCount a number of clusters 
sl@0
   143
*/
sl@0
   144
void CFatTable::IncrementFreeClusterCount(TUint32 aCount)
sl@0
   145
{
sl@0
   146
    const TUint32 newVal = iFreeClusters+aCount;
sl@0
   147
    __ASSERT_DEBUG(newVal<=MaxEntries(), Fault(EFatCorrupt));
sl@0
   148
    
sl@0
   149
    iFreeClusters = newVal;
sl@0
   150
}
sl@0
   151
sl@0
   152
/** @return number of free clusters in the FAT */
sl@0
   153
TUint32 CFatTable::NumberOfFreeClusters(TBool /*aSyncOperation=EFalse*/) const
sl@0
   154
{
sl@0
   155
    return FreeClusters();
sl@0
   156
}
sl@0
   157
sl@0
   158
void CFatTable::SetFreeClusters(TUint32 aFreeClusters)
sl@0
   159
{   
sl@0
   160
    iFreeClusters=aFreeClusters;
sl@0
   161
}
sl@0
   162
sl@0
   163
/**
sl@0
   164
    Get the hint about the last known free cluster number.
sl@0
   165
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   166
    cluster of a large file.
sl@0
   167
sl@0
   168
    @return cluster number supposedly close to the free one.
sl@0
   169
*/
sl@0
   170
TUint32 CFatTable::FreeClusterHint() const 
sl@0
   171
{
sl@0
   172
    ASSERT(ClusterNumberValid(iFreeClusterHint));
sl@0
   173
    return iFreeClusterHint;
sl@0
   174
} 
sl@0
   175
sl@0
   176
/**
sl@0
   177
    Set a free cluster hint. The next search fro the free cluster can start from this value.
sl@0
   178
    aCluster doesn't have to be a precise number of free FAT entry; it just needs to be as close as possible to the 
sl@0
   179
    free entries chain.
sl@0
   180
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   181
    cluster of a large file.
sl@0
   182
sl@0
   183
    @param aCluster cluster number hint.
sl@0
   184
*/
sl@0
   185
void CFatTable::SetFreeClusterHint(TUint32 aCluster) 
sl@0
   186
{
sl@0
   187
    ASSERT(ClusterNumberValid(aCluster));
sl@0
   188
    iFreeClusterHint=aCluster;
sl@0
   189
} 
sl@0
   190
sl@0
   191
//-----------------------------------------------------------------------------
sl@0
   192
sl@0
   193
/**
sl@0
   194
    Find out the number of free clusters on the volume.
sl@0
   195
    Reads whole FAT and counts free clusters.
sl@0
   196
*/
sl@0
   197
void CFatTable::CountFreeClustersL()
sl@0
   198
{
sl@0
   199
    __PRINT1(_L("#- CFatTable::CountFreeClustersL(), drv:%d"), iOwner->DriveNumber());
sl@0
   200
sl@0
   201
    const TUint32 KUsableClusters = iOwner->UsableClusters();
sl@0
   202
    (void)KUsableClusters;
sl@0
   203
    
sl@0
   204
    TUint32 freeClusters = 0;
sl@0
   205
    TUint32 firstFreeCluster = 0;
sl@0
   206
sl@0
   207
    TTime   timeStart;
sl@0
   208
    TTime   timeEnd;
sl@0
   209
    timeStart.UniversalTime(); //-- take start time
sl@0
   210
sl@0
   211
    //-- walk through whole FAT table looking for free clusters
sl@0
   212
    for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i)
sl@0
   213
    {
sl@0
   214
        if(ReadL(i) == KSpareCluster)
sl@0
   215
        {//-- found a free cluster
sl@0
   216
            ++freeClusters;
sl@0
   217
            
sl@0
   218
            if(!firstFreeCluster)
sl@0
   219
                firstFreeCluster = i;
sl@0
   220
        }
sl@0
   221
    }
sl@0
   222
sl@0
   223
    timeEnd.UniversalTime(); //-- take end time
sl@0
   224
    const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
sl@0
   225
    __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime);
sl@0
   226
    (void)msScanTime;
sl@0
   227
sl@0
   228
    if(!firstFreeCluster) //-- haven't found free clusters on the volume
sl@0
   229
        firstFreeCluster = KFatFirstSearchCluster;
sl@0
   230
sl@0
   231
    ASSERT(freeClusters <= KUsableClusters);
sl@0
   232
sl@0
   233
    SetFreeClusters(freeClusters);
sl@0
   234
    SetFreeClusterHint(firstFreeCluster);
sl@0
   235
}
sl@0
   236
sl@0
   237
//-----------------------------------------------------------------------------
sl@0
   238
sl@0
   239
/**
sl@0
   240
Count the number of contiguous cluster from a start cluster
sl@0
   241
sl@0
   242
@param aStartCluster cluster to start counting from
sl@0
   243
@param anEndCluster contains the end cluster number upon return
sl@0
   244
@param aMaxCount Maximum cluster required
sl@0
   245
@leave System wide error values
sl@0
   246
@return Number of contiguous clusters from aStartCluster.
sl@0
   247
*/
sl@0
   248
TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const
sl@0
   249
    {
sl@0
   250
    __PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount);
sl@0
   251
    TUint32 clusterListLen=1;
sl@0
   252
    TInt endCluster=aStartCluster;
sl@0
   253
    TInt64 endClusterPos=DataPositionInBytes(endCluster);
sl@0
   254
    while (clusterListLen<aMaxCount)
sl@0
   255
        {
sl@0
   256
        TInt oldCluster=endCluster;
sl@0
   257
        TInt64 oldClusterPos=endClusterPos;
sl@0
   258
        if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
sl@0
   259
            {
sl@0
   260
            endCluster=oldCluster;
sl@0
   261
            break;
sl@0
   262
            }
sl@0
   263
        clusterListLen++;
sl@0
   264
        }
sl@0
   265
    anEndCluster=endCluster;
sl@0
   266
    return(clusterListLen);
sl@0
   267
    }   
sl@0
   268
sl@0
   269
//-----------------------------------------------------------------------------
sl@0
   270
sl@0
   271
/**
sl@0
   272
    Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full).
sl@0
   273
sl@0
   274
    @param aNumber  amount of clusters to allocate
sl@0
   275
    @param aCluster FAT entry index to start with.
sl@0
   276
sl@0
   277
    @leave KErrDiskFull + system wide error codes
sl@0
   278
*/
sl@0
   279
void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
sl@0
   280
    {
sl@0
   281
    __PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster);
sl@0
   282
    __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
sl@0
   283
    
sl@0
   284
    while(aNumber && GetNextClusterL(aCluster))
sl@0
   285
        aNumber--;
sl@0
   286
sl@0
   287
    if(!aNumber)
sl@0
   288
        return;
sl@0
   289
sl@0
   290
    if (iFreeClusters<aNumber)
sl@0
   291
        {
sl@0
   292
        __PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull"));
sl@0
   293
        User::Leave(KErrDiskFull);
sl@0
   294
        }
sl@0
   295
sl@0
   296
sl@0
   297
    TUint32 freeCluster = 0;
sl@0
   298
    
sl@0
   299
    //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL()
sl@0
   300
    for(TUint i=0; i<aNumber; ++i)
sl@0
   301
        {
sl@0
   302
        freeCluster = FindClosestFreeClusterL(aCluster);
sl@0
   303
        WriteFatEntryEofL(freeCluster); //  Must write EOF for FindClosestFreeCluster to work again
sl@0
   304
        WriteL(aCluster,freeCluster);
sl@0
   305
        aCluster=freeCluster;
sl@0
   306
        }
sl@0
   307
    
sl@0
   308
    //-- decrement number of available clusters
sl@0
   309
    DecrementFreeClusterCount(aNumber);
sl@0
   310
sl@0
   311
    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from
sl@0
   312
    SetFreeClusterHint(aCluster); 
sl@0
   313
    
sl@0
   314
    }
sl@0
   315
sl@0
   316
//-----------------------------------------------------------------------------
sl@0
   317
sl@0
   318
/**
sl@0
   319
Allocate and mark as EOF a single cluster as close as possible to aNearestCluster
sl@0
   320
sl@0
   321
@param aNearestCluster Cluster the new cluster should be nearest to
sl@0
   322
@leave System wide error codes
sl@0
   323
@return The cluster number allocated
sl@0
   324
*/
sl@0
   325
TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
sl@0
   326
    {
sl@0
   327
    __PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster);
sl@0
   328
    if (iFreeClusters==0)
sl@0
   329
        User::Leave(KErrDiskFull);
sl@0
   330
    const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster);
sl@0
   331
    WriteFatEntryEofL(freeCluster);
sl@0
   332
    DecrementFreeClusterCount(1);
sl@0
   333
sl@0
   334
    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from.
sl@0
   335
    SetFreeClusterHint(freeCluster); 
sl@0
   336
sl@0
   337
    return(freeCluster);
sl@0
   338
    }   
sl@0
   339
sl@0
   340
//-----------------------------------------------------------------------------
sl@0
   341
sl@0
   342
/**
sl@0
   343
Allocate and link a cluster chain, leaves if there are not enough free clusters.
sl@0
   344
Chain starts as close as possible to aNearestCluster, last cluster will be marked as EOF.
sl@0
   345
sl@0
   346
@param aNumber Number of clusters to allocate
sl@0
   347
@param aNearestCluster Cluster the new chain should be nearest to
sl@0
   348
@leave System wide error codes
sl@0
   349
@return The first cluster number allocated
sl@0
   350
*/
sl@0
   351
TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster)
sl@0
   352
    {
sl@0
   353
    __PRINT2(_L("#>> CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster);
sl@0
   354
    __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
sl@0
   355
sl@0
   356
    if (iFreeClusters<aNumber)
sl@0
   357
        {
sl@0
   358
        __PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull"));
sl@0
   359
        User::Leave(KErrDiskFull);
sl@0
   360
        }
sl@0
   361
sl@0
   362
    TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster);
sl@0
   363
    if (aNumber>1)
sl@0
   364
        ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster);
sl@0
   365
sl@0
   366
    return(firstCluster);
sl@0
   367
    }   
sl@0
   368
sl@0
   369
//-----------------------------------------------------------------------------
sl@0
   370
sl@0
   371
/**
sl@0
   372
    Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported.
sl@0
   373
    @param aFreedClusters array with FAT numbers of clusters that shall be marked as "deleted"
sl@0
   374
*/
sl@0
   375
void CFatTable::DoFreedClustersNotify(RClusterArray &aFreedClusters)
sl@0
   376
{
sl@0
   377
    ASSERT(iMediaAtt & KMediaAttDeleteNotify);
sl@0
   378
sl@0
   379
    const TUint clusterCount = aFreedClusters.Count();
sl@0
   380
sl@0
   381
    if(!clusterCount)
sl@0
   382
        return;
sl@0
   383
    
sl@0
   384
    FlushL(); //-- Commit the FAT changes to disk first to be safe
sl@0
   385
sl@0
   386
    const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2();
sl@0
   387
sl@0
   388
    TInt64  byteAddress = 0;    
sl@0
   389
    TUint   deleteLen = 0;  // zero indicates no clusters accumulated yet
sl@0
   390
sl@0
   391
    for (TUint i=0; i<clusterCount; ++i)
sl@0
   392
    {
sl@0
   393
        const TUint currCluster = aFreedClusters[i];
sl@0
   394
        
sl@0
   395
        if (deleteLen == 0)
sl@0
   396
            byteAddress = DataPositionInBytes(currCluster); //-- start of the media range
sl@0
   397
        
sl@0
   398
        deleteLen += bytesPerCluster;
sl@0
   399
sl@0
   400
        //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver
sl@0
   401
        if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1))
sl@0
   402
        {
sl@0
   403
            //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen);
sl@0
   404
            //__PRINT2(_L("   first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster);
sl@0
   405
            const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen);
sl@0
   406
            if(r != KErrNone)
sl@0
   407
                {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; 
sl@0
   408
                 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media.
sl@0
   409
                const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement);
sl@0
   410
                __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
sl@0
   411
sl@0
   412
                if(platSecEnabled)
sl@0
   413
                    {
sl@0
   414
                    //-- if PlatSec is enabled, we can't afford jeopardize the security; without DeleteNotify()
sl@0
   415
                    //-- it's possible to pick up data from deleted files, so, panic the file server.
sl@0
   416
                    Fault(EFatBadLocalDrive);
sl@0
   417
                    }
sl@0
   418
                else
sl@0
   419
                    {
sl@0
   420
                    //-- if PlatSec is disabled, it's OK to ignore the NAND fault in release mode.
sl@0
   421
                    __ASSERT_DEBUG(0, Fault(EFatBadLocalDrive));
sl@0
   422
                    }        
sl@0
   423
                }
sl@0
   424
            
sl@0
   425
            
sl@0
   426
            deleteLen = 0;
sl@0
   427
        }
sl@0
   428
sl@0
   429
    }
sl@0
   430
sl@0
   431
    //-- empty the array.
sl@0
   432
    aFreedClusters.Reset();
sl@0
   433
}
sl@0
   434
sl@0
   435
//-----------------------------------------------------------------------------
sl@0
   436
/**
sl@0
   437
Mark a chain of clusters as free in the FAT. 
sl@0
   438
sl@0
   439
@param aCluster Start cluster of cluster chain to free
sl@0
   440
@leave System wide error codes
sl@0
   441
*/
sl@0
   442
void CFatTable::FreeClusterListL(TUint32 aCluster)
sl@0
   443
    {
sl@0
   444
    __PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster);
sl@0
   445
    if (aCluster == KSpareCluster)
sl@0
   446
        return; 
sl@0
   447
sl@0
   448
    //-- here we can store array of freed cluster numbers in order to 
sl@0
   449
    //-- notify media drive about the media addresses marked as "invalid"
sl@0
   450
    RClusterArray deletedClusters;      
sl@0
   451
    CleanupClosePushL(deletedClusters);
sl@0
   452
sl@0
   453
    //-- if ETrue, we need to notify media driver about invalidated media addressses
sl@0
   454
    const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify;
sl@0
   455
sl@0
   456
    //-- this is a maximal number of FAT entries in the deletedClusters array.
sl@0
   457
    //-- as soon as we collect this number of entries in the array, FAT cache will be flushed
sl@0
   458
    //-- and driver notified. The array will be emptied. Used to avoid huge array when deleting
sl@0
   459
    //--  large files on NAND media 
sl@0
   460
    const TUint KSubListLen = 4096;
sl@0
   461
    ASSERT(IsPowerOf2(KSubListLen));
sl@0
   462
sl@0
   463
    TUint32 lastKnownFreeCluster = FreeClusterHint();
sl@0
   464
    TUint32 cntFreedClusters = 0;
sl@0
   465
sl@0
   466
    TUint32 currCluster = aCluster;
sl@0
   467
    TInt    nextCluster = aCluster;
sl@0
   468
sl@0
   469
    for(;;)
sl@0
   470
        {
sl@0
   471
        const TBool bEOF = !GetNextClusterL(nextCluster);    
sl@0
   472
        WriteL(currCluster, KSpareCluster);
sl@0
   473
sl@0
   474
        lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster);
sl@0
   475
sl@0
   476
        // Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe 
sl@0
   477
        // to do once the FAT changes have been written to disk.
sl@0
   478
        if(bFreeClustersNotify)
sl@0
   479
            deletedClusters.Append(currCluster);
sl@0
   480
sl@0
   481
        ++cntFreedClusters;
sl@0
   482
        currCluster = nextCluster;
sl@0
   483
sl@0
   484
        if (bEOF || aCluster == KSpareCluster)
sl@0
   485
            break;
sl@0
   486
sl@0
   487
        if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0)
sl@0
   488
        {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array.
sl@0
   489
            IncrementFreeClusterCount(cntFreedClusters);
sl@0
   490
            cntFreedClusters = 0;
sl@0
   491
sl@0
   492
            SetFreeClusterHint(lastKnownFreeCluster);
sl@0
   493
            DoFreedClustersNotify(deletedClusters);
sl@0
   494
        }
sl@0
   495
sl@0
   496
    }
sl@0
   497
sl@0
   498
    //-- increase the number of free clusters and notify the driver if required.
sl@0
   499
    IncrementFreeClusterCount(cntFreedClusters);
sl@0
   500
    SetFreeClusterHint(lastKnownFreeCluster);
sl@0
   501
    
sl@0
   502
    if(bFreeClustersNotify)
sl@0
   503
    DoFreedClustersNotify(deletedClusters);
sl@0
   504
sl@0
   505
    CleanupStack::PopAndDestroy(&deletedClusters);
sl@0
   506
    }
sl@0
   507
sl@0
   508
//-----------------------------------------------------------------------------
sl@0
   509
sl@0
   510
/**
sl@0
   511
Find a free cluster nearest to aCluster, Always checks to the right of aCluster first 
sl@0
   512
but checks in both directions in the Fat.
sl@0
   513
sl@0
   514
@param aCluster Cluster to find nearest free cluster to.
sl@0
   515
@leave KErrDiskFull + system wide error codes
sl@0
   516
@return cluster number found
sl@0
   517
*/
sl@0
   518
TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster)
sl@0
   519
    {
sl@0
   520
    __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
sl@0
   521
sl@0
   522
    if(!ClusterNumberValid(aCluster))
sl@0
   523
        {
sl@0
   524
        ASSERT(0);
sl@0
   525
        User::Leave(KErrCorrupt);
sl@0
   526
        }
sl@0
   527
sl@0
   528
sl@0
   529
    if(iFreeClusters==0)
sl@0
   530
        {//-- there is no at least 1 free cluster available
sl@0
   531
        __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
sl@0
   532
        User::Leave(KErrDiskFull);
sl@0
   533
        }
sl@0
   534
    
sl@0
   535
    //-- 1. look if the given index contains a free entry 
sl@0
   536
    if(ReadL(aCluster) != KSpareCluster)
sl@0
   537
        {//-- no, it doesn't...
sl@0
   538
        
sl@0
   539
        //-- 2. look in both directions starting from the aCluster, looking in the right direction first
sl@0
   540
        
sl@0
   541
        const TUint32 maxEntries = MaxEntries();
sl@0
   542
        const TUint32 MinIdx = KFatFirstSearchCluster;
sl@0
   543
        const TUint32 MaxIdx = maxEntries-1; 
sl@0
   544
sl@0
   545
        TBool canGoRight = ETrue;
sl@0
   546
        TBool canGoLeft = ETrue;
sl@0
   547
    
sl@0
   548
        TUint32 rightIdx = aCluster;
sl@0
   549
        TUint32 leftIdx  = aCluster;
sl@0
   550
        
sl@0
   551
        for(TUint i=0; i<maxEntries; ++i)
sl@0
   552
            {
sl@0
   553
            if(canGoRight)
sl@0
   554
                {
sl@0
   555
                if(rightIdx < MaxIdx)
sl@0
   556
                    ++rightIdx;
sl@0
   557
                else
sl@0
   558
                    canGoRight = EFalse;
sl@0
   559
                }
sl@0
   560
sl@0
   561
            if(canGoLeft)
sl@0
   562
                {
sl@0
   563
                if(leftIdx > MinIdx)
sl@0
   564
                    --leftIdx;
sl@0
   565
                else        
sl@0
   566
                    canGoLeft = EFalse;
sl@0
   567
                }
sl@0
   568
sl@0
   569
        if(!canGoRight && !canGoLeft)
sl@0
   570
            {
sl@0
   571
            __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2"));
sl@0
   572
            User::Leave(KErrDiskFull);
sl@0
   573
            }
sl@0
   574
sl@0
   575
        if (canGoRight && ReadL(rightIdx) == KSpareCluster)
sl@0
   576
            {
sl@0
   577
            aCluster = rightIdx;
sl@0
   578
            break;
sl@0
   579
            }
sl@0
   580
sl@0
   581
        if (canGoLeft && ReadL(leftIdx) == KSpareCluster)
sl@0
   582
            {
sl@0
   583
            aCluster = leftIdx;
sl@0
   584
            break;
sl@0
   585
            }
sl@0
   586
            }//for(..)
sl@0
   587
sl@0
   588
        }//if(ReadL(aCluster) != KSpareCluster)
sl@0
   589
sl@0
   590
sl@0
   591
    //-- note: do not update free cluster hint here by calling SetFreeClusterHint(). This is going to be 
sl@0
   592
    //-- expensive especially if overridden methods with synchronisation are called. Instead, set the number of 
sl@0
   593
    //-- the last known free cluster in the caller of this internal method.
sl@0
   594
sl@0
   595
//    __PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster);
sl@0
   596
sl@0
   597
    return aCluster;
sl@0
   598
    }
sl@0
   599
sl@0
   600
//-----------------------------------------------------------------------------
sl@0
   601
sl@0
   602
/**
sl@0
   603
    Converts a cluster number to byte offset in the FAT
sl@0
   604
sl@0
   605
@param aFatIndex Cluster number
sl@0
   606
    @return Number of bytes from the beginning of the FAT
sl@0
   607
*/
sl@0
   608
TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const
sl@0
   609
    {
sl@0
   610
    switch(FatType())
sl@0
   611
        {
sl@0
   612
        case EFat12:
sl@0
   613
            return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry
sl@0
   614
sl@0
   615
        case EFat16:
sl@0
   616
            return aFatIndex<<1; //-- 2 bytes per FAT entry
sl@0
   617
sl@0
   618
        default:
sl@0
   619
            ASSERT(0);
sl@0
   620
            return 0;//-- get rid of warning
sl@0
   621
        };
sl@0
   622
sl@0
   623
    }
sl@0
   624
sl@0
   625
//-----------------------------------------------------------------------------
sl@0
   626
sl@0
   627
/**
sl@0
   628
    Checks if we have at least aClustersRequired clusters free in the FAT.
sl@0
   629
    This is, actually a dummy implementation.
sl@0
   630
sl@0
   631
    @param  aClustersRequired number of free clusters required
sl@0
   632
    @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
sl@0
   633
*/
sl@0
   634
TBool CFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
sl@0
   635
{
sl@0
   636
    //ASSERT(aClustersRequired >0 && aClustersRequired <= iOwner->UsableClusters());
sl@0
   637
    ASSERT(aClustersRequired >0);
sl@0
   638
    return (NumberOfFreeClusters() >= aClustersRequired);
sl@0
   639
}
sl@0
   640
sl@0
   641
//-----------------------------------------------------------------------------
sl@0
   642
/**
sl@0
   643
    @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
sl@0
   644
*/
sl@0
   645
TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const 
sl@0
   646
    {
sl@0
   647
    return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries); 
sl@0
   648
    }
sl@0
   649
sl@0
   650
sl@0
   651
sl@0
   652
//#######################################################################################################################################
sl@0
   653
//#     CAtaFatTable class implementation 
sl@0
   654
//#######################################################################################################################################
sl@0
   655
sl@0
   656
/**
sl@0
   657
Constructor
sl@0
   658
*/
sl@0
   659
CAtaFatTable::CAtaFatTable(CFatMountCB& aOwner)
sl@0
   660
             :CFatTable(aOwner)
sl@0
   661
    {
sl@0
   662
    }
sl@0
   663
sl@0
   664
sl@0
   665
/** factory method */
sl@0
   666
CAtaFatTable* CAtaFatTable::NewL(CFatMountCB& aOwner)
sl@0
   667
{
sl@0
   668
    __PRINT1(_L("CAtaFatTable::NewL() drv:%d"),aOwner.DriveNumber());
sl@0
   669
    CAtaFatTable* pSelf = new (ELeave) CAtaFatTable(aOwner);
sl@0
   670
sl@0
   671
    CleanupStack::PushL(pSelf);
sl@0
   672
    pSelf->InitializeL();
sl@0
   673
    CleanupStack::Pop();
sl@0
   674
sl@0
   675
    return pSelf;
sl@0
   676
}
sl@0
   677
sl@0
   678
sl@0
   679
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   680
sl@0
   681
/**
sl@0
   682
    CAtaFatTable's FAT cache factory method.
sl@0
   683
    Creates fixed cache for FAT12 or FAT16
sl@0
   684
*/
sl@0
   685
void CAtaFatTable::CreateCacheL()
sl@0
   686
{
sl@0
   687
    ASSERT(iOwner);
sl@0
   688
    const TUint32 fatSize=iOwner->FatSizeInBytes();
sl@0
   689
    __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize);
sl@0
   690
    
sl@0
   691
sl@0
   692
    //-- according to FAT specs:
sl@0
   693
    //-- FAT12 max size is 4084 entries or 6126 bytes                                               => create fixed cache for whole FAT
sl@0
   694
    //-- FAT16 min size is 4085 entries or 8170 bytes, max size is 65525 entries or 131048 bytes    => create fixed cache for whole FAT
sl@0
   695
sl@0
   696
    ASSERT(!iCache);
sl@0
   697
sl@0
   698
    //-- this is used for chaches granularity sanity check 
sl@0
   699
    const TUint32 KMaxGranularityLog2 = 18; //-- 256K is a maximal allowed granularity
sl@0
   700
    const TUint32 KMinGranularityLog2 = KDefSectorSzLog2;  //-- 512 bytes is a minimal allowed granularity
sl@0
   701
sl@0
   702
    switch(FatType())
sl@0
   703
    {
sl@0
   704
        case EFat12: //-- create fixed FAT12 cache
sl@0
   705
            iCache = CFat12Cache::NewL(iOwner, fatSize); 
sl@0
   706
        break;
sl@0
   707
    
sl@0
   708
        case EFat16: //-- create fixed FAT16 cache
sl@0
   709
        {
sl@0
   710
            TUint32 fat16_ReadGranularity_Log2; //-- FAT16 cache read granularity Log2
sl@0
   711
            TUint32 fat16_WriteGranularity_Log2;//-- FAT16 cache write granularity Log2
sl@0
   712
            
sl@0
   713
            iOwner->FatConfig().Fat16FixedCacheParams(fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2);
sl@0
   714
            
sl@0
   715
            //-- check if granularity values look sensible
sl@0
   716
            const TBool bParamsValid = fat16_ReadGranularity_Log2  >= KMinGranularityLog2 && fat16_ReadGranularity_Log2  <= KMaxGranularityLog2 &&
sl@0
   717
                                       fat16_WriteGranularity_Log2 >= KMinGranularityLog2 && fat16_WriteGranularity_Log2 <= KMaxGranularityLog2;
sl@0
   718
            
sl@0
   719
            __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity)); 
sl@0
   720
sl@0
   721
        
sl@0
   722
            iCache = CFat16FixedCache::NewL(iOwner, fatSize, fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2); 
sl@0
   723
        }
sl@0
   724
        break;
sl@0
   725
sl@0
   726
        default:
sl@0
   727
        ASSERT(0);
sl@0
   728
        User::Leave(KErrCorrupt);
sl@0
   729
        break;
sl@0
   730
    };
sl@0
   731
sl@0
   732
    ASSERT(iCache);
sl@0
   733
}
sl@0
   734
sl@0
   735
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   736
sl@0
   737
sl@0
   738
/**
sl@0
   739
    Flush the FAT cache on disk
sl@0
   740
@leave System wide error codes
sl@0
   741
*/
sl@0
   742
void CAtaFatTable::FlushL()
sl@0
   743
    {
sl@0
   744
    //-- the data can't be written if the mount is inconsistent
sl@0
   745
    iOwner->CheckStateConsistentL();
sl@0
   746
sl@0
   747
    if (iCache)
sl@0
   748
        iCache->FlushL();
sl@0
   749
    }
sl@0
   750
sl@0
   751
/**
sl@0
   752
Clear any cached data
sl@0
   753
    @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded.
sl@0
   754
*/
sl@0
   755
void CAtaFatTable::Dismount(TBool aDiscardDirtyData)
sl@0
   756
    {
sl@0
   757
    if (iCache)
sl@0
   758
        {
sl@0
   759
        //-- cache's Close() can check if the cache is clean. 
sl@0
   760
        //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data)
sl@0
   761
        //-- or if we are asked to do so.
sl@0
   762
        const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState();
sl@0
   763
        iCache->Close(bIgnoreDirtyData);
sl@0
   764
sl@0
   765
        delete iCache;
sl@0
   766
        iCache=NULL;
sl@0
   767
        }
sl@0
   768
sl@0
   769
    }
sl@0
   770
sl@0
   771
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   772
sl@0
   773
/**
sl@0
   774
    Invalidate whole FAT cache.
sl@0
   775
    Depending of cache type this may just mark cache invalid with reading on demand or re-read whole cache from the media
sl@0
   776
*/
sl@0
   777
void CAtaFatTable::InvalidateCacheL()
sl@0
   778
{
sl@0
   779
    __PRINT1(_L("CAtaFatTable::InvalidateCache(), drv:%d"), iOwner->DriveNumber());
sl@0
   780
sl@0
   781
    //-- if we have a cache, invalidate it entirely
sl@0
   782
    if(iCache)
sl@0
   783
    {
sl@0
   784
        User::LeaveIfError(iCache->Invalidate());
sl@0
   785
    }
sl@0
   786
}
sl@0
   787
sl@0
   788
sl@0
   789
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   790
sl@0
   791
/**
sl@0
   792
    Invalidate specified region of the FAT cache
sl@0
   793
    Depending of cache type this may just mark part of the cache invalid with reading on demand later
sl@0
   794
    or re-read whole cache from the media.
sl@0
   795
sl@0
   796
    @param aPos absolute media position where the region being invalidated starts.
sl@0
   797
    @param aLength length in bytes of region to invalidate / refresh
sl@0
   798
*/
sl@0
   799
void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength)
sl@0
   800
    {
sl@0
   801
    __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength);
sl@0
   802
sl@0
   803
    if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength))
sl@0
   804
        return; //-- FAT tables can't span over 4G 
sl@0
   805
sl@0
   806
    const TUint32 mediaPos32 = I64LOW(aPos);
sl@0
   807
sl@0
   808
    //-- we do not use other copies of FAT, so trach changes only in FAT1
sl@0
   809
    const TUint32 fat1StartPos = iOwner->StartOfFatInBytes();
sl@0
   810
    const TUint32 fat1EndPos   = fat1StartPos + iOwner->FatSizeInBytes();
sl@0
   811
sl@0
   812
    TUint32 invRegionPosStart = 0; //-- media pos where the invalidated region starts
sl@0
   813
    TUint32 invRegionLen = 0;      //-- size of the invalidated region, bytes
sl@0
   814
    
sl@0
   815
    //-- calculate the FAT1 region being invalidated
sl@0
   816
    if(mediaPos32 < fat1StartPos)
sl@0
   817
    {
sl@0
   818
        if((mediaPos32 + aLength) <= fat1StartPos)
sl@0
   819
            return;
sl@0
   820
sl@0
   821
        invRegionPosStart = fat1StartPos;
sl@0
   822
        invRegionLen = aLength - (fat1StartPos-mediaPos32);
sl@0
   823
    }
sl@0
   824
    else //if(mediaPos32 < fat1StartPos)
sl@0
   825
    {//-- mediaPos32 >= fat1StartPos)
sl@0
   826
        if(mediaPos32 >= fat1EndPos)
sl@0
   827
            return;
sl@0
   828
    
sl@0
   829
        invRegionPosStart = mediaPos32;
sl@0
   830
        
sl@0
   831
        if((mediaPos32 + aLength) <= fat1EndPos)
sl@0
   832
        {
sl@0
   833
            invRegionLen = aLength;
sl@0
   834
        }
sl@0
   835
        else 
sl@0
   836
        {
sl@0
   837
            invRegionLen = mediaPos32+aLength-fat1EndPos;
sl@0
   838
        }
sl@0
   839
    }
sl@0
   840
sl@0
   841
    //-- convert the media pos of the region into FAT entries basis, depending on the FAT type
sl@0
   842
    ASSERT(invRegionPosStart >= fat1StartPos && invRegionLen <= (TUint)iOwner->FatSizeInBytes());
sl@0
   843
    
sl@0
   844
    TUint32 startFatEntry=0;
sl@0
   845
    TUint32 numEntries = 0;
sl@0
   846
sl@0
   847
    switch(FatType())
sl@0
   848
    {
sl@0
   849
        case EFat12:
sl@0
   850
        //-- invalidate whole cache; it is not worth making calculations for such small memory region.
sl@0
   851
        User::LeaveIfError(iCache->Invalidate());
sl@0
   852
        return;
sl@0
   853
sl@0
   854
        case EFat16:
sl@0
   855
        startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat16EntrySzLog2;
sl@0
   856
        numEntries = (invRegionLen + (sizeof(TFat16Entry)-1)) >> KFat16EntrySzLog2;
sl@0
   857
        break;
sl@0
   858
sl@0
   859
        default:
sl@0
   860
        ASSERT(0);
sl@0
   861
        return;
sl@0
   862
    };
sl@0
   863
sl@0
   864
    if(startFatEntry < KFatFirstSearchCluster)
sl@0
   865
    {//-- FAT[0] and FAT[1] can't be legally accessed, they are reserved entries. We need to adjust region being refreshed.
sl@0
   866
        if(numEntries <= KFatFirstSearchCluster)
sl@0
   867
            return; //-- nothing to refresh
sl@0
   868
                    
sl@0
   869
        startFatEntry += KFatFirstSearchCluster;
sl@0
   870
        numEntries -= KFatFirstSearchCluster;
sl@0
   871
    }
sl@0
   872
sl@0
   873
    User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries));
sl@0
   874
    }
sl@0
   875
sl@0
   876
sl@0
   877
//-----------------------------------------------------------------------------
sl@0
   878
/**
sl@0
   879
    Initialize the object, create FAT cache if required
sl@0
   880
@leave KErrNoMemory
sl@0
   881
*/
sl@0
   882
void CAtaFatTable::InitializeL()
sl@0
   883
    {
sl@0
   884
    __PRINT1(_L("CAtaFatTable::InitializeL() drv:%d"), iOwner->DriveNumber());
sl@0
   885
    CFatTable::InitializeL();
sl@0
   886
sl@0
   887
    //-- create the FAT cache.
sl@0
   888
    ASSERT(!iCache);
sl@0
   889
    CreateCacheL();
sl@0
   890
    }
sl@0
   891
sl@0
   892
sl@0
   893
//-----------------------------------------------------------------------------
sl@0
   894
/**
sl@0
   895
    Remount the FAT table. This method call means that the media parameters wasn't changed, 
sl@0
   896
    otherwise CFatMountCB::DoReMountL() would reject it. 
sl@0
   897
    Just do some re-initialisation work.
sl@0
   898
*/
sl@0
   899
void CAtaFatTable::ReMountL()
sl@0
   900
{
sl@0
   901
    __PRINT1(_L("CAtaFatTable::ReMountL() drv:%d"), iOwner->DriveNumber());
sl@0
   902
sl@0
   903
    if(iCache)
sl@0
   904
        {
sl@0
   905
        iCache->Invalidate();
sl@0
   906
        }
sl@0
   907
    else
sl@0
   908
        {
sl@0
   909
        //-- this situation can happen when someone called CAtaFatTable::Dismount() that deletes the cache object
sl@0
   910
        //-- and then ReMount happens. We need to re-initialise this object.
sl@0
   911
        InitializeL();
sl@0
   912
        }
sl@0
   913
}
sl@0
   914
sl@0
   915
sl@0
   916
//-----------------------------------------------------------------------------
sl@0
   917
/**
sl@0
   918
    Read an entry from the FAT table
sl@0
   919
sl@0
   920
    @param aFatIndex FAT entry number to read
sl@0
   921
    @return FAT entry value
sl@0
   922
*/
sl@0
   923
TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const
sl@0
   924
    {
sl@0
   925
    if(!ClusterNumberValid(aFatIndex))
sl@0
   926
        {
sl@0
   927
        //ASSERT(0); //-- for some silly reason some callers pass 0 here and expect it to leave
sl@0
   928
        User::Leave(KErrCorrupt);
sl@0
   929
        }
sl@0
   930
sl@0
   931
sl@0
   932
    const TUint entry = iCache->ReadEntryL(aFatIndex);
sl@0
   933
    return entry;
sl@0
   934
    }
sl@0
   935
sl@0
   936
sl@0
   937
//-----------------------------------------------------------------------------
sl@0
   938
/**
sl@0
   939
    Write an entry to the FAT table
sl@0
   940
sl@0
   941
    @param aFatIndex    aFatIndex FAT entry number to write
sl@0
   942
    @param aValue       FAT entry to write
sl@0
   943
@leave
sl@0
   944
*/
sl@0
   945
void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
sl@0
   946
    {
sl@0
   947
    const TUint32 KFat16EntryMask = 0x0FFFF;
sl@0
   948
    
sl@0
   949
    __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue);
sl@0
   950
    
sl@0
   951
    if(!ClusterNumberValid(aFatIndex))
sl@0
   952
        {
sl@0
   953
        ASSERT(0); 
sl@0
   954
        User::Leave(KErrCorrupt);
sl@0
   955
        }
sl@0
   956
    
sl@0
   957
    if(aValue != KSpareCluster && (aValue < KFatFirstSearchCluster || aValue > KFat16EntryMask))
sl@0
   958
        {
sl@0
   959
        ASSERT(0);
sl@0
   960
        User::Leave(KErrCorrupt);
sl@0
   961
        }
sl@0
   962
    iCache->WriteEntryL(aFatIndex, aValue);
sl@0
   963
    }
sl@0
   964
sl@0
   965
sl@0
   966
/**
sl@0
   967
Get the next cluster in the chain from the FAT
sl@0
   968
sl@0
   969
@param aCluster number to read, contains next cluster upon return
sl@0
   970
@leave
sl@0
   971
@return False if end of cluster chain
sl@0
   972
*/
sl@0
   973
TBool CFatTable::GetNextClusterL(TInt& aCluster) const
sl@0
   974
    {
sl@0
   975
    __PRINT1(_L("CAtaFatTable::GetNextClusterL(%d)"), aCluster);
sl@0
   976
    
sl@0
   977
    const TInt nextCluster = ReadL(aCluster);
sl@0
   978
    TBool ret = EFalse; 
sl@0
   979
sl@0
   980
    switch(FatType())
sl@0
   981
        {
sl@0
   982
        case EFat12:
sl@0
   983
            ret=!IsEof12Bit(nextCluster);
sl@0
   984
        break;
sl@0
   985
sl@0
   986
        case EFat16:
sl@0
   987
            ret=!IsEof16Bit(nextCluster);
sl@0
   988
        break;
sl@0
   989
sl@0
   990
        default:
sl@0
   991
            ASSERT(0);
sl@0
   992
            return EFalse;//-- get rid of warning
sl@0
   993
        };
sl@0
   994
    
sl@0
   995
    if (ret)
sl@0
   996
        {
sl@0
   997
        aCluster=nextCluster;
sl@0
   998
        }
sl@0
   999
    
sl@0
  1000
    return ret;
sl@0
  1001
sl@0
  1002
    }
sl@0
  1003
sl@0
  1004
/**
sl@0
  1005
Write EOF to aFatIndex
sl@0
  1006
    @param aFatIndex index in FAT (cluster number) to be written
sl@0
  1007
*/
sl@0
  1008
void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex)
sl@0
  1009
    {
sl@0
  1010
    __PRINT1(_L("CAtaFatTable::WriteFatEntryEofL(%d)"), aFatIndex);
sl@0
  1011
sl@0
  1012
    //-- use EOF_16Bit (0x0ffff) for all types of FAT, FAT cache will mask it appropriately
sl@0
  1013
    WriteL(aFatIndex, EOF_16Bit);
sl@0
  1014
    }
sl@0
  1015
sl@0
  1016
sl@0
  1017
sl@0
  1018
/** 
sl@0
  1019
    Mark cluster number aFatIndex in FAT as bad 
sl@0
  1020
    @param aFatIndex index in FAT (cluster number) to be written
sl@0
  1021
*/
sl@0
  1022
void CFatTable::MarkAsBadClusterL(TUint32 aFatIndex)
sl@0
  1023
    {
sl@0
  1024
    __PRINT1(_L("CAtaFatTable::MarkAsBadClusterL(%d)"),aFatIndex);
sl@0
  1025
sl@0
  1026
    //-- use KBad_16Bit (0x0fff7) for all types of FAT, FAT cache will mask it appropriately
sl@0
  1027
    WriteL(aFatIndex, KBad_16Bit);
sl@0
  1028
    
sl@0
  1029
    FlushL();
sl@0
  1030
    }
sl@0
  1031
sl@0
  1032
sl@0
  1033
/**
sl@0
  1034
Return the location of a Cluster in the data section of the media
sl@0
  1035
sl@0
  1036
@param aCluster to find location of
sl@0
  1037
@return Byte offset of the cluster data 
sl@0
  1038
*/
sl@0
  1039
TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const
sl@0
  1040
    {
sl@0
  1041
    __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex));
sl@0
  1042
sl@0
  1043
    const TInt clusterBasePosition=iOwner->ClusterBasePosition();
sl@0
  1044
    return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition);
sl@0
  1045
    }
sl@0
  1046
sl@0
  1047
sl@0
  1048
sl@0
  1049
sl@0
  1050
sl@0
  1051