--- a/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Thu Aug 19 11:14:22 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Tue Aug 31 16:34:26 2010 +0300
@@ -72,10 +72,11 @@
ASSERT(aMount);
//--- setting up
- iMount=aMount;
- iGenericError = ENoErrors;
- iDirError = ENoDirError;
- iMaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers
+ iMount = aMount;
+ iGenericError = ENoErrors;
+ iDirError = ENoDirError;
+ iHangingClusters = 0;
+ iMaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers
//------------------------------
//-- create bit vectors that will represent FAT on media and reconstructed by ScanDrive. Each bit in the vector represents 1 FAT cluster.
@@ -109,7 +110,7 @@
const TUint32 nFatEntry = ReadFatL(i);
//-- each '1' bit represents a used cluster
- if(nFatEntry != KSpareCluster)
+ if(nFatEntry != KSpareCluster)
iMediaFatBits.SetBit(i);
}
}
@@ -125,7 +126,7 @@
ASSERT((aBuf.Size() & (sizeof(TFat32Entry)-1)) == 0);
const TInt KNumEntries = aBuf.Size() >> KFat32EntrySzLog2;
- const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr());
+ const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr());
for(TInt i=0; i<KNumEntries; ++i)
{
@@ -161,11 +162,11 @@
iMediaFatBits.Fill(0);
- RBuf8 buf;
- CleanupClosePushL(buf);
+ RBuf8 fatParseBuf;
+ CleanupClosePushL(fatParseBuf);
//-- allocate memory for FAT parse buffer
- buf.CreateMaxL(KFatBufSz);
+ fatParseBuf.CreateMaxL(KFatBufSz);
//-- read FAT directly from the media into the large buffer and parse it
TUint32 rem = KFatSize;
@@ -175,10 +176,10 @@
while(rem)
{
const TUint32 bytesToRead=Min(rem, KFatBufSz);
- TPtrC8 ptrData(buf.Ptr(), bytesToRead);
+ TPtrC8 ptrData(fatParseBuf.Ptr(), bytesToRead);
//-- read portion of the FAT into buffer
- User::LeaveIfError(iMount->LocalDrive()->Read(mediaPos, bytesToRead, buf));
+ User::LeaveIfError(iMount->LocalDrive()->Read(mediaPos, bytesToRead, fatParseBuf));
//-- parse the buffer and populate bit vector
DoParseFat32Buf(ptrData, currFatEntry);
@@ -187,8 +188,8 @@
rem -= bytesToRead;
}
- buf.Close();
- CleanupStack::PopAndDestroy(&buf);
+ fatParseBuf.Close();
+ CleanupStack::PopAndDestroy(&fatParseBuf);
}
@@ -241,7 +242,7 @@
}
/**
- Sets the flag indicating than there are errors in filesystem structure
+ Sets the flag indicating that there are errors in filesystem structure
See ProblemsDiscovered()
@param aError a code describing the error
@@ -300,7 +301,6 @@
PrintErrors();
-
timeEnd.UniversalTime(); //-- take end time
const TInt elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
(void)elapsedTime;
@@ -478,7 +478,7 @@
{
CheckDirL(iMount->RootIndicator());
// Due to recursive nature of CheckDirL when a depth of
- // KMaxScanDepth is reached clusters are stored in a list
+ // KMaxScanDepth is reached, clusters are stored in a list
// and passed into CheckDirL afresh
for(TUint i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
@@ -518,7 +518,7 @@
TEntryPos entryPos(aCluster,0);
TInt dirEntries=0;
- FOREVER
+ for(;;)
{
TFatDirEntry entry;
ReadDirEntryL(entryPos,entry);
@@ -660,11 +660,11 @@
{
if(IsClusterUsedL(aCluster))
{//-- this cluster already seems to belong to some other object; crosslinked cluster chain. Can't fix it.
- __PRINT1(_L("CScanDrive::RecordClusterChainL #1 %d"),aCluster);
+ __PRINT1(_L("CScanDrive::RecordClusterChainL #1 %d"),aCluster);
if(CheckDiskMode())
- {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning
- __PRINT(_L("CScanDrive::RecordClusterChainL #1.1"));
+ {//-- in check disk mode this is an FS error; Indicate error and abort further scanning
+ __PRINT(_L("CScanDrive::RecordClusterChainL #1.1"));
IndicateErrorsFound(EClusterAlreadyInUse);
User::Leave(KErrCorrupt);
}
@@ -687,16 +687,26 @@
if(clusterCount==1)
{//-- we have reached the end of the cluster chain
if(!iMount->IsEndOfClusterCh(ReadFatL(aCluster)))
- {//-- seems to be a rugged FAT artefact; File truncation/extension had failed before and now file length is less than
- //-- the corresponding cluster chain shall be. It will be truncated to the size recorded in file DOS entry.
- iTruncationCluster = aCluster;
+ {
+ // According to the directory entry, we have reached the end of the cluster chain,
+ // whereas in the media FAT, it is not.
+ // This is a rugged FAT artefact; hanging cluster chain:
+ // A cluster chain which is longer in the FAT table than is recorded in the corresponding directory entry
+ // or not terminated by an EOC entry in FAT.
+ // This is caused by:
+ // - File truncation failing.
+ // - OR file expanding failing during flushing to the media FAT.
if(CheckDiskMode())
- {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning
- __PRINT1(_L("CScanDrive::RecordClusterChainL #2 %d"),aCluster);
+ {//-- in check disk mode this is an FS error; Indicate error and abort further scanning
+ __PRINT1(_L("CScanDrive::RecordClusterChainL #2 Hanging cluster=%d"),aCluster);
IndicateErrorsFound(EInvalidEntrySize);
User::Leave(KErrCorrupt);
}
+
+ // The chain will be truncated to the size recorded in the file's DOS entry and
+ // the remaining lost cluster chain will be fixed later in CompareAndFixFatsL().
+ FixHangingClusterChainL(aCluster);
}
//__PRINT1(_L("#--: %d -> EOC"), aCluster);
@@ -763,8 +773,8 @@
if(!IsValidVFatEntry(aEntry,toFollow))
return(EFalse);
}
-
- return(IsDosEntry(aEntry));
+ // A sequence of VFat entries must end with a Dos entry to be valid.
+ return(IsDosEntry(aEntry));
}
//----------------------------------------------------------------------------------------------------
@@ -845,7 +855,7 @@
//----------------------------------------------------------------------------------------------------
/**
- Scan for differnces in the new and old FAT table writing them to media if discovered
+ Scan for differences in the new and old FAT table writing them to media if discovered
It is supposed to be called in 'ScanDrive' mode only
@leave System wide error codes
@@ -885,9 +895,10 @@
continue;
}
- //-- here we found a lost cluster. Its FAT entry will be replaced with KSpareCluster. In the case of multiple lost clusters FAT table will
- //-- be flushed on media sector basis. It is much faster than flushing FAT after every write and will
- //-- guarantee that FAT won't be corrupted if the media driver provides atomic sector write.
+ //-- Here we found a lost cluster. Its FAT entry will be replaced with KSpareCluster.
+ //-- In the case of multiple lost clusters FAT table will be flushed on media sector basis.
+ //-- It is much faster than flushing FAT after every write and will guarantee
+ //-- that FAT won't be corrupted if the media driver provides atomic sector write.
if(nClustersFixed == 0)
{//-- this is the first lost cluster entry we found
@@ -902,7 +913,7 @@
const TUint32 fatSec = iMount->FAT().PosInBytes(i) >> KSectorSzLog2;
if(fatSec != dirtyFatSector)
- {//-- we are going to write to a differrent media sector
+ {//-- we are going to write to a different media sector
iMount->FAT().FlushL();
iMount->FAT().WriteL(i, KSpareCluster); //-- fix lost cluster
dirtyFatSector = fatSec;
@@ -928,18 +939,11 @@
//------
- if(iTruncationCluster != 0)
- {
- iMount->FAT().WriteFatEntryEofL(iTruncationCluster);
- iMount->FAT().FlushL();
-
- //-- indicate that there are some problems in FAT. and we probably wrote something there.
- IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors
-
- ++nClustersFixed;
- }
+
+ // Add the number of hanging clusters fixed by ScanDrive
+ nClustersFixed += iHangingClusters;
- __PRINT2(_L("CScanDrive::WriteNewFatsL() fixed:%d, bad:%d"), nClustersFixed, nBadClusters);
+ __PRINT3(_L("CScanDrive::WriteNewFatsL() fixed clusters=%d,hanging clusters=%d,bad clusters=%d"),nClustersFixed,iHangingClusters,nBadClusters);
}
//----------------------------------------------------------------------------------------------------
@@ -1015,6 +1019,28 @@
//----------------------------------------------------------------------------------------------------
/**
+ Fix a hanging cluster chain.
+ Writes EOF to the corresponding FAT entry, making this cluster chain length correspond to the
+ real file size recorded in the directory entry.
+ The remainder of the chain will be cleaned up later in CompareAndFixFatsL().
+
+ @leave System wide error code
+*/
+void CScanDrive::FixHangingClusterChainL(TUint32 aFatEofIndex)
+ {
+ __PRINT1(_L("CScanDrive::FixHangingClusterL() Hanging cluster=%d"), aFatEofIndex);
+
+ iMount->FAT().WriteFatEntryEofL(aFatEofIndex);
+ iMount->FAT().FlushL();
+ iHangingClusters++;
+
+ // Indicate that we have found an error
+ IndicateErrorsFound(EScanDriveDirError);
+ }
+
+
+//----------------------------------------------------------------------------------------------------
+/**
Move past specified number of entries
@param aEntryPos Start position to move from, updated as move takes place
@@ -1087,35 +1113,26 @@
if(BoolXOR(bRealFatEntry, bNewFatEntry))
{//-- mismatch between FAT on the media and the FAT bitmap restored by walking directory structure
- if(bRealFatEntry)
- {//-- FAT[i] on the media is marked as occupied, but retored FAT bitmap shows that it is free
- if(iMount->IsBadCluster(ReadFatL(i)))
- continue; //-- this is a BAD cluster it can't be occupied by the FS object, OK.
+ if(bRealFatEntry)
+ {//-- FAT[i] on the media is marked as occupied, but restored FAT bitmap shows that it is free
+ if(iMount->IsBadCluster(ReadFatL(i)))
+ continue; //-- this is a BAD cluster it can't be occupied by the FS object, OK.
- __PRINT2(_L("FAT[%d] = %d\n"), i, ReadFatL(i));
- __PRINT1(_L("iTruncationCluster = %d\n"), iTruncationCluster);
-
- //-- this is a lost cluster
- if(!IsEofF(ReadFatL(i)) && (i==iTruncationCluster))
- {//-- seems to be a Rugged FAT ertefact
- __PRINT1(_L("Hanging cluster = %d\n"),i);
- }
- else
- {
- __PRINT1(_L("Lost cluster=%d\n"),i);
- }
-
-
- IndicateErrorsFound(EBadClusterValue);
- }
- else
- {//-- FAT[i] on the media is marked as free, but retored FAT bitmap shows that it is occupied by some object
- IndicateErrorsFound(EClusterAlreadyInUse);
- __PRINT1(_L("Unflushed cluster = %d\n"),i);
- }
+ __PRINT2(_L("FAT[%d] = %d\n"), i, ReadFatL(i));
+
+ //-- this is a Rugged FAT artefact; a lost cluster
+ __PRINT1(_L("Lost cluster=%d\n"),i);
+
+ IndicateErrorsFound(EBadClusterValue);
+ }
+ else
+ {//-- FAT[i] on the media is marked as free, but restored FAT bitmap shows that it is occupied by some object
+ IndicateErrorsFound(EClusterAlreadyInUse);
+ __PRINT1(_L("Unflushed cluster = %d\n"),i);
+ }
- if(aStopOnFirstErrorFound)
- break; //-- not asked to check for errors further
+ if(aStopOnFirstErrorFound)
+ break; //-- not asked to check for errors further
}
@@ -1187,13 +1204,13 @@
}
/**
- Read a cluster from the Media Fat if scan run in a seperate thread read from scan fat table
+ Read a cluster from the Media Fat if scan run in a separate thread read from scan Fat table
otherwise read from mount owned Fat table
@param aClusterNum Cluster to read
@return Value of cluster read from Fat
*/
-TUint32 CScanDrive::ReadFatL(TUint aClusterNum)
+TUint32 CScanDrive::ReadFatL(TUint aClusterNum)
{
if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters())
{