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\sfat32\ram_fat_table32.cpp
15 // FAT16/32 File Allocation Table classes implementation for the RAM media
27 #include "sl_fatcache32.h"
28 #include "fat_table32.h"
31 //---------------------------------------------------------------------------------------------------------------------------------------
33 //#######################################################################################################################################
34 //# CRamFatTable class implementation
35 //#######################################################################################################################################
38 Constructor, the RamFatTable allows disk compression by redirecting the FAT
40 @param aOwner Owning mount.
42 CRamFatTable::CRamFatTable(CFatMountCB& aOwner)
45 iFatTablePos=aOwner.FirstFatSector()<<aOwner.SectorSizeLog2();
46 iIndirectionTablePos=iFatTablePos+aOwner.FatSizeInBytes();
50 CRamFatTable* CRamFatTable::NewL(CFatMountCB& aOwner)
52 __PRINT1(_L("CRamFatTable::NewL() drv:%d"),aOwner.DriveNumber());
54 CRamFatTable* pSelf = new (ELeave) CRamFatTable(aOwner);
56 CleanupStack::PushL(pSelf);
64 void CRamFatTable::InitializeL()
66 CFatTable::InitializeL();
68 ASSERT(iMediaAtt & KMediaAttVariableSize);
69 ASSERT(FatType() == EFat16 || FatType()== EFat32);
71 iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
72 iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
74 //-- set RAM disk base
75 TLocalDriveCapsV2 caps;
76 TPckg<TLocalDriveCapsV2> capsPckg(caps);
77 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
79 iRamDiskBase = caps.iBaseAddress;
83 Just Count free clusters in the FAT
85 void CRamFatTable::MountL(const TMountParams& /*aMountParam*/)
92 Return the start address of the Ram Drive
93 @return start address of the Ram Drive
95 TUint8 *CRamFatTable::RamDiskBase() const
102 Allocate a new cluster number
104 @return New cluster number
106 TInt CRamFatTable::AllocateClusterNumber()
108 return(iOwner->MaxClusterNumber()-NumberOfFreeClusters());
112 Write a value to the FAT (indirection table)
114 @param aFatIndex Cluster to write to
115 @param aValue value to write to Fat
117 void CRamFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
119 //__PRINT(_L("CRamFatTable::WriteL"));
121 // __ASSERT_ALWAYS(aFatIndex>=2 && (aValue>=2 || aValue==0) && aValue<=0xFFFF,User::Leave(KErrCorrupt));
122 TUint32 indirectCluster=aFatIndex;
123 TUint32 indirectClusterNewVal=0;
124 ReadIndirectionTable(indirectCluster);
125 // If value in indirection table!=0 we assume we have already written to the indirection table
126 // So just update the FAT table
127 if (indirectCluster!=0 && aValue!=0)
129 WriteFatTable(aFatIndex,aValue);
132 // If value in indirection table is 0, we haven't written to it yet, though the memory has
133 // already been allocated by the EnlargeL() function
134 if (indirectCluster==0 && aValue!=0) // Assumes memory has already been allocated
135 indirectClusterNewVal=AllocateClusterNumber();
136 // Write aValue into aFaxIndex and indirectClusterNewVal into the corresponding position
137 // in the indirection table
138 WriteFatTable(aFatIndex,aValue,indirectClusterNewVal);
142 Read the value of a cluster in the Fat
144 @param aFatIndex A cluster to read
145 @return The cluster value read
147 TUint32 CRamFatTable::ReadL(TUint32 aFatIndex) const
149 __ASSERT_ALWAYS(aFatIndex>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
156 clusterVal=*(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos);
160 clusterVal=*(TUint32*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos);
172 Write a value to the FAT and indirection table
174 @param aFatIndex Cluster number to write to
175 @param aFatValue Cluster value for Fat
176 @param anIndirectionValue Value for indirection table
178 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue,TInt anIndirectionValue)
180 const TUint8* pos=RamDiskBase()+PosInBytes(aFatIndex);
185 *(TUint16*)(pos+iFatTablePos)=(TUint16)aFatValue;
186 *(TUint16*)(pos+iIndirectionTablePos)=(TUint16)anIndirectionValue;
190 *(TUint32*)(pos+iFatTablePos)=(TUint32)aFatValue;
191 *(TUint32*)(pos+iIndirectionTablePos)=(TUint32)anIndirectionValue;
202 Write to just the fat table
204 @param aFatIndex Cluster number to write to
205 @param aFatValue Cluster value for Fat
207 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue)
213 *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint16)aFatValue;
217 *(TUint32*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint32)aFatValue;
228 Write to just the fat table
230 @param aFatIndex Cluster number to write to
231 @param aFatValue Value for indirection table
233 void CRamFatTable::WriteIndirectionTable(TInt aFatIndex,TInt aFatValue)
238 *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint16)aFatValue;
242 *(TUint32*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint32)aFatValue;
252 Find the real location of aCluster
253 @param aCluster Cluster to read, contians cluster value upon return
255 void CRamFatTable::ReadIndirectionTable(TUint32& aCluster) const
260 aCluster=*(TUint16*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos);
264 aCluster=*(TUint32*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos);
275 Copy memory in RAM drive area, unlocking required
277 @param aTrg Pointer to destination location
278 @param aSrc Pointer to source location
279 @param aLength Length of data to copy
280 @return Pointer to end of data copied
282 TUint8* CRamFatTable::MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength)
284 TUint8* p=Mem::Copy(aTrg,aSrc,aLength);
289 Copy memory with filling the source buffer with zeroes. Target and source buffers can overlap.
290 Used on RAMDrive srinking in order to wipe data from the file that is being deleted.
292 @param aTrg pointer to the target address
293 @param aSrc pointer to the destination address
294 @param aLength how many bytes to copy
295 @return A pointer to a location aLength bytes beyond aTrg (i.e. the location aTrg+aLength).
297 TUint8* CRamFatTable::MemCopyFillZ(TAny* aTrg, TAny* aSrc,TInt aLength)
299 //-- just copy src to the trg, the memory areas can overlap.
300 TUint8* p=Mem::Copy(aTrg, aSrc, aLength);
302 //-- now zero-fill the source memory area taking into account possible overlap.
303 TUint8* pSrc = static_cast<TUint8*>(aSrc);
304 TUint8* pTrg = static_cast<TUint8*>(aTrg);
306 TUint8* pZFill = NULL; //-- pointer to the beginning of zerofilled area
307 TInt zFillLen = 0; //-- a number of bytes to zero-fill
311 if(pTrg+aLength < pSrc)
312 {//-- target and source areas do not overlap
317 {//-- target and source areas overlap, try not to corrupt the target area
318 zFillLen = pSrc-pTrg;
319 pZFill = pTrg+aLength;
324 if(pSrc+aLength < pTrg)
325 {//-- target and source areas do not overlap
330 {//-- target and source areas overlap, try not to corrupt the target area
331 zFillLen = pSrc+aLength-pTrg;
336 Mem::FillZ(pZFill, zFillLen);
343 Zero fill RAM area corresponding to the cluster number aCluster
344 @param aCluster a cluster number to be zero-filled
346 void CRamFatTable::ZeroFillCluster(TInt aCluster)
348 TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster));
349 Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2());
354 Return the location of a Cluster in the data section of the media
356 @param aCluster to find location of
357 @return Byte offset of the cluster data
359 TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const
361 //__PRINT(_L("CRamFatTable::DataPositionInBytes"));
362 ReadIndirectionTable(aCluster);
363 return(aCluster<<iOwner->ClusterSizeLog2());
366 //-----------------------------------------------------------------------------
369 Allocate and link a cluster chain, leaves if there are not enough free clusters.
370 Chain starts as close as possible to aNearestCluster, last cluster will be marked as EOF.
372 @param aNumber Number of clusters to allocate
373 @param aNearestCluster Cluster the new chain should be nearest to
374 @leave System wide error codes
375 @return The first cluster number allocated
377 TUint32 CRamFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster)
379 __PRINT2(_L("CRamFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster);
380 __ASSERT_DEBUG(aNumber>0, Fault(EFatBadParameter));
382 if(!RequestFreeClusters(aNumber))
384 __PRINT(_L("CRamFatTable::AllocateClusterListL - leaving KErrDirFull"));
385 User::Leave(KErrDiskFull);
388 //-- if this leaves for some reason, there will be no lost clusters
389 TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster);
393 {//-- if this part leaves (e.g. fail to expand the RAM drive), we will need to handle the first allocated EOC
394 TRAPD(nRes, ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster));
397 __PRINT1(_L("CRamFatTable::AllocateClusterListL:ExtendClusterListL() failed with %d") ,nRes);
398 FreeClusterListL(firstCluster); //-- clean up EOC in firstCluster
408 Allocate and mark as EOF a single cluster as close as possible to aNearestCluster,
409 calls base class implementation but must Enlarge the RAM drive first. Allocated cluster RAM area will be zero-filled.
411 @param aNearestCluster Cluster the new cluster should be nearest to
412 @leave System wide error codes
413 @return The cluster number allocated
415 TUint32 CRamFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
417 __PRINT(_L("CRamFatTable::AllocateSingleClusterL"));
418 iOwner->EnlargeL(1<<iOwner->ClusterSizeLog2()); // First enlarge the RAM drive
419 TInt fileAllocated=CFatTable::AllocateSingleClusterL(aNearestCluster); // Now update the free cluster and fat/fit
420 ZeroFillCluster(fileAllocated); //-- zero-fill allocated cluster
421 return(fileAllocated);
426 Extend a file or directory cluster chain, enlarging RAM drive first. Allocated clusters are zero-filled.
427 Leaves if there are no free clusters (the disk is full).
428 Note that method now doesn't call CFatTable::ExtendClusterListL() from its base class, be careful making changes there.
430 @param aNumber number of clusters to allocate
431 @param aCluster starting cluster number / ending cluster number after
432 @leave KErrDiskFull + system wide error codes
434 void CRamFatTable::ExtendClusterListL(TUint32 aNumber, TInt& aCluster)
436 __PRINT2(_L("CRamFatTable::ExtendClusterListL(%d, %d)"), aNumber, aCluster);
437 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
439 iOwner->EnlargeL(aNumber<<iOwner->ClusterSizeLog2());
441 while(aNumber && GetNextClusterL(aCluster))
447 if (NumberOfFreeClusters() < aNumber)
449 __PRINT(_L("CRamFatTable::ExtendClusterListL - leaving KErrDirFull"));
450 User::Leave(KErrDiskFull);
455 const TInt freeCluster=FindClosestFreeClusterL(aCluster);
457 WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again
458 DecrementFreeClusterCount(1);
459 WriteL(aCluster,freeCluster);
460 aCluster=freeCluster;
461 ZeroFillCluster(freeCluster); //-- zero fill just allocated cluster (RAM area)
464 SetFreeClusterHint(aCluster);
469 Mark a chain of clusters as free in the FAT. Shrinks the RAM drive once the
472 @param aCluster Start cluster of cluster chain to free
473 @leave System wide error codes
475 void CRamFatTable::FreeClusterListL(TUint32 aCluster)
477 __PRINT1(_L("CRamFatTable::FreeClusterListL aCluster=%d"),aCluster);
479 return; // File has no cluster allocated
481 const TInt clusterShift=iOwner->ClusterSizeLog2();
482 TInt startCluster=aCluster;
489 while(endCluster!=EOF_32Bit)
491 TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt);
492 if (GetNextClusterL(endCluster)==EFalse || endCluster==0)
493 endCluster=EOF_32Bit; // endCluster==0 -> file contained FAT loop
495 // Real position in bytes of the start cluster in the data area
496 TLinAddr startClusterPos=I64LOW(DataPositionInBytes(startCluster));
497 // Sliding value when more than one block is freed
498 TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
499 __PRINT1(_L("trg=0x%x"),trg);
501 // Beginning of data area to move
502 TLinAddr srcStart=startClusterPos+(num<<clusterShift);
503 __PRINT1(_L("srcStart=0x%x"),srcStart);
504 // Position of next part of cluster chain or position of end of ram drive
505 if (endCluster==EOF_32Bit) // Last cluster is the end of the chain
509 // Fixed to use the genuine RAM drive size rather than the number
510 // of free clusters - though they *should* be the same
511 // It avoids the problem of iFreeClusters getting out of sync with
512 // the RAM drive size but doesn't solve the issue of why it can happen...
514 srcEnd=I64LOW(iOwner->Size());
515 __PRINT1(_L("srcEnd=0x%x"),srcEnd);
517 else // Just move up to the next part of the chain
518 srcEnd=I64LOW(DataPositionInBytes(endCluster));
520 //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
521 //-- zero-filling free space to avoid leaving something important there
522 ASSERT(srcEnd >= srcStart);
523 if(srcEnd-srcStart > 0)
525 MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart);
528 {//-- we are freeing the cluster chain at the end of the RAM drive; Nothing to copy to the drive space that has become free,
529 //-- but nevertheless zero fill this space.
530 Mem::FillZ(iRamDiskBase+trg, num<<clusterShift);
535 startCluster=endCluster;
536 UpdateIndirectionTable(srcStart>>clusterShift,srcEnd>>clusterShift,totalFreed);
541 while(endCluster!=EOF_16Bit)
543 TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt);
544 if (GetNextClusterL(endCluster)==EFalse || endCluster==0)
545 endCluster=EOF_16Bit; // endCluster==0 -> file contained FAT loop
547 // Real position in bytes of the start cluster in the data area
548 TLinAddr startClusterPos=I64LOW(DataPositionInBytes(startCluster));
549 // Sliding value when more than one block is freed
550 TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
551 __PRINT1(_L("trg=0x%x"),trg);
553 // Beginning of data area to move
554 TLinAddr srcStart=startClusterPos+(num<<clusterShift);
555 __PRINT1(_L("srcStart=0x%x"),srcStart);
556 // Position of next part of cluster chain or position of end of ram drive
557 if (endCluster==EOF_16Bit) // Last cluster is the end of the chain
561 // Fixed to use the genuine RAM drive size rather than the number
562 // of free clusters - though they *should* be the same
563 // It avoids the problem of iFreeClusters getting out of sync with
564 // the RAM drive size but doesn't solve the issue of why it can happen...
566 srcEnd=I64LOW(iOwner->Size());
567 __PRINT1(_L("srcEnd=0x%x"),srcEnd);
569 else // Just move up to the next part of the chain
570 srcEnd=I64LOW(DataPositionInBytes(endCluster));
572 //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
573 //-- zero-filling free space to avoid leaving something important there
574 ASSERT(srcEnd >= srcStart);
575 if(srcEnd-srcStart > 0)
577 MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart);
580 {//-- we are freeing the cluster chain at the end of the RAMdrive; Nothing to copy to the drive space that has become free,
581 //-- but nevertheless zero fill this space.
582 Mem::FillZ(iRamDiskBase+trg, num<<clusterShift);
586 startCluster=endCluster;
587 UpdateIndirectionTable(srcStart>>clusterShift,srcEnd>>clusterShift,totalFreed);
590 TInt bytesFreed=totalFreed<<clusterShift;
592 // First free the cluster list
593 CFatTable::FreeClusterListL(aCluster);
594 // Now reduce the size of the RAM drive
595 iOwner->ReduceSizeL(srcEnd-bytesFreed,bytesFreed);
599 Shift any clusters between aStart and anEnd backwards by aClusterShift
601 @param aStart Start of shift region
602 @param anEnd End of shift region
603 @param aClusterShift amount to shift cluster by
605 void CRamFatTable::UpdateIndirectionTable(TUint32 aStart,TUint32 anEnd,TInt aClusterShift)
607 __PRINT(_L("CRamFatTable::UpdateIndirectionTable"));
608 #if defined(__WINS__)
609 TUint32 count=iOwner->MaxClusterNumber();
612 TUint32 cluster=count;
613 ReadIndirectionTable(cluster);
614 if (cluster>=aStart && cluster<anEnd)
615 WriteIndirectionTable(count,cluster-aClusterShift);
618 TUint16* table=(TUint16*)(RamDiskBase()+iIndirectionTablePos);
619 TUint16* entry=table+iOwner->MaxClusterNumber();
622 TUint32 cluster=*--entry;
626 *entry=TUint16(cluster-aClusterShift);