userlibandfileserver/fileserver/sfat/sl_scan.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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