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