os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/fat_table32.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
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\sfat32\fat_table32.cpp
sl@0
    15
// FAT32 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
#include "sl_std.h"
sl@0
    27
#include "sl_fatcache32.h"
sl@0
    28
#include "fat_table32.h"
sl@0
    29
sl@0
    30
sl@0
    31
sl@0
    32
sl@0
    33
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
    34
/** 
sl@0
    35
    Implements automatic locking object.
sl@0
    36
    Calls TDriveInterface::AcquireLock() on construction and TDriveInterface::ReleaseLock() on destruction. 
sl@0
    37
    Can be constructed on the stack only.
sl@0
    38
*/
sl@0
    39
class XAutoLock
sl@0
    40
    {
sl@0
    41
     public:
sl@0
    42
       inline XAutoLock(CFatMountCB* apOwner) : iDrv(apOwner->DriveInterface()) {iDrv.AcquireLock();}
sl@0
    43
       inline XAutoLock(TDriveInterface& aDrv) : iDrv(aDrv) {iDrv.AcquireLock();}
sl@0
    44
       inline ~XAutoLock() {iDrv.ReleaseLock();}
sl@0
    45
sl@0
    46
     private:
sl@0
    47
        void* operator new(TUint); //-- disable creating objects on heap.
sl@0
    48
        void* operator new(TUint, void*);
sl@0
    49
sl@0
    50
     private:
sl@0
    51
        TDriveInterface &iDrv; ///< reference to the drive interface
sl@0
    52
    };
sl@0
    53
sl@0
    54
sl@0
    55
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
    56
sl@0
    57
sl@0
    58
sl@0
    59
//#######################################################################################################################################
sl@0
    60
//#     CFatTable class implementation 
sl@0
    61
//#######################################################################################################################################
sl@0
    62
sl@0
    63
/**
sl@0
    64
    FAT object factory method.
sl@0
    65
    Constructs either CAtaFatTable or CRamFatTable depending on the media type parameter
sl@0
    66
sl@0
    67
    @param aOwner Pointer to the owning mount
sl@0
    68
    @param aLocDrvCaps local drive attributes
sl@0
    69
    @leave KErrNoMemory
sl@0
    70
    @return Pointer to the Fat table
sl@0
    71
*/
sl@0
    72
CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps)
sl@0
    73
	{
sl@0
    74
    CFatTable* pFatTable=NULL;
sl@0
    75
    
sl@0
    76
    switch(aLocDrvCaps.iType)
sl@0
    77
        {
sl@0
    78
        case EMediaRam:
sl@0
    79
		    {//-- this is RAM media, try to create CRamFatTable instance.
sl@0
    80
            const TFatType fatType = aOwner.FatType();
sl@0
    81
            
sl@0
    82
            if(fatType != EFat16 && fatType != EFat32)
sl@0
    83
                {//-- CRamFatTable doesn't support FAT12, FAT16 & FAT32 only.
sl@0
    84
                __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType);
sl@0
    85
                ASSERT(0);
sl@0
    86
                return NULL;
sl@0
    87
                }
sl@0
    88
            
sl@0
    89
            pFatTable = CRamFatTable::NewL(aOwner);
sl@0
    90
            }
sl@0
    91
        break;
sl@0
    92
sl@0
    93
        default:
sl@0
    94
            //-- other media
sl@0
    95
            pFatTable = CAtaFatTable::NewL(aOwner);
sl@0
    96
        break;
sl@0
    97
        };
sl@0
    98
sl@0
    99
	return pFatTable;
sl@0
   100
	}
sl@0
   101
sl@0
   102
sl@0
   103
CFatTable::CFatTable(CFatMountCB& aOwner)
sl@0
   104
{
sl@0
   105
    iOwner = &aOwner;
sl@0
   106
    ASSERT(iOwner);
sl@0
   107
}
sl@0
   108
sl@0
   109
CFatTable::~CFatTable()
sl@0
   110
{
sl@0
   111
    //-- destroy cache ignoring dirty data in cache
sl@0
   112
    //-- the destructor isn't an appropriate place to flush the data.
sl@0
   113
    Dismount(ETrue); 
sl@0
   114
}
sl@0
   115
sl@0
   116
//-----------------------------------------------------------------------------
sl@0
   117
sl@0
   118
/**
sl@0
   119
    Initialise the object, get data from the owning CFatMountCB
sl@0
   120
*/
sl@0
   121
void CFatTable::InitializeL()
sl@0
   122
    {
sl@0
   123
    ASSERT(iOwner);
sl@0
   124
sl@0
   125
    //-- get FAT type from the owner
sl@0
   126
    iFatType = iOwner->FatType();
sl@0
   127
    ASSERT(IsFat12() || IsFat16() || IsFat32());
sl@0
   128
sl@0
   129
    //-- set the EOC code
sl@0
   130
    iFatEocCode = EocCodeByFatType(iFatType);
sl@0
   131
    
sl@0
   132
sl@0
   133
sl@0
   134
sl@0
   135
    iFreeClusterHint = KFatFirstSearchCluster;
sl@0
   136
sl@0
   137
    //-- cache the media attributes
sl@0
   138
    TLocalDriveCapsV2 caps;
sl@0
   139
    TPckg<TLocalDriveCapsV2> capsPckg(caps);
sl@0
   140
    User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
sl@0
   141
    iMediaAtt = caps.iMediaAtt;
sl@0
   142
sl@0
   143
    //-- obtain maximal number of entries in the table
sl@0
   144
    iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use
sl@0
   145
sl@0
   146
    __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries);
sl@0
   147
    }
sl@0
   148
sl@0
   149
//-----------------------------------------------------------------------------
sl@0
   150
sl@0
   151
/** 
sl@0
   152
    Decrements the free cluster count.
sl@0
   153
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   154
    cluster of a large file. Use more than one cluster granularity.
sl@0
   155
     
sl@0
   156
    @param  aCount a number of clusters 
sl@0
   157
*/
sl@0
   158
void CFatTable::DecrementFreeClusterCount(TUint32 aCount)
sl@0
   159
    {
sl@0
   160
    __ASSERT_DEBUG(iFreeClusters >= aCount, Fault(EFatCorrupt));
sl@0
   161
    iFreeClusters -= aCount;
sl@0
   162
    }
sl@0
   163
sl@0
   164
/** 
sl@0
   165
    Increments the free cluster count.
sl@0
   166
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   167
    cluster of a large file. Use more than one cluster granularity.
sl@0
   168
sl@0
   169
    @param  aCount a number of clusters 
sl@0
   170
*/
sl@0
   171
void CFatTable::IncrementFreeClusterCount(TUint32 aCount)
sl@0
   172
    {
sl@0
   173
	const TUint32 newVal = iFreeClusters+aCount;
sl@0
   174
    __ASSERT_DEBUG(newVal<=MaxEntries(), Fault(EFatCorrupt));
sl@0
   175
    
sl@0
   176
    iFreeClusters = newVal;
sl@0
   177
    }
sl@0
   178
sl@0
   179
/** @return number of free clusters in the FAT */
sl@0
   180
TUint32 CFatTable::NumberOfFreeClusters(TBool /*aSyncOperation=EFalse*/) const
sl@0
   181
    {
sl@0
   182
    return FreeClusters();
sl@0
   183
    }
sl@0
   184
sl@0
   185
void CFatTable::SetFreeClusters(TUint32 aFreeClusters)
sl@0
   186
    {   
sl@0
   187
    iFreeClusters=aFreeClusters;
sl@0
   188
    }
sl@0
   189
sl@0
   190
/**
sl@0
   191
    Get the hint about the last known free cluster number.
sl@0
   192
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   193
    cluster of a large file.
sl@0
   194
sl@0
   195
    @return cluster number supposedly close to the free one.
sl@0
   196
*/
sl@0
   197
TUint32 CFatTable::FreeClusterHint() const 
sl@0
   198
    {
sl@0
   199
    ASSERT(ClusterNumberValid(iFreeClusterHint));
sl@0
   200
    return iFreeClusterHint;
sl@0
   201
    } 
sl@0
   202
sl@0
   203
/**
sl@0
   204
    Set a free cluster hint. The next search fro the free cluster can start from this value.
sl@0
   205
    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
   206
    free entries chain.
sl@0
   207
    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
sl@0
   208
    cluster of a large file.
sl@0
   209
sl@0
   210
    @param aCluster cluster number hint.
sl@0
   211
*/
sl@0
   212
void CFatTable::SetFreeClusterHint(TUint32 aCluster) 
sl@0
   213
    {
sl@0
   214
    ASSERT(ClusterNumberValid(aCluster));
sl@0
   215
    iFreeClusterHint=aCluster;
sl@0
   216
    } 
sl@0
   217
sl@0
   218
//-----------------------------------------------------------------------------
sl@0
   219
sl@0
   220
/**
sl@0
   221
    Find out the number of free clusters on the volume.
sl@0
   222
    Reads whole FAT and counts free clusters.
sl@0
   223
*/
sl@0
   224
void CFatTable::CountFreeClustersL()
sl@0
   225
    {
sl@0
   226
    __PRINT1(_L("#- CFatTable::CountFreeClustersL(), drv:%d"), iOwner->DriveNumber());
sl@0
   227
sl@0
   228
    const TUint32 KUsableClusters = iOwner->UsableClusters();
sl@0
   229
    (void)KUsableClusters;
sl@0
   230
sl@0
   231
    TUint32 freeClusters = 0;
sl@0
   232
    TUint32 firstFreeCluster = 0;
sl@0
   233
sl@0
   234
    TTime   timeStart;
sl@0
   235
    TTime   timeEnd;
sl@0
   236
    timeStart.UniversalTime(); //-- take start time
sl@0
   237
sl@0
   238
    //-- walk through whole FAT table looking for free clusters
sl@0
   239
	for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i)
sl@0
   240
    {
sl@0
   241
	    if(ReadL(i) == KSpareCluster)
sl@0
   242
            {//-- found a free cluster
sl@0
   243
		    ++freeClusters;
sl@0
   244
            
sl@0
   245
            if(!firstFreeCluster)
sl@0
   246
                firstFreeCluster = i;
sl@0
   247
            }
sl@0
   248
	    }
sl@0
   249
sl@0
   250
    timeEnd.UniversalTime(); //-- take end time
sl@0
   251
    const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
sl@0
   252
    __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime);
sl@0
   253
    (void)msScanTime;
sl@0
   254
sl@0
   255
    if(!firstFreeCluster) //-- haven't found free clusters on the volume
sl@0
   256
        firstFreeCluster = KFatFirstSearchCluster;
sl@0
   257
sl@0
   258
    ASSERT(freeClusters <= KUsableClusters);
sl@0
   259
sl@0
   260
    SetFreeClusters(freeClusters);
sl@0
   261
    SetFreeClusterHint(firstFreeCluster);
sl@0
   262
    }
sl@0
   263
sl@0
   264
//-----------------------------------------------------------------------------
sl@0
   265
sl@0
   266
/**
sl@0
   267
Count the number of contiguous cluster from a start cluster
sl@0
   268
sl@0
   269
@param aStartCluster cluster to start counting from
sl@0
   270
@param anEndCluster contains the end cluster number upon return
sl@0
   271
@param aMaxCount Maximum cluster required
sl@0
   272
@leave System wide error values
sl@0
   273
@return Number of contiguous clusters from aStartCluster.
sl@0
   274
*/
sl@0
   275
TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const
sl@0
   276
	{
sl@0
   277
	__PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount);
sl@0
   278
	TUint32 clusterListLen=1;
sl@0
   279
	TInt endCluster=aStartCluster;
sl@0
   280
	TInt64 endClusterPos=DataPositionInBytes(endCluster);
sl@0
   281
	while (clusterListLen<aMaxCount)
sl@0
   282
		{
sl@0
   283
		TInt oldCluster=endCluster;
sl@0
   284
		TInt64 oldClusterPos=endClusterPos;
sl@0
   285
		if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
sl@0
   286
			{
sl@0
   287
			endCluster=oldCluster;
sl@0
   288
			break;
sl@0
   289
			}
sl@0
   290
		clusterListLen++;
sl@0
   291
		}
sl@0
   292
	anEndCluster=endCluster;
sl@0
   293
	return(clusterListLen);
sl@0
   294
	}	
sl@0
   295
sl@0
   296
//-----------------------------------------------------------------------------
sl@0
   297
sl@0
   298
/**
sl@0
   299
    Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full).
sl@0
   300
sl@0
   301
    @param aNumber  amount of clusters to allocate
sl@0
   302
    @param aCluster FAT entry index to start with.
sl@0
   303
sl@0
   304
    @leave KErrDiskFull + system wide error codes
sl@0
   305
*/
sl@0
   306
void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
sl@0
   307
	{
sl@0
   308
	__PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster);
sl@0
   309
	__ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
sl@0
   310
	
sl@0
   311
	while(aNumber && GetNextClusterL(aCluster))
sl@0
   312
		aNumber--;
sl@0
   313
sl@0
   314
    if(!aNumber)
sl@0
   315
        return;
sl@0
   316
sl@0
   317
    if(!RequestFreeClusters(aNumber))
sl@0
   318
		{
sl@0
   319
		__PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull"));
sl@0
   320
		User::Leave(KErrDiskFull);
sl@0
   321
		}
sl@0
   322
sl@0
   323
sl@0
   324
    TUint32 freeCluster = 0;
sl@0
   325
    
sl@0
   326
    //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL()
sl@0
   327
    for(TUint i=0; i<aNumber; ++i)
sl@0
   328
        {
sl@0
   329
        freeCluster = FindClosestFreeClusterL(aCluster);
sl@0
   330
        WriteFatEntryEofL(freeCluster); //	Must write EOF for FindClosestFreeCluster to work again
sl@0
   331
        WriteL(aCluster,freeCluster);
sl@0
   332
        aCluster=freeCluster;
sl@0
   333
        }
sl@0
   334
    
sl@0
   335
    //-- decrement number of available clusters
sl@0
   336
    DecrementFreeClusterCount(aNumber);
sl@0
   337
sl@0
   338
    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from
sl@0
   339
    SetFreeClusterHint(aCluster); 
sl@0
   340
    
sl@0
   341
    }
sl@0
   342
sl@0
   343
//-----------------------------------------------------------------------------
sl@0
   344
sl@0
   345
/**
sl@0
   346
    Allocate and mark as EOF a single cluster as close as possible to aNearestCluster
sl@0
   347
sl@0
   348
    @param aNearestCluster Cluster the new cluster should be nearest to
sl@0
   349
    @leave System wide error codes
sl@0
   350
    @return The cluster number allocated
sl@0
   351
*/
sl@0
   352
TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
sl@0
   353
	{
sl@0
   354
	__PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster);
sl@0
   355
	
sl@0
   356
    const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster);
sl@0
   357
	WriteFatEntryEofL(freeCluster);
sl@0
   358
	DecrementFreeClusterCount(1);
sl@0
   359
sl@0
   360
    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from.
sl@0
   361
    SetFreeClusterHint(freeCluster); 
sl@0
   362
sl@0
   363
	return(freeCluster);
sl@0
   364
	}	
sl@0
   365
sl@0
   366
//-----------------------------------------------------------------------------
sl@0
   367
sl@0
   368
/**
sl@0
   369
    Allocate and link a cluster chain, leaves if there are not enough free clusters.
sl@0
   370
    Chain starts as close as possible to aNearestCluster, last cluster will be marked as EOF.
sl@0
   371
sl@0
   372
    @param aNumber Number of clusters to allocate
sl@0
   373
    @param aNearestCluster Cluster the new chain should be nearest to
sl@0
   374
    @leave System wide error codes
sl@0
   375
    @return The first cluster number allocated
sl@0
   376
*/
sl@0
   377
TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster)
sl@0
   378
	{
sl@0
   379
    __PRINT2(_L("CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster);
sl@0
   380
	__ASSERT_DEBUG(aNumber>0, Fault(EFatBadParameter));
sl@0
   381
sl@0
   382
	if(!RequestFreeClusters(aNumber))
sl@0
   383
    	{
sl@0
   384
		__PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull"));
sl@0
   385
		User::Leave(KErrDiskFull);
sl@0
   386
		}
sl@0
   387
sl@0
   388
	TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster);
sl@0
   389
	if (aNumber>1)
sl@0
   390
		ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster);
sl@0
   391
sl@0
   392
    return(firstCluster);
sl@0
   393
	}	
sl@0
   394
sl@0
   395
//-----------------------------------------------------------------------------
sl@0
   396
sl@0
   397
/**
sl@0
   398
    Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported.
sl@0
   399
    @param aFreedClusters array with FAT numbers of clusters that shall be marked as "deleted"
sl@0
   400
*/
sl@0
   401
void CFatTable::DoFreedClustersNotify(RClusterArray &aFreedClusters)
sl@0
   402
{
sl@0
   403
    ASSERT(iMediaAtt & KMediaAttDeleteNotify);
sl@0
   404
sl@0
   405
    const TUint clusterCount = aFreedClusters.Count();
sl@0
   406
sl@0
   407
    if(!clusterCount)
sl@0
   408
        return;
sl@0
   409
    
sl@0
   410
    FlushL(); //-- Commit the FAT changes to disk first to be safe
sl@0
   411
sl@0
   412
    const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2();
sl@0
   413
sl@0
   414
    TInt64  byteAddress = 0;	
sl@0
   415
	TUint   deleteLen = 0;	// zero indicates no clusters accumulated yet
sl@0
   416
sl@0
   417
	for (TUint i=0; i<clusterCount; ++i)
sl@0
   418
	{
sl@0
   419
        const TUint currCluster = aFreedClusters[i];
sl@0
   420
        
sl@0
   421
        if (deleteLen == 0)
sl@0
   422
		    byteAddress = DataPositionInBytes(currCluster); //-- start of the media range
sl@0
   423
        
sl@0
   424
        deleteLen += bytesPerCluster;
sl@0
   425
sl@0
   426
        //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver
sl@0
   427
		if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1))
sl@0
   428
        {
sl@0
   429
            //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen);
sl@0
   430
			//__PRINT2(_L("   first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster);
sl@0
   431
	
sl@0
   432
            const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen);
sl@0
   433
			if(r != KErrNone)
sl@0
   434
                {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; 
sl@0
   435
                 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media.
sl@0
   436
                const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement);
sl@0
   437
                __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
sl@0
   438
sl@0
   439
                if(platSecEnabled)
sl@0
   440
                    {
sl@0
   441
                    //-- if PlatSec is enabled, we can't afford jeopardize the security; without DeleteNotify()
sl@0
   442
                    //-- it's possible to pick up data from deleted files, so, panic the file server.
sl@0
   443
                    Fault(EFatBadLocalDrive);
sl@0
   444
                    }
sl@0
   445
                else
sl@0
   446
                    {
sl@0
   447
                    //-- if PlatSec is disabled, it's OK to ignore the NAND fault in release mode.
sl@0
   448
                    __ASSERT_DEBUG(0, Fault(EFatBadLocalDrive));
sl@0
   449
                    }        
sl@0
   450
                }
sl@0
   451
sl@0
   452
            
sl@0
   453
            deleteLen = 0;
sl@0
   454
        }
sl@0
   455
sl@0
   456
    }
sl@0
   457
sl@0
   458
    //-- empty the array.
sl@0
   459
    aFreedClusters.Reset();
sl@0
   460
}
sl@0
   461
sl@0
   462
//-----------------------------------------------------------------------------
sl@0
   463
/**
sl@0
   464
    Mark a chain of clusters as free in the FAT. 
sl@0
   465
sl@0
   466
    @param aCluster Start cluster of cluster chain to free
sl@0
   467
    @leave System wide error codes
sl@0
   468
*/
sl@0
   469
void CFatTable::FreeClusterListL(TUint32 aCluster)
sl@0
   470
	{
sl@0
   471
	__PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster);
sl@0
   472
	if (aCluster == KSpareCluster)
sl@0
   473
		return; 
sl@0
   474
sl@0
   475
	//-- here we can store array of freed cluster numbers in order to 
sl@0
   476
    //-- notify media drive about the media addresses marked as "invalid"
sl@0
   477
    RClusterArray deletedClusters;      
sl@0
   478
	CleanupClosePushL(deletedClusters);
sl@0
   479
sl@0
   480
    //-- if ETrue, we need to notify media driver about invalidated media addressses
sl@0
   481
    const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify;
sl@0
   482
sl@0
   483
    //-- this is a maximal number of FAT entries in the deletedClusters array.
sl@0
   484
    //-- as soon as we collect this number of entries in the array, FAT cache will be flushed
sl@0
   485
    //-- and driver notified. The array will be emptied. Used to avoid huge array when deleting
sl@0
   486
    //--  large files on NAND media 
sl@0
   487
    const TUint KSubListLen = 4096;
sl@0
   488
    ASSERT(IsPowerOf2(KSubListLen));
sl@0
   489
sl@0
   490
    TUint32 lastKnownFreeCluster = FreeClusterHint();
sl@0
   491
    TUint32 cntFreedClusters = 0;
sl@0
   492
sl@0
   493
    TUint32 currCluster = aCluster;
sl@0
   494
    TInt    nextCluster = aCluster;
sl@0
   495
sl@0
   496
    for(;;)
sl@0
   497
    {
sl@0
   498
        const TBool bEOF = !GetNextClusterL(nextCluster);    
sl@0
   499
        WriteL(currCluster, KSpareCluster);
sl@0
   500
sl@0
   501
        lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster);
sl@0
   502
sl@0
   503
		// Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe 
sl@0
   504
		// to do once the FAT changes have been written to disk.
sl@0
   505
        if(bFreeClustersNotify)
sl@0
   506
            deletedClusters.Append(currCluster);
sl@0
   507
sl@0
   508
        ++cntFreedClusters;
sl@0
   509
        currCluster = nextCluster;
sl@0
   510
sl@0
   511
		if (bEOF || aCluster == KSpareCluster)
sl@0
   512
			break;
sl@0
   513
sl@0
   514
        if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0)
sl@0
   515
        {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array.
sl@0
   516
            IncrementFreeClusterCount(cntFreedClusters);
sl@0
   517
            cntFreedClusters = 0;
sl@0
   518
sl@0
   519
            SetFreeClusterHint(lastKnownFreeCluster);
sl@0
   520
            DoFreedClustersNotify(deletedClusters);
sl@0
   521
        }
sl@0
   522
sl@0
   523
    }
sl@0
   524
sl@0
   525
    //-- increase the number of free clusters and notify the driver if required.
sl@0
   526
    IncrementFreeClusterCount(cntFreedClusters);
sl@0
   527
    SetFreeClusterHint(lastKnownFreeCluster);
sl@0
   528
    
sl@0
   529
    if(bFreeClustersNotify)
sl@0
   530
        DoFreedClustersNotify(deletedClusters);
sl@0
   531
sl@0
   532
	CleanupStack::PopAndDestroy(&deletedClusters);
sl@0
   533
	}
sl@0
   534
sl@0
   535
//-----------------------------------------------------------------------------
sl@0
   536
sl@0
   537
/**
sl@0
   538
    Find a free cluster nearest to aCluster, Always checks to the right of aCluster first 
sl@0
   539
    but checks in both directions in the Fat.
sl@0
   540
sl@0
   541
    @param aCluster Cluster to find nearest free cluster to.
sl@0
   542
    @leave KErrDiskFull + system wide error codes
sl@0
   543
    @return cluster number found
sl@0
   544
*/
sl@0
   545
TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster)
sl@0
   546
	{
sl@0
   547
    __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
sl@0
   548
	
sl@0
   549
    if(!ClusterNumberValid(aCluster))
sl@0
   550
        {
sl@0
   551
        ASSERT(0);
sl@0
   552
        User::Leave(KErrCorrupt);
sl@0
   553
        }
sl@0
   554
sl@0
   555
    if(!RequestFreeClusters(1))
sl@0
   556
	    {//-- there is no at least 1 free cluster available
sl@0
   557
    	__PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
sl@0
   558
        User::Leave(KErrDiskFull);
sl@0
   559
        }
sl@0
   560
sl@0
   561
    //-- 1. look if the given index contains a free entry 
sl@0
   562
    if(ReadL(aCluster) != KSpareCluster)
sl@0
   563
        {//-- no, it doesn't...
sl@0
   564
        
sl@0
   565
        //-- 2. look in both directions starting from the aCluster, looking in the right direction first
sl@0
   566
        
sl@0
   567
        const TUint32 maxEntries = MaxEntries();
sl@0
   568
        const TUint32 MinIdx = KFatFirstSearchCluster;
sl@0
   569
        const TUint32 MaxIdx = maxEntries-1;
sl@0
   570
sl@0
   571
        TBool canGoRight = ETrue;
sl@0
   572
        TBool canGoLeft = ETrue;
sl@0
   573
    
sl@0
   574
        TUint32 rightIdx = aCluster;
sl@0
   575
        TUint32 leftIdx  = aCluster;
sl@0
   576
        
sl@0
   577
        for(TUint i=0; i<maxEntries; ++i)
sl@0
   578
            {
sl@0
   579
            if(canGoRight)
sl@0
   580
                {
sl@0
   581
                if(rightIdx < MaxIdx)
sl@0
   582
                    ++rightIdx;
sl@0
   583
                else
sl@0
   584
                    canGoRight = EFalse;
sl@0
   585
                }
sl@0
   586
sl@0
   587
            if(canGoLeft)
sl@0
   588
                {
sl@0
   589
                if(leftIdx > MinIdx)
sl@0
   590
                    --leftIdx;
sl@0
   591
                else        
sl@0
   592
                    canGoLeft = EFalse;
sl@0
   593
                }
sl@0
   594
sl@0
   595
            if(!canGoRight && !canGoLeft)
sl@0
   596
	            {
sl@0
   597
    	        __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2"));
sl@0
   598
                User::Leave(KErrDiskFull);
sl@0
   599
                }
sl@0
   600
sl@0
   601
            if(canGoRight && ReadL(rightIdx) == KSpareCluster)
sl@0
   602
			    {
sl@0
   603
			    aCluster = rightIdx;
sl@0
   604
			    break;
sl@0
   605
			    }
sl@0
   606
sl@0
   607
		    if (canGoLeft && ReadL(leftIdx) == KSpareCluster)
sl@0
   608
			    {
sl@0
   609
			    aCluster = leftIdx;
sl@0
   610
			    break;
sl@0
   611
			    }
sl@0
   612
            }//for(..)
sl@0
   613
sl@0
   614
        }//if(ReadL(aCluster) != KSpareCluster)
sl@0
   615
sl@0
   616
sl@0
   617
    //-- note: do not update free cluster hint here by calling SetFreeClusterHint(). This is going to be 
sl@0
   618
    //-- expensive especially if overridden methods with synchronisation are called. Instead, set the number of 
sl@0
   619
    //-- the last known free cluster in the caller of this internal method.
sl@0
   620
sl@0
   621
    //__PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster);
sl@0
   622
sl@0
   623
    return aCluster;
sl@0
   624
	}
sl@0
   625
sl@0
   626
//-----------------------------------------------------------------------------
sl@0
   627
sl@0
   628
/**
sl@0
   629
    Converts a cluster number to byte offset in the FAT
sl@0
   630
sl@0
   631
    @param aFatIndex Cluster number
sl@0
   632
    @return Number of bytes from the beginning of the FAT
sl@0
   633
*/
sl@0
   634
TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const
sl@0
   635
	{
sl@0
   636
    switch(FatType())
sl@0
   637
        {
sl@0
   638
        case EFat12:
sl@0
   639
            return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry
sl@0
   640
sl@0
   641
        case EFat16:
sl@0
   642
            return aFatIndex<<1; //-- 2 bytes per FAT entry
sl@0
   643
sl@0
   644
        case EFat32:
sl@0
   645
            return aFatIndex<<2; //-- 4 bytes per FAT entry
sl@0
   646
sl@0
   647
        default:
sl@0
   648
            ASSERT(0);
sl@0
   649
            return 0;//-- get rid of warning
sl@0
   650
        };
sl@0
   651
sl@0
   652
	}
sl@0
   653
sl@0
   654
//-----------------------------------------------------------------------------
sl@0
   655
sl@0
   656
/**
sl@0
   657
    Checks if we have at least aClustersRequired clusters free in the FAT.
sl@0
   658
    This is, actually a dummy implementation.
sl@0
   659
sl@0
   660
    @param  aClustersRequired number of free clusters required
sl@0
   661
    @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
sl@0
   662
*/
sl@0
   663
TBool CFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
sl@0
   664
    {
sl@0
   665
    //__PRINT1(_L("#- CFatTable::RequestFreeClusters(%d)"),aClustersRequired);
sl@0
   666
    ASSERT(aClustersRequired >0);
sl@0
   667
    return (NumberOfFreeClusters() >= aClustersRequired);
sl@0
   668
    }
sl@0
   669
sl@0
   670
//-----------------------------------------------------------------------------
sl@0
   671
/**
sl@0
   672
    @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
sl@0
   673
*/
sl@0
   674
TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const 
sl@0
   675
    {
sl@0
   676
    return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries); 
sl@0
   677
    }
sl@0
   678
    
sl@0
   679
sl@0
   680
sl@0
   681
//#######################################################################################################################################
sl@0
   682
//#     CAtaFatTable class implementation 
sl@0
   683
//#######################################################################################################################################
sl@0
   684
sl@0
   685
/**
sl@0
   686
    Constructor
sl@0
   687
*/
sl@0
   688
CAtaFatTable::CAtaFatTable(CFatMountCB& aOwner)
sl@0
   689
             :CFatTable(aOwner), iDriveInteface(aOwner.DriveInterface())
sl@0
   690
    {
sl@0
   691
        iState = ENotInitialised;
sl@0
   692
    }
sl@0
   693
sl@0
   694
sl@0
   695
CAtaFatTable::~CAtaFatTable()
sl@0
   696
    {
sl@0
   697
    DestroyHelperThread();
sl@0
   698
    }
sl@0
   699
sl@0
   700
sl@0
   701
/** factory method */
sl@0
   702
CAtaFatTable* CAtaFatTable::NewL(CFatMountCB& aOwner)
sl@0
   703
{
sl@0
   704
    __PRINT1(_L("CAtaFatTable::NewL() drv:%d"),aOwner.DriveNumber());
sl@0
   705
    CAtaFatTable* pSelf = new (ELeave) CAtaFatTable(aOwner);
sl@0
   706
sl@0
   707
    CleanupStack::PushL(pSelf);
sl@0
   708
    pSelf->InitializeL();
sl@0
   709
    CleanupStack::Pop();
sl@0
   710
sl@0
   711
    return pSelf;
sl@0
   712
}
sl@0
   713
sl@0
   714
sl@0
   715
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   716
sl@0
   717
/**
sl@0
   718
    CAtaFatTable's FAT cache factory method.
sl@0
   719
    Creates fixed cache for FAT12/FAT16 or LRU cache for FAT32
sl@0
   720
*/
sl@0
   721
void CAtaFatTable::CreateCacheL()
sl@0
   722
{
sl@0
   723
    ASSERT(iOwner);
sl@0
   724
    const TUint32 fatSize=iOwner->FatSizeInBytes();
sl@0
   725
    __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize);
sl@0
   726
	
sl@0
   727
sl@0
   728
    //-- according to FAT specs:
sl@0
   729
    //-- FAT12 max size is 4084 entries or 6126 bytes                                               => create fixed cache for whole FAT
sl@0
   730
    //-- 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
   731
    //-- FAT32 min size is 65526 entries or 262104 bytes                                            => create LRU paged cache of max size: KFat32LRUCacheSize
sl@0
   732
sl@0
   733
    ASSERT(!iCache);
sl@0
   734
sl@0
   735
    //-- this is used for chaches granularity sanity check 
sl@0
   736
    const TUint32 KMinGranularityLog2 = KDefSectorSzLog2;  //-- 512 bytes is a minimal allowed granularity
sl@0
   737
    const TUint32 KMaxGranularityLog2 = 18; //-- 256K is a maximal allowed granularity
sl@0
   738
sl@0
   739
    switch(FatType())
sl@0
   740
    {
sl@0
   741
        //-- create fixed FAT12 cache
sl@0
   742
        case EFat12: 
sl@0
   743
            iCache = CFat12Cache::NewL(iOwner, fatSize); 
sl@0
   744
        break;
sl@0
   745
    
sl@0
   746
        //-- create fixed FAT16 cache
sl@0
   747
        case EFat16: 
sl@0
   748
            {
sl@0
   749
            TUint32 fat16_ReadGranularity_Log2; //-- FAT16 cache read granularity Log2
sl@0
   750
            TUint32 fat16_WriteGranularity_Log2;//-- FAT16 cache write granularity Log2
sl@0
   751
            
sl@0
   752
            iOwner->FatConfig().Fat16FixedCacheParams(fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2);
sl@0
   753
            
sl@0
   754
            //-- check if granularity values look sensible
sl@0
   755
            const TBool bParamsValid = fat16_ReadGranularity_Log2  >= KMinGranularityLog2 && fat16_ReadGranularity_Log2  <= KMaxGranularityLog2 &&
sl@0
   756
                                       fat16_WriteGranularity_Log2 >= KMinGranularityLog2 && fat16_WriteGranularity_Log2 <= KMaxGranularityLog2;
sl@0
   757
sl@0
   758
             __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity)); 
sl@0
   759
sl@0
   760
sl@0
   761
            iCache = CFat16FixedCache::NewL(iOwner, fatSize, fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2); 
sl@0
   762
            }
sl@0
   763
        break;
sl@0
   764
sl@0
   765
        //-- create FAT32 LRU paged cache
sl@0
   766
        case EFat32: 
sl@0
   767
            {
sl@0
   768
            TUint32 fat32_LRUCache_MaxMemSize;  //-- Maximum memory for the LRU FAT32 cache
sl@0
   769
            TUint32 fat32_ReadGranularity_Log2; //-- FAT32 cache read granularity Log2
sl@0
   770
            TUint32 fat32_WriteGranularity_Log2;//-- FAT32 cache write granularity Log2
sl@0
   771
    
sl@0
   772
            iOwner->FatConfig().Fat32LruCacheParams(fat32_ReadGranularity_Log2, fat32_WriteGranularity_Log2, fat32_LRUCache_MaxMemSize);
sl@0
   773
sl@0
   774
            
sl@0
   775
            //-- check if granularity  and required cache size values look sensible
sl@0
   776
            const TBool bParamsValid = fat32_ReadGranularity_Log2  >= KMinGranularityLog2 && fat32_ReadGranularity_Log2  <= KMaxGranularityLog2 &&
sl@0
   777
                                       fat32_WriteGranularity_Log2 >= KMinGranularityLog2 && fat32_WriteGranularity_Log2 <= KMaxGranularityLog2 &&
sl@0
   778
                                       fat32_LRUCache_MaxMemSize >= 8*K1KiloByte && fat32_LRUCache_MaxMemSize < 4*K1MegaByte;
sl@0
   779
            
sl@0
   780
            __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity)); 
sl@0
   781
            
sl@0
   782
            iCache = CFat32LruCache::NewL(iOwner, fat32_LRUCache_MaxMemSize, fat32_ReadGranularity_Log2, fat32_WriteGranularity_Log2);
sl@0
   783
            }
sl@0
   784
        break;
sl@0
   785
sl@0
   786
        default:
sl@0
   787
        ASSERT(0);
sl@0
   788
        User::Leave(KErrCorrupt);
sl@0
   789
        break;
sl@0
   790
    };
sl@0
   791
sl@0
   792
    ASSERT(iCache);
sl@0
   793
}
sl@0
   794
sl@0
   795
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   796
sl@0
   797
/**
sl@0
   798
    Destroys a helper thread object.
sl@0
   799
    If the thread is running, stops it first. than deletes the ipHelperThread and sets it to NULL
sl@0
   800
*/
sl@0
   801
void CAtaFatTable::DestroyHelperThread()
sl@0
   802
{
sl@0
   803
sl@0
   804
    if(!ipHelperThread)
sl@0
   805
        return;
sl@0
   806
  
sl@0
   807
    __PRINT1(_L("CAtaFatTable::DestroyHelperThread(), drv:%d"), iOwner->DriveNumber());
sl@0
   808
    ipHelperThread->ForceStop();
sl@0
   809
    delete ipHelperThread;
sl@0
   810
    ipHelperThread = NULL;
sl@0
   811
}
sl@0
   812
sl@0
   813
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   814
sl@0
   815
/**
sl@0
   816
    Flush the FAT cache on disk
sl@0
   817
    @leave System wide error codes
sl@0
   818
*/
sl@0
   819
void CAtaFatTable::FlushL()
sl@0
   820
	{
sl@0
   821
    __PRINT1(_L("CAtaFatTable::FlushL(), drv:%d"), iOwner->DriveNumber());
sl@0
   822
sl@0
   823
    //-- the data can't be written if the mount is inconsistent
sl@0
   824
    iOwner->CheckStateConsistentL();
sl@0
   825
sl@0
   826
    if (iCache)
sl@0
   827
		iCache->FlushL();
sl@0
   828
	}
sl@0
   829
sl@0
   830
sl@0
   831
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   832
sl@0
   833
/**
sl@0
   834
    Dismount the cache. Stops any activity, deallocates caches etc.
sl@0
   835
    @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded.
sl@0
   836
*/
sl@0
   837
void CAtaFatTable::Dismount(TBool aDiscardDirtyData)
sl@0
   838
	{
sl@0
   839
    __PRINT3(_L("#=-= CAtaFatTable::Dismount(%d), drv:%d, state:%d"), aDiscardDirtyData, iOwner->DriveNumber(), State());
sl@0
   840
sl@0
   841
    //-- if there is a helper thread, stop it and delete its object
sl@0
   842
    DestroyHelperThread();
sl@0
   843
sl@0
   844
    //-- if there is the cache, close it (it may lead to deallocating its memory)
sl@0
   845
	if(iCache)
sl@0
   846
		{
sl@0
   847
        //-- cache's Close() can check if the cache is clean. 
sl@0
   848
        //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data)
sl@0
   849
        //-- or if we are asked to do so.
sl@0
   850
        const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState();
sl@0
   851
        iCache->Close(bIgnoreDirtyData);
sl@0
   852
sl@0
   853
        delete iCache;
sl@0
   854
		iCache=NULL;
sl@0
   855
		}
sl@0
   856
sl@0
   857
     SetState(EDismounted);
sl@0
   858
	}
sl@0
   859
sl@0
   860
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   861
sl@0
   862
/**
sl@0
   863
    Invalidate whole FAT cache.
sl@0
   864
    Depending of cache type this may just mark cache invalid with reading on demand or re-read whole cache from the media
sl@0
   865
*/
sl@0
   866
void CAtaFatTable::InvalidateCacheL()
sl@0
   867
{
sl@0
   868
    __PRINT1(_L("CAtaFatTable::InvalidateCache(), drv:%d"), iOwner->DriveNumber());
sl@0
   869
sl@0
   870
    //-- if we have a cache, invalidate it entirely
sl@0
   871
    if(iCache)
sl@0
   872
        {
sl@0
   873
        User::LeaveIfError(iCache->Invalidate());
sl@0
   874
        }
sl@0
   875
sl@0
   876
    //-- invalidating whole FAT cache means that something very serious happened.
sl@0
   877
    //-- if we have a helper thread running, abort it.
sl@0
   878
    if(ipHelperThread)
sl@0
   879
        ipHelperThread->ForceStop();
sl@0
   880
sl@0
   881
}
sl@0
   882
sl@0
   883
sl@0
   884
//---------------------------------------------------------------------------------------------------------------------------------------
sl@0
   885
sl@0
   886
/**
sl@0
   887
    Invalidate specified region of the FAT cache
sl@0
   888
    Depending of cache type this may just mark part of the cache invalid with reading on demand later
sl@0
   889
    or re-read whole cache from the media.
sl@0
   890
sl@0
   891
    @param aPos absolute media position where the region being invalidated starts.
sl@0
   892
    @param aLength length in bytes of region to invalidate / refresh
sl@0
   893
*/
sl@0
   894
void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength)
sl@0
   895
	{
sl@0
   896
    __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength);
sl@0
   897
sl@0
   898
    if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength))
sl@0
   899
        return; //-- FAT tables can't span over 4G 
sl@0
   900
sl@0
   901
    const TUint32 mediaPos32 = I64LOW(aPos);
sl@0
   902
sl@0
   903
    //-- we do not use other copies of FAT, so trach changes only in FAT1
sl@0
   904
    const TUint32 fat1StartPos = iOwner->StartOfFatInBytes();
sl@0
   905
    const TUint32 fat1EndPos   = fat1StartPos + iOwner->FatSizeInBytes();
sl@0
   906
sl@0
   907
    TUint32 invRegionPosStart = 0; //-- media pos where the invalidated region starts
sl@0
   908
    TUint32 invRegionLen = 0;      //-- size of the invalidated region, bytes
sl@0
   909
    
sl@0
   910
    //-- calculate the FAT1 region being invalidated
sl@0
   911
    if(mediaPos32 < fat1StartPos)
sl@0
   912
        {
sl@0
   913
        if((mediaPos32 + aLength) <= fat1StartPos)
sl@0
   914
            return;
sl@0
   915
sl@0
   916
        invRegionPosStart = fat1StartPos;
sl@0
   917
        invRegionLen = aLength - (fat1StartPos-mediaPos32);
sl@0
   918
        }
sl@0
   919
    else //if(mediaPos32 < fat1StartPos)
sl@0
   920
        {//-- mediaPos32 >= fat1StartPos)
sl@0
   921
        if(mediaPos32 >= fat1EndPos)
sl@0
   922
            return;
sl@0
   923
    
sl@0
   924
        invRegionPosStart = mediaPos32;
sl@0
   925
        
sl@0
   926
        if((mediaPos32 + aLength) <= fat1EndPos)
sl@0
   927
            {
sl@0
   928
            invRegionLen = aLength;
sl@0
   929
            }
sl@0
   930
        else 
sl@0
   931
            {
sl@0
   932
            invRegionLen = mediaPos32+aLength-fat1EndPos;
sl@0
   933
            }
sl@0
   934
        }
sl@0
   935
sl@0
   936
    //-- convert the media pos of the region into FAT entries basis, depending on the FAT type
sl@0
   937
    ASSERT(invRegionPosStart >= fat1StartPos && invRegionLen <= (TUint)iOwner->FatSizeInBytes());
sl@0
   938
    
sl@0
   939
    TUint32 startFatEntry=0;
sl@0
   940
    TUint32 numEntries = 0;
sl@0
   941
sl@0
   942
    switch(FatType())
sl@0
   943
        {
sl@0
   944
        case EFat12:
sl@0
   945
        //-- invalidate whole cache; it is not worth making calculations for such small memory region.
sl@0
   946
        User::LeaveIfError(iCache->Invalidate());
sl@0
   947
        return;
sl@0
   948
sl@0
   949
        case EFat16:
sl@0
   950
        startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat16EntrySzLog2;
sl@0
   951
        numEntries = (invRegionLen + (sizeof(TFat16Entry)-1)) >> KFat16EntrySzLog2;
sl@0
   952
        break;
sl@0
   953
sl@0
   954
        case EFat32:
sl@0
   955
        startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat32EntrySzLog2;
sl@0
   956
        numEntries = (invRegionLen + (sizeof(TFat32Entry)-1)) >> KFat32EntrySzLog2;
sl@0
   957
        break;
sl@0
   958
sl@0
   959
        default:
sl@0
   960
        ASSERT(0);
sl@0
   961
        return;
sl@0
   962
        };
sl@0
   963
sl@0
   964
    if(startFatEntry < KFatFirstSearchCluster)
sl@0
   965
        {//-- FAT[0] and FAT[1] can't be legally accessed, they are reserved entries. We need to adjust region being refreshed.
sl@0
   966
        if(numEntries <= KFatFirstSearchCluster)
sl@0
   967
            return; //-- nothing to refresh
sl@0
   968
                    
sl@0
   969
        startFatEntry += KFatFirstSearchCluster;
sl@0
   970
        numEntries -= KFatFirstSearchCluster;
sl@0
   971
        }
sl@0
   972
sl@0
   973
    User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries));
sl@0
   974
	}
sl@0
   975
sl@0
   976
sl@0
   977
//-----------------------------------------------------------------------------
sl@0
   978
/**
sl@0
   979
    Initialize the object, create FAT cache if required
sl@0
   980
    @leave KErrNoMemory
sl@0
   981
*/
sl@0
   982
void CAtaFatTable::InitializeL()
sl@0
   983
	{
sl@0
   984
    __PRINT2(_L("CAtaFatTable::InitializeL() drv:%d, state%d"), iOwner->DriveNumber(), State());
sl@0
   985
    CFatTable::InitializeL();
sl@0
   986
sl@0
   987
    ASSERT(!iCache);
sl@0
   988
    ASSERT(State() == ENotInitialised);
sl@0
   989
    
sl@0
   990
    //-- create the FAT cache.
sl@0
   991
    CreateCacheL();
sl@0
   992
sl@0
   993
    SetState(EInitialised);
sl@0
   994
sl@0
   995
	}
sl@0
   996
sl@0
   997
//-----------------------------------------------------------------------------
sl@0
   998
/**
sl@0
   999
    Mount the FAT table to the CFatMountCB. Depending on mount parameters and configuration this method 
sl@0
  1000
    can do various things, like counting free clusters synchronously if data from FSInfo isn't valid, 
sl@0
  1001
    or setting up a FAT backround thread and return immediately etc.
sl@0
  1002
sl@0
  1003
    @param  aMountParam mounting parameters, like some data from FSInfo
sl@0
  1004
sl@0
  1005
*/
sl@0
  1006
void CAtaFatTable::MountL(const TMountParams& aMountParam)
sl@0
  1007
    {
sl@0
  1008
    __PRINT2(_L("CAtaFatTable::MountL() drv:%d, state:%d"), iOwner->DriveNumber(), State());
sl@0
  1009
sl@0
  1010
    ASSERT(State() == EInitialised);
sl@0
  1011
    SetState(EMounting);
sl@0
  1012
sl@0
  1013
    if(ipHelperThread)
sl@0
  1014
        {   
sl@0
  1015
        __PRINT(_L("CAtaFatTable::MountL() Helper thread is present!"));
sl@0
  1016
        ASSERT(0);
sl@0
  1017
        DestroyHelperThread();
sl@0
  1018
        }
sl@0
  1019
    
sl@0
  1020
sl@0
  1021
    //-- Check if we have valid data from FSInfo. In this case we don't need to count free clusters
sl@0
  1022
    if(aMountParam.iFsInfoValid)
sl@0
  1023
        {
sl@0
  1024
        ASSERT(IsFat32());
sl@0
  1025
        ASSERT(aMountParam.iFreeClusters <= MaxEntries());
sl@0
  1026
        
sl@0
  1027
        ASSERT(ClusterNumberValid(aMountParam.iFirstFreeCluster));
sl@0
  1028
sl@0
  1029
        SetFreeClusters(aMountParam.iFreeClusters);
sl@0
  1030
        SetFreeClusterHint(aMountParam.iFirstFreeCluster);
sl@0
  1031
sl@0
  1032
        __PRINT2(_L("CAtaFatTable::MountL() Using data from FSInfo sector. free clusters:%d, 1st free:%d"), FreeClusters(), FreeClusterHint());
sl@0
  1033
sl@0
  1034
        //-- We don't need to scan entire FAT to find out the number of free entries, because the data are taken from FSInfo.
sl@0
  1035
        //-- But if we are going to use the FAT32 bit supercache, we need to populate it. So, try to start up a special 
sl@0
  1036
        //-- populating thread.
sl@0
  1037
        CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
sl@0
  1038
        if(pFatBitCache)
sl@0
  1039
            {//-- bit cache is present, we need to populate (or repopulate it)
sl@0
  1040
            //-- create helper thread object and start the thread
sl@0
  1041
            ipHelperThread = CFat32BitCachePopulator::NewL(*this);
sl@0
  1042
sl@0
  1043
            ipHelperThread->Launch(); 
sl@0
  1044
            //-- background FAT bit cache populating thread is running now.
sl@0
  1045
            //-- the result of thread start up and completion isn't very interesting: If it fails to 
sl@0
  1046
            //-- properly populate the cache, nothing fatal will happen.
sl@0
  1047
            }
sl@0
  1048
sl@0
  1049
        //-- CFat32BitCachePopulator doesn't affect FAT table state. 
sl@0
  1050
        SetState(EMounted);
sl@0
  1051
        return; 
sl@0
  1052
        }
sl@0
  1053
sl@0
  1054
    //-- FSInfo data are invalid; we need to count free clusters by reading whole FAT table
sl@0
  1055
    //-- This method can optionally create a background thread (that will count free clusters) and return immideately.
sl@0
  1056
    CountFreeClustersL();
sl@0
  1057
    }
sl@0
  1058
sl@0
  1059
//-----------------------------------------------------------------------------
sl@0
  1060
sl@0
  1061
/**
sl@0
  1062
    Decrements the free cluster count. This is an overridden method with synchronisation.
sl@0
  1063
    @param  aCount a number of clusters 
sl@0
  1064
*/
sl@0
  1065
void CAtaFatTable::DecrementFreeClusterCount(TUint32 aCount)
sl@0
  1066
    {
sl@0
  1067
    XAutoLock lock(iOwner); //-- enter critical section
sl@0
  1068
    CFatTable::DecrementFreeClusterCount(aCount);
sl@0
  1069
    }
sl@0
  1070
sl@0
  1071
/**
sl@0
  1072
    Increments the free cluster count.  This is an overridden method with synchronisation.
sl@0
  1073
    @param  aCount a number of clusters 
sl@0
  1074
*/
sl@0
  1075
void CAtaFatTable::IncrementFreeClusterCount(TUint32 aCount)
sl@0
  1076
    {
sl@0
  1077
    XAutoLock lock(iOwner); //-- enter critical section
sl@0
  1078
    CFatTable::IncrementFreeClusterCount(aCount);
sl@0
  1079
    }
sl@0
  1080
sl@0
  1081
//-----------------------------------------------------------------------------
sl@0
  1082
sl@0
  1083
/**
sl@0
  1084
    Obtain number of free clusters on the volume. This is an overridden method.
sl@0
  1085
    Depending on the "aSyncOperation" parameter this operation can be fully synhronous (exact number of free clusters ) or asynchronous
sl@0
  1086
    (current number of free clusters) if the FAT scanning thread is still running.
sl@0
  1087
sl@0
  1088
    @param aSyncOperation if ETrue, this method will wait until FAT scan thread finishes and return exact number of free clusters
sl@0
  1089
                          if false, it will return current number of free clusters counted by FAT scan thread if it hasn't finished yet.  
sl@0
  1090
    
sl@0
  1091
    @return Number of free clusters. See also CAtaFatTable::RequestFreeClusters()
sl@0
  1092
*/
sl@0
  1093
TUint32 CAtaFatTable::NumberOfFreeClusters(TBool aSyncOperation/*=EFalse*/) const
sl@0
  1094
    {
sl@0
  1095
    if(ipHelperThread && ipHelperThread->ThreadWorking() && ipHelperThread->Type() == CFatHelperThreadBase::EFreeSpaceScanner)
sl@0
  1096
        {//-- here we have running helper thread that counts free entries in FAT.
sl@0
  1097
        //-- if this operation is synchronous, we need to wait until it finish its job in order to get _exact_ number of free cluster,
sl@0
  1098
        //-- not currently counted  
sl@0
  1099
        
sl@0
  1100
        //__PRINT2(_L("#- CAtaFatTable::NumberOfFreeClusters(), drv:%d enter, sync:%d"), iOwner->DriveNumber(), aSyncOperation);
sl@0
  1101
sl@0
  1102
        if(aSyncOperation)
sl@0
  1103
            {//-- wait for background scanning thread to finish counting free clusters if this operation is synchronous
sl@0
  1104
            ipHelperThread->BoostPriority(ETrue);
sl@0
  1105
            ipHelperThread->WaitToFinish();
sl@0
  1106
            }
sl@0
  1107
        
sl@0
  1108
        XAutoLock lock(iOwner); //-- enter critical section
sl@0
  1109
        
sl@0
  1110
        const TUint32 freeClusters = FreeClusters();
sl@0
  1111
        //__PRINT2(_L("#- CAtaFatTable::NumberOfFreeClusters(), drv:%d Exit, clusters:%d"), iOwner->DriveNumber(), freeClusters);
sl@0
  1112
        return freeClusters;
sl@0
  1113
        }
sl@0
  1114
sl@0
  1115
    return FreeClusters();
sl@0
  1116
sl@0
  1117
    }
sl@0
  1118
sl@0
  1119
//-----------------------------------------------------------------------------
sl@0
  1120
sl@0
  1121
/** 
sl@0
  1122
    Set free cluster count. This is an overridden method with synchronisation. 
sl@0
  1123
    @param aFreeClusters new value of free clusters
sl@0
  1124
*/
sl@0
  1125
void CAtaFatTable::SetFreeClusters(TUint32 aFreeClusters)
sl@0
  1126
    {   
sl@0
  1127
    XAutoLock lock(iOwner); //-- enter critical section
sl@0
  1128
    CFatTable::SetFreeClusters(aFreeClusters);
sl@0
  1129
    }
sl@0
  1130
sl@0
  1131
/** 
sl@0
  1132
    This is an overridden method with synchronisation. 
sl@0
  1133
    @return the last known free cluster number.
sl@0
  1134
*/
sl@0
  1135
TUint32 CAtaFatTable::FreeClusterHint() const 
sl@0
  1136
    {
sl@0
  1137
    XAutoLock lock(iOwner); //-- enter critical section
sl@0
  1138
    return CFatTable::FreeClusterHint();
sl@0
  1139
    } 
sl@0
  1140
sl@0
  1141
/** Set next free cluster number. This is an overridden method with synchronisation. */
sl@0
  1142
void CAtaFatTable::SetFreeClusterHint(TUint32 aCluster) 
sl@0
  1143
    {
sl@0
  1144
    XAutoLock lock(iOwner); //-- enter critical section
sl@0
  1145
    CFatTable::SetFreeClusterHint(aCluster);
sl@0
  1146
    } 
sl@0
  1147
sl@0
  1148
/**
sl@0
  1149
    @return ETrue if the state of the object is consistent; i.e. it is 
sl@0
  1150
    fully constructed, valid and the amount of free entries is known.
sl@0
  1151
    Used in the case of asynchronous mounting.
sl@0
  1152
*/
sl@0
  1153
TBool CAtaFatTable::ConsistentState() const
sl@0
  1154
    {
sl@0
  1155
    return State() == EMounted;
sl@0
  1156
    }
sl@0
  1157
sl@0
  1158
//-----------------------------------------------------------------------------
sl@0
  1159
sl@0
  1160
/**
sl@0
  1161
    Request for the raw write access to the FAT area (all copies of FAT).
sl@0
  1162
    If FAT helper thread is running, waits until it finishes.
sl@0
  1163
sl@0
  1164
    @param  aPos absolute media position we are going to write to. Be careful with casting it from TInt64 and losing high word.
sl@0
  1165
    @param  aLen length of the area being written
sl@0
  1166
*/
sl@0
  1167
void CAtaFatTable::RequestRawWriteAccess(TInt64 aPos, TUint32 aLen) const
sl@0
  1168
    {
sl@0
  1169
    if(I64HIGH(aPos))
sl@0
  1170
        return;
sl@0
  1171
sl@0
  1172
    const TUint32 pos32 = I64LOW(aPos);
sl@0
  1173
    const TUint32 posFatStart = iOwner->StartOfFatInBytes(); //-- position of the FAT start on the volume
sl@0
  1174
    const TUint32 posFatsEnd  = posFatStart + iOwner->NumberOfFats()*iOwner->FatSizeInBytes();  //-- position of the ent of ALL FATs
sl@0
  1175
sl@0
  1176
    if(pos32 >= posFatsEnd || (pos32+aLen) <= posFatStart)
sl@0
  1177
        return;
sl@0
  1178
sl@0
  1179
    __PRINT2(_L("#=- CAtaFatTable::RequestRawWriteAccess() pos:%d, len:%d"),pos32, aLen);
sl@0
  1180
sl@0
  1181
    //-- someone tries to write to FAT area directly. Wait for the FAT helper thread to finish
sl@0
  1182
    if(ipHelperThread)
sl@0
  1183
        ipHelperThread->WaitToFinish();     
sl@0
  1184
sl@0
  1185
    }
sl@0
  1186
sl@0
  1187
//-----------------------------------------------------------------------------
sl@0
  1188
sl@0
  1189
/**
sl@0
  1190
    Checks if we have at least "aClustersRequired" clusters free in the FAT.
sl@0
  1191
    If FAT scannng thread is running, waits until requested number of free clusters counted or the thread finishes.
sl@0
  1192
sl@0
  1193
    @param  aClustersRequired number of free clusters required
sl@0
  1194
    @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
sl@0
  1195
*/
sl@0
  1196
TBool CAtaFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
sl@0
  1197
    {
sl@0
  1198
    //__PRINT1(_L("#- CAtaFatTable::RequestFreeClusters(%d)"),aClustersRequired);
sl@0
  1199
    ASSERT(aClustersRequired >0);
sl@0
  1200
sl@0
  1201
    if(!ipHelperThread || !ipHelperThread->ThreadWorking() || ipHelperThread->Type() != CFatHelperThreadBase::EFreeSpaceScanner)
sl@0
  1202
        {//-- there is no FAT free space scan thread running, number of free entries can't increase in background
sl@0
  1203
        return (FreeClusters() >= aClustersRequired); //-- use simple, non-thread safe method
sl@0
  1204
        }     
sl@0
  1205
sl@0
  1206
    //-- FAT free space scan thread is running, counting free FAT entries. wait until it has counted enough or finish.
sl@0
  1207
    ASSERT(ipHelperThread->Type() == CFatHelperThreadBase::EFreeSpaceScanner);
sl@0
  1208
    
sl@0
  1209
    TUint32 currFreeClusters;
sl@0
  1210
    const TUint KWaitGranularity = 20*K1mSec; //-- wait granularity
sl@0
  1211
    
sl@0
  1212
    ipHelperThread->BoostPriority(ETrue); //-- increase thread priority
sl@0
  1213
sl@0
  1214
    for(;;)
sl@0
  1215
        {
sl@0
  1216
        currFreeClusters = NumberOfFreeClusters(EFalse); //-- get _current_ number of free clusters asynchronously
sl@0
  1217
        if(currFreeClusters >= aClustersRequired)
sl@0
  1218
            break; //-- OK, the request is satisfied
sl@0
  1219
sl@0
  1220
        if(!ipHelperThread->ThreadWorking())
sl@0
  1221
            {//-- the thread has finished its work
sl@0
  1222
            currFreeClusters = NumberOfFreeClusters(EFalse); //-- get _current_ number of free clusters asynchronously
sl@0
  1223
            break; 
sl@0
  1224
            }
sl@0
  1225
sl@0
  1226
        User::After(KWaitGranularity); //-- wait some time allowing FAT scanning thread to count free clusters.     
sl@0
  1227
        }
sl@0
  1228
sl@0
  1229
    ipHelperThread->BoostPriority(EFalse); //-- set thread priority back to normal
sl@0
  1230
    //__PRINT1(_L("#- CAtaFatTable::RequestFreeClusters() #2 curr:%d"),currFreeClusters);
sl@0
  1231
    
sl@0
  1232
    return (currFreeClusters >= aClustersRequired);
sl@0
  1233
sl@0
  1234
    }
sl@0
  1235
sl@0
  1236
//-----------------------------------------------------------------------------
sl@0
  1237
sl@0
  1238
/**
sl@0
  1239
    Parse a buffer filled with FAT16 or FAT32 entries, counting free clusters and looking for the firs free cluster number.
sl@0
  1240
    Note that this method can be called from a helper FAT scan thread.
sl@0
  1241
sl@0
  1242
    @param  aBuf        FAT buffer descriptor. Must contain whole number of FAT16 or FAT32 entries
sl@0
  1243
    @param aScanParam   the structure to be filled with values, like number of counted free and non-free clusters, etc.
sl@0
  1244
*/
sl@0
  1245
void CAtaFatTable::DoParseFatBuf(const TPtrC8& aBuf, TFatScanParam& aScanParam) const
sl@0
  1246
    {
sl@0
  1247
    
sl@0
  1248
    if(IsFat16())
sl@0
  1249
        {//-- we are processing a buffer of FAT16 entries
sl@0
  1250
        ASSERT(!ipHelperThread);
sl@0
  1251
        ASSERT((aBuf.Size() & (sizeof(TFat16Entry)-1)) == 0);
sl@0
  1252
        const TInt KNumEntries = aBuf.Size() >> KFat16EntrySzLog2; 
sl@0
  1253
        const TFat16Entry* const pFatEntry = (const TFat16Entry*)(aBuf.Ptr()); 
sl@0
  1254
sl@0
  1255
        for(TInt i=0; i<KNumEntries; ++i)
sl@0
  1256
            {
sl@0
  1257
            if(aScanParam.iEntriesScanned >= KFatFirstSearchCluster)
sl@0
  1258
                {
sl@0
  1259
                const TFat16Entry entry = pFatEntry[i];
sl@0
  1260
sl@0
  1261
                if(entry == KSpareCluster)
sl@0
  1262
                    {//-- found a free FAT entry
sl@0
  1263
                    aScanParam.iCurrFreeEntries++;
sl@0
  1264
                    
sl@0
  1265
                    if(aScanParam.iFirstFree < KFatFirstSearchCluster)
sl@0
  1266
                        aScanParam.iFirstFree = aScanParam.iEntriesScanned;    
sl@0
  1267
sl@0
  1268
                    }
sl@0
  1269
                 else
sl@0
  1270
                    {//-- found occupied FAT entry, count bad clusters as well 
sl@0
  1271
                    aScanParam.iCurrOccupiedEntries++;
sl@0
  1272
                    }
sl@0
  1273
sl@0
  1274
                }
sl@0
  1275
sl@0
  1276
            aScanParam.iEntriesScanned++;
sl@0
  1277
            }
sl@0
  1278
        }//if(IsFat16())
sl@0
  1279
    else
sl@0
  1280
    if(IsFat32())
sl@0
  1281
        {//-- we are processing a buffer of FAT32 entries.
sl@0
  1282
         //-- note that here we can be in the context of the FAT free entries scan thread.   
sl@0
  1283
        ASSERT((aBuf.Size() & (sizeof(TFat32Entry)-1)) == 0);
sl@0
  1284
        
sl@0
  1285
        //-- pointer to the FAT32 bit supercache. If present, we will populate it here
sl@0
  1286
        CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
sl@0
  1287
sl@0
  1288
        const TInt KNumEntries = aBuf.Size() >> KFat32EntrySzLog2;
sl@0
  1289
        const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr()); 
sl@0
  1290
sl@0
  1291
        for(TInt i=0; i<KNumEntries; ++i)
sl@0
  1292
            {
sl@0
  1293
              if(aScanParam.iEntriesScanned >= KFatFirstSearchCluster)
sl@0
  1294
                {
sl@0
  1295
                const TFat32Entry entry = pFatEntry[i] & KFat32EntryMask;
sl@0
  1296
sl@0
  1297
                if(entry == KSpareCluster)
sl@0
  1298
                    {//-- found a free FAT32 entry
sl@0
  1299
                    ++aScanParam.iCurrFreeEntries;
sl@0
  1300
                    
sl@0
  1301
                    if(aScanParam.iFirstFree < KFatFirstSearchCluster)
sl@0
  1302
                        aScanParam.iFirstFree = aScanParam.iEntriesScanned;    
sl@0
  1303
sl@0
  1304
                    
sl@0
  1305
                    //-- feed the information about free FAT entry at index aClustersScanned to the FAT bit supercache. 
sl@0
  1306
                    if(pFatBitCache)
sl@0
  1307
                        {
sl@0
  1308
                        pFatBitCache->SetFreeFatEntry(aScanParam.iEntriesScanned);
sl@0
  1309
                        }
sl@0
  1310
sl@0
  1311
                    
sl@0
  1312
                    }//if(entry == KSpareCluster)
sl@0
  1313
                    else
sl@0
  1314
                        {//-- found occupied FAT32 entry, count bad clusters as well
sl@0
  1315
                        aScanParam.iCurrOccupiedEntries++;
sl@0
  1316
                        }
sl@0
  1317
                }
sl@0
  1318
sl@0
  1319
            ++aScanParam.iEntriesScanned;
sl@0
  1320
            }
sl@0
  1321
sl@0
  1322
        }//if(IsFat32())
sl@0
  1323
    else
sl@0
  1324
        {
sl@0
  1325
        ASSERT(0);
sl@0
  1326
        }
sl@0
  1327
    }
sl@0
  1328
sl@0
  1329
//-----------------------------------------------------------------------------
sl@0
  1330
sl@0
  1331
/**
sl@0
  1332
    Count free clusters in FAT16 or FAT32. Uses relatively large buffer to read FAT entries into; 
sl@0
  1333
    This is faster than usual ReadL() calls.
sl@0
  1334
*/
sl@0
  1335
void CAtaFatTable::DoCountFreeClustersL()
sl@0
  1336
    {
sl@0
  1337
    __PRINT2(_L("#- CAtaFatTable::DoCountFreeClustersL() drv:%d, state:%d"), iOwner->DriveNumber(), State());
sl@0
  1338
    
sl@0
  1339
    if(!IsFat16() && !IsFat32())
sl@0
  1340
        {
sl@0
  1341
        ASSERT(0);
sl@0
  1342
        User::Leave(KErrNotSupported);
sl@0
  1343
        }
sl@0
  1344
sl@0
  1345
    const TUint32 KFat1StartPos = iOwner->StartOfFatInBytes();
sl@0
  1346
    const TUint32 KNumClusters  = MaxEntries(); //-- FAT[0] & FAT[1] are reserved and not counted by UsableClusters()
sl@0
  1347
    const TUint32 KNumFATs      = iOwner->NumberOfFats();
sl@0
  1348
    const TUint32 KFatSize      = KNumClusters * (IsFat32() ? sizeof(TFat32Entry) : sizeof(TFat16Entry)); //-- usable size of one FAT.
sl@0
  1349
sl@0
  1350
    (void)KNumFATs;
sl@0
  1351
sl@0
  1352
    ASSERT(KFat1StartPos >= 1*KDefaultSectorSize);
sl@0
  1353
    ASSERT(KNumClusters > KFatFirstSearchCluster);
sl@0
  1354
    ASSERT(KNumFATs > 0);
sl@0
  1355
sl@0
  1356
    const TUint32 KFatBufSz = 32*K1KiloByte; //-- buffer size for FAT reading. 32K seems to be optimal size
sl@0
  1357
sl@0
  1358
    __ASSERT_COMPILE((KFatBufSz % sizeof(TFat32Entry)) == 0);
sl@0
  1359
    __ASSERT_COMPILE((KFatBufSz % sizeof(TFat16Entry)) == 0);   
sl@0
  1360
sl@0
  1361
    RBuf8 buf;
sl@0
  1362
    CleanupClosePushL(buf);
sl@0
  1363
sl@0
  1364
    //-- allocate memory for FAT parse buffer
sl@0
  1365
    buf.CreateMaxL(KFatBufSz);
sl@0
  1366
sl@0
  1367
    //-- read FAT into the large buffer and parse it
sl@0
  1368
    TUint32 rem = KFatSize;
sl@0
  1369
    TUint32 mediaPos = KFat1StartPos;   
sl@0
  1370
        
sl@0
  1371
    //-- prepare FAT bit supercache to being populated.
sl@0
  1372
    //-- actual populating will happen in ::DoParseFatBuf()
sl@0
  1373
    CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
sl@0
  1374
sl@0
  1375
    if(pFatBitCache)
sl@0
  1376
        {
sl@0
  1377
        pFatBitCache->StartPopulating();
sl@0
  1378
        }
sl@0
  1379
sl@0
  1380
    TFatScanParam fatScanParam;
sl@0
  1381
sl@0
  1382
    //-- used for measuring time
sl@0
  1383
    TTime   timeStart;
sl@0
  1384
    TTime   timeEnd;
sl@0
  1385
    timeStart.UniversalTime(); //-- take start time
sl@0
  1386
sl@0
  1387
sl@0
  1388
    while(rem)
sl@0
  1389
        {
sl@0
  1390
        const TUint32 bytesToRead=Min(rem, KFatBufSz);
sl@0
  1391
        TPtrC8 ptrData(buf.Ptr(), bytesToRead);
sl@0
  1392
        
sl@0
  1393
        //__PRINT2(_L("#=--- CAtaFatTable::DoCountFreeClustersL() read %d bytes pos:0x%x"), bytesToRead, (TUint32)mediaPos);
sl@0
  1394
        User::LeaveIfError(iOwner->LocalDrive()->Read(mediaPos, bytesToRead, buf)); 
sl@0
  1395
        
sl@0
  1396
        DoParseFatBuf(ptrData, fatScanParam);
sl@0
  1397
sl@0
  1398
        mediaPos += bytesToRead;
sl@0
  1399
        rem -= bytesToRead;
sl@0
  1400
        }
sl@0
  1401
sl@0
  1402
    //-- here fatScanParam contains values for the whole FAT. 
sl@0
  1403
    
sl@0
  1404
    timeEnd.UniversalTime(); //-- take end time
sl@0
  1405
    const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
sl@0
  1406
    (void)msScanTime;
sl@0
  1407
    __PRINT1(_L("#- CAtaFatTable::DoCountFreeClustersL() finished. Taken:%d ms "), msScanTime);
sl@0
  1408
    
sl@0
  1409
sl@0
  1410
    //-- tell FAT bit cache that we have finished populating it
sl@0
  1411
    if(pFatBitCache)
sl@0
  1412
        {
sl@0
  1413
        pFatBitCache->FinishPopulating(ETrue);
sl@0
  1414
        pFatBitCache->Dump();
sl@0
  1415
        }
sl@0
  1416
sl@0
  1417
    if(!fatScanParam.iFirstFree)//-- haven't found free clusters on the volume
sl@0
  1418
        fatScanParam.iFirstFree = KFatFirstSearchCluster;
sl@0
  1419
sl@0
  1420
    ASSERT(fatScanParam.iCurrFreeEntries <= iOwner->UsableClusters());
sl@0
  1421
    ASSERT(ClusterNumberValid(fatScanParam.iFirstFree));
sl@0
  1422
    
sl@0
  1423
    SetFreeClusters(fatScanParam.iCurrFreeEntries);
sl@0
  1424
    SetFreeClusterHint(fatScanParam.iFirstFree);
sl@0
  1425
sl@0
  1426
    CleanupStack::PopAndDestroy(&buf); 
sl@0
  1427
    }
sl@0
  1428
sl@0
  1429
//-----------------------------------------------------------------------------
sl@0
  1430
sl@0
  1431
/**
sl@0
  1432
    Count free clusters on the volume.
sl@0
  1433
    Depending on FAT type can count clusters synchronously or start a thread to do it in background.
sl@0
  1434
*/
sl@0
  1435
void CAtaFatTable::CountFreeClustersL()
sl@0
  1436
    {
sl@0
  1437
    __PRINT3(_L("#=- CAtaFatTable::CountFreeClustersL() drv:%d, FAT%d, state:%d"),iOwner->DriveNumber(),FatType(), State());
sl@0
  1438
    
sl@0
  1439
    ASSERT(State() == EMounting);
sl@0
  1440
    ASSERT(!ipHelperThread);
sl@0
  1441
sl@0
  1442
    TInt nRes;
sl@0
  1443
sl@0
  1444
    switch(FatType())
sl@0
  1445
        {
sl@0
  1446
        case EFat12: //-- use old default scanning, it is synchronous
sl@0
  1447
        CFatTable::CountFreeClustersL();
sl@0
  1448
        SetState(EMounted);
sl@0
  1449
        break;
sl@0
  1450
           
sl@0
  1451
        case EFat16: //-- enhanced FAT scan, but still synchronous
sl@0
  1452
            TRAP(nRes, DoCountFreeClustersL());
sl@0
  1453
            if(nRes !=KErrNone) 
sl@0
  1454
                {
sl@0
  1455
                CFatTable::CountFreeClustersL(); //-- fall back to the legacy method
sl@0
  1456
                }
sl@0
  1457
sl@0
  1458
            SetState(EMounted);
sl@0
  1459
        break;
sl@0
  1460
   
sl@0
  1461
        case EFat32: //-- This is FAT32, try to set up a FAT scanning thread if allowed
sl@0
  1462
            {
sl@0
  1463
                TBool bFat32BkGndScan = ETrue; //-- if true, we will try to start up a background scanning thread.
sl@0
  1464
sl@0
  1465
                //-- 1. check if background FAT scanning is disabled in config
sl@0
  1466
                if(!iOwner->FatConfig().FAT32_AsynchMount())
sl@0
  1467
                {
sl@0
  1468
                    __PRINT(_L("#=- FAT32 BkGnd scan is disabled in config."));
sl@0
  1469
                    bFat32BkGndScan = EFalse;
sl@0
  1470
                }
sl@0
  1471
sl@0
  1472
                //-- 2. check if background FAT scanning is disabled by test interface
sl@0
  1473
#ifdef _DEBUG
sl@0
  1474
                TInt nMntDebugFlags;
sl@0
  1475
                if(bFat32BkGndScan && RProperty::Get(KSID_Test1, iOwner->DriveNumber(), nMntDebugFlags) == KErrNone)
sl@0
  1476
                {//-- test property for this drive is defined
sl@0
  1477
                    if(nMntDebugFlags & KMntDisable_FatBkGndScan)
sl@0
  1478
                    {
sl@0
  1479
                    __PRINT(_L("#- FAT32 BkGnd scan is disabled is disabled by debug interface."));
sl@0
  1480
                    bFat32BkGndScan = EFalse;
sl@0
  1481
                    }
sl@0
  1482
            
sl@0
  1483
                }
sl@0
  1484
#endif
sl@0
  1485
                //-- 3. try to start FAT32 free entries scanning thread.
sl@0
  1486
                if(bFat32BkGndScan)
sl@0
  1487
                {
sl@0
  1488
                    __PRINT(_L("#=- Starting up FAT32 free entries scanner thread..."));
sl@0
  1489
                    TRAP(nRes, DoLaunchFat32FreeSpaceScanThreadL());
sl@0
  1490
                    if(nRes == KErrNone) 
sl@0
  1491
                        break; //-- let thread run by itself
sl@0
  1492
sl@0
  1493
                    //-- DoLaunchFat32FreeSpaceScanThreadL() has set this object state.
sl@0
  1494
                }
sl@0
  1495
sl@0
  1496
            //-- we either failed to launch the thread or this feature was disabled somehow. Fall back to the synchronous scan.
sl@0
  1497
            TRAP(nRes, DoCountFreeClustersL());
sl@0
  1498
            if(nRes !=KErrNone) 
sl@0
  1499
                {
sl@0
  1500
                CFatTable::CountFreeClustersL(); //-- fall back to the legacy method
sl@0
  1501
                }
sl@0
  1502
sl@0
  1503
             SetState(EMounted);
sl@0
  1504
            }//case EFat32
sl@0
  1505
        break;
sl@0
  1506
   
sl@0
  1507
        default:
sl@0
  1508
            ASSERT(0);
sl@0
  1509
        break;
sl@0
  1510
sl@0
  1511
        } //switch(FatType())
sl@0
  1512
    }
sl@0
  1513
sl@0
  1514
//-----------------------------------------------------------------------------
sl@0
  1515
sl@0
  1516
/** 
sl@0
  1517
    Set up and start FAT scan thread.
sl@0
  1518
    Leaves on error.
sl@0
  1519
*/
sl@0
  1520
void CAtaFatTable::DoLaunchFat32FreeSpaceScanThreadL()
sl@0
  1521
    {
sl@0
  1522
    __PRINT2(_L("#=- CAtaFatTable::DoLaunchFat32FreeSpaceScanThreadL() drv:%d, state:%d"),iOwner->DriveNumber(), State());
sl@0
  1523
    ASSERT(State() == EMounting);
sl@0
  1524
sl@0
  1525
    //-- 1. check if something is already working (shan't be!)
sl@0
  1526
    if(ipHelperThread)
sl@0
  1527
        {
sl@0
  1528
        if(ipHelperThread->ThreadWorking())
sl@0
  1529
            {
sl@0
  1530
            __PRINT(_L("#=- CAtaFatTable::DoLaunchScanThread() some thread is already running ?"));
sl@0
  1531
            ASSERT(0);
sl@0
  1532
            User::Leave(KErrAlreadyExists);
sl@0
  1533
            }
sl@0
  1534
sl@0
  1535
        DestroyHelperThread();        
sl@0
  1536
        }
sl@0
  1537
sl@0
  1538
    //-- 2. create helper thread object and start the thread
sl@0
  1539
    ipHelperThread = CFat32FreeSpaceScanner::NewL(*this);
sl@0
  1540
    
sl@0
  1541
    SetState(EFreeClustersScan);
sl@0
  1542
    
sl@0
  1543
    ipHelperThread->Launch(); 
sl@0
  1544
    //-- background FAT scanning thread is running now
sl@0
  1545
    }
sl@0
  1546
sl@0
  1547
//-----------------------------------------------------------------------------
sl@0
  1548
/**
sl@0
  1549
    Read an entry from the FAT table
sl@0
  1550
sl@0
  1551
    @param aFatIndex FAT entry number to read
sl@0
  1552
    @return FAT entry value
sl@0
  1553
*/
sl@0
  1554
TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const
sl@0
  1555
    {
sl@0
  1556
    if(!ClusterNumberValid(aFatIndex))
sl@0
  1557
        {
sl@0
  1558
        //ASSERT(0); //-- deliberately corrupted (by some tests) DOS directory entries can have 0 in the "first cluster" field.
sl@0
  1559
        __PRINT1(_L("CAtaFatTable::ReadL(%d) bad Index!"), aFatIndex);
sl@0
  1560
        User::Leave(KErrCorrupt);
sl@0
  1561
        }
sl@0
  1562
sl@0
  1563
sl@0
  1564
    const TUint entry = iCache->ReadEntryL(aFatIndex);
sl@0
  1565
    return entry;
sl@0
  1566
    }
sl@0
  1567
sl@0
  1568
sl@0
  1569
//-----------------------------------------------------------------------------
sl@0
  1570
/**
sl@0
  1571
    Write an entry to the FAT table
sl@0
  1572
sl@0
  1573
    @param aFatIndex    aFatIndex FAT entry number to write
sl@0
  1574
    @param aValue       FAT entry to write
sl@0
  1575
    @leave 
sl@0
  1576
*/
sl@0
  1577
void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
sl@0
  1578
	{
sl@0
  1579
sl@0
  1580
    __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue);
sl@0
  1581
    
sl@0
  1582
    if(!ClusterNumberValid(aFatIndex))
sl@0
  1583
        {
sl@0
  1584
        ASSERT(0); 
sl@0
  1585
        User::Leave(KErrCorrupt);
sl@0
  1586
        }
sl@0
  1587
    
sl@0
  1588
    if(aValue != KSpareCluster && (aValue < KFatFirstSearchCluster || aValue > KFat32EntryMask))
sl@0
  1589
        {
sl@0
  1590
        ASSERT(0);
sl@0
  1591
        User::Leave(KErrCorrupt);
sl@0
  1592
        }
sl@0
  1593
sl@0
  1594
    //-- wait until we are allowed to write FAT entry
sl@0
  1595
    if(ipHelperThread && ipHelperThread->ThreadWorking())
sl@0
  1596
        {
sl@0
  1597
        ASSERT(ipHelperThread->ThreadId() != RThread().Id()); //-- this method must not be called the FAT helper thread	    
sl@0
  1598
        ipHelperThread->RequestFatEntryWriteAccess(aFatIndex);
sl@0
  1599
        }
sl@0
  1600
sl@0
  1601
    //-- write entry to the FAT through FAT cache
sl@0
  1602
    iCache->WriteEntryL(aFatIndex, aValue);
sl@0
  1603
sl@0
  1604
    
sl@0
  1605
    //-- if we are writing "spare" FAT entry, tell FAT bit supercache about it.
sl@0
  1606
    //-- it will store the information that corresponding FAT cache sector has a spare FAT entry.
sl@0
  1607
    //-- writing non-spare FAT entry doesn't mean anything: that FAT cache sector might or might not contain free entries.
sl@0
  1608
    if(aValue == KSpareCluster && iCache->BitCacheInterface())
sl@0
  1609
        {
sl@0
  1610
            CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
sl@0
  1611
            const CFatBitCache::TState cacheState= pFatBitCache->State();
sl@0
  1612
            if(cacheState == CFatBitCache::EPopulated || cacheState == CFatBitCache::EPopulating)
sl@0
  1613
            {//-- bit cache is either normally populated or being populated by one of the helper threads
sl@0
  1614
            if(ipHelperThread && ipHelperThread->ThreadWorking())    
sl@0
  1615
                {
sl@0
  1616
                //-- here we have a multithreading issue. Helper FAT thread can be parsing FAT and optionally calling ReportFreeFatEntry(..) as well.
sl@0
  1617
                //-- in this case we need either to suspend the helper thread in order to prevent corruption of the FAT bit cache data,
sl@0
  1618
                //-- or ignore this call and rely on the fact that the FAT bit supercache is a kind of self-learning and the missing data will be
sl@0
  1619
                //-- fixed during conflict resolution (this can lead to performance degradation).
sl@0
  1620
sl@0
  1621
                //-- ok, suspend the helper thread while we are changing data in the bit cache
sl@0
  1622
                AcquireLock();
sl@0
  1623
                ipHelperThread->Suspend();
sl@0
  1624
                    pFatBitCache->SetFreeFatEntry(aFatIndex);
sl@0
  1625
                ipHelperThread->Resume();
sl@0
  1626
                ReleaseLock();
sl@0
  1627
sl@0
  1628
                }
sl@0
  1629
            else
sl@0
  1630
                {//-- no one else is accessing FAT in this time
sl@0
  1631
                ASSERT(pFatBitCache->UsableState());
sl@0
  1632
                pFatBitCache->SetFreeFatEntry(aFatIndex);
sl@0
  1633
                }
sl@0
  1634
            }
sl@0
  1635
sl@0
  1636
        }//if(aValue == KSpareCluster)
sl@0
  1637
sl@0
  1638
    }
sl@0
  1639
sl@0
  1640
//-----------------------------------------------------------------------------
sl@0
  1641
/**
sl@0
  1642
    This is an overridden method from CFatTable. See CFatTable::FindClosestFreeClusterL(...)
sl@0
  1643
    Does the same, i.e looks for the closest to "aCluster" free FAT entry, but more advanced,
sl@0
  1644
    it can use FAT bit supercache for quick lookup.
sl@0
  1645
sl@0
  1646
    @param aCluster Cluster to find nearest free cluster to.
sl@0
  1647
    @leave KErrDiskFull + system wide error codes
sl@0
  1648
    @return cluster number found
sl@0
  1649
*/
sl@0
  1650
TUint32 CAtaFatTable::FindClosestFreeClusterL(TUint32 aCluster)
sl@0
  1651
    {
sl@0
  1652
    __PRINT2(_L("CAtaFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
sl@0
  1653
sl@0
  1654
    if(!ClusterNumberValid(aCluster))
sl@0
  1655
        {
sl@0
  1656
        ASSERT(0);
sl@0
  1657
        User::Leave(KErrCorrupt);
sl@0
  1658
        }
sl@0
  1659
sl@0
  1660
sl@0
  1661
    if(!RequestFreeClusters(1))
sl@0
  1662
	    {//-- there is no at least 1 free cluster available
sl@0
  1663
    	__PRINT(_L("CAtaFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
sl@0
  1664
        User::Leave(KErrDiskFull);
sl@0
  1665
        }
sl@0
  1666
sl@0
  1667
    //-- check if we have FAT bit supercache and it is in consistent state
sl@0
  1668
    CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
sl@0
  1669
    if(!pFatBitCache)
sl@0
  1670
        return CFatTable::FindClosestFreeClusterL(aCluster); //-- fall back to the old search method
sl@0
  1671
sl@0
  1672
    ASSERT(IsFat32());
sl@0
  1673
sl@0
  1674
    if(!pFatBitCache->UsableState())
sl@0
  1675
        {
sl@0
  1676
        //__PRINT(_L("#++ CAtaFatTable::FindClosestFreeClusterL() FAT bit cache isn't consistent!"));
sl@0
  1677
        return CFatTable::FindClosestFreeClusterL(aCluster); //-- fall back to the old search method
sl@0
  1678
        }
sl@0
  1679
sl@0
  1680
    //-- ask FAT bit supercache to find us FAT cache sector (closest to the aCluster) that contains free FAT entries.
sl@0
  1681
    //__PRINT2(_L("#++ CAtaFatTable::FindClosestFreeClusterL(%d) hint free cl:%d"), aCluster, FreeClusterHint());
sl@0
  1682
    
sl@0
  1683
    const TInt KMaxLookupRetries = 2;
sl@0
  1684
    for(TInt i=0; i<KMaxLookupRetries; ++i)
sl@0
  1685
        {
sl@0
  1686
        const TInt nRes = pFatBitCache->FindClosestFreeFatEntry(aCluster);
sl@0
  1687
        switch(nRes)
sl@0
  1688
            {
sl@0
  1689
            case KErrNone:
sl@0
  1690
            //-- FAT bit supercache has found a free FAT entry in the FAT32 cache
sl@0
  1691
            //__PRINT1(_L("#++ CAtaFatTable::FindClosestFreeClusterL FOUND! cl:%d"), aCluster);
sl@0
  1692
            
sl@0
  1693
            ASSERT(ClusterNumberValid(aCluster));
sl@0
  1694
sl@0
  1695
            //-- do not update the last known free cluster, it can be quite expensive.
sl@0
  1696
            //-- do it in the caller method with bigger granularity.
sl@0
  1697
            return aCluster;        
sl@0
  1698
sl@0
  1699
            case KErrNotFound:
sl@0
  1700
            //-- there was a bit cache conflict, when FAT cache sector is marked as having free FAT entries, but it doesn't have them in reality.
sl@0
  1701
            //-- It can happen because FAT bit cache entry is marked '1' only on populating the bit vector or if someone writes KSpareCluster into the 
sl@0
  1702
            //-- corresponding FAT cache sector. Such conflict can happen quite often.
sl@0
  1703
            //-- Try search again, the search is very likely to succeed very close, because the FAT bit cache entry had already been fixed as the result of conflict resolution.
sl@0
  1704
            break;
sl@0
  1705
sl@0
  1706
            case KErrCorrupt: 
sl@0
  1707
            //-- pFatBitCache->FindClosestFreeFatEntry failed to read a page from the media
sl@0
  1708
            //-- break out from the loop and fall back to old search just in case.
sl@0
  1709
sl@0
  1710
            case KErrEof:
sl@0
  1711
            //-- there are no '1' entries in whole FAT bit cache vector at all, which is quite unlikely
sl@0
  1712
            //-- break out from the loop and fall back to old search.
sl@0
  1713
            i=KMaxLookupRetries;
sl@0
  1714
            break;
sl@0
  1715
sl@0
  1716
            //-- unexpected result code.
sl@0
  1717
            default:
sl@0
  1718
            ASSERT(0); 
sl@0
  1719
            i=KMaxLookupRetries;
sl@0
  1720
            break;
sl@0
  1721
sl@0
  1722
        
sl@0
  1723
            };//switch(nRes)
sl@0
  1724
sl@0
  1725
        }//for(TInt i=0; i<KMaxLookupRetries; ++i)
sl@0
  1726
sl@0
  1727
    //-- something went wrong, Bit Fat supercache could not find FAT cache sector that contains at least one free FAT entry.
sl@0
  1728
    //-- this is most likely because of the FAT data mismatch between FAT and bit cache.
sl@0
  1729
    __PRINT(_L("#++ CAtaFatTable::FindClosestFreeClusterL FALLBACK #1"));
sl@0
  1730
    
sl@0
  1731
    //!!!!?? use  not aCluster, but previous search result here ???
sl@0
  1732
    return CFatTable::FindClosestFreeClusterL(aCluster); //-- fall back to the old search method
sl@0
  1733
    }
sl@0
  1734
sl@0
  1735
sl@0
  1736
sl@0
  1737
/**
sl@0
  1738
    Get the next cluster in the chain from the FAT
sl@0
  1739
sl@0
  1740
    @param aCluster number to read, contains next cluster upon return
sl@0
  1741
    @return False if end of cluster chain
sl@0
  1742
*/
sl@0
  1743
TBool CFatTable::GetNextClusterL(TInt& aCluster) const
sl@0
  1744
    {
sl@0
  1745
	__PRINT1(_L("CAtaFatTable::GetNextClusterL(%d)"), aCluster);
sl@0
  1746
    
sl@0
  1747
    const TUint32 nextCluster = ReadL(aCluster);
sl@0
  1748
    const TBool bEOC = IsEndOfClusterCh(nextCluster);
sl@0
  1749
sl@0
  1750
    if(bEOC) 
sl@0
  1751
        return EFalse; //-- the end of cluster chain
sl@0
  1752
sl@0
  1753
    aCluster = nextCluster;
sl@0
  1754
    
sl@0
  1755
    return ETrue;    
sl@0
  1756
    }
sl@0
  1757
sl@0
  1758
/**
sl@0
  1759
    Write EOF to aFatIndex
sl@0
  1760
    @param aFatIndex index in FAT (cluster number) to be written
sl@0
  1761
*/
sl@0
  1762
void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex)
sl@0
  1763
	{
sl@0
  1764
	__PRINT1(_L("CFatTable::WriteFatEntryEofL(%d)"), aFatIndex);
sl@0
  1765
sl@0
  1766
    //-- use EOF_32Bit (0x0fffffff) for all types of FAT, FAT cache will mask it appropriately
sl@0
  1767
    WriteL(aFatIndex, EOF_32Bit);
sl@0
  1768
    }
sl@0
  1769
sl@0
  1770
sl@0
  1771
sl@0
  1772
/** 
sl@0
  1773
    Mark cluster number aFatIndex in FAT as bad 
sl@0
  1774
    @param aFatIndex index in FAT (cluster number) to be written
sl@0
  1775
*/
sl@0
  1776
void CFatTable::MarkAsBadClusterL(TUint32 aFatIndex)
sl@0
  1777
    {
sl@0
  1778
    __PRINT1(_L("CAtaFatTable::MarkAsBadClusterL(%d)"),aFatIndex);
sl@0
  1779
sl@0
  1780
    //-- use KBad_32Bit (0x0ffffff7) for all types of FAT, FAT cache will mask it appropriately
sl@0
  1781
    WriteL(aFatIndex, KBad_32Bit);
sl@0
  1782
    
sl@0
  1783
    FlushL();
sl@0
  1784
	}
sl@0
  1785
sl@0
  1786
sl@0
  1787
/**
sl@0
  1788
    Return the location of a Cluster in the data section of the media
sl@0
  1789
sl@0
  1790
    @param aCluster to find location of
sl@0
  1791
    @return Byte offset of the cluster data 
sl@0
  1792
*/
sl@0
  1793
TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const
sl@0
  1794
	{
sl@0
  1795
sl@0
  1796
    __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex));
sl@0
  1797
sl@0
  1798
    const TInt clusterBasePosition=iOwner->ClusterBasePosition();
sl@0
  1799
	return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition);
sl@0
  1800
	}
sl@0
  1801
sl@0
  1802
sl@0
  1803
sl@0
  1804
sl@0
  1805
//#######################################################################################################################################
sl@0
  1806
//#     CFatHelperThreadBase  implementation
sl@0
  1807
//#######################################################################################################################################
sl@0
  1808
sl@0
  1809
//-----------------------------------------------------------------------------
sl@0
  1810
CFatHelperThreadBase::CFatHelperThreadBase(CAtaFatTable& aOwner)
sl@0
  1811
                      :iOwner(aOwner)
sl@0
  1812
    {
sl@0
  1813
sl@0
  1814
    SetState(EInvalid);
sl@0
  1815
    }
sl@0
  1816
sl@0
  1817
CFatHelperThreadBase::~CFatHelperThreadBase()
sl@0
  1818
    {
sl@0
  1819
    Close();
sl@0
  1820
    }
sl@0
  1821
sl@0
  1822
//-----------------------------------------------------------------------------
sl@0
  1823
/**
sl@0
  1824
    Closes the thread object handle.
sl@0
  1825
    The thread shall not be running.
sl@0
  1826
*/
sl@0
  1827
void CFatHelperThreadBase::Close()
sl@0
  1828
    {
sl@0
  1829
    if(ThreadWorking())
sl@0
  1830
        {
sl@0
  1831
        ASSERT(0);
sl@0
  1832
        ForceStop();
sl@0
  1833
        }
sl@0
  1834
sl@0
  1835
    iThread.Close();
sl@0
  1836
    }
sl@0
  1837
sl@0
  1838
//-----------------------------------------------------------------------------
sl@0
  1839
/**
sl@0
  1840
    Waits for the thread to finish (thread function exit). if it is running.
sl@0
  1841
    @return thread completion code.
sl@0
  1842
sl@0
  1843
    !!!! definitely need a timeout processing here to avoid any possibitlity of hanging forever !!
sl@0
  1844
sl@0
  1845
*/
sl@0
  1846
TInt CFatHelperThreadBase::WaitToFinish() const
sl@0
  1847
    {
sl@0
  1848
    if(!ThreadWorking())
sl@0
  1849
        return ThreadCompletionCode();
sl@0
  1850
sl@0
  1851
    
sl@0
  1852
    //--todo: use timeout and assert to avoid hanging forever ?
sl@0
  1853
    __PRINT1(_L("#= CFatHelperThreadBase::WaitToFinish(), stat:%d"),iThreadStatus.Int());
sl@0
  1854
    User::WaitForRequest(iThreadStatus);
sl@0
  1855
    return iThreadStatus.Int();
sl@0
  1856
    }
sl@0
  1857
sl@0
  1858
//-----------------------------------------------------------------------------
sl@0
  1859
sl@0
  1860
/**
sl@0
  1861
    Requests the fat helper thread function to finish gracefully ASAP; then closes the thread handle. 
sl@0
  1862
    Just sets a flag that is analysed by the thread function and waits thread's request completion.
sl@0
  1863
*/
sl@0
  1864
void CFatHelperThreadBase::ForceStop()
sl@0
  1865
    {
sl@0
  1866
    if(ThreadWorking())
sl@0
  1867
        {
sl@0
  1868
        DBG_STATEMENT(TName name = iThread.Name();)
sl@0
  1869
        __PRINT3(_L("#=!! CFatHelperThreadBase::ForceStop() id:%u, name:%S, status:%d"), (TUint)iThread.Id(), &name, ThreadCompletionCode());
sl@0
  1870
        DBG_STATEMENT(name.Zero()); //-- to avoid warning
sl@0
  1871
sl@0
  1872
        iOwner.AcquireLock();
sl@0
  1873
    
sl@0
  1874
        AllowToLive(EFalse) ; //-- signal the thread to exit ASAP
sl@0
  1875
sl@0
  1876
        iOwner.ReleaseLock();
sl@0
  1877
sl@0
  1878
        WaitToFinish(); //-- wait for the thread to finish.
sl@0
  1879
sl@0
  1880
        //-- don't know why but we need a delay, at least on the emulator. Otherwise thread object doesn't look destroyed.
sl@0
  1881
        //-- probably something with scheduling.
sl@0
  1882
        User::After(10*K1mSec); 
sl@0
  1883
        }
sl@0
  1884
sl@0
  1885
    iThread.Close();
sl@0
  1886
    }
sl@0
  1887
sl@0
  1888
sl@0
  1889
//-----------------------------------------------------------------------------
sl@0
  1890
sl@0
  1891
sl@0
  1892
/**
sl@0
  1893
    Created, initialises and starts the helper thread.
sl@0
  1894
    
sl@0
  1895
    @param  aFunction           pointer to the thread function
sl@0
  1896
    @param  aThreadParameter    parameter to be passed to the thread function. Its interpretation depends on the thread function.
sl@0
  1897
    @return KErrNone on success; standard error code otherwise
sl@0
  1898
*/
sl@0
  1899
TInt CFatHelperThreadBase::DoLaunchThread(TThreadFunction aFunction, TAny* aThreadParameter)
sl@0
  1900
    {
sl@0
  1901
    __PRINT2(_L("#=- CFatHelperThreadBase::DoLaunchThread() thread stat:%d, state:%d"), ThreadCompletionCode(), State());
sl@0
  1902
    
sl@0
  1903
    ASSERT(aFunction);
sl@0
  1904
    ASSERT(State() != EWorking);
sl@0
  1905
sl@0
  1906
    if(ThreadWorking())
sl@0
  1907
        {
sl@0
  1908
        ASSERT(0);
sl@0
  1909
        return KErrInUse;
sl@0
  1910
        }
sl@0
  1911
sl@0
  1912
    if(iOwner.OwnerMount()->Drive().IsSynchronous())
sl@0
  1913
        {
sl@0
  1914
        //-- if the drive is synchronous, this is a main File Server thread. Don't play with it, it has its own scheduler
sl@0
  1915
        //-- and completing other requests rather than native CFsRequest leads to the stray events, because it waits on the 
sl@0
  1916
        //-- User::WaitForAnyRequest and doesn't check which request has completed.
sl@0
  1917
        __PRINT(_L("CFatHelperThreadBase::DoLaunchThread() the drive is synchronous, skipping."));
sl@0
  1918
        return KErrNotSupported;
sl@0
  1919
        }
sl@0
  1920
sl@0
  1921
sl@0
  1922
    TInt nRes;
sl@0
  1923
    TName nameBuf; //-- this will be initial thread name, it will rename itself in its thread function
sl@0
  1924
    nameBuf.Format(_L("Fat32HelperThread_drv_%d"), iOwner.OwnerMount()->DriveNumber());
sl@0
  1925
    const TInt stackSz = 4*K1KiloByte; //-- thread stack size, 4K
sl@0
  1926
sl@0
  1927
    iThread.Close();
sl@0
  1928
sl@0
  1929
    //-- 1. create the thread
sl@0
  1930
    nRes = iThread.Create(nameBuf, aFunction, stackSz, &User::Allocator(), aThreadParameter, EOwnerProcess);
sl@0
  1931
	if(nRes != KErrNone)
sl@0
  1932
	    {
sl@0
  1933
        __PRINT1(_L("#=- CFatHelperThreadBase::DoLaunchThread() failure#1 res:%d"), nRes);
sl@0
  1934
        iThread.Close();
sl@0
  1935
        ASSERT(0);
sl@0
  1936
        return nRes;
sl@0
  1937
        }
sl@0
  1938
sl@0
  1939
    //-- 2. set up its working environment
sl@0
  1940
    AllowToLive(ETrue);
sl@0
  1941
	iThread.SetPriority((TThreadPriority)EHelperPriorityNormal); //-- initially the thread has very low priority
sl@0
  1942
	
sl@0
  1943
    //-- the state of this object now will be controlled by the thread 
sl@0
  1944
    SetState(ENotStarted);
sl@0
  1945
sl@0
  1946
    //-- 3. resume thread and wait until it finishes its initialisation
sl@0
  1947
    TRequestStatus rqStatInit(KRequestPending);
sl@0
  1948
    
sl@0
  1949
    iThread.Logon(iThreadStatus);
sl@0
  1950
    iThread.Rendezvous(rqStatInit);
sl@0
  1951
    iThread.Resume();
sl@0
  1952
   
sl@0
  1953
    User::WaitForRequest(rqStatInit);
sl@0
  1954
sl@0
  1955
    if(rqStatInit.Int() != KErrNone)
sl@0
  1956
        {//-- thread couldn't initialise
sl@0
  1957
        __PRINT1(_L("#=- CFatHelperThreadBase::DoLaunchThread() failure#2 res:%d"), nRes);
sl@0
  1958
        ForceStop();
sl@0
  1959
        ASSERT(0);
sl@0
  1960
        return nRes;
sl@0
  1961
        }
sl@0
  1962
sl@0
  1963
   //-- Helper FAT thread is running now
sl@0
  1964
   return KErrNone; 
sl@0
  1965
    }
sl@0
  1966
sl@0
  1967
sl@0
  1968
//#######################################################################################################################################
sl@0
  1969
//#     CFat32ScanThread implementation
sl@0
  1970
//#######################################################################################################################################
sl@0
  1971
sl@0
  1972
sl@0
  1973
CFat32ScanThread::CFat32ScanThread(CAtaFatTable& aOwner)
sl@0
  1974
                 :CFatHelperThreadBase(aOwner)
sl@0
  1975
    {
sl@0
  1976
    }
sl@0
  1977
sl@0
  1978
//-----------------------------------------------------------------------------
sl@0
  1979
sl@0
  1980
/**
sl@0
  1981
    Launches the FAT32_ScanThread scaner thread.
sl@0
  1982
    @return  standard error code
sl@0
  1983
*/
sl@0
  1984
TInt CFat32ScanThread::Launch()
sl@0
  1985
    {
sl@0
  1986
    return DoLaunchThread(FAT32_ScanThread, this);    
sl@0
  1987
    }
sl@0
  1988
sl@0
  1989
//-----------------------------------------------------------------------------
sl@0
  1990
sl@0
  1991
/**
sl@0
  1992
    FAT32_ScanThread preamble function. It gets called by the scan thread at the very beginning.
sl@0
  1993
    Does some initialisation work and its return code is signaled to the thread owner by RThread::Rendezvous();
sl@0
  1994
    
sl@0
  1995
    @return Thread object initialisation code, KErrNone on success.
sl@0
  1996
*/
sl@0
  1997
TInt CFat32ScanThread::Thread_Preamble()
sl@0
  1998
    {
sl@0
  1999
    //__PRINT(_L("#=-  CFat32ScanThread::Thread_Preamble()"));
sl@0
  2000
sl@0
  2001
    ipFatBitCache = iOwner.iCache->BitCacheInterface();
sl@0
  2002
    iTimeStart.UniversalTime(); //-- take thread start time
sl@0
  2003
    
sl@0
  2004
    ASSERT(State() == CFatHelperThreadBase::ENotStarted); //-- see the thread launcher
sl@0
  2005
    
sl@0
  2006
    if(!iOwner.IsFat32())
sl@0
  2007
        {//-- this stuff is supposed to work for FAT32 only
sl@0
  2008
        ASSERT(0);
sl@0
  2009
        return KErrArgument; 
sl@0
  2010
        }
sl@0
  2011
sl@0
  2012
    return KErrNone;
sl@0
  2013
    }
sl@0
  2014
sl@0
  2015
//-----------------------------------------------------------------------------
sl@0
  2016
/**
sl@0
  2017
    FAT32_ScanThread postamble function. It gets called by the scan thread just before its function exits.
sl@0
  2018
    Does some finalisation work and its return code is the thread completion code;
sl@0
  2019
    
sl@0
  2020
    @return Thread object finalisation code, KErrNone on success.
sl@0
  2021
*/
sl@0
  2022
TInt CFat32ScanThread::Thread_Postamble(TInt aResult)
sl@0
  2023
    {
sl@0
  2024
    //__PRINT(_L("#=-  CFat32ScanThread::Thread_Postamble()"));
sl@0
  2025
sl@0
  2026
#ifdef _DEBUG    
sl@0
  2027
    //-- print out time taken the thread to finish
sl@0
  2028
    TName nameBuf;
sl@0
  2029
    iTimeEnd.UniversalTime(); //-- take end time
sl@0
  2030
    const TInt msScanTime = (TInt)( (iTimeEnd.MicroSecondsFrom(iTimeStart)).Int64() / K1mSec);
sl@0
  2031
    nameBuf.Copy(RThread().Name());
sl@0
  2032
    nameBuf.Insert(0,_L("#=-<<<")); 
sl@0
  2033
    nameBuf.AppendFormat(_L(" Thread Exit. id:%d, Code:%d, time:%d ms"), (TUint)RThread().Id(), aResult, msScanTime);
sl@0
  2034
    __PRINT(nameBuf);
sl@0
  2035
#endif
sl@0
  2036
    
sl@0
  2037
    //-- tell FAT bit supercache (if we have it) that we have finished populating it, successfully or not
sl@0
  2038
    if(ipFatBitCache) 
sl@0
  2039
        {
sl@0
  2040
        ipFatBitCache->FinishPopulating(aResult == KErrNone);
sl@0
  2041
        ipFatBitCache->Dump();
sl@0
  2042
        }
sl@0
  2043
sl@0
  2044
    //-- close FAT chunk buffer
sl@0
  2045
    iFatChunkBuf.Close();
sl@0
  2046
sl@0
  2047
    //-- set the host object state depending on the work results.
sl@0
  2048
    if(aResult == KErrNone)
sl@0
  2049
        SetState(CFatHelperThreadBase::EFinished_OK); 
sl@0
  2050
    else
sl@0
  2051
        SetState(CFatHelperThreadBase::EFailed); 
sl@0
  2052
sl@0
  2053
   
sl@0
  2054
    return aResult;
sl@0
  2055
    }
sl@0
  2056
sl@0
  2057
//#######################################################################################################################################
sl@0
  2058
//#     CFat32FreeSpaceScanner implementation
sl@0
  2059
//#######################################################################################################################################
sl@0
  2060
sl@0
  2061
CFat32FreeSpaceScanner::CFat32FreeSpaceScanner(CAtaFatTable& aOwner)
sl@0
  2062
                       :CFat32ScanThread(aOwner) 
sl@0
  2063
    {
sl@0
  2064
    }
sl@0
  2065
sl@0
  2066
/**
sl@0
  2067
    Factory method.
sl@0
  2068
    @param  aOwner owning CAtaFatTable
sl@0
  2069
    @return pointer to the constructed instance of the class
sl@0
  2070
*/
sl@0
  2071
CFat32FreeSpaceScanner* CFat32FreeSpaceScanner::NewL(CAtaFatTable& aOwner)
sl@0
  2072
    {
sl@0
  2073
    CFat32FreeSpaceScanner* pThis = NULL;
sl@0
  2074
    pThis = new (ELeave) CFat32FreeSpaceScanner(aOwner);    
sl@0
  2075
    
sl@0
  2076
    return pThis;
sl@0
  2077
    }
sl@0
  2078
sl@0
  2079
//-----------------------------------------------------------------------------
sl@0
  2080
sl@0
  2081
/**
sl@0
  2082
    Waits until FAT32 free clusters scan thread allows other thread (caller) to write to the FAT entry "aFatIndex".
sl@0
  2083
    Thread scans FAT from the beginning to the end and just waits untill scanning passes the entry number "aFatIndex"
sl@0
  2084
    
sl@0
  2085
    @param  aFatIndex index of the FAT entry we are going to write.
sl@0
  2086
*/
sl@0
  2087
void CFat32FreeSpaceScanner::RequestFatEntryWriteAccess(TUint32 aFatIndex) const
sl@0
  2088
    {
sl@0
  2089
    if(!ThreadWorking())
sl@0
  2090
        return;
sl@0
  2091
sl@0
  2092
    ASSERT(iOwner.ClusterNumberValid(aFatIndex));
sl@0
  2093
sl@0
  2094
    const TUint KWaitGranularity = 20*K1mSec; //-- wait granularity
sl@0
  2095
sl@0
  2096
    //-- wait until FAT[aFatIndex] is available to write
sl@0
  2097
    while(aFatIndex > ClustersScanned() && ThreadWorking())
sl@0
  2098
        {
sl@0
  2099
        BoostPriority(ETrue); //-- Boost scan thread priority
sl@0
  2100
        User::After(KWaitGranularity); 
sl@0
  2101
        }
sl@0
  2102
    }
sl@0
  2103
sl@0
  2104
//-----------------------------------------------------------------------------
sl@0
  2105
sl@0
  2106
/** just an internal helper method. Stores the number of FAT entries already scanned by FAT free entries scan thread.  */
sl@0
  2107
void CFat32FreeSpaceScanner::SetClustersScanned(TUint32 aClusters) 
sl@0
  2108
    {
sl@0
  2109
    XAutoLock lock(iOwner.DriveInterface()); //-- enter critical section
sl@0
  2110
    iClustersScanned=aClusters;
sl@0
  2111
    }
sl@0
  2112
sl@0
  2113
/** just an internal helper method. returns the number of FAT entries already scanned by FAT free entrie sscan thread.  */
sl@0
  2114
TUint32 CFat32FreeSpaceScanner::ClustersScanned() const
sl@0
  2115
    {
sl@0
  2116
    XAutoLock lock(iOwner.DriveInterface()); //-- enter critical section
sl@0
  2117
    return iClustersScanned;
sl@0
  2118
    }
sl@0
  2119
sl@0
  2120
//-----------------------------------------------------------------------------
sl@0
  2121
sl@0
  2122
/**
sl@0
  2123
    overriden FAT32_ScanThread preamble function. 
sl@0
  2124
    See CFat32ScanThread::Thread_Preamble()
sl@0
  2125
*/
sl@0
  2126
TInt CFat32FreeSpaceScanner::Thread_Preamble()
sl@0
  2127
    {
sl@0
  2128
    __PRINT1(_L("#=- CFat32FreeSpaceScanner::Thread_Preamble(), FAT state:%d"), iOwner.State());
sl@0
  2129
  
sl@0
  2130
    ASSERT(iOwner.State() == CAtaFatTable::EFreeClustersScan);
sl@0
  2131
    
sl@0
  2132
    //-- invoke generic preamble first
sl@0
  2133
    TInt nRes = CFat32ScanThread::Thread_Preamble();
sl@0
  2134
    if(nRes != KErrNone)
sl@0
  2135
        return nRes;
sl@0
  2136
sl@0
  2137
    //-- do specific to this thread object initialisation work
sl@0
  2138
sl@0
  2139
    //-- rename the thread
sl@0
  2140
    TName nameBuf;
sl@0
  2141
    const CFatMountCB& fatMount = *(iOwner.OwnerMount());
sl@0
  2142
    nameBuf.Format(_L("Fat32FreeSpaceScanner_drv_%d"), fatMount.DriveNumber());
sl@0
  2143
    RThread::RenameMe(nameBuf);
sl@0
  2144
sl@0
  2145
    //-- allocate FAT chunk buffer; its size will depend on FAT table size.
sl@0
  2146
    const TUint32 fatSz = iOwner.MaxEntries() << KFat32EntrySzLog2;
sl@0
  2147
sl@0
  2148
    if(fatSz < KBigSzFat_Threshold)
sl@0
  2149
        {//-- create a small buffer
sl@0
  2150
        if(iFatChunkBuf.CreateMax(KFatChunkBufSize_Small) != KErrNone)
sl@0
  2151
            return KErrNoMemory;
sl@0
  2152
        }
sl@0
  2153
    else
sl@0
  2154
        {//-- try to create larger buffer
sl@0
  2155
        if(iFatChunkBuf.CreateMax(KFatChunkBufSize_Big) != KErrNone && iFatChunkBuf.CreateMax(KFatChunkBufSize_Small) != KErrNone)
sl@0
  2156
            return KErrNoMemory;
sl@0
  2157
        }
sl@0
  2158
sl@0
  2159
sl@0
  2160
    //-- setup FAT table's parameters
sl@0
  2161
    //-- No free clusters yet; be careful with SetFreeClusters(), free clusters count can be 
sl@0
  2162
    //-- modified from other thread, e.g. from FreeClusterList. Use read-modify-write instead of assignment.
sl@0
  2163
    SetClustersScanned(0);
sl@0
  2164
    iOwner.SetFreeClusters(0); 
sl@0
  2165
sl@0
  2166
    //-- calculate number of FAT entires need to be processed for CMountCB::SetDiskSpaceChange() call.
sl@0
  2167
    //-- if number of processed entries in FAT exceeds iEntriesNotifyThreshold, CMountCB::SetDiskSpaceChange()
sl@0
  2168
    //-- will be called and the iEntriesNotifyThreshold will be updated.
sl@0
  2169
    iNfyThresholdInc = (TUint32)KVolSpaceNotifyThreshold >> fatMount.ClusterSizeLog2();
sl@0
  2170
    iEntriesNotifyThreshold = iNfyThresholdInc;
sl@0
  2171
sl@0
  2172
    //-- if there is an interface to the FAT bit supercache, tell it to start populating.  
sl@0
  2173
    //-- We will be populating this cache while reading and parsing FAT32.
sl@0
  2174
    if(ipFatBitCache)
sl@0
  2175
        ipFatBitCache->StartPopulating();
sl@0
  2176
sl@0
  2177
sl@0
  2178
    return KErrNone;
sl@0
  2179
    }
sl@0
  2180
sl@0
  2181
//-----------------------------------------------------------------------------
sl@0
  2182
/**
sl@0
  2183
    overriden FAT32_ScanThread postamble function. 
sl@0
  2184
    See CFat32ScanThread::Thread_Postamble()
sl@0
  2185
*/
sl@0
  2186
TInt CFat32FreeSpaceScanner::Thread_Postamble(TInt aResult)
sl@0
  2187
    {
sl@0
  2188
    __PRINT2(_L("#=- CFat32FreeSpaceScanner::Thread_Postamble(%d), FAT state:%d"), aResult, iOwner.State());
sl@0
  2189
    __PRINT2(_L("#=- FAT_ScanThread: counted Free clusters:%d, 1st free:%d"), iOwner.NumberOfFreeClusters(), iOwner.FreeClusterHint());
sl@0
  2190
sl@0
  2191
    ASSERT(iOwner.State() == CAtaFatTable::EFreeClustersScan);
sl@0
  2192
sl@0
  2193
    //-- there was an error somewhere within FAT32 scan thread
sl@0
  2194
    if(aResult != KErrNone)
sl@0
  2195
        {
sl@0
  2196
        //-- indicate that the FAT table initialisation failed
sl@0
  2197
        __PRINT(_L("#=- Asynch FAT table initialisation failed !"));
sl@0
  2198
sl@0
  2199
        iOwner.SetState(CAtaFatTable::EMountAborted);
sl@0
  2200
     
sl@0
  2201
        //-- fix up some FAT table parameters
sl@0
  2202
        if(iOwner.FreeClusterHint() < KFatFirstSearchCluster)
sl@0
  2203
            iOwner.SetFreeClusterHint(KFatFirstSearchCluster);    
sl@0
  2204
sl@0
  2205
        }
sl@0
  2206
sl@0
  2207
   
sl@0
  2208
    //-- call generic postamble
sl@0
  2209
    TInt nRes = CFat32ScanThread::Thread_Postamble(aResult);
sl@0
  2210
    
sl@0
  2211
    if(nRes == KErrNone)
sl@0
  2212
        {//-- FAT table now fully initialised
sl@0
  2213
        ASSERT(aResult == KErrNone);
sl@0
  2214
        iOwner.SetState(CAtaFatTable::EMounted);
sl@0
  2215
sl@0
  2216
        //-- free space counting finished OK, call the notifier last time
sl@0
  2217
        CFatMountCB& fatMount = *(iOwner.OwnerMount());
sl@0
  2218
        
sl@0
  2219
        iOwner.AcquireLock();
sl@0
  2220
        const TInt64 currFreeSpace = ((TInt64)iOwner.FreeClusters()) << fatMount.ClusterSizeLog2();
sl@0
  2221
        iOwner.ReleaseLock();
sl@0
  2222
sl@0
  2223
        fatMount.SetDiskSpaceChange(currFreeSpace);
sl@0
  2224
sl@0
  2225
sl@0
  2226
        }
sl@0
  2227
    else if(aResult == KErrNone)
sl@0
  2228
        {//-- CFat32ScanThread::Thread_Postamble() signaled a fault
sl@0
  2229
        iOwner.SetState(CAtaFatTable::EMountAborted);
sl@0
  2230
        }
sl@0
  2231
sl@0
  2232
    return aResult;
sl@0
  2233
    }
sl@0
  2234
sl@0
  2235
//-----------------------------------------------------------------------------
sl@0
  2236
/**
sl@0
  2237
    Process free FAT entries collected by the scan thread that parses chunk of FAT data.
sl@0
  2238
    This method gets called by the FAT scanning thread after a portion of FAT is read into the buffer and parsed
sl@0
  2239
sl@0
  2240
    @param  aFreeEntriesInChunk number of free FAT entries counted in FAT chunk
sl@0
  2241
    @param  aCurrFirstFreeEntry current number of the first free FAT entry found
sl@0
  2242
    @param  aClustersScanned    total number of FAT entries scanned by the thread
sl@0
  2243
sl@0
  2244
    @return standard error code, KErrNone on success
sl@0
  2245
*/
sl@0
  2246
TInt CFat32FreeSpaceScanner::Thread_ProcessCollectedFreeEntries(const CAtaFatTable::TFatScanParam& aFatScanParam)
sl@0
  2247
    {
sl@0
  2248
    ASSERT(State() == CFatHelperThreadBase::EWorking); 
sl@0
  2249
sl@0
  2250
    CAtaFatTable& ataFatTable = iOwner;
sl@0
  2251
sl@0
  2252
    //-------------------------------------------
sl@0
  2253
    //-- publish values to the CAtaFatTable object
sl@0
  2254
    ataFatTable.AcquireLock();
sl@0
  2255
            
sl@0
  2256
    //-- publish free cluster count, use read-modify-write here
sl@0
  2257
    //-- CFatTable::iFreeClusters can be already modified from other thread.
sl@0
  2258
    TUint32 currFreeClusters = ataFatTable.FreeClusters(); //-- simple non-thread safe method
sl@0
  2259
    
sl@0
  2260
    currFreeClusters += aFatScanParam.iCurrFreeEntries;
sl@0
  2261
sl@0
  2262
    ataFatTable.SetFreeClusters(currFreeClusters);
sl@0
  2263
sl@0
  2264
    //-- store total number of scanned clusters (not to be modified from other thread)
sl@0
  2265
    const TUint32 scannedEntries = aFatScanParam.iEntriesScanned;
sl@0
  2266
    SetClustersScanned(scannedEntries); 
sl@0
  2267
   
sl@0
  2268
sl@0
  2269
    if(aFatScanParam.iFirstFree >= KFatFirstSearchCluster)
sl@0
  2270
        ataFatTable.SetFreeClusterHint(aFatScanParam.iFirstFree);//-- probably found next free cluster number 
sl@0
  2271
sl@0
  2272
    ataFatTable.ReleaseLock();
sl@0
  2273
sl@0
  2274
    //-- check if we need to call CMountCB::SetDiskSpaceChange() to notify it that the amount of processed FAT entries has reached the given threshold
sl@0
  2275
    if(scannedEntries >= iEntriesNotifyThreshold)
sl@0
  2276
        {
sl@0
  2277
        iEntriesNotifyThreshold += iNfyThresholdInc;
sl@0
  2278
sl@0
  2279
        CFatMountCB& fatMount = *(iOwner.OwnerMount());
sl@0
  2280
        const TInt64 currFreeSpace = ((TInt64)currFreeClusters) << fatMount.ClusterSizeLog2();
sl@0
  2281
        fatMount.SetDiskSpaceChange(currFreeSpace);
sl@0
  2282
        }
sl@0
  2283
sl@0
  2284
sl@0
  2285
    return KErrNone;
sl@0
  2286
    }
sl@0
  2287
sl@0
  2288
//#######################################################################################################################################
sl@0
  2289
//#     CFat32BitCachePopulator implementation
sl@0
  2290
//#######################################################################################################################################
sl@0
  2291
CFat32BitCachePopulator::CFat32BitCachePopulator(CAtaFatTable& aOwner)
sl@0
  2292
                       :CFat32ScanThread(aOwner) 
sl@0
  2293
    {
sl@0
  2294
    }
sl@0
  2295
sl@0
  2296
/**
sl@0
  2297
    Factory method.
sl@0
  2298
    @param  aOwner owning CAtaFatTable
sl@0
  2299
    @return pointer to the constructed instance of the class
sl@0
  2300
*/
sl@0
  2301
CFat32BitCachePopulator* CFat32BitCachePopulator::NewL(CAtaFatTable& aOwner)
sl@0
  2302
    {
sl@0
  2303
    CFat32BitCachePopulator* pThis = NULL;
sl@0
  2304
    pThis = new (ELeave) CFat32BitCachePopulator(aOwner);    
sl@0
  2305
    
sl@0
  2306
    return pThis;
sl@0
  2307
    }
sl@0
  2308
sl@0
  2309
//-----------------------------------------------------------------------------
sl@0
  2310
sl@0
  2311
/**
sl@0
  2312
    The main FS thread tries to write the "aFatIndex" entry in FAT while this thread is running.
sl@0
  2313
    We can't do anything useful here, because FAT32 bit supercache doesn't work on FAT entry level and
sl@0
  2314
    deals with much less scale - FAT32 cache sector, which can consist from many FAT32 entries.
sl@0
  2315
    The conflict situation will be resolved in the CAtaFatTable::WriteL()
sl@0
  2316
*/
sl@0
  2317
void CFat32BitCachePopulator::RequestFatEntryWriteAccess(TUint32 /*aFatIndex*/) const
sl@0
  2318
    {
sl@0
  2319
    //-- do nothing here, do not block the caller
sl@0
  2320
    }
sl@0
  2321
sl@0
  2322
sl@0
  2323
//-----------------------------------------------------------------------------
sl@0
  2324
/**
sl@0
  2325
    overriden FAT32_ScanThread preamble function. 
sl@0
  2326
    See CFat32ScanThread::Thread_Preamble()
sl@0
  2327
*/
sl@0
  2328
TInt CFat32BitCachePopulator::Thread_Preamble()
sl@0
  2329
    {
sl@0
  2330
    __PRINT(_L("#=- CFat32BitCachePopulator::Thread_Preamble()"));
sl@0
  2331
    
sl@0
  2332
    //-- invoke generic preamble
sl@0
  2333
    TInt nRes = CFat32ScanThread::Thread_Preamble();
sl@0
  2334
    if(nRes != KErrNone)
sl@0
  2335
        return nRes;
sl@0
  2336
sl@0
  2337
    //-- do specific to this thread object initialisation work
sl@0
  2338
    iTotalOccupiedFatEntries = 0;
sl@0
  2339
sl@0
  2340
    //-- rename the thread
sl@0
  2341
    TName nameBuf;
sl@0
  2342
    const CFatMountCB& fatMount = *(iOwner.OwnerMount());
sl@0
  2343
    nameBuf.Format(_L("CFat32BitCachePopulator_drv_%d"), fatMount.DriveNumber());
sl@0
  2344
    RThread::RenameMe(nameBuf);
sl@0
  2345
sl@0
  2346
    //-- allocate FAT chunk buffer
sl@0
  2347
    nRes = iFatChunkBuf.CreateMax(KFatChunkBufSize);
sl@0
  2348
    if(nRes != KErrNone)
sl@0
  2349
        return nRes;
sl@0
  2350
sl@0
  2351
    
sl@0
  2352
    if(!ipFatBitCache)
sl@0
  2353
        {//-- this is a bit cache populator and the bit cache object must have been constructed before setting up the populating thread.
sl@0
  2354
        ASSERT(0);
sl@0
  2355
        return KErrCorrupt;
sl@0
  2356
        }
sl@0
  2357
    
sl@0
  2358
    //-- Tell FAT bit supercache to start populating. We will be populating this cache while reading and parsing FAT32.
sl@0
  2359
    if(ipFatBitCache->StartPopulating())
sl@0
  2360
        nRes = KErrNone;
sl@0
  2361
    else
sl@0
  2362
        nRes = KErrCorrupt;
sl@0
  2363
sl@0
  2364
    return nRes;
sl@0
  2365
    }
sl@0
  2366
sl@0
  2367
//-----------------------------------------------------------------------------
sl@0
  2368
sl@0
  2369
/**
sl@0
  2370
    overriden FAT32_ScanThread postamble function. 
sl@0
  2371
    See CFat32ScanThread::Thread_Postamble()
sl@0
  2372
*/
sl@0
  2373
TInt CFat32BitCachePopulator::Thread_Postamble(TInt aResult)
sl@0
  2374
    {
sl@0
  2375
    __PRINT1(_L("#=- CFat32BitCachePopulator::Thread_Postamble(%d)"), aResult);
sl@0
  2376
sl@0
  2377
    //-- nothing specific to do, just call generic method
sl@0
  2378
    return CFat32ScanThread::Thread_Postamble(aResult);
sl@0
  2379
    }
sl@0
  2380
sl@0
  2381
//-----------------------------------------------------------------------------
sl@0
  2382
/**
sl@0
  2383
    This method gets called by the FAT scanning thread after a portion of FAT is read into the buffer and parsed
sl@0
  2384
    @return standard error code, KErrNone on success
sl@0
  2385
*/
sl@0
  2386
TInt CFat32BitCachePopulator::Thread_ProcessCollectedFreeEntries(const CAtaFatTable::TFatScanParam& aFatScanParam)
sl@0
  2387
    {
sl@0
  2388
    ASSERT(State() == CFatHelperThreadBase::EWorking); 
sl@0
  2389
    
sl@0
  2390
    //-- check the bit cache state
sl@0
  2391
    if(ipFatBitCache->State() != CFatBitCache::EPopulating)
sl@0
  2392
        {//-- something wrong happened to the cache, e.g. someone forcedly invalidated it (probably from another thread)
sl@0
  2393
        return KErrAbort;
sl@0
  2394
        }
sl@0
  2395
sl@0
  2396
    
sl@0
  2397
    //-- if CFat32BitCachePopulator has already counted all _occupied_ FAT entries, there is no need to 
sl@0
  2398
    //-- continue FAT reading; just mark the rest of the FAT bit supercache as containing free FAT entries and abort scanning
sl@0
  2399
sl@0
  2400
    CAtaFatTable& ataFatTable = iOwner;
sl@0
  2401
sl@0
  2402
    ataFatTable.AcquireLock();
sl@0
  2403
    
sl@0
  2404
    //-- current amount of non-free entries in FAT, excluding FAT[0] & FAT[1]
sl@0
  2405
    const TUint32 KCurrNonFreeEntries = ataFatTable.MaxEntries() - ataFatTable.FreeClusters() - KFatFirstSearchCluster;
sl@0
  2406
    
sl@0
  2407
    iTotalOccupiedFatEntries += aFatScanParam.iCurrOccupiedEntries;
sl@0
  2408
    
sl@0
  2409
    //-- check if the thread needs to continue it work
sl@0
  2410
    const TBool KNoNeedToScanFurther = (iTotalOccupiedFatEntries >= KCurrNonFreeEntries);
sl@0
  2411
sl@0
  2412
    if(KNoNeedToScanFurther)
sl@0
  2413
        {
sl@0
  2414
        //-- tell FAT bit supercache to mark the range from currently scanned FAT entry to the end of the FAT as containing free entries.
sl@0
  2415
        __PRINT2(_L("#=- CFat32BitCachePopulator::Thread_ProcessCollectedFreeEntries() counted: %d/%d; aborting scan."), iTotalOccupiedFatEntries, KCurrNonFreeEntries);
sl@0
  2416
        
sl@0
  2417
        const TUint32 entryStart = aFatScanParam.iEntriesScanned; //-- first FAT entry in the range to be marked as 'free'
sl@0
  2418
        const TUint32 entryEnd   = ataFatTable.MaxEntries()-1;    //-- last FAT entry in the range to be marked as 'free', last FAT entry
sl@0
  2419
sl@0
  2420
        ipFatBitCache->MarkFatRange(entryStart, entryEnd, ETrue);
sl@0
  2421
        
sl@0
  2422
        //-- signal that the thread shall finish with normal (KErrNone) reason
sl@0
  2423
        //-- it will also normally finish FAT bit cache populating in postamble
sl@0
  2424
        AllowToLive(EFalse); 
sl@0
  2425
        }
sl@0
  2426
sl@0
  2427
    ataFatTable.ReleaseLock();
sl@0
  2428
sl@0
  2429
    
sl@0
  2430
    return KErrNone;
sl@0
  2431
    }
sl@0
  2432
sl@0
  2433
sl@0
  2434
//#######################################################################################################################################
sl@0
  2435
/**
sl@0
  2436
    FAT32 free entries scan thread function. Walks through FAT32 and counts free entries.
sl@0
  2437
    It uses its own buffer to read FAT and parse it in order to avoid multithreaded problems with FAT cache and don't thrash it.
sl@0
  2438
sl@0
  2439
    @param apHostObject pointer to the host object of CFat32ScanThread base class.
sl@0
  2440
*/
sl@0
  2441
//#######################################################################################################################################
sl@0
  2442
TInt FAT32_ScanThread(TAny* apHostObject)
sl@0
  2443
    {
sl@0
  2444
    TInt    nRes;
sl@0
  2445
sl@0
  2446
#ifdef _DEBUG
sl@0
  2447
    TName   nameBuf;
sl@0
  2448
    nameBuf.Copy(RThread().Name());
sl@0
  2449
    nameBuf.Insert(0,_L("#=->>>")); nameBuf.AppendFormat(_L(" Thread Enter (id:%d)"), (TUint)RThread().Id());
sl@0
  2450
    __PRINT(nameBuf);
sl@0
  2451
#endif
sl@0
  2452
    
sl@0
  2453
    ASSERT(apHostObject);
sl@0
  2454
    CFat32FreeSpaceScanner* pSelf = (CFat32FreeSpaceScanner*)apHostObject;
sl@0
  2455
sl@0
  2456
    CAtaFatTable& ataFatTable = pSelf->iOwner;
sl@0
  2457
    CFatMountCB&  fatMount = *(ataFatTable.OwnerMount());
sl@0
  2458
sl@0
  2459
    const TUint32 KFat32EntrySz = sizeof(TFat32Entry); 
sl@0
  2460
    const TUint32 KFat1StartPos = fatMount.StartOfFatInBytes();
sl@0
  2461
    const TUint32 KNumClusters = ataFatTable.MaxEntries(); //-- FAT[0] & FAT[1] are reserved and not counted by UsableClusters()
sl@0
  2462
sl@0
  2463
    //-- perform thread preamble work
sl@0
  2464
    nRes = pSelf->Thread_Preamble();
sl@0
  2465
sl@0
  2466
    //-- signal the thread initialisation result
sl@0
  2467
    RThread::Rendezvous(nRes);
sl@0
  2468
sl@0
  2469
sl@0
  2470
    //-- Initialisation OK, do real job: FAT scanning
sl@0
  2471
    if(nRes == KErrNone)
sl@0
  2472
        {
sl@0
  2473
        pSelf->SetState(CFatHelperThreadBase::EWorking); 
sl@0
  2474
sl@0
  2475
        TUint32 rem = KNumClusters * KFat32EntrySz; 
sl@0
  2476
        TUint32 mediaPos = KFat1StartPos;   
sl@0
  2477
        
sl@0
  2478
        CAtaFatTable::TFatScanParam fatScanParam; //-- FAT scanning parameters
sl@0
  2479
sl@0
  2480
        //============================================
sl@0
  2481
        //=== FAT read and parse loop ================
sl@0
  2482
        //-- in this loop we read portions of raw FAT32 data in a buffer, than parse this buffer 
sl@0
  2483
        //-- in order to find out the number of free FAT entries there and other stuff
sl@0
  2484
        while(rem)
sl@0
  2485
            {
sl@0
  2486
            const TUint32 bytesToRead=Min(rem, (TUint32)pSelf->iFatChunkBuf.Size());
sl@0
  2487
            TPtrC8 ptrData(pSelf->iFatChunkBuf.Ptr(), bytesToRead);
sl@0
  2488
sl@0
  2489
            //-- check for sudden media change
sl@0
  2490
            if(fatMount.Drive().IsChanged()) 
sl@0
  2491
                {
sl@0
  2492
                __PRINT(_L("#=--- FAT32_ScanThread: Media change occured, aborting!"));
sl@0
  2493
                nRes = KErrAbort;
sl@0
  2494
                break;
sl@0
  2495
                }
sl@0
  2496
sl@0
  2497
            //-------------------------------------------
sl@0
  2498
            //-- read a portion of FAT into the buffer
sl@0
  2499
            ataFatTable.AcquireLock();
sl@0
  2500
            
sl@0
  2501
            //-- check if the thread was requested to finish
sl@0
  2502
            if(!pSelf->AllowedToLive()) 
sl@0
  2503
                {
sl@0
  2504
                ataFatTable.ReleaseLock();
sl@0
  2505
                nRes = KErrAbort;
sl@0
  2506
                break;
sl@0
  2507
                }
sl@0
  2508
sl@0
  2509
            //-- actual read
sl@0
  2510
            //__PRINT3(_L("#=--- FAT32_ScanThread: read %d bytes pos:0x%x, boost:%d"), bytesToRead, mediaPos, pSelf->IsPriorityBoosted());
sl@0
  2511
sl@0
  2512
            nRes = fatMount.LocalDrive()->Read(mediaPos, bytesToRead, pSelf->iFatChunkBuf); 
sl@0
  2513
            
sl@0
  2514
            ataFatTable.ReleaseLock();
sl@0
  2515
sl@0
  2516
            //-------------------------------------------
sl@0
  2517
            //-- analyse the read error code
sl@0
  2518
            if(nRes != KErrNone)
sl@0
  2519
                {
sl@0
  2520
                __PRINT1(_L("#=--- FAT32_ScanThread read error! res:%d"), nRes);
sl@0
  2521
                break; //-- abort scanning
sl@0
  2522
                }
sl@0
  2523
sl@0
  2524
            //-------------------------------------------
sl@0
  2525
            //-- parse FAT from the buffer
sl@0
  2526
            
sl@0
  2527
            //-- we need number of free and occupied entries in the _current_ FAT chunk being read and parsed
sl@0
  2528
            fatScanParam.iCurrFreeEntries     = 0;
sl@0
  2529
            fatScanParam.iCurrOccupiedEntries = 0;
sl@0
  2530
sl@0
  2531
            ataFatTable.DoParseFatBuf(ptrData, fatScanParam);
sl@0
  2532
sl@0
  2533
            //--- process the the results of FAT buffer parsing
sl@0
  2534
            nRes = pSelf->Thread_ProcessCollectedFreeEntries(fatScanParam);
sl@0
  2535
            if(nRes != KErrNone || !pSelf->AllowedToLive())
sl@0
  2536
                {//-- some types of worker threads may wish to finish normally but prematurely, by the result of Thread_ProcessCollectedFreeEntries()
sl@0
  2537
                break; //-- abort scanning
sl@0
  2538
                }
sl@0
  2539
sl@0
  2540
sl@0
  2541
            //-- allow this thread to be preempted by another one that wants to access the media driver.
sl@0
  2542
            //-- without this wait we will have priority inversion, because this (low priority) thread continiously reads data by big chunks 
sl@0
  2543
            //-- and doesn't allow others to access the driver.
sl@0
  2544
            //-- On the other hand, if the thread's priority is boosted, there is no reason to be polite.
sl@0
  2545
            if(!pSelf->IsPriorityBoosted())
sl@0
  2546
                User::After(K1mSec); //-- User::After() granularity can be much coarser than 1ms
sl@0
  2547
sl@0
  2548
            //-------------------------------------------
sl@0
  2549
            mediaPos += bytesToRead;
sl@0
  2550
            rem -= bytesToRead;
sl@0
  2551
        
sl@0
  2552
            }//while(rem)
sl@0
  2553
    
sl@0
  2554
        }//if(nRes == KErrNone)
sl@0
  2555
sl@0
  2556
sl@0
  2557
    //-- perform thread postamble work
sl@0
  2558
    nRes = pSelf->Thread_Postamble(nRes);
sl@0
  2559
sl@0
  2560
    return nRes;
sl@0
  2561
    }
sl@0
  2562
sl@0
  2563
sl@0
  2564
sl@0
  2565
sl@0
  2566
sl@0
  2567
sl@0
  2568
sl@0
  2569
sl@0
  2570
sl@0
  2571
sl@0
  2572
sl@0
  2573
sl@0
  2574
sl@0
  2575
sl@0
  2576
sl@0
  2577
sl@0
  2578
sl@0
  2579
sl@0
  2580
sl@0
  2581
sl@0
  2582
sl@0
  2583
sl@0
  2584
sl@0
  2585
sl@0
  2586
sl@0
  2587
sl@0
  2588
sl@0
  2589
sl@0
  2590
sl@0
  2591
sl@0
  2592
sl@0
  2593
sl@0
  2594