61 iScanFatBits.Close(); |
62 iScanFatBits.Close(); |
62 |
63 |
63 } |
64 } |
64 |
65 |
65 /** |
66 /** |
66 Allocates the Cluster array, the bit packed Fats and if run in a seperate |
67 Creates the structure of this class. |
67 thread the extra CFatTable and cluster buffer |
68 @param aMount The owning mount |
68 |
|
69 @param aMount The owning mount |
|
70 */ |
69 */ |
71 void CScanDrive::ConstructL(CFatMountCB* aMount) |
70 void CScanDrive::ConstructL(CFatMountCB* aMount) |
72 { |
71 { |
73 iMount=aMount; |
72 ASSERT(aMount); |
|
73 |
|
74 //--- setting up |
|
75 iMount=aMount; |
|
76 iGenericError = ENoErrors; |
|
77 iDirError = ENoDirError; |
|
78 iMaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers |
|
79 //------------------------------ |
74 |
80 |
75 //-- create bit vectors that will represent FAT on media and reconstructed by ScanDrive |
81 //-- create bit vectors that will represent FAT on media and reconstructed by ScanDrive. Each bit in the vector represents 1 FAT cluster. |
76 //-- each bit in the vector represents 1 FAT cluster. |
82 const TUint32 KClustersNum = MaxClusters(); |
77 const TUint32 KClustersNum = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers |
83 |
78 |
|
79 CleanupClosePushL(iMediaFatBits); |
84 CleanupClosePushL(iMediaFatBits); |
80 CleanupClosePushL(iScanFatBits); |
85 CleanupClosePushL(iScanFatBits); |
81 |
86 |
82 iMediaFatBits.CreateL(KClustersNum); |
87 iMediaFatBits.CreateL(KClustersNum); |
83 iScanFatBits.CreateL(KClustersNum);; |
88 iScanFatBits.CreateL(KClustersNum); |
84 |
89 |
85 CleanupStack::Pop(&iScanFatBits); |
90 CleanupStack::Pop(&iScanFatBits); |
86 CleanupStack::Pop(&iMediaFatBits); |
91 CleanupStack::Pop(&iMediaFatBits); |
87 } |
92 } |
88 |
93 |
89 //---------------------------------------------------------------------------------------------------- |
94 //---------------------------------------------------------------------------------------------------- |
90 /** |
95 /** |
91 FAT type-agnnostic parser. Reads whole FAT and sets up a bit vector. |
96 FAT type-agnostic parser. Reads whole FAT and sets up a bit vector. |
92 for FAT12/16 it's OK, because the FAT12/16 is fully cached. |
97 for FAT12/16 it's OK, because the FAT12/16 is fully cached. |
93 */ |
98 */ |
94 void CScanDrive::DoParseFatL() |
99 void CScanDrive::DoParseFatL() |
95 { |
100 { |
96 const TInt MaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; |
101 const TInt KMaxClusters = MaxClusters(); |
97 |
|
98 |
|
99 |
102 |
100 iMediaFatBits.Fill(0); |
103 iMediaFatBits.Fill(0); |
101 |
104 |
102 for(TInt i=KFatFirstSearchCluster; i<MaxClusters; ++i) |
105 __PRINT1(_L("CScanDrive::DoParseFatL(), clusters:%d"), KMaxClusters); |
|
106 |
|
107 for(TInt i=KFatFirstSearchCluster; i<KMaxClusters; ++i) |
103 { |
108 { |
104 const TUint32 nFatEntry = ReadFatL(i); |
109 const TUint32 nFatEntry = ReadFatL(i); |
105 |
110 |
106 //-- each '1' bit represents a used cluster |
111 //-- each '1' bit represents a used cluster |
107 if(nFatEntry != KSpareCluster) |
112 if(nFatEntry != KSpareCluster) |
181 |
189 |
182 buf.Close(); |
190 buf.Close(); |
183 CleanupStack::PopAndDestroy(&buf); |
191 CleanupStack::PopAndDestroy(&buf); |
184 } |
192 } |
185 |
193 |
|
194 |
|
195 |
186 //---------------------------------------------------------------------------------------------------- |
196 //---------------------------------------------------------------------------------------------------- |
187 /** |
197 /** |
188 Sets up a bit list representation of the media fat |
198 Sets up a bit list representation of the media fat |
189 Reads whole FAT and sets '1' bits in the bit vector corresponding to the occupied clusters. |
199 Reads whole FAT and sets '1' bits in the bit vector corresponding to the occupied clusters. |
190 */ |
200 */ |
191 void CScanDrive::ReadMediaFatL() |
201 void CScanDrive::ReadMediaFatL() |
192 { |
202 { |
193 ASSERT(iMount->ConsistentState()); |
203 ASSERT(iMount->ConsistentState()); |
194 |
204 |
|
205 TInt nRes; |
|
206 |
195 if(iMount->FatType() == EFat32) |
207 if(iMount->FatType() == EFat32) |
196 {//-- for FAT32 try to use specialised method of parsing |
208 {//-- for FAT32 try to use specialised method of parsing |
197 TInt nRes; |
|
198 TRAP(nRes, DoParseFat32L()) |
209 TRAP(nRes, DoParseFat32L()) |
199 if(nRes == KErrNone) |
210 if(nRes == KErrNone) |
200 return; |
211 return; |
201 } |
212 } |
202 |
213 |
|
214 |
203 //-- use old FAT-agnostic parsing |
215 //-- use old FAT-agnostic parsing |
204 DoParseFatL(); |
216 DoParseFatL(); |
205 } |
217 } |
206 |
218 |
207 /** |
219 |
208 Set a cluster as visited in the bit packed scan Fat |
220 /** |
209 |
221 @return True if a directory error has been found |
210 @param aCluster Cluster number |
|
211 */ |
|
212 void CScanDrive::SetUsedL(TUint aCluster) |
|
213 { |
|
214 __ASSERT_ALWAYS(aCluster >= KFatFirstSearchCluster && aCluster < (KFatFirstSearchCluster+iMount->UsableClusters()),User::Leave(KErrCorrupt)); |
|
215 iScanFatBits.SetBit(aCluster); |
|
216 } |
|
217 |
|
218 |
|
219 /** |
|
220 Query whether a cluster is already set as used |
|
221 |
|
222 @param aCluster Cluster to query |
|
223 */ |
|
224 TBool CScanDrive::AlreadyUsedL(TUint aCluster) const |
|
225 { |
|
226 __ASSERT_ALWAYS(aCluster >= KFatFirstSearchCluster && aCluster < (KFatFirstSearchCluster+iMount->UsableClusters()),User::Leave(KErrCorrupt)); |
|
227 |
|
228 return iScanFatBits[aCluster]; |
|
229 } |
|
230 |
|
231 /** |
|
232 @param aPos Position in a directory cluster |
|
233 @return ETrue if aPos is the last entry in the root directory |
|
234 */ |
|
235 TBool CScanDrive::IsEndOfRootDir(const TEntryPos& aPos)const |
|
236 { |
|
237 return(iMount->IsRootDir(aPos)&&(iMount->StartOfRootDirInBytes()+aPos.iPos==(iMount->RootDirEnd()-KSizeOfFatDirEntry))); |
|
238 } |
|
239 |
|
240 /** |
|
241 @param aVal Value of the cluster to be tested |
|
242 @return ETrue if aVal is the end of cluster marker |
|
243 */ |
|
244 TBool CScanDrive::IsEofF(TInt aVal) const |
|
245 { |
|
246 return iMount->IsEndOfClusterCh(aVal); |
|
247 } |
|
248 |
|
249 |
|
250 /** |
|
251 @return True if a directory error has been found |
|
252 */ |
222 */ |
253 TBool CScanDrive::IsDirError() const |
223 TBool CScanDrive::IsDirError() const |
254 { |
224 { |
255 return(iDirError!=0); |
225 return(iDirError!=0); |
256 } |
226 } |
257 |
227 |
258 /** |
228 /** |
259 After StartL() and finishing allows us to know if there were any problems at all. |
229 After StartL() and finishing allows us to know if there were any problems discovered at all. |
260 The client may wish to remount the filesystem if there were errors. |
230 The client may wish to remount the filesystem if there were errors. |
261 |
231 |
262 @return EFalse if there were no problems in FS. |
232 @return The code describing the problem. |
263 */ |
233 */ |
264 TBool CScanDrive::ProblemsDiscovered() const |
234 CScanDrive::TGenericError CScanDrive::ProblemsDiscovered() const |
265 { |
235 { |
266 return IsDirError() || iFoundProblems; |
236 |
|
237 if(IsDirError()) |
|
238 return EScanDriveDirError; |
|
239 else |
|
240 return iGenericError; |
267 } |
241 } |
268 |
242 |
269 /** |
243 /** |
270 Sets the flag indicating than there are errors in filesystem structure |
244 Sets the flag indicating than there are errors in filesystem structure |
271 See ProblemsDiscovered() |
245 See ProblemsDiscovered() |
272 */ |
246 |
273 void CScanDrive::IndicateErrorsFound() |
247 @param aError a code describing the error |
|
248 */ |
|
249 void CScanDrive::IndicateErrorsFound(TGenericError aError) |
274 { |
250 { |
275 iFoundProblems = ETrue; |
251 ASSERT(aError != ENoErrors); |
|
252 iGenericError = aError; |
276 } |
253 } |
277 |
254 |
278 |
255 |
279 |
256 //---------------------------------------------------------------------------------------------------- |
280 /** |
257 /** |
281 Start point for scan drive also fixes up errors |
258 Start the scanner. The this calss description about what it actually does. |
282 |
259 @param aMode specifies the operational mode. |
283 @return The result of the scan |
260 */ |
284 @leave |
261 void CScanDrive::StartL(TScanDriveMode aMode) |
285 */ |
262 { |
286 TInt CScanDrive::StartL() |
263 __PRINT2(_L("CScanDrive::StartL(%d), drive:%d"), aMode, iMount->DriveNumber()); |
287 { |
264 iScanDriveMode = aMode; |
288 __PRINT1(_L("CScanDrive::StartL(), drive:%d"), iMount->DriveNumber()); |
|
289 |
265 |
290 //-- used for measuring time |
266 //-- used for measuring time |
291 TTime timeStart; |
267 TTime timeStart; |
292 TTime timeEnd; |
268 TTime timeEnd; |
|
269 |
293 timeStart.UniversalTime(); //-- take start time |
270 timeStart.UniversalTime(); //-- take start time |
294 |
271 |
295 |
|
296 ReadMediaFatL(); |
272 ReadMediaFatL(); |
297 |
273 |
|
274 //timeEnd.UniversalTime(); //-- take end time |
|
275 //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
|
276 //__PRINT1(_L("#@@@ CScanDrive #1:%d ms "), elapsedTime); |
|
277 |
298 CheckDirStructureL(); |
278 CheckDirStructureL(); |
299 #if defined(DEBUG_SCANDRIVE) |
279 |
300 CompareFatsL(); |
280 //-- uncomments a line below if you need to compare real and restored FAT tables and print out all differences |
301 #endif |
281 //CompareFatsL(EFalse); |
302 if(IsDirError()) |
282 |
303 FixupDirErrorL(); |
283 //timeEnd.UniversalTime(); //-- take end time |
304 |
284 //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
305 WriteNewFatsL(); |
285 //__PRINT1(_L("#@@@ CScanDrive #2:%d ms "), elapsedTime); |
306 #if defined(DEBUG_SCANDRIVE) |
286 |
|
287 if(CheckDiskMode()) |
|
288 {//-- in check disk mode it is nesessarily just to detech FS errors |
|
289 CompareFatsL(ETrue); //-- will stop on the first error found |
|
290 } |
|
291 else |
|
292 {//-- In ScanDrive mode we need to find and fix Rugged FAT artefacts. |
|
293 |
|
294 if(IsDirError()) |
|
295 FixupDirErrorL(); |
|
296 |
|
297 CompareAndFixFatsL(); |
|
298 } |
|
299 |
307 PrintErrors(); |
300 PrintErrors(); |
308 #endif |
|
309 |
|
310 |
301 |
311 |
302 |
312 timeEnd.UniversalTime(); //-- take end time |
303 timeEnd.UniversalTime(); //-- take end time |
313 const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
304 const TInt elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
314 (void)msScanTime; |
305 (void)elapsedTime; |
315 |
306 |
316 __PRINT1(_L("CScanDrive: Directories visisted = %d\n"),iDirsChecked); |
307 __PRINT1(_L("CScanDrive: Directories visisted = %d\n"),iDirsChecked); |
317 __PRINT1(_L("#@@@ CScanDrive time taken:%d ms "), msScanTime); |
308 __PRINT1(_L("#@@@ CScanDrive time taken:%d ms "), elapsedTime); |
318 |
309 |
319 return KErrNone; |
310 |
320 } |
311 |
321 |
312 return; |
322 /** |
313 } |
323 Fix errors detected by the drive scan |
314 |
|
315 //---------------------------------------------------------------------------------------------------- |
|
316 /** |
|
317 Fix errors detected by the drive scan |
324 |
318 |
325 @leave System wide error code |
319 @leave System wide error code |
326 */ |
320 */ |
327 void CScanDrive::FixupDirErrorL() |
321 void CScanDrive::FixupDirErrorL() |
328 { |
322 { |
329 if(!IsDirError()) |
323 ASSERT(!CheckDiskMode()); |
|
324 |
|
325 if(!IsDirError()) |
330 return; |
326 return; |
331 |
327 |
332 if(iDirError==EScanMatchingEntry) |
328 if(iDirError==EScanMatchingEntry) |
333 { |
329 { |
334 FindSameStartClusterL(); |
330 FindSameStartClusterL(); |
400 break; |
400 break; |
401 TBool isComplete; |
401 TBool isComplete; |
402 TEntryPos vfatPos=entryPos; |
402 TEntryPos vfatPos=entryPos; |
403 isComplete=MoveToVFatEndL(entryPos,entry,dirEntries); |
403 isComplete=MoveToVFatEndL(entryPos,entry,dirEntries); |
404 __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName)); |
404 __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName)); |
|
405 |
405 TInt err=CheckEntryClusterL(entry,vfatPos); |
406 TInt err=CheckEntryClusterL(entry,vfatPos); |
406 if(err==KErrNone) |
407 if(err==KErrNone) |
407 { |
408 { |
408 --iRecursiveDepth; |
409 --iRecursiveDepth; |
409 return(err); |
410 return(err); |
410 } |
411 } |
|
412 |
411 if(IsEndOfRootDir(entryPos)) |
413 if(IsEndOfRootDir(entryPos)) |
412 break; |
414 break; |
|
415 |
413 MoveToNextEntryL(entryPos); |
416 MoveToNextEntryL(entryPos); |
414 } |
417 } |
415 --iRecursiveDepth; |
418 --iRecursiveDepth; |
416 return(KErrNotFound); |
419 return(KErrNotFound); |
417 } |
420 } |
418 |
421 |
419 /** |
422 //---------------------------------------------------------------------------------------------------- |
420 Procces aEntry to find matching start cluster |
423 /** |
421 |
424 Procces aEntry to find matching start cluster |
422 @param aEntry Directory entry to check |
425 |
423 @param aEntryPos Position of directory to check |
426 @param aEntry Directory entry to check |
424 @return System wide error value |
427 @param aEntryPos Position of directory to check |
425 @leave |
428 @return System wide error value |
|
429 @leave |
426 */ |
430 */ |
427 TInt CScanDrive::CheckEntryClusterL(const TFatDirEntry& aEntry, const TEntryPos& aEntryPos) |
431 TInt CScanDrive::CheckEntryClusterL(const TFatDirEntry& aEntry, const TEntryPos& aEntryPos) |
428 { |
432 { |
429 __PRINT(_L("CScanDrive::CheckEntryClusterL")); |
433 __PRINT(_L("CScanDrive::CheckEntryClusterL")); |
430 if(iMount->StartCluster(aEntry)==iMatching.iStartCluster) |
434 if((TUint)iMount->StartCluster(aEntry)==iMatching.iStartCluster) |
431 { |
435 { |
432 TBool complete=AddMatchingEntryL(aEntryPos); |
436 TBool complete=AddMatchingEntryL(aEntryPos); |
433 if(complete) |
437 if(complete) |
434 return(KErrNone); |
438 return(KErrNone); |
435 } |
439 } |
436 else if(aEntry.Attributes()&KEntryAttDir) |
440 else if(aEntry.Attributes()&KEntryAttDir) |
437 return(FindStartClusterL(iMount->StartCluster(aEntry))); |
441 return(FindStartClusterL(iMount->StartCluster(aEntry))); |
|
442 |
438 return(KErrNotFound); |
443 return(KErrNotFound); |
439 } |
444 } |
440 |
445 |
441 /** |
446 //---------------------------------------------------------------------------------------------------- |
442 Checks directory strucutre for errors, can be considered the start point of the scan. |
447 /** |
443 Handles recursion depth to avoid stack overflow. |
448 Checks directory structure for errors, can be considered the start point of the scan. |
444 |
449 Handles recursion depth to avoid stack overflow. |
445 @leave System wide error code |
450 |
|
451 @leave System wide error code |
446 */ |
452 */ |
447 void CScanDrive::CheckDirStructureL() |
453 void CScanDrive::CheckDirStructureL() |
448 { |
454 { |
449 CheckDirL(iMount->RootIndicator()); |
455 CheckDirL(iMount->RootIndicator()); |
450 // Due to recursive nature of CheckDirL when a depth of |
456 // Due to recursive nature of CheckDirL when a depth of |
451 // KMaxScanDepth is reached clusters are stored in a list |
457 // KMaxScanDepth is reached clusters are stored in a list |
452 // and passed into CheckDirL afresh |
458 // and passed into CheckDirL afresh |
453 for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i) |
459 |
|
460 for(TUint i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i) |
454 { |
461 { |
455 RArray<TInt>* clusterList=iClusterListArray[i]; |
462 RArray<TInt>* clusterList=iClusterListArray[i]; |
456 ++iListArrayIndex; |
463 ++iListArrayIndex; |
457 for(TInt j=0;j<clusterList->Count();++j) |
464 for(TInt j=0;j<clusterList->Count();++j) |
458 { |
465 { |
461 } |
468 } |
462 } |
469 } |
463 } |
470 } |
464 |
471 |
465 |
472 |
466 /** |
473 //---------------------------------------------------------------------------------------------------- |
467 Function is called recursively with Process entry untill the whole volume has been scanned. |
474 /** |
468 Each directory entry is scanned for errors, these are recorded for later fixing. |
475 This function is called recursively with Process entry untill the whole volume has been scanned. |
469 |
476 Each directory entry is scanned for errors, these are recorded for later fixing. |
470 @param aCluster Directory cluster to start checking |
477 |
471 @leave System wide error codes |
478 @param aCluster Directory cluster to start checking |
472 */ |
479 @leave System wide error codes |
473 void CScanDrive::CheckDirL(TInt aCluster) |
480 */ |
|
481 void CScanDrive::CheckDirL(TUint32 aCluster) |
474 { |
482 { |
475 __PRINT1(_L("CScanDrive::CheckDirL aCluster=%d"),aCluster); |
483 __PRINT1(_L("CScanDrive::CheckDirL aCluster=%d"),aCluster); |
476 __ASSERT_ALWAYS(aCluster>=0,User::Leave(KErrCorrupt)); |
484 |
477 // check depth of recursion |
485 // check depth of recursion |
478 if(++iRecursiveDepth==KMaxScanDepth) |
486 if(++iRecursiveDepth==KMaxScanDepth) |
479 { |
487 { |
480 AddToClusterListL(aCluster); |
488 AddToClusterListL(aCluster); |
481 --iRecursiveDepth; |
489 --iRecursiveDepth; |
482 return; |
490 return; |
483 } |
491 } |
484 #if defined(DEBUG_SCANDRIVE) |
492 |
485 ++iDirsChecked; |
493 ++iDirsChecked; |
486 #endif |
494 |
487 TEntryPos entryPos(aCluster,0); |
495 TEntryPos entryPos(aCluster,0); |
488 TInt dirEntries=0; |
496 TInt dirEntries=0; |
489 FOREVER |
497 FOREVER |
490 { |
498 { |
491 TFatDirEntry entry; |
499 TFatDirEntry entry; |
492 ReadDirEntryL(entryPos,entry); |
500 ReadDirEntryL(entryPos,entry); |
493 if(!iMount->IsEndOfClusterCh(entryPos.iCluster)) |
501 if(!iMount->IsEndOfClusterCh(entryPos.iCluster)) |
494 ++dirEntries; |
502 ++dirEntries; |
495 if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased()) |
503 |
|
504 if(entry.IsParentDirectory() || entry.IsCurrentDirectory() || entry.IsErased()) |
496 { |
505 { |
497 if(IsEndOfRootDir(entryPos)) |
506 if(IsEndOfRootDir(entryPos)) |
498 break; |
507 break; |
|
508 |
499 MoveToNextEntryL(entryPos); |
509 MoveToNextEntryL(entryPos); |
500 continue; |
510 continue; |
501 } |
511 } |
|
512 |
502 if(entry.IsEndOfDirectory()) |
513 if(entry.IsEndOfDirectory()) |
503 { |
514 { |
504 if(aCluster) |
515 if(aCluster) |
505 WriteClusterChainL(aCluster,dirEntries<<KSizeOfFatDirEntryLog2); |
516 RecordClusterChainL(aCluster,dirEntries<<KSizeOfFatDirEntryLog2); |
|
517 |
506 break; |
518 break; |
507 } |
519 } |
|
520 |
508 TEntryPos origPos=entryPos; |
521 TEntryPos origPos=entryPos; |
509 TFatDirEntry origEntry=entry; |
522 TFatDirEntry origEntry=entry; |
510 TInt origDirEntries=dirEntries; |
523 TInt origDirEntries=dirEntries; |
511 TBool isComplete; |
524 |
512 isComplete=MoveToVFatEndL(entryPos,entry,dirEntries); |
525 const TBool isComplete = MoveToVFatEndL(entryPos,entry,dirEntries); |
513 // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set; |
526 |
|
527 if(!isComplete && CheckDiskMode()) |
|
528 {//-- broken VFAT entryset; in CheckDisk mode this is the FS error, abort further activity |
|
529 IndicateErrorsFound(EInvalidEntrySize); |
|
530 User::Leave(KErrCorrupt); |
|
531 } |
|
532 |
|
533 // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set; |
514 // assuming a non-VFAT corrupted entry is a VFAT entry is dangerous as we then assume that the |
534 // assuming a non-VFAT corrupted entry is a VFAT entry is dangerous as we then assume that the |
515 // first byte is a count of entries to skip, thus completely invalidating the next <n> directories. |
535 // first byte is a count of entries to skip, thus completely invalidating the next <n> directories. |
516 if (!isComplete && origEntry.IsVFatEntry()) |
536 |
|
537 //-- this code seems to deal with one of the Rugged FAT artefacts: partially deleted VFAT entryset, when DOS entry is deleted first |
|
538 //-- and delettion of VFAT ones had failed |
|
539 if(!isComplete && origEntry.IsVFatEntry()) |
517 { |
540 { |
518 AddPartialVFatL(origPos,origEntry); |
541 AddPartialVFatL(origPos,origEntry); |
519 if(entryPos.iCluster!=KEndOfDirectory) |
542 if(!IsEofF(entryPos.iCluster)) |
520 { |
543 { |
521 TInt toMove=origEntry.NumFollowing()-(dirEntries-origDirEntries); |
544 TInt toMove=origEntry.NumFollowing()-(dirEntries-origDirEntries); |
522 if(toMove) |
545 if(toMove) |
523 MovePastEntriesL(entryPos,entry,toMove,dirEntries); |
546 MovePastEntriesL(entryPos,entry,toMove,dirEntries); |
524 } |
547 } |
528 // incomplete long file name entry |
551 // incomplete long file name entry |
529 dirEntries = origDirEntries; |
552 dirEntries = origDirEntries; |
530 } |
553 } |
531 } |
554 } |
532 else |
555 else |
533 ProcessEntryL(entry); |
556 { |
|
557 ProcessEntryL(entry); |
|
558 } |
|
559 |
534 if(IsEndOfRootDir(entryPos)) |
560 if(IsEndOfRootDir(entryPos)) |
535 break; |
561 break; |
|
562 |
536 MoveToNextEntryL(entryPos); |
563 MoveToNextEntryL(entryPos); |
537 } |
564 } |
538 --iRecursiveDepth; |
565 --iRecursiveDepth; |
539 } |
566 } |
540 |
567 |
541 |
568 //---------------------------------------------------------------------------------------------------- |
542 /** |
569 /** |
543 Process non trivial entries, such as files, if they are correct by filling out their |
570 Process non trivial entries, such as files, if they are correct by filling out their |
544 cluster allocation in the bit packed Fat table. If it comes accross a directory |
571 cluster allocation in the bit packed Fat table. If it comes accross a directory |
545 CheckDirL will be called. |
572 CheckDirL will be called. |
546 |
573 |
547 @param aEntry Directory entry to check |
574 @param aEntry Directory entry to check |
548 @leave System wide error code |
575 @leave System wide error code |
549 */ |
576 */ |
550 void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry) |
577 void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry) |
551 { |
578 { |
552 __PRINT(_L("CScanDrive::ProcessEntryL")); |
579 __PRINT(_L("CScanDrive::ProcessEntryL")); |
553 TInt entryAtt=aEntry.Attributes(); |
580 TInt entryAtt=aEntry.Attributes(); |
554 |
581 |
555 __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt)); |
582 __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt)); |
556 if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0) |
583 |
557 WriteClusterChainL(iMount->StartCluster(aEntry),(TUint) aEntry.Size()); |
584 if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0) |
|
585 {//-- this is a file with length >0. Check that its cluster chain corresponds to its size |
|
586 RecordClusterChainL(iMount->StartCluster(aEntry),(TUint) aEntry.Size()); |
|
587 } |
558 else if(entryAtt&KEntryAttDir) |
588 else if(entryAtt&KEntryAttDir) |
559 CheckDirL(iMount->StartCluster(aEntry)); |
589 {//-- this is the directory, walk into it |
560 } |
590 CheckDirL(iMount->StartCluster(aEntry)); |
561 |
591 } |
562 /** |
592 } |
563 Writes out the cluster chain for a correct file or directory, checks that the cluster |
593 |
564 has not already been used and that the correct number of clusters are allocated for the |
594 //---------------------------------------------------------------------------------------------------- |
565 size of file. Registers cluster as used if correct |
595 /** |
566 |
596 Walks the cluster chain for a correct file or directory, checks that the cluster |
567 @param aCluster Cluster chain start point |
597 has not already been used and that the correct number of clusters are allocated for the |
568 @param aSizeInBytes Size of the file or directory in bytes |
598 size of file. Registers cluster as used, if correct. |
569 @leave System wide error values |
599 |
570 */ |
600 @param aCluster Cluster chain start point |
571 void CScanDrive::WriteClusterChainL(TInt aCluster,TUint aSizeInBytes) |
601 @param aSizeInBytes Size of the file or directory in bytes |
572 // |
602 @leave System wide error values |
573 // Mark off in the new fat the clusters used by entry with start cluster of aCluster |
603 */ |
574 // |
604 void CScanDrive::RecordClusterChainL(TInt aCluster, TUint aSizeInBytes) |
575 { |
605 { |
576 __PRINT1(_L("CScanDrive::WriteClusterChainL starting at %d"),aCluster); |
606 __PRINT2(_L("CScanDrive::RecordClusterChainL() cl:%d, sz:%d") ,aCluster, aSizeInBytes); |
577 __ASSERT_ALWAYS(aCluster>0,User::Leave(KErrCorrupt)); |
607 __ASSERT_ALWAYS(aCluster>0, User::Leave(KErrCorrupt)); |
578 TInt clusterCount; |
608 |
579 if(aSizeInBytes==0) |
609 TUint clusterCount; |
|
610 |
|
611 if(aSizeInBytes==0) |
580 clusterCount=1; |
612 clusterCount=1; |
581 else |
613 else |
582 clusterCount = (TInt) (( TInt64(aSizeInBytes) + TInt64((1<<iMount->ClusterSizeLog2())-1) ) >> iMount->ClusterSizeLog2()); |
614 { |
|
615 const TUint64 tmp = aSizeInBytes + Pow2_64(iMount->ClusterSizeLog2()) - 1; |
|
616 clusterCount = (TUint) (tmp >> iMount->ClusterSizeLog2()); |
|
617 } |
|
618 |
583 TInt startCluster=aCluster; |
619 TInt startCluster=aCluster; |
584 while(clusterCount) |
620 while(clusterCount) |
585 { |
621 { |
586 if(AlreadyUsedL(aCluster)) |
622 if(IsClusterUsedL(aCluster)) |
587 { |
623 {//-- this cluster already seems to belong to some other object; crosslinked cluster chain. Can't fix it. |
588 __ASSERT_ALWAYS(!IsDirError()&&iMatching.iStartCluster==0&&aCluster==startCluster,User::Leave(KErrCorrupt)); |
624 if(CheckDiskMode()) |
|
625 {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning |
|
626 __PRINT1(_L("CScanDrive::RecordClusterChainL #1 %d"),aCluster); |
|
627 IndicateErrorsFound(EClusterAlreadyInUse); |
|
628 User::Leave(KErrCorrupt); |
|
629 } |
|
630 |
|
631 __ASSERT_ALWAYS(!IsDirError() && iMatching.iStartCluster==0 && aCluster==startCluster,User::Leave(KErrCorrupt)); |
589 iMatching.iStartCluster=aCluster; |
632 iMatching.iStartCluster=aCluster; |
590 iDirError=EScanMatchingEntry; //ERROR POINT |
633 iDirError=EScanMatchingEntry; //ERROR POINT |
591 IndicateErrorsFound(); //-- indicate that we have found errors |
634 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
592 return; |
635 return; |
593 } |
636 } |
594 if(clusterCount==1) |
637 |
|
638 |
|
639 if(clusterCount==1) |
595 { |
640 { |
596 if(!iMount->IsEndOfClusterCh(ReadFatL(aCluster))) |
641 if(!iMount->IsEndOfClusterCh(ReadFatL(aCluster))) |
597 { |
642 {//-- seems to be a rugged FAT artefact; File truncation had failed before and now file length is less than |
598 //This is a genuine truncation |
643 //-- the corresponding cluster chain shall be. It will be truncated. |
599 iTruncationCluster = aCluster; |
644 iTruncationCluster = aCluster; |
|
645 |
|
646 if(CheckDiskMode()) |
|
647 {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning |
|
648 __PRINT1(_L("CScanDrive::RecordClusterChainL #2 %d"),aCluster); |
|
649 IndicateErrorsFound(EInvalidEntrySize); |
|
650 User::Leave(KErrCorrupt); |
|
651 } |
600 } |
652 } |
601 SetUsedL(aCluster); |
653 |
|
654 //__PRINT1(_L("#--: %d -> EOC"), aCluster); |
|
655 MarkClusterUsedL(aCluster); |
602 return; |
656 return; |
603 } |
657 } |
604 else |
658 else |
605 { |
659 { |
606 TInt clusterVal=ReadFatL(aCluster); |
660 const TUint clusterVal=ReadFatL(aCluster); |
607 __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal!=0,User::Leave(KErrCorrupt)); |
661 |
608 SetUsedL(aCluster); |
662 //__PRINT2(_L("#--: %d -> %d"), aCluster, clusterVal); |
|
663 |
|
664 __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal !=KSpareCluster, User::Leave(KErrCorrupt)); |
|
665 MarkClusterUsedL(aCluster); |
609 aCluster=clusterVal; |
666 aCluster=clusterVal; |
610 --clusterCount; |
667 --clusterCount; |
611 } |
668 } |
612 } |
669 |
613 } |
670 }//while(clusterCount) |
614 |
671 } |
615 /** |
672 |
616 Move to dos entry, checking all vfat entry ID numbers are in sequence. |
673 //---------------------------------------------------------------------------------------------------- |
617 Assumes aEntry is not erased |
674 /** |
618 |
675 Move to dos entry, checking all vfat entry ID numbers are in sequence. |
619 @param aPos Position of the entry to move from, returns with new position |
676 Assumes aEntry is not erased |
620 @param aEntry The Dos entry after the Vfat entries on return |
677 |
621 @param aDirLength Running total of the length of the directory in entries |
678 @param aPos Position of the entry to move from, returns with new position |
622 @leave System wide error codes |
679 @param aEntry The Dos entry after the Vfat entries on return |
623 @return EFalse if not valid vfat entries or dos entry, else returns ETrue |
680 @param aDirLength Running total of the length of the directory in entries |
|
681 @leave System wide error codes |
|
682 @return EFalse if not valid vfat entries or dos entry, else returns ETrue |
624 */ |
683 */ |
625 TBool CScanDrive::MoveToVFatEndL(TEntryPos& aPos,TFatDirEntry& aEntry,TInt& aDirLength) |
684 TBool CScanDrive::MoveToVFatEndL(TEntryPos& aPos,TFatDirEntry& aEntry,TInt& aDirLength) |
626 { |
685 { |
627 __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos); |
686 __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos); |
628 if(!aEntry.IsVFatEntry()) |
687 if(!aEntry.IsVFatEntry()) |
629 return IsDosEntry(aEntry); |
688 return IsDosEntry(aEntry); |
|
689 |
630 TInt toFollow=aEntry.NumFollowing(); |
690 TInt toFollow=aEntry.NumFollowing(); |
631 __ASSERT_ALWAYS(toFollow>0&&!aEntry.IsErased(),User::Leave(KErrCorrupt)); |
691 __ASSERT_ALWAYS(toFollow>0 && !aEntry.IsErased(), User::Leave(KErrCorrupt)); |
|
692 |
632 FOREVER |
693 FOREVER |
633 { |
694 { |
634 MoveToNextEntryL(aPos); |
695 MoveToNextEntryL(aPos); |
635 ReadDirEntryL(aPos,aEntry); |
696 ReadDirEntryL(aPos,aEntry); |
636 ++aDirLength; |
697 ++aDirLength; |
637 --toFollow; |
698 --toFollow; |
638 if(!toFollow) |
699 if(!toFollow) |
639 break; |
700 break; |
640 if(!IsValidVFatEntry(aEntry,toFollow)) |
701 |
|
702 if(!IsValidVFatEntry(aEntry,toFollow)) |
641 return(EFalse); |
703 return(EFalse); |
642 } |
704 } |
643 return(IsDosEntry(aEntry)); |
705 |
644 } |
706 return(IsDosEntry(aEntry)); |
645 |
707 } |
646 /** |
708 |
647 Check if an entry is valid VFat |
709 //---------------------------------------------------------------------------------------------------- |
648 |
710 /** |
649 @param aEntry Entry to check |
711 Check if an entry is valid VFat |
650 @param aPrevNum Number into VFat entries for a dos entry to ensure in correct position |
712 |
651 @return ETrue if aEntry is a valid vfat entry |
713 @param aEntry Entry to check |
|
714 @param aPrevNum Number into VFat entries for a dos entry to ensure in correct position |
|
715 @return ETrue if aEntry is a valid vfat entry |
652 */ |
716 */ |
653 TBool CScanDrive::IsValidVFatEntry(const TFatDirEntry& aEntry,TInt aPrevNum)const |
717 TBool CScanDrive::IsValidVFatEntry(const TFatDirEntry& aEntry,TInt aPrevNum)const |
654 { |
718 { |
655 if(aEntry.IsErased()||!aEntry.IsVFatEntry()) |
719 if(aEntry.IsErased()||!aEntry.IsVFatEntry()) |
656 return(EFalse); |
720 return EFalse; |
|
721 |
657 return(aEntry.NumFollowing()==aPrevNum); |
722 return(aEntry.NumFollowing()==aPrevNum); |
658 } |
723 } |
659 |
724 |
660 /** |
725 //---------------------------------------------------------------------------------------------------- |
661 Check if an entry is a Dos entry |
726 /** |
662 |
727 Check if an entry is a Dos entry |
663 @param aEntry Entry to check |
728 |
664 @return ETrue if aEntry is a dos entry |
729 @param aEntry Entry to check |
|
730 @return ETrue if aEntry is a dos entry |
665 */ |
731 */ |
666 TBool CScanDrive::IsDosEntry(const TFatDirEntry& aEntry)const |
732 TBool CScanDrive::IsDosEntry(const TFatDirEntry& aEntry)const |
667 { |
733 { |
668 TBool res = !(aEntry.Attributes()&~KEntryAttMaskSupported) && !aEntry.IsErased() && !aEntry.IsVFatEntry() && !aEntry.IsEndOfDirectory(); |
734 TBool res = !(aEntry.Attributes()&~KEntryAttMaskSupported) && !aEntry.IsErased() && !aEntry.IsVFatEntry() && !aEntry.IsEndOfDirectory(); |
669 return res; |
735 return res; |
670 } |
736 } |
671 |
737 |
672 /** |
738 //---------------------------------------------------------------------------------------------------- |
673 Add partial entry to iPartEntry under the error condition of not all Vfat entries |
739 /** |
674 being present |
740 Add partial entry to iPartEntry under the error condition of not all Vfat entries being present |
675 |
741 |
676 @param aStartPos Position of the Dos entry associated with the VFat entries |
742 @param aStartPos Position of the Dos entry associated with the VFat entries |
677 @param aEntry Directory Entry of the Dos entry associated with the VFat entries |
743 @param aEntry Directory Entry of the Dos entry associated with the VFat entries |
678 @leave KErrCorrupt Occurs if the entry is not valid |
744 @leave KErrCorrupt Occurs if the entry is not valid |
679 */ |
745 */ |
680 void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry) |
746 void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry) |
681 { |
747 { |
682 __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos); |
748 __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos); |
683 __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt)); |
749 __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt)); |
684 iPartEntry.iEntryPos=aStartPos; |
750 iPartEntry.iEntryPos=aStartPos; |
685 iPartEntry.iEntry=aEntry; |
751 iPartEntry.iEntry=aEntry; |
686 iDirError=EScanPartEntry; |
752 iDirError=EScanPartEntry; |
687 } |
753 } |
688 |
754 |
689 /** |
755 //---------------------------------------------------------------------------------------------------- |
690 Add entry position to iMatching |
756 /** |
691 |
757 Add entry position to iMatching |
692 @param aEntryPos Position of the entry with the matching entry |
758 |
693 @leave KErrCorrupt if the start cluster is 0 or more that two matching entries occurs |
759 @param aEntryPos Position of the entry with the matching entry |
694 @return |
760 @leave KErrCorrupt if the start cluster is 0 or more that two matching entries occurs |
|
761 @return |
695 */ |
762 */ |
696 TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos) |
763 TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos) |
697 { |
764 { |
698 __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos); |
765 __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos); |
699 __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCount<KMaxMatchingEntries,User::Leave(KErrCorrupt)); |
766 __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCount<KMaxMatchingEntries,User::Leave(KErrCorrupt)); |
700 iMatching.iEntries[iMatching.iCount++]=aEntryPos; |
767 iMatching.iEntries[iMatching.iCount++]=aEntryPos; |
701 return iMatching.iCount==KMaxMatchingEntries; |
768 return iMatching.iCount==KMaxMatchingEntries; |
702 } |
769 } |
703 |
770 |
704 |
771 |
705 /** |
772 //---------------------------------------------------------------------------------------------------- |
706 Scan for differnces in the new and old FAT table writing them to media if discovered |
773 /** |
707 |
774 Scan for differnces in the new and old FAT table writing them to media if discovered |
708 @leave System wide error codes |
775 It is supposed to be called in 'ScanDrive' mode only |
709 */ |
776 |
710 void CScanDrive::WriteNewFatsL() |
777 @leave System wide error codes |
|
778 */ |
|
779 void CScanDrive::CompareAndFixFatsL() |
711 { |
780 { |
712 |
781 __PRINT1(_L("CScanDrive::CompareAndFixFatsL() drv:%d"),iMount->DriveNumber()); |
713 __PRINT1(_L("CScanDrive::WriteNewFatsL() drv:%d"),iMount->DriveNumber()); |
782 |
|
783 ASSERT(!CheckDiskMode()); |
714 |
784 |
715 TUint32 nClustersFixed = 0; //-- fixed clusters count |
785 TUint32 nClustersFixed = 0; //-- fixed clusters count |
716 TUint32 nBadClusters = 0; //-- bad cluster count |
786 TUint32 nBadClusters = 0; //-- bad cluster count |
717 TUint32 dirtyFatSector = 0; //-- FAT table media sector with not-flushed data |
787 TUint32 dirtyFatSector = 0; //-- FAT table media sector with not-flushed data |
718 |
788 |
820 ReadDirEntryL(aVFatPos,entry); |
891 ReadDirEntryL(aVFatPos,entry); |
821 } |
892 } |
822 return(entry.RuggedFatEntryId()); |
893 return(entry.RuggedFatEntryId()); |
823 } |
894 } |
824 |
895 |
825 /** |
896 //---------------------------------------------------------------------------------------------------- |
826 Erase part entry found in iPartEntry |
897 /** |
827 |
898 Erase part entry found in iPartEntry |
828 @leave System wide error code |
899 @leave System wide error code |
829 */ |
900 */ |
830 void CScanDrive::FixPartEntryL() |
901 void CScanDrive::FixPartEntryL() |
831 { |
902 { |
832 __PRINT2(_L("CScanDrive::FixPartEntryL cluster=%d,pos=%d"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos); |
903 __PRINT2(_L("CScanDrive::FixPartEntryL cluster=%d,pos=%d"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos); |
833 iMount->EraseDirEntryL(iPartEntry.iEntryPos,iPartEntry.iEntry); |
904 ASSERT(!CheckDiskMode()); |
834 IndicateErrorsFound(); //-- indicate that we have found errors |
905 iMount->EraseDirEntryL(iPartEntry.iEntryPos,iPartEntry.iEntry); |
|
906 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
835 } |
907 } |
836 |
908 |
837 /** |
909 //---------------------------------------------------------------------------------------------------- |
838 Delete entry with largest value in the reserved2 section(bytes 20 and 21) of dos entry |
910 /** |
839 |
911 Delete entry with largest value in the reserved2 section(bytes 20 and 21) of dos entry |
840 @leave System wide error code |
912 |
|
913 @leave System wide error code |
841 */ |
914 */ |
842 void CScanDrive::FixMatchingEntryL() |
915 void CScanDrive::FixMatchingEntryL() |
843 { |
916 { |
844 __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster); |
917 |
|
918 __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster); |
845 __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt)); |
919 __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt)); |
846 TInt idOne=GetReservedidL(iMatching.iEntries[0]); |
920 ASSERT(!CheckDiskMode()); |
|
921 |
|
922 TInt idOne=GetReservedidL(iMatching.iEntries[0]); |
847 TInt idTwo=GetReservedidL(iMatching.iEntries[1]); |
923 TInt idTwo=GetReservedidL(iMatching.iEntries[1]); |
848 TFatDirEntry entry; |
924 TFatDirEntry entry; |
849 TInt num=idOne>idTwo?0:1; |
925 TInt num=idOne>idTwo?0:1; |
850 ReadDirEntryL(iMatching.iEntries[num],entry); |
926 ReadDirEntryL(iMatching.iEntries[num],entry); |
851 iMount->EraseDirEntryL(iMatching.iEntries[num],entry); |
927 iMount->EraseDirEntryL(iMatching.iEntries[num],entry); |
852 IndicateErrorsFound(); //-- indicate that we have found errors |
928 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
853 } |
929 } |
854 /** |
930 |
855 Move past specified number of entries |
931 //---------------------------------------------------------------------------------------------------- |
856 |
932 /** |
857 @param aEntryPos Start position to move from, updated as move takes place |
933 Move past specified number of entries |
858 @param aEntry Directory entry moved to |
934 |
859 @param aToMove Number of entries to move through |
935 @param aEntryPos Start position to move from, updated as move takes place |
860 @param aDirEntries Number of entries moved, updated as move takes place |
936 @param aEntry Directory entry moved to |
861 @leave System wide error code |
937 @param aToMove Number of entries to move through |
|
938 @param aDirEntries Number of entries moved, updated as move takes place |
|
939 @leave System wide error code |
862 */ |
940 */ |
863 void CScanDrive::MovePastEntriesL(TEntryPos& aEntryPos,TFatDirEntry& aEntry,TInt aToMove,TInt& aDirEntries) |
941 void CScanDrive::MovePastEntriesL(TEntryPos& aEntryPos,TFatDirEntry& aEntry,TInt aToMove,TInt& aDirEntries) |
864 { |
942 { |
865 while(aToMove-- && aEntryPos.iCluster!=KEndOfDirectory) |
943 while(aToMove-- && !IsEofF(aEntryPos.iCluster)) |
866 { |
944 { |
867 MoveToNextEntryL(aEntryPos); |
945 MoveToNextEntryL(aEntryPos); |
868 ++aDirEntries; |
946 ++aDirEntries; |
869 } |
947 } |
870 ReadDirEntryL(aEntryPos,aEntry); |
948 ReadDirEntryL(aEntryPos,aEntry); |
871 } |
949 } |
872 |
950 |
873 /** |
951 //---------------------------------------------------------------------------------------------------- |
874 Adds aCluster to cluster list array so that it may be revisited later, avoids stack |
952 /** |
875 over flow |
953 Adds aCluster to cluster list array so that it may be revisited later, avoids stack |
876 |
954 over flow |
877 @param aCluster Directory cluster number to add to the list |
955 |
878 @leave KErrNoMemory If allocation fails |
956 @param aCluster Directory cluster number to add to the list |
|
957 @leave KErrNoMemory If allocation fails |
879 */ |
958 */ |
880 void CScanDrive::AddToClusterListL(TInt aCluster) |
959 void CScanDrive::AddToClusterListL(TInt aCluster) |
881 { |
960 { |
|
961 |
882 if(iListArrayIndex>=KMaxArrayDepth) |
962 if(iListArrayIndex>=KMaxArrayDepth) |
883 return; |
963 return; |
|
964 |
884 if(iClusterListArray[iListArrayIndex]==NULL) |
965 if(iClusterListArray[iListArrayIndex]==NULL) |
885 iClusterListArray[iListArrayIndex]=new(ELeave) RArray<TInt>(KClusterListGranularity); |
966 iClusterListArray[iListArrayIndex]=new(ELeave) RArray<TInt>(KClusterListGranularity); |
886 iClusterListArray[iListArrayIndex]->Append(aCluster); |
967 iClusterListArray[iListArrayIndex]->Append(aCluster); |
887 } |
968 } |
888 |
969 |
889 |
970 |
890 #if defined(DEBUG_SCANDRIVE) |
971 //---------------------------------------------------------------------------------------------------- |
891 /** |
972 /** |
892 Used for debug purposes only, compares new Fat and first Fat table, displays any differences |
973 Used in "CheckDisk" mode mostly. Compares first FAT table on the media with the FAT bitmap restored by walking the directory structure. |
893 and there meaning |
974 Displays any differences and records an error if found. |
894 |
975 |
895 @leave System wide error codes |
976 @param aStopOnFirstErrorFound if ETrue will stop after discovering first error (FATs discrepancy) |
896 */ |
977 |
897 void CScanDrive::CompareFatsL() const |
978 @leave System wide error codes |
|
979 */ |
|
980 void CScanDrive::CompareFatsL(TBool aStopOnFirstErrorFound) |
898 { |
981 { |
899 __PRINT(_L("CScanDrive::CompareFatsL()")); |
982 __PRINT1(_L("CScanDrive::CompareFatsL(%d)"), aStopOnFirstErrorFound); |
900 |
983 |
901 |
984 |
902 TUint32 diffPos; |
985 TUint32 diffPos; |
903 if(!iMediaFatBits.Diff(iScanFatBits, diffPos)) |
986 if(!iMediaFatBits.Diff(iScanFatBits, diffPos)) |
904 return; //-- FATs are identical |
987 return; //-- FATs are identical |
905 |
988 |
906 //-- there is a difference between the real FAT and reconstructed one. Find the mismaching bit and fix FAT. |
989 //-- there is a difference between the real FAT and reconstructed one. Find the mismaching bit and fix FAT. |
907 const TInt clusters = iMount->UsableClusters(); |
990 const TUint clusters = iMount->UsableClusters(); |
908 ASSERT(diffPos < (TUint32)clusters); |
991 ASSERT(diffPos < (TUint32)clusters); |
909 |
992 |
910 TInt scanusedcnt=0; |
993 TUint scanusedcnt=0; |
911 TInt mediausedcnt=0; |
994 TUint mediausedcnt=0; |
912 |
995 |
913 for(TInt i=diffPos; i<clusters; ++i) |
996 for(TUint i=diffPos; i<clusters; ++i) |
914 { |
997 { |
915 const TBool bRealFatEntry = iMediaFatBits[i]; |
998 const TBool bRealFatEntry = iMediaFatBits[i]; |
916 const TBool bNewFatEntry = iScanFatBits[i]; |
999 const TBool bNewFatEntry = iScanFatBits[i]; |
917 |
1000 |
918 if(BoolXOR(bRealFatEntry, bNewFatEntry)) |
1001 if(BoolXOR(bRealFatEntry, bNewFatEntry)) |
919 { |
1002 {//-- mismatch between FAT on the media and the FAT bitmap restored by walking directory structure |
920 if(bRealFatEntry && !bNewFatEntry) |
1003 |
921 { |
1004 if(bRealFatEntry) |
922 __PRINT1(_L("Lost cluster=%d\n"),i); |
1005 {//-- FAT[i] on the media is marked as occupied, but retored FAT bitmap shows that it is free |
|
1006 if(iMount->IsBadCluster(ReadFatL(i))) |
|
1007 continue; //-- this is a BAD cluster it can't be occupied by the FS object, OK. |
|
1008 |
|
1009 __PRINT2(_L("FAT[%d] = %d\n"), i, ReadFatL(i)); |
|
1010 __PRINT1(_L("iTruncationCluster = %d\n"), iTruncationCluster); |
|
1011 |
|
1012 //-- this is a lost cluster |
|
1013 if(!IsEofF(ReadFatL(i)) && (i==iTruncationCluster)) |
|
1014 {//-- seems to be a Rugged FAT ertefact |
|
1015 __PRINT1(_L("Hanging cluster = %d\n"),i); |
|
1016 } |
|
1017 else |
|
1018 { |
|
1019 __PRINT1(_L("Lost cluster=%d\n"),i); |
|
1020 } |
|
1021 |
|
1022 |
|
1023 IndicateErrorsFound(EBadClusterValue); |
923 } |
1024 } |
924 else if((bRealFatEntry && !IsEofF(ReadFatL(i))) && (i==iTruncationCluster)) |
1025 else |
925 { |
1026 {//-- FAT[i] on the media is marked as free, but retored FAT bitmap shows that it is occupied by some object |
926 __PRINT1(_L("Hanging cluster = %d\n"),i); |
1027 IndicateErrorsFound(EClusterAlreadyInUse); |
|
1028 __PRINT1(_L("Unflushed cluster = %d\n"),i); |
927 } |
1029 } |
928 else if(!bRealFatEntry && bNewFatEntry) |
1030 |
929 { |
1031 if(aStopOnFirstErrorFound) |
930 __PRINT1(_L("Unflushed cluster = %d\n"),i); |
1032 break; //-- not asked to check for errors further |
931 } |
1033 |
932 else |
1034 } |
933 User::Leave(KErrCorrupt); |
|
934 } |
|
935 |
1035 |
936 if(bRealFatEntry) |
1036 if(bRealFatEntry) |
937 mediausedcnt++; |
1037 mediausedcnt++; |
938 |
1038 |
939 if(bNewFatEntry) |
1039 if(bNewFatEntry) |
983 iMount->ReadDirEntryL(aPos, aDirEntry); |
1087 iMount->ReadDirEntryL(aPos, aDirEntry); |
984 } |
1088 } |
985 |
1089 |
986 |
1090 |
987 /** |
1091 /** |
988 Move to next directory entry, if anEntry is at the end of the cluster, and we are not |
1092 Move to next directory entry, if anEntry is at the end of the cluster, and we are not |
989 the root dir, move it to the next cluster in the chain. |
1093 the root dir, move it to the next cluster in the chain. |
990 |
1094 |
991 @param aPos Current directory position up dated to position of next entry. |
1095 @param aPos Current directory position up dated to position of next entry. |
992 @leave System wide error codes |
|
993 |
|
994 */ |
1096 */ |
995 void CScanDrive::MoveToNextEntryL(TEntryPos& aPos) |
1097 void CScanDrive::MoveToNextEntryL(TEntryPos& aPos) |
996 { |
1098 { |
997 //__PRINT(_L("CScanDrive::MoveToNextEntryL")); |
1099 //__PRINT(_L("CScanDrive::MoveToNextEntryL")); |
998 iMount->MoveToNextEntryL(aPos); |
1100 iMount->MoveToNextEntryL(aPos); |
999 } |
1101 } |
1000 |
1102 |
1001 /** |
1103 /** |
1002 Read a cluster from the Media Fat if scan run in a seperate thread read from scan fat table |
1104 Read a cluster from the Media Fat if scan run in a seperate thread read from scan fat table |
1003 otherwise read from mount owned Fat table |
1105 otherwise read from mount owned Fat table |
1004 |
1106 |
1005 @param aClusterNum Cluster to read |
1107 @param aClusterNum Cluster to read |
1006 @leave System wide error code |
1108 @return Value of cluster read from Fat |
1007 @return Value of cluster read from Fat |
1109 */ |
1008 */ |
1110 TUint32 CScanDrive::ReadFatL(TUint aClusterNum) |
1009 TUint32 CScanDrive::ReadFatL(TInt aClusterNum) const |
1111 { |
1010 { |
1112 if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters()) |
1011 return iMount->FAT().ReadL(aClusterNum); |
1113 { |
|
1114 IndicateErrorsFound(EBadClusterNumber); |
|
1115 User::Leave(KErrCorrupt); |
|
1116 } |
|
1117 |
|
1118 //-- actually, ReadL() can leave with some error code, that won't be reflected in IndicateErrorsFound(). |
|
1119 //-- it's possible to improve but is it worth it? |
|
1120 return iMount->FAT().ReadL(aClusterNum); |
1012 } |
1121 } |
1013 |
1122 |
1014 |
1123 |
1015 |
1124 /** |
1016 |
1125 Set a cluster as visited in the bit packed scan Fat |
1017 |
1126 @param aCluster Cluster number |
1018 |
1127 */ |
1019 |
1128 void CScanDrive::MarkClusterUsedL(TUint aClusterNum) |
1020 |
1129 { |
1021 |
1130 if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters()) |
1022 |
1131 { |
1023 |
1132 IndicateErrorsFound(EBadClusterNumber); |
|
1133 User::Leave(KErrCorrupt); |
|
1134 } |
|
1135 |
|
1136 iScanFatBits.SetBit(aClusterNum); |
|
1137 } |
|
1138 |
|
1139 |
|
1140 /** |
|
1141 Query whether a cluster is already set as used |
|
1142 @param aCluster Cluster to query |
|
1143 */ |
|
1144 TBool CScanDrive::IsClusterUsedL(TUint aClusterNum) |
|
1145 { |
|
1146 if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters()) |
|
1147 { |
|
1148 IndicateErrorsFound(EBadClusterNumber); |
|
1149 User::Leave(KErrCorrupt); |
|
1150 } |
|
1151 |
|
1152 return iScanFatBits[aClusterNum]; |
|
1153 } |
|
1154 |
|
1155 /** |
|
1156 @param aPos Position in a directory cluster |
|
1157 @return ETrue if aPos is the last entry in the root directory |
|
1158 */ |
|
1159 TBool CScanDrive::IsEndOfRootDir(const TEntryPos& aPos)const |
|
1160 { |
|
1161 return(iMount->IsRootDir(aPos)&&(iMount->StartOfRootDirInBytes()+aPos.iPos==(iMount->RootDirEnd()-KSizeOfFatDirEntry))); |
|
1162 } |
|
1163 |
|
1164 /** |
|
1165 @param aVal Value of the cluster to be tested |
|
1166 @return ETrue if aVal is the end of cluster marker |
|
1167 */ |
|
1168 TBool CScanDrive::IsEofF(TInt aVal) const |
|
1169 { |
|
1170 return iMount->IsEndOfClusterCh(aVal); |
|
1171 } |
|
1172 |
|
1173 /** @return max. number of clusters on the volume being scanned */ |
|
1174 TUint32 CScanDrive::MaxClusters() const |
|
1175 { |
|
1176 ASSERT(iMaxClusters); |
|
1177 return iMaxClusters; |
|
1178 } |
|
1179 |
|
1180 /** @return ETrue in we are operating in "CheckDisk" mode*/ |
|
1181 TBool CScanDrive::CheckDiskMode() const |
|
1182 { |
|
1183 return iScanDriveMode == ECheckDisk; |
|
1184 } |
|
1185 |
|
1186 |
|
1187 |
|
1188 |
|
1189 |
|
1190 |
|
1191 |
|
1192 |
|
1193 |