275 //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
275 //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
276 //__PRINT1(_L("#@@@ CScanDrive #1:%d ms "), elapsedTime); |
276 //__PRINT1(_L("#@@@ CScanDrive #1:%d ms "), elapsedTime); |
277 |
277 |
278 CheckDirStructureL(); |
278 CheckDirStructureL(); |
279 |
279 |
280 //-- uncomments a line below if you need to compare real and restored FAT tables and print out all differences |
280 //-- uncomment a line below if you need to compare real and restored FAT tables and print out all differences |
281 //CompareFatsL(EFalse); |
281 //CompareFatsL(EFalse); |
282 |
282 |
283 //timeEnd.UniversalTime(); //-- take end time |
283 //timeEnd.UniversalTime(); //-- take end time |
284 //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
284 //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
285 //__PRINT1(_L("#@@@ CScanDrive #2:%d ms "), elapsedTime); |
285 //__PRINT1(_L("#@@@ CScanDrive #2:%d ms "), elapsedTime); |
361 if(err==KErrNone) |
361 if(err==KErrNone) |
362 return; |
362 return; |
363 } |
363 } |
364 } |
364 } |
365 |
365 |
366 __ASSERT_ALWAYS(err==KErrNone,User::Leave(KErrNotFound)); |
366 if(err != KErrNone) |
|
367 { |
|
368 __PRINT1(_L("CScanDrive::FindSameStartClusterL() #1 %d"), err); |
|
369 User::Leave(KErrNotFound); |
|
370 } |
367 } |
371 } |
368 |
372 |
369 //---------------------------------------------------------------------------------------------------- |
373 //---------------------------------------------------------------------------------------------------- |
370 /** |
374 /** |
371 Scan through directory structure looking for start cluster found in iMatching |
375 Scan through directory structure looking for start cluster found in iMatching |
372 |
376 |
373 @param aDirCluster Start cluster for scan to start |
377 @param aDirCluster Start cluster for scan to start |
374 @return System wide error value |
378 @return System wide error value |
375 @leave |
379 @leave |
376 */ |
380 */ |
377 TInt CScanDrive::FindStartClusterL(TInt aDirCluster) |
381 TInt CScanDrive::FindStartClusterL(TUint32 aDirCluster) |
378 { |
382 { |
379 __PRINT1(_L("CScanDrive::FindStartCluster dirCluster=%d"),aDirCluster); |
383 __PRINT1(_L("CScanDrive::FindStartCluster dirCluster=%d"),aDirCluster); |
380 __ASSERT_ALWAYS(aDirCluster>=iMount->RootIndicator(),User::Leave(KErrCorrupt)); |
384 |
|
385 if(aDirCluster < (TUint)iMount->RootIndicator() || aDirCluster >= MaxClusters()) |
|
386 { |
|
387 __PRINT(_L("CScanDrive::FindStartCluster() #!\n")); |
|
388 IndicateErrorsFound(EBadClusterNumber); |
|
389 User::Leave(KErrCorrupt); |
|
390 } |
|
391 |
|
392 |
381 if(++iRecursiveDepth==KMaxScanDepth) |
393 if(++iRecursiveDepth==KMaxScanDepth) |
382 { |
394 { |
383 --iRecursiveDepth; |
395 --iRecursiveDepth; |
384 return(KErrNotFound); |
396 return(KErrNotFound); |
385 } |
397 } |
|
398 |
386 TEntryPos entryPos(aDirCluster,0); |
399 TEntryPos entryPos(aDirCluster,0); |
387 TInt dirEntries=0; |
400 TInt dirEntries=0; |
388 FOREVER |
401 |
|
402 for(;;) |
389 { |
403 { |
390 TFatDirEntry entry; |
404 TFatDirEntry entry; |
391 ReadDirEntryL(entryPos,entry); |
405 ReadDirEntryL(entryPos,entry); |
|
406 |
392 if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased()) |
407 if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased()) |
393 { |
408 { |
394 if(IsEndOfRootDir(entryPos)) |
409 if(IsEndOfRootDir(entryPos)) |
395 break; |
410 break; |
396 MoveToNextEntryL(entryPos); |
411 MoveToNextEntryL(entryPos); |
397 continue; |
412 continue; |
398 } |
413 } |
|
414 |
399 if(entry.IsEndOfDirectory()) |
415 if(entry.IsEndOfDirectory()) |
400 break; |
416 break; |
401 TBool isComplete; |
417 |
402 TEntryPos vfatPos=entryPos; |
418 TEntryPos vfatPos=entryPos; |
403 isComplete=MoveToVFatEndL(entryPos,entry,dirEntries); |
419 const TBool isComplete = MoveToVFatEndL(entryPos,entry,dirEntries); |
404 __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName)); |
420 |
|
421 if(!isComplete) |
|
422 { |
|
423 __PRINT(_L("CScanDrive::FindStartCluster() #2\n")); |
|
424 IndicateErrorsFound(EEntrySetIncomplete); |
|
425 User::Leave(KErrBadName); |
|
426 } |
|
427 |
405 |
428 |
406 TInt err=CheckEntryClusterL(entry,vfatPos); |
429 TInt err=CheckEntryClusterL(entry,vfatPos); |
407 if(err==KErrNone) |
430 if(err==KErrNone) |
408 { |
431 { |
409 --iRecursiveDepth; |
432 --iRecursiveDepth; |
524 |
547 |
525 const TBool isComplete = MoveToVFatEndL(entryPos,entry,dirEntries); |
548 const TBool isComplete = MoveToVFatEndL(entryPos,entry,dirEntries); |
526 |
549 |
527 if(!isComplete && CheckDiskMode()) |
550 if(!isComplete && CheckDiskMode()) |
528 {//-- broken VFAT entryset; in CheckDisk mode this is the FS error, abort further activity |
551 {//-- broken VFAT entryset; in CheckDisk mode this is the FS error, abort further activity |
|
552 __PRINT(_L("CScanDrive::CheckDirL() #1")); |
529 IndicateErrorsFound(EInvalidEntrySize); |
553 IndicateErrorsFound(EInvalidEntrySize); |
530 User::Leave(KErrCorrupt); |
554 User::Leave(KErrCorrupt); |
531 } |
555 } |
532 |
556 |
533 // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set; |
557 // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set; |
575 @leave System wide error code |
599 @leave System wide error code |
576 */ |
600 */ |
577 void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry) |
601 void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry) |
578 { |
602 { |
579 __PRINT(_L("CScanDrive::ProcessEntryL")); |
603 __PRINT(_L("CScanDrive::ProcessEntryL")); |
580 TInt entryAtt=aEntry.Attributes(); |
604 const TUint entryAtt=aEntry.Attributes(); |
581 |
605 |
582 __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt)); |
606 if((entryAtt & ~KEntryAttMaskSupported) || aEntry.IsErased()) |
|
607 { |
|
608 __PRINT1(_L("CScanDrive::ProcessEntryL() wrong entry att: 0x%x"), entryAtt); |
|
609 IndicateErrorsFound(EEntryBadAtt); |
|
610 User::Leave(KErrCorrupt); |
|
611 } |
583 |
612 |
584 if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0) |
613 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 |
614 {//-- this is a file with length >0. Check that its cluster chain corresponds to its size |
586 RecordClusterChainL(iMount->StartCluster(aEntry),(TUint) aEntry.Size()); |
615 RecordClusterChainL(iMount->StartCluster(aEntry), aEntry.Size()); |
587 } |
616 } |
588 else if(entryAtt&KEntryAttDir) |
617 else if(entryAtt&KEntryAttDir) |
589 {//-- this is the directory, walk into it |
618 {//-- this is the directory, walk into it |
590 CheckDirL(iMount->StartCluster(aEntry)); |
619 CheckDirL(iMount->StartCluster(aEntry)); |
591 } |
620 } |
599 |
628 |
600 @param aCluster Cluster chain start point |
629 @param aCluster Cluster chain start point |
601 @param aSizeInBytes Size of the file or directory in bytes |
630 @param aSizeInBytes Size of the file or directory in bytes |
602 @leave System wide error values |
631 @leave System wide error values |
603 */ |
632 */ |
604 void CScanDrive::RecordClusterChainL(TInt aCluster, TUint aSizeInBytes) |
633 void CScanDrive::RecordClusterChainL(TUint32 aCluster, TUint aSizeInBytes) |
605 { |
634 { |
606 __PRINT2(_L("CScanDrive::RecordClusterChainL() cl:%d, sz:%d") ,aCluster, aSizeInBytes); |
635 __PRINT2(_L("CScanDrive::RecordClusterChainL() cl:%d, sz:%d") ,aCluster, aSizeInBytes); |
607 __ASSERT_ALWAYS(aCluster>0, User::Leave(KErrCorrupt)); |
636 |
|
637 if(aCluster < KFatFirstSearchCluster || aCluster >= MaxClusters()) |
|
638 { |
|
639 __PRINT(_L("CScanDrive::RecordClusterChainL() #0")); |
|
640 IndicateErrorsFound(EBadClusterNumber); |
|
641 User::Leave(KErrCorrupt); |
|
642 } |
608 |
643 |
609 TUint clusterCount; |
644 TUint clusterCount; |
610 |
645 |
611 if(aSizeInBytes==0) |
646 if(aSizeInBytes==0) |
|
647 { |
612 clusterCount=1; |
648 clusterCount=1; |
|
649 } |
613 else |
650 else |
614 { |
651 { |
615 const TUint64 tmp = aSizeInBytes + Pow2_64(iMount->ClusterSizeLog2()) - 1; |
652 const TUint64 tmp = aSizeInBytes + Pow2_64(iMount->ClusterSizeLog2()) - 1; |
616 clusterCount = (TUint) (tmp >> iMount->ClusterSizeLog2()); |
653 clusterCount = (TUint) (tmp >> iMount->ClusterSizeLog2()); |
617 } |
654 } |
618 |
655 |
619 TInt startCluster=aCluster; |
656 TUint startCluster=aCluster; |
|
657 |
620 while(clusterCount) |
658 while(clusterCount) |
621 { |
659 { |
622 if(IsClusterUsedL(aCluster)) |
660 if(IsClusterUsedL(aCluster)) |
623 {//-- this cluster already seems to belong to some other object; crosslinked cluster chain. Can't fix it. |
661 {//-- this cluster already seems to belong to some other object; crosslinked cluster chain. Can't fix it. |
624 if(CheckDiskMode()) |
662 __PRINT1(_L("CScanDrive::RecordClusterChainL #1 %d"),aCluster); |
|
663 |
|
664 if(CheckDiskMode()) |
625 {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning |
665 {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning |
626 __PRINT1(_L("CScanDrive::RecordClusterChainL #1 %d"),aCluster); |
666 __PRINT(_L("CScanDrive::RecordClusterChainL #1.1")); |
627 IndicateErrorsFound(EClusterAlreadyInUse); |
667 IndicateErrorsFound(EClusterAlreadyInUse); |
628 User::Leave(KErrCorrupt); |
668 User::Leave(KErrCorrupt); |
629 } |
669 } |
630 |
670 |
631 __ASSERT_ALWAYS(!IsDirError() && iMatching.iStartCluster==0 && aCluster==startCluster,User::Leave(KErrCorrupt)); |
671 |
|
672 if(IsDirError() || iMatching.iStartCluster > 0 || aCluster != startCluster) |
|
673 {//-- secondary entry into this state |
|
674 __PRINT(_L("CScanDrive::RecordClusterChainL #1.2")); |
|
675 IndicateErrorsFound(EClusterAlreadyInUse); |
|
676 User::Leave(KErrCorrupt); |
|
677 } |
|
678 |
632 iMatching.iStartCluster=aCluster; |
679 iMatching.iStartCluster=aCluster; |
633 iDirError=EScanMatchingEntry; //ERROR POINT |
680 iDirError=EScanMatchingEntry; //ERROR POINT |
634 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
681 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
635 return; |
682 return; |
636 } |
683 } |
637 |
684 |
638 |
685 |
639 if(clusterCount==1) |
686 if(clusterCount==1) |
640 { |
687 {//-- we have reached the end of the cluster chain |
641 if(!iMount->IsEndOfClusterCh(ReadFatL(aCluster))) |
688 if(!iMount->IsEndOfClusterCh(ReadFatL(aCluster))) |
642 {//-- seems to be a rugged FAT artefact; File truncation had failed before and now file length is less than |
689 {//-- seems to be a rugged FAT artefact; File truncation/extension had failed before and now file length is less than |
643 //-- the corresponding cluster chain shall be. It will be truncated. |
690 //-- the corresponding cluster chain shall be. It will be truncated to the size recorded in file DOS entry. |
644 iTruncationCluster = aCluster; |
691 iTruncationCluster = aCluster; |
645 |
692 |
646 if(CheckDiskMode()) |
693 if(CheckDiskMode()) |
647 {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning |
694 {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning |
648 __PRINT1(_L("CScanDrive::RecordClusterChainL #2 %d"),aCluster); |
695 __PRINT1(_L("CScanDrive::RecordClusterChainL #2 %d"),aCluster); |
658 else |
705 else |
659 { |
706 { |
660 const TUint clusterVal=ReadFatL(aCluster); |
707 const TUint clusterVal=ReadFatL(aCluster); |
661 |
708 |
662 //__PRINT2(_L("#--: %d -> %d"), aCluster, clusterVal); |
709 //__PRINT2(_L("#--: %d -> %d"), aCluster, clusterVal); |
663 |
710 if(IsEofF(clusterVal) || clusterVal == KSpareCluster ) |
664 __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal !=KSpareCluster, User::Leave(KErrCorrupt)); |
711 {//-- unexpected end of the cluster chain (it is shorter than recorded in file dir. entry) |
|
712 __PRINT1(_L("CScanDrive::RecordClusterChainL #3 %d"),clusterVal); |
|
713 IndicateErrorsFound(EBadClusterValue); |
|
714 User::Leave(KErrCorrupt); |
|
715 } |
|
716 |
|
717 |
665 MarkClusterUsedL(aCluster); |
718 MarkClusterUsedL(aCluster); |
666 aCluster=clusterVal; |
719 aCluster=clusterVal; |
667 --clusterCount; |
720 --clusterCount; |
668 } |
721 } |
669 |
722 |
686 __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos); |
739 __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos); |
687 if(!aEntry.IsVFatEntry()) |
740 if(!aEntry.IsVFatEntry()) |
688 return IsDosEntry(aEntry); |
741 return IsDosEntry(aEntry); |
689 |
742 |
690 TInt toFollow=aEntry.NumFollowing(); |
743 TInt toFollow=aEntry.NumFollowing(); |
691 __ASSERT_ALWAYS(toFollow>0 && !aEntry.IsErased(), User::Leave(KErrCorrupt)); |
744 |
692 |
745 if(toFollow <=0 || aEntry.IsErased()) |
693 FOREVER |
746 { |
|
747 __PRINT1(_L("CScanDrive::MoveToVFatEndL #1 %d"),toFollow); |
|
748 IndicateErrorsFound(EEntrySetIncomplete); |
|
749 User::Leave(KErrCorrupt); |
|
750 } |
|
751 |
|
752 |
|
753 for(;;) |
694 { |
754 { |
695 MoveToNextEntryL(aPos); |
755 MoveToNextEntryL(aPos); |
696 ReadDirEntryL(aPos,aEntry); |
756 ReadDirEntryL(aPos,aEntry); |
697 ++aDirLength; |
757 ++aDirLength; |
698 --toFollow; |
758 --toFollow; |
744 @leave KErrCorrupt Occurs if the entry is not valid |
804 @leave KErrCorrupt Occurs if the entry is not valid |
745 */ |
805 */ |
746 void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry) |
806 void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry) |
747 { |
807 { |
748 __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos); |
808 __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos); |
749 __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt)); |
809 |
|
810 if(IsDirError()) |
|
811 { |
|
812 __PRINT(_L("CScanDrive::AddPartialVFatL #1")); |
|
813 User::Leave(KErrCorrupt); |
|
814 } |
|
815 |
750 iPartEntry.iEntryPos=aStartPos; |
816 iPartEntry.iEntryPos=aStartPos; |
751 iPartEntry.iEntry=aEntry; |
817 iPartEntry.iEntry=aEntry; |
752 iDirError=EScanPartEntry; |
818 iDirError=EScanPartEntry; |
753 } |
819 } |
754 |
820 |
761 @return |
827 @return |
762 */ |
828 */ |
763 TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos) |
829 TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos) |
764 { |
830 { |
765 __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos); |
831 __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos); |
766 __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCount<KMaxMatchingEntries,User::Leave(KErrCorrupt)); |
832 |
|
833 if(iMatching.iStartCluster <= 0 || iMatching.iCount >= KMaxMatchingEntries) |
|
834 { |
|
835 __PRINT(_L("CScanDrive::AddMatchingEntryL #1")); |
|
836 User::Leave(KErrCorrupt); |
|
837 } |
|
838 |
|
839 |
767 iMatching.iEntries[iMatching.iCount++]=aEntryPos; |
840 iMatching.iEntries[iMatching.iCount++]=aEntryPos; |
768 return iMatching.iCount==KMaxMatchingEntries; |
841 return iMatching.iCount==KMaxMatchingEntries; |
769 } |
842 } |
770 |
843 |
771 |
844 |
884 TFatDirEntry entry; |
957 TFatDirEntry entry; |
885 ReadDirEntryL(aVFatPos,entry); |
958 ReadDirEntryL(aVFatPos,entry); |
886 if(!IsDosEntry(entry)) |
959 if(!IsDosEntry(entry)) |
887 { |
960 { |
888 TInt toMove=entry.NumFollowing(); |
961 TInt toMove=entry.NumFollowing(); |
|
962 |
889 while(toMove--) |
963 while(toMove--) |
890 MoveToNextEntryL(aVFatPos); |
964 MoveToNextEntryL(aVFatPos); |
|
965 |
891 ReadDirEntryL(aVFatPos,entry); |
966 ReadDirEntryL(aVFatPos,entry); |
892 } |
967 } |
|
968 |
893 return(entry.RuggedFatEntryId()); |
969 return(entry.RuggedFatEntryId()); |
894 } |
970 } |
895 |
971 |
896 //---------------------------------------------------------------------------------------------------- |
972 //---------------------------------------------------------------------------------------------------- |
897 /** |
973 /** |
914 */ |
990 */ |
915 void CScanDrive::FixMatchingEntryL() |
991 void CScanDrive::FixMatchingEntryL() |
916 { |
992 { |
917 |
993 |
918 __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster); |
994 __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster); |
919 __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt)); |
995 |
|
996 if(iMatching.iCount != KMaxMatchingEntries) |
|
997 { |
|
998 __PRINT1(_L("CScanDrive::FixMatchingEntryL() #1 %d"), iMatching.iCount); |
|
999 User::Leave(KErrCorrupt); |
|
1000 } |
|
1001 |
920 ASSERT(!CheckDiskMode()); |
1002 ASSERT(!CheckDiskMode()); |
921 |
1003 |
922 TInt idOne=GetReservedidL(iMatching.iEntries[0]); |
1004 const TInt idOne=GetReservedidL(iMatching.iEntries[0]); |
923 TInt idTwo=GetReservedidL(iMatching.iEntries[1]); |
1005 const TInt idTwo=GetReservedidL(iMatching.iEntries[1]); |
924 TFatDirEntry entry; |
1006 TFatDirEntry entry; |
925 TInt num=idOne>idTwo?0:1; |
1007 |
|
1008 const TInt num = idOne>idTwo ? 0:1; |
926 ReadDirEntryL(iMatching.iEntries[num],entry); |
1009 ReadDirEntryL(iMatching.iEntries[num],entry); |
|
1010 |
927 iMount->EraseDirEntryL(iMatching.iEntries[num],entry); |
1011 iMount->EraseDirEntryL(iMatching.iEntries[num],entry); |
|
1012 |
928 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
1013 IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors |
929 } |
1014 } |
930 |
1015 |
931 //---------------------------------------------------------------------------------------------------- |
1016 //---------------------------------------------------------------------------------------------------- |
932 /** |
1017 /** |