sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32\sfat\sl_scan.cpp sl@0: // ScanDrive code, specific for EFAT.FSY sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: */ sl@0: sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: //!! sl@0: //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it sl@0: //!! sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: sl@0: sl@0: //#define DEBUG_SCANDRIVE sl@0: sl@0: #include "sl_std.h" sl@0: #include "sl_scandrv.h" sl@0: sl@0: const TInt KEndOfDirectory = 0xFFFF; ///< End of directory marker sl@0: const TInt KMaxScanDepth = 20; ///< Maximum scan depth of to avoid stack over flow sl@0: const TInt KClusterListGranularity = 8; ///< Granularity of cluster list used for storage of clusters when KMaxScanDepth is reached sl@0: sl@0: /** sl@0: Creates a CScanDrive sl@0: sl@0: @param aMount The owning mount sl@0: */ sl@0: CScanDrive* CScanDrive::NewL(CFatMountCB* aMount) sl@0: { sl@0: if(aMount==NULL) sl@0: User::Leave(KErrArgument); sl@0: CScanDrive* self=new (ELeave) CScanDrive(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aMount); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: CScanDrive::CScanDrive() sl@0: // sl@0: // Constructor sl@0: // sl@0: { sl@0: } sl@0: sl@0: sl@0: CScanDrive::~CScanDrive() sl@0: // sl@0: // Destructor sl@0: // sl@0: { sl@0: delete iNewFat; sl@0: for(TInt i=0;iClose(); sl@0: delete iClusterListArray[i]; sl@0: } sl@0: } sl@0: sl@0: sl@0: void CScanDrive::ConstructL(CFatMountCB* aMount) sl@0: // sl@0: // Create the new fat and initalise sl@0: // sl@0: { sl@0: iMount=aMount; sl@0: iNewFat=CCheckFatTable::NewL(aMount); sl@0: iNewFat->InitializeL(); sl@0: } sl@0: sl@0: sl@0: TBool CScanDrive::AlreadyExistsL(TInt aCluster)const sl@0: // sl@0: // Return ETrue if aCluster in the new fat contains a non-zero entry sl@0: // sl@0: { sl@0: return(iNewFat->ReadL(aCluster)!=0); sl@0: } sl@0: sl@0: sl@0: TBool CScanDrive::IsEndOfRootDir(const TEntryPos& aPos)const sl@0: // sl@0: // Return ETrue if aPos is the last entry in the root directory sl@0: // sl@0: { sl@0: return(iMount->IsRootDir(aPos)&&(iMount->StartOfRootDirInBytes()+aPos.iPos==(iMount->RootDirEnd()-KSizeOfFatDirEntry))); sl@0: } sl@0: sl@0: /** sl@0: @param aVal Value of the cluster to be tested sl@0: @return ETrue if aVal is the end of cluster marker sl@0: */ sl@0: TBool CScanDrive::IsEofF(TInt aVal)const sl@0: { sl@0: return iMount->IsEndOfClusterCh(aVal); sl@0: } sl@0: sl@0: /** sl@0: @return True if a directory error has been found sl@0: */ sl@0: TBool CScanDrive::IsDirError()const sl@0: { sl@0: return(iDirError!=0); sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: After StartL() and finishing allows us to know if there were any problems at all. sl@0: The client may wish to remount the filesystem if there were errors. sl@0: sl@0: @return EFalse if there were no problems in FS. sl@0: */ sl@0: TBool CScanDrive::ProblemsDiscovered() const sl@0: { sl@0: return IsDirError() || iFoundProblems; sl@0: } sl@0: sl@0: /** sl@0: Sets the flag indicating than there are errors in filesystem structure sl@0: See ProblemsDiscovered() sl@0: */ sl@0: void CScanDrive::IndicateErrorsFound() sl@0: { sl@0: iFoundProblems = ETrue; sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: Start point for scan drive also fixes up errors sl@0: sl@0: @return The result of the scan sl@0: @leave sl@0: */ sl@0: TInt CScanDrive::StartL() sl@0: { sl@0: __PRINT(_L("CScanDrive::StartL")); sl@0: // check directory structure sl@0: CheckDirStructureL(); sl@0: #if defined(DEBUG_SCANDRIVE) sl@0: CompareFatsL(); sl@0: #endif sl@0: // fix error in directory structure sl@0: if(IsDirError()) sl@0: FixupDirErrorL(); sl@0: // flush new fat sl@0: WriteNewFatsL(); sl@0: #if defined(DEBUG_SCANDRIVE) sl@0: PrintErrors(); sl@0: #endif sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Fix errors detected by the drive scan sl@0: sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::FixupDirErrorL() sl@0: { sl@0: if(!IsDirError()) sl@0: return; sl@0: if(iDirError==EScanMatchingEntry) sl@0: { sl@0: FindSameStartClusterL(); sl@0: FixMatchingEntryL(); sl@0: } sl@0: else sl@0: { sl@0: FixPartEntryL(); sl@0: } sl@0: sl@0: IndicateErrorsFound(); //-- indicate that we have found errors sl@0: } sl@0: sl@0: /** sl@0: Find positions of entries with same start cluster for error correction, searches sl@0: the whole volume. Starts at the root directory. sl@0: sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::FindSameStartClusterL() sl@0: { sl@0: TInt err=FindStartClusterL(0); sl@0: if(err==KErrNone) sl@0: return; sl@0: for(TInt i=0;i* clusterList=iClusterListArray[i]; sl@0: for(TInt j=0;jCount();++j) sl@0: { sl@0: iRecursiveDepth=0; sl@0: err=FindStartClusterL((*clusterList)[j]); sl@0: if(err==KErrNone) sl@0: return; sl@0: } sl@0: } sl@0: __ASSERT_ALWAYS(err==KErrNone,User::Leave(KErrNotFound)); sl@0: } sl@0: /** sl@0: Scan through directory structure looking for start cluster found in iMatching sl@0: sl@0: @param aDirCluster Start cluster for scan to start sl@0: @return System wide error value sl@0: @leave sl@0: */ sl@0: TInt CScanDrive::FindStartClusterL(TInt aDirCluster) sl@0: { sl@0: __PRINT1(_L("CScanDrive::FindStartCluster dirCluster=%d"),aDirCluster); sl@0: __ASSERT_ALWAYS(aDirCluster>=0,User::Leave(KErrCorrupt)); sl@0: if(++iRecursiveDepth==KMaxScanDepth) sl@0: { sl@0: --iRecursiveDepth; sl@0: return(KErrNotFound); sl@0: } sl@0: TEntryPos entryPos(aDirCluster,0); sl@0: TInt dirEntries=0; sl@0: FOREVER sl@0: { sl@0: TFatDirEntry entry; sl@0: iMount->ReadDirEntryL(entryPos,entry); sl@0: if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased()) sl@0: { sl@0: if(IsEndOfRootDir(entryPos)) sl@0: break; sl@0: iMount->MoveToNextEntryL(entryPos); sl@0: continue; sl@0: } sl@0: if(entry.IsEndOfDirectory()) sl@0: break; sl@0: TBool isComplete; sl@0: TEntryPos vfatPos=entryPos; sl@0: isComplete=MoveToVFatEndL(entryPos,entry,dirEntries); sl@0: __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName)); sl@0: TInt err=CheckEntryClusterL(entry,vfatPos); sl@0: if(err==KErrNone) sl@0: { sl@0: --iRecursiveDepth; sl@0: return(err); sl@0: } sl@0: if(IsEndOfRootDir(entryPos)) sl@0: break; sl@0: iMount->MoveToNextEntryL(entryPos); sl@0: } sl@0: --iRecursiveDepth; sl@0: return(KErrNotFound); sl@0: } sl@0: sl@0: /** sl@0: Procces aEntry to find matching start cluster sl@0: sl@0: @param aEntry Directory entry to check sl@0: @param aEntryPos Position of directory to check sl@0: @return System wide error value sl@0: @leave sl@0: */ sl@0: TInt CScanDrive::CheckEntryClusterL(const TFatDirEntry& aEntry, const TEntryPos& aEntryPos) sl@0: { sl@0: __PRINT(_L("CScanDrive::CheckEntryClusterL")); sl@0: if(iMount->StartCluster(aEntry)==iMatching.iStartCluster) sl@0: { sl@0: TBool complete=AddMatchingEntryL(aEntryPos); sl@0: if(complete) sl@0: return(KErrNone); sl@0: } sl@0: else if(aEntry.Attributes()&KEntryAttDir) sl@0: return(FindStartClusterL(iMount->StartCluster(aEntry))); sl@0: return(KErrNotFound); sl@0: } sl@0: sl@0: /** sl@0: Checks directory strucutre for errors, can be considered the start point of the scan. sl@0: Handles recursion depth to avoid stack overflow. sl@0: sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::CheckDirStructureL() sl@0: { sl@0: CheckDirL(iMount->RootIndicator()); sl@0: // Due to recursive nature of CheckDirL when a depth of sl@0: // KMaxScanDepth is reached clusters are stored in a list sl@0: // and passed into CheckDirL afresh sl@0: for(TInt i=0;i* clusterList=iClusterListArray[i]; sl@0: ++iListArrayIndex; sl@0: for(TInt j=0;jCount();++j) sl@0: { sl@0: iRecursiveDepth=0; sl@0: CheckDirL((*clusterList)[j]); sl@0: } sl@0: } sl@0: } sl@0: /** sl@0: Function is called recursively with Process entry untill the whole volume has been scanned. sl@0: Each directory entry is scanned for errors, these are recorded for later fixing. sl@0: sl@0: @param aCluster Directory cluster to start checking sl@0: @leave System wide error codes sl@0: */ sl@0: void CScanDrive::CheckDirL(TInt aCluster) sl@0: { sl@0: __PRINT1(_L("CScanDrive::CheckDirL aCluster=%d"),aCluster); sl@0: __ASSERT_ALWAYS(aCluster>=0,User::Leave(KErrCorrupt)); sl@0: // check depth of recursion sl@0: if(++iRecursiveDepth==KMaxScanDepth) sl@0: { sl@0: AddToClusterListL(aCluster); sl@0: --iRecursiveDepth; sl@0: return; sl@0: } sl@0: #if defined(DEBUG_SCANDRIVE) sl@0: ++iDirsChecked; sl@0: #endif sl@0: TEntryPos entryPos(aCluster,0); sl@0: TInt dirEntries=0; sl@0: FOREVER sl@0: { sl@0: TFatDirEntry entry; sl@0: iMount->ReadDirEntryL(entryPos,entry); sl@0: if(!iMount->IsEndOfClusterCh(entryPos.iCluster)) sl@0: ++dirEntries; sl@0: if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased()) sl@0: { sl@0: if(IsEndOfRootDir(entryPos)) sl@0: break; sl@0: iMount->MoveToNextEntryL(entryPos); sl@0: continue; sl@0: } sl@0: if(entry.IsEndOfDirectory()) sl@0: { sl@0: if(aCluster) sl@0: WriteClusterChainL(aCluster,dirEntries< directories. sl@0: if (!isComplete && origEntry.IsVFatEntry()) sl@0: { sl@0: AddPartialVFatL(origPos,origEntry); sl@0: if(entryPos.iCluster!=KEndOfDirectory) sl@0: { sl@0: TInt toMove=origEntry.NumFollowing()-(dirEntries-origDirEntries); sl@0: if(toMove) sl@0: MovePastEntriesL(entryPos,entry,toMove,dirEntries); sl@0: } sl@0: else sl@0: { sl@0: // we fell off the end of the directory file, so just strip this sl@0: // incomplete long file name entry sl@0: dirEntries = origDirEntries; sl@0: } sl@0: } sl@0: else sl@0: ProcessEntryL(entry); sl@0: if(IsEndOfRootDir(entryPos)) sl@0: break; sl@0: iMount->MoveToNextEntryL(entryPos); sl@0: } sl@0: --iRecursiveDepth; sl@0: } sl@0: sl@0: /** sl@0: Process non trivial entries, such as files, if they are correct by filling out their sl@0: cluster allocation in the bit packed Fat table. If it comes accross a directory sl@0: CheckDirL will be called. sl@0: sl@0: @param aEntry Directory entry to check sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry) sl@0: { sl@0: __PRINT(_L("CScanDrive::ProcessEntryL")); sl@0: TInt entryAtt=aEntry.Attributes(); sl@0: __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt)); sl@0: if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0) sl@0: WriteClusterChainL(iMount->StartCluster(aEntry),aEntry.Size()); sl@0: else if(entryAtt&KEntryAttDir) sl@0: CheckDirL(iMount->StartCluster(aEntry)); sl@0: } sl@0: sl@0: /** sl@0: Writes out the cluster chain for a correct file or directory, checks that the cluster sl@0: has not already been used and that the correct number of clusters are allocated for the sl@0: size of file. Registers cluster as used if correct sl@0: sl@0: @param aCluster Cluster chain start point sl@0: @param aSizeInBytes Size of the file or directory in bytes sl@0: @leave System wide error values sl@0: */ sl@0: void CScanDrive::WriteClusterChainL(TInt aCluster,TInt aSizeInBytes) sl@0: // sl@0: // Mark off in the new fat the clusters used by entry with start cluster of aCluster sl@0: // sl@0: { sl@0: sl@0: IndicateErrorsFound(); //-- indicate that we have found errors sl@0: sl@0: __PRINT1(_L("CScanDrive::WriteClusterChainL starting at %d"),aCluster); sl@0: __ASSERT_ALWAYS(aCluster>0 && aSizeInBytes>=0,User::Leave(KErrCorrupt)); sl@0: TInt clusterCount; sl@0: if(aSizeInBytes==0) sl@0: clusterCount=1; sl@0: else sl@0: clusterCount=(aSizeInBytes+(1<ClusterSizeLog2())-1)>>iMount->ClusterSizeLog2(); sl@0: TInt startCluster=aCluster; sl@0: while(clusterCount) sl@0: { sl@0: if(AlreadyExistsL(aCluster)) sl@0: { sl@0: __ASSERT_ALWAYS(!IsDirError()&&iMatching.iStartCluster==0&&aCluster==startCluster,User::Leave(KErrCorrupt)); sl@0: iMatching.iStartCluster=aCluster; sl@0: iDirError=EScanMatchingEntry; sl@0: return; sl@0: } sl@0: if(clusterCount==1) sl@0: { sl@0: iNewFat->WriteFatEntryEofFL(aCluster); sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: TInt clusterVal; sl@0: clusterVal=iMount->FAT().ReadL(aCluster); sl@0: __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal!=0,User::Leave(KErrCorrupt)); sl@0: iNewFat->WriteL(aCluster,clusterVal); sl@0: aCluster=clusterVal; sl@0: --clusterCount; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Move to dos entry, checking all vfat entry ID numbers are in sequence. sl@0: Assumes aEntry is not erased sl@0: sl@0: @param aPos Position of the entry to move from, returns with new position sl@0: @param aEntry The Dos entry after the Vfat entries on return sl@0: @param aDirLength Running total of the length of the directory in entries sl@0: @leave System wide error codes sl@0: @return EFalse if not valid vfat entries or dos entry, else returns ETrue sl@0: */ sl@0: TBool CScanDrive::MoveToVFatEndL(TEntryPos& aPos,TFatDirEntry& aEntry,TInt& aDirLength) sl@0: { sl@0: __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos); sl@0: if(!aEntry.IsVFatEntry()) sl@0: return IsDosEntry(aEntry); sl@0: TInt toFollow=aEntry.NumFollowing(); sl@0: __ASSERT_ALWAYS(toFollow>0&&!aEntry.IsErased(),User::Leave(KErrCorrupt)); sl@0: FOREVER sl@0: { sl@0: iMount->MoveToNextEntryL(aPos); sl@0: iMount->ReadDirEntryL(aPos,aEntry); sl@0: ++aDirLength; sl@0: --toFollow; sl@0: if(!toFollow) sl@0: break; sl@0: if(!IsValidVFatEntry(aEntry,toFollow)) sl@0: return(EFalse); sl@0: } sl@0: return(IsDosEntry(aEntry)); sl@0: } sl@0: sl@0: /** sl@0: Check if an entry is valid VFat sl@0: sl@0: @param aEntry Entry to check sl@0: @param aPrevNum Number into VFat entries for a dos entry to ensure in correct position sl@0: @return ETrue if aEntry is a valid vfat entry sl@0: */ sl@0: TBool CScanDrive::IsValidVFatEntry(const TFatDirEntry& aEntry, TInt aPrevNum)const sl@0: { sl@0: if(aEntry.IsErased()||!aEntry.IsVFatEntry()) sl@0: return(EFalse); sl@0: return(aEntry.NumFollowing()==aPrevNum); sl@0: } sl@0: sl@0: /** sl@0: Check if an entry is a Dos entry sl@0: sl@0: @param aEntry Entry to check sl@0: @return ETrue if aEntry is a dos entry sl@0: */ sl@0: TBool CScanDrive::IsDosEntry(const TFatDirEntry& aEntry)const sl@0: { sl@0: TBool res = !(aEntry.Attributes()&~KEntryAttMaskSupported) && !aEntry.IsErased() && !aEntry.IsVFatEntry() && !aEntry.IsEndOfDirectory(); sl@0: return res; sl@0: } sl@0: sl@0: /** sl@0: Add partial entry to iPartEntry under the error condition of not all Vfat entries sl@0: being present sl@0: sl@0: @param aStartPos Position of the Dos entry associated with the VFat entries sl@0: @param aEntry Directory Entry of the Dos entry associated with the VFat entries sl@0: @leave KErrCorrupt Occurs if the entry is not valid sl@0: */ sl@0: void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry) sl@0: { sl@0: __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos); sl@0: __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt)); sl@0: iPartEntry.iEntryPos=aStartPos; sl@0: iPartEntry.iEntry=aEntry; sl@0: iDirError=EScanPartEntry; sl@0: } sl@0: sl@0: /** sl@0: Add entry position to iMatching sl@0: sl@0: @param aEntryPos Position of the entry with the matching entry sl@0: @leave KErrCorrupt if the start cluster is 0 or more that two matching entries occurs sl@0: @return sl@0: */ sl@0: TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos) sl@0: { sl@0: __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos); sl@0: __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCountFlushL()) sl@0: IndicateErrorsFound(); //-- indicate that we have found errors sl@0: } sl@0: sl@0: TInt CScanDrive::GetReservedidL(TEntryPos aVFatPos) sl@0: // sl@0: // Return the id found in reserved2 field of dos entry sl@0: // sl@0: { sl@0: __PRINT(_L("CScanDrive::GetReservedidL")); sl@0: TFatDirEntry entry; sl@0: iMount->ReadDirEntryL(aVFatPos,entry); sl@0: if(!IsDosEntry(entry)) sl@0: { sl@0: TInt toMove=entry.NumFollowing(); sl@0: while(toMove--) sl@0: iMount->MoveToNextEntryL(aVFatPos); sl@0: iMount->ReadDirEntryL(aVFatPos,entry); sl@0: } sl@0: return(entry.RuggedFatEntryId()); sl@0: } sl@0: sl@0: /** sl@0: Erase part entry found in iPartEntry sl@0: sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::FixPartEntryL() sl@0: { sl@0: __PRINT2(_L("CScanDrive::FixPartEntryL cluster=%d,pos=%d"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos); sl@0: iMount->EraseDirEntryL(iPartEntry.iEntryPos,iPartEntry.iEntry); sl@0: IndicateErrorsFound(); //-- indicate that we have found errors sl@0: } sl@0: sl@0: /** sl@0: Delete entry with largest value in the reserved2 section(bytes 20 and 21) of dos entry sl@0: sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::FixMatchingEntryL() sl@0: { sl@0: __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster); sl@0: __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt)); sl@0: TInt idOne=GetReservedidL(iMatching.iEntries[0]); sl@0: TInt idTwo=GetReservedidL(iMatching.iEntries[1]); sl@0: TFatDirEntry entry; sl@0: TInt num=idOne>idTwo?0:1; sl@0: iMount->ReadDirEntryL(iMatching.iEntries[num],entry); sl@0: iMount->EraseDirEntryL(iMatching.iEntries[num],entry); sl@0: IndicateErrorsFound(); //-- indicate that we have found errors sl@0: } sl@0: /** sl@0: Move past specified number of entries sl@0: sl@0: @param aEntryPos Start position to move from, updated as move takes place sl@0: @param aEntry Directory entry moved to sl@0: @param aToMove Number of entries to move through sl@0: @param aDirEntries Number of entries moved, updated as move takes place sl@0: @leave System wide error code sl@0: */ sl@0: void CScanDrive::MovePastEntriesL(TEntryPos& aEntryPos,TFatDirEntry& aEntry,TInt aToMove,TInt& aDirEntries) sl@0: { sl@0: while(aToMove-- && aEntryPos.iCluster!=KEndOfDirectory) sl@0: { sl@0: iMount->MoveToNextEntryL(aEntryPos); sl@0: ++aDirEntries; sl@0: } sl@0: iMount->ReadDirEntryL(aEntryPos,aEntry); sl@0: } sl@0: sl@0: /** sl@0: Adds aCluster to cluster list array so that it may be revisited later, avoids stack sl@0: over flow sl@0: sl@0: @param aCluster Directory cluster number to add to the list sl@0: @leave KErrNoMemory If allocation fails sl@0: */ sl@0: void CScanDrive::AddToClusterListL(TInt aCluster) sl@0: { sl@0: if(iListArrayIndex>=KMaxArrayDepth) sl@0: return; sl@0: if(iClusterListArray[iListArrayIndex]==NULL) sl@0: iClusterListArray[iListArrayIndex]=new(ELeave) RArray(KClusterListGranularity); sl@0: iClusterListArray[iListArrayIndex]->Append(aCluster); sl@0: } sl@0: sl@0: sl@0: #if defined(DEBUG_SCANDRIVE) sl@0: void CScanDrive::CompareFatsL() sl@0: // sl@0: // Compare new fat and first fat table sl@0: // sl@0: { sl@0: __PRINT(_L("CScanDrive::CompareFatsL()")); sl@0: TInt maxClusters; sl@0: maxClusters=iMount->UsableClusters(); sl@0: for(TInt i=KFatFirstSearchCluster; iFAT().ReadL(i); sl@0: TInt newFat=iNewFat->ReadL(i); sl@0: if(realFat!=newFat) sl@0: { sl@0: if(realFat!=0 && newFat==0) sl@0: __PRINT1(_L("Lost cluster=%d\n"),i) sl@0: else if((realFat>0 && !IsEofF(realFat)) && IsEofF(newFat)) sl@0: __PRINT1(_L("Hanging cluster = %d\n"),i) sl@0: else if(realFat==0 && newFat>0) sl@0: __PRINT1(_L("Unflushed cluster = %d\n"),i) sl@0: else sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: For debug purposes, print errors found as debug output sl@0: sl@0: */ sl@0: void CScanDrive::PrintErrors() sl@0: { sl@0: __PRINT1(_L("Directories visisted = %d\n"),iDirsChecked); sl@0: if(iDirError==EScanPartEntry) sl@0: __PRINT2(_L("Part entry-dir cluster=%d,dir pos=%d,\n"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos) sl@0: else if(iDirError==EScanMatchingEntry) sl@0: { sl@0: __PRINT1(_L("Matching cluster - cluster no=%d\n"),iMatching.iStartCluster); sl@0: __PRINT2(_L("\tcluster 1 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[0].iCluster,iMatching.iEntries[0].iPos); sl@0: __PRINT2(_L("\tcluster 2 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[1].iCluster,iMatching.iEntries[1].iPos); sl@0: } sl@0: } sl@0: sl@0: #endif sl@0: sl@0: sl@0: sl@0: