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