userlibandfileserver/fileserver/sfat32/sl_mnt.cpp
changeset 45 329ab0095843
parent 44 36bfc973b146
child 62 4a8fed1c0ef6
child 90 947f0dc9f7a8
equal deleted inserted replaced
44:36bfc973b146 45:329ab0095843
    27 #include "sl_scandrv.h"
    27 #include "sl_scandrv.h"
    28 #include <hal.h>
    28 #include <hal.h>
    29 
    29 
    30 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively);
    30 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively);
    31 
    31 
    32 static void  MarkClusterVisited(RBitVector& aFatBitVec, TUint32 aCluster);
       
    33 static TBool IsClusterVisited(const RBitVector& aFatBitVec, TUint32 aCluster);
       
    34 static TInt  NextUnvisitedCluster(const RBitVector& aFatBitVec, TUint32 aCluster);
       
    35 
    32 
    36 //-----------------------------------------------------------------------------------------
    33 //-----------------------------------------------------------------------------------------
    37 
    34 
    38 TFatVolParam::TFatVolParam()
    35 TFatVolParam::TFatVolParam()
    39     {
    36     {
  2505     //-- locate the name in the cache first to avoid reading from media
  2502     //-- locate the name in the cache first to avoid reading from media
  2506     //-- if the entry belongs to the root directory (for FAT12,16) skip the lookup, because root directory isn't aligned by cluster size boundary,
  2503     //-- if the entry belongs to the root directory (for FAT12,16) skip the lookup, because root directory isn't aligned by cluster size boundary,
  2507     //-- while directory cache pages are. For FAT32 it doesn't matter, because root dir is a usual file.
  2504     //-- while directory cache pages are. For FAT32 it doesn't matter, because root dir is a usual file.
  2508     
  2505     
  2509     //-- the "rummage dir. cache" can be swithed off. This is not affecting the functionality, only the performance.
  2506     //-- the "rummage dir. cache" can be swithed off. This is not affecting the functionality, only the performance.
  2510  #if 1
  2507  #ifdef USE_DIR_CACHE_RUMMAGE
       
  2508                                                                  
  2511     if(iRawDisk->DirCacheInterface() && trgNameFullySpecified && !IsRootDir(aDosEntryPos) && !aFileCreationHelper)
  2509     if(iRawDisk->DirCacheInterface() && trgNameFullySpecified && !IsRootDir(aDosEntryPos) && !aFileCreationHelper)
  2512         {//-- aName is fully specified, i.e doesn't contain wildcards
  2510         {//-- aName is fully specified, i.e doesn't contain wildcards
  2513 
  2511 
  2514         findHelper.InitialiseL(trgtNameNoDot);
  2512         findHelper.InitialiseL(trgtNameNoDot);
  2515 
  2513 
  4120     TFatDirEntry dosEntry;
  4118     TFatDirEntry dosEntry;
  4121     InitializeRootEntry(dosEntry);  // Nugatory initialisation to placate warnings
  4119     InitializeRootEntry(dosEntry);  // Nugatory initialisation to placate warnings
  4122     TRAPD(err,GetDosEntryFromNameL(aName,dosEntryPos,dosEntry));
  4120     TRAPD(err,GetDosEntryFromNameL(aName,dosEntryPos,dosEntry));
  4123     if(err!=KErrNone)
  4121     if(err!=KErrNone)
  4124         return err;
  4122         return err;
       
  4123 
  4125     TInt startCluster=StartCluster(dosEntry);
  4124     TInt startCluster=StartCluster(dosEntry);
  4126     // Empty files will return a cluster of zero
  4125     // Empty files will return a cluster of zero
  4127     if(startCluster==0)
  4126     if(startCluster==0)
  4128         return KErrEof;
  4127         return KErrEof;
       
  4128 
  4129     aUniqueId=MAKE_TINT64(0,startCluster);
  4129     aUniqueId=MAKE_TINT64(0,startCluster);
  4130     return KErrNone;
  4130     return KErrNone;
  4131     }
  4131     }
  4132 //-----------------------------------------------------------------------------------------
  4132 //-----------------------------------------------------------------------------------------
  4133 
  4133 
  4147     return KErrNotSupported;
  4147     return KErrNotSupported;
  4148     }
  4148     }
  4149 
  4149 
  4150 //-----------------------------------------------------------------------------------------
  4150 //-----------------------------------------------------------------------------------------
  4151 
  4151 
  4152 //-- maximal level of recursion for the CheckDisk. i.e. the max. number of folded directories to check.
  4152 /** 
  4153 const TInt KCheckDskMaxRecursionLevel = 50;
  4153     Check file system for errors. 
  4154 
  4154     @return KErrNone if no errors found, otherwise a error code hopefully describing the problem found.
  4155 //
  4155 */
  4156 // Walks a directory cluster list then checks all the entries.
       
  4157 //
       
  4158 void  CFatMountCB::ChkDirL(RBitVector& aFatBitVec, TInt aDirCluster)
       
  4159     {
       
  4160     //__PRINT1(_L("### CFatMountCB::ChkDirL() level:%d"),iChkDiscRecLevel);
       
  4161 
       
  4162     //-- check if we have reached the recursion limit. on hardware the stack is very limited
       
  4163     //-- and its overflow will lead to crash.
       
  4164     if(iChkDiscRecLevel++ >= KCheckDskMaxRecursionLevel)
       
  4165         {
       
  4166          __PRINT1(_L("CFatMountCB::ChkDirL() max recursion level(%d) reached. Leaving!"),iChkDiscRecLevel);
       
  4167          User::Leave(KErrTooBig);
       
  4168         }
       
  4169 
       
  4170     if(/*Is32BitFat() &&*/aDirCluster != 0 && (aDirCluster == RootIndicator()))//the bit in comments maybe required
       
  4171         WalkClusterListL(aFatBitVec, RootIndicator());
       
  4172 
       
  4173     TEntryPos entryPos(aDirCluster,0);
       
  4174     FOREVER
       
  4175         {
       
  4176         TFatDirEntry entry;
       
  4177         ReadDirEntryL(entryPos,entry);
       
  4178         MoveToDosEntryL(entryPos,entry);
       
  4179         if (entry.IsEndOfDirectory())
       
  4180             break;
       
  4181         if (IsRootDir(entryPos)&&(StartOfRootDirInBytes()+entryPos.iPos==(RootDirEnd()-KSizeOfFatDirEntry)))
       
  4182             {
       
  4183             if(!entry.IsErased())
       
  4184                 ChkEntryL(aFatBitVec, entry);
       
  4185             break;  //  Allows maximum number of entries in root directory
       
  4186             }
       
  4187         MoveToNextEntryL(entryPos);
       
  4188         if (entry.IsParentDirectory() || entry.IsCurrentDirectory() || entry.IsErased())
       
  4189             continue;
       
  4190         ChkEntryL(aFatBitVec, entry);
       
  4191         }
       
  4192 
       
  4193     iChkDiscRecLevel--;
       
  4194     }
       
  4195 
       
  4196 //-----------------------------------------------------------------------------------------
       
  4197 
       
  4198 //
       
  4199 // Check FAT is valid for anEntry
       
  4200 //
       
  4201 void  CFatMountCB::ChkEntryL(RBitVector& aFatBitVec, const TFatDirEntry& anEntry)
       
  4202     {
       
  4203     TInt listLength=0;
       
  4204 
       
  4205     if ((anEntry.Attributes()&(KEntryAttDir)) || anEntry.Size())
       
  4206         listLength=WalkClusterListL(aFatBitVec, StartCluster(anEntry));
       
  4207     else if (anEntry.StartCluster() != 0)        // zero length file
       
  4208         User::Leave(EFatChkDskInvalidEntrySize); // shouldn't have clusters
       
  4209 
       
  4210     if (anEntry.Attributes()&KEntryAttDir)
       
  4211         ChkDirL(aFatBitVec, StartCluster(anEntry));
       
  4212 
       
  4213     //  Check that the correct number of clusters have been allocated for the size of the file.
       
  4214 
       
  4215     else if ((anEntry.Attributes()&KEntryAttVolume)==0)
       
  4216         {
       
  4217         TInt clustersForFileSize;
       
  4218         TInt clusterSize=1<<ClusterSizeLog2();
       
  4219         clustersForFileSize = (TInt) ( (TInt64(anEntry.Size()) + TInt64(clusterSize-1)) >> ClusterSizeLog2() );
       
  4220 
       
  4221         if (listLength!=clustersForFileSize)
       
  4222             User::Leave(EFatChkDskInvalidEntrySize);
       
  4223         }
       
  4224     }
       
  4225 
       
  4226 //-----------------------------------------------------------------------------------------
       
  4227 
       
  4228 //
       
  4229 // Walks cluster list from aCluster to EOF
       
  4230 // Reports an error if an invalid cluster is found before EOF or
       
  4231 // a cluster has been visited before.
       
  4232 //
       
  4233 TInt  CFatMountCB::WalkClusterListL(RBitVector& aFatBitVec, TInt aCluster)
       
  4234     {
       
  4235 
       
  4236     TInt i=0;
       
  4237     do  {
       
  4238         i++;
       
  4239         if (!ValidClusterNumber(aCluster))
       
  4240             {
       
  4241             __PRINT1(_L("Bad Cluster number %d"),aCluster);
       
  4242             User::Leave(EFatChkDskIllegalClusterNumber);
       
  4243             }
       
  4244 
       
  4245         if (IsClusterVisited(aFatBitVec, aCluster))
       
  4246             {
       
  4247             __PRINT1(_L("Cluster already in use %d"),aCluster);
       
  4248             User::Leave(EFatChkDskClusterAlreadyInUse);
       
  4249             }
       
  4250 
       
  4251         MarkClusterVisited(aFatBitVec, aCluster);
       
  4252 
       
  4253         } while (FAT().GetNextClusterL(aCluster));
       
  4254 
       
  4255     return(i);
       
  4256     }
       
  4257 
       
  4258 //-----------------------------------------------------------------------------------------
       
  4259 
       
  4260 //
       
  4261 // Checks that all unvisited clusters are marked as free in the FAT
       
  4262 //
       
  4263 void  CFatMountCB::CheckUnvisitedClustersL(const RBitVector& aFatBitVec) const
       
  4264     {
       
  4265 
       
  4266     TInt cluster=2;
       
  4267     TInt maxCluster=cluster + UsableClusters();
       
  4268     while (cluster<maxCluster)
       
  4269         {
       
  4270         cluster=NextUnvisitedCluster(aFatBitVec, cluster); //-- move to the next unvisited cluster
       
  4271         if(cluster < 0 || cluster >= maxCluster)
       
  4272             break;
       
  4273 
       
  4274         TInt clusterVal=FAT().ReadL(cluster);
       
  4275         if (clusterVal!=0 && IsEndOfClusterCh(clusterVal)==EFalse && !IsBadCluster(clusterVal))
       
  4276             {
       
  4277             __PRINT1(_L("\n*****Bad cluster Num = %d"),cluster);
       
  4278             User::Leave(EFatChkDskBadCluster);
       
  4279             }
       
  4280         }
       
  4281     }
       
  4282 
       
  4283 //-----------------------------------------------------------------------------------------
       
  4284 
       
  4285 /**
       
  4286 @param  aCluster cluster number to check for validity
       
  4287 @returns ETrue if aCluster is a valid cluster number
       
  4288 */
       
  4289 TBool CFatMountCB::ValidClusterNumber(TUint32 aCluster) const
       
  4290     {
       
  4291     return (aCluster>=KFatFirstSearchCluster && aCluster<=MaxClusterNumber());
       
  4292     }
       
  4293 
       
  4294 //-----------------------------------------------------------------------------------------
       
  4295 
       
  4296 //
       
  4297 // Walk the FAT, returns error if find an unterminated list or
       
  4298 // lists that merge.
       
  4299 //
       
  4300 TInt CFatMountCB::CheckDisk()
  4156 TInt CFatMountCB::CheckDisk()
  4301 	{
  4157 	{
  4302 
  4158 
  4303     __PRINT1(_L("CFatMountCB::CheckDisk() drv:%d"), DriveNumber());
  4159     __PRINT1(_L("CFatMountCB::CheckDisk() drv:%d"), DriveNumber());
  4304 
  4160 
  4305     if(!ConsistentState())
  4161     if(!ConsistentState())
  4306         return KErrCorrupt;
  4162         return KErrCorrupt;
  4307 
  4163 
  4308     //-- create a bit representation of the FAT
  4164     //-- create a bit representation of the FAT
  4309     const TUint32 MaxClusters = UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers
  4165     const TUint32 MaxClusters = UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers
  4310 
       
  4311 
       
  4312     // cluster count may be zero if boot sector failed to be read (e.g. if the media is locked)
       
  4313     // or if TDrive::MountMedia(ETrue) has been called (in which case the boot sector may
       
  4314     if (MaxClusters == 0)
  4166     if (MaxClusters == 0)
  4315         return KErrCorrupt;
  4167         return KErrCorrupt;
  4316 
  4168 
  4317     //-- used for measuring time
  4169     //-- used for measuring time
  4318     TTime   timeStart;
  4170     TTime   timeStart;
  4319     TTime   timeEnd;
  4171     TTime   timeEnd;
  4320     timeStart.UniversalTime(); //-- take start time
  4172     timeStart.UniversalTime(); //-- take start time
  4321 
  4173 
  4322 
       
  4323     RBitVector bitVec; //-- each bit in this vector represents a FAT cluster
       
  4324 
       
  4325     TInt nRes = bitVec.Create(MaxClusters);
       
  4326     if(nRes != KErrNone)
       
  4327         {
       
  4328         ASSERT(nRes == KErrNoMemory); //-- the only one possible reason.
       
  4329         return KErrNoMemory;
       
  4330         }
       
  4331 
       
  4332     iChkDiscRecLevel = 0; //-- reset CheckDisk recursion counter
       
  4333     TRAPD(r,ChkDirL(bitVec, RootIndicator())); // Check from root directory
       
  4334     if (r==KErrNone)
       
  4335         {
       
  4336         TRAP(r,CheckUnvisitedClustersL(bitVec));
       
  4337         }
       
  4338 
       
  4339 
       
  4340     bitVec.Close();
       
  4341 
       
  4342     timeEnd.UniversalTime(); //-- take end time
       
  4343     const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
       
  4344     (void)msScanTime;
       
  4345 
       
  4346     __PRINT1(_L("#@@@ CheckDisk() time taken:%d ms"), msScanTime);
       
  4347 
       
  4348 
       
  4349     switch(r)
       
  4350         {
       
  4351 
       
  4352     case KErrNone:
       
  4353         return KErrNone;
       
  4354 
       
  4355     case EFatChkDskIllegalClusterNumber:
       
  4356         return(1);
       
  4357 
       
  4358     case EFatChkDskClusterAlreadyInUse:
       
  4359         return(2);
       
  4360 
       
  4361     case EFatChkDskBadCluster:
       
  4362         return(3);
       
  4363 
       
  4364     case EFatChkDskInvalidEntrySize:
       
  4365         return(4);
       
  4366 
       
  4367     default:
       
  4368         break;
       
  4369         }
       
  4370 
       
  4371     return(r);
       
  4372     }
       
  4373 
       
  4374 
       
  4375 //-----------------------------------------------------------------------------------------
       
  4376 //  Helper functions for Check Disk functionality
       
  4377 //-----------------------------------------------------------------------------------------
       
  4378 
       
  4379 /**
       
  4380     Find the next unvisited cluster number in the bit array.
       
  4381 
       
  4382     @param  aBitList    bit array, where '0' bits represent unvisited clusters.
       
  4383     @param  aCluster    cluster number to start search with.
       
  4384 
       
  4385     @return positive integer indicating next unvisited cluster number
       
  4386             KErrNotFound (-1) if there are no unvisited clusters
       
  4387 
       
  4388 */
       
  4389 static TInt  NextUnvisitedCluster(const RBitVector& aFatBitVec, TUint32 aCluster)
       
  4390 {
       
  4391     __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved
       
  4392 
       
  4393     TUint32 searchPos = aCluster; //-- bit number to start search with
       
  4394 
       
  4395     //-- look for the unvisited cluster (bit '0') in the bit array from the searchPos to the right
       
  4396     if(aFatBitVec.Find(searchPos, 0, RBitVector::ERight))
       
  4397         return searchPos;
       
  4398 
       
  4399     return KErrNotFound;
       
  4400 }
       
  4401 
       
  4402 
       
  4403 /**
       
  4404     Check if we have visited cluster aCluster
       
  4405 
       
  4406     @param  aFatBitVec  bit array, where '0' bits represent unvisited clusters.
       
  4407     @param  aCluster    cluster number to check
       
  4408     @return ETrue if aCluster has been visited.
       
  4409 */
       
  4410 static TBool IsClusterVisited(const RBitVector& aFatBitVec, TUint32 aCluster)
       
  4411 {
       
  4412     __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved
       
  4413 
       
  4414     return aFatBitVec[aCluster];
       
  4415 }
       
  4416 
       
  4417 /**
       
  4418     Mark aCluster as visited
       
  4419     @param  aFatBitVec  bit array, where '0' bits represent unvisited clusters.
       
  4420     @param  aCluster    cluster number to mark
       
  4421 */
       
  4422 static void MarkClusterVisited(RBitVector& aFatBitVec, TUint32 aCluster)
       
  4423 {
       
  4424     __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved
       
  4425 
       
  4426     aFatBitVec.SetBit(aCluster); //-- '1' bit in a bit array means that the corresponding cluster is visited
       
  4427 }
       
  4428 
       
  4429 
       
  4430 
       
  4431 //-------------------------------------------------------------------------------------------------------------------
       
  4432 
       
  4433 /**
       
  4434     Creates a scan drive object and starts the scan.
       
  4435 */
       
  4436 TInt CFatMountCB::DoRunScanDrive()
       
  4437 {
       
  4438     TInt nRes;
  4174     TInt nRes;
  4439 
  4175  
  4440     CScanDrive* pScnDrv = NULL;
  4176     CScanDrive* pScnDrv = NULL;
  4441     TRAP(nRes, pScnDrv=CScanDrive::NewL(this));
  4177     TRAP(nRes, pScnDrv=CScanDrive::NewL(this));
  4442     if(nRes != KErrNone)
  4178     if(nRes != KErrNone)
  4443         return nRes;
  4179         return nRes;
  4444 
  4180 
  4445     TRAPD(nScnDrvRes, pScnDrv->StartL());
  4181     //-- start ScanDrive in "checkdisk" mode
       
  4182     TRAPD(nScnDrvRes, pScnDrv->StartL(CScanDrive::ECheckDisk));
       
  4183     
       
  4184     timeEnd.UniversalTime(); //-- take end time
       
  4185     const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
       
  4186     (void)msScanTime;
       
  4187     __PRINT1(_L("#@@@ CheckDisk() time taken:%d ms"), msScanTime);
       
  4188  
       
  4189     CScanDrive::TGenericError chkDskRes = pScnDrv->ProblemsDiscovered();
       
  4190     const TBool bProblemsFound = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered();
       
  4191     
       
  4192     if(bProblemsFound && chkDskRes == CScanDrive::ENoErrors)
       
  4193         {//-- ScanDrive in this mode can leave unexpectedly without setting an error code that is returned by ProblemsDiscovered();
       
  4194          //-- leave itself means a problem
       
  4195         chkDskRes = CScanDrive::EUnknownError;
       
  4196         }
       
  4197 
       
  4198     delete pScnDrv;
       
  4199 
       
  4200     if(chkDskRes != KErrNone)
       
  4201         {
       
  4202         __PRINT2(_L("CFatMountCB::CheckDisk() drv:%d, result:%d"), DriveNumber(), chkDskRes);
       
  4203         }
       
  4204     
       
  4205     return chkDskRes;
       
  4206 
       
  4207     }
       
  4208 
       
  4209 
       
  4210 //-------------------------------------------------------------------------------------------------------------------
       
  4211 
       
  4212 /**
       
  4213     Creates a scan drive object and starts the scan.
       
  4214 */
       
  4215 TInt CFatMountCB::DoRunScanDrive()
       
  4216 {
       
  4217     TInt nRes;
       
  4218 
       
  4219     CScanDrive* pScnDrv = NULL;
       
  4220     TRAP(nRes, pScnDrv=CScanDrive::NewL(this));
       
  4221     if(nRes != KErrNone)
       
  4222         return nRes;
       
  4223 
       
  4224     TRAPD(nScnDrvRes, pScnDrv->StartL(CScanDrive::EScanAndFix));
  4446 
  4225 
  4447     const TBool bNeedFatRemount = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered();
  4226     const TBool bNeedFatRemount = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered();
  4448     delete pScnDrv;
  4227     delete pScnDrv;
  4449 
  4228 
  4450 
  4229 
  4457 
  4236 
  4458     if(nScnDrvRes != KErrNone)
  4237     if(nScnDrvRes != KErrNone)
  4459         return nScnDrvRes;
  4238         return nScnDrvRes;
  4460 
  4239 
  4461 
  4240 
  4462     //-- if ScanDrive hasn't found anything wrong or has fixed recoverable erros, mark the volume clean
  4241     //-- if ScanDrive hasn't found anything wrong or has fixed recoverable errors, mark the volume clean
  4463     if(VolCleanFlagSupported())
  4242     if(VolCleanFlagSupported())
  4464         {
  4243         {
  4465         //-- if there is a background FAT scanning thread, we need to wait until it finishes its work.
  4244         //-- if there is a background FAT scanning thread, we need to wait until it finishes its work.
  4466         //-- otherwise it's possible to have incorrect amount of free space on the volume until next remounting.
  4245         //-- otherwise it's possible to have incorrect amount of free space on the volume until next remounting.
  4467         (void)FAT().NumberOfFreeClusters(ETrue);
  4246         (void)FAT().NumberOfFreeClusters(ETrue);