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