|
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\sfat\ram_fat_table.cpp |
|
15 // FAT16 File Allocation Table classes implementation for the RAM media |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalTechnology |
|
22 */ |
|
23 |
|
24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
25 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
26 //!! |
|
27 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it |
|
28 //!! |
|
29 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
30 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
31 |
|
32 |
|
33 #include "sl_std.h" |
|
34 #include "sl_fatcache.h" |
|
35 #include "fat_table.h" |
|
36 |
|
37 |
|
38 //####################################################################################################################################### |
|
39 //# CRamFatTable class implementation |
|
40 //####################################################################################################################################### |
|
41 |
|
42 /** |
|
43 Constructor, the RamFatTable allows disk compression by redirecting the FAT |
|
44 |
|
45 @param aOwner Owning mount. |
|
46 */ |
|
47 CRamFatTable::CRamFatTable(CFatMountCB& aOwner) |
|
48 :CFatTable(aOwner) |
|
49 { |
|
50 iFatTablePos=aOwner.FirstFatSector()<<aOwner.SectorSizeLog2(); |
|
51 iIndirectionTablePos=iFatTablePos+aOwner.FatSizeInBytes(); |
|
52 } |
|
53 |
|
54 /** factory method */ |
|
55 CRamFatTable* CRamFatTable::NewL(CFatMountCB& aOwner) |
|
56 { |
|
57 __PRINT1(_L("CRamFatTable::NewL() drv:%d"),aOwner.DriveNumber()); |
|
58 |
|
59 CRamFatTable* pSelf = new (ELeave) CRamFatTable(aOwner); |
|
60 |
|
61 CleanupStack::PushL(pSelf); |
|
62 pSelf->InitializeL(); |
|
63 CleanupStack::Pop(); |
|
64 |
|
65 return pSelf; |
|
66 } |
|
67 |
|
68 void CRamFatTable::InitializeL() |
|
69 { |
|
70 CFatTable::InitializeL(); |
|
71 |
|
72 ASSERT(iMediaAtt & KMediaAttVariableSize); |
|
73 |
|
74 iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2(); |
|
75 iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes(); |
|
76 |
|
77 //-- set RAM disk base |
|
78 TLocalDriveCapsV2 caps; |
|
79 TPckg<TLocalDriveCapsV2> capsPckg(caps); |
|
80 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg)); |
|
81 |
|
82 iRamDiskBase = caps.iBaseAddress; |
|
83 } |
|
84 |
|
85 /** |
|
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. |
|
89 */ |
|
90 void CRamFatTable::ReMountL() |
|
91 { |
|
92 //-- re-initialise, actually |
|
93 ASSERT(iMediaAtt & KMediaAttVariableSize); |
|
94 ASSERT(FatType() == EFat16); |
|
95 |
|
96 iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2(); |
|
97 iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes(); |
|
98 |
|
99 //-- set RAM disk base |
|
100 TLocalDriveCapsV2 caps; |
|
101 TPckg<TLocalDriveCapsV2> capsPckg(caps); |
|
102 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg)); |
|
103 |
|
104 iRamDiskBase = caps.iBaseAddress; |
|
105 } |
|
106 |
|
107 |
|
108 /** |
|
109 Return the start address of the Ram Drive |
|
110 |
|
111 @return start address of the Ram Drive |
|
112 */ |
|
113 TUint8 *CRamFatTable::RamDiskBase() const |
|
114 { |
|
115 return(iRamDiskBase); |
|
116 } |
|
117 |
|
118 |
|
119 /** |
|
120 Allocate a new cluster number |
|
121 |
|
122 @return New cluster number |
|
123 */ |
|
124 TInt CRamFatTable::AllocateClusterNumber() |
|
125 { |
|
126 return(iOwner->MaxClusterNumber()-NumberOfFreeClusters()); |
|
127 } |
|
128 |
|
129 /** |
|
130 Write a value to the FAT (indirection table) |
|
131 |
|
132 @param aFatIndex Cluster to write to |
|
133 @param aValue value to write to Fat |
|
134 @leave |
|
135 */ |
|
136 void CRamFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue) |
|
137 { |
|
138 //__PRINT(_L("CRamFatTable::WriteL")); |
|
139 |
|
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) |
|
147 { |
|
148 WriteFatTable(aFatIndex,aValue); |
|
149 return; |
|
150 } |
|
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); |
|
158 } |
|
159 |
|
160 /** |
|
161 Read the value of a cluster in the Fat |
|
162 |
|
163 @param aFatIndex A cluster to read |
|
164 @leave |
|
165 @return The cluster value read |
|
166 */ |
|
167 |
|
168 TUint32 CRamFatTable::ReadL(TUint32 aFatIndex) const |
|
169 { |
|
170 __ASSERT_ALWAYS(aFatIndex>=KFatFirstSearchCluster,User::Leave(KErrCorrupt)); |
|
171 TUint clusterVal=*(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos); |
|
172 return(clusterVal); |
|
173 } |
|
174 |
|
175 /** |
|
176 Write a value to the FAT and indirection table |
|
177 |
|
178 @param aFatIndex Cluster number to write to |
|
179 @param aFatValue Cluster value for Fat |
|
180 @param anIndirectionValue Value for indirection table |
|
181 */ |
|
182 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue,TInt anIndirectionValue) |
|
183 { |
|
184 TUint8* pos=RamDiskBase()+PosInBytes(aFatIndex); |
|
185 *(TUint16*)(pos+iFatTablePos)=(TUint16)aFatValue; |
|
186 *(TUint16*)(pos+iIndirectionTablePos)=(TUint16)anIndirectionValue; |
|
187 } |
|
188 |
|
189 /** |
|
190 Write to just the fat table |
|
191 |
|
192 @param aFatIndex Cluster number to write to |
|
193 @param aFatValue Cluster value for Fat |
|
194 */ |
|
195 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue) |
|
196 { |
|
197 *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint16)aFatValue; |
|
198 } |
|
199 |
|
200 /** |
|
201 Write to just the fat table |
|
202 |
|
203 @param aFatIndex Cluster number to write to |
|
204 @param aFatValue Value for indirection table |
|
205 */ |
|
206 void CRamFatTable::WriteIndirectionTable(TInt aFatIndex,TInt aFatValue) |
|
207 { |
|
208 *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint16)aFatValue; |
|
209 } |
|
210 |
|
211 /** |
|
212 Find the real location of aCluster |
|
213 |
|
214 @param aCluster Cluster to read, contians cluster value upon return |
|
215 */ |
|
216 void CRamFatTable::ReadIndirectionTable(TUint32& aCluster) const |
|
217 { |
|
218 aCluster=*(TUint16*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos); |
|
219 } |
|
220 |
|
221 /** |
|
222 Copy memory in RAM drive area, unlocking required |
|
223 |
|
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 |
|
228 */ |
|
229 TUint8* CRamFatTable::MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength) |
|
230 { |
|
231 TUint8* p=Mem::Copy(aTrg,aSrc,aLength); |
|
232 return(p); |
|
233 } |
|
234 |
|
235 /** |
|
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. |
|
238 |
|
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). |
|
243 */ |
|
244 TUint8* CRamFatTable::MemCopyFillZ(TAny* aTrg, TAny* aSrc,TInt aLength) |
|
245 { |
|
246 //-- just copy src to the trg, the memory areas can overlap. |
|
247 TUint8* p=Mem::Copy(aTrg, aSrc, aLength); |
|
248 |
|
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); |
|
252 |
|
253 TUint8* pZFill = NULL; //-- pointer to the beginning of zerofilled area |
|
254 TInt zFillLen = 0; //-- a number of bytes to zero-fill |
|
255 |
|
256 if(aTrg < aSrc) |
|
257 { |
|
258 if(pTrg+aLength < pSrc) |
|
259 {//-- target and source areas do not overlap |
|
260 pZFill = pSrc; |
|
261 zFillLen = aLength; |
|
262 } |
|
263 else |
|
264 {//-- target and source areas overlap, try not to corrupt the target area |
|
265 zFillLen = pSrc-pTrg; |
|
266 pZFill = pTrg+aLength; |
|
267 } |
|
268 } |
|
269 else |
|
270 { |
|
271 if(pSrc+aLength < pTrg) |
|
272 {//-- target and source areas do not overlap |
|
273 pZFill = pSrc; |
|
274 zFillLen = aLength; |
|
275 } |
|
276 else |
|
277 {//-- target and source areas overlap, try not to corrupt the target area |
|
278 zFillLen = pSrc+aLength-pTrg; |
|
279 pZFill = pSrc; |
|
280 } |
|
281 } |
|
282 |
|
283 Mem::FillZ(pZFill, zFillLen); |
|
284 |
|
285 return(p); |
|
286 } |
|
287 |
|
288 /** |
|
289 Zero fill RAM area corresponding to the cluster number aCluster |
|
290 @param aCluster a cluster number to be zero-filled |
|
291 */ |
|
292 void CRamFatTable::ZeroFillCluster(TInt aCluster) |
|
293 { |
|
294 TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster)); |
|
295 Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2()); |
|
296 } |
|
297 |
|
298 |
|
299 /** |
|
300 Return the location of a Cluster in the data section of the media |
|
301 |
|
302 @param aCluster to find location of |
|
303 @return Byte offset of the cluster data |
|
304 */ |
|
305 TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const |
|
306 { |
|
307 //__PRINT(_L("CRamFatTable::DataPositionInBytes")); |
|
308 ReadIndirectionTable(aCluster); |
|
309 return(aCluster<<iOwner->ClusterSizeLog2()); |
|
310 } |
|
311 |
|
312 /** |
|
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. |
|
315 |
|
316 @param aNearestCluster Cluster the new cluster should be nearest to |
|
317 @leave System wide error codes |
|
318 @return The cluster number allocated |
|
319 */ |
|
320 TUint32 CRamFatTable::AllocateSingleClusterL(TUint32 aNearestCluster) |
|
321 { |
|
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); |
|
327 } |
|
328 |
|
329 |
|
330 /** |
|
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. |
|
334 |
|
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 |
|
338 */ |
|
339 void CRamFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster) |
|
340 { |
|
341 __PRINT(_L("CRamFatTable::ExtendClusterListL")); |
|
342 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); |
|
343 |
|
344 iOwner->EnlargeL(aNumber<<iOwner->ClusterSizeLog2()); |
|
345 |
|
346 while(aNumber && GetNextClusterL(aCluster)) |
|
347 aNumber--; |
|
348 |
|
349 if(!aNumber) |
|
350 return; |
|
351 |
|
352 if (NumberOfFreeClusters() < aNumber) |
|
353 { |
|
354 __PRINT(_L("CRamFatTable::ExtendClusterListL - leaving KErrDirFull")); |
|
355 User::Leave(KErrDiskFull); |
|
356 } |
|
357 |
|
358 while (aNumber--) |
|
359 { |
|
360 const TInt freeCluster=FindClosestFreeClusterL(aCluster); |
|
361 |
|
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) |
|
367 } |
|
368 |
|
369 SetFreeClusterHint(aCluster); |
|
370 |
|
371 } |
|
372 |
|
373 /** |
|
374 Mark a chain of clusters as free in the FAT. Shrinks the RAM drive once the |
|
375 clusters are free |
|
376 |
|
377 @param aCluster Start cluster of cluster chain to free |
|
378 @leave System wide error codes |
|
379 */ |
|
380 void CRamFatTable::FreeClusterListL(TUint32 aCluster) |
|
381 { |
|
382 __PRINT1(_L("CRamFatTable::FreeClusterListL aCluster=%d"),aCluster); |
|
383 if (aCluster==0) |
|
384 return; // File has no cluster allocated |
|
385 |
|
386 const TInt clusterShift=iOwner->ClusterSizeLog2(); |
|
387 TInt startCluster=aCluster; |
|
388 TInt endCluster=0; |
|
389 TInt totalFreed=0; |
|
390 TLinAddr srcEnd=0; |
|
391 |
|
392 while(endCluster!=EOF_16Bit) |
|
393 { |
|
394 TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt); |
|
395 if (GetNextClusterL(endCluster)==EFalse || endCluster==0) |
|
396 endCluster=EOF_16Bit; // endCluster==0 -> file contained FAT loop |
|
397 |
|
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); |
|
403 |
|
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 |
|
409 { |
|
410 |
|
411 |
|
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... |
|
416 |
|
417 srcEnd=I64LOW(iOwner->Size()); |
|
418 __PRINT1(_L("srcEnd=0x%x"),srcEnd); |
|
419 } |
|
420 else // Just move up to the next part of the chain |
|
421 srcEnd=I64LOW(DataPositionInBytes(endCluster)); |
|
422 |
|
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) |
|
427 { |
|
428 MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart); |
|
429 } |
|
430 else |
|
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); |
|
434 } |
|
435 |
|
436 totalFreed+=num; |
|
437 startCluster=endCluster; |
|
438 UpdateIndirectionTable(srcStart>>clusterShift,srcEnd>>clusterShift,totalFreed); |
|
439 } |
|
440 TInt bytesFreed=totalFreed<<clusterShift; |
|
441 |
|
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); |
|
446 } |
|
447 |
|
448 /** |
|
449 Shift any clusters between aStart and anEnd backwards by aClusterShift |
|
450 |
|
451 @param aStart Start of shift region |
|
452 @param anEnd End of shift region |
|
453 @param aClusterShift amount to shift cluster by |
|
454 */ |
|
455 void CRamFatTable::UpdateIndirectionTable(TUint32 aStart,TUint32 anEnd,TInt aClusterShift) |
|
456 { |
|
457 __PRINT(_L("CRamFatTable::UpdateIndirectionTable")); |
|
458 #if defined(__WINS__) |
|
459 TUint32 count=iOwner->MaxClusterNumber(); |
|
460 while (count--) |
|
461 { |
|
462 TUint32 cluster=count; |
|
463 ReadIndirectionTable(cluster); |
|
464 if (cluster>=aStart && cluster<anEnd) |
|
465 WriteIndirectionTable(count,cluster-aClusterShift); |
|
466 } |
|
467 #else |
|
468 TUint16* table=(TUint16*)(RamDiskBase()+iIndirectionTablePos); |
|
469 TUint16* entry=table+iOwner->MaxClusterNumber(); |
|
470 while (entry>table) |
|
471 { |
|
472 TUint32 cluster=*--entry; |
|
473 if (cluster<aStart) |
|
474 continue; |
|
475 if (cluster<anEnd) |
|
476 *entry=TUint16(cluster-aClusterShift); |
|
477 } |
|
478 #endif |
|
479 } |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |