os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/fat_table32.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/fat_table32.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,2594 @@
     1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// f32\sfat32\fat_table32.cpp
    1.18 +// FAT32 File Allocation Table classes implementation
    1.19 +// 
    1.20 +//
    1.21 +
    1.22 +/**
    1.23 + @file
    1.24 + @internalTechnology
    1.25 +*/
    1.26 +
    1.27 +
    1.28 +
    1.29 +#include "sl_std.h"
    1.30 +#include "sl_fatcache32.h"
    1.31 +#include "fat_table32.h"
    1.32 +
    1.33 +
    1.34 +
    1.35 +
    1.36 +//---------------------------------------------------------------------------------------------------------------------------------------
    1.37 +/** 
    1.38 +    Implements automatic locking object.
    1.39 +    Calls TDriveInterface::AcquireLock() on construction and TDriveInterface::ReleaseLock() on destruction. 
    1.40 +    Can be constructed on the stack only.
    1.41 +*/
    1.42 +class XAutoLock
    1.43 +    {
    1.44 +     public:
    1.45 +       inline XAutoLock(CFatMountCB* apOwner) : iDrv(apOwner->DriveInterface()) {iDrv.AcquireLock();}
    1.46 +       inline XAutoLock(TDriveInterface& aDrv) : iDrv(aDrv) {iDrv.AcquireLock();}
    1.47 +       inline ~XAutoLock() {iDrv.ReleaseLock();}
    1.48 +
    1.49 +     private:
    1.50 +        void* operator new(TUint); //-- disable creating objects on heap.
    1.51 +        void* operator new(TUint, void*);
    1.52 +
    1.53 +     private:
    1.54 +        TDriveInterface &iDrv; ///< reference to the drive interface
    1.55 +    };
    1.56 +
    1.57 +
    1.58 +//---------------------------------------------------------------------------------------------------------------------------------------
    1.59 +
    1.60 +
    1.61 +
    1.62 +//#######################################################################################################################################
    1.63 +//#     CFatTable class implementation 
    1.64 +//#######################################################################################################################################
    1.65 +
    1.66 +/**
    1.67 +    FAT object factory method.
    1.68 +    Constructs either CAtaFatTable or CRamFatTable depending on the media type parameter
    1.69 +
    1.70 +    @param aOwner Pointer to the owning mount
    1.71 +    @param aLocDrvCaps local drive attributes
    1.72 +    @leave KErrNoMemory
    1.73 +    @return Pointer to the Fat table
    1.74 +*/
    1.75 +CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps)
    1.76 +	{
    1.77 +    CFatTable* pFatTable=NULL;
    1.78 +    
    1.79 +    switch(aLocDrvCaps.iType)
    1.80 +        {
    1.81 +        case EMediaRam:
    1.82 +		    {//-- this is RAM media, try to create CRamFatTable instance.
    1.83 +            const TFatType fatType = aOwner.FatType();
    1.84 +            
    1.85 +            if(fatType != EFat16 && fatType != EFat32)
    1.86 +                {//-- CRamFatTable doesn't support FAT12, FAT16 & FAT32 only.
    1.87 +                __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType);
    1.88 +                ASSERT(0);
    1.89 +                return NULL;
    1.90 +                }
    1.91 +            
    1.92 +            pFatTable = CRamFatTable::NewL(aOwner);
    1.93 +            }
    1.94 +        break;
    1.95 +
    1.96 +        default:
    1.97 +            //-- other media
    1.98 +            pFatTable = CAtaFatTable::NewL(aOwner);
    1.99 +        break;
   1.100 +        };
   1.101 +
   1.102 +	return pFatTable;
   1.103 +	}
   1.104 +
   1.105 +
   1.106 +CFatTable::CFatTable(CFatMountCB& aOwner)
   1.107 +{
   1.108 +    iOwner = &aOwner;
   1.109 +    ASSERT(iOwner);
   1.110 +}
   1.111 +
   1.112 +CFatTable::~CFatTable()
   1.113 +{
   1.114 +    //-- destroy cache ignoring dirty data in cache
   1.115 +    //-- the destructor isn't an appropriate place to flush the data.
   1.116 +    Dismount(ETrue); 
   1.117 +}
   1.118 +
   1.119 +//-----------------------------------------------------------------------------
   1.120 +
   1.121 +/**
   1.122 +    Initialise the object, get data from the owning CFatMountCB
   1.123 +*/
   1.124 +void CFatTable::InitializeL()
   1.125 +    {
   1.126 +    ASSERT(iOwner);
   1.127 +
   1.128 +    //-- get FAT type from the owner
   1.129 +    iFatType = iOwner->FatType();
   1.130 +    ASSERT(IsFat12() || IsFat16() || IsFat32());
   1.131 +
   1.132 +    //-- set the EOC code
   1.133 +    iFatEocCode = EocCodeByFatType(iFatType);
   1.134 +    
   1.135 +
   1.136 +
   1.137 +
   1.138 +    iFreeClusterHint = KFatFirstSearchCluster;
   1.139 +
   1.140 +    //-- cache the media attributes
   1.141 +    TLocalDriveCapsV2 caps;
   1.142 +    TPckg<TLocalDriveCapsV2> capsPckg(caps);
   1.143 +    User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
   1.144 +    iMediaAtt = caps.iMediaAtt;
   1.145 +
   1.146 +    //-- obtain maximal number of entries in the table
   1.147 +    iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use
   1.148 +
   1.149 +    __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries);
   1.150 +    }
   1.151 +
   1.152 +//-----------------------------------------------------------------------------
   1.153 +
   1.154 +/** 
   1.155 +    Decrements the free cluster count.
   1.156 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.157 +    cluster of a large file. Use more than one cluster granularity.
   1.158 +     
   1.159 +    @param  aCount a number of clusters 
   1.160 +*/
   1.161 +void CFatTable::DecrementFreeClusterCount(TUint32 aCount)
   1.162 +    {
   1.163 +    __ASSERT_DEBUG(iFreeClusters >= aCount, Fault(EFatCorrupt));
   1.164 +    iFreeClusters -= aCount;
   1.165 +    }
   1.166 +
   1.167 +/** 
   1.168 +    Increments the free cluster count.
   1.169 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.170 +    cluster of a large file. Use more than one cluster granularity.
   1.171 +
   1.172 +    @param  aCount a number of clusters 
   1.173 +*/
   1.174 +void CFatTable::IncrementFreeClusterCount(TUint32 aCount)
   1.175 +    {
   1.176 +	const TUint32 newVal = iFreeClusters+aCount;
   1.177 +    __ASSERT_DEBUG(newVal<=MaxEntries(), Fault(EFatCorrupt));
   1.178 +    
   1.179 +    iFreeClusters = newVal;
   1.180 +    }
   1.181 +
   1.182 +/** @return number of free clusters in the FAT */
   1.183 +TUint32 CFatTable::NumberOfFreeClusters(TBool /*aSyncOperation=EFalse*/) const
   1.184 +    {
   1.185 +    return FreeClusters();
   1.186 +    }
   1.187 +
   1.188 +void CFatTable::SetFreeClusters(TUint32 aFreeClusters)
   1.189 +    {   
   1.190 +    iFreeClusters=aFreeClusters;
   1.191 +    }
   1.192 +
   1.193 +/**
   1.194 +    Get the hint about the last known free cluster number.
   1.195 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.196 +    cluster of a large file.
   1.197 +
   1.198 +    @return cluster number supposedly close to the free one.
   1.199 +*/
   1.200 +TUint32 CFatTable::FreeClusterHint() const 
   1.201 +    {
   1.202 +    ASSERT(ClusterNumberValid(iFreeClusterHint));
   1.203 +    return iFreeClusterHint;
   1.204 +    } 
   1.205 +
   1.206 +/**
   1.207 +    Set a free cluster hint. The next search fro the free cluster can start from this value.
   1.208 +    aCluster doesn't have to be a precise number of free FAT entry; it just needs to be as close as possible to the 
   1.209 +    free entries chain.
   1.210 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.211 +    cluster of a large file.
   1.212 +
   1.213 +    @param aCluster cluster number hint.
   1.214 +*/
   1.215 +void CFatTable::SetFreeClusterHint(TUint32 aCluster) 
   1.216 +    {
   1.217 +    ASSERT(ClusterNumberValid(aCluster));
   1.218 +    iFreeClusterHint=aCluster;
   1.219 +    } 
   1.220 +
   1.221 +//-----------------------------------------------------------------------------
   1.222 +
   1.223 +/**
   1.224 +    Find out the number of free clusters on the volume.
   1.225 +    Reads whole FAT and counts free clusters.
   1.226 +*/
   1.227 +void CFatTable::CountFreeClustersL()
   1.228 +    {
   1.229 +    __PRINT1(_L("#- CFatTable::CountFreeClustersL(), drv:%d"), iOwner->DriveNumber());
   1.230 +
   1.231 +    const TUint32 KUsableClusters = iOwner->UsableClusters();
   1.232 +    (void)KUsableClusters;
   1.233 +
   1.234 +    TUint32 freeClusters = 0;
   1.235 +    TUint32 firstFreeCluster = 0;
   1.236 +
   1.237 +    TTime   timeStart;
   1.238 +    TTime   timeEnd;
   1.239 +    timeStart.UniversalTime(); //-- take start time
   1.240 +
   1.241 +    //-- walk through whole FAT table looking for free clusters
   1.242 +	for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i)
   1.243 +    {
   1.244 +	    if(ReadL(i) == KSpareCluster)
   1.245 +            {//-- found a free cluster
   1.246 +		    ++freeClusters;
   1.247 +            
   1.248 +            if(!firstFreeCluster)
   1.249 +                firstFreeCluster = i;
   1.250 +            }
   1.251 +	    }
   1.252 +
   1.253 +    timeEnd.UniversalTime(); //-- take end time
   1.254 +    const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
   1.255 +    __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime);
   1.256 +    (void)msScanTime;
   1.257 +
   1.258 +    if(!firstFreeCluster) //-- haven't found free clusters on the volume
   1.259 +        firstFreeCluster = KFatFirstSearchCluster;
   1.260 +
   1.261 +    ASSERT(freeClusters <= KUsableClusters);
   1.262 +
   1.263 +    SetFreeClusters(freeClusters);
   1.264 +    SetFreeClusterHint(firstFreeCluster);
   1.265 +    }
   1.266 +
   1.267 +//-----------------------------------------------------------------------------
   1.268 +
   1.269 +/**
   1.270 +Count the number of contiguous cluster from a start cluster
   1.271 +
   1.272 +@param aStartCluster cluster to start counting from
   1.273 +@param anEndCluster contains the end cluster number upon return
   1.274 +@param aMaxCount Maximum cluster required
   1.275 +@leave System wide error values
   1.276 +@return Number of contiguous clusters from aStartCluster.
   1.277 +*/
   1.278 +TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const
   1.279 +	{
   1.280 +	__PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount);
   1.281 +	TUint32 clusterListLen=1;
   1.282 +	TInt endCluster=aStartCluster;
   1.283 +	TInt64 endClusterPos=DataPositionInBytes(endCluster);
   1.284 +	while (clusterListLen<aMaxCount)
   1.285 +		{
   1.286 +		TInt oldCluster=endCluster;
   1.287 +		TInt64 oldClusterPos=endClusterPos;
   1.288 +		if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
   1.289 +			{
   1.290 +			endCluster=oldCluster;
   1.291 +			break;
   1.292 +			}
   1.293 +		clusterListLen++;
   1.294 +		}
   1.295 +	anEndCluster=endCluster;
   1.296 +	return(clusterListLen);
   1.297 +	}	
   1.298 +
   1.299 +//-----------------------------------------------------------------------------
   1.300 +
   1.301 +/**
   1.302 +    Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full).
   1.303 +
   1.304 +    @param aNumber  amount of clusters to allocate
   1.305 +    @param aCluster FAT entry index to start with.
   1.306 +
   1.307 +    @leave KErrDiskFull + system wide error codes
   1.308 +*/
   1.309 +void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
   1.310 +	{
   1.311 +	__PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster);
   1.312 +	__ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
   1.313 +	
   1.314 +	while(aNumber && GetNextClusterL(aCluster))
   1.315 +		aNumber--;
   1.316 +
   1.317 +    if(!aNumber)
   1.318 +        return;
   1.319 +
   1.320 +    if(!RequestFreeClusters(aNumber))
   1.321 +		{
   1.322 +		__PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull"));
   1.323 +		User::Leave(KErrDiskFull);
   1.324 +		}
   1.325 +
   1.326 +
   1.327 +    TUint32 freeCluster = 0;
   1.328 +    
   1.329 +    //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL()
   1.330 +    for(TUint i=0; i<aNumber; ++i)
   1.331 +        {
   1.332 +        freeCluster = FindClosestFreeClusterL(aCluster);
   1.333 +        WriteFatEntryEofL(freeCluster); //	Must write EOF for FindClosestFreeCluster to work again
   1.334 +        WriteL(aCluster,freeCluster);
   1.335 +        aCluster=freeCluster;
   1.336 +        }
   1.337 +    
   1.338 +    //-- decrement number of available clusters
   1.339 +    DecrementFreeClusterCount(aNumber);
   1.340 +
   1.341 +    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from
   1.342 +    SetFreeClusterHint(aCluster); 
   1.343 +    
   1.344 +    }
   1.345 +
   1.346 +//-----------------------------------------------------------------------------
   1.347 +
   1.348 +/**
   1.349 +    Allocate and mark as EOF a single cluster as close as possible to aNearestCluster
   1.350 +
   1.351 +    @param aNearestCluster Cluster the new cluster should be nearest to
   1.352 +    @leave System wide error codes
   1.353 +    @return The cluster number allocated
   1.354 +*/
   1.355 +TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
   1.356 +	{
   1.357 +	__PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster);
   1.358 +	
   1.359 +    const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster);
   1.360 +	WriteFatEntryEofL(freeCluster);
   1.361 +	DecrementFreeClusterCount(1);
   1.362 +
   1.363 +    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from.
   1.364 +    SetFreeClusterHint(freeCluster); 
   1.365 +
   1.366 +	return(freeCluster);
   1.367 +	}	
   1.368 +
   1.369 +//-----------------------------------------------------------------------------
   1.370 +
   1.371 +/**
   1.372 +    Allocate and link a cluster chain, leaves if there are not enough free clusters.
   1.373 +    Chain starts as close as possible to aNearestCluster, last cluster will be marked as EOF.
   1.374 +
   1.375 +    @param aNumber Number of clusters to allocate
   1.376 +    @param aNearestCluster Cluster the new chain should be nearest to
   1.377 +    @leave System wide error codes
   1.378 +    @return The first cluster number allocated
   1.379 +*/
   1.380 +TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster)
   1.381 +	{
   1.382 +    __PRINT2(_L("CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster);
   1.383 +	__ASSERT_DEBUG(aNumber>0, Fault(EFatBadParameter));
   1.384 +
   1.385 +	if(!RequestFreeClusters(aNumber))
   1.386 +    	{
   1.387 +		__PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull"));
   1.388 +		User::Leave(KErrDiskFull);
   1.389 +		}
   1.390 +
   1.391 +	TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster);
   1.392 +	if (aNumber>1)
   1.393 +		ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster);
   1.394 +
   1.395 +    return(firstCluster);
   1.396 +	}	
   1.397 +
   1.398 +//-----------------------------------------------------------------------------
   1.399 +
   1.400 +/**
   1.401 +    Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported.
   1.402 +    @param aFreedClusters array with FAT numbers of clusters that shall be marked as "deleted"
   1.403 +*/
   1.404 +void CFatTable::DoFreedClustersNotify(RClusterArray &aFreedClusters)
   1.405 +{
   1.406 +    ASSERT(iMediaAtt & KMediaAttDeleteNotify);
   1.407 +
   1.408 +    const TUint clusterCount = aFreedClusters.Count();
   1.409 +
   1.410 +    if(!clusterCount)
   1.411 +        return;
   1.412 +    
   1.413 +    FlushL(); //-- Commit the FAT changes to disk first to be safe
   1.414 +
   1.415 +    const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2();
   1.416 +
   1.417 +    TInt64  byteAddress = 0;	
   1.418 +	TUint   deleteLen = 0;	// zero indicates no clusters accumulated yet
   1.419 +
   1.420 +	for (TUint i=0; i<clusterCount; ++i)
   1.421 +	{
   1.422 +        const TUint currCluster = aFreedClusters[i];
   1.423 +        
   1.424 +        if (deleteLen == 0)
   1.425 +		    byteAddress = DataPositionInBytes(currCluster); //-- start of the media range
   1.426 +        
   1.427 +        deleteLen += bytesPerCluster;
   1.428 +
   1.429 +        //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver
   1.430 +		if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1))
   1.431 +        {
   1.432 +            //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen);
   1.433 +			//__PRINT2(_L("   first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster);
   1.434 +	
   1.435 +            const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen);
   1.436 +			if(r != KErrNone)
   1.437 +                {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; 
   1.438 +                 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media.
   1.439 +                const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement);
   1.440 +                __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
   1.441 +
   1.442 +                if(platSecEnabled)
   1.443 +                    {
   1.444 +                    //-- if PlatSec is enabled, we can't afford jeopardize the security; without DeleteNotify()
   1.445 +                    //-- it's possible to pick up data from deleted files, so, panic the file server.
   1.446 +                    Fault(EFatBadLocalDrive);
   1.447 +                    }
   1.448 +                else
   1.449 +                    {
   1.450 +                    //-- if PlatSec is disabled, it's OK to ignore the NAND fault in release mode.
   1.451 +                    __ASSERT_DEBUG(0, Fault(EFatBadLocalDrive));
   1.452 +                    }        
   1.453 +                }
   1.454 +
   1.455 +            
   1.456 +            deleteLen = 0;
   1.457 +        }
   1.458 +
   1.459 +    }
   1.460 +
   1.461 +    //-- empty the array.
   1.462 +    aFreedClusters.Reset();
   1.463 +}
   1.464 +
   1.465 +//-----------------------------------------------------------------------------
   1.466 +/**
   1.467 +    Mark a chain of clusters as free in the FAT. 
   1.468 +
   1.469 +    @param aCluster Start cluster of cluster chain to free
   1.470 +    @leave System wide error codes
   1.471 +*/
   1.472 +void CFatTable::FreeClusterListL(TUint32 aCluster)
   1.473 +	{
   1.474 +	__PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster);
   1.475 +	if (aCluster == KSpareCluster)
   1.476 +		return; 
   1.477 +
   1.478 +	//-- here we can store array of freed cluster numbers in order to 
   1.479 +    //-- notify media drive about the media addresses marked as "invalid"
   1.480 +    RClusterArray deletedClusters;      
   1.481 +	CleanupClosePushL(deletedClusters);
   1.482 +
   1.483 +    //-- if ETrue, we need to notify media driver about invalidated media addressses
   1.484 +    const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify;
   1.485 +
   1.486 +    //-- this is a maximal number of FAT entries in the deletedClusters array.
   1.487 +    //-- as soon as we collect this number of entries in the array, FAT cache will be flushed
   1.488 +    //-- and driver notified. The array will be emptied. Used to avoid huge array when deleting
   1.489 +    //--  large files on NAND media 
   1.490 +    const TUint KSubListLen = 4096;
   1.491 +    ASSERT(IsPowerOf2(KSubListLen));
   1.492 +
   1.493 +    TUint32 lastKnownFreeCluster = FreeClusterHint();
   1.494 +    TUint32 cntFreedClusters = 0;
   1.495 +
   1.496 +    TUint32 currCluster = aCluster;
   1.497 +    TInt    nextCluster = aCluster;
   1.498 +
   1.499 +    for(;;)
   1.500 +    {
   1.501 +        const TBool bEOF = !GetNextClusterL(nextCluster);    
   1.502 +        WriteL(currCluster, KSpareCluster);
   1.503 +
   1.504 +        lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster);
   1.505 +
   1.506 +		// Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe 
   1.507 +		// to do once the FAT changes have been written to disk.
   1.508 +        if(bFreeClustersNotify)
   1.509 +            deletedClusters.Append(currCluster);
   1.510 +
   1.511 +        ++cntFreedClusters;
   1.512 +        currCluster = nextCluster;
   1.513 +
   1.514 +		if (bEOF || aCluster == KSpareCluster)
   1.515 +			break;
   1.516 +
   1.517 +        if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0)
   1.518 +        {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array.
   1.519 +            IncrementFreeClusterCount(cntFreedClusters);
   1.520 +            cntFreedClusters = 0;
   1.521 +
   1.522 +            SetFreeClusterHint(lastKnownFreeCluster);
   1.523 +            DoFreedClustersNotify(deletedClusters);
   1.524 +        }
   1.525 +
   1.526 +    }
   1.527 +
   1.528 +    //-- increase the number of free clusters and notify the driver if required.
   1.529 +    IncrementFreeClusterCount(cntFreedClusters);
   1.530 +    SetFreeClusterHint(lastKnownFreeCluster);
   1.531 +    
   1.532 +    if(bFreeClustersNotify)
   1.533 +        DoFreedClustersNotify(deletedClusters);
   1.534 +
   1.535 +	CleanupStack::PopAndDestroy(&deletedClusters);
   1.536 +	}
   1.537 +
   1.538 +//-----------------------------------------------------------------------------
   1.539 +
   1.540 +/**
   1.541 +    Find a free cluster nearest to aCluster, Always checks to the right of aCluster first 
   1.542 +    but checks in both directions in the Fat.
   1.543 +
   1.544 +    @param aCluster Cluster to find nearest free cluster to.
   1.545 +    @leave KErrDiskFull + system wide error codes
   1.546 +    @return cluster number found
   1.547 +*/
   1.548 +TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster)
   1.549 +	{
   1.550 +    __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
   1.551 +	
   1.552 +    if(!ClusterNumberValid(aCluster))
   1.553 +        {
   1.554 +        ASSERT(0);
   1.555 +        User::Leave(KErrCorrupt);
   1.556 +        }
   1.557 +
   1.558 +    if(!RequestFreeClusters(1))
   1.559 +	    {//-- there is no at least 1 free cluster available
   1.560 +    	__PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
   1.561 +        User::Leave(KErrDiskFull);
   1.562 +        }
   1.563 +
   1.564 +    //-- 1. look if the given index contains a free entry 
   1.565 +    if(ReadL(aCluster) != KSpareCluster)
   1.566 +        {//-- no, it doesn't...
   1.567 +        
   1.568 +        //-- 2. look in both directions starting from the aCluster, looking in the right direction first
   1.569 +        
   1.570 +        const TUint32 maxEntries = MaxEntries();
   1.571 +        const TUint32 MinIdx = KFatFirstSearchCluster;
   1.572 +        const TUint32 MaxIdx = maxEntries-1;
   1.573 +
   1.574 +        TBool canGoRight = ETrue;
   1.575 +        TBool canGoLeft = ETrue;
   1.576 +    
   1.577 +        TUint32 rightIdx = aCluster;
   1.578 +        TUint32 leftIdx  = aCluster;
   1.579 +        
   1.580 +        for(TUint i=0; i<maxEntries; ++i)
   1.581 +            {
   1.582 +            if(canGoRight)
   1.583 +                {
   1.584 +                if(rightIdx < MaxIdx)
   1.585 +                    ++rightIdx;
   1.586 +                else
   1.587 +                    canGoRight = EFalse;
   1.588 +                }
   1.589 +
   1.590 +            if(canGoLeft)
   1.591 +                {
   1.592 +                if(leftIdx > MinIdx)
   1.593 +                    --leftIdx;
   1.594 +                else        
   1.595 +                    canGoLeft = EFalse;
   1.596 +                }
   1.597 +
   1.598 +            if(!canGoRight && !canGoLeft)
   1.599 +	            {
   1.600 +    	        __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2"));
   1.601 +                User::Leave(KErrDiskFull);
   1.602 +                }
   1.603 +
   1.604 +            if(canGoRight && ReadL(rightIdx) == KSpareCluster)
   1.605 +			    {
   1.606 +			    aCluster = rightIdx;
   1.607 +			    break;
   1.608 +			    }
   1.609 +
   1.610 +		    if (canGoLeft && ReadL(leftIdx) == KSpareCluster)
   1.611 +			    {
   1.612 +			    aCluster = leftIdx;
   1.613 +			    break;
   1.614 +			    }
   1.615 +            }//for(..)
   1.616 +
   1.617 +        }//if(ReadL(aCluster) != KSpareCluster)
   1.618 +
   1.619 +
   1.620 +    //-- note: do not update free cluster hint here by calling SetFreeClusterHint(). This is going to be 
   1.621 +    //-- expensive especially if overridden methods with synchronisation are called. Instead, set the number of 
   1.622 +    //-- the last known free cluster in the caller of this internal method.
   1.623 +
   1.624 +    //__PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster);
   1.625 +
   1.626 +    return aCluster;
   1.627 +	}
   1.628 +
   1.629 +//-----------------------------------------------------------------------------
   1.630 +
   1.631 +/**
   1.632 +    Converts a cluster number to byte offset in the FAT
   1.633 +
   1.634 +    @param aFatIndex Cluster number
   1.635 +    @return Number of bytes from the beginning of the FAT
   1.636 +*/
   1.637 +TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const
   1.638 +	{
   1.639 +    switch(FatType())
   1.640 +        {
   1.641 +        case EFat12:
   1.642 +            return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry
   1.643 +
   1.644 +        case EFat16:
   1.645 +            return aFatIndex<<1; //-- 2 bytes per FAT entry
   1.646 +
   1.647 +        case EFat32:
   1.648 +            return aFatIndex<<2; //-- 4 bytes per FAT entry
   1.649 +
   1.650 +        default:
   1.651 +            ASSERT(0);
   1.652 +            return 0;//-- get rid of warning
   1.653 +        };
   1.654 +
   1.655 +	}
   1.656 +
   1.657 +//-----------------------------------------------------------------------------
   1.658 +
   1.659 +/**
   1.660 +    Checks if we have at least aClustersRequired clusters free in the FAT.
   1.661 +    This is, actually a dummy implementation.
   1.662 +
   1.663 +    @param  aClustersRequired number of free clusters required
   1.664 +    @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
   1.665 +*/
   1.666 +TBool CFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
   1.667 +    {
   1.668 +    //__PRINT1(_L("#- CFatTable::RequestFreeClusters(%d)"),aClustersRequired);
   1.669 +    ASSERT(aClustersRequired >0);
   1.670 +    return (NumberOfFreeClusters() >= aClustersRequired);
   1.671 +    }
   1.672 +
   1.673 +//-----------------------------------------------------------------------------
   1.674 +/**
   1.675 +    @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
   1.676 +*/
   1.677 +TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const 
   1.678 +    {
   1.679 +    return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries); 
   1.680 +    }
   1.681 +    
   1.682 +
   1.683 +
   1.684 +//#######################################################################################################################################
   1.685 +//#     CAtaFatTable class implementation 
   1.686 +//#######################################################################################################################################
   1.687 +
   1.688 +/**
   1.689 +    Constructor
   1.690 +*/
   1.691 +CAtaFatTable::CAtaFatTable(CFatMountCB& aOwner)
   1.692 +             :CFatTable(aOwner), iDriveInteface(aOwner.DriveInterface())
   1.693 +    {
   1.694 +        iState = ENotInitialised;
   1.695 +    }
   1.696 +
   1.697 +
   1.698 +CAtaFatTable::~CAtaFatTable()
   1.699 +    {
   1.700 +    DestroyHelperThread();
   1.701 +    }
   1.702 +
   1.703 +
   1.704 +/** factory method */
   1.705 +CAtaFatTable* CAtaFatTable::NewL(CFatMountCB& aOwner)
   1.706 +{
   1.707 +    __PRINT1(_L("CAtaFatTable::NewL() drv:%d"),aOwner.DriveNumber());
   1.708 +    CAtaFatTable* pSelf = new (ELeave) CAtaFatTable(aOwner);
   1.709 +
   1.710 +    CleanupStack::PushL(pSelf);
   1.711 +    pSelf->InitializeL();
   1.712 +    CleanupStack::Pop();
   1.713 +
   1.714 +    return pSelf;
   1.715 +}
   1.716 +
   1.717 +
   1.718 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.719 +
   1.720 +/**
   1.721 +    CAtaFatTable's FAT cache factory method.
   1.722 +    Creates fixed cache for FAT12/FAT16 or LRU cache for FAT32
   1.723 +*/
   1.724 +void CAtaFatTable::CreateCacheL()
   1.725 +{
   1.726 +    ASSERT(iOwner);
   1.727 +    const TUint32 fatSize=iOwner->FatSizeInBytes();
   1.728 +    __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize);
   1.729 +	
   1.730 +
   1.731 +    //-- according to FAT specs:
   1.732 +    //-- FAT12 max size is 4084 entries or 6126 bytes                                               => create fixed cache for whole FAT
   1.733 +    //-- FAT16 min size is 4085 entries or 8170 bytes, max size is 65525 entries or 131048 bytes    => create fixed cache for whole FAT
   1.734 +    //-- FAT32 min size is 65526 entries or 262104 bytes                                            => create LRU paged cache of max size: KFat32LRUCacheSize
   1.735 +
   1.736 +    ASSERT(!iCache);
   1.737 +
   1.738 +    //-- this is used for chaches granularity sanity check 
   1.739 +    const TUint32 KMinGranularityLog2 = KDefSectorSzLog2;  //-- 512 bytes is a minimal allowed granularity
   1.740 +    const TUint32 KMaxGranularityLog2 = 18; //-- 256K is a maximal allowed granularity
   1.741 +
   1.742 +    switch(FatType())
   1.743 +    {
   1.744 +        //-- create fixed FAT12 cache
   1.745 +        case EFat12: 
   1.746 +            iCache = CFat12Cache::NewL(iOwner, fatSize); 
   1.747 +        break;
   1.748 +    
   1.749 +        //-- create fixed FAT16 cache
   1.750 +        case EFat16: 
   1.751 +            {
   1.752 +            TUint32 fat16_ReadGranularity_Log2; //-- FAT16 cache read granularity Log2
   1.753 +            TUint32 fat16_WriteGranularity_Log2;//-- FAT16 cache write granularity Log2
   1.754 +            
   1.755 +            iOwner->FatConfig().Fat16FixedCacheParams(fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2);
   1.756 +            
   1.757 +            //-- check if granularity values look sensible
   1.758 +            const TBool bParamsValid = fat16_ReadGranularity_Log2  >= KMinGranularityLog2 && fat16_ReadGranularity_Log2  <= KMaxGranularityLog2 &&
   1.759 +                                       fat16_WriteGranularity_Log2 >= KMinGranularityLog2 && fat16_WriteGranularity_Log2 <= KMaxGranularityLog2;
   1.760 +
   1.761 +             __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity)); 
   1.762 +
   1.763 +
   1.764 +            iCache = CFat16FixedCache::NewL(iOwner, fatSize, fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2); 
   1.765 +            }
   1.766 +        break;
   1.767 +
   1.768 +        //-- create FAT32 LRU paged cache
   1.769 +        case EFat32: 
   1.770 +            {
   1.771 +            TUint32 fat32_LRUCache_MaxMemSize;  //-- Maximum memory for the LRU FAT32 cache
   1.772 +            TUint32 fat32_ReadGranularity_Log2; //-- FAT32 cache read granularity Log2
   1.773 +            TUint32 fat32_WriteGranularity_Log2;//-- FAT32 cache write granularity Log2
   1.774 +    
   1.775 +            iOwner->FatConfig().Fat32LruCacheParams(fat32_ReadGranularity_Log2, fat32_WriteGranularity_Log2, fat32_LRUCache_MaxMemSize);
   1.776 +
   1.777 +            
   1.778 +            //-- check if granularity  and required cache size values look sensible
   1.779 +            const TBool bParamsValid = fat32_ReadGranularity_Log2  >= KMinGranularityLog2 && fat32_ReadGranularity_Log2  <= KMaxGranularityLog2 &&
   1.780 +                                       fat32_WriteGranularity_Log2 >= KMinGranularityLog2 && fat32_WriteGranularity_Log2 <= KMaxGranularityLog2 &&
   1.781 +                                       fat32_LRUCache_MaxMemSize >= 8*K1KiloByte && fat32_LRUCache_MaxMemSize < 4*K1MegaByte;
   1.782 +            
   1.783 +            __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity)); 
   1.784 +            
   1.785 +            iCache = CFat32LruCache::NewL(iOwner, fat32_LRUCache_MaxMemSize, fat32_ReadGranularity_Log2, fat32_WriteGranularity_Log2);
   1.786 +            }
   1.787 +        break;
   1.788 +
   1.789 +        default:
   1.790 +        ASSERT(0);
   1.791 +        User::Leave(KErrCorrupt);
   1.792 +        break;
   1.793 +    };
   1.794 +
   1.795 +    ASSERT(iCache);
   1.796 +}
   1.797 +
   1.798 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.799 +
   1.800 +/**
   1.801 +    Destroys a helper thread object.
   1.802 +    If the thread is running, stops it first. than deletes the ipHelperThread and sets it to NULL
   1.803 +*/
   1.804 +void CAtaFatTable::DestroyHelperThread()
   1.805 +{
   1.806 +
   1.807 +    if(!ipHelperThread)
   1.808 +        return;
   1.809 +  
   1.810 +    __PRINT1(_L("CAtaFatTable::DestroyHelperThread(), drv:%d"), iOwner->DriveNumber());
   1.811 +    ipHelperThread->ForceStop();
   1.812 +    delete ipHelperThread;
   1.813 +    ipHelperThread = NULL;
   1.814 +}
   1.815 +
   1.816 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.817 +
   1.818 +/**
   1.819 +    Flush the FAT cache on disk
   1.820 +    @leave System wide error codes
   1.821 +*/
   1.822 +void CAtaFatTable::FlushL()
   1.823 +	{
   1.824 +    __PRINT1(_L("CAtaFatTable::FlushL(), drv:%d"), iOwner->DriveNumber());
   1.825 +
   1.826 +    //-- the data can't be written if the mount is inconsistent
   1.827 +    iOwner->CheckStateConsistentL();
   1.828 +
   1.829 +    if (iCache)
   1.830 +		iCache->FlushL();
   1.831 +	}
   1.832 +
   1.833 +
   1.834 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.835 +
   1.836 +/**
   1.837 +    Dismount the cache. Stops any activity, deallocates caches etc.
   1.838 +    @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded.
   1.839 +*/
   1.840 +void CAtaFatTable::Dismount(TBool aDiscardDirtyData)
   1.841 +	{
   1.842 +    __PRINT3(_L("#=-= CAtaFatTable::Dismount(%d), drv:%d, state:%d"), aDiscardDirtyData, iOwner->DriveNumber(), State());
   1.843 +
   1.844 +    //-- if there is a helper thread, stop it and delete its object
   1.845 +    DestroyHelperThread();
   1.846 +
   1.847 +    //-- if there is the cache, close it (it may lead to deallocating its memory)
   1.848 +	if(iCache)
   1.849 +		{
   1.850 +        //-- cache's Close() can check if the cache is clean. 
   1.851 +        //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data)
   1.852 +        //-- or if we are asked to do so.
   1.853 +        const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState();
   1.854 +        iCache->Close(bIgnoreDirtyData);
   1.855 +
   1.856 +        delete iCache;
   1.857 +		iCache=NULL;
   1.858 +		}
   1.859 +
   1.860 +     SetState(EDismounted);
   1.861 +	}
   1.862 +
   1.863 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.864 +
   1.865 +/**
   1.866 +    Invalidate whole FAT cache.
   1.867 +    Depending of cache type this may just mark cache invalid with reading on demand or re-read whole cache from the media
   1.868 +*/
   1.869 +void CAtaFatTable::InvalidateCacheL()
   1.870 +{
   1.871 +    __PRINT1(_L("CAtaFatTable::InvalidateCache(), drv:%d"), iOwner->DriveNumber());
   1.872 +
   1.873 +    //-- if we have a cache, invalidate it entirely
   1.874 +    if(iCache)
   1.875 +        {
   1.876 +        User::LeaveIfError(iCache->Invalidate());
   1.877 +        }
   1.878 +
   1.879 +    //-- invalidating whole FAT cache means that something very serious happened.
   1.880 +    //-- if we have a helper thread running, abort it.
   1.881 +    if(ipHelperThread)
   1.882 +        ipHelperThread->ForceStop();
   1.883 +
   1.884 +}
   1.885 +
   1.886 +
   1.887 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.888 +
   1.889 +/**
   1.890 +    Invalidate specified region of the FAT cache
   1.891 +    Depending of cache type this may just mark part of the cache invalid with reading on demand later
   1.892 +    or re-read whole cache from the media.
   1.893 +
   1.894 +    @param aPos absolute media position where the region being invalidated starts.
   1.895 +    @param aLength length in bytes of region to invalidate / refresh
   1.896 +*/
   1.897 +void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength)
   1.898 +	{
   1.899 +    __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength);
   1.900 +
   1.901 +    if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength))
   1.902 +        return; //-- FAT tables can't span over 4G 
   1.903 +
   1.904 +    const TUint32 mediaPos32 = I64LOW(aPos);
   1.905 +
   1.906 +    //-- we do not use other copies of FAT, so trach changes only in FAT1
   1.907 +    const TUint32 fat1StartPos = iOwner->StartOfFatInBytes();
   1.908 +    const TUint32 fat1EndPos   = fat1StartPos + iOwner->FatSizeInBytes();
   1.909 +
   1.910 +    TUint32 invRegionPosStart = 0; //-- media pos where the invalidated region starts
   1.911 +    TUint32 invRegionLen = 0;      //-- size of the invalidated region, bytes
   1.912 +    
   1.913 +    //-- calculate the FAT1 region being invalidated
   1.914 +    if(mediaPos32 < fat1StartPos)
   1.915 +        {
   1.916 +        if((mediaPos32 + aLength) <= fat1StartPos)
   1.917 +            return;
   1.918 +
   1.919 +        invRegionPosStart = fat1StartPos;
   1.920 +        invRegionLen = aLength - (fat1StartPos-mediaPos32);
   1.921 +        }
   1.922 +    else //if(mediaPos32 < fat1StartPos)
   1.923 +        {//-- mediaPos32 >= fat1StartPos)
   1.924 +        if(mediaPos32 >= fat1EndPos)
   1.925 +            return;
   1.926 +    
   1.927 +        invRegionPosStart = mediaPos32;
   1.928 +        
   1.929 +        if((mediaPos32 + aLength) <= fat1EndPos)
   1.930 +            {
   1.931 +            invRegionLen = aLength;
   1.932 +            }
   1.933 +        else 
   1.934 +            {
   1.935 +            invRegionLen = mediaPos32+aLength-fat1EndPos;
   1.936 +            }
   1.937 +        }
   1.938 +
   1.939 +    //-- convert the media pos of the region into FAT entries basis, depending on the FAT type
   1.940 +    ASSERT(invRegionPosStart >= fat1StartPos && invRegionLen <= (TUint)iOwner->FatSizeInBytes());
   1.941 +    
   1.942 +    TUint32 startFatEntry=0;
   1.943 +    TUint32 numEntries = 0;
   1.944 +
   1.945 +    switch(FatType())
   1.946 +        {
   1.947 +        case EFat12:
   1.948 +        //-- invalidate whole cache; it is not worth making calculations for such small memory region.
   1.949 +        User::LeaveIfError(iCache->Invalidate());
   1.950 +        return;
   1.951 +
   1.952 +        case EFat16:
   1.953 +        startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat16EntrySzLog2;
   1.954 +        numEntries = (invRegionLen + (sizeof(TFat16Entry)-1)) >> KFat16EntrySzLog2;
   1.955 +        break;
   1.956 +
   1.957 +        case EFat32:
   1.958 +        startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat32EntrySzLog2;
   1.959 +        numEntries = (invRegionLen + (sizeof(TFat32Entry)-1)) >> KFat32EntrySzLog2;
   1.960 +        break;
   1.961 +
   1.962 +        default:
   1.963 +        ASSERT(0);
   1.964 +        return;
   1.965 +        };
   1.966 +
   1.967 +    if(startFatEntry < KFatFirstSearchCluster)
   1.968 +        {//-- FAT[0] and FAT[1] can't be legally accessed, they are reserved entries. We need to adjust region being refreshed.
   1.969 +        if(numEntries <= KFatFirstSearchCluster)
   1.970 +            return; //-- nothing to refresh
   1.971 +                    
   1.972 +        startFatEntry += KFatFirstSearchCluster;
   1.973 +        numEntries -= KFatFirstSearchCluster;
   1.974 +        }
   1.975 +
   1.976 +    User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries));
   1.977 +	}
   1.978 +
   1.979 +
   1.980 +//-----------------------------------------------------------------------------
   1.981 +/**
   1.982 +    Initialize the object, create FAT cache if required
   1.983 +    @leave KErrNoMemory
   1.984 +*/
   1.985 +void CAtaFatTable::InitializeL()
   1.986 +	{
   1.987 +    __PRINT2(_L("CAtaFatTable::InitializeL() drv:%d, state%d"), iOwner->DriveNumber(), State());
   1.988 +    CFatTable::InitializeL();
   1.989 +
   1.990 +    ASSERT(!iCache);
   1.991 +    ASSERT(State() == ENotInitialised);
   1.992 +    
   1.993 +    //-- create the FAT cache.
   1.994 +    CreateCacheL();
   1.995 +
   1.996 +    SetState(EInitialised);
   1.997 +
   1.998 +	}
   1.999 +
  1.1000 +//-----------------------------------------------------------------------------
  1.1001 +/**
  1.1002 +    Mount the FAT table to the CFatMountCB. Depending on mount parameters and configuration this method 
  1.1003 +    can do various things, like counting free clusters synchronously if data from FSInfo isn't valid, 
  1.1004 +    or setting up a FAT backround thread and return immediately etc.
  1.1005 +
  1.1006 +    @param  aMountParam mounting parameters, like some data from FSInfo
  1.1007 +
  1.1008 +*/
  1.1009 +void CAtaFatTable::MountL(const TMountParams& aMountParam)
  1.1010 +    {
  1.1011 +    __PRINT2(_L("CAtaFatTable::MountL() drv:%d, state:%d"), iOwner->DriveNumber(), State());
  1.1012 +
  1.1013 +    ASSERT(State() == EInitialised);
  1.1014 +    SetState(EMounting);
  1.1015 +
  1.1016 +    if(ipHelperThread)
  1.1017 +        {   
  1.1018 +        __PRINT(_L("CAtaFatTable::MountL() Helper thread is present!"));
  1.1019 +        ASSERT(0);
  1.1020 +        DestroyHelperThread();
  1.1021 +        }
  1.1022 +    
  1.1023 +
  1.1024 +    //-- Check if we have valid data from FSInfo. In this case we don't need to count free clusters
  1.1025 +    if(aMountParam.iFsInfoValid)
  1.1026 +        {
  1.1027 +        ASSERT(IsFat32());
  1.1028 +        ASSERT(aMountParam.iFreeClusters <= MaxEntries());
  1.1029 +        
  1.1030 +        ASSERT(ClusterNumberValid(aMountParam.iFirstFreeCluster));
  1.1031 +
  1.1032 +        SetFreeClusters(aMountParam.iFreeClusters);
  1.1033 +        SetFreeClusterHint(aMountParam.iFirstFreeCluster);
  1.1034 +
  1.1035 +        __PRINT2(_L("CAtaFatTable::MountL() Using data from FSInfo sector. free clusters:%d, 1st free:%d"), FreeClusters(), FreeClusterHint());
  1.1036 +
  1.1037 +        //-- We don't need to scan entire FAT to find out the number of free entries, because the data are taken from FSInfo.
  1.1038 +        //-- But if we are going to use the FAT32 bit supercache, we need to populate it. So, try to start up a special 
  1.1039 +        //-- populating thread.
  1.1040 +        CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
  1.1041 +        if(pFatBitCache)
  1.1042 +            {//-- bit cache is present, we need to populate (or repopulate it)
  1.1043 +            //-- create helper thread object and start the thread
  1.1044 +            ipHelperThread = CFat32BitCachePopulator::NewL(*this);
  1.1045 +
  1.1046 +            ipHelperThread->Launch(); 
  1.1047 +            //-- background FAT bit cache populating thread is running now.
  1.1048 +            //-- the result of thread start up and completion isn't very interesting: If it fails to 
  1.1049 +            //-- properly populate the cache, nothing fatal will happen.
  1.1050 +            }
  1.1051 +
  1.1052 +        //-- CFat32BitCachePopulator doesn't affect FAT table state. 
  1.1053 +        SetState(EMounted);
  1.1054 +        return; 
  1.1055 +        }
  1.1056 +
  1.1057 +    //-- FSInfo data are invalid; we need to count free clusters by reading whole FAT table
  1.1058 +    //-- This method can optionally create a background thread (that will count free clusters) and return immideately.
  1.1059 +    CountFreeClustersL();
  1.1060 +    }
  1.1061 +
  1.1062 +//-----------------------------------------------------------------------------
  1.1063 +
  1.1064 +/**
  1.1065 +    Decrements the free cluster count. This is an overridden method with synchronisation.
  1.1066 +    @param  aCount a number of clusters 
  1.1067 +*/
  1.1068 +void CAtaFatTable::DecrementFreeClusterCount(TUint32 aCount)
  1.1069 +    {
  1.1070 +    XAutoLock lock(iOwner); //-- enter critical section
  1.1071 +    CFatTable::DecrementFreeClusterCount(aCount);
  1.1072 +    }
  1.1073 +
  1.1074 +/**
  1.1075 +    Increments the free cluster count.  This is an overridden method with synchronisation.
  1.1076 +    @param  aCount a number of clusters 
  1.1077 +*/
  1.1078 +void CAtaFatTable::IncrementFreeClusterCount(TUint32 aCount)
  1.1079 +    {
  1.1080 +    XAutoLock lock(iOwner); //-- enter critical section
  1.1081 +    CFatTable::IncrementFreeClusterCount(aCount);
  1.1082 +    }
  1.1083 +
  1.1084 +//-----------------------------------------------------------------------------
  1.1085 +
  1.1086 +/**
  1.1087 +    Obtain number of free clusters on the volume. This is an overridden method.
  1.1088 +    Depending on the "aSyncOperation" parameter this operation can be fully synhronous (exact number of free clusters ) or asynchronous
  1.1089 +    (current number of free clusters) if the FAT scanning thread is still running.
  1.1090 +
  1.1091 +    @param aSyncOperation if ETrue, this method will wait until FAT scan thread finishes and return exact number of free clusters
  1.1092 +                          if false, it will return current number of free clusters counted by FAT scan thread if it hasn't finished yet.  
  1.1093 +    
  1.1094 +    @return Number of free clusters. See also CAtaFatTable::RequestFreeClusters()
  1.1095 +*/
  1.1096 +TUint32 CAtaFatTable::NumberOfFreeClusters(TBool aSyncOperation/*=EFalse*/) const
  1.1097 +    {
  1.1098 +    if(ipHelperThread && ipHelperThread->ThreadWorking() && ipHelperThread->Type() == CFatHelperThreadBase::EFreeSpaceScanner)
  1.1099 +        {//-- here we have running helper thread that counts free entries in FAT.
  1.1100 +        //-- if this operation is synchronous, we need to wait until it finish its job in order to get _exact_ number of free cluster,
  1.1101 +        //-- not currently counted  
  1.1102 +        
  1.1103 +        //__PRINT2(_L("#- CAtaFatTable::NumberOfFreeClusters(), drv:%d enter, sync:%d"), iOwner->DriveNumber(), aSyncOperation);
  1.1104 +
  1.1105 +        if(aSyncOperation)
  1.1106 +            {//-- wait for background scanning thread to finish counting free clusters if this operation is synchronous
  1.1107 +            ipHelperThread->BoostPriority(ETrue);
  1.1108 +            ipHelperThread->WaitToFinish();
  1.1109 +            }
  1.1110 +        
  1.1111 +        XAutoLock lock(iOwner); //-- enter critical section
  1.1112 +        
  1.1113 +        const TUint32 freeClusters = FreeClusters();
  1.1114 +        //__PRINT2(_L("#- CAtaFatTable::NumberOfFreeClusters(), drv:%d Exit, clusters:%d"), iOwner->DriveNumber(), freeClusters);
  1.1115 +        return freeClusters;
  1.1116 +        }
  1.1117 +
  1.1118 +    return FreeClusters();
  1.1119 +
  1.1120 +    }
  1.1121 +
  1.1122 +//-----------------------------------------------------------------------------
  1.1123 +
  1.1124 +/** 
  1.1125 +    Set free cluster count. This is an overridden method with synchronisation. 
  1.1126 +    @param aFreeClusters new value of free clusters
  1.1127 +*/
  1.1128 +void CAtaFatTable::SetFreeClusters(TUint32 aFreeClusters)
  1.1129 +    {   
  1.1130 +    XAutoLock lock(iOwner); //-- enter critical section
  1.1131 +    CFatTable::SetFreeClusters(aFreeClusters);
  1.1132 +    }
  1.1133 +
  1.1134 +/** 
  1.1135 +    This is an overridden method with synchronisation. 
  1.1136 +    @return the last known free cluster number.
  1.1137 +*/
  1.1138 +TUint32 CAtaFatTable::FreeClusterHint() const 
  1.1139 +    {
  1.1140 +    XAutoLock lock(iOwner); //-- enter critical section
  1.1141 +    return CFatTable::FreeClusterHint();
  1.1142 +    } 
  1.1143 +
  1.1144 +/** Set next free cluster number. This is an overridden method with synchronisation. */
  1.1145 +void CAtaFatTable::SetFreeClusterHint(TUint32 aCluster) 
  1.1146 +    {
  1.1147 +    XAutoLock lock(iOwner); //-- enter critical section
  1.1148 +    CFatTable::SetFreeClusterHint(aCluster);
  1.1149 +    } 
  1.1150 +
  1.1151 +/**
  1.1152 +    @return ETrue if the state of the object is consistent; i.e. it is 
  1.1153 +    fully constructed, valid and the amount of free entries is known.
  1.1154 +    Used in the case of asynchronous mounting.
  1.1155 +*/
  1.1156 +TBool CAtaFatTable::ConsistentState() const
  1.1157 +    {
  1.1158 +    return State() == EMounted;
  1.1159 +    }
  1.1160 +
  1.1161 +//-----------------------------------------------------------------------------
  1.1162 +
  1.1163 +/**
  1.1164 +    Request for the raw write access to the FAT area (all copies of FAT).
  1.1165 +    If FAT helper thread is running, waits until it finishes.
  1.1166 +
  1.1167 +    @param  aPos absolute media position we are going to write to. Be careful with casting it from TInt64 and losing high word.
  1.1168 +    @param  aLen length of the area being written
  1.1169 +*/
  1.1170 +void CAtaFatTable::RequestRawWriteAccess(TInt64 aPos, TUint32 aLen) const
  1.1171 +    {
  1.1172 +    if(I64HIGH(aPos))
  1.1173 +        return;
  1.1174 +
  1.1175 +    const TUint32 pos32 = I64LOW(aPos);
  1.1176 +    const TUint32 posFatStart = iOwner->StartOfFatInBytes(); //-- position of the FAT start on the volume
  1.1177 +    const TUint32 posFatsEnd  = posFatStart + iOwner->NumberOfFats()*iOwner->FatSizeInBytes();  //-- position of the ent of ALL FATs
  1.1178 +
  1.1179 +    if(pos32 >= posFatsEnd || (pos32+aLen) <= posFatStart)
  1.1180 +        return;
  1.1181 +
  1.1182 +    __PRINT2(_L("#=- CAtaFatTable::RequestRawWriteAccess() pos:%d, len:%d"),pos32, aLen);
  1.1183 +
  1.1184 +    //-- someone tries to write to FAT area directly. Wait for the FAT helper thread to finish
  1.1185 +    if(ipHelperThread)
  1.1186 +        ipHelperThread->WaitToFinish();     
  1.1187 +
  1.1188 +    }
  1.1189 +
  1.1190 +//-----------------------------------------------------------------------------
  1.1191 +
  1.1192 +/**
  1.1193 +    Checks if we have at least "aClustersRequired" clusters free in the FAT.
  1.1194 +    If FAT scannng thread is running, waits until requested number of free clusters counted or the thread finishes.
  1.1195 +
  1.1196 +    @param  aClustersRequired number of free clusters required
  1.1197 +    @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
  1.1198 +*/
  1.1199 +TBool CAtaFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
  1.1200 +    {
  1.1201 +    //__PRINT1(_L("#- CAtaFatTable::RequestFreeClusters(%d)"),aClustersRequired);
  1.1202 +    ASSERT(aClustersRequired >0);
  1.1203 +
  1.1204 +    if(!ipHelperThread || !ipHelperThread->ThreadWorking() || ipHelperThread->Type() != CFatHelperThreadBase::EFreeSpaceScanner)
  1.1205 +        {//-- there is no FAT free space scan thread running, number of free entries can't increase in background
  1.1206 +        return (FreeClusters() >= aClustersRequired); //-- use simple, non-thread safe method
  1.1207 +        }     
  1.1208 +
  1.1209 +    //-- FAT free space scan thread is running, counting free FAT entries. wait until it has counted enough or finish.
  1.1210 +    ASSERT(ipHelperThread->Type() == CFatHelperThreadBase::EFreeSpaceScanner);
  1.1211 +    
  1.1212 +    TUint32 currFreeClusters;
  1.1213 +    const TUint KWaitGranularity = 20*K1mSec; //-- wait granularity
  1.1214 +    
  1.1215 +    ipHelperThread->BoostPriority(ETrue); //-- increase thread priority
  1.1216 +
  1.1217 +    for(;;)
  1.1218 +        {
  1.1219 +        currFreeClusters = NumberOfFreeClusters(EFalse); //-- get _current_ number of free clusters asynchronously
  1.1220 +        if(currFreeClusters >= aClustersRequired)
  1.1221 +            break; //-- OK, the request is satisfied
  1.1222 +
  1.1223 +        if(!ipHelperThread->ThreadWorking())
  1.1224 +            {//-- the thread has finished its work
  1.1225 +            currFreeClusters = NumberOfFreeClusters(EFalse); //-- get _current_ number of free clusters asynchronously
  1.1226 +            break; 
  1.1227 +            }
  1.1228 +
  1.1229 +        User::After(KWaitGranularity); //-- wait some time allowing FAT scanning thread to count free clusters.     
  1.1230 +        }
  1.1231 +
  1.1232 +    ipHelperThread->BoostPriority(EFalse); //-- set thread priority back to normal
  1.1233 +    //__PRINT1(_L("#- CAtaFatTable::RequestFreeClusters() #2 curr:%d"),currFreeClusters);
  1.1234 +    
  1.1235 +    return (currFreeClusters >= aClustersRequired);
  1.1236 +
  1.1237 +    }
  1.1238 +
  1.1239 +//-----------------------------------------------------------------------------
  1.1240 +
  1.1241 +/**
  1.1242 +    Parse a buffer filled with FAT16 or FAT32 entries, counting free clusters and looking for the firs free cluster number.
  1.1243 +    Note that this method can be called from a helper FAT scan thread.
  1.1244 +
  1.1245 +    @param  aBuf        FAT buffer descriptor. Must contain whole number of FAT16 or FAT32 entries
  1.1246 +    @param aScanParam   the structure to be filled with values, like number of counted free and non-free clusters, etc.
  1.1247 +*/
  1.1248 +void CAtaFatTable::DoParseFatBuf(const TPtrC8& aBuf, TFatScanParam& aScanParam) const
  1.1249 +    {
  1.1250 +    
  1.1251 +    if(IsFat16())
  1.1252 +        {//-- we are processing a buffer of FAT16 entries
  1.1253 +        ASSERT(!ipHelperThread);
  1.1254 +        ASSERT((aBuf.Size() & (sizeof(TFat16Entry)-1)) == 0);
  1.1255 +        const TInt KNumEntries = aBuf.Size() >> KFat16EntrySzLog2; 
  1.1256 +        const TFat16Entry* const pFatEntry = (const TFat16Entry*)(aBuf.Ptr()); 
  1.1257 +
  1.1258 +        for(TInt i=0; i<KNumEntries; ++i)
  1.1259 +            {
  1.1260 +            if(aScanParam.iEntriesScanned >= KFatFirstSearchCluster)
  1.1261 +                {
  1.1262 +                const TFat16Entry entry = pFatEntry[i];
  1.1263 +
  1.1264 +                if(entry == KSpareCluster)
  1.1265 +                    {//-- found a free FAT entry
  1.1266 +                    aScanParam.iCurrFreeEntries++;
  1.1267 +                    
  1.1268 +                    if(aScanParam.iFirstFree < KFatFirstSearchCluster)
  1.1269 +                        aScanParam.iFirstFree = aScanParam.iEntriesScanned;    
  1.1270 +
  1.1271 +                    }
  1.1272 +                 else
  1.1273 +                    {//-- found occupied FAT entry, count bad clusters as well 
  1.1274 +                    aScanParam.iCurrOccupiedEntries++;
  1.1275 +                    }
  1.1276 +
  1.1277 +                }
  1.1278 +
  1.1279 +            aScanParam.iEntriesScanned++;
  1.1280 +            }
  1.1281 +        }//if(IsFat16())
  1.1282 +    else
  1.1283 +    if(IsFat32())
  1.1284 +        {//-- we are processing a buffer of FAT32 entries.
  1.1285 +         //-- note that here we can be in the context of the FAT free entries scan thread.   
  1.1286 +        ASSERT((aBuf.Size() & (sizeof(TFat32Entry)-1)) == 0);
  1.1287 +        
  1.1288 +        //-- pointer to the FAT32 bit supercache. If present, we will populate it here
  1.1289 +        CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
  1.1290 +
  1.1291 +        const TInt KNumEntries = aBuf.Size() >> KFat32EntrySzLog2;
  1.1292 +        const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr()); 
  1.1293 +
  1.1294 +        for(TInt i=0; i<KNumEntries; ++i)
  1.1295 +            {
  1.1296 +              if(aScanParam.iEntriesScanned >= KFatFirstSearchCluster)
  1.1297 +                {
  1.1298 +                const TFat32Entry entry = pFatEntry[i] & KFat32EntryMask;
  1.1299 +
  1.1300 +                if(entry == KSpareCluster)
  1.1301 +                    {//-- found a free FAT32 entry
  1.1302 +                    ++aScanParam.iCurrFreeEntries;
  1.1303 +                    
  1.1304 +                    if(aScanParam.iFirstFree < KFatFirstSearchCluster)
  1.1305 +                        aScanParam.iFirstFree = aScanParam.iEntriesScanned;    
  1.1306 +
  1.1307 +                    
  1.1308 +                    //-- feed the information about free FAT entry at index aClustersScanned to the FAT bit supercache. 
  1.1309 +                    if(pFatBitCache)
  1.1310 +                        {
  1.1311 +                        pFatBitCache->SetFreeFatEntry(aScanParam.iEntriesScanned);
  1.1312 +                        }
  1.1313 +
  1.1314 +                    
  1.1315 +                    }//if(entry == KSpareCluster)
  1.1316 +                    else
  1.1317 +                        {//-- found occupied FAT32 entry, count bad clusters as well
  1.1318 +                        aScanParam.iCurrOccupiedEntries++;
  1.1319 +                        }
  1.1320 +                }
  1.1321 +
  1.1322 +            ++aScanParam.iEntriesScanned;
  1.1323 +            }
  1.1324 +
  1.1325 +        }//if(IsFat32())
  1.1326 +    else
  1.1327 +        {
  1.1328 +        ASSERT(0);
  1.1329 +        }
  1.1330 +    }
  1.1331 +
  1.1332 +//-----------------------------------------------------------------------------
  1.1333 +
  1.1334 +/**
  1.1335 +    Count free clusters in FAT16 or FAT32. Uses relatively large buffer to read FAT entries into; 
  1.1336 +    This is faster than usual ReadL() calls.
  1.1337 +*/
  1.1338 +void CAtaFatTable::DoCountFreeClustersL()
  1.1339 +    {
  1.1340 +    __PRINT2(_L("#- CAtaFatTable::DoCountFreeClustersL() drv:%d, state:%d"), iOwner->DriveNumber(), State());
  1.1341 +    
  1.1342 +    if(!IsFat16() && !IsFat32())
  1.1343 +        {
  1.1344 +        ASSERT(0);
  1.1345 +        User::Leave(KErrNotSupported);
  1.1346 +        }
  1.1347 +
  1.1348 +    const TUint32 KFat1StartPos = iOwner->StartOfFatInBytes();
  1.1349 +    const TUint32 KNumClusters  = MaxEntries(); //-- FAT[0] & FAT[1] are reserved and not counted by UsableClusters()
  1.1350 +    const TUint32 KNumFATs      = iOwner->NumberOfFats();
  1.1351 +    const TUint32 KFatSize      = KNumClusters * (IsFat32() ? sizeof(TFat32Entry) : sizeof(TFat16Entry)); //-- usable size of one FAT.
  1.1352 +
  1.1353 +    (void)KNumFATs;
  1.1354 +
  1.1355 +    ASSERT(KFat1StartPos >= 1*KDefaultSectorSize);
  1.1356 +    ASSERT(KNumClusters > KFatFirstSearchCluster);
  1.1357 +    ASSERT(KNumFATs > 0);
  1.1358 +
  1.1359 +    const TUint32 KFatBufSz = 32*K1KiloByte; //-- buffer size for FAT reading. 32K seems to be optimal size
  1.1360 +
  1.1361 +    __ASSERT_COMPILE((KFatBufSz % sizeof(TFat32Entry)) == 0);
  1.1362 +    __ASSERT_COMPILE((KFatBufSz % sizeof(TFat16Entry)) == 0);   
  1.1363 +
  1.1364 +    RBuf8 buf;
  1.1365 +    CleanupClosePushL(buf);
  1.1366 +
  1.1367 +    //-- allocate memory for FAT parse buffer
  1.1368 +    buf.CreateMaxL(KFatBufSz);
  1.1369 +
  1.1370 +    //-- read FAT into the large buffer and parse it
  1.1371 +    TUint32 rem = KFatSize;
  1.1372 +    TUint32 mediaPos = KFat1StartPos;   
  1.1373 +        
  1.1374 +    //-- prepare FAT bit supercache to being populated.
  1.1375 +    //-- actual populating will happen in ::DoParseFatBuf()
  1.1376 +    CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
  1.1377 +
  1.1378 +    if(pFatBitCache)
  1.1379 +        {
  1.1380 +        pFatBitCache->StartPopulating();
  1.1381 +        }
  1.1382 +
  1.1383 +    TFatScanParam fatScanParam;
  1.1384 +
  1.1385 +    //-- used for measuring time
  1.1386 +    TTime   timeStart;
  1.1387 +    TTime   timeEnd;
  1.1388 +    timeStart.UniversalTime(); //-- take start time
  1.1389 +
  1.1390 +
  1.1391 +    while(rem)
  1.1392 +        {
  1.1393 +        const TUint32 bytesToRead=Min(rem, KFatBufSz);
  1.1394 +        TPtrC8 ptrData(buf.Ptr(), bytesToRead);
  1.1395 +        
  1.1396 +        //__PRINT2(_L("#=--- CAtaFatTable::DoCountFreeClustersL() read %d bytes pos:0x%x"), bytesToRead, (TUint32)mediaPos);
  1.1397 +        User::LeaveIfError(iOwner->LocalDrive()->Read(mediaPos, bytesToRead, buf)); 
  1.1398 +        
  1.1399 +        DoParseFatBuf(ptrData, fatScanParam);
  1.1400 +
  1.1401 +        mediaPos += bytesToRead;
  1.1402 +        rem -= bytesToRead;
  1.1403 +        }
  1.1404 +
  1.1405 +    //-- here fatScanParam contains values for the whole FAT. 
  1.1406 +    
  1.1407 +    timeEnd.UniversalTime(); //-- take end time
  1.1408 +    const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
  1.1409 +    (void)msScanTime;
  1.1410 +    __PRINT1(_L("#- CAtaFatTable::DoCountFreeClustersL() finished. Taken:%d ms "), msScanTime);
  1.1411 +    
  1.1412 +
  1.1413 +    //-- tell FAT bit cache that we have finished populating it
  1.1414 +    if(pFatBitCache)
  1.1415 +        {
  1.1416 +        pFatBitCache->FinishPopulating(ETrue);
  1.1417 +        pFatBitCache->Dump();
  1.1418 +        }
  1.1419 +
  1.1420 +    if(!fatScanParam.iFirstFree)//-- haven't found free clusters on the volume
  1.1421 +        fatScanParam.iFirstFree = KFatFirstSearchCluster;
  1.1422 +
  1.1423 +    ASSERT(fatScanParam.iCurrFreeEntries <= iOwner->UsableClusters());
  1.1424 +    ASSERT(ClusterNumberValid(fatScanParam.iFirstFree));
  1.1425 +    
  1.1426 +    SetFreeClusters(fatScanParam.iCurrFreeEntries);
  1.1427 +    SetFreeClusterHint(fatScanParam.iFirstFree);
  1.1428 +
  1.1429 +    CleanupStack::PopAndDestroy(&buf); 
  1.1430 +    }
  1.1431 +
  1.1432 +//-----------------------------------------------------------------------------
  1.1433 +
  1.1434 +/**
  1.1435 +    Count free clusters on the volume.
  1.1436 +    Depending on FAT type can count clusters synchronously or start a thread to do it in background.
  1.1437 +*/
  1.1438 +void CAtaFatTable::CountFreeClustersL()
  1.1439 +    {
  1.1440 +    __PRINT3(_L("#=- CAtaFatTable::CountFreeClustersL() drv:%d, FAT%d, state:%d"),iOwner->DriveNumber(),FatType(), State());
  1.1441 +    
  1.1442 +    ASSERT(State() == EMounting);
  1.1443 +    ASSERT(!ipHelperThread);
  1.1444 +
  1.1445 +    TInt nRes;
  1.1446 +
  1.1447 +    switch(FatType())
  1.1448 +        {
  1.1449 +        case EFat12: //-- use old default scanning, it is synchronous
  1.1450 +        CFatTable::CountFreeClustersL();
  1.1451 +        SetState(EMounted);
  1.1452 +        break;
  1.1453 +           
  1.1454 +        case EFat16: //-- enhanced FAT scan, but still synchronous
  1.1455 +            TRAP(nRes, DoCountFreeClustersL());
  1.1456 +            if(nRes !=KErrNone) 
  1.1457 +                {
  1.1458 +                CFatTable::CountFreeClustersL(); //-- fall back to the legacy method
  1.1459 +                }
  1.1460 +
  1.1461 +            SetState(EMounted);
  1.1462 +        break;
  1.1463 +   
  1.1464 +        case EFat32: //-- This is FAT32, try to set up a FAT scanning thread if allowed
  1.1465 +            {
  1.1466 +                TBool bFat32BkGndScan = ETrue; //-- if true, we will try to start up a background scanning thread.
  1.1467 +
  1.1468 +                //-- 1. check if background FAT scanning is disabled in config
  1.1469 +                if(!iOwner->FatConfig().FAT32_AsynchMount())
  1.1470 +                {
  1.1471 +                    __PRINT(_L("#=- FAT32 BkGnd scan is disabled in config."));
  1.1472 +                    bFat32BkGndScan = EFalse;
  1.1473 +                }
  1.1474 +
  1.1475 +                //-- 2. check if background FAT scanning is disabled by test interface
  1.1476 +#ifdef _DEBUG
  1.1477 +                TInt nMntDebugFlags;
  1.1478 +                if(bFat32BkGndScan && RProperty::Get(KSID_Test1, iOwner->DriveNumber(), nMntDebugFlags) == KErrNone)
  1.1479 +                {//-- test property for this drive is defined
  1.1480 +                    if(nMntDebugFlags & KMntDisable_FatBkGndScan)
  1.1481 +                    {
  1.1482 +                    __PRINT(_L("#- FAT32 BkGnd scan is disabled is disabled by debug interface."));
  1.1483 +                    bFat32BkGndScan = EFalse;
  1.1484 +                    }
  1.1485 +            
  1.1486 +                }
  1.1487 +#endif
  1.1488 +                //-- 3. try to start FAT32 free entries scanning thread.
  1.1489 +                if(bFat32BkGndScan)
  1.1490 +                {
  1.1491 +                    __PRINT(_L("#=- Starting up FAT32 free entries scanner thread..."));
  1.1492 +                    TRAP(nRes, DoLaunchFat32FreeSpaceScanThreadL());
  1.1493 +                    if(nRes == KErrNone) 
  1.1494 +                        break; //-- let thread run by itself
  1.1495 +
  1.1496 +                    //-- DoLaunchFat32FreeSpaceScanThreadL() has set this object state.
  1.1497 +                }
  1.1498 +
  1.1499 +            //-- we either failed to launch the thread or this feature was disabled somehow. Fall back to the synchronous scan.
  1.1500 +            TRAP(nRes, DoCountFreeClustersL());
  1.1501 +            if(nRes !=KErrNone) 
  1.1502 +                {
  1.1503 +                CFatTable::CountFreeClustersL(); //-- fall back to the legacy method
  1.1504 +                }
  1.1505 +
  1.1506 +             SetState(EMounted);
  1.1507 +            }//case EFat32
  1.1508 +        break;
  1.1509 +   
  1.1510 +        default:
  1.1511 +            ASSERT(0);
  1.1512 +        break;
  1.1513 +
  1.1514 +        } //switch(FatType())
  1.1515 +    }
  1.1516 +
  1.1517 +//-----------------------------------------------------------------------------
  1.1518 +
  1.1519 +/** 
  1.1520 +    Set up and start FAT scan thread.
  1.1521 +    Leaves on error.
  1.1522 +*/
  1.1523 +void CAtaFatTable::DoLaunchFat32FreeSpaceScanThreadL()
  1.1524 +    {
  1.1525 +    __PRINT2(_L("#=- CAtaFatTable::DoLaunchFat32FreeSpaceScanThreadL() drv:%d, state:%d"),iOwner->DriveNumber(), State());
  1.1526 +    ASSERT(State() == EMounting);
  1.1527 +
  1.1528 +    //-- 1. check if something is already working (shan't be!)
  1.1529 +    if(ipHelperThread)
  1.1530 +        {
  1.1531 +        if(ipHelperThread->ThreadWorking())
  1.1532 +            {
  1.1533 +            __PRINT(_L("#=- CAtaFatTable::DoLaunchScanThread() some thread is already running ?"));
  1.1534 +            ASSERT(0);
  1.1535 +            User::Leave(KErrAlreadyExists);
  1.1536 +            }
  1.1537 +
  1.1538 +        DestroyHelperThread();        
  1.1539 +        }
  1.1540 +
  1.1541 +    //-- 2. create helper thread object and start the thread
  1.1542 +    ipHelperThread = CFat32FreeSpaceScanner::NewL(*this);
  1.1543 +    
  1.1544 +    SetState(EFreeClustersScan);
  1.1545 +    
  1.1546 +    ipHelperThread->Launch(); 
  1.1547 +    //-- background FAT scanning thread is running now
  1.1548 +    }
  1.1549 +
  1.1550 +//-----------------------------------------------------------------------------
  1.1551 +/**
  1.1552 +    Read an entry from the FAT table
  1.1553 +
  1.1554 +    @param aFatIndex FAT entry number to read
  1.1555 +    @return FAT entry value
  1.1556 +*/
  1.1557 +TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const
  1.1558 +    {
  1.1559 +    if(!ClusterNumberValid(aFatIndex))
  1.1560 +        {
  1.1561 +        //ASSERT(0); //-- deliberately corrupted (by some tests) DOS directory entries can have 0 in the "first cluster" field.
  1.1562 +        __PRINT1(_L("CAtaFatTable::ReadL(%d) bad Index!"), aFatIndex);
  1.1563 +        User::Leave(KErrCorrupt);
  1.1564 +        }
  1.1565 +
  1.1566 +
  1.1567 +    const TUint entry = iCache->ReadEntryL(aFatIndex);
  1.1568 +    return entry;
  1.1569 +    }
  1.1570 +
  1.1571 +
  1.1572 +//-----------------------------------------------------------------------------
  1.1573 +/**
  1.1574 +    Write an entry to the FAT table
  1.1575 +
  1.1576 +    @param aFatIndex    aFatIndex FAT entry number to write
  1.1577 +    @param aValue       FAT entry to write
  1.1578 +    @leave 
  1.1579 +*/
  1.1580 +void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
  1.1581 +	{
  1.1582 +
  1.1583 +    __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue);
  1.1584 +    
  1.1585 +    if(!ClusterNumberValid(aFatIndex))
  1.1586 +        {
  1.1587 +        ASSERT(0); 
  1.1588 +        User::Leave(KErrCorrupt);
  1.1589 +        }
  1.1590 +    
  1.1591 +    if(aValue != KSpareCluster && (aValue < KFatFirstSearchCluster || aValue > KFat32EntryMask))
  1.1592 +        {
  1.1593 +        ASSERT(0);
  1.1594 +        User::Leave(KErrCorrupt);
  1.1595 +        }
  1.1596 +
  1.1597 +    //-- wait until we are allowed to write FAT entry
  1.1598 +    if(ipHelperThread && ipHelperThread->ThreadWorking())
  1.1599 +        {
  1.1600 +        ASSERT(ipHelperThread->ThreadId() != RThread().Id()); //-- this method must not be called the FAT helper thread	    
  1.1601 +        ipHelperThread->RequestFatEntryWriteAccess(aFatIndex);
  1.1602 +        }
  1.1603 +
  1.1604 +    //-- write entry to the FAT through FAT cache
  1.1605 +    iCache->WriteEntryL(aFatIndex, aValue);
  1.1606 +
  1.1607 +    
  1.1608 +    //-- if we are writing "spare" FAT entry, tell FAT bit supercache about it.
  1.1609 +    //-- it will store the information that corresponding FAT cache sector has a spare FAT entry.
  1.1610 +    //-- writing non-spare FAT entry doesn't mean anything: that FAT cache sector might or might not contain free entries.
  1.1611 +    if(aValue == KSpareCluster && iCache->BitCacheInterface())
  1.1612 +        {
  1.1613 +            CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
  1.1614 +            const CFatBitCache::TState cacheState= pFatBitCache->State();
  1.1615 +            if(cacheState == CFatBitCache::EPopulated || cacheState == CFatBitCache::EPopulating)
  1.1616 +            {//-- bit cache is either normally populated or being populated by one of the helper threads
  1.1617 +            if(ipHelperThread && ipHelperThread->ThreadWorking())    
  1.1618 +                {
  1.1619 +                //-- here we have a multithreading issue. Helper FAT thread can be parsing FAT and optionally calling ReportFreeFatEntry(..) as well.
  1.1620 +                //-- in this case we need either to suspend the helper thread in order to prevent corruption of the FAT bit cache data,
  1.1621 +                //-- 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
  1.1622 +                //-- fixed during conflict resolution (this can lead to performance degradation).
  1.1623 +
  1.1624 +                //-- ok, suspend the helper thread while we are changing data in the bit cache
  1.1625 +                AcquireLock();
  1.1626 +                ipHelperThread->Suspend();
  1.1627 +                    pFatBitCache->SetFreeFatEntry(aFatIndex);
  1.1628 +                ipHelperThread->Resume();
  1.1629 +                ReleaseLock();
  1.1630 +
  1.1631 +                }
  1.1632 +            else
  1.1633 +                {//-- no one else is accessing FAT in this time
  1.1634 +                ASSERT(pFatBitCache->UsableState());
  1.1635 +                pFatBitCache->SetFreeFatEntry(aFatIndex);
  1.1636 +                }
  1.1637 +            }
  1.1638 +
  1.1639 +        }//if(aValue == KSpareCluster)
  1.1640 +
  1.1641 +    }
  1.1642 +
  1.1643 +//-----------------------------------------------------------------------------
  1.1644 +/**
  1.1645 +    This is an overridden method from CFatTable. See CFatTable::FindClosestFreeClusterL(...)
  1.1646 +    Does the same, i.e looks for the closest to "aCluster" free FAT entry, but more advanced,
  1.1647 +    it can use FAT bit supercache for quick lookup.
  1.1648 +
  1.1649 +    @param aCluster Cluster to find nearest free cluster to.
  1.1650 +    @leave KErrDiskFull + system wide error codes
  1.1651 +    @return cluster number found
  1.1652 +*/
  1.1653 +TUint32 CAtaFatTable::FindClosestFreeClusterL(TUint32 aCluster)
  1.1654 +    {
  1.1655 +    __PRINT2(_L("CAtaFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
  1.1656 +
  1.1657 +    if(!ClusterNumberValid(aCluster))
  1.1658 +        {
  1.1659 +        ASSERT(0);
  1.1660 +        User::Leave(KErrCorrupt);
  1.1661 +        }
  1.1662 +
  1.1663 +
  1.1664 +    if(!RequestFreeClusters(1))
  1.1665 +	    {//-- there is no at least 1 free cluster available
  1.1666 +    	__PRINT(_L("CAtaFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
  1.1667 +        User::Leave(KErrDiskFull);
  1.1668 +        }
  1.1669 +
  1.1670 +    //-- check if we have FAT bit supercache and it is in consistent state
  1.1671 +    CFatBitCache *pFatBitCache = iCache->BitCacheInterface();
  1.1672 +    if(!pFatBitCache)
  1.1673 +        return CFatTable::FindClosestFreeClusterL(aCluster); //-- fall back to the old search method
  1.1674 +
  1.1675 +    ASSERT(IsFat32());
  1.1676 +
  1.1677 +    if(!pFatBitCache->UsableState())
  1.1678 +        {
  1.1679 +        //__PRINT(_L("#++ CAtaFatTable::FindClosestFreeClusterL() FAT bit cache isn't consistent!"));
  1.1680 +        return CFatTable::FindClosestFreeClusterL(aCluster); //-- fall back to the old search method
  1.1681 +        }
  1.1682 +
  1.1683 +    //-- ask FAT bit supercache to find us FAT cache sector (closest to the aCluster) that contains free FAT entries.
  1.1684 +    //__PRINT2(_L("#++ CAtaFatTable::FindClosestFreeClusterL(%d) hint free cl:%d"), aCluster, FreeClusterHint());
  1.1685 +    
  1.1686 +    const TInt KMaxLookupRetries = 2;
  1.1687 +    for(TInt i=0; i<KMaxLookupRetries; ++i)
  1.1688 +        {
  1.1689 +        const TInt nRes = pFatBitCache->FindClosestFreeFatEntry(aCluster);
  1.1690 +        switch(nRes)
  1.1691 +            {
  1.1692 +            case KErrNone:
  1.1693 +            //-- FAT bit supercache has found a free FAT entry in the FAT32 cache
  1.1694 +            //__PRINT1(_L("#++ CAtaFatTable::FindClosestFreeClusterL FOUND! cl:%d"), aCluster);
  1.1695 +            
  1.1696 +            ASSERT(ClusterNumberValid(aCluster));
  1.1697 +
  1.1698 +            //-- do not update the last known free cluster, it can be quite expensive.
  1.1699 +            //-- do it in the caller method with bigger granularity.
  1.1700 +            return aCluster;        
  1.1701 +
  1.1702 +            case KErrNotFound:
  1.1703 +            //-- 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.
  1.1704 +            //-- It can happen because FAT bit cache entry is marked '1' only on populating the bit vector or if someone writes KSpareCluster into the 
  1.1705 +            //-- corresponding FAT cache sector. Such conflict can happen quite often.
  1.1706 +            //-- 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.
  1.1707 +            break;
  1.1708 +
  1.1709 +            case KErrCorrupt: 
  1.1710 +            //-- pFatBitCache->FindClosestFreeFatEntry failed to read a page from the media
  1.1711 +            //-- break out from the loop and fall back to old search just in case.
  1.1712 +
  1.1713 +            case KErrEof:
  1.1714 +            //-- there are no '1' entries in whole FAT bit cache vector at all, which is quite unlikely
  1.1715 +            //-- break out from the loop and fall back to old search.
  1.1716 +            i=KMaxLookupRetries;
  1.1717 +            break;
  1.1718 +
  1.1719 +            //-- unexpected result code.
  1.1720 +            default:
  1.1721 +            ASSERT(0); 
  1.1722 +            i=KMaxLookupRetries;
  1.1723 +            break;
  1.1724 +
  1.1725 +        
  1.1726 +            };//switch(nRes)
  1.1727 +
  1.1728 +        }//for(TInt i=0; i<KMaxLookupRetries; ++i)
  1.1729 +
  1.1730 +    //-- something went wrong, Bit Fat supercache could not find FAT cache sector that contains at least one free FAT entry.
  1.1731 +    //-- this is most likely because of the FAT data mismatch between FAT and bit cache.
  1.1732 +    __PRINT(_L("#++ CAtaFatTable::FindClosestFreeClusterL FALLBACK #1"));
  1.1733 +    
  1.1734 +    //!!!!?? use  not aCluster, but previous search result here ???
  1.1735 +    return CFatTable::FindClosestFreeClusterL(aCluster); //-- fall back to the old search method
  1.1736 +    }
  1.1737 +
  1.1738 +
  1.1739 +
  1.1740 +/**
  1.1741 +    Get the next cluster in the chain from the FAT
  1.1742 +
  1.1743 +    @param aCluster number to read, contains next cluster upon return
  1.1744 +    @return False if end of cluster chain
  1.1745 +*/
  1.1746 +TBool CFatTable::GetNextClusterL(TInt& aCluster) const
  1.1747 +    {
  1.1748 +	__PRINT1(_L("CAtaFatTable::GetNextClusterL(%d)"), aCluster);
  1.1749 +    
  1.1750 +    const TUint32 nextCluster = ReadL(aCluster);
  1.1751 +    const TBool bEOC = IsEndOfClusterCh(nextCluster);
  1.1752 +
  1.1753 +    if(bEOC) 
  1.1754 +        return EFalse; //-- the end of cluster chain
  1.1755 +
  1.1756 +    aCluster = nextCluster;
  1.1757 +    
  1.1758 +    return ETrue;    
  1.1759 +    }
  1.1760 +
  1.1761 +/**
  1.1762 +    Write EOF to aFatIndex
  1.1763 +    @param aFatIndex index in FAT (cluster number) to be written
  1.1764 +*/
  1.1765 +void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex)
  1.1766 +	{
  1.1767 +	__PRINT1(_L("CFatTable::WriteFatEntryEofL(%d)"), aFatIndex);
  1.1768 +
  1.1769 +    //-- use EOF_32Bit (0x0fffffff) for all types of FAT, FAT cache will mask it appropriately
  1.1770 +    WriteL(aFatIndex, EOF_32Bit);
  1.1771 +    }
  1.1772 +
  1.1773 +
  1.1774 +
  1.1775 +/** 
  1.1776 +    Mark cluster number aFatIndex in FAT as bad 
  1.1777 +    @param aFatIndex index in FAT (cluster number) to be written
  1.1778 +*/
  1.1779 +void CFatTable::MarkAsBadClusterL(TUint32 aFatIndex)
  1.1780 +    {
  1.1781 +    __PRINT1(_L("CAtaFatTable::MarkAsBadClusterL(%d)"),aFatIndex);
  1.1782 +
  1.1783 +    //-- use KBad_32Bit (0x0ffffff7) for all types of FAT, FAT cache will mask it appropriately
  1.1784 +    WriteL(aFatIndex, KBad_32Bit);
  1.1785 +    
  1.1786 +    FlushL();
  1.1787 +	}
  1.1788 +
  1.1789 +
  1.1790 +/**
  1.1791 +    Return the location of a Cluster in the data section of the media
  1.1792 +
  1.1793 +    @param aCluster to find location of
  1.1794 +    @return Byte offset of the cluster data 
  1.1795 +*/
  1.1796 +TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const
  1.1797 +	{
  1.1798 +
  1.1799 +    __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex));
  1.1800 +
  1.1801 +    const TInt clusterBasePosition=iOwner->ClusterBasePosition();
  1.1802 +	return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition);
  1.1803 +	}
  1.1804 +
  1.1805 +
  1.1806 +
  1.1807 +
  1.1808 +//#######################################################################################################################################
  1.1809 +//#     CFatHelperThreadBase  implementation
  1.1810 +//#######################################################################################################################################
  1.1811 +
  1.1812 +//-----------------------------------------------------------------------------
  1.1813 +CFatHelperThreadBase::CFatHelperThreadBase(CAtaFatTable& aOwner)
  1.1814 +                      :iOwner(aOwner)
  1.1815 +    {
  1.1816 +
  1.1817 +    SetState(EInvalid);
  1.1818 +    }
  1.1819 +
  1.1820 +CFatHelperThreadBase::~CFatHelperThreadBase()
  1.1821 +    {
  1.1822 +    Close();
  1.1823 +    }
  1.1824 +
  1.1825 +//-----------------------------------------------------------------------------
  1.1826 +/**
  1.1827 +    Closes the thread object handle.
  1.1828 +    The thread shall not be running.
  1.1829 +*/
  1.1830 +void CFatHelperThreadBase::Close()
  1.1831 +    {
  1.1832 +    if(ThreadWorking())
  1.1833 +        {
  1.1834 +        ASSERT(0);
  1.1835 +        ForceStop();
  1.1836 +        }
  1.1837 +
  1.1838 +    iThread.Close();
  1.1839 +    }
  1.1840 +
  1.1841 +//-----------------------------------------------------------------------------
  1.1842 +/**
  1.1843 +    Waits for the thread to finish (thread function exit). if it is running.
  1.1844 +    @return thread completion code.
  1.1845 +
  1.1846 +    !!!! definitely need a timeout processing here to avoid any possibitlity of hanging forever !!
  1.1847 +
  1.1848 +*/
  1.1849 +TInt CFatHelperThreadBase::WaitToFinish() const
  1.1850 +    {
  1.1851 +    if(!ThreadWorking())
  1.1852 +        return ThreadCompletionCode();
  1.1853 +
  1.1854 +    
  1.1855 +    //--todo: use timeout and assert to avoid hanging forever ?
  1.1856 +    __PRINT1(_L("#= CFatHelperThreadBase::WaitToFinish(), stat:%d"),iThreadStatus.Int());
  1.1857 +    User::WaitForRequest(iThreadStatus);
  1.1858 +    return iThreadStatus.Int();
  1.1859 +    }
  1.1860 +
  1.1861 +//-----------------------------------------------------------------------------
  1.1862 +
  1.1863 +/**
  1.1864 +    Requests the fat helper thread function to finish gracefully ASAP; then closes the thread handle. 
  1.1865 +    Just sets a flag that is analysed by the thread function and waits thread's request completion.
  1.1866 +*/
  1.1867 +void CFatHelperThreadBase::ForceStop()
  1.1868 +    {
  1.1869 +    if(ThreadWorking())
  1.1870 +        {
  1.1871 +        DBG_STATEMENT(TName name = iThread.Name();)
  1.1872 +        __PRINT3(_L("#=!! CFatHelperThreadBase::ForceStop() id:%u, name:%S, status:%d"), (TUint)iThread.Id(), &name, ThreadCompletionCode());
  1.1873 +        DBG_STATEMENT(name.Zero()); //-- to avoid warning
  1.1874 +
  1.1875 +        iOwner.AcquireLock();
  1.1876 +    
  1.1877 +        AllowToLive(EFalse) ; //-- signal the thread to exit ASAP
  1.1878 +
  1.1879 +        iOwner.ReleaseLock();
  1.1880 +
  1.1881 +        WaitToFinish(); //-- wait for the thread to finish.
  1.1882 +
  1.1883 +        //-- don't know why but we need a delay, at least on the emulator. Otherwise thread object doesn't look destroyed.
  1.1884 +        //-- probably something with scheduling.
  1.1885 +        User::After(10*K1mSec); 
  1.1886 +        }
  1.1887 +
  1.1888 +    iThread.Close();
  1.1889 +    }
  1.1890 +
  1.1891 +
  1.1892 +//-----------------------------------------------------------------------------
  1.1893 +
  1.1894 +
  1.1895 +/**
  1.1896 +    Created, initialises and starts the helper thread.
  1.1897 +    
  1.1898 +    @param  aFunction           pointer to the thread function
  1.1899 +    @param  aThreadParameter    parameter to be passed to the thread function. Its interpretation depends on the thread function.
  1.1900 +    @return KErrNone on success; standard error code otherwise
  1.1901 +*/
  1.1902 +TInt CFatHelperThreadBase::DoLaunchThread(TThreadFunction aFunction, TAny* aThreadParameter)
  1.1903 +    {
  1.1904 +    __PRINT2(_L("#=- CFatHelperThreadBase::DoLaunchThread() thread stat:%d, state:%d"), ThreadCompletionCode(), State());
  1.1905 +    
  1.1906 +    ASSERT(aFunction);
  1.1907 +    ASSERT(State() != EWorking);
  1.1908 +
  1.1909 +    if(ThreadWorking())
  1.1910 +        {
  1.1911 +        ASSERT(0);
  1.1912 +        return KErrInUse;
  1.1913 +        }
  1.1914 +
  1.1915 +    if(iOwner.OwnerMount()->Drive().IsSynchronous())
  1.1916 +        {
  1.1917 +        //-- if the drive is synchronous, this is a main File Server thread. Don't play with it, it has its own scheduler
  1.1918 +        //-- and completing other requests rather than native CFsRequest leads to the stray events, because it waits on the 
  1.1919 +        //-- User::WaitForAnyRequest and doesn't check which request has completed.
  1.1920 +        __PRINT(_L("CFatHelperThreadBase::DoLaunchThread() the drive is synchronous, skipping."));
  1.1921 +        return KErrNotSupported;
  1.1922 +        }
  1.1923 +
  1.1924 +
  1.1925 +    TInt nRes;
  1.1926 +    TName nameBuf; //-- this will be initial thread name, it will rename itself in its thread function
  1.1927 +    nameBuf.Format(_L("Fat32HelperThread_drv_%d"), iOwner.OwnerMount()->DriveNumber());
  1.1928 +    const TInt stackSz = 4*K1KiloByte; //-- thread stack size, 4K
  1.1929 +
  1.1930 +    iThread.Close();
  1.1931 +
  1.1932 +    //-- 1. create the thread
  1.1933 +    nRes = iThread.Create(nameBuf, aFunction, stackSz, &User::Allocator(), aThreadParameter, EOwnerProcess);
  1.1934 +	if(nRes != KErrNone)
  1.1935 +	    {
  1.1936 +        __PRINT1(_L("#=- CFatHelperThreadBase::DoLaunchThread() failure#1 res:%d"), nRes);
  1.1937 +        iThread.Close();
  1.1938 +        ASSERT(0);
  1.1939 +        return nRes;
  1.1940 +        }
  1.1941 +
  1.1942 +    //-- 2. set up its working environment
  1.1943 +    AllowToLive(ETrue);
  1.1944 +	iThread.SetPriority((TThreadPriority)EHelperPriorityNormal); //-- initially the thread has very low priority
  1.1945 +	
  1.1946 +    //-- the state of this object now will be controlled by the thread 
  1.1947 +    SetState(ENotStarted);
  1.1948 +
  1.1949 +    //-- 3. resume thread and wait until it finishes its initialisation
  1.1950 +    TRequestStatus rqStatInit(KRequestPending);
  1.1951 +    
  1.1952 +    iThread.Logon(iThreadStatus);
  1.1953 +    iThread.Rendezvous(rqStatInit);
  1.1954 +    iThread.Resume();
  1.1955 +   
  1.1956 +    User::WaitForRequest(rqStatInit);
  1.1957 +
  1.1958 +    if(rqStatInit.Int() != KErrNone)
  1.1959 +        {//-- thread couldn't initialise
  1.1960 +        __PRINT1(_L("#=- CFatHelperThreadBase::DoLaunchThread() failure#2 res:%d"), nRes);
  1.1961 +        ForceStop();
  1.1962 +        ASSERT(0);
  1.1963 +        return nRes;
  1.1964 +        }
  1.1965 +
  1.1966 +   //-- Helper FAT thread is running now
  1.1967 +   return KErrNone; 
  1.1968 +    }
  1.1969 +
  1.1970 +
  1.1971 +//#######################################################################################################################################
  1.1972 +//#     CFat32ScanThread implementation
  1.1973 +//#######################################################################################################################################
  1.1974 +
  1.1975 +
  1.1976 +CFat32ScanThread::CFat32ScanThread(CAtaFatTable& aOwner)
  1.1977 +                 :CFatHelperThreadBase(aOwner)
  1.1978 +    {
  1.1979 +    }
  1.1980 +
  1.1981 +//-----------------------------------------------------------------------------
  1.1982 +
  1.1983 +/**
  1.1984 +    Launches the FAT32_ScanThread scaner thread.
  1.1985 +    @return  standard error code
  1.1986 +*/
  1.1987 +TInt CFat32ScanThread::Launch()
  1.1988 +    {
  1.1989 +    return DoLaunchThread(FAT32_ScanThread, this);    
  1.1990 +    }
  1.1991 +
  1.1992 +//-----------------------------------------------------------------------------
  1.1993 +
  1.1994 +/**
  1.1995 +    FAT32_ScanThread preamble function. It gets called by the scan thread at the very beginning.
  1.1996 +    Does some initialisation work and its return code is signaled to the thread owner by RThread::Rendezvous();
  1.1997 +    
  1.1998 +    @return Thread object initialisation code, KErrNone on success.
  1.1999 +*/
  1.2000 +TInt CFat32ScanThread::Thread_Preamble()
  1.2001 +    {
  1.2002 +    //__PRINT(_L("#=-  CFat32ScanThread::Thread_Preamble()"));
  1.2003 +
  1.2004 +    ipFatBitCache = iOwner.iCache->BitCacheInterface();
  1.2005 +    iTimeStart.UniversalTime(); //-- take thread start time
  1.2006 +    
  1.2007 +    ASSERT(State() == CFatHelperThreadBase::ENotStarted); //-- see the thread launcher
  1.2008 +    
  1.2009 +    if(!iOwner.IsFat32())
  1.2010 +        {//-- this stuff is supposed to work for FAT32 only
  1.2011 +        ASSERT(0);
  1.2012 +        return KErrArgument; 
  1.2013 +        }
  1.2014 +
  1.2015 +    return KErrNone;
  1.2016 +    }
  1.2017 +
  1.2018 +//-----------------------------------------------------------------------------
  1.2019 +/**
  1.2020 +    FAT32_ScanThread postamble function. It gets called by the scan thread just before its function exits.
  1.2021 +    Does some finalisation work and its return code is the thread completion code;
  1.2022 +    
  1.2023 +    @return Thread object finalisation code, KErrNone on success.
  1.2024 +*/
  1.2025 +TInt CFat32ScanThread::Thread_Postamble(TInt aResult)
  1.2026 +    {
  1.2027 +    //__PRINT(_L("#=-  CFat32ScanThread::Thread_Postamble()"));
  1.2028 +
  1.2029 +#ifdef _DEBUG    
  1.2030 +    //-- print out time taken the thread to finish
  1.2031 +    TName nameBuf;
  1.2032 +    iTimeEnd.UniversalTime(); //-- take end time
  1.2033 +    const TInt msScanTime = (TInt)( (iTimeEnd.MicroSecondsFrom(iTimeStart)).Int64() / K1mSec);
  1.2034 +    nameBuf.Copy(RThread().Name());
  1.2035 +    nameBuf.Insert(0,_L("#=-<<<")); 
  1.2036 +    nameBuf.AppendFormat(_L(" Thread Exit. id:%d, Code:%d, time:%d ms"), (TUint)RThread().Id(), aResult, msScanTime);
  1.2037 +    __PRINT(nameBuf);
  1.2038 +#endif
  1.2039 +    
  1.2040 +    //-- tell FAT bit supercache (if we have it) that we have finished populating it, successfully or not
  1.2041 +    if(ipFatBitCache) 
  1.2042 +        {
  1.2043 +        ipFatBitCache->FinishPopulating(aResult == KErrNone);
  1.2044 +        ipFatBitCache->Dump();
  1.2045 +        }
  1.2046 +
  1.2047 +    //-- close FAT chunk buffer
  1.2048 +    iFatChunkBuf.Close();
  1.2049 +
  1.2050 +    //-- set the host object state depending on the work results.
  1.2051 +    if(aResult == KErrNone)
  1.2052 +        SetState(CFatHelperThreadBase::EFinished_OK); 
  1.2053 +    else
  1.2054 +        SetState(CFatHelperThreadBase::EFailed); 
  1.2055 +
  1.2056 +   
  1.2057 +    return aResult;
  1.2058 +    }
  1.2059 +
  1.2060 +//#######################################################################################################################################
  1.2061 +//#     CFat32FreeSpaceScanner implementation
  1.2062 +//#######################################################################################################################################
  1.2063 +
  1.2064 +CFat32FreeSpaceScanner::CFat32FreeSpaceScanner(CAtaFatTable& aOwner)
  1.2065 +                       :CFat32ScanThread(aOwner) 
  1.2066 +    {
  1.2067 +    }
  1.2068 +
  1.2069 +/**
  1.2070 +    Factory method.
  1.2071 +    @param  aOwner owning CAtaFatTable
  1.2072 +    @return pointer to the constructed instance of the class
  1.2073 +*/
  1.2074 +CFat32FreeSpaceScanner* CFat32FreeSpaceScanner::NewL(CAtaFatTable& aOwner)
  1.2075 +    {
  1.2076 +    CFat32FreeSpaceScanner* pThis = NULL;
  1.2077 +    pThis = new (ELeave) CFat32FreeSpaceScanner(aOwner);    
  1.2078 +    
  1.2079 +    return pThis;
  1.2080 +    }
  1.2081 +
  1.2082 +//-----------------------------------------------------------------------------
  1.2083 +
  1.2084 +/**
  1.2085 +    Waits until FAT32 free clusters scan thread allows other thread (caller) to write to the FAT entry "aFatIndex".
  1.2086 +    Thread scans FAT from the beginning to the end and just waits untill scanning passes the entry number "aFatIndex"
  1.2087 +    
  1.2088 +    @param  aFatIndex index of the FAT entry we are going to write.
  1.2089 +*/
  1.2090 +void CFat32FreeSpaceScanner::RequestFatEntryWriteAccess(TUint32 aFatIndex) const
  1.2091 +    {
  1.2092 +    if(!ThreadWorking())
  1.2093 +        return;
  1.2094 +
  1.2095 +    ASSERT(iOwner.ClusterNumberValid(aFatIndex));
  1.2096 +
  1.2097 +    const TUint KWaitGranularity = 20*K1mSec; //-- wait granularity
  1.2098 +
  1.2099 +    //-- wait until FAT[aFatIndex] is available to write
  1.2100 +    while(aFatIndex > ClustersScanned() && ThreadWorking())
  1.2101 +        {
  1.2102 +        BoostPriority(ETrue); //-- Boost scan thread priority
  1.2103 +        User::After(KWaitGranularity); 
  1.2104 +        }
  1.2105 +    }
  1.2106 +
  1.2107 +//-----------------------------------------------------------------------------
  1.2108 +
  1.2109 +/** just an internal helper method. Stores the number of FAT entries already scanned by FAT free entries scan thread.  */
  1.2110 +void CFat32FreeSpaceScanner::SetClustersScanned(TUint32 aClusters) 
  1.2111 +    {
  1.2112 +    XAutoLock lock(iOwner.DriveInterface()); //-- enter critical section
  1.2113 +    iClustersScanned=aClusters;
  1.2114 +    }
  1.2115 +
  1.2116 +/** just an internal helper method. returns the number of FAT entries already scanned by FAT free entrie sscan thread.  */
  1.2117 +TUint32 CFat32FreeSpaceScanner::ClustersScanned() const
  1.2118 +    {
  1.2119 +    XAutoLock lock(iOwner.DriveInterface()); //-- enter critical section
  1.2120 +    return iClustersScanned;
  1.2121 +    }
  1.2122 +
  1.2123 +//-----------------------------------------------------------------------------
  1.2124 +
  1.2125 +/**
  1.2126 +    overriden FAT32_ScanThread preamble function. 
  1.2127 +    See CFat32ScanThread::Thread_Preamble()
  1.2128 +*/
  1.2129 +TInt CFat32FreeSpaceScanner::Thread_Preamble()
  1.2130 +    {
  1.2131 +    __PRINT1(_L("#=- CFat32FreeSpaceScanner::Thread_Preamble(), FAT state:%d"), iOwner.State());
  1.2132 +  
  1.2133 +    ASSERT(iOwner.State() == CAtaFatTable::EFreeClustersScan);
  1.2134 +    
  1.2135 +    //-- invoke generic preamble first
  1.2136 +    TInt nRes = CFat32ScanThread::Thread_Preamble();
  1.2137 +    if(nRes != KErrNone)
  1.2138 +        return nRes;
  1.2139 +
  1.2140 +    //-- do specific to this thread object initialisation work
  1.2141 +
  1.2142 +    //-- rename the thread
  1.2143 +    TName nameBuf;
  1.2144 +    const CFatMountCB& fatMount = *(iOwner.OwnerMount());
  1.2145 +    nameBuf.Format(_L("Fat32FreeSpaceScanner_drv_%d"), fatMount.DriveNumber());
  1.2146 +    RThread::RenameMe(nameBuf);
  1.2147 +
  1.2148 +    //-- allocate FAT chunk buffer; its size will depend on FAT table size.
  1.2149 +    const TUint32 fatSz = iOwner.MaxEntries() << KFat32EntrySzLog2;
  1.2150 +
  1.2151 +    if(fatSz < KBigSzFat_Threshold)
  1.2152 +        {//-- create a small buffer
  1.2153 +        if(iFatChunkBuf.CreateMax(KFatChunkBufSize_Small) != KErrNone)
  1.2154 +            return KErrNoMemory;
  1.2155 +        }
  1.2156 +    else
  1.2157 +        {//-- try to create larger buffer
  1.2158 +        if(iFatChunkBuf.CreateMax(KFatChunkBufSize_Big) != KErrNone && iFatChunkBuf.CreateMax(KFatChunkBufSize_Small) != KErrNone)
  1.2159 +            return KErrNoMemory;
  1.2160 +        }
  1.2161 +
  1.2162 +
  1.2163 +    //-- setup FAT table's parameters
  1.2164 +    //-- No free clusters yet; be careful with SetFreeClusters(), free clusters count can be 
  1.2165 +    //-- modified from other thread, e.g. from FreeClusterList. Use read-modify-write instead of assignment.
  1.2166 +    SetClustersScanned(0);
  1.2167 +    iOwner.SetFreeClusters(0); 
  1.2168 +
  1.2169 +    //-- calculate number of FAT entires need to be processed for CMountCB::SetDiskSpaceChange() call.
  1.2170 +    //-- if number of processed entries in FAT exceeds iEntriesNotifyThreshold, CMountCB::SetDiskSpaceChange()
  1.2171 +    //-- will be called and the iEntriesNotifyThreshold will be updated.
  1.2172 +    iNfyThresholdInc = (TUint32)KVolSpaceNotifyThreshold >> fatMount.ClusterSizeLog2();
  1.2173 +    iEntriesNotifyThreshold = iNfyThresholdInc;
  1.2174 +
  1.2175 +    //-- if there is an interface to the FAT bit supercache, tell it to start populating.  
  1.2176 +    //-- We will be populating this cache while reading and parsing FAT32.
  1.2177 +    if(ipFatBitCache)
  1.2178 +        ipFatBitCache->StartPopulating();
  1.2179 +
  1.2180 +
  1.2181 +    return KErrNone;
  1.2182 +    }
  1.2183 +
  1.2184 +//-----------------------------------------------------------------------------
  1.2185 +/**
  1.2186 +    overriden FAT32_ScanThread postamble function. 
  1.2187 +    See CFat32ScanThread::Thread_Postamble()
  1.2188 +*/
  1.2189 +TInt CFat32FreeSpaceScanner::Thread_Postamble(TInt aResult)
  1.2190 +    {
  1.2191 +    __PRINT2(_L("#=- CFat32FreeSpaceScanner::Thread_Postamble(%d), FAT state:%d"), aResult, iOwner.State());
  1.2192 +    __PRINT2(_L("#=- FAT_ScanThread: counted Free clusters:%d, 1st free:%d"), iOwner.NumberOfFreeClusters(), iOwner.FreeClusterHint());
  1.2193 +
  1.2194 +    ASSERT(iOwner.State() == CAtaFatTable::EFreeClustersScan);
  1.2195 +
  1.2196 +    //-- there was an error somewhere within FAT32 scan thread
  1.2197 +    if(aResult != KErrNone)
  1.2198 +        {
  1.2199 +        //-- indicate that the FAT table initialisation failed
  1.2200 +        __PRINT(_L("#=- Asynch FAT table initialisation failed !"));
  1.2201 +
  1.2202 +        iOwner.SetState(CAtaFatTable::EMountAborted);
  1.2203 +     
  1.2204 +        //-- fix up some FAT table parameters
  1.2205 +        if(iOwner.FreeClusterHint() < KFatFirstSearchCluster)
  1.2206 +            iOwner.SetFreeClusterHint(KFatFirstSearchCluster);    
  1.2207 +
  1.2208 +        }
  1.2209 +
  1.2210 +   
  1.2211 +    //-- call generic postamble
  1.2212 +    TInt nRes = CFat32ScanThread::Thread_Postamble(aResult);
  1.2213 +    
  1.2214 +    if(nRes == KErrNone)
  1.2215 +        {//-- FAT table now fully initialised
  1.2216 +        ASSERT(aResult == KErrNone);
  1.2217 +        iOwner.SetState(CAtaFatTable::EMounted);
  1.2218 +
  1.2219 +        //-- free space counting finished OK, call the notifier last time
  1.2220 +        CFatMountCB& fatMount = *(iOwner.OwnerMount());
  1.2221 +        
  1.2222 +        iOwner.AcquireLock();
  1.2223 +        const TInt64 currFreeSpace = ((TInt64)iOwner.FreeClusters()) << fatMount.ClusterSizeLog2();
  1.2224 +        iOwner.ReleaseLock();
  1.2225 +
  1.2226 +        fatMount.SetDiskSpaceChange(currFreeSpace);
  1.2227 +
  1.2228 +
  1.2229 +        }
  1.2230 +    else if(aResult == KErrNone)
  1.2231 +        {//-- CFat32ScanThread::Thread_Postamble() signaled a fault
  1.2232 +        iOwner.SetState(CAtaFatTable::EMountAborted);
  1.2233 +        }
  1.2234 +
  1.2235 +    return aResult;
  1.2236 +    }
  1.2237 +
  1.2238 +//-----------------------------------------------------------------------------
  1.2239 +/**
  1.2240 +    Process free FAT entries collected by the scan thread that parses chunk of FAT data.
  1.2241 +    This method gets called by the FAT scanning thread after a portion of FAT is read into the buffer and parsed
  1.2242 +
  1.2243 +    @param  aFreeEntriesInChunk number of free FAT entries counted in FAT chunk
  1.2244 +    @param  aCurrFirstFreeEntry current number of the first free FAT entry found
  1.2245 +    @param  aClustersScanned    total number of FAT entries scanned by the thread
  1.2246 +
  1.2247 +    @return standard error code, KErrNone on success
  1.2248 +*/
  1.2249 +TInt CFat32FreeSpaceScanner::Thread_ProcessCollectedFreeEntries(const CAtaFatTable::TFatScanParam& aFatScanParam)
  1.2250 +    {
  1.2251 +    ASSERT(State() == CFatHelperThreadBase::EWorking); 
  1.2252 +
  1.2253 +    CAtaFatTable& ataFatTable = iOwner;
  1.2254 +
  1.2255 +    //-------------------------------------------
  1.2256 +    //-- publish values to the CAtaFatTable object
  1.2257 +    ataFatTable.AcquireLock();
  1.2258 +            
  1.2259 +    //-- publish free cluster count, use read-modify-write here
  1.2260 +    //-- CFatTable::iFreeClusters can be already modified from other thread.
  1.2261 +    TUint32 currFreeClusters = ataFatTable.FreeClusters(); //-- simple non-thread safe method
  1.2262 +    
  1.2263 +    currFreeClusters += aFatScanParam.iCurrFreeEntries;
  1.2264 +
  1.2265 +    ataFatTable.SetFreeClusters(currFreeClusters);
  1.2266 +
  1.2267 +    //-- store total number of scanned clusters (not to be modified from other thread)
  1.2268 +    const TUint32 scannedEntries = aFatScanParam.iEntriesScanned;
  1.2269 +    SetClustersScanned(scannedEntries); 
  1.2270 +   
  1.2271 +
  1.2272 +    if(aFatScanParam.iFirstFree >= KFatFirstSearchCluster)
  1.2273 +        ataFatTable.SetFreeClusterHint(aFatScanParam.iFirstFree);//-- probably found next free cluster number 
  1.2274 +
  1.2275 +    ataFatTable.ReleaseLock();
  1.2276 +
  1.2277 +    //-- check if we need to call CMountCB::SetDiskSpaceChange() to notify it that the amount of processed FAT entries has reached the given threshold
  1.2278 +    if(scannedEntries >= iEntriesNotifyThreshold)
  1.2279 +        {
  1.2280 +        iEntriesNotifyThreshold += iNfyThresholdInc;
  1.2281 +
  1.2282 +        CFatMountCB& fatMount = *(iOwner.OwnerMount());
  1.2283 +        const TInt64 currFreeSpace = ((TInt64)currFreeClusters) << fatMount.ClusterSizeLog2();
  1.2284 +        fatMount.SetDiskSpaceChange(currFreeSpace);
  1.2285 +        }
  1.2286 +
  1.2287 +
  1.2288 +    return KErrNone;
  1.2289 +    }
  1.2290 +
  1.2291 +//#######################################################################################################################################
  1.2292 +//#     CFat32BitCachePopulator implementation
  1.2293 +//#######################################################################################################################################
  1.2294 +CFat32BitCachePopulator::CFat32BitCachePopulator(CAtaFatTable& aOwner)
  1.2295 +                       :CFat32ScanThread(aOwner) 
  1.2296 +    {
  1.2297 +    }
  1.2298 +
  1.2299 +/**
  1.2300 +    Factory method.
  1.2301 +    @param  aOwner owning CAtaFatTable
  1.2302 +    @return pointer to the constructed instance of the class
  1.2303 +*/
  1.2304 +CFat32BitCachePopulator* CFat32BitCachePopulator::NewL(CAtaFatTable& aOwner)
  1.2305 +    {
  1.2306 +    CFat32BitCachePopulator* pThis = NULL;
  1.2307 +    pThis = new (ELeave) CFat32BitCachePopulator(aOwner);    
  1.2308 +    
  1.2309 +    return pThis;
  1.2310 +    }
  1.2311 +
  1.2312 +//-----------------------------------------------------------------------------
  1.2313 +
  1.2314 +/**
  1.2315 +    The main FS thread tries to write the "aFatIndex" entry in FAT while this thread is running.
  1.2316 +    We can't do anything useful here, because FAT32 bit supercache doesn't work on FAT entry level and
  1.2317 +    deals with much less scale - FAT32 cache sector, which can consist from many FAT32 entries.
  1.2318 +    The conflict situation will be resolved in the CAtaFatTable::WriteL()
  1.2319 +*/
  1.2320 +void CFat32BitCachePopulator::RequestFatEntryWriteAccess(TUint32 /*aFatIndex*/) const
  1.2321 +    {
  1.2322 +    //-- do nothing here, do not block the caller
  1.2323 +    }
  1.2324 +
  1.2325 +
  1.2326 +//-----------------------------------------------------------------------------
  1.2327 +/**
  1.2328 +    overriden FAT32_ScanThread preamble function. 
  1.2329 +    See CFat32ScanThread::Thread_Preamble()
  1.2330 +*/
  1.2331 +TInt CFat32BitCachePopulator::Thread_Preamble()
  1.2332 +    {
  1.2333 +    __PRINT(_L("#=- CFat32BitCachePopulator::Thread_Preamble()"));
  1.2334 +    
  1.2335 +    //-- invoke generic preamble
  1.2336 +    TInt nRes = CFat32ScanThread::Thread_Preamble();
  1.2337 +    if(nRes != KErrNone)
  1.2338 +        return nRes;
  1.2339 +
  1.2340 +    //-- do specific to this thread object initialisation work
  1.2341 +    iTotalOccupiedFatEntries = 0;
  1.2342 +
  1.2343 +    //-- rename the thread
  1.2344 +    TName nameBuf;
  1.2345 +    const CFatMountCB& fatMount = *(iOwner.OwnerMount());
  1.2346 +    nameBuf.Format(_L("CFat32BitCachePopulator_drv_%d"), fatMount.DriveNumber());
  1.2347 +    RThread::RenameMe(nameBuf);
  1.2348 +
  1.2349 +    //-- allocate FAT chunk buffer
  1.2350 +    nRes = iFatChunkBuf.CreateMax(KFatChunkBufSize);
  1.2351 +    if(nRes != KErrNone)
  1.2352 +        return nRes;
  1.2353 +
  1.2354 +    
  1.2355 +    if(!ipFatBitCache)
  1.2356 +        {//-- this is a bit cache populator and the bit cache object must have been constructed before setting up the populating thread.
  1.2357 +        ASSERT(0);
  1.2358 +        return KErrCorrupt;
  1.2359 +        }
  1.2360 +    
  1.2361 +    //-- Tell FAT bit supercache to start populating. We will be populating this cache while reading and parsing FAT32.
  1.2362 +    if(ipFatBitCache->StartPopulating())
  1.2363 +        nRes = KErrNone;
  1.2364 +    else
  1.2365 +        nRes = KErrCorrupt;
  1.2366 +
  1.2367 +    return nRes;
  1.2368 +    }
  1.2369 +
  1.2370 +//-----------------------------------------------------------------------------
  1.2371 +
  1.2372 +/**
  1.2373 +    overriden FAT32_ScanThread postamble function. 
  1.2374 +    See CFat32ScanThread::Thread_Postamble()
  1.2375 +*/
  1.2376 +TInt CFat32BitCachePopulator::Thread_Postamble(TInt aResult)
  1.2377 +    {
  1.2378 +    __PRINT1(_L("#=- CFat32BitCachePopulator::Thread_Postamble(%d)"), aResult);
  1.2379 +
  1.2380 +    //-- nothing specific to do, just call generic method
  1.2381 +    return CFat32ScanThread::Thread_Postamble(aResult);
  1.2382 +    }
  1.2383 +
  1.2384 +//-----------------------------------------------------------------------------
  1.2385 +/**
  1.2386 +    This method gets called by the FAT scanning thread after a portion of FAT is read into the buffer and parsed
  1.2387 +    @return standard error code, KErrNone on success
  1.2388 +*/
  1.2389 +TInt CFat32BitCachePopulator::Thread_ProcessCollectedFreeEntries(const CAtaFatTable::TFatScanParam& aFatScanParam)
  1.2390 +    {
  1.2391 +    ASSERT(State() == CFatHelperThreadBase::EWorking); 
  1.2392 +    
  1.2393 +    //-- check the bit cache state
  1.2394 +    if(ipFatBitCache->State() != CFatBitCache::EPopulating)
  1.2395 +        {//-- something wrong happened to the cache, e.g. someone forcedly invalidated it (probably from another thread)
  1.2396 +        return KErrAbort;
  1.2397 +        }
  1.2398 +
  1.2399 +    
  1.2400 +    //-- if CFat32BitCachePopulator has already counted all _occupied_ FAT entries, there is no need to 
  1.2401 +    //-- continue FAT reading; just mark the rest of the FAT bit supercache as containing free FAT entries and abort scanning
  1.2402 +
  1.2403 +    CAtaFatTable& ataFatTable = iOwner;
  1.2404 +
  1.2405 +    ataFatTable.AcquireLock();
  1.2406 +    
  1.2407 +    //-- current amount of non-free entries in FAT, excluding FAT[0] & FAT[1]
  1.2408 +    const TUint32 KCurrNonFreeEntries = ataFatTable.MaxEntries() - ataFatTable.FreeClusters() - KFatFirstSearchCluster;
  1.2409 +    
  1.2410 +    iTotalOccupiedFatEntries += aFatScanParam.iCurrOccupiedEntries;
  1.2411 +    
  1.2412 +    //-- check if the thread needs to continue it work
  1.2413 +    const TBool KNoNeedToScanFurther = (iTotalOccupiedFatEntries >= KCurrNonFreeEntries);
  1.2414 +
  1.2415 +    if(KNoNeedToScanFurther)
  1.2416 +        {
  1.2417 +        //-- tell FAT bit supercache to mark the range from currently scanned FAT entry to the end of the FAT as containing free entries.
  1.2418 +        __PRINT2(_L("#=- CFat32BitCachePopulator::Thread_ProcessCollectedFreeEntries() counted: %d/%d; aborting scan."), iTotalOccupiedFatEntries, KCurrNonFreeEntries);
  1.2419 +        
  1.2420 +        const TUint32 entryStart = aFatScanParam.iEntriesScanned; //-- first FAT entry in the range to be marked as 'free'
  1.2421 +        const TUint32 entryEnd   = ataFatTable.MaxEntries()-1;    //-- last FAT entry in the range to be marked as 'free', last FAT entry
  1.2422 +
  1.2423 +        ipFatBitCache->MarkFatRange(entryStart, entryEnd, ETrue);
  1.2424 +        
  1.2425 +        //-- signal that the thread shall finish with normal (KErrNone) reason
  1.2426 +        //-- it will also normally finish FAT bit cache populating in postamble
  1.2427 +        AllowToLive(EFalse); 
  1.2428 +        }
  1.2429 +
  1.2430 +    ataFatTable.ReleaseLock();
  1.2431 +
  1.2432 +    
  1.2433 +    return KErrNone;
  1.2434 +    }
  1.2435 +
  1.2436 +
  1.2437 +//#######################################################################################################################################
  1.2438 +/**
  1.2439 +    FAT32 free entries scan thread function. Walks through FAT32 and counts free entries.
  1.2440 +    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.
  1.2441 +
  1.2442 +    @param apHostObject pointer to the host object of CFat32ScanThread base class.
  1.2443 +*/
  1.2444 +//#######################################################################################################################################
  1.2445 +TInt FAT32_ScanThread(TAny* apHostObject)
  1.2446 +    {
  1.2447 +    TInt    nRes;
  1.2448 +
  1.2449 +#ifdef _DEBUG
  1.2450 +    TName   nameBuf;
  1.2451 +    nameBuf.Copy(RThread().Name());
  1.2452 +    nameBuf.Insert(0,_L("#=->>>")); nameBuf.AppendFormat(_L(" Thread Enter (id:%d)"), (TUint)RThread().Id());
  1.2453 +    __PRINT(nameBuf);
  1.2454 +#endif
  1.2455 +    
  1.2456 +    ASSERT(apHostObject);
  1.2457 +    CFat32FreeSpaceScanner* pSelf = (CFat32FreeSpaceScanner*)apHostObject;
  1.2458 +
  1.2459 +    CAtaFatTable& ataFatTable = pSelf->iOwner;
  1.2460 +    CFatMountCB&  fatMount = *(ataFatTable.OwnerMount());
  1.2461 +
  1.2462 +    const TUint32 KFat32EntrySz = sizeof(TFat32Entry); 
  1.2463 +    const TUint32 KFat1StartPos = fatMount.StartOfFatInBytes();
  1.2464 +    const TUint32 KNumClusters = ataFatTable.MaxEntries(); //-- FAT[0] & FAT[1] are reserved and not counted by UsableClusters()
  1.2465 +
  1.2466 +    //-- perform thread preamble work
  1.2467 +    nRes = pSelf->Thread_Preamble();
  1.2468 +
  1.2469 +    //-- signal the thread initialisation result
  1.2470 +    RThread::Rendezvous(nRes);
  1.2471 +
  1.2472 +
  1.2473 +    //-- Initialisation OK, do real job: FAT scanning
  1.2474 +    if(nRes == KErrNone)
  1.2475 +        {
  1.2476 +        pSelf->SetState(CFatHelperThreadBase::EWorking); 
  1.2477 +
  1.2478 +        TUint32 rem = KNumClusters * KFat32EntrySz; 
  1.2479 +        TUint32 mediaPos = KFat1StartPos;   
  1.2480 +        
  1.2481 +        CAtaFatTable::TFatScanParam fatScanParam; //-- FAT scanning parameters
  1.2482 +
  1.2483 +        //============================================
  1.2484 +        //=== FAT read and parse loop ================
  1.2485 +        //-- in this loop we read portions of raw FAT32 data in a buffer, than parse this buffer 
  1.2486 +        //-- in order to find out the number of free FAT entries there and other stuff
  1.2487 +        while(rem)
  1.2488 +            {
  1.2489 +            const TUint32 bytesToRead=Min(rem, (TUint32)pSelf->iFatChunkBuf.Size());
  1.2490 +            TPtrC8 ptrData(pSelf->iFatChunkBuf.Ptr(), bytesToRead);
  1.2491 +
  1.2492 +            //-- check for sudden media change
  1.2493 +            if(fatMount.Drive().IsChanged()) 
  1.2494 +                {
  1.2495 +                __PRINT(_L("#=--- FAT32_ScanThread: Media change occured, aborting!"));
  1.2496 +                nRes = KErrAbort;
  1.2497 +                break;
  1.2498 +                }
  1.2499 +
  1.2500 +            //-------------------------------------------
  1.2501 +            //-- read a portion of FAT into the buffer
  1.2502 +            ataFatTable.AcquireLock();
  1.2503 +            
  1.2504 +            //-- check if the thread was requested to finish
  1.2505 +            if(!pSelf->AllowedToLive()) 
  1.2506 +                {
  1.2507 +                ataFatTable.ReleaseLock();
  1.2508 +                nRes = KErrAbort;
  1.2509 +                break;
  1.2510 +                }
  1.2511 +
  1.2512 +            //-- actual read
  1.2513 +            //__PRINT3(_L("#=--- FAT32_ScanThread: read %d bytes pos:0x%x, boost:%d"), bytesToRead, mediaPos, pSelf->IsPriorityBoosted());
  1.2514 +
  1.2515 +            nRes = fatMount.LocalDrive()->Read(mediaPos, bytesToRead, pSelf->iFatChunkBuf); 
  1.2516 +            
  1.2517 +            ataFatTable.ReleaseLock();
  1.2518 +
  1.2519 +            //-------------------------------------------
  1.2520 +            //-- analyse the read error code
  1.2521 +            if(nRes != KErrNone)
  1.2522 +                {
  1.2523 +                __PRINT1(_L("#=--- FAT32_ScanThread read error! res:%d"), nRes);
  1.2524 +                break; //-- abort scanning
  1.2525 +                }
  1.2526 +
  1.2527 +            //-------------------------------------------
  1.2528 +            //-- parse FAT from the buffer
  1.2529 +            
  1.2530 +            //-- we need number of free and occupied entries in the _current_ FAT chunk being read and parsed
  1.2531 +            fatScanParam.iCurrFreeEntries     = 0;
  1.2532 +            fatScanParam.iCurrOccupiedEntries = 0;
  1.2533 +
  1.2534 +            ataFatTable.DoParseFatBuf(ptrData, fatScanParam);
  1.2535 +
  1.2536 +            //--- process the the results of FAT buffer parsing
  1.2537 +            nRes = pSelf->Thread_ProcessCollectedFreeEntries(fatScanParam);
  1.2538 +            if(nRes != KErrNone || !pSelf->AllowedToLive())
  1.2539 +                {//-- some types of worker threads may wish to finish normally but prematurely, by the result of Thread_ProcessCollectedFreeEntries()
  1.2540 +                break; //-- abort scanning
  1.2541 +                }
  1.2542 +
  1.2543 +
  1.2544 +            //-- allow this thread to be preempted by another one that wants to access the media driver.
  1.2545 +            //-- without this wait we will have priority inversion, because this (low priority) thread continiously reads data by big chunks 
  1.2546 +            //-- and doesn't allow others to access the driver.
  1.2547 +            //-- On the other hand, if the thread's priority is boosted, there is no reason to be polite.
  1.2548 +            if(!pSelf->IsPriorityBoosted())
  1.2549 +                User::After(K1mSec); //-- User::After() granularity can be much coarser than 1ms
  1.2550 +
  1.2551 +            //-------------------------------------------
  1.2552 +            mediaPos += bytesToRead;
  1.2553 +            rem -= bytesToRead;
  1.2554 +        
  1.2555 +            }//while(rem)
  1.2556 +    
  1.2557 +        }//if(nRes == KErrNone)
  1.2558 +
  1.2559 +
  1.2560 +    //-- perform thread postamble work
  1.2561 +    nRes = pSelf->Thread_Postamble(nRes);
  1.2562 +
  1.2563 +    return nRes;
  1.2564 +    }
  1.2565 +
  1.2566 +
  1.2567 +
  1.2568 +
  1.2569 +
  1.2570 +
  1.2571 +
  1.2572 +
  1.2573 +
  1.2574 +
  1.2575 +
  1.2576 +
  1.2577 +
  1.2578 +
  1.2579 +
  1.2580 +
  1.2581 +
  1.2582 +
  1.2583 +
  1.2584 +
  1.2585 +
  1.2586 +
  1.2587 +
  1.2588 +
  1.2589 +
  1.2590 +
  1.2591 +
  1.2592 +
  1.2593 +
  1.2594 +
  1.2595 +
  1.2596 +
  1.2597 +