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\ram_fat_table.cpp
15 // FAT16 File Allocation Table classes implementation for the RAM media
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 //# CRamFatTable class implementation
40 //#######################################################################################################################################
43 Constructor, the RamFatTable allows disk compression by redirecting the FAT
45 @param aOwner Owning mount.
47 CRamFatTable::CRamFatTable(CFatMountCB& aOwner)
50 iFatTablePos=aOwner.FirstFatSector()<<aOwner.SectorSizeLog2();
51 iIndirectionTablePos=iFatTablePos+aOwner.FatSizeInBytes();
55 CRamFatTable* CRamFatTable::NewL(CFatMountCB& aOwner)
57 __PRINT1(_L("CRamFatTable::NewL() drv:%d"),aOwner.DriveNumber());
59 CRamFatTable* pSelf = new (ELeave) CRamFatTable(aOwner);
61 CleanupStack::PushL(pSelf);
68 void CRamFatTable::InitializeL()
70 CFatTable::InitializeL();
72 ASSERT(iMediaAtt & KMediaAttVariableSize);
74 iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
75 iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
77 //-- set RAM disk base
78 TLocalDriveCapsV2 caps;
79 TPckg<TLocalDriveCapsV2> capsPckg(caps);
80 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
82 iRamDiskBase = caps.iBaseAddress;
86 Remount the FAT table. This method call means that the media parameters wasn't changed,
87 otherwise CFatMountCB::DoReMountL() would reject it.
88 Just do some re-initialisation work.
90 void CRamFatTable::ReMountL()
92 //-- re-initialise, actually
93 ASSERT(iMediaAtt & KMediaAttVariableSize);
94 ASSERT(FatType() == EFat16);
96 iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
97 iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
99 //-- set RAM disk base
100 TLocalDriveCapsV2 caps;
101 TPckg<TLocalDriveCapsV2> capsPckg(caps);
102 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
104 iRamDiskBase = caps.iBaseAddress;
109 Return the start address of the Ram Drive
111 @return start address of the Ram Drive
113 TUint8 *CRamFatTable::RamDiskBase() const
115 return(iRamDiskBase);
120 Allocate a new cluster number
122 @return New cluster number
124 TInt CRamFatTable::AllocateClusterNumber()
126 return(iOwner->MaxClusterNumber()-NumberOfFreeClusters());
130 Write a value to the FAT (indirection table)
132 @param aFatIndex Cluster to write to
133 @param aValue value to write to Fat
136 void CRamFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
138 //__PRINT(_L("CRamFatTable::WriteL"));
140 __ASSERT_ALWAYS(aFatIndex>=2 && (aValue>=2 || aValue==0) && aValue<=0xFFFF,User::Leave(KErrCorrupt));
141 TUint32 indirectCluster=aFatIndex;
142 TUint32 indirectClusterNewVal=0;
143 ReadIndirectionTable(indirectCluster);
144 // If value in indirection table!=0 we assume we have already written to the indirection table
145 // So just update the FAT table
146 if (indirectCluster!=0 && aValue!=0)
148 WriteFatTable(aFatIndex,aValue);
151 // If value in indirection table is 0, we haven't written to it yet, though the memory has
152 // already been allocated by the EnlargeL() function
153 if (indirectCluster==0 && aValue!=0) // Assumes memory has already been allocated
154 indirectClusterNewVal=AllocateClusterNumber();
155 // Write aValue into aFaxIndex and indirectClusterNewVal into the corresponding position
156 // in the indirection table
157 WriteFatTable(aFatIndex,aValue,indirectClusterNewVal);
161 Read the value of a cluster in the Fat
163 @param aFatIndex A cluster to read
165 @return The cluster value read
168 TUint32 CRamFatTable::ReadL(TUint32 aFatIndex) const
170 __ASSERT_ALWAYS(aFatIndex>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
171 TUint clusterVal=*(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos);
176 Write a value to the FAT and indirection table
178 @param aFatIndex Cluster number to write to
179 @param aFatValue Cluster value for Fat
180 @param anIndirectionValue Value for indirection table
182 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue,TInt anIndirectionValue)
184 TUint8* pos=RamDiskBase()+PosInBytes(aFatIndex);
185 *(TUint16*)(pos+iFatTablePos)=(TUint16)aFatValue;
186 *(TUint16*)(pos+iIndirectionTablePos)=(TUint16)anIndirectionValue;
190 Write to just the fat table
192 @param aFatIndex Cluster number to write to
193 @param aFatValue Cluster value for Fat
195 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue)
197 *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint16)aFatValue;
201 Write to just the fat table
203 @param aFatIndex Cluster number to write to
204 @param aFatValue Value for indirection table
206 void CRamFatTable::WriteIndirectionTable(TInt aFatIndex,TInt aFatValue)
208 *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint16)aFatValue;
212 Find the real location of aCluster
214 @param aCluster Cluster to read, contians cluster value upon return
216 void CRamFatTable::ReadIndirectionTable(TUint32& aCluster) const
218 aCluster=*(TUint16*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos);
222 Copy memory in RAM drive area, unlocking required
224 @param aTrg Pointer to destination location
225 @param aSrc Pointer to source location
226 @param aLength Length of data to copy
227 @return Pointer to end of data copied
229 TUint8* CRamFatTable::MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength)
231 TUint8* p=Mem::Copy(aTrg,aSrc,aLength);
236 Copy memory with filling the source buffer with zeroes. Target and source buffers can overlap.
237 Used on RAMDrive srinking in order to wipe data from the file that is being deleted.
239 @param aTrg pointer to the target address
240 @param aSrc pointer to the destination address
241 @param aLength how many bytes to copy
242 @return A pointer to a location aLength bytes beyond aTrg (i.e. the location aTrg+aLength).
244 TUint8* CRamFatTable::MemCopyFillZ(TAny* aTrg, TAny* aSrc,TInt aLength)
246 //-- just copy src to the trg, the memory areas can overlap.
247 TUint8* p=Mem::Copy(aTrg, aSrc, aLength);
249 //-- now zero-fill the source memory area taking into account possible overlap.
250 TUint8* pSrc = static_cast<TUint8*>(aSrc);
251 TUint8* pTrg = static_cast<TUint8*>(aTrg);
253 TUint8* pZFill = NULL; //-- pointer to the beginning of zerofilled area
254 TInt zFillLen = 0; //-- a number of bytes to zero-fill
258 if(pTrg+aLength < pSrc)
259 {//-- target and source areas do not overlap
264 {//-- target and source areas overlap, try not to corrupt the target area
265 zFillLen = pSrc-pTrg;
266 pZFill = pTrg+aLength;
271 if(pSrc+aLength < pTrg)
272 {//-- target and source areas do not overlap
277 {//-- target and source areas overlap, try not to corrupt the target area
278 zFillLen = pSrc+aLength-pTrg;
283 Mem::FillZ(pZFill, zFillLen);
289 Zero fill RAM area corresponding to the cluster number aCluster
290 @param aCluster a cluster number to be zero-filled
292 void CRamFatTable::ZeroFillCluster(TInt aCluster)
294 TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster));
295 Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2());
300 Return the location of a Cluster in the data section of the media
302 @param aCluster to find location of
303 @return Byte offset of the cluster data
305 TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const
307 //__PRINT(_L("CRamFatTable::DataPositionInBytes"));
308 ReadIndirectionTable(aCluster);
309 return(aCluster<<iOwner->ClusterSizeLog2());
313 Allocate and mark as EOF a single cluster as close as possible to aNearestCluster,
314 calls base class implementation but must Enlarge the RAM drive first. Allocated cluster RAM area will be zero-filled.
316 @param aNearestCluster Cluster the new cluster should be nearest to
317 @leave System wide error codes
318 @return The cluster number allocated
320 TUint32 CRamFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
322 __PRINT(_L("CRamFatTable::AllocateSingleClusterL"));
323 iOwner->EnlargeL(1<<iOwner->ClusterSizeLog2()); // First enlarge the RAM drive
324 TInt fileAllocated=CFatTable::AllocateSingleClusterL(aNearestCluster); // Now update the free cluster and fat/fit
325 ZeroFillCluster(fileAllocated); //-- zero-fill allocated cluster
326 return(fileAllocated);
331 Extend a file or directory cluster chain, enlarging RAM drive first. Allocated clusters are zero-filled.
332 Leaves if there are no free clusters (the disk is full).
333 Note that method now doesn't call CFatTable::ExtendClusterListL() from its base class, be careful making changes there.
335 @param aNumber number of clusters to allocate
336 @param aCluster starting cluster number / ending cluster number after
337 @leave KErrDiskFull + system wide error codes
339 void CRamFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
341 __PRINT(_L("CRamFatTable::ExtendClusterListL"));
342 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
344 iOwner->EnlargeL(aNumber<<iOwner->ClusterSizeLog2());
346 while(aNumber && GetNextClusterL(aCluster))
352 if (NumberOfFreeClusters() < aNumber)
354 __PRINT(_L("CRamFatTable::ExtendClusterListL - leaving KErrDirFull"));
355 User::Leave(KErrDiskFull);
360 const TInt freeCluster=FindClosestFreeClusterL(aCluster);
362 WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again
363 DecrementFreeClusterCount(1);
364 WriteL(aCluster,freeCluster);
365 aCluster=freeCluster;
366 ZeroFillCluster(freeCluster); //-- zero fill just allocated cluster (RAM area)
369 SetFreeClusterHint(aCluster);
374 Mark a chain of clusters as free in the FAT. Shrinks the RAM drive once the
377 @param aCluster Start cluster of cluster chain to free
378 @leave System wide error codes
380 void CRamFatTable::FreeClusterListL(TUint32 aCluster)
382 __PRINT1(_L("CRamFatTable::FreeClusterListL aCluster=%d"),aCluster);
384 return; // File has no cluster allocated
386 const TInt clusterShift=iOwner->ClusterSizeLog2();
387 TInt startCluster=aCluster;
392 while(endCluster!=EOF_16Bit)
394 TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt);
395 if (GetNextClusterL(endCluster)==EFalse || endCluster==0)
396 endCluster=EOF_16Bit; // endCluster==0 -> file contained FAT loop
398 // Real position in bytes of the start cluster in the data area
399 TLinAddr startClusterPos= I64LOW(DataPositionInBytes(startCluster));
400 // Sliding value when more than one block is freed
401 TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
402 __PRINT1(_L("trg=0x%x"),trg);
404 // Beginning of data area to move
405 TLinAddr srcStart=startClusterPos+(num<<clusterShift);
406 __PRINT1(_L("srcStart=0x%x"),srcStart);
407 // Position of next part of cluster chain or position of end of ram drive
408 if (endCluster==EOF_16Bit) // Last cluster is the end of the chain
412 // Fixed to use the genuine RAM drive size rather than the number
413 // of free clusters - though they *should* be the same
414 // It avoids the problem of iFreeClusters getting out of sync with
415 // the RAM drive size but doesn't solve the issue of why it can happen...
417 srcEnd=I64LOW(iOwner->Size());
418 __PRINT1(_L("srcEnd=0x%x"),srcEnd);
420 else // Just move up to the next part of the chain
421 srcEnd=I64LOW(DataPositionInBytes(endCluster));
423 //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
424 //-- zero-filling free space to avoid leaving something important there
425 ASSERT(srcEnd >= srcStart);
426 if(srcEnd-srcStart > 0)
428 MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart);
431 {//-- we are freeing the cluster chain at the end of the RAMdrive; Nothing to copy to the drive space that has become free,
432 //-- but nevertheless zero fill this space.
433 Mem::FillZ(iRamDiskBase+trg, num<<clusterShift);
437 startCluster=endCluster;
438 UpdateIndirectionTable(srcStart>>clusterShift,srcEnd>>clusterShift,totalFreed);
440 TInt bytesFreed=totalFreed<<clusterShift;
442 // First free the cluster list
443 CFatTable::FreeClusterListL(aCluster);
444 // Now reduce the size of the RAM drive
445 iOwner->ReduceSizeL(srcEnd-bytesFreed,bytesFreed);
449 Shift any clusters between aStart and anEnd backwards by aClusterShift
451 @param aStart Start of shift region
452 @param anEnd End of shift region
453 @param aClusterShift amount to shift cluster by
455 void CRamFatTable::UpdateIndirectionTable(TUint32 aStart,TUint32 anEnd,TInt aClusterShift)
457 __PRINT(_L("CRamFatTable::UpdateIndirectionTable"));
458 #if defined(__WINS__)
459 TUint32 count=iOwner->MaxClusterNumber();
462 TUint32 cluster=count;
463 ReadIndirectionTable(cluster);
464 if (cluster>=aStart && cluster<anEnd)
465 WriteIndirectionTable(count,cluster-aClusterShift);
468 TUint16* table=(TUint16*)(RamDiskBase()+iIndirectionTablePos);
469 TUint16* entry=table+iOwner->MaxClusterNumber();
472 TUint32 cluster=*--entry;
476 *entry=TUint16(cluster-aClusterShift);