Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfat\fat_table.cpp
15 // FAT12/16 File Allocation Table classes implementation
24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
25 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
29 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
30 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
34 #include "sl_fatcache.h"
35 #include "fat_table.h"
38 //#######################################################################################################################################
39 //# CFatTable class implementation
40 //#######################################################################################################################################
43 FAT object factory method.
44 Constructs either CAtaFatTable or CRamFatTable depending on the media type parameter
46 @param aOwner Pointer to the owning mount
47 @param aLocDrvCaps local drive attributes
49 @return Pointer to the Fat table
51 CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps)
53 CFatTable* pFatTable=NULL;
56 switch(aLocDrvCaps.iType)
59 {//-- this is RAM media, try to create CRamFatTable instance.
60 const TFatType fatType = aOwner.FatType();
62 if(fatType != EFat16 )
63 {//-- CRamFatTable doesn't support FAT12; FAT16 only.
64 __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType);
69 pFatTable = CRamFatTable::NewL(aOwner);
75 pFatTable = CAtaFatTable::NewL(aOwner);
82 CFatTable::CFatTable(CFatMountCB& aOwner)
88 CFatTable::~CFatTable()
90 //-- destroy cache ignoring dirty data in cache
91 //-- the destructor isn't an appropriate place to flush the data.
95 //-----------------------------------------------------------------------------
98 Initialise the object, get data from the owning CFatMountCB
100 void CFatTable::InitializeL()
104 //-- get FAT type from the owner
105 iFatType = iOwner->FatType();
106 ASSERT(IsFat12() || IsFat16());
108 iFreeClusterHint = KFatFirstSearchCluster;
110 //-- cache the media attributes
111 TLocalDriveCapsV2 caps;
112 TPckg<TLocalDriveCapsV2> capsPckg(caps);
113 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
114 iMediaAtt = caps.iMediaAtt;
116 //-- obtain maximal number of entries in the table
117 iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use
119 __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries);
122 //-----------------------------------------------------------------------------
125 Decrements the free cluster count.
126 Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every
127 cluster of a large file. Use more than one cluster granularity.
129 @param aCount a number of clusters
131 void CFatTable::DecrementFreeClusterCount(TUint32 aCount)
133 __ASSERT_DEBUG(iFreeClusters >= aCount, Fault(EFatCorrupt));
134 iFreeClusters -= aCount;
138 Increments the free cluster count.
139 Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every
140 cluster of a large file. Use more than one cluster granularity.
142 @param aCount a number of clusters
144 void CFatTable::IncrementFreeClusterCount(TUint32 aCount)
146 const TUint32 newVal = iFreeClusters+aCount;
147 __ASSERT_DEBUG(newVal<=MaxEntries(), Fault(EFatCorrupt));
149 iFreeClusters = newVal;
152 /** @return number of free clusters in the FAT */
153 TUint32 CFatTable::NumberOfFreeClusters(TBool /*aSyncOperation=EFalse*/) const
155 return FreeClusters();
158 void CFatTable::SetFreeClusters(TUint32 aFreeClusters)
160 iFreeClusters=aFreeClusters;
164 Get the hint about the last known free cluster number.
165 Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every
166 cluster of a large file.
168 @return cluster number supposedly close to the free one.
170 TUint32 CFatTable::FreeClusterHint() const
172 ASSERT(ClusterNumberValid(iFreeClusterHint));
173 return iFreeClusterHint;
177 Set a free cluster hint. The next search fro the free cluster can start from this value.
178 aCluster doesn't have to be a precise number of free FAT entry; it just needs to be as close as possible to the
180 Note that can be quite expensive operation (especially for overrides with synchronisation), if it is called for every
181 cluster of a large file.
183 @param aCluster cluster number hint.
185 void CFatTable::SetFreeClusterHint(TUint32 aCluster)
187 ASSERT(ClusterNumberValid(aCluster));
188 iFreeClusterHint=aCluster;
191 //-----------------------------------------------------------------------------
194 Find out the number of free clusters on the volume.
195 Reads whole FAT and counts free clusters.
197 void CFatTable::CountFreeClustersL()
199 __PRINT1(_L("#- CFatTable::CountFreeClustersL(), drv:%d"), iOwner->DriveNumber());
201 const TUint32 KUsableClusters = iOwner->UsableClusters();
202 (void)KUsableClusters;
204 TUint32 freeClusters = 0;
205 TUint32 firstFreeCluster = 0;
209 timeStart.UniversalTime(); //-- take start time
211 //-- walk through whole FAT table looking for free clusters
212 for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i)
214 if(ReadL(i) == KSpareCluster)
215 {//-- found a free cluster
218 if(!firstFreeCluster)
219 firstFreeCluster = i;
223 timeEnd.UniversalTime(); //-- take end time
224 const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
225 __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime);
228 if(!firstFreeCluster) //-- haven't found free clusters on the volume
229 firstFreeCluster = KFatFirstSearchCluster;
231 ASSERT(freeClusters <= KUsableClusters);
233 SetFreeClusters(freeClusters);
234 SetFreeClusterHint(firstFreeCluster);
237 //-----------------------------------------------------------------------------
240 Count the number of contiguous cluster from a start cluster
242 @param aStartCluster cluster to start counting from
243 @param anEndCluster contains the end cluster number upon return
244 @param aMaxCount Maximum cluster required
245 @leave System wide error values
246 @return Number of contiguous clusters from aStartCluster.
248 TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const
250 __PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount);
251 TUint32 clusterListLen=1;
252 TInt endCluster=aStartCluster;
253 TInt64 endClusterPos=DataPositionInBytes(endCluster);
254 while (clusterListLen<aMaxCount)
256 TInt oldCluster=endCluster;
257 TInt64 oldClusterPos=endClusterPos;
258 if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
260 endCluster=oldCluster;
265 anEndCluster=endCluster;
266 return(clusterListLen);
269 //-----------------------------------------------------------------------------
272 Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full).
274 @param aNumber amount of clusters to allocate
275 @param aCluster FAT entry index to start with.
277 @leave KErrDiskFull + system wide error codes
279 void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
281 __PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster);
282 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
284 while(aNumber && GetNextClusterL(aCluster))
290 if (iFreeClusters<aNumber)
292 __PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull"));
293 User::Leave(KErrDiskFull);
297 TUint32 freeCluster = 0;
299 //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL()
300 for(TUint i=0; i<aNumber; ++i)
302 freeCluster = FindClosestFreeClusterL(aCluster);
303 WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again
304 WriteL(aCluster,freeCluster);
305 aCluster=freeCluster;
308 //-- decrement number of available clusters
309 DecrementFreeClusterCount(aNumber);
311 //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from
312 SetFreeClusterHint(aCluster);
316 //-----------------------------------------------------------------------------
319 Allocate and mark as EOF a single cluster as close as possible to aNearestCluster
321 @param aNearestCluster Cluster the new cluster should be nearest to
322 @leave System wide error codes
323 @return The cluster number allocated
325 TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
327 __PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster);
328 if (iFreeClusters==0)
329 User::Leave(KErrDiskFull);
330 const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster);
331 WriteFatEntryEofL(freeCluster);
332 DecrementFreeClusterCount(1);
334 //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from.
335 SetFreeClusterHint(freeCluster);
340 //-----------------------------------------------------------------------------
343 Allocate and link a cluster chain, leaves if there are not enough free clusters.
344 Chain starts as close as possible to aNearestCluster, last cluster will be marked as EOF.
346 @param aNumber Number of clusters to allocate
347 @param aNearestCluster Cluster the new chain should be nearest to
348 @leave System wide error codes
349 @return The first cluster number allocated
351 TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster)
353 __PRINT2(_L("#>> CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster);
354 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
356 if (iFreeClusters<aNumber)
358 __PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull"));
359 User::Leave(KErrDiskFull);
362 TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster);
364 ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster);
366 return(firstCluster);
369 //-----------------------------------------------------------------------------
372 Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported.
373 @param aFreedClusters array with FAT numbers of clusters that shall be marked as "deleted"
375 void CFatTable::DoFreedClustersNotify(RClusterArray &aFreedClusters)
377 ASSERT(iMediaAtt & KMediaAttDeleteNotify);
379 const TUint clusterCount = aFreedClusters.Count();
384 FlushL(); //-- Commit the FAT changes to disk first to be safe
386 const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2();
388 TInt64 byteAddress = 0;
389 TUint deleteLen = 0; // zero indicates no clusters accumulated yet
391 for (TUint i=0; i<clusterCount; ++i)
393 const TUint currCluster = aFreedClusters[i];
396 byteAddress = DataPositionInBytes(currCluster); //-- start of the media range
398 deleteLen += bytesPerCluster;
400 //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver
401 if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1))
403 //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen);
404 //__PRINT2(_L(" first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster);
405 const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen);
407 {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media;
408 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media.
409 const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement);
410 __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
414 //-- if PlatSec is enabled, we can't afford jeopardize the security; without DeleteNotify()
415 //-- it's possible to pick up data from deleted files, so, panic the file server.
416 Fault(EFatBadLocalDrive);
420 //-- if PlatSec is disabled, it's OK to ignore the NAND fault in release mode.
421 __ASSERT_DEBUG(0, Fault(EFatBadLocalDrive));
431 //-- empty the array.
432 aFreedClusters.Reset();
435 //-----------------------------------------------------------------------------
437 Mark a chain of clusters as free in the FAT.
439 @param aCluster Start cluster of cluster chain to free
440 @leave System wide error codes
442 void CFatTable::FreeClusterListL(TUint32 aCluster)
444 __PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster);
445 if (aCluster == KSpareCluster)
448 //-- here we can store array of freed cluster numbers in order to
449 //-- notify media drive about the media addresses marked as "invalid"
450 RClusterArray deletedClusters;
451 CleanupClosePushL(deletedClusters);
453 //-- if ETrue, we need to notify media driver about invalidated media addressses
454 const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify;
456 //-- this is a maximal number of FAT entries in the deletedClusters array.
457 //-- as soon as we collect this number of entries in the array, FAT cache will be flushed
458 //-- and driver notified. The array will be emptied. Used to avoid huge array when deleting
459 //-- large files on NAND media
460 const TUint KSubListLen = 4096;
461 ASSERT(IsPowerOf2(KSubListLen));
463 TUint32 lastKnownFreeCluster = FreeClusterHint();
464 TUint32 cntFreedClusters = 0;
466 TUint32 currCluster = aCluster;
467 TInt nextCluster = aCluster;
471 const TBool bEOF = !GetNextClusterL(nextCluster);
472 WriteL(currCluster, KSpareCluster);
474 lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster);
476 // Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe
477 // to do once the FAT changes have been written to disk.
478 if(bFreeClustersNotify)
479 deletedClusters.Append(currCluster);
482 currCluster = nextCluster;
484 if (bEOF || aCluster == KSpareCluster)
487 if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0)
488 {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array.
489 IncrementFreeClusterCount(cntFreedClusters);
490 cntFreedClusters = 0;
492 SetFreeClusterHint(lastKnownFreeCluster);
493 DoFreedClustersNotify(deletedClusters);
498 //-- increase the number of free clusters and notify the driver if required.
499 IncrementFreeClusterCount(cntFreedClusters);
500 SetFreeClusterHint(lastKnownFreeCluster);
502 if(bFreeClustersNotify)
503 DoFreedClustersNotify(deletedClusters);
505 CleanupStack::PopAndDestroy(&deletedClusters);
508 //-----------------------------------------------------------------------------
511 Find a free cluster nearest to aCluster, Always checks to the right of aCluster first
512 but checks in both directions in the Fat.
514 @param aCluster Cluster to find nearest free cluster to.
515 @leave KErrDiskFull + system wide error codes
516 @return cluster number found
518 TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster)
520 __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster);
522 if(!ClusterNumberValid(aCluster))
525 User::Leave(KErrCorrupt);
530 {//-- there is no at least 1 free cluster available
531 __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1"));
532 User::Leave(KErrDiskFull);
535 //-- 1. look if the given index contains a free entry
536 if(ReadL(aCluster) != KSpareCluster)
537 {//-- no, it doesn't...
539 //-- 2. look in both directions starting from the aCluster, looking in the right direction first
541 const TUint32 maxEntries = MaxEntries();
542 const TUint32 MinIdx = KFatFirstSearchCluster;
543 const TUint32 MaxIdx = maxEntries-1;
545 TBool canGoRight = ETrue;
546 TBool canGoLeft = ETrue;
548 TUint32 rightIdx = aCluster;
549 TUint32 leftIdx = aCluster;
551 for(TUint i=0; i<maxEntries; ++i)
555 if(rightIdx < MaxIdx)
569 if(!canGoRight && !canGoLeft)
571 __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2"));
572 User::Leave(KErrDiskFull);
575 if (canGoRight && ReadL(rightIdx) == KSpareCluster)
581 if (canGoLeft && ReadL(leftIdx) == KSpareCluster)
588 }//if(ReadL(aCluster) != KSpareCluster)
591 //-- note: do not update free cluster hint here by calling SetFreeClusterHint(). This is going to be
592 //-- expensive especially if overridden methods with synchronisation are called. Instead, set the number of
593 //-- the last known free cluster in the caller of this internal method.
595 // __PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster);
600 //-----------------------------------------------------------------------------
603 Converts a cluster number to byte offset in the FAT
605 @param aFatIndex Cluster number
606 @return Number of bytes from the beginning of the FAT
608 TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const
613 return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry
616 return aFatIndex<<1; //-- 2 bytes per FAT entry
620 return 0;//-- get rid of warning
625 //-----------------------------------------------------------------------------
628 Checks if we have at least aClustersRequired clusters free in the FAT.
629 This is, actually a dummy implementation.
631 @param aClustersRequired number of free clusters required
632 @return ETrue if there is at least aClustersRequired free clusters available, EFalse otherwise.
634 TBool CFatTable::RequestFreeClusters(TUint32 aClustersRequired) const
636 //ASSERT(aClustersRequired >0 && aClustersRequired <= iOwner->UsableClusters());
637 ASSERT(aClustersRequired >0);
638 return (NumberOfFreeClusters() >= aClustersRequired);
641 //-----------------------------------------------------------------------------
643 @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
645 TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const
647 return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries);
652 //#######################################################################################################################################
653 //# CAtaFatTable class implementation
654 //#######################################################################################################################################
659 CAtaFatTable::CAtaFatTable(CFatMountCB& aOwner)
665 /** factory method */
666 CAtaFatTable* CAtaFatTable::NewL(CFatMountCB& aOwner)
668 __PRINT1(_L("CAtaFatTable::NewL() drv:%d"),aOwner.DriveNumber());
669 CAtaFatTable* pSelf = new (ELeave) CAtaFatTable(aOwner);
671 CleanupStack::PushL(pSelf);
672 pSelf->InitializeL();
679 //---------------------------------------------------------------------------------------------------------------------------------------
682 CAtaFatTable's FAT cache factory method.
683 Creates fixed cache for FAT12 or FAT16
685 void CAtaFatTable::CreateCacheL()
688 const TUint32 fatSize=iOwner->FatSizeInBytes();
689 __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize);
692 //-- according to FAT specs:
693 //-- FAT12 max size is 4084 entries or 6126 bytes => create fixed cache for whole FAT
694 //-- FAT16 min size is 4085 entries or 8170 bytes, max size is 65525 entries or 131048 bytes => create fixed cache for whole FAT
698 //-- this is used for chaches granularity sanity check
699 const TUint32 KMaxGranularityLog2 = 18; //-- 256K is a maximal allowed granularity
700 const TUint32 KMinGranularityLog2 = KDefSectorSzLog2; //-- 512 bytes is a minimal allowed granularity
704 case EFat12: //-- create fixed FAT12 cache
705 iCache = CFat12Cache::NewL(iOwner, fatSize);
708 case EFat16: //-- create fixed FAT16 cache
710 TUint32 fat16_ReadGranularity_Log2; //-- FAT16 cache read granularity Log2
711 TUint32 fat16_WriteGranularity_Log2;//-- FAT16 cache write granularity Log2
713 iOwner->FatConfig().Fat16FixedCacheParams(fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2);
715 //-- check if granularity values look sensible
716 const TBool bParamsValid = fat16_ReadGranularity_Log2 >= KMinGranularityLog2 && fat16_ReadGranularity_Log2 <= KMaxGranularityLog2 &&
717 fat16_WriteGranularity_Log2 >= KMinGranularityLog2 && fat16_WriteGranularity_Log2 <= KMaxGranularityLog2;
719 __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity));
722 iCache = CFat16FixedCache::NewL(iOwner, fatSize, fat16_ReadGranularity_Log2, fat16_WriteGranularity_Log2);
728 User::Leave(KErrCorrupt);
735 //---------------------------------------------------------------------------------------------------------------------------------------
739 Flush the FAT cache on disk
740 @leave System wide error codes
742 void CAtaFatTable::FlushL()
744 //-- the data can't be written if the mount is inconsistent
745 iOwner->CheckStateConsistentL();
752 Clear any cached data
753 @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded.
755 void CAtaFatTable::Dismount(TBool aDiscardDirtyData)
759 //-- cache's Close() can check if the cache is clean.
760 //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data)
761 //-- or if we are asked to do so.
762 const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState();
763 iCache->Close(bIgnoreDirtyData);
771 //---------------------------------------------------------------------------------------------------------------------------------------
774 Invalidate whole FAT cache.
775 Depending of cache type this may just mark cache invalid with reading on demand or re-read whole cache from the media
777 void CAtaFatTable::InvalidateCacheL()
779 __PRINT1(_L("CAtaFatTable::InvalidateCache(), drv:%d"), iOwner->DriveNumber());
781 //-- if we have a cache, invalidate it entirely
784 User::LeaveIfError(iCache->Invalidate());
789 //---------------------------------------------------------------------------------------------------------------------------------------
792 Invalidate specified region of the FAT cache
793 Depending of cache type this may just mark part of the cache invalid with reading on demand later
794 or re-read whole cache from the media.
796 @param aPos absolute media position where the region being invalidated starts.
797 @param aLength length in bytes of region to invalidate / refresh
799 void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength)
801 __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength);
803 if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength))
804 return; //-- FAT tables can't span over 4G
806 const TUint32 mediaPos32 = I64LOW(aPos);
808 //-- we do not use other copies of FAT, so trach changes only in FAT1
809 const TUint32 fat1StartPos = iOwner->StartOfFatInBytes();
810 const TUint32 fat1EndPos = fat1StartPos + iOwner->FatSizeInBytes();
812 TUint32 invRegionPosStart = 0; //-- media pos where the invalidated region starts
813 TUint32 invRegionLen = 0; //-- size of the invalidated region, bytes
815 //-- calculate the FAT1 region being invalidated
816 if(mediaPos32 < fat1StartPos)
818 if((mediaPos32 + aLength) <= fat1StartPos)
821 invRegionPosStart = fat1StartPos;
822 invRegionLen = aLength - (fat1StartPos-mediaPos32);
824 else //if(mediaPos32 < fat1StartPos)
825 {//-- mediaPos32 >= fat1StartPos)
826 if(mediaPos32 >= fat1EndPos)
829 invRegionPosStart = mediaPos32;
831 if((mediaPos32 + aLength) <= fat1EndPos)
833 invRegionLen = aLength;
837 invRegionLen = mediaPos32+aLength-fat1EndPos;
841 //-- convert the media pos of the region into FAT entries basis, depending on the FAT type
842 ASSERT(invRegionPosStart >= fat1StartPos && invRegionLen <= (TUint)iOwner->FatSizeInBytes());
844 TUint32 startFatEntry=0;
845 TUint32 numEntries = 0;
850 //-- invalidate whole cache; it is not worth making calculations for such small memory region.
851 User::LeaveIfError(iCache->Invalidate());
855 startFatEntry = (invRegionPosStart-fat1StartPos) >> KFat16EntrySzLog2;
856 numEntries = (invRegionLen + (sizeof(TFat16Entry)-1)) >> KFat16EntrySzLog2;
864 if(startFatEntry < KFatFirstSearchCluster)
865 {//-- FAT[0] and FAT[1] can't be legally accessed, they are reserved entries. We need to adjust region being refreshed.
866 if(numEntries <= KFatFirstSearchCluster)
867 return; //-- nothing to refresh
869 startFatEntry += KFatFirstSearchCluster;
870 numEntries -= KFatFirstSearchCluster;
873 User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries));
877 //-----------------------------------------------------------------------------
879 Initialize the object, create FAT cache if required
882 void CAtaFatTable::InitializeL()
884 __PRINT1(_L("CAtaFatTable::InitializeL() drv:%d"), iOwner->DriveNumber());
885 CFatTable::InitializeL();
887 //-- create the FAT cache.
893 //-----------------------------------------------------------------------------
895 Remount the FAT table. This method call means that the media parameters wasn't changed,
896 otherwise CFatMountCB::DoReMountL() would reject it.
897 Just do some re-initialisation work.
899 void CAtaFatTable::ReMountL()
901 __PRINT1(_L("CAtaFatTable::ReMountL() drv:%d"), iOwner->DriveNumber());
905 iCache->Invalidate();
909 //-- this situation can happen when someone called CAtaFatTable::Dismount() that deletes the cache object
910 //-- and then ReMount happens. We need to re-initialise this object.
916 //-----------------------------------------------------------------------------
918 Read an entry from the FAT table
920 @param aFatIndex FAT entry number to read
921 @return FAT entry value
923 TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const
925 if(!ClusterNumberValid(aFatIndex))
927 //ASSERT(0); //-- for some silly reason some callers pass 0 here and expect it to leave
928 User::Leave(KErrCorrupt);
932 const TUint entry = iCache->ReadEntryL(aFatIndex);
937 //-----------------------------------------------------------------------------
939 Write an entry to the FAT table
941 @param aFatIndex aFatIndex FAT entry number to write
942 @param aValue FAT entry to write
945 void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
947 const TUint32 KFat16EntryMask = 0x0FFFF;
949 __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue);
951 if(!ClusterNumberValid(aFatIndex))
954 User::Leave(KErrCorrupt);
957 if(aValue != KSpareCluster && (aValue < KFatFirstSearchCluster || aValue > KFat16EntryMask))
960 User::Leave(KErrCorrupt);
962 iCache->WriteEntryL(aFatIndex, aValue);
967 Get the next cluster in the chain from the FAT
969 @param aCluster number to read, contains next cluster upon return
971 @return False if end of cluster chain
973 TBool CFatTable::GetNextClusterL(TInt& aCluster) const
975 __PRINT1(_L("CAtaFatTable::GetNextClusterL(%d)"), aCluster);
977 const TInt nextCluster = ReadL(aCluster);
983 ret=!IsEof12Bit(nextCluster);
987 ret=!IsEof16Bit(nextCluster);
992 return EFalse;//-- get rid of warning
997 aCluster=nextCluster;
1005 Write EOF to aFatIndex
1006 @param aFatIndex index in FAT (cluster number) to be written
1008 void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex)
1010 __PRINT1(_L("CAtaFatTable::WriteFatEntryEofL(%d)"), aFatIndex);
1012 //-- use EOF_16Bit (0x0ffff) for all types of FAT, FAT cache will mask it appropriately
1013 WriteL(aFatIndex, EOF_16Bit);
1019 Mark cluster number aFatIndex in FAT as bad
1020 @param aFatIndex index in FAT (cluster number) to be written
1022 void CFatTable::MarkAsBadClusterL(TUint32 aFatIndex)
1024 __PRINT1(_L("CAtaFatTable::MarkAsBadClusterL(%d)"),aFatIndex);
1026 //-- use KBad_16Bit (0x0fff7) for all types of FAT, FAT cache will mask it appropriately
1027 WriteL(aFatIndex, KBad_16Bit);
1034 Return the location of a Cluster in the data section of the media
1036 @param aCluster to find location of
1037 @return Byte offset of the cluster data
1039 TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const
1041 __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex));
1043 const TInt clusterBasePosition=iOwner->ClusterBasePosition();
1044 return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition);