os/kernelhwsrv/userlibandfileserver/fileserver/sfat/fat_table.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat/fat_table.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1051 @@
     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\sfat\fat_table.cpp
    1.18 +// FAT12/16 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 +//!!
    1.30 +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
    1.31 +//!!
    1.32 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1.33 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    1.34 +
    1.35 +
    1.36 +#include "sl_std.h"
    1.37 +#include "sl_fatcache.h"
    1.38 +#include "fat_table.h"
    1.39 +
    1.40 +
    1.41 +//#######################################################################################################################################
    1.42 +//#     CFatTable class implementation 
    1.43 +//#######################################################################################################################################
    1.44 +
    1.45 +/**
    1.46 +    FAT object factory method.
    1.47 +    Constructs either CAtaFatTable or CRamFatTable depending on the media type parameter
    1.48 +
    1.49 +    @param aOwner Pointer to the owning mount
    1.50 +    @param aLocDrvCaps local drive attributes
    1.51 +    @leave KErrNoMemory
    1.52 +    @return Pointer to the Fat table
    1.53 +*/
    1.54 +CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps)
    1.55 +    {
    1.56 +    CFatTable* pFatTable=NULL;
    1.57 +
    1.58 +    
    1.59 +    switch(aLocDrvCaps.iType)
    1.60 +        {
    1.61 +        case EMediaRam:
    1.62 +            {//-- this is RAM media, try to create CRamFatTable instance.
    1.63 +            const TFatType fatType = aOwner.FatType();
    1.64 +            
    1.65 +            if(fatType != EFat16 )
    1.66 +                {//-- CRamFatTable doesn't support FAT12; FAT16 only.
    1.67 +                __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType);
    1.68 +                ASSERT(0);
    1.69 +                return NULL;
    1.70 +                }
    1.71 +            
    1.72 +                pFatTable = CRamFatTable::NewL(aOwner);            
    1.73 +            }
    1.74 +        break;
    1.75 +
    1.76 +        default:
    1.77 +            //-- other media
    1.78 +            pFatTable = CAtaFatTable::NewL(aOwner);
    1.79 +        break;
    1.80 +        };
    1.81 +
    1.82 +    return pFatTable;
    1.83 +    }
    1.84 +
    1.85 +CFatTable::CFatTable(CFatMountCB& aOwner)
    1.86 +{
    1.87 +    iOwner = &aOwner;
    1.88 +    ASSERT(iOwner);
    1.89 +}
    1.90 +
    1.91 +CFatTable::~CFatTable()
    1.92 +{
    1.93 +    //-- destroy cache ignoring dirty data in cache
    1.94 +    //-- the destructor isn't an appropriate place to flush the data.
    1.95 +    Dismount(ETrue); 
    1.96 +}
    1.97 +
    1.98 +//-----------------------------------------------------------------------------
    1.99 +
   1.100 +/**
   1.101 +    Initialise the object, get data from the owning CFatMountCB
   1.102 +*/
   1.103 +void CFatTable::InitializeL()
   1.104 +    {
   1.105 +    ASSERT(iOwner);
   1.106 +
   1.107 +    //-- get FAT type from the owner
   1.108 +    iFatType = iOwner->FatType();
   1.109 +    ASSERT(IsFat12() || IsFat16());
   1.110 +
   1.111 +    iFreeClusterHint = KFatFirstSearchCluster;
   1.112 +
   1.113 +    //-- cache the media attributes
   1.114 +    TLocalDriveCapsV2 caps;
   1.115 +    TPckg<TLocalDriveCapsV2> capsPckg(caps);
   1.116 +    User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
   1.117 +    iMediaAtt = caps.iMediaAtt;
   1.118 +    
   1.119 +    //-- obtain maximal number of entries in the table
   1.120 +    iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use
   1.121 +
   1.122 +    __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries);
   1.123 +    }
   1.124 +
   1.125 +//-----------------------------------------------------------------------------
   1.126 +
   1.127 +/** 
   1.128 +    Decrements the free cluster count.
   1.129 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.130 +    cluster of a large file. Use more than one cluster granularity.
   1.131 +     
   1.132 +    @param  aCount a number of clusters 
   1.133 +*/
   1.134 +void CFatTable::DecrementFreeClusterCount(TUint32 aCount)
   1.135 +{
   1.136 +    __ASSERT_DEBUG(iFreeClusters >= aCount, Fault(EFatCorrupt));
   1.137 +    iFreeClusters -= aCount;
   1.138 +}
   1.139 +
   1.140 +/** 
   1.141 +    Increments the free cluster count.
   1.142 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.143 +    cluster of a large file. Use more than one cluster granularity.
   1.144 +
   1.145 +    @param  aCount a number of clusters 
   1.146 +*/
   1.147 +void CFatTable::IncrementFreeClusterCount(TUint32 aCount)
   1.148 +{
   1.149 +    const TUint32 newVal = iFreeClusters+aCount;
   1.150 +    __ASSERT_DEBUG(newVal<=MaxEntries(), Fault(EFatCorrupt));
   1.151 +    
   1.152 +    iFreeClusters = newVal;
   1.153 +}
   1.154 +
   1.155 +/** @return number of free clusters in the FAT */
   1.156 +TUint32 CFatTable::NumberOfFreeClusters(TBool /*aSyncOperation=EFalse*/) const
   1.157 +{
   1.158 +    return FreeClusters();
   1.159 +}
   1.160 +
   1.161 +void CFatTable::SetFreeClusters(TUint32 aFreeClusters)
   1.162 +{   
   1.163 +    iFreeClusters=aFreeClusters;
   1.164 +}
   1.165 +
   1.166 +/**
   1.167 +    Get the hint about the last known free cluster number.
   1.168 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.169 +    cluster of a large file.
   1.170 +
   1.171 +    @return cluster number supposedly close to the free one.
   1.172 +*/
   1.173 +TUint32 CFatTable::FreeClusterHint() const 
   1.174 +{
   1.175 +    ASSERT(ClusterNumberValid(iFreeClusterHint));
   1.176 +    return iFreeClusterHint;
   1.177 +} 
   1.178 +
   1.179 +/**
   1.180 +    Set a free cluster hint. The next search fro the free cluster can start from this value.
   1.181 +    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.182 +    free entries chain.
   1.183 +    Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every 
   1.184 +    cluster of a large file.
   1.185 +
   1.186 +    @param aCluster cluster number hint.
   1.187 +*/
   1.188 +void CFatTable::SetFreeClusterHint(TUint32 aCluster) 
   1.189 +{
   1.190 +    ASSERT(ClusterNumberValid(aCluster));
   1.191 +    iFreeClusterHint=aCluster;
   1.192 +} 
   1.193 +
   1.194 +//-----------------------------------------------------------------------------
   1.195 +
   1.196 +/**
   1.197 +    Find out the number of free clusters on the volume.
   1.198 +    Reads whole FAT and counts free clusters.
   1.199 +*/
   1.200 +void CFatTable::CountFreeClustersL()
   1.201 +{
   1.202 +    __PRINT1(_L("#- CFatTable::CountFreeClustersL(), drv:%d"), iOwner->DriveNumber());
   1.203 +
   1.204 +    const TUint32 KUsableClusters = iOwner->UsableClusters();
   1.205 +    (void)KUsableClusters;
   1.206 +    
   1.207 +    TUint32 freeClusters = 0;
   1.208 +    TUint32 firstFreeCluster = 0;
   1.209 +
   1.210 +    TTime   timeStart;
   1.211 +    TTime   timeEnd;
   1.212 +    timeStart.UniversalTime(); //-- take start time
   1.213 +
   1.214 +    //-- walk through whole FAT table looking for free clusters
   1.215 +    for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i)
   1.216 +    {
   1.217 +        if(ReadL(i) == KSpareCluster)
   1.218 +        {//-- found a free cluster
   1.219 +            ++freeClusters;
   1.220 +            
   1.221 +            if(!firstFreeCluster)
   1.222 +                firstFreeCluster = i;
   1.223 +        }
   1.224 +    }
   1.225 +
   1.226 +    timeEnd.UniversalTime(); //-- take end time
   1.227 +    const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
   1.228 +    __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime);
   1.229 +    (void)msScanTime;
   1.230 +
   1.231 +    if(!firstFreeCluster) //-- haven't found free clusters on the volume
   1.232 +        firstFreeCluster = KFatFirstSearchCluster;
   1.233 +
   1.234 +    ASSERT(freeClusters <= KUsableClusters);
   1.235 +
   1.236 +    SetFreeClusters(freeClusters);
   1.237 +    SetFreeClusterHint(firstFreeCluster);
   1.238 +}
   1.239 +
   1.240 +//-----------------------------------------------------------------------------
   1.241 +
   1.242 +/**
   1.243 +Count the number of contiguous cluster from a start cluster
   1.244 +
   1.245 +@param aStartCluster cluster to start counting from
   1.246 +@param anEndCluster contains the end cluster number upon return
   1.247 +@param aMaxCount Maximum cluster required
   1.248 +@leave System wide error values
   1.249 +@return Number of contiguous clusters from aStartCluster.
   1.250 +*/
   1.251 +TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const
   1.252 +    {
   1.253 +    __PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount);
   1.254 +    TUint32 clusterListLen=1;
   1.255 +    TInt endCluster=aStartCluster;
   1.256 +    TInt64 endClusterPos=DataPositionInBytes(endCluster);
   1.257 +    while (clusterListLen<aMaxCount)
   1.258 +        {
   1.259 +        TInt oldCluster=endCluster;
   1.260 +        TInt64 oldClusterPos=endClusterPos;
   1.261 +        if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
   1.262 +            {
   1.263 +            endCluster=oldCluster;
   1.264 +            break;
   1.265 +            }
   1.266 +        clusterListLen++;
   1.267 +        }
   1.268 +    anEndCluster=endCluster;
   1.269 +    return(clusterListLen);
   1.270 +    }   
   1.271 +
   1.272 +//-----------------------------------------------------------------------------
   1.273 +
   1.274 +/**
   1.275 +    Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full).
   1.276 +
   1.277 +    @param aNumber  amount of clusters to allocate
   1.278 +    @param aCluster FAT entry index to start with.
   1.279 +
   1.280 +    @leave KErrDiskFull + system wide error codes
   1.281 +*/
   1.282 +void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
   1.283 +    {
   1.284 +    __PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster);
   1.285 +    __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
   1.286 +    
   1.287 +    while(aNumber && GetNextClusterL(aCluster))
   1.288 +        aNumber--;
   1.289 +
   1.290 +    if(!aNumber)
   1.291 +        return;
   1.292 +
   1.293 +    if (iFreeClusters<aNumber)
   1.294 +        {
   1.295 +        __PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull"));
   1.296 +        User::Leave(KErrDiskFull);
   1.297 +        }
   1.298 +
   1.299 +
   1.300 +    TUint32 freeCluster = 0;
   1.301 +    
   1.302 +    //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL()
   1.303 +    for(TUint i=0; i<aNumber; ++i)
   1.304 +        {
   1.305 +        freeCluster = FindClosestFreeClusterL(aCluster);
   1.306 +        WriteFatEntryEofL(freeCluster); //  Must write EOF for FindClosestFreeCluster to work again
   1.307 +        WriteL(aCluster,freeCluster);
   1.308 +        aCluster=freeCluster;
   1.309 +        }
   1.310 +    
   1.311 +    //-- decrement number of available clusters
   1.312 +    DecrementFreeClusterCount(aNumber);
   1.313 +
   1.314 +    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from
   1.315 +    SetFreeClusterHint(aCluster); 
   1.316 +    
   1.317 +    }
   1.318 +
   1.319 +//-----------------------------------------------------------------------------
   1.320 +
   1.321 +/**
   1.322 +Allocate and mark as EOF a single cluster as close as possible to aNearestCluster
   1.323 +
   1.324 +@param aNearestCluster Cluster the new cluster should be nearest to
   1.325 +@leave System wide error codes
   1.326 +@return The cluster number allocated
   1.327 +*/
   1.328 +TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
   1.329 +    {
   1.330 +    __PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster);
   1.331 +    if (iFreeClusters==0)
   1.332 +        User::Leave(KErrDiskFull);
   1.333 +    const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster);
   1.334 +    WriteFatEntryEofL(freeCluster);
   1.335 +    DecrementFreeClusterCount(1);
   1.336 +
   1.337 +    //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from.
   1.338 +    SetFreeClusterHint(freeCluster); 
   1.339 +
   1.340 +    return(freeCluster);
   1.341 +    }   
   1.342 +
   1.343 +//-----------------------------------------------------------------------------
   1.344 +
   1.345 +/**
   1.346 +Allocate and link a cluster chain, leaves if there are not enough free clusters.
   1.347 +Chain starts as close as possible to aNearestCluster, last cluster will be marked as EOF.
   1.348 +
   1.349 +@param aNumber Number of clusters to allocate
   1.350 +@param aNearestCluster Cluster the new chain should be nearest to
   1.351 +@leave System wide error codes
   1.352 +@return The first cluster number allocated
   1.353 +*/
   1.354 +TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster)
   1.355 +    {
   1.356 +    __PRINT2(_L("#>> CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster);
   1.357 +    __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
   1.358 +
   1.359 +    if (iFreeClusters<aNumber)
   1.360 +        {
   1.361 +        __PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull"));
   1.362 +        User::Leave(KErrDiskFull);
   1.363 +        }
   1.364 +
   1.365 +    TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster);
   1.366 +    if (aNumber>1)
   1.367 +        ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster);
   1.368 +
   1.369 +    return(firstCluster);
   1.370 +    }   
   1.371 +
   1.372 +//-----------------------------------------------------------------------------
   1.373 +
   1.374 +/**
   1.375 +    Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported.
   1.376 +    @param aFreedClusters array with FAT numbers of clusters that shall be marked as "deleted"
   1.377 +*/
   1.378 +void CFatTable::DoFreedClustersNotify(RClusterArray &aFreedClusters)
   1.379 +{
   1.380 +    ASSERT(iMediaAtt & KMediaAttDeleteNotify);
   1.381 +
   1.382 +    const TUint clusterCount = aFreedClusters.Count();
   1.383 +
   1.384 +    if(!clusterCount)
   1.385 +        return;
   1.386 +    
   1.387 +    FlushL(); //-- Commit the FAT changes to disk first to be safe
   1.388 +
   1.389 +    const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2();
   1.390 +
   1.391 +    TInt64  byteAddress = 0;    
   1.392 +    TUint   deleteLen = 0;  // zero indicates no clusters accumulated yet
   1.393 +
   1.394 +    for (TUint i=0; i<clusterCount; ++i)
   1.395 +    {
   1.396 +        const TUint currCluster = aFreedClusters[i];
   1.397 +        
   1.398 +        if (deleteLen == 0)
   1.399 +            byteAddress = DataPositionInBytes(currCluster); //-- start of the media range
   1.400 +        
   1.401 +        deleteLen += bytesPerCluster;
   1.402 +
   1.403 +        //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver
   1.404 +        if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1))
   1.405 +        {
   1.406 +            //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen);
   1.407 +            //__PRINT2(_L("   first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster);
   1.408 +            const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen);
   1.409 +            if(r != KErrNone)
   1.410 +                {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; 
   1.411 +                 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media.
   1.412 +                const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement);
   1.413 +                __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
   1.414 +
   1.415 +                if(platSecEnabled)
   1.416 +                    {
   1.417 +                    //-- if PlatSec is enabled, we can't afford jeopardize the security; without DeleteNotify()
   1.418 +                    //-- it's possible to pick up data from deleted files, so, panic the file server.
   1.419 +                    Fault(EFatBadLocalDrive);
   1.420 +                    }
   1.421 +                else
   1.422 +                    {
   1.423 +                    //-- if PlatSec is disabled, it's OK to ignore the NAND fault in release mode.
   1.424 +                    __ASSERT_DEBUG(0, Fault(EFatBadLocalDrive));
   1.425 +                    }        
   1.426 +                }
   1.427 +            
   1.428 +            
   1.429 +            deleteLen = 0;
   1.430 +        }
   1.431 +
   1.432 +    }
   1.433 +
   1.434 +    //-- empty the array.
   1.435 +    aFreedClusters.Reset();
   1.436 +}
   1.437 +
   1.438 +//-----------------------------------------------------------------------------
   1.439 +/**
   1.440 +Mark a chain of clusters as free in the FAT. 
   1.441 +
   1.442 +@param aCluster Start cluster of cluster chain to free
   1.443 +@leave System wide error codes
   1.444 +*/
   1.445 +void CFatTable::FreeClusterListL(TUint32 aCluster)
   1.446 +    {
   1.447 +    __PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster);
   1.448 +    if (aCluster == KSpareCluster)
   1.449 +        return; 
   1.450 +
   1.451 +    //-- here we can store array of freed cluster numbers in order to 
   1.452 +    //-- notify media drive about the media addresses marked as "invalid"
   1.453 +    RClusterArray deletedClusters;      
   1.454 +    CleanupClosePushL(deletedClusters);
   1.455 +
   1.456 +    //-- if ETrue, we need to notify media driver about invalidated media addressses
   1.457 +    const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify;
   1.458 +
   1.459 +    //-- this is a maximal number of FAT entries in the deletedClusters array.
   1.460 +    //-- as soon as we collect this number of entries in the array, FAT cache will be flushed
   1.461 +    //-- and driver notified. The array will be emptied. Used to avoid huge array when deleting
   1.462 +    //--  large files on NAND media 
   1.463 +    const TUint KSubListLen = 4096;
   1.464 +    ASSERT(IsPowerOf2(KSubListLen));
   1.465 +
   1.466 +    TUint32 lastKnownFreeCluster = FreeClusterHint();
   1.467 +    TUint32 cntFreedClusters = 0;
   1.468 +
   1.469 +    TUint32 currCluster = aCluster;
   1.470 +    TInt    nextCluster = aCluster;
   1.471 +
   1.472 +    for(;;)
   1.473 +        {
   1.474 +        const TBool bEOF = !GetNextClusterL(nextCluster);    
   1.475 +        WriteL(currCluster, KSpareCluster);
   1.476 +
   1.477 +        lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster);
   1.478 +
   1.479 +        // Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe 
   1.480 +        // to do once the FAT changes have been written to disk.
   1.481 +        if(bFreeClustersNotify)
   1.482 +            deletedClusters.Append(currCluster);
   1.483 +
   1.484 +        ++cntFreedClusters;
   1.485 +        currCluster = nextCluster;
   1.486 +
   1.487 +        if (bEOF || aCluster == KSpareCluster)
   1.488 +            break;
   1.489 +
   1.490 +        if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0)
   1.491 +        {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array.
   1.492 +            IncrementFreeClusterCount(cntFreedClusters);
   1.493 +            cntFreedClusters = 0;
   1.494 +
   1.495 +            SetFreeClusterHint(lastKnownFreeCluster);
   1.496 +            DoFreedClustersNotify(deletedClusters);
   1.497 +        }
   1.498 +
   1.499 +    }
   1.500 +
   1.501 +    //-- increase the number of free clusters and notify the driver if required.
   1.502 +    IncrementFreeClusterCount(cntFreedClusters);
   1.503 +    SetFreeClusterHint(lastKnownFreeCluster);
   1.504 +    
   1.505 +    if(bFreeClustersNotify)
   1.506 +    DoFreedClustersNotify(deletedClusters);
   1.507 +
   1.508 +    CleanupStack::PopAndDestroy(&deletedClusters);
   1.509 +    }
   1.510 +
   1.511 +//-----------------------------------------------------------------------------
   1.512 +
   1.513 +/**
   1.514 +Find a free cluster nearest to aCluster, Always checks to the right of aCluster first 
   1.515 +but checks in both directions in the Fat.
   1.516 +
   1.517 +@param aCluster Cluster to find nearest free cluster to.
   1.518 +@leave KErrDiskFull + system wide error codes
   1.519 +@return cluster number found
   1.520 +*/
   1.521 +TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster)
   1.522 +    {
   1.523 +    __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
   1.524 +
   1.525 +    if(!ClusterNumberValid(aCluster))
   1.526 +        {
   1.527 +        ASSERT(0);
   1.528 +        User::Leave(KErrCorrupt);
   1.529 +        }
   1.530 +
   1.531 +
   1.532 +    if(iFreeClusters==0)
   1.533 +        {//-- there is no at least 1 free cluster available
   1.534 +        __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
   1.535 +        User::Leave(KErrDiskFull);
   1.536 +        }
   1.537 +    
   1.538 +    //-- 1. look if the given index contains a free entry 
   1.539 +    if(ReadL(aCluster) != KSpareCluster)
   1.540 +        {//-- no, it doesn't...
   1.541 +        
   1.542 +        //-- 2. look in both directions starting from the aCluster, looking in the right direction first
   1.543 +        
   1.544 +        const TUint32 maxEntries = MaxEntries();
   1.545 +        const TUint32 MinIdx = KFatFirstSearchCluster;
   1.546 +        const TUint32 MaxIdx = maxEntries-1; 
   1.547 +
   1.548 +        TBool canGoRight = ETrue;
   1.549 +        TBool canGoLeft = ETrue;
   1.550 +    
   1.551 +        TUint32 rightIdx = aCluster;
   1.552 +        TUint32 leftIdx  = aCluster;
   1.553 +        
   1.554 +        for(TUint i=0; i<maxEntries; ++i)
   1.555 +            {
   1.556 +            if(canGoRight)
   1.557 +                {
   1.558 +                if(rightIdx < MaxIdx)
   1.559 +                    ++rightIdx;
   1.560 +                else
   1.561 +                    canGoRight = EFalse;
   1.562 +                }
   1.563 +
   1.564 +            if(canGoLeft)
   1.565 +                {
   1.566 +                if(leftIdx > MinIdx)
   1.567 +                    --leftIdx;
   1.568 +                else        
   1.569 +                    canGoLeft = EFalse;
   1.570 +                }
   1.571 +
   1.572 +        if(!canGoRight && !canGoLeft)
   1.573 +            {
   1.574 +            __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2"));
   1.575 +            User::Leave(KErrDiskFull);
   1.576 +            }
   1.577 +
   1.578 +        if (canGoRight && ReadL(rightIdx) == KSpareCluster)
   1.579 +            {
   1.580 +            aCluster = rightIdx;
   1.581 +            break;
   1.582 +            }
   1.583 +
   1.584 +        if (canGoLeft && ReadL(leftIdx) == KSpareCluster)
   1.585 +            {
   1.586 +            aCluster = leftIdx;
   1.587 +            break;
   1.588 +            }
   1.589 +            }//for(..)
   1.590 +
   1.591 +        }//if(ReadL(aCluster) != KSpareCluster)
   1.592 +
   1.593 +
   1.594 +    //-- note: do not update free cluster hint here by calling SetFreeClusterHint(). This is going to be 
   1.595 +    //-- expensive especially if overridden methods with synchronisation are called. Instead, set the number of 
   1.596 +    //-- the last known free cluster in the caller of this internal method.
   1.597 +
   1.598 +//    __PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster);
   1.599 +
   1.600 +    return aCluster;
   1.601 +    }
   1.602 +
   1.603 +//-----------------------------------------------------------------------------
   1.604 +
   1.605 +/**
   1.606 +    Converts a cluster number to byte offset in the FAT
   1.607 +
   1.608 +@param aFatIndex Cluster number
   1.609 +    @return Number of bytes from the beginning of the FAT
   1.610 +*/
   1.611 +TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const
   1.612 +    {
   1.613 +    switch(FatType())
   1.614 +        {
   1.615 +        case EFat12:
   1.616 +            return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry
   1.617 +
   1.618 +        case EFat16:
   1.619 +            return aFatIndex<<1; //-- 2 bytes per FAT entry
   1.620 +
   1.621 +        default:
   1.622 +            ASSERT(0);
   1.623 +            return 0;//-- get rid of warning
   1.624 +        };
   1.625 +
   1.626 +    }
   1.627 +
   1.628 +//-----------------------------------------------------------------------------
   1.629 +
   1.630 +/**
   1.631 +    Checks if we have at least aClustersRequired clusters free in the FAT.
   1.632 +    This is, actually a dummy implementation.
   1.633 +
   1.634 +    @param  aClustersRequired number of free clusters required
   1.635 +    @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
   1.636 +*/
   1.637 +TBool CFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
   1.638 +{
   1.639 +    //ASSERT(aClustersRequired >0 && aClustersRequired <= iOwner->UsableClusters());
   1.640 +    ASSERT(aClustersRequired >0);
   1.641 +    return (NumberOfFreeClusters() >= aClustersRequired);
   1.642 +}
   1.643 +
   1.644 +//-----------------------------------------------------------------------------
   1.645 +/**
   1.646 +    @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
   1.647 +*/
   1.648 +TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const 
   1.649 +    {
   1.650 +    return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries); 
   1.651 +    }
   1.652 +
   1.653 +
   1.654 +
   1.655 +//#######################################################################################################################################
   1.656 +//#     CAtaFatTable class implementation 
   1.657 +//#######################################################################################################################################
   1.658 +
   1.659 +/**
   1.660 +Constructor
   1.661 +*/
   1.662 +CAtaFatTable::CAtaFatTable(CFatMountCB& aOwner)
   1.663 +             :CFatTable(aOwner)
   1.664 +    {
   1.665 +    }
   1.666 +
   1.667 +
   1.668 +/** factory method */
   1.669 +CAtaFatTable* CAtaFatTable::NewL(CFatMountCB& aOwner)
   1.670 +{
   1.671 +    __PRINT1(_L("CAtaFatTable::NewL() drv:%d"),aOwner.DriveNumber());
   1.672 +    CAtaFatTable* pSelf = new (ELeave) CAtaFatTable(aOwner);
   1.673 +
   1.674 +    CleanupStack::PushL(pSelf);
   1.675 +    pSelf->InitializeL();
   1.676 +    CleanupStack::Pop();
   1.677 +
   1.678 +    return pSelf;
   1.679 +}
   1.680 +
   1.681 +
   1.682 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.683 +
   1.684 +/**
   1.685 +    CAtaFatTable's FAT cache factory method.
   1.686 +    Creates fixed cache for FAT12 or FAT16
   1.687 +*/
   1.688 +void CAtaFatTable::CreateCacheL()
   1.689 +{
   1.690 +    ASSERT(iOwner);
   1.691 +    const TUint32 fatSize=iOwner->FatSizeInBytes();
   1.692 +    __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize);
   1.693 +    
   1.694 +
   1.695 +    //-- according to FAT specs:
   1.696 +    //-- FAT12 max size is 4084 entries or 6126 bytes                                               => create fixed cache for whole FAT
   1.697 +    //-- FAT16 min size is 4085 entries or 8170 bytes, max size is 65525 entries or 131048 bytes    => create fixed cache for whole FAT
   1.698 +
   1.699 +    ASSERT(!iCache);
   1.700 +
   1.701 +    //-- this is used for chaches granularity sanity check 
   1.702 +    const TUint32 KMaxGranularityLog2 = 18; //-- 256K is a maximal allowed granularity
   1.703 +    const TUint32 KMinGranularityLog2 = KDefSectorSzLog2;  //-- 512 bytes is a minimal allowed granularity
   1.704 +
   1.705 +    switch(FatType())
   1.706 +    {
   1.707 +        case EFat12: //-- create fixed FAT12 cache
   1.708 +            iCache = CFat12Cache::NewL(iOwner, fatSize); 
   1.709 +        break;
   1.710 +    
   1.711 +        case EFat16: //-- create fixed FAT16 cache
   1.712 +        {
   1.713 +            TUint32 fat16_ReadGranularity_Log2; //-- FAT16 cache read granularity Log2
   1.714 +            TUint32 fat16_WriteGranularity_Log2;//-- FAT16 cache write granularity Log2
   1.715 +            
   1.716 +            iOwner->FatConfig().Fat16FixedCacheParams(fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2);
   1.717 +            
   1.718 +            //-- check if granularity values look sensible
   1.719 +            const TBool bParamsValid = fat16_ReadGranularity_Log2  >= KMinGranularityLog2 && fat16_ReadGranularity_Log2  <= KMaxGranularityLog2 &&
   1.720 +                                       fat16_WriteGranularity_Log2 >= KMinGranularityLog2 && fat16_WriteGranularity_Log2 <= KMaxGranularityLog2;
   1.721 +            
   1.722 +            __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity)); 
   1.723 +
   1.724 +        
   1.725 +            iCache = CFat16FixedCache::NewL(iOwner, fatSize, fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2); 
   1.726 +        }
   1.727 +        break;
   1.728 +
   1.729 +        default:
   1.730 +        ASSERT(0);
   1.731 +        User::Leave(KErrCorrupt);
   1.732 +        break;
   1.733 +    };
   1.734 +
   1.735 +    ASSERT(iCache);
   1.736 +}
   1.737 +
   1.738 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.739 +
   1.740 +
   1.741 +/**
   1.742 +    Flush the FAT cache on disk
   1.743 +@leave System wide error codes
   1.744 +*/
   1.745 +void CAtaFatTable::FlushL()
   1.746 +    {
   1.747 +    //-- the data can't be written if the mount is inconsistent
   1.748 +    iOwner->CheckStateConsistentL();
   1.749 +
   1.750 +    if (iCache)
   1.751 +        iCache->FlushL();
   1.752 +    }
   1.753 +
   1.754 +/**
   1.755 +Clear any cached data
   1.756 +    @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded.
   1.757 +*/
   1.758 +void CAtaFatTable::Dismount(TBool aDiscardDirtyData)
   1.759 +    {
   1.760 +    if (iCache)
   1.761 +        {
   1.762 +        //-- cache's Close() can check if the cache is clean. 
   1.763 +        //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data)
   1.764 +        //-- or if we are asked to do so.
   1.765 +        const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState();
   1.766 +        iCache->Close(bIgnoreDirtyData);
   1.767 +
   1.768 +        delete iCache;
   1.769 +        iCache=NULL;
   1.770 +        }
   1.771 +
   1.772 +    }
   1.773 +
   1.774 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.775 +
   1.776 +/**
   1.777 +    Invalidate whole FAT cache.
   1.778 +    Depending of cache type this may just mark cache invalid with reading on demand or re-read whole cache from the media
   1.779 +*/
   1.780 +void CAtaFatTable::InvalidateCacheL()
   1.781 +{
   1.782 +    __PRINT1(_L("CAtaFatTable::InvalidateCache(), drv:%d"), iOwner->DriveNumber());
   1.783 +
   1.784 +    //-- if we have a cache, invalidate it entirely
   1.785 +    if(iCache)
   1.786 +    {
   1.787 +        User::LeaveIfError(iCache->Invalidate());
   1.788 +    }
   1.789 +}
   1.790 +
   1.791 +
   1.792 +//---------------------------------------------------------------------------------------------------------------------------------------
   1.793 +
   1.794 +/**
   1.795 +    Invalidate specified region of the FAT cache
   1.796 +    Depending of cache type this may just mark part of the cache invalid with reading on demand later
   1.797 +    or re-read whole cache from the media.
   1.798 +
   1.799 +    @param aPos absolute media position where the region being invalidated starts.
   1.800 +    @param aLength length in bytes of region to invalidate / refresh
   1.801 +*/
   1.802 +void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength)
   1.803 +    {
   1.804 +    __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength);
   1.805 +
   1.806 +    if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength))
   1.807 +        return; //-- FAT tables can't span over 4G 
   1.808 +
   1.809 +    const TUint32 mediaPos32 = I64LOW(aPos);
   1.810 +
   1.811 +    //-- we do not use other copies of FAT, so trach changes only in FAT1
   1.812 +    const TUint32 fat1StartPos = iOwner->StartOfFatInBytes();
   1.813 +    const TUint32 fat1EndPos   = fat1StartPos + iOwner->FatSizeInBytes();
   1.814 +
   1.815 +    TUint32 invRegionPosStart = 0; //-- media pos where the invalidated region starts
   1.816 +    TUint32 invRegionLen = 0;      //-- size of the invalidated region, bytes
   1.817 +    
   1.818 +    //-- calculate the FAT1 region being invalidated
   1.819 +    if(mediaPos32 < fat1StartPos)
   1.820 +    {
   1.821 +        if((mediaPos32 + aLength) <= fat1StartPos)
   1.822 +            return;
   1.823 +
   1.824 +        invRegionPosStart = fat1StartPos;
   1.825 +        invRegionLen = aLength - (fat1StartPos-mediaPos32);
   1.826 +    }
   1.827 +    else //if(mediaPos32 < fat1StartPos)
   1.828 +    {//-- mediaPos32 >= fat1StartPos)
   1.829 +        if(mediaPos32 >= fat1EndPos)
   1.830 +            return;
   1.831 +    
   1.832 +        invRegionPosStart = mediaPos32;
   1.833 +        
   1.834 +        if((mediaPos32 + aLength) <= fat1EndPos)
   1.835 +        {
   1.836 +            invRegionLen = aLength;
   1.837 +        }
   1.838 +        else 
   1.839 +        {
   1.840 +            invRegionLen = mediaPos32+aLength-fat1EndPos;
   1.841 +        }
   1.842 +    }
   1.843 +
   1.844 +    //-- convert the media pos of the region into FAT entries basis, depending on the FAT type
   1.845 +    ASSERT(invRegionPosStart >= fat1StartPos && invRegionLen <= (TUint)iOwner->FatSizeInBytes());
   1.846 +    
   1.847 +    TUint32 startFatEntry=0;
   1.848 +    TUint32 numEntries = 0;
   1.849 +
   1.850 +    switch(FatType())
   1.851 +    {
   1.852 +        case EFat12:
   1.853 +        //-- invalidate whole cache; it is not worth making calculations for such small memory region.
   1.854 +        User::LeaveIfError(iCache->Invalidate());
   1.855 +        return;
   1.856 +
   1.857 +        case EFat16:
   1.858 +        startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat16EntrySzLog2;
   1.859 +        numEntries = (invRegionLen + (sizeof(TFat16Entry)-1)) >> KFat16EntrySzLog2;
   1.860 +        break;
   1.861 +
   1.862 +        default:
   1.863 +        ASSERT(0);
   1.864 +        return;
   1.865 +    };
   1.866 +
   1.867 +    if(startFatEntry < KFatFirstSearchCluster)
   1.868 +    {//-- FAT[0] and FAT[1] can't be legally accessed, they are reserved entries. We need to adjust region being refreshed.
   1.869 +        if(numEntries <= KFatFirstSearchCluster)
   1.870 +            return; //-- nothing to refresh
   1.871 +                    
   1.872 +        startFatEntry += KFatFirstSearchCluster;
   1.873 +        numEntries -= KFatFirstSearchCluster;
   1.874 +    }
   1.875 +
   1.876 +    User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries));
   1.877 +    }
   1.878 +
   1.879 +
   1.880 +//-----------------------------------------------------------------------------
   1.881 +/**
   1.882 +    Initialize the object, create FAT cache if required
   1.883 +@leave KErrNoMemory
   1.884 +*/
   1.885 +void CAtaFatTable::InitializeL()
   1.886 +    {
   1.887 +    __PRINT1(_L("CAtaFatTable::InitializeL() drv:%d"), iOwner->DriveNumber());
   1.888 +    CFatTable::InitializeL();
   1.889 +
   1.890 +    //-- create the FAT cache.
   1.891 +    ASSERT(!iCache);
   1.892 +    CreateCacheL();
   1.893 +    }
   1.894 +
   1.895 +
   1.896 +//-----------------------------------------------------------------------------
   1.897 +/**
   1.898 +    Remount the FAT table. This method call means that the media parameters wasn't changed, 
   1.899 +    otherwise CFatMountCB::DoReMountL() would reject it. 
   1.900 +    Just do some re-initialisation work.
   1.901 +*/
   1.902 +void CAtaFatTable::ReMountL()
   1.903 +{
   1.904 +    __PRINT1(_L("CAtaFatTable::ReMountL() drv:%d"), iOwner->DriveNumber());
   1.905 +
   1.906 +    if(iCache)
   1.907 +        {
   1.908 +        iCache->Invalidate();
   1.909 +        }
   1.910 +    else
   1.911 +        {
   1.912 +        //-- this situation can happen when someone called CAtaFatTable::Dismount() that deletes the cache object
   1.913 +        //-- and then ReMount happens. We need to re-initialise this object.
   1.914 +        InitializeL();
   1.915 +        }
   1.916 +}
   1.917 +
   1.918 +
   1.919 +//-----------------------------------------------------------------------------
   1.920 +/**
   1.921 +    Read an entry from the FAT table
   1.922 +
   1.923 +    @param aFatIndex FAT entry number to read
   1.924 +    @return FAT entry value
   1.925 +*/
   1.926 +TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const
   1.927 +    {
   1.928 +    if(!ClusterNumberValid(aFatIndex))
   1.929 +        {
   1.930 +        //ASSERT(0); //-- for some silly reason some callers pass 0 here and expect it to leave
   1.931 +        User::Leave(KErrCorrupt);
   1.932 +        }
   1.933 +
   1.934 +
   1.935 +    const TUint entry = iCache->ReadEntryL(aFatIndex);
   1.936 +    return entry;
   1.937 +    }
   1.938 +
   1.939 +
   1.940 +//-----------------------------------------------------------------------------
   1.941 +/**
   1.942 +    Write an entry to the FAT table
   1.943 +
   1.944 +    @param aFatIndex    aFatIndex FAT entry number to write
   1.945 +    @param aValue       FAT entry to write
   1.946 +@leave
   1.947 +*/
   1.948 +void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
   1.949 +    {
   1.950 +    const TUint32 KFat16EntryMask = 0x0FFFF;
   1.951 +    
   1.952 +    __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue);
   1.953 +    
   1.954 +    if(!ClusterNumberValid(aFatIndex))
   1.955 +        {
   1.956 +        ASSERT(0); 
   1.957 +        User::Leave(KErrCorrupt);
   1.958 +        }
   1.959 +    
   1.960 +    if(aValue != KSpareCluster && (aValue < KFatFirstSearchCluster || aValue > KFat16EntryMask))
   1.961 +        {
   1.962 +        ASSERT(0);
   1.963 +        User::Leave(KErrCorrupt);
   1.964 +        }
   1.965 +    iCache->WriteEntryL(aFatIndex, aValue);
   1.966 +    }
   1.967 +
   1.968 +
   1.969 +/**
   1.970 +Get the next cluster in the chain from the FAT
   1.971 +
   1.972 +@param aCluster number to read, contains next cluster upon return
   1.973 +@leave
   1.974 +@return False if end of cluster chain
   1.975 +*/
   1.976 +TBool CFatTable::GetNextClusterL(TInt& aCluster) const
   1.977 +    {
   1.978 +    __PRINT1(_L("CAtaFatTable::GetNextClusterL(%d)"), aCluster);
   1.979 +    
   1.980 +    const TInt nextCluster = ReadL(aCluster);
   1.981 +    TBool ret = EFalse; 
   1.982 +
   1.983 +    switch(FatType())
   1.984 +        {
   1.985 +        case EFat12:
   1.986 +            ret=!IsEof12Bit(nextCluster);
   1.987 +        break;
   1.988 +
   1.989 +        case EFat16:
   1.990 +            ret=!IsEof16Bit(nextCluster);
   1.991 +        break;
   1.992 +
   1.993 +        default:
   1.994 +            ASSERT(0);
   1.995 +            return EFalse;//-- get rid of warning
   1.996 +        };
   1.997 +    
   1.998 +    if (ret)
   1.999 +        {
  1.1000 +        aCluster=nextCluster;
  1.1001 +        }
  1.1002 +    
  1.1003 +    return ret;
  1.1004 +
  1.1005 +    }
  1.1006 +
  1.1007 +/**
  1.1008 +Write EOF to aFatIndex
  1.1009 +    @param aFatIndex index in FAT (cluster number) to be written
  1.1010 +*/
  1.1011 +void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex)
  1.1012 +    {
  1.1013 +    __PRINT1(_L("CAtaFatTable::WriteFatEntryEofL(%d)"), aFatIndex);
  1.1014 +
  1.1015 +    //-- use EOF_16Bit (0x0ffff) for all types of FAT, FAT cache will mask it appropriately
  1.1016 +    WriteL(aFatIndex, EOF_16Bit);
  1.1017 +    }
  1.1018 +
  1.1019 +
  1.1020 +
  1.1021 +/** 
  1.1022 +    Mark cluster number aFatIndex in FAT as bad 
  1.1023 +    @param aFatIndex index in FAT (cluster number) to be written
  1.1024 +*/
  1.1025 +void CFatTable::MarkAsBadClusterL(TUint32 aFatIndex)
  1.1026 +    {
  1.1027 +    __PRINT1(_L("CAtaFatTable::MarkAsBadClusterL(%d)"),aFatIndex);
  1.1028 +
  1.1029 +    //-- use KBad_16Bit (0x0fff7) for all types of FAT, FAT cache will mask it appropriately
  1.1030 +    WriteL(aFatIndex, KBad_16Bit);
  1.1031 +    
  1.1032 +    FlushL();
  1.1033 +    }
  1.1034 +
  1.1035 +
  1.1036 +/**
  1.1037 +Return the location of a Cluster in the data section of the media
  1.1038 +
  1.1039 +@param aCluster to find location of
  1.1040 +@return Byte offset of the cluster data 
  1.1041 +*/
  1.1042 +TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const
  1.1043 +    {
  1.1044 +    __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex));
  1.1045 +
  1.1046 +    const TInt clusterBasePosition=iOwner->ClusterBasePosition();
  1.1047 +    return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition);
  1.1048 +    }
  1.1049 +
  1.1050 +
  1.1051 +
  1.1052 +
  1.1053 +
  1.1054 +