os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_scan.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfat\sl_scan.cpp
    15 // ScanDrive code, specific for EFAT.FSY
    16 // 
    17 //
    18 
    19 /**
    20  @file
    21  @internalTechnology
    22 */
    23 
    24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    25 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    26 //!!
    27 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
    28 //!!
    29 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    30 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    31 
    32 
    33 //#define DEBUG_SCANDRIVE
    34 
    35 #include "sl_std.h"
    36 #include "sl_scandrv.h"
    37 
    38 const TInt KEndOfDirectory          = 0xFFFF;   ///< End of directory marker
    39 const TInt KMaxScanDepth            = 20;       ///< Maximum scan depth of to avoid stack over flow 
    40 const TInt KClusterListGranularity  = 8;        ///< Granularity of cluster list used for storage of clusters when KMaxScanDepth is reached
    41 
    42 /**
    43 Creates a CScanDrive
    44 
    45 @param aMount The owning mount
    46 */
    47 CScanDrive* CScanDrive::NewL(CFatMountCB* aMount)
    48     {
    49     if(aMount==NULL)
    50         User::Leave(KErrArgument);
    51     CScanDrive* self=new (ELeave) CScanDrive();
    52     CleanupStack::PushL(self);
    53     self->ConstructL(aMount);
    54     CleanupStack::Pop();
    55     return self;
    56     }
    57 
    58 
    59 CScanDrive::CScanDrive()
    60 //
    61 // Constructor
    62 //
    63     {
    64     }
    65 
    66 
    67 CScanDrive::~CScanDrive()
    68 //
    69 // Destructor
    70 //
    71     {
    72     delete iNewFat;
    73     for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
    74         {
    75         iClusterListArray[i]->Close();
    76         delete iClusterListArray[i];
    77         }
    78     }
    79 
    80 
    81 void CScanDrive::ConstructL(CFatMountCB* aMount)
    82 //
    83 // Create the new fat and initalise
    84 //
    85     {
    86     iMount=aMount;
    87     iNewFat=CCheckFatTable::NewL(aMount);
    88     iNewFat->InitializeL();
    89     }
    90 
    91 
    92 TBool CScanDrive::AlreadyExistsL(TInt aCluster)const
    93 //
    94 //  Return ETrue if aCluster in the new fat contains a non-zero entry
    95 //
    96     {
    97     return(iNewFat->ReadL(aCluster)!=0);
    98     }
    99 
   100 
   101 TBool CScanDrive::IsEndOfRootDir(const TEntryPos& aPos)const
   102 //
   103 // Return ETrue if aPos is the last entry in the root directory
   104 //
   105     {
   106     return(iMount->IsRootDir(aPos)&&(iMount->StartOfRootDirInBytes()+aPos.iPos==(iMount->RootDirEnd()-KSizeOfFatDirEntry)));
   107     }
   108 
   109 /**
   110 @param aVal Value of the cluster to be tested
   111 @return ETrue if aVal is the end of cluster marker
   112 */
   113 TBool CScanDrive::IsEofF(TInt aVal)const 
   114     {
   115     return iMount->IsEndOfClusterCh(aVal);
   116     }
   117 
   118 /**
   119 @return True if a directory error has been found
   120 */
   121 TBool CScanDrive::IsDirError()const
   122     {
   123     return(iDirError!=0);
   124     }
   125 
   126 
   127 
   128 /**
   129     After StartL() and finishing allows us to know if there were any problems at all.
   130     The client may wish to remount the filesystem if there were errors.
   131 
   132     @return EFalse if there were no problems in FS.
   133 */
   134 TBool CScanDrive::ProblemsDiscovered() const
   135 {
   136     return IsDirError() || iFoundProblems;
   137 }
   138 
   139 /**
   140     Sets the flag indicating than there are errors in filesystem structure
   141     See ProblemsDiscovered()
   142 */
   143 void CScanDrive::IndicateErrorsFound()
   144 {
   145     iFoundProblems = ETrue;
   146 }
   147 
   148 
   149 
   150 /**
   151 Start point for scan drive also fixes up errors 
   152 
   153 @return The result of the scan
   154 @leave 
   155 */
   156 TInt CScanDrive::StartL()
   157     {
   158     __PRINT(_L("CScanDrive::StartL"));
   159     // check directory structure
   160     CheckDirStructureL();
   161 #if defined(DEBUG_SCANDRIVE)
   162     CompareFatsL();
   163 #endif
   164     // fix error in directory structure
   165     if(IsDirError())
   166         FixupDirErrorL();
   167     // flush new fat
   168     WriteNewFatsL();
   169 #if defined(DEBUG_SCANDRIVE)
   170     PrintErrors();
   171 #endif
   172     return KErrNone;
   173     }
   174 
   175 /**
   176 Fix errors detected by the drive scan
   177 
   178 @leave System wide error code
   179 */
   180 void CScanDrive::FixupDirErrorL()
   181     {
   182     if(!IsDirError())
   183         return;
   184     if(iDirError==EScanMatchingEntry)
   185         {
   186         FindSameStartClusterL();
   187         FixMatchingEntryL();
   188         }
   189     else
   190         {
   191         FixPartEntryL();
   192         }
   193 
   194     IndicateErrorsFound(); //-- indicate that we have found errors
   195     }
   196 
   197 /**
   198 Find positions of entries with same start cluster for error correction, searches
   199 the whole volume. Starts at the root directory. 
   200 
   201 @leave System wide error code
   202 */
   203 void CScanDrive::FindSameStartClusterL()
   204     {
   205     TInt err=FindStartClusterL(0);
   206     if(err==KErrNone)
   207         return;
   208     for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
   209         {
   210         RArray<TInt>* clusterList=iClusterListArray[i];
   211         for(TInt j=0;j<clusterList->Count();++j)
   212             {
   213             iRecursiveDepth=0;
   214             err=FindStartClusterL((*clusterList)[j]);
   215             if(err==KErrNone)
   216                 return;
   217             }
   218         }
   219     __ASSERT_ALWAYS(err==KErrNone,User::Leave(KErrNotFound));
   220     }
   221 /**
   222 Scan through directory structure looking for start cluster found in iMatching
   223 
   224 @param aDirCluster Start cluster for scan to start
   225 @return System wide error value
   226 @leave 
   227 */
   228 TInt CScanDrive::FindStartClusterL(TInt aDirCluster)
   229     {
   230     __PRINT1(_L("CScanDrive::FindStartCluster dirCluster=%d"),aDirCluster);
   231     __ASSERT_ALWAYS(aDirCluster>=0,User::Leave(KErrCorrupt));
   232     if(++iRecursiveDepth==KMaxScanDepth)
   233         {
   234         --iRecursiveDepth;
   235         return(KErrNotFound);
   236         }
   237     TEntryPos entryPos(aDirCluster,0);
   238     TInt dirEntries=0;
   239     FOREVER
   240         {
   241         TFatDirEntry entry;
   242         iMount->ReadDirEntryL(entryPos,entry);
   243         if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased())
   244             {
   245             if(IsEndOfRootDir(entryPos))
   246                 break;
   247             iMount->MoveToNextEntryL(entryPos);
   248             continue;
   249             }
   250         if(entry.IsEndOfDirectory())
   251             break;
   252         TBool isComplete;
   253         TEntryPos vfatPos=entryPos;
   254         isComplete=MoveToVFatEndL(entryPos,entry,dirEntries);
   255         __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName));
   256         TInt err=CheckEntryClusterL(entry,vfatPos);
   257         if(err==KErrNone)
   258             {
   259             --iRecursiveDepth;
   260             return(err);
   261             }
   262         if(IsEndOfRootDir(entryPos))
   263             break;
   264         iMount->MoveToNextEntryL(entryPos);
   265         }
   266     --iRecursiveDepth;
   267     return(KErrNotFound);
   268     }
   269 
   270 /**
   271 Procces aEntry to find matching start cluster
   272 
   273 @param aEntry Directory entry to check
   274 @param aEntryPos Position of directory to check
   275 @return System wide error value
   276 @leave 
   277 */
   278 TInt CScanDrive::CheckEntryClusterL(const TFatDirEntry& aEntry, const TEntryPos& aEntryPos)
   279     {
   280     __PRINT(_L("CScanDrive::CheckEntryClusterL"));
   281     if(iMount->StartCluster(aEntry)==iMatching.iStartCluster)
   282         {
   283         TBool complete=AddMatchingEntryL(aEntryPos);
   284         if(complete)
   285             return(KErrNone);
   286         }
   287     else if(aEntry.Attributes()&KEntryAttDir)
   288         return(FindStartClusterL(iMount->StartCluster(aEntry)));
   289     return(KErrNotFound);
   290     }
   291 
   292 /**
   293 Checks directory strucutre for errors, can be considered the start point of the scan.  
   294 Handles recursion depth to avoid stack overflow.
   295 
   296 @leave System wide error code
   297 */
   298 void CScanDrive::CheckDirStructureL()
   299     {
   300     CheckDirL(iMount->RootIndicator());
   301     // Due to recursive nature of CheckDirL when a depth of
   302     // KMaxScanDepth is reached clusters are stored in a list
   303     // and passed into CheckDirL afresh
   304     for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
   305         {
   306         RArray<TInt>* clusterList=iClusterListArray[i];
   307         ++iListArrayIndex;
   308         for(TInt j=0;j<clusterList->Count();++j)
   309             {
   310             iRecursiveDepth=0;
   311             CheckDirL((*clusterList)[j]);
   312             }
   313         }
   314     }
   315 /**
   316 Function is called recursively with Process entry untill the whole volume has been scanned.
   317 Each directory entry is scanned for errors, these are recorded for later fixing. 
   318 
   319 @param aCluster Directory cluster to start checking
   320 @leave System wide error codes
   321 */
   322 void CScanDrive::CheckDirL(TInt aCluster)
   323     {
   324     __PRINT1(_L("CScanDrive::CheckDirL aCluster=%d"),aCluster);
   325     __ASSERT_ALWAYS(aCluster>=0,User::Leave(KErrCorrupt));
   326     // check depth of recursion
   327     if(++iRecursiveDepth==KMaxScanDepth)
   328         {
   329         AddToClusterListL(aCluster);
   330         --iRecursiveDepth;
   331         return;
   332         }
   333 #if defined(DEBUG_SCANDRIVE)
   334     ++iDirsChecked;
   335 #endif
   336     TEntryPos entryPos(aCluster,0);
   337     TInt dirEntries=0;
   338     FOREVER
   339         {
   340         TFatDirEntry entry;
   341         iMount->ReadDirEntryL(entryPos,entry);
   342         if(!iMount->IsEndOfClusterCh(entryPos.iCluster))
   343             ++dirEntries;
   344         if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased())
   345             {
   346             if(IsEndOfRootDir(entryPos))
   347                 break;
   348             iMount->MoveToNextEntryL(entryPos);
   349             continue;
   350             }
   351         if(entry.IsEndOfDirectory())
   352             {
   353             if(aCluster)    
   354                 WriteClusterChainL(aCluster,dirEntries<<KSizeOfFatDirEntryLog2);
   355             break;
   356             }
   357         TEntryPos origPos=entryPos;
   358         TFatDirEntry origEntry=entry;
   359         TInt origDirEntries=dirEntries;
   360         TBool isComplete;
   361         isComplete=MoveToVFatEndL(entryPos,entry,dirEntries);
   362         // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set; 
   363         // assuming a non-VFAT corrupted entry is a VFAT entry is dangerous as we then assume that the 
   364         // first byte is a count of entries to skip, thus completely invalidating the next <n> directories.
   365         if (!isComplete && origEntry.IsVFatEntry())
   366             {
   367             AddPartialVFatL(origPos,origEntry);
   368             if(entryPos.iCluster!=KEndOfDirectory)
   369                 {
   370                 TInt toMove=origEntry.NumFollowing()-(dirEntries-origDirEntries);
   371                 if(toMove)
   372                     MovePastEntriesL(entryPos,entry,toMove,dirEntries);
   373                 }
   374             else
   375                 {
   376                 // we fell off the end of the directory file, so just strip this
   377                 // incomplete long file name entry
   378                 dirEntries = origDirEntries;
   379                 }
   380             }
   381         else
   382             ProcessEntryL(entry);
   383         if(IsEndOfRootDir(entryPos))
   384             break;
   385         iMount->MoveToNextEntryL(entryPos);
   386         }
   387     --iRecursiveDepth;
   388     }
   389 
   390 /**
   391 Process non trivial entries, such as files, if they are correct by filling out their 
   392 cluster allocation in the bit packed Fat table. If it comes accross a directory 
   393 CheckDirL will be called.
   394 
   395 @param aEntry Directory entry to check
   396 @leave System wide error code
   397 */
   398 void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry)
   399     {
   400     __PRINT(_L("CScanDrive::ProcessEntryL"));
   401     TInt entryAtt=aEntry.Attributes();
   402     __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt));
   403     if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0)
   404         WriteClusterChainL(iMount->StartCluster(aEntry),aEntry.Size());
   405     else if(entryAtt&KEntryAttDir)
   406         CheckDirL(iMount->StartCluster(aEntry));
   407     }
   408 
   409 /**
   410 Writes out the cluster chain for a correct file or directory, checks that the cluster 
   411 has not already been used and that the correct number of clusters are allocated for the 
   412 size of file. Registers cluster as used if correct
   413 
   414 @param aCluster Cluster chain start point
   415 @param aSizeInBytes Size of the file or directory in bytes
   416 @leave System wide error values
   417 */
   418 void CScanDrive::WriteClusterChainL(TInt aCluster,TInt aSizeInBytes)
   419 //
   420 // Mark off in the new fat the clusters used by entry with start cluster of aCluster
   421 //
   422     {
   423 
   424     IndicateErrorsFound(); //-- indicate that we have found errors
   425 
   426     __PRINT1(_L("CScanDrive::WriteClusterChainL starting at %d"),aCluster);
   427     __ASSERT_ALWAYS(aCluster>0 && aSizeInBytes>=0,User::Leave(KErrCorrupt));
   428     TInt clusterCount;
   429     if(aSizeInBytes==0)
   430         clusterCount=1;
   431     else
   432         clusterCount=(aSizeInBytes+(1<<iMount->ClusterSizeLog2())-1)>>iMount->ClusterSizeLog2();
   433     TInt startCluster=aCluster;
   434     while(clusterCount)
   435         {
   436         if(AlreadyExistsL(aCluster))
   437             {
   438             __ASSERT_ALWAYS(!IsDirError()&&iMatching.iStartCluster==0&&aCluster==startCluster,User::Leave(KErrCorrupt));
   439             iMatching.iStartCluster=aCluster;
   440             iDirError=EScanMatchingEntry;
   441             return;
   442             }
   443         if(clusterCount==1)
   444             {
   445             iNewFat->WriteFatEntryEofFL(aCluster);
   446             return;
   447             }
   448         else
   449             {
   450             TInt clusterVal;
   451             clusterVal=iMount->FAT().ReadL(aCluster);
   452             __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal!=0,User::Leave(KErrCorrupt));
   453             iNewFat->WriteL(aCluster,clusterVal);
   454             aCluster=clusterVal;
   455             --clusterCount;
   456             }
   457         }
   458     }
   459 
   460 /**
   461 Move to dos entry, checking all vfat entry ID numbers are in sequence.
   462 Assumes aEntry is not erased
   463 
   464 @param aPos Position of the entry to move from, returns with new position
   465 @param aEntry The Dos entry after the Vfat entries on return
   466 @param aDirLength Running total of the length of the directory in entries
   467 @leave System wide error codes
   468 @return EFalse if not valid vfat entries or dos entry, else returns ETrue
   469 */
   470 TBool CScanDrive::MoveToVFatEndL(TEntryPos& aPos,TFatDirEntry& aEntry,TInt& aDirLength)
   471     {
   472     __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos);
   473     if(!aEntry.IsVFatEntry())
   474         return IsDosEntry(aEntry);
   475     TInt toFollow=aEntry.NumFollowing();
   476     __ASSERT_ALWAYS(toFollow>0&&!aEntry.IsErased(),User::Leave(KErrCorrupt));
   477     FOREVER
   478         {
   479         iMount->MoveToNextEntryL(aPos);
   480         iMount->ReadDirEntryL(aPos,aEntry);
   481         ++aDirLength;
   482         --toFollow;
   483         if(!toFollow)
   484             break;
   485         if(!IsValidVFatEntry(aEntry,toFollow))
   486             return(EFalse);
   487         }
   488     return(IsDosEntry(aEntry));
   489     }
   490 
   491 /**
   492 Check if an entry is valid VFat
   493 
   494 @param aEntry Entry to check
   495 @param aPrevNum Number into VFat entries for a dos entry to ensure in correct position
   496 @return ETrue if aEntry is a valid vfat entry
   497 */
   498 TBool CScanDrive::IsValidVFatEntry(const TFatDirEntry& aEntry, TInt aPrevNum)const
   499     {
   500     if(aEntry.IsErased()||!aEntry.IsVFatEntry())
   501         return(EFalse);
   502     return(aEntry.NumFollowing()==aPrevNum);
   503     }
   504 
   505 /**
   506 Check if an entry is a Dos entry
   507 
   508 @param aEntry Entry to check
   509 @return ETrue if aEntry is a dos entry
   510 */
   511 TBool CScanDrive::IsDosEntry(const TFatDirEntry& aEntry)const
   512     {
   513     TBool res = !(aEntry.Attributes()&~KEntryAttMaskSupported) && !aEntry.IsErased() && !aEntry.IsVFatEntry() && !aEntry.IsEndOfDirectory();
   514     return res;
   515     } 
   516 
   517 /**
   518 Add partial entry to iPartEntry under the error condition of not all Vfat entries 
   519 being present
   520 
   521 @param aStartPos Position of the Dos entry associated with the VFat entries
   522 @param aEntry Directory Entry of the Dos entry associated with the VFat entries
   523 @leave KErrCorrupt Occurs if the entry is not valid
   524 */
   525 void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry)
   526     {
   527     __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos);
   528     __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt));
   529     iPartEntry.iEntryPos=aStartPos;
   530     iPartEntry.iEntry=aEntry;
   531     iDirError=EScanPartEntry;
   532     }
   533 
   534 /**
   535 Add entry position to iMatching
   536 
   537 @param aEntryPos Position of the entry with the matching entry
   538 @leave KErrCorrupt if the start cluster is 0 or more that two matching entries occurs
   539 @return 
   540 */
   541 TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos)
   542     {
   543     __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos);
   544     __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCount<KMaxMatchingEntries,User::Leave(KErrCorrupt));
   545     iMatching.iEntries[iMatching.iCount++]=aEntryPos;
   546     return iMatching.iCount==KMaxMatchingEntries;
   547     }
   548 
   549 
   550 /**
   551 Scan for differnces in the new and old FAT table writing them to media if discovered
   552 
   553 @leave System wide error codes
   554 */
   555 void CScanDrive::WriteNewFatsL()
   556 //
   557 // Write the new fat table to disk
   558 //
   559     {
   560     if(iNewFat->FlushL())
   561         IndicateErrorsFound(); //-- indicate that we have found errors       
   562     }
   563 
   564 TInt CScanDrive::GetReservedidL(TEntryPos aVFatPos)
   565 //
   566 // Return the id found in reserved2 field of dos entry
   567 //
   568     {
   569     __PRINT(_L("CScanDrive::GetReservedidL"));
   570     TFatDirEntry entry;
   571     iMount->ReadDirEntryL(aVFatPos,entry);
   572     if(!IsDosEntry(entry))
   573         {
   574         TInt toMove=entry.NumFollowing();
   575         while(toMove--)
   576             iMount->MoveToNextEntryL(aVFatPos);
   577         iMount->ReadDirEntryL(aVFatPos,entry);
   578         }
   579     return(entry.RuggedFatEntryId());
   580     }
   581 
   582 /**
   583 Erase part entry found in iPartEntry
   584 
   585 @leave System wide error code
   586 */
   587 void CScanDrive::FixPartEntryL()
   588     {
   589     __PRINT2(_L("CScanDrive::FixPartEntryL cluster=%d,pos=%d"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos);
   590     iMount->EraseDirEntryL(iPartEntry.iEntryPos,iPartEntry.iEntry);
   591     IndicateErrorsFound(); //-- indicate that we have found errors
   592     }
   593     
   594 /**
   595 Delete entry with largest value in the reserved2 section(bytes 20 and 21) of dos entry
   596     
   597 @leave System wide error code
   598 */
   599 void CScanDrive::FixMatchingEntryL()
   600     {
   601     __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster);
   602     __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt));
   603     TInt idOne=GetReservedidL(iMatching.iEntries[0]);
   604     TInt idTwo=GetReservedidL(iMatching.iEntries[1]);
   605     TFatDirEntry entry;
   606     TInt num=idOne>idTwo?0:1;
   607     iMount->ReadDirEntryL(iMatching.iEntries[num],entry);
   608     iMount->EraseDirEntryL(iMatching.iEntries[num],entry);
   609     IndicateErrorsFound(); //-- indicate that we have found errors
   610     }
   611 /**
   612 Move past specified number of entries
   613 
   614 @param aEntryPos Start position to move from, updated as move takes place
   615 @param aEntry Directory entry moved to
   616 @param aToMove Number of entries to move through
   617 @param aDirEntries Number of entries moved, updated as move takes place
   618 @leave System wide error code
   619 */
   620 void CScanDrive::MovePastEntriesL(TEntryPos& aEntryPos,TFatDirEntry& aEntry,TInt aToMove,TInt& aDirEntries)
   621     {
   622     while(aToMove-- && aEntryPos.iCluster!=KEndOfDirectory)
   623         {
   624         iMount->MoveToNextEntryL(aEntryPos);
   625         ++aDirEntries;
   626         }
   627     iMount->ReadDirEntryL(aEntryPos,aEntry);
   628     }
   629 
   630 /**
   631 Adds aCluster to cluster list array so that it may be revisited later, avoids stack 
   632 over flow
   633 
   634 @param aCluster Directory cluster number to add to the list
   635 @leave KErrNoMemory If allocation fails
   636 */
   637 void CScanDrive::AddToClusterListL(TInt aCluster)
   638     {
   639     if(iListArrayIndex>=KMaxArrayDepth)
   640         return;
   641     if(iClusterListArray[iListArrayIndex]==NULL)
   642         iClusterListArray[iListArrayIndex]=new(ELeave) RArray<TInt>(KClusterListGranularity);
   643     iClusterListArray[iListArrayIndex]->Append(aCluster);
   644     }
   645 
   646 
   647 #if defined(DEBUG_SCANDRIVE)
   648 void CScanDrive::CompareFatsL()
   649 //
   650 // Compare new fat and first fat table
   651 //  
   652     {
   653     __PRINT(_L("CScanDrive::CompareFatsL()"));
   654     TInt maxClusters;
   655     maxClusters=iMount->UsableClusters();
   656     for(TInt i=KFatFirstSearchCluster; i<maxClusters; ++i)
   657         {
   658         TInt realFat=iMount->FAT().ReadL(i);
   659         TInt newFat=iNewFat->ReadL(i);
   660         if(realFat!=newFat)
   661             {
   662             if(realFat!=0 && newFat==0)
   663                 __PRINT1(_L("Lost cluster=%d\n"),i)
   664             else if((realFat>0 && !IsEofF(realFat)) && IsEofF(newFat))
   665                 __PRINT1(_L("Hanging cluster = %d\n"),i)
   666             else if(realFat==0 && newFat>0)
   667                 __PRINT1(_L("Unflushed cluster = %d\n"),i)
   668             else
   669                 User::Leave(KErrCorrupt);
   670             }
   671         }
   672     }   
   673 
   674 
   675 /** 
   676 For debug purposes, print errors found as debug output 
   677  
   678 */ 
   679 void CScanDrive::PrintErrors()
   680     {
   681     __PRINT1(_L("Directories visisted = %d\n"),iDirsChecked);
   682     if(iDirError==EScanPartEntry)
   683         __PRINT2(_L("Part entry-dir cluster=%d,dir pos=%d,\n"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos)
   684     else if(iDirError==EScanMatchingEntry)
   685         {
   686         __PRINT1(_L("Matching cluster - cluster no=%d\n"),iMatching.iStartCluster);
   687         __PRINT2(_L("\tcluster 1 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[0].iCluster,iMatching.iEntries[0].iPos);
   688         __PRINT2(_L("\tcluster 2 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[1].iCluster,iMatching.iEntries[1].iPos);
   689         }
   690     }
   691     
   692 #endif
   693 
   694 
   695 
   696