40 @param aLocDrvCaps local drive attributes |
47 @param aLocDrvCaps local drive attributes |
41 @leave KErrNoMemory |
48 @leave KErrNoMemory |
42 @return Pointer to the Fat table |
49 @return Pointer to the Fat table |
43 */ |
50 */ |
44 CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps) |
51 CFatTable* CFatTable::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps) |
45 { |
52 { |
46 CFatTable* pFatTable=NULL; |
53 CFatTable* pFatTable=NULL; |
47 |
54 |
48 |
55 |
49 switch(aLocDrvCaps.iType) |
56 switch(aLocDrvCaps.iType) |
50 { |
57 { |
51 case EMediaRam: |
58 case EMediaRam: |
52 {//-- this is RAM media, try to create CRamFatTable instance. |
59 {//-- this is RAM media, try to create CRamFatTable instance. |
53 const TFatType fatType = aOwner.FatType(); |
60 const TFatType fatType = aOwner.FatType(); |
54 |
61 |
55 if(fatType != EFat16 ) |
62 if(fatType != EFat16 ) |
56 {//-- CRamFatTable doesn't support FAT12; FAT16 only. |
63 {//-- CRamFatTable doesn't support FAT12; FAT16 only. |
57 __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType); |
64 __PRINT1(_L("CFatTable::NewL() CRamFatTable doesn't support this FAT type:%d"), fatType); |
89 |
96 |
90 /** |
97 /** |
91 Initialise the object, get data from the owning CFatMountCB |
98 Initialise the object, get data from the owning CFatMountCB |
92 */ |
99 */ |
93 void CFatTable::InitializeL() |
100 void CFatTable::InitializeL() |
94 { |
101 { |
95 ASSERT(iOwner); |
102 ASSERT(iOwner); |
96 |
103 |
97 //-- get FAT type from the owner |
104 //-- get FAT type from the owner |
98 iFatType = iOwner->FatType(); |
105 iFatType = iOwner->FatType(); |
99 ASSERT(IsFat12() || IsFat16()); |
106 ASSERT(IsFat12() || IsFat16()); |
100 |
107 |
101 iFreeClusterHint = KFatFirstSearchCluster; |
108 iFreeClusterHint = KFatFirstSearchCluster; |
102 |
109 |
103 //-- cache the media attributes |
110 //-- cache the media attributes |
104 TLocalDriveCapsV2 caps; |
111 TLocalDriveCapsV2 caps; |
105 TPckg<TLocalDriveCapsV2> capsPckg(caps); |
112 TPckg<TLocalDriveCapsV2> capsPckg(caps); |
106 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg)); |
113 User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg)); |
107 iMediaAtt = caps.iMediaAtt; |
114 iMediaAtt = caps.iMediaAtt; |
108 |
115 |
109 //-- obtain maximal number of entries in the table |
116 //-- obtain maximal number of entries in the table |
110 iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use |
117 iMaxEntries = iOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use |
111 |
118 |
112 __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries); |
119 __PRINT3(_L("CFatTable::InitializeL(), drv:%d, iMediaAtt = %08X, max Entries:%d"), iOwner->DriveNumber(), iMediaAtt, iMaxEntries); |
113 } |
120 } |
114 |
121 |
115 //----------------------------------------------------------------------------- |
122 //----------------------------------------------------------------------------- |
116 |
123 |
117 /** |
124 /** |
118 Decrements the free cluster count. |
125 Decrements the free cluster count. |
200 TTime timeStart; |
207 TTime timeStart; |
201 TTime timeEnd; |
208 TTime timeEnd; |
202 timeStart.UniversalTime(); //-- take start time |
209 timeStart.UniversalTime(); //-- take start time |
203 |
210 |
204 //-- walk through whole FAT table looking for free clusters |
211 //-- walk through whole FAT table looking for free clusters |
205 for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i) |
212 for(TUint i=KFatFirstSearchCluster; i<MaxEntries(); ++i) |
206 { |
213 { |
207 if(ReadL(i) == KSpareCluster) |
214 if(ReadL(i) == KSpareCluster) |
208 {//-- found a free cluster |
215 {//-- found a free cluster |
209 ++freeClusters; |
216 ++freeClusters; |
210 |
217 |
211 if(!firstFreeCluster) |
218 if(!firstFreeCluster) |
212 firstFreeCluster = i; |
219 firstFreeCluster = i; |
213 } |
220 } |
214 } |
221 } |
215 |
222 |
216 timeEnd.UniversalTime(); //-- take end time |
223 timeEnd.UniversalTime(); //-- take end time |
217 const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
224 const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
218 __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime); |
225 __PRINT1(_L("#- CFatTable::CountFreeClustersL() finished. Taken:%d ms"), msScanTime); |
219 (void)msScanTime; |
226 (void)msScanTime; |
237 @param aMaxCount Maximum cluster required |
244 @param aMaxCount Maximum cluster required |
238 @leave System wide error values |
245 @leave System wide error values |
239 @return Number of contiguous clusters from aStartCluster. |
246 @return Number of contiguous clusters from aStartCluster. |
240 */ |
247 */ |
241 TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const |
248 TInt CFatTable::CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster,TUint32 aMaxCount) const |
242 { |
249 { |
243 __PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount); |
250 __PRINT2(_L("CFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount); |
244 TUint32 clusterListLen=1; |
251 TUint32 clusterListLen=1; |
245 TInt endCluster=aStartCluster; |
252 TInt endCluster=aStartCluster; |
246 TInt64 endClusterPos=DataPositionInBytes(endCluster); |
253 TInt64 endClusterPos=DataPositionInBytes(endCluster); |
247 while (clusterListLen<aMaxCount) |
254 while (clusterListLen<aMaxCount) |
248 { |
255 { |
249 TInt oldCluster=endCluster; |
256 TInt oldCluster=endCluster; |
250 TInt64 oldClusterPos=endClusterPos; |
257 TInt64 oldClusterPos=endClusterPos; |
251 if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2()))) |
258 if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2()))) |
252 { |
259 { |
253 endCluster=oldCluster; |
260 endCluster=oldCluster; |
254 break; |
261 break; |
255 } |
262 } |
256 clusterListLen++; |
263 clusterListLen++; |
257 } |
264 } |
258 anEndCluster=endCluster; |
265 anEndCluster=endCluster; |
259 return(clusterListLen); |
266 return(clusterListLen); |
260 } |
267 } |
261 |
268 |
262 //----------------------------------------------------------------------------- |
269 //----------------------------------------------------------------------------- |
263 |
270 |
264 /** |
271 /** |
265 Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full). |
272 Extend a file or directory cluster chain, leaves if there are no free clusters (the disk is full). |
268 @param aCluster FAT entry index to start with. |
275 @param aCluster FAT entry index to start with. |
269 |
276 |
270 @leave KErrDiskFull + system wide error codes |
277 @leave KErrDiskFull + system wide error codes |
271 */ |
278 */ |
272 void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster) |
279 void CFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster) |
273 { |
280 { |
274 __PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster); |
281 __PRINT2(_L("CFatTable::ExtendClusterListL() num:%d, clust:%d"), aNumber, aCluster); |
275 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); |
282 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); |
276 |
283 |
277 while(aNumber && GetNextClusterL(aCluster)) |
284 while(aNumber && GetNextClusterL(aCluster)) |
278 aNumber--; |
285 aNumber--; |
279 |
286 |
280 if(!aNumber) |
287 if(!aNumber) |
281 return; |
288 return; |
282 |
289 |
283 if (iFreeClusters<aNumber) |
290 if (iFreeClusters<aNumber) |
284 { |
291 { |
285 __PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull")); |
292 __PRINT(_L("CFatTable::ExtendClusterListL - leaving KErrDirFull")); |
286 User::Leave(KErrDiskFull); |
293 User::Leave(KErrDiskFull); |
287 } |
294 } |
288 |
295 |
289 |
296 |
290 TUint32 freeCluster = 0; |
297 TUint32 freeCluster = 0; |
291 |
298 |
292 //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL() |
299 //-- note: this can be impoved by trying to fing as long chain of free clusters as possible in FindClosestFreeClusterL() |
293 for(TUint i=0; i<aNumber; ++i) |
300 for(TUint i=0; i<aNumber; ++i) |
294 { |
301 { |
295 freeCluster = FindClosestFreeClusterL(aCluster); |
302 freeCluster = FindClosestFreeClusterL(aCluster); |
296 WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again |
303 WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again |
297 WriteL(aCluster,freeCluster); |
304 WriteL(aCluster,freeCluster); |
298 aCluster=freeCluster; |
305 aCluster=freeCluster; |
299 } |
306 } |
300 |
307 |
301 //-- decrement number of available clusters |
308 //-- decrement number of available clusters |
302 DecrementFreeClusterCount(aNumber); |
309 DecrementFreeClusterCount(aNumber); |
303 |
310 |
304 //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from |
311 //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from |
305 SetFreeClusterHint(aCluster); |
312 SetFreeClusterHint(aCluster); |
306 |
313 |
307 } |
314 } |
308 |
315 |
309 //----------------------------------------------------------------------------- |
316 //----------------------------------------------------------------------------- |
310 |
317 |
311 /** |
318 /** |
312 Allocate and mark as EOF a single cluster as close as possible to aNearestCluster |
319 Allocate and mark as EOF a single cluster as close as possible to aNearestCluster |
314 @param aNearestCluster Cluster the new cluster should be nearest to |
321 @param aNearestCluster Cluster the new cluster should be nearest to |
315 @leave System wide error codes |
322 @leave System wide error codes |
316 @return The cluster number allocated |
323 @return The cluster number allocated |
317 */ |
324 */ |
318 TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster) |
325 TUint32 CFatTable::AllocateSingleClusterL(TUint32 aNearestCluster) |
319 { |
326 { |
320 __PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster); |
327 __PRINT1(_L("CFatTable::AllocateSingleCluster() nearest:%d"), aNearestCluster); |
321 if (iFreeClusters==0) |
328 if (iFreeClusters==0) |
322 User::Leave(KErrDiskFull); |
329 User::Leave(KErrDiskFull); |
323 const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster); |
330 const TInt freeCluster=FindClosestFreeClusterL(aNearestCluster); |
324 WriteFatEntryEofL(freeCluster); |
331 WriteFatEntryEofL(freeCluster); |
325 DecrementFreeClusterCount(1); |
332 DecrementFreeClusterCount(1); |
326 |
333 |
327 //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from. |
334 //-- update free cluster hint, it isn't required to be a precise value, just a hint where to start the from from. |
328 SetFreeClusterHint(freeCluster); |
335 SetFreeClusterHint(freeCluster); |
329 |
336 |
330 return(freeCluster); |
337 return(freeCluster); |
331 } |
338 } |
332 |
339 |
333 //----------------------------------------------------------------------------- |
340 //----------------------------------------------------------------------------- |
334 |
341 |
335 /** |
342 /** |
336 Allocate and link a cluster chain, leaves if there are not enough free clusters. |
343 Allocate and link a cluster chain, leaves if there are not enough free clusters. |
340 @param aNearestCluster Cluster the new chain should be nearest to |
347 @param aNearestCluster Cluster the new chain should be nearest to |
341 @leave System wide error codes |
348 @leave System wide error codes |
342 @return The first cluster number allocated |
349 @return The first cluster number allocated |
343 */ |
350 */ |
344 TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster) |
351 TUint32 CFatTable::AllocateClusterListL(TUint32 aNumber, TUint32 aNearestCluster) |
345 { |
352 { |
346 __PRINT2(_L("#>> CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster); |
353 __PRINT2(_L("#>> CFatTable::AllocateClusterList() N:%d,NearestCL:%d"),aNumber,aNearestCluster); |
347 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); |
354 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); |
348 |
355 |
349 if (iFreeClusters<aNumber) |
356 if (iFreeClusters<aNumber) |
350 { |
357 { |
351 __PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull")); |
358 __PRINT(_L("CFatTable::AllocateClusterListL - leaving KErrDirFull")); |
352 User::Leave(KErrDiskFull); |
359 User::Leave(KErrDiskFull); |
353 } |
360 } |
354 |
361 |
355 TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster); |
362 TInt firstCluster = aNearestCluster = AllocateSingleClusterL(aNearestCluster); |
356 if (aNumber>1) |
363 if (aNumber>1) |
357 ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster); |
364 ExtendClusterListL(aNumber-1, (TInt&)aNearestCluster); |
358 |
365 |
359 return(firstCluster); |
366 return(firstCluster); |
360 } |
367 } |
361 |
368 |
362 //----------------------------------------------------------------------------- |
369 //----------------------------------------------------------------------------- |
363 |
370 |
364 /** |
371 /** |
365 Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported. |
372 Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported. |
376 |
383 |
377 FlushL(); //-- Commit the FAT changes to disk first to be safe |
384 FlushL(); //-- Commit the FAT changes to disk first to be safe |
378 |
385 |
379 const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2(); |
386 const TUint bytesPerCluster = 1 << iOwner->ClusterSizeLog2(); |
380 |
387 |
381 TInt64 byteAddress = 0; |
388 TInt64 byteAddress = 0; |
382 TUint deleteLen = 0; // zero indicates no clusters accumulated yet |
389 TUint deleteLen = 0; // zero indicates no clusters accumulated yet |
383 |
390 |
384 for (TUint i=0; i<clusterCount; ++i) |
391 for (TUint i=0; i<clusterCount; ++i) |
385 { |
392 { |
386 const TUint currCluster = aFreedClusters[i]; |
393 const TUint currCluster = aFreedClusters[i]; |
387 |
394 |
388 if (deleteLen == 0) |
395 if (deleteLen == 0) |
389 byteAddress = DataPositionInBytes(currCluster); //-- start of the media range |
396 byteAddress = DataPositionInBytes(currCluster); //-- start of the media range |
390 |
397 |
391 deleteLen += bytesPerCluster; |
398 deleteLen += bytesPerCluster; |
392 |
399 |
393 //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver |
400 //-- if this is the last entry in the array or the net cluster number is not consecutive, notify the driver |
394 if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1)) |
401 if ((i+1) == clusterCount || aFreedClusters[i+1] != (currCluster+1)) |
395 { |
402 { |
396 //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen); |
403 //__PRINT3(_L("DeleteNotify(%08X:%08X, %u), first cluster %u last cluster #%u"), I64HIGH(byteAddress), I64LOW(byteAddress), deleteLen); |
397 //__PRINT2(_L(" first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster); |
404 //__PRINT2(_L(" first cluster %u last cluster #%u"), I64LOW((byteAddress - iOwner->ClusterBasePosition()) >> iOwner->ClusterSizeLog2()) + 2, cluster); |
398 const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen); |
405 const TInt r = iOwner->LocalDrive()->DeleteNotify(byteAddress, deleteLen); |
399 if(r != KErrNone) |
406 if(r != KErrNone) |
400 {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; |
407 {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; |
401 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media. |
408 //-- in normal circumstances it can not happen. One of the reasons: totally worn out media. |
402 const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement); |
409 const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement); |
403 __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled); |
410 __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled); |
404 |
411 |
431 |
438 |
432 @param aCluster Start cluster of cluster chain to free |
439 @param aCluster Start cluster of cluster chain to free |
433 @leave System wide error codes |
440 @leave System wide error codes |
434 */ |
441 */ |
435 void CFatTable::FreeClusterListL(TUint32 aCluster) |
442 void CFatTable::FreeClusterListL(TUint32 aCluster) |
436 { |
443 { |
437 __PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster); |
444 __PRINT1(_L("CFatTable::FreeClusterListL startCluster=%d"),aCluster); |
438 if (aCluster == KSpareCluster) |
445 if (aCluster == KSpareCluster) |
439 return; |
446 return; |
440 |
447 |
441 //-- here we can store array of freed cluster numbers in order to |
448 //-- here we can store array of freed cluster numbers in order to |
442 //-- notify media drive about the media addresses marked as "invalid" |
449 //-- notify media drive about the media addresses marked as "invalid" |
443 RClusterArray deletedClusters; |
450 RClusterArray deletedClusters; |
444 CleanupClosePushL(deletedClusters); |
451 CleanupClosePushL(deletedClusters); |
445 |
452 |
446 //-- if ETrue, we need to notify media driver about invalidated media addressses |
453 //-- if ETrue, we need to notify media driver about invalidated media addressses |
447 const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify; |
454 const TBool bFreeClustersNotify = iMediaAtt & KMediaAttDeleteNotify; |
448 |
455 |
449 //-- this is a maximal number of FAT entries in the deletedClusters array. |
456 //-- this is a maximal number of FAT entries in the deletedClusters array. |
458 |
465 |
459 TUint32 currCluster = aCluster; |
466 TUint32 currCluster = aCluster; |
460 TInt nextCluster = aCluster; |
467 TInt nextCluster = aCluster; |
461 |
468 |
462 for(;;) |
469 for(;;) |
463 { |
470 { |
464 const TBool bEOF = !GetNextClusterL(nextCluster); |
471 const TBool bEOF = !GetNextClusterL(nextCluster); |
465 WriteL(currCluster, KSpareCluster); |
472 WriteL(currCluster, KSpareCluster); |
466 |
473 |
467 lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster); |
474 lastKnownFreeCluster = Min(currCluster, lastKnownFreeCluster); |
468 |
475 |
469 // Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe |
476 // Keep a record of the deleted clusters so that we can subsequently notify the media driver. This is only safe |
470 // to do once the FAT changes have been written to disk. |
477 // to do once the FAT changes have been written to disk. |
471 if(bFreeClustersNotify) |
478 if(bFreeClustersNotify) |
472 deletedClusters.Append(currCluster); |
479 deletedClusters.Append(currCluster); |
473 |
480 |
474 ++cntFreedClusters; |
481 ++cntFreedClusters; |
475 currCluster = nextCluster; |
482 currCluster = nextCluster; |
476 |
483 |
477 if (bEOF || aCluster == KSpareCluster) |
484 if (bEOF || aCluster == KSpareCluster) |
478 break; |
485 break; |
479 |
486 |
480 if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0) |
487 if(bFreeClustersNotify && cntFreedClusters && (cntFreedClusters & (KSubListLen-1))==0) |
481 {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array. |
488 {//-- reached a limit of the entries in the array. Flush FAT cache, notify the driver and empty the array. |
482 IncrementFreeClusterCount(cntFreedClusters); |
489 IncrementFreeClusterCount(cntFreedClusters); |
483 cntFreedClusters = 0; |
490 cntFreedClusters = 0; |
493 SetFreeClusterHint(lastKnownFreeCluster); |
500 SetFreeClusterHint(lastKnownFreeCluster); |
494 |
501 |
495 if(bFreeClustersNotify) |
502 if(bFreeClustersNotify) |
496 DoFreedClustersNotify(deletedClusters); |
503 DoFreedClustersNotify(deletedClusters); |
497 |
504 |
498 CleanupStack::PopAndDestroy(&deletedClusters); |
505 CleanupStack::PopAndDestroy(&deletedClusters); |
499 } |
506 } |
500 |
507 |
501 //----------------------------------------------------------------------------- |
508 //----------------------------------------------------------------------------- |
502 |
509 |
503 /** |
510 /** |
504 Find a free cluster nearest to aCluster, Always checks to the right of aCluster first |
511 Find a free cluster nearest to aCluster, Always checks to the right of aCluster first |
507 @param aCluster Cluster to find nearest free cluster to. |
514 @param aCluster Cluster to find nearest free cluster to. |
508 @leave KErrDiskFull + system wide error codes |
515 @leave KErrDiskFull + system wide error codes |
509 @return cluster number found |
516 @return cluster number found |
510 */ |
517 */ |
511 TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster) |
518 TUint32 CFatTable::FindClosestFreeClusterL(TUint32 aCluster) |
512 { |
519 { |
513 __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster); |
520 __PRINT2(_L("CFatTable::FindClosestFreeClusterL() drv:%d cl:%d"),iOwner->DriveNumber(),aCluster); |
514 |
521 |
515 if(!ClusterNumberValid(aCluster)) |
522 if(!ClusterNumberValid(aCluster)) |
516 { |
523 { |
517 ASSERT(0); |
524 ASSERT(0); |
518 User::Leave(KErrCorrupt); |
525 User::Leave(KErrCorrupt); |
519 } |
526 } |
520 |
527 |
521 |
528 |
522 if(iFreeClusters==0) |
529 if(iFreeClusters==0) |
523 {//-- there is no at least 1 free cluster available |
530 {//-- there is no at least 1 free cluster available |
524 __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1")); |
531 __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #1")); |
525 User::Leave(KErrDiskFull); |
532 User::Leave(KErrDiskFull); |
526 } |
533 } |
527 |
534 |
528 //-- 1. look if the given index contains a free entry |
535 //-- 1. look if the given index contains a free entry |
529 if(ReadL(aCluster) != KSpareCluster) |
536 if(ReadL(aCluster) != KSpareCluster) |
530 {//-- no, it doesn't... |
537 {//-- no, it doesn't... |
531 |
538 |
532 //-- 2. look in both directions starting from the aCluster, looking in the right direction first |
539 //-- 2. look in both directions starting from the aCluster, looking in the right direction first |
558 else |
565 else |
559 canGoLeft = EFalse; |
566 canGoLeft = EFalse; |
560 } |
567 } |
561 |
568 |
562 if(!canGoRight && !canGoLeft) |
569 if(!canGoRight && !canGoLeft) |
563 { |
570 { |
564 __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2")); |
571 __PRINT(_L("CFatTable::FindClosestFreeClusterL() leaving KErrDiskFull #2")); |
565 User::Leave(KErrDiskFull); |
572 User::Leave(KErrDiskFull); |
566 } |
573 } |
567 |
574 |
568 if (canGoRight && ReadL(rightIdx) == KSpareCluster) |
575 if (canGoRight && ReadL(rightIdx) == KSpareCluster) |
569 { |
576 { |
570 aCluster = rightIdx; |
577 aCluster = rightIdx; |
571 break; |
578 break; |
572 } |
579 } |
573 |
580 |
574 if (canGoLeft && ReadL(leftIdx) == KSpareCluster) |
581 if (canGoLeft && ReadL(leftIdx) == KSpareCluster) |
575 { |
582 { |
576 aCluster = leftIdx; |
583 aCluster = leftIdx; |
577 break; |
584 break; |
578 } |
585 } |
579 }//for(..) |
586 }//for(..) |
580 |
587 |
581 }//if(ReadL(aCluster) != KSpareCluster) |
588 }//if(ReadL(aCluster) != KSpareCluster) |
582 |
589 |
583 |
590 |
586 //-- the last known free cluster in the caller of this internal method. |
593 //-- the last known free cluster in the caller of this internal method. |
587 |
594 |
588 // __PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster); |
595 // __PRINT1(_L("CFatTable::FindClosestFreeClusterL found:%d"),aCluster); |
589 |
596 |
590 return aCluster; |
597 return aCluster; |
591 } |
598 } |
592 |
599 |
593 //----------------------------------------------------------------------------- |
600 //----------------------------------------------------------------------------- |
594 |
601 |
595 /** |
602 /** |
596 Converts a cluster number to byte offset in the FAT |
603 Converts a cluster number to byte offset in the FAT |
597 |
604 |
598 @param aFatIndex Cluster number |
605 @param aFatIndex Cluster number |
599 @return Number of bytes from the beginning of the FAT |
606 @return Number of bytes from the beginning of the FAT |
600 */ |
607 */ |
601 TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const |
608 TUint32 CFatTable::PosInBytes(TUint32 aFatIndex) const |
602 { |
609 { |
603 switch(FatType()) |
610 switch(FatType()) |
604 { |
611 { |
605 case EFat12: |
612 case EFat12: |
606 return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry |
613 return (((aFatIndex>>1)<<1) + (aFatIndex>>1)); //-- 1.5 bytes per FAT entry |
607 |
614 |
678 void CAtaFatTable::CreateCacheL() |
685 void CAtaFatTable::CreateCacheL() |
679 { |
686 { |
680 ASSERT(iOwner); |
687 ASSERT(iOwner); |
681 const TUint32 fatSize=iOwner->FatSizeInBytes(); |
688 const TUint32 fatSize=iOwner->FatSizeInBytes(); |
682 __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize); |
689 __PRINT3(_L("CAtaFatTable::CreateCacheL drv:%d, FAT:%d, FAT Size:%d"), iOwner->DriveNumber(), FatType(), fatSize); |
683 |
690 |
684 |
691 |
685 //-- according to FAT specs: |
692 //-- according to FAT specs: |
686 //-- FAT12 max size is 4084 entries or 6126 bytes => create fixed cache for whole FAT |
693 //-- FAT12 max size is 4084 entries or 6126 bytes => create fixed cache for whole FAT |
687 //-- FAT16 min size is 4085 entries or 8170 bytes, max size is 65525 entries or 131048 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 |
688 |
695 |
731 /** |
738 /** |
732 Flush the FAT cache on disk |
739 Flush the FAT cache on disk |
733 @leave System wide error codes |
740 @leave System wide error codes |
734 */ |
741 */ |
735 void CAtaFatTable::FlushL() |
742 void CAtaFatTable::FlushL() |
736 { |
743 { |
737 //-- the data can't be written if the mount is inconsistent |
744 //-- the data can't be written if the mount is inconsistent |
738 iOwner->CheckStateConsistentL(); |
745 iOwner->CheckStateConsistentL(); |
739 |
746 |
740 if (iCache) |
747 if (iCache) |
741 iCache->FlushL(); |
748 iCache->FlushL(); |
742 } |
749 } |
743 |
750 |
744 /** |
751 /** |
745 Clear any cached data |
752 Clear any cached data |
746 @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded. |
753 @param aDiscardDirtyData if ETrue, non-flushed data in the cache will be discarded. |
747 */ |
754 */ |
748 void CAtaFatTable::Dismount(TBool aDiscardDirtyData) |
755 void CAtaFatTable::Dismount(TBool aDiscardDirtyData) |
749 { |
756 { |
750 if (iCache) |
757 if (iCache) |
751 { |
758 { |
752 //-- cache's Close() can check if the cache is clean. |
759 //-- cache's Close() can check if the cache is clean. |
753 //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data) |
760 //-- ignore dirty data in cache if the mount is not in consistent state (it's impossible to flush cache data) |
754 //-- or if we are asked to do so. |
761 //-- or if we are asked to do so. |
755 const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState(); |
762 const TBool bIgnoreDirtyData = aDiscardDirtyData || !iOwner->ConsistentState(); |
756 iCache->Close(bIgnoreDirtyData); |
763 iCache->Close(bIgnoreDirtyData); |
757 |
764 |
758 delete iCache; |
765 delete iCache; |
759 iCache=NULL; |
766 iCache=NULL; |
760 } |
767 } |
761 |
768 |
762 } |
769 } |
763 |
770 |
764 //--------------------------------------------------------------------------------------------------------------------------------------- |
771 //--------------------------------------------------------------------------------------------------------------------------------------- |
765 |
772 |
766 /** |
773 /** |
767 Invalidate whole FAT cache. |
774 Invalidate whole FAT cache. |
788 |
795 |
789 @param aPos absolute media position where the region being invalidated starts. |
796 @param aPos absolute media position where the region being invalidated starts. |
790 @param aLength length in bytes of region to invalidate / refresh |
797 @param aLength length in bytes of region to invalidate / refresh |
791 */ |
798 */ |
792 void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength) |
799 void CAtaFatTable::InvalidateCacheL(TInt64 aPos, TUint32 aLength) |
793 { |
800 { |
794 __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength); |
801 __PRINT3(_L("CAtaFatTable::InvalidateCacheL() drv:%d, pos:%LU, len:%u,"), iOwner->DriveNumber(), aPos, aLength); |
795 |
802 |
796 if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength)) |
803 if(I64HIGH(aPos) || !aLength || I64HIGH(aPos+aLength)) |
797 return; //-- FAT tables can't span over 4G |
804 return; //-- FAT tables can't span over 4G |
798 |
805 |
862 startFatEntry += KFatFirstSearchCluster; |
869 startFatEntry += KFatFirstSearchCluster; |
863 numEntries -= KFatFirstSearchCluster; |
870 numEntries -= KFatFirstSearchCluster; |
864 } |
871 } |
865 |
872 |
866 User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries)); |
873 User::LeaveIfError(iCache->InvalidateRegion(startFatEntry, numEntries)); |
867 } |
874 } |
868 |
875 |
869 |
876 |
870 //----------------------------------------------------------------------------- |
877 //----------------------------------------------------------------------------- |
871 /** |
878 /** |
872 Initialize the object, create FAT cache if required |
879 Initialize the object, create FAT cache if required |
873 @leave KErrNoMemory |
880 @leave KErrNoMemory |
874 */ |
881 */ |
875 void CAtaFatTable::InitializeL() |
882 void CAtaFatTable::InitializeL() |
876 { |
883 { |
877 __PRINT1(_L("CAtaFatTable::InitializeL() drv:%d"), iOwner->DriveNumber()); |
884 __PRINT1(_L("CAtaFatTable::InitializeL() drv:%d"), iOwner->DriveNumber()); |
878 CFatTable::InitializeL(); |
885 CFatTable::InitializeL(); |
879 |
886 |
880 //-- create the FAT cache. |
887 //-- create the FAT cache. |
881 ASSERT(!iCache); |
888 ASSERT(!iCache); |
882 CreateCacheL(); |
889 CreateCacheL(); |
883 } |
890 } |
884 |
891 |
885 |
892 |
886 //----------------------------------------------------------------------------- |
893 //----------------------------------------------------------------------------- |
887 /** |
894 /** |
888 Remount the FAT table. This method call means that the media parameters wasn't changed, |
895 Remount the FAT table. This method call means that the media parameters wasn't changed, |
912 |
919 |
913 @param aFatIndex FAT entry number to read |
920 @param aFatIndex FAT entry number to read |
914 @return FAT entry value |
921 @return FAT entry value |
915 */ |
922 */ |
916 TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const |
923 TUint32 CAtaFatTable::ReadL(TUint32 aFatIndex) const |
917 { |
924 { |
918 if(!ClusterNumberValid(aFatIndex)) |
925 if(!ClusterNumberValid(aFatIndex)) |
919 { |
926 { |
920 //ASSERT(0); //-- for some silly reason some callers pass 0 here and expect it to leave |
927 //ASSERT(0); //-- for some silly reason some callers pass 0 here and expect it to leave |
921 User::Leave(KErrCorrupt); |
928 User::Leave(KErrCorrupt); |
922 } |
929 } |
934 @param aFatIndex aFatIndex FAT entry number to write |
941 @param aFatIndex aFatIndex FAT entry number to write |
935 @param aValue FAT entry to write |
942 @param aValue FAT entry to write |
936 @leave |
943 @leave |
937 */ |
944 */ |
938 void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue) |
945 void CAtaFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue) |
939 { |
946 { |
940 const TUint32 KFat16EntryMask = 0x0FFFF; |
947 const TUint32 KFat16EntryMask = 0x0FFFF; |
941 |
948 |
942 __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue); |
949 __PRINT2(_L("CAtaFatTable::WriteL() entry:%d, val:0x%x"), aFatIndex, aValue); |
943 |
950 |
944 if(!ClusterNumberValid(aFatIndex)) |
951 if(!ClusterNumberValid(aFatIndex)) |
982 |
989 |
983 default: |
990 default: |
984 ASSERT(0); |
991 ASSERT(0); |
985 return EFalse;//-- get rid of warning |
992 return EFalse;//-- get rid of warning |
986 }; |
993 }; |
987 |
994 |
988 if (ret) |
995 if (ret) |
989 { |
996 { |
990 aCluster=nextCluster; |
997 aCluster=nextCluster; |
991 } |
998 } |
992 |
999 |
993 return ret; |
1000 return ret; |
994 |
1001 |
995 } |
1002 } |
996 |
1003 |
997 /** |
1004 /** |
998 Write EOF to aFatIndex |
1005 Write EOF to aFatIndex |
999 @param aFatIndex index in FAT (cluster number) to be written |
1006 @param aFatIndex index in FAT (cluster number) to be written |
1000 */ |
1007 */ |
1001 void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex) |
1008 void CFatTable::WriteFatEntryEofL(TUint32 aFatIndex) |
1002 { |
1009 { |
1003 __PRINT1(_L("CAtaFatTable::WriteFatEntryEofL(%d)"), aFatIndex); |
1010 __PRINT1(_L("CAtaFatTable::WriteFatEntryEofL(%d)"), aFatIndex); |
1004 |
1011 |
1005 //-- use EOF_16Bit (0x0ffff) for all types of FAT, FAT cache will mask it appropriately |
1012 //-- use EOF_16Bit (0x0ffff) for all types of FAT, FAT cache will mask it appropriately |
1006 WriteL(aFatIndex, EOF_16Bit); |
1013 WriteL(aFatIndex, EOF_16Bit); |
1007 } |
1014 } |
1008 |
1015 |
1009 |
1016 |
1010 |
1017 |
1011 /** |
1018 /** |
1012 Mark cluster number aFatIndex in FAT as bad |
1019 Mark cluster number aFatIndex in FAT as bad |
1018 |
1025 |
1019 //-- use KBad_16Bit (0x0fff7) for all types of FAT, FAT cache will mask it appropriately |
1026 //-- use KBad_16Bit (0x0fff7) for all types of FAT, FAT cache will mask it appropriately |
1020 WriteL(aFatIndex, KBad_16Bit); |
1027 WriteL(aFatIndex, KBad_16Bit); |
1021 |
1028 |
1022 FlushL(); |
1029 FlushL(); |
1023 } |
1030 } |
1024 |
1031 |
1025 |
1032 |
1026 /** |
1033 /** |
1027 Return the location of a Cluster in the data section of the media |
1034 Return the location of a Cluster in the data section of the media |
1028 |
1035 |
1029 @param aCluster to find location of |
1036 @param aCluster to find location of |
1030 @return Byte offset of the cluster data |
1037 @return Byte offset of the cluster data |
1031 */ |
1038 */ |
1032 TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const |
1039 TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const |
1033 { |
1040 { |
1034 __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex)); |
1041 __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex)); |
1035 |
1042 |
1036 const TInt clusterBasePosition=iOwner->ClusterBasePosition(); |
1043 const TInt clusterBasePosition=iOwner->ClusterBasePosition(); |
1037 return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition); |
1044 return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition); |
1038 } |
1045 } |
1039 |
1046 |
1040 |
1047 |
1041 |
1048 |
1042 |
1049 |
1043 |
1050 |
1044 |
1051 |