userlibandfileserver/fileserver/sfat/sl_mnt.cpp
changeset 0 a41df078684a
child 15 4122176ea935
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1996-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 // Common CFatMountCB code for both EFAT.FSY and EFAT32.fsy
       
    15 //
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalTechnology
       
    21 */
       
    22 
       
    23 #include "sl_std.h"
       
    24 #include "sl_cache.h"
       
    25 #include "sl_leafdir_cache.h"
       
    26 #include "sl_dir_cache.h"
       
    27 #include "sl_scandrv.h"
       
    28 #include <hal.h>
       
    29 
       
    30 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively);
       
    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 
       
    36 //-----------------------------------------------------------------------------------------
       
    37 
       
    38 TFatVolParam::TFatVolParam()
       
    39     {
       
    40     Mem::FillZ(this, sizeof(TFatVolParam));
       
    41     }
       
    42 
       
    43 /**
       
    44     populate the object with the values from the boot sector.
       
    45     @param aBootSector a reference to the valid boots sector
       
    46 */
       
    47 void TFatVolParam::Populate(const TFatBootSector& aBootSector)
       
    48     {
       
    49     ASSERT(aBootSector.IsValid());
       
    50 
       
    51     iSectorsPerCluster = aBootSector.SectorsPerCluster();
       
    52     iSectorSizeLog2    = Log2(aBootSector.BytesPerSector());
       
    53     iClusterSizeLog2   = iSectorSizeLog2+Log2(iSectorsPerCluster);
       
    54     iFirstFatSector    = aBootSector.FirstFatSector();
       
    55     iNumberOfFats      = aBootSector.NumberOfFats();
       
    56     iFatSizeInBytes    = aBootSector.TotalFatSectors()*aBootSector.BytesPerSector();
       
    57     iTotalSectors      = aBootSector.VolumeTotalSectorNumber();
       
    58     iRootClusterNum    = aBootSector.RootClusterNum(); //-- will be 0 for FAT12/16
       
    59 
       
    60     iRootDirectorySector = aBootSector.RootDirStartSector();
       
    61     iRootDirEnd = (iRootDirectorySector + aBootSector.RootDirSectors()) << SectorSizeLog2(); //-- doesn't matter for FAT32
       
    62 
       
    63     //-- get main and backup FSInfo sectors position, these fields will be 0 for FAT12/16
       
    64     iFSInfoSectorNum   = aBootSector.FSInfoSectorNum();
       
    65     iBkFSInfoSectorNum = (TUint16)(aBootSector.BkBootRecSector()+iFSInfoSectorNum); //-- Bk FSInfo sector must follow the Bk boot sector
       
    66     }
       
    67 
       
    68 TBool TFatVolParam::operator==(const TFatVolParam& aRhs) const
       
    69     {
       
    70     ASSERT(&aRhs != this);
       
    71     if(&aRhs == this)
       
    72         return ETrue; //-- comparing with itself
       
    73 
       
    74     return (Mem::Compare((TUint8*)this, sizeof(TFatVolParam), (TUint8*)&aRhs, sizeof(TFatVolParam)) == 0);
       
    75     }
       
    76 
       
    77 
       
    78 //-----------------------------------------------------------------------------------------
       
    79 
       
    80 
       
    81 CFatMountCB::CFatMountCB()
       
    82     {
       
    83     __PRINT2(_L("CFatMountCB::CFatMountCB() 0x%x, %S"), this, &KThisFsyName);
       
    84     iFatType = EInvalid;
       
    85     iState   = ENotMounted;
       
    86     DBG_STATEMENT(iCBRecFlag = 0); //-- debug flag only
       
    87     }
       
    88 
       
    89 CFatMountCB::~CFatMountCB()
       
    90     {
       
    91     __PRINT1(_L("#-CFatMountCB::~CFatMountCB() 0x%x"), this);
       
    92 
       
    93     DoDismount();
       
    94 
       
    95     delete iNotifier;
       
    96     delete iFatTable;
       
    97     delete iRawDisk;
       
    98     delete iLeafDirCache;
       
    99 
       
   100     }
       
   101 
       
   102 //-----------------------------------------------------------------------------------------
       
   103 
       
   104 CFatMountCB* CFatMountCB::NewL()
       
   105     {
       
   106     CFatMountCB* pSelf = new(ELeave) CFatMountCB;
       
   107 
       
   108     CleanupStack::PushL(pSelf);
       
   109     pSelf->ConstructL();
       
   110     CleanupStack::Pop(pSelf);
       
   111 
       
   112     return pSelf;
       
   113     }
       
   114 
       
   115 // second-stage constructor
       
   116 void CFatMountCB::ConstructL()
       
   117 {
       
   118     //-- create Notifier
       
   119     iNotifier = CAsyncNotifier::New();
       
   120     if( !iNotifier )
       
   121         {
       
   122         Close();
       
   123         User::Leave(KErrNoMemory);
       
   124         }
       
   125 
       
   126     iNotifier->SetMount(this);
       
   127     }
       
   128 
       
   129 //-------------------------------------------------------------------------------------------------------------------
       
   130 
       
   131 /**
       
   132 Implementation of CMountCB::FileSystemClusterSize(). Returns cluster size of this mount.
       
   133 @return Cluster size value if successful; otherwise KErrNotReady if the mount is not ready.
       
   134 @see CMountCB::FileSystemClusterSize()
       
   135 */
       
   136 TInt CFatMountCB::ClusterSize() const
       
   137     {
       
   138     if (ClusterSizeLog2())
       
   139         return (1 << ClusterSizeLog2());
       
   140 
       
   141     return KErrNotReady;
       
   142     }
       
   143 
       
   144 //-------------------------------------------------------------------------------------------------------------------
       
   145 
       
   146 /**
       
   147     @leave KErrAccessDenied if the mount is read-only
       
   148 */
       
   149 void CFatMountCB::CheckWritableL() const
       
   150     {
       
   151     if(ReadOnly())
       
   152         {
       
   153         __PRINT(_L("CFatMountCB is RO!"));
       
   154         User::Leave(KErrAccessDenied);
       
   155         }
       
   156     }
       
   157 
       
   158 /**
       
   159     @leave KErrCorrupt if the mount is in inconsistent state i.e high-level file and directory  operations can not be performed
       
   160 */
       
   161 void CFatMountCB::CheckStateConsistentL() const
       
   162     {
       
   163     if(!ConsistentState())
       
   164         {
       
   165         __PRINT(_L("CFatMountCB state is inconsistent !"));
       
   166         User::Leave(KErrCorrupt);
       
   167         }
       
   168     }
       
   169 
       
   170 
       
   171 //-------------------------------------------------------------------------------------------------------------------
       
   172 /**
       
   173     Helper Method. Check if the parameters of the volume being remounted are the same as current ones.
       
   174     @return ETrue if volume parameters remained same.
       
   175 */
       
   176 TBool CFatMountCB::CheckVolumeTheSame()
       
   177 {
       
   178     //-- initialise local drive
       
   179     TInt nRes =InitLocalDrive();
       
   180     if(nRes != KErrNone)
       
   181         return EFalse;
       
   182 
       
   183     //-- read the boot sector or its backup copy if the main is damaged. It will aslo validate it.
       
   184     TFatBootSector bootSector;
       
   185     nRes = ReadBootSector(bootSector, iRamDrive);
       
   186     if(nRes != KErrNone)
       
   187         return EFalse;
       
   188 
       
   189     //-- 1. check volume Uid
       
   190     if(iUniqueID != bootSector.UniqueID())
       
   191         return EFalse;
       
   192 
       
   193     //-- check volume parameters, they must remain the same
       
   194     TFatVolParam volParam;
       
   195     volParam.Populate(bootSector);
       
   196 
       
   197     if(!(volParam == iVolParam))
       
   198         return EFalse;
       
   199 
       
   200 
       
   201     return ETrue;
       
   202 
       
   203 }
       
   204 //-------------------------------------------------------------------------------------------------------------------
       
   205 
       
   206 /**
       
   207     Helper Method. Check if the parameters of the volume being remounted are the same as current ones.
       
   208     If they are, re-initialises the mount.
       
   209 */
       
   210 void CFatMountCB::DoReMountL()
       
   211     {
       
   212 
       
   213     if(!CheckVolumeTheSame())
       
   214         User::Leave(KErrGeneral);
       
   215 
       
   216 	//-- get drive capabilities
       
   217     TLocalDriveCapsV2Buf capsBuf;
       
   218 	User::LeaveIfError(LocalDrive()->Caps(capsBuf));
       
   219 
       
   220     //-- the volume is the same as it was on original MountL()
       
   221     //-- we need to re-initialize for the case when the media was removed, FAT or directory structure changed on other device and the media returned back.
       
   222     DoDismount();
       
   223 
       
   224     SetState(EMounting);
       
   225 
       
   226     InitializeL(capsBuf(), ETrue); //-- forcedly disable FSInfo usage. This will lead to FAT free clusters re-counting.
       
   227 
       
   228     }
       
   229 
       
   230 //-------------------------------------------------------------------------------------------------------------------
       
   231 
       
   232 /**
       
   233     Try remount this Fat volume. Checks if the volume parameters remained the same as on original MountL() call, and
       
   234     if they are, re-initialises the mount. This includes resetting all caches.
       
   235     ! Do not call this method from TFatDriveInterface methods, like citical and non-critical notifiers ! This can lead to the
       
   236     recursive loops and undefined behaviour.
       
   237 
       
   238     @return KErrNone if the remount was OK
       
   239             system-wide error code otherwise
       
   240 */
       
   241 TInt CFatMountCB::ReMount()
       
   242     {
       
   243     __PRINT2(_L("CFatMountCB::ReMount(), drv:%d, curr state:%d"), DriveNumber(), State());
       
   244 
       
   245     const TFatMntState currState = State();
       
   246 
       
   247     //-- analyse the mount state and find out if we can remount at all.
       
   248     switch(currState)
       
   249         {
       
   250         case ENotMounted:
       
   251         __PRINT(_L("CFatMountCB::ReMount() Invalid mount state!"));
       
   252 
       
   253         ASSERT(0);
       
   254         return KErrGeneral;
       
   255 
       
   256         //-- correct state, proceed to remount
       
   257         default:
       
   258         break;
       
   259     }
       
   260 
       
   261     //-- there are 2 options here:
       
   262     //-- 1. normally initialised mount had been forcedly dismounted (it can optionally have objects opened on it)
       
   263     //--    in this case the DoReMountL() will succeed and everything will be fine, the objects will be accessible afterwards
       
   264     //-- 2. the mount hasn't been initialised at all (it does not have for example, FAT table created etc.)
       
   265     //--    in this case we may need to fake the success. This can only happen on forced mount by CFormatCB
       
   266     TInt nRes;
       
   267     TRAP(nRes, DoReMountL());
       
   268 
       
   269     if(nRes != KErrNone)
       
   270         {
       
   271         //-- note that the mount may be here left in inconsistent state (EMounting)
       
   272         //-- if DoReMountL() fails. This is OK, because we can not make any valid read/write operations in such a state and
       
   273         //-- the drive must be dismounted and mounted again. File Server's TDrive shall do this.
       
   274         __PRINT1(_L("CFatMountCB::ReMount() failed! code:%d"), nRes);
       
   275 
       
   276         //-- If we are in the EInit_Forced state, it means that we are trying to remount the volume that has been formatted.
       
   277         //-- scenario: On formatting, if we can't read a bootsector, new _empty_ object of the CFatMountCB is created and
       
   278         //-- it is used for performing a format. If the format has finished, but RFormat isn't closed yet and we try to access the volume,
       
   279         //-- we will get here, because all members of the constructed mount will be zeroes.
       
   280         if(currState == EInit_Forced)
       
   281             {
       
   282             __PRINT(_L("CFatMountCB::ReMount() simulating normal remount!"));
       
   283             SetState(currState);
       
   284             return KErrNone;
       
   285             }
       
   286 
       
   287         return nRes;
       
   288         }
       
   289 
       
   290     __PRINT1(_L("CFatMountCB::ReMount() Completed drv:%d"), DriveNumber());
       
   291     SetState(EInit_R);
       
   292     return nRes;
       
   293     }
       
   294 
       
   295 //-------------------------------------------------------------------------------------------------------------------
       
   296 
       
   297 /**
       
   298     Reset the last leaf dir or invalidate leaf dir cache if leaf dir cache is
       
   299     instantiated.
       
   300 */
       
   301 
       
   302 void CFatMountCB::InvalidateLeafDirCache()
       
   303 	{
       
   304     if (iLeafDirCache)
       
   305     	{
       
   306         iLeafDirCache->Reset();
       
   307     	}
       
   308     else
       
   309     	{
       
   310         User::Free(iLastLeafDir);
       
   311         iLastLeafDir=NULL;
       
   312     	}
       
   313 	}
       
   314 
       
   315 //-------------------------------------------------------------------------------------------------------------------
       
   316 
       
   317 /**
       
   318     Delete mount's caches
       
   319     Moves CFatMountCB into ENotMounted state immediately.
       
   320 */
       
   321 void CFatMountCB::DoDismount()
       
   322     {
       
   323     __PRINT1(_L("CFatMountCB::DoDismount() drv:%d"), DriveNumber());
       
   324 
       
   325     //-- try to flush and destroy FAT cache
       
   326     if (iFatTable)
       
   327         {
       
   328         if(!ConsistentState() || ReadOnly())
       
   329             {//-- the mount state is inconsistent, so the data can't be flushed. Ignore dirty cache either.
       
   330             iFatTable->Dismount(ETrue);
       
   331             }
       
   332         else
       
   333             {//-- Try to flush the FAT - if this fails there's not much we can do
       
   334             TRAPD(r, iFatTable->FlushL());
       
   335             iFatTable->Dismount(r != KErrNone); //-- ignore dirty data if we failed to flush the cache
       
   336             }
       
   337         }
       
   338 
       
   339     //-- destroy leafdir name cache, this cache will be re-created while mounting or re-mounting
       
   340     //-- see CFatMountCB::InitializeL()
       
   341     delete iLeafDirCache;
       
   342     iLeafDirCache = NULL;
       
   343 
       
   344     //-- destroy directory cache, this cache will be re-created while mounting or re-mounting
       
   345     //-- see CFatMountCB::InitializeL()
       
   346     delete iRawDisk;
       
   347     iRawDisk = NULL;
       
   348 
       
   349     //-- Set mount state to "Dismounted". Which means that there might be no caches, but the mount is alive,
       
   350     //-- i.e. iFatTable & iRawDisk are valid
       
   351     SetState(EDismounted);
       
   352     }
       
   353 
       
   354 //-----------------------------------------------------------------------------------------
       
   355 
       
   356 /** old implementation */
       
   357 void CFatMountCB::FinaliseMountL()
       
   358     {
       
   359     FinaliseMountL(RFs::EFinal_RW);
       
   360     }
       
   361 
       
   362 //-----------------------------------------------------------------------------------------
       
   363 /**
       
   364     Dismount the CFatMountCB and the drive.
       
   365     called from TDrive::Dismount().
       
   366 */
       
   367 void CFatMountCB::Dismounted()
       
   368     {
       
   369     __PRINT1(_L("CFatMountCB::Dismounted() drv:%d"), DriveNumber());
       
   370 
       
   371     //-- n.b. it is no safe to do a kind of filnalisatin work here that implies accessing the media.
       
   372     //-- this method may be called after the media change occured from the TDrive::Dismount(). It means
       
   373     //-- that if we try to write some data here, they could be written into a different medium, if it had been
       
   374     //-- physically changed.
       
   375 
       
   376     const TFatMntState prevState = State();
       
   377 
       
   378     DoDismount(); //-- it will change mount state to EDismounted
       
   379     DismountedLocalDrive();
       
   380 
       
   381     //-- check if the previous state was EInit_Forced, which means that this method was called
       
   382     //-- on the mount that might not be alive (no valid iFatTable & iRawDisk).
       
   383     //-- This can happen only during format operation on non-mounted previously volume.
       
   384     //-- this EInit_Forced state must be processed separately, see ::Remount()
       
   385     if(prevState == EInit_Forced)
       
   386         SetState(EInit_Forced);
       
   387 
       
   388     }
       
   389 
       
   390 
       
   391 //-------------------------------------------------------------------------------------------------------------------
       
   392 
       
   393 /**
       
   394     Find out if the mount is finalised.
       
   395     @param  aFinalised on exit will be ETrue if the maunt is finalised, EFalse otherwise.
       
   396     @return standard error codes.
       
   397 */
       
   398 TInt CFatMountCB::IsFinalised(TBool& aFinalised)
       
   399     {
       
   400     switch(State())
       
   401         {
       
   402         case EFinalised: //-- already explicitly finalised
       
   403             aFinalised = ETrue;
       
   404         return KErrNone;
       
   405 
       
   406         case EInit_W: //-- the volume had been written
       
   407             aFinalised = EFalse;
       
   408         return KErrNone;
       
   409 
       
   410         default: //-- it depends on the state
       
   411         break;
       
   412         }
       
   413 
       
   414     //-- find out if the volume is _physically_ finalised.
       
   415     //-- It can be in the state EInit_R, but finalised before mounting
       
   416     if(!VolCleanFlagSupported())
       
   417         return KErrNotSupported;
       
   418 
       
   419     TInt nRes = KErrNone;
       
   420     TRAP(nRes, aFinalised = VolumeCleanL());
       
   421 
       
   422     return nRes;
       
   423     }
       
   424 
       
   425 //-------------------------------------------------------------------------------------------------------------------
       
   426 
       
   427 /**
       
   428     @return ETrue if the mount is in consistent state i.e. normally mounted.
       
   429     See TFatMntState enum for more detail.
       
   430 */
       
   431 TBool CFatMountCB::ConsistentState() const
       
   432     {
       
   433     return (iState==EInit_R) || (iState==EInit_W) || (iState == EFinalised);
       
   434     }
       
   435 
       
   436 //-------------------------------------------------------------------------------------------------------------------
       
   437 
       
   438 /**
       
   439     Open CFatMountCB for write. I.e. perform some actions on the first write attempt.
       
   440     This is a callback from TFatDriveInterface.
       
   441     @return System wide error code.
       
   442 */
       
   443 TInt CFatMountCB::OpenMountForWrite()
       
   444     {
       
   445     if(State() == EInit_W)
       
   446         return KErrNone; //-- nothing to do, the mount is already opened for write
       
   447 
       
   448     __PRINT1(_L("#- CFatMountCB::OpenMountForWrite() drv:%d\n"),DriveNumber());
       
   449 
       
   450     ASSERT(State() == EInit_R || State() == EFinalised);
       
   451 
       
   452     //-- Check possible recursion. This method must not be called recursively. SetVolumeCleanL() works through direct disc access and
       
   453     //-- can not call TFatDriveInterface methods that call this method etc.
       
   454     ASSERT(iCBRecFlag == 0);
       
   455     DBG_STATEMENT(iCBRecFlag = 1); //-- set recursion check flag
       
   456 
       
   457     //-- do here some "opening" work, like marking volme as dirty
       
   458     //-- be careful here, as soon as this is a callback from TFatDriveInterface, writing via TFatDriveInterface may cause some unwanted recursion.
       
   459 
       
   460     //-- mark the volume as dirty
       
   461     TInt nRes=KErrNone;
       
   462     TRAP(nRes, SetVolumeCleanL(EFalse));
       
   463     if(nRes == KErrNone)
       
   464         {
       
   465         SetState(EInit_W);
       
   466         }
       
   467 
       
   468     DBG_STATEMENT(iCBRecFlag = 0); //-- reset recursion check flag
       
   469 
       
   470     return nRes;
       
   471 
       
   472     }
       
   473 
       
   474 //-------------------------------------------------------------------------------------------------------------------
       
   475 
       
   476 /**
       
   477     Unfinalise the mount, reset "VolumeCleanShutDown" flag and change the state if necessarily.
       
   478 */
       
   479 void CFatMountCB::UnFinaliseMountL()
       
   480     {
       
   481     switch(State())
       
   482         {
       
   483         case EFinalised:
       
   484         case EInit_R:
       
   485             SetVolumeCleanL(EFalse); //-- the mount, mark volume "dirty"
       
   486             SetState(EInit_R);
       
   487         return;
       
   488 
       
   489         case EInit_W:
       
   490         return; //-- nothing to do
       
   491 
       
   492         default:
       
   493         //-- other mount states are inconsistent; can't perform this operation
       
   494         User::Leave(KErrAbort);
       
   495         break;
       
   496 
       
   497         }
       
   498 
       
   499     }
       
   500 
       
   501 //-------------------------------------------------------------------------------------------------------------------
       
   502 
       
   503 /**
       
   504     Finalise the mount.
       
   505 
       
   506     @param  aOperation  describes finalisation operation ,see RFs::TFinaliseDrvMode
       
   507     @param  aParam1     not used, for future expansion
       
   508     @param  aParam2     not used, for future expansion
       
   509 
       
   510     @leave  System wide error code. particular cases:
       
   511             KErrArgument invalid arguments
       
   512             KErrInUse    if the volume has opened objects (files, directories etc)
       
   513             KErrCorrupt  if the volume is corrupt
       
   514 
       
   515 */
       
   516 void CFatMountCB::FinaliseMountL(TInt aOperation, TAny* /*aParam1*/, TAny* /*aParam2*/)
       
   517     {
       
   518     __PRINT2(_L("#- CFatMountCB::FinaliseMountL() op:%d, drv:%d"), aOperation, DriveNumber());
       
   519 
       
   520     switch(aOperation)
       
   521         {
       
   522         case RFs::EFinal_RW:
       
   523         case RFs::EFinal_RO:
       
   524         break;
       
   525 
       
   526         case RFs::EForceUnfinalise:
       
   527             UnFinaliseMountL();
       
   528         return;
       
   529 
       
   530         default:
       
   531             __PRINT1(_L("#- CFatMountCB::FinaliseMountL() unexpected operation!:%d"), aOperation);
       
   532             ASSERT(0);
       
   533             User::Leave(KErrArgument);
       
   534         return;
       
   535         }
       
   536 
       
   537     //-- mount finalisation work
       
   538 
       
   539     ASSERT(aOperation == RFs::EFinal_RW || aOperation == RFs::EFinal_RO);
       
   540 
       
   541     if(State() == EFinalised)
       
   542         {//-- the mount is already finalised. All we can do is to set it to RO mode
       
   543         if(ReadOnly() && aOperation == RFs::EFinal_RW)
       
   544             {
       
   545             User::Leave(KErrAccessDenied); //-- can't override RO flag
       
   546             }
       
   547 
       
   548 		(void)LocalDrive()->Finalise(ETrue);
       
   549 
       
   550         if(aOperation == RFs::EFinal_RO)
       
   551             {
       
   552             SetReadOnly(ETrue);
       
   553             return;
       
   554             }
       
   555 
       
   556         return;
       
   557         }
       
   558 
       
   559     if(LockStatus() != 0)
       
   560         {//-- can't finalise the volume if it has opened objects and not in the consistent state.
       
   561          //-- Theoretically, we can finalise the mount if we have files opened only for read, but at present,
       
   562          //-- it's impossible to detect such situation.
       
   563         User::Leave(KErrInUse);
       
   564         }
       
   565 
       
   566     if(State() != EInit_R && State() != EInit_W)
       
   567         {//-- can't finalise the mount because it can be in an inconsistent state; e.g. corrupt.
       
   568         __PRINT1(_L("#- CFatMountCB::FinaliseMountL() Invalid mount State: %d"),State());
       
   569         User::Leave(KErrCorrupt);
       
   570         }
       
   571 
       
   572     //-- flush FAT cache
       
   573     FAT().FlushL();
       
   574 
       
   575     //-- for FAT32 we may need to update data in FSInfo sectors
       
   576     if(Is32BitFat())
       
   577         {
       
   578         if(FAT().ConsistentState())
       
   579             {//-- FAT table state is consistent and the number of free clusters is known.
       
   580              //-- Do it disregarding the mount state, it may help in the situation when 2 copies of the FSInfo are different for some reason.
       
   581             DoUpdateFSInfoSectorsL(EFalse);
       
   582             }
       
   583             else
       
   584             {//-- FAT table state is inconsistent, the most probable case here: background scan for free clusters is still working.
       
   585              //-- in this case we can't put corect values into the FSInfo.
       
   586             if(State() == EInit_W)
       
   587                 {//-- bad situation: free clusters may be being counted and someone has already written something on the volume at the same time.
       
   588                  //-- we do not know the exact number of free clustes and can't wait until scan finishes. Invalidate FSInfo.
       
   589                 __PRINT(_L("#- CFatMountCB::FinaliseMountL() invalidating FSInfo"));
       
   590                 DoUpdateFSInfoSectorsL(ETrue);
       
   591                 }
       
   592              else
       
   593                 {//-- no changes on the volume, just do not update FSInfo
       
   594                 __PRINT(_L("#- CFatMountCB::FinaliseMountL() FAT state inconsistent; FSInfo isn't updated"));
       
   595                 }
       
   596 
       
   597             }//if(FAT().ConsistentState())
       
   598 
       
   599         }//if(Is32BitFat())
       
   600 
       
   601 
       
   602 
       
   603     //-- mark the volume as clean
       
   604     SetVolumeCleanL(ETrue);
       
   605 
       
   606     //-- finally, put the volume into RO mode if required
       
   607     if(aOperation == RFs::EFinal_RO)
       
   608         SetReadOnly(ETrue);
       
   609 
       
   610     SetState(EFinalised);
       
   611     }
       
   612 
       
   613 
       
   614 //-------------------------------------------------------------------------------------------------------------------
       
   615 
       
   616 /**
       
   617 @return ETrue if "VolumeClean" flag is supported i.e. this is not FAT12
       
   618 */
       
   619 TBool CFatMountCB::VolCleanFlagSupported() const
       
   620     {
       
   621         const TFatType fatType=FatType();
       
   622 
       
   623         ASSERT(fatType == EFat12 || fatType == EFat16 || fatType == EFat32);
       
   624         return (fatType != EFat12);
       
   625     }
       
   626 
       
   627 //-----------------------------------------------------------------------------------------
       
   628 
       
   629 
       
   630 /**
       
   631     Obtain the volume information.
       
   632     All information except iSize and iFree has been added by TDrive::Volume().
       
   633 
       
   634     @param  aVolume on return will contain iSize & iFree fields filled with actual data.
       
   635 */
       
   636 void CFatMountCB::VolumeL(TVolumeInfo& aVolume) const
       
   637     {
       
   638 
       
   639     //-- if true, this operation will be synchronous, i.e the client will be suspended until FAT32 scanning thread finishes, if running.
       
   640     //-- the information if this operation is synchronous or not can be passed by client in TVolumeInfo::iFileCacheFlags field.
       
   641     //-- if the client sets aVolume.iVolSizeAsync flag there, RFs::Volume() will be asynchronous, i.e the _current_ number of free clusters
       
   642     //-- will be returned.
       
   643     const TBool bSyncOp = !aVolume.iVolSizeAsync;
       
   644     aVolume.iVolSizeAsync = EFalse; //-- reset this flag in order it not to be reused on the client side
       
   645 
       
   646 	__PRINT2(_L("CFatMountCB::VolumeL() drv:%d, synch:%d"), DriveNumber(), bSyncOp);
       
   647     const TDriveInfo& drvInfo=aVolume.iDrive;
       
   648 
       
   649 #if defined(__EPOC32__)
       
   650     // if RAM drive, cap size according to HAL.
       
   651     if (drvInfo.iType==EMediaRam)
       
   652         {
       
   653         TLocalDriveCapsV2Buf caps;
       
   654         LocalDrive()->Caps(caps);
       
   655 
       
   656         const TInt max_drive_size=TInt(caps().iEraseBlockSize);
       
   657         const TInt cur_drive_size=I64INT(caps().iSize);
       
   658 
       
   659         aVolume.iSize=max_drive_size;
       
   660         aVolume.iFree=max_drive_size-cur_drive_size;
       
   661 
       
   662         aVolume.iSize=aVolume.iFree+iSize;
       
   663 
       
   664         TInt maxSize;
       
   665         if (HAL::Get(HAL::EMaxRAMDriveSize, maxSize) == KErrNone)
       
   666             {
       
   667             // iSize will never grow beyond maxRam because of a check in medint.
       
   668             // d <= f; (s{f} + f) - m <= f; s{f} <= m
       
   669             __ASSERT_DEBUG(iSize <= maxSize, Fault(EFatRAMDriveSizeInvalid));
       
   670             if (aVolume.iSize > maxSize)
       
   671                 {
       
   672                 TInt64 d = aVolume.iSize - maxSize;
       
   673                 __ASSERT_DEBUG(d <= aVolume.iFree, Fault(EFatRAMDriveFreeInvalid));
       
   674                 aVolume.iSize -= d;
       
   675                 aVolume.iFree -= d;
       
   676                 }
       
   677             }
       
   678 
       
   679         aVolume.iSize-=ClusterBasePosition(); // Allow for bytes used by FAT etc
       
   680         aVolume.iSize=(aVolume.iSize>>ClusterSizeLog2())<<ClusterSizeLog2();  //-- round down to cluster size
       
   681 
       
   682         return;
       
   683         }//if (drvInfo.iType==EMediaRam)
       
   684 
       
   685 #endif
       
   686 
       
   687 
       
   688     const TUint32 freeClusters = FAT().NumberOfFreeClusters(bSyncOp);
       
   689 
       
   690     __PRINT1(_L("CFatMountCB::VolumeL() free clusters:%d"), freeClusters);
       
   691 
       
   692     aVolume.iFree = (TInt64)freeClusters << ClusterSizeLog2();
       
   693 
       
   694     if (drvInfo.iType==EMediaRam)
       
   695         aVolume.iSize=aVolume.iFree+iSize;
       
   696 
       
   697     aVolume.iSize-=ClusterBasePosition(); // Allow for bytes used by FAT etc
       
   698     aVolume.iSize=(aVolume.iSize >> ClusterSizeLog2()) << ClusterSizeLog2();  //-- round down to cluster size
       
   699 
       
   700     }
       
   701 
       
   702 
       
   703 //-----------------------------------------------------------------------------------------
       
   704 
       
   705 //
       
   706 //  Set the volume label (write aVolume label into BPB & Volume Label File)
       
   707 //  aName string may be zero length but is assumed to contain no illegal characters or NULLs.
       
   708 //
       
   709 void CFatMountCB::SetVolumeL(TDes& aName)
       
   710     {
       
   711 
       
   712     __PRINT(_L("CFatMountCB::SetVolumeL"));
       
   713 
       
   714     CheckStateConsistentL();
       
   715     CheckWritableL();
       
   716 
       
   717     __ASSERT_ALWAYS(aName.Length()<=KVolumeLabelSize,User::Leave(KErrBadName));
       
   718 
       
   719     TBuf8<KVolumeLabelSize> buf8(KVolumeLabelSize);
       
   720     buf8.Zero();
       
   721 	LocaleUtils::ConvertFromUnicodeL(buf8, aName, TFatUtilityFunctions::EOverflowActionLeave);
       
   722 	aName.Zero();
       
   723 	LocaleUtils::ConvertToUnicodeL(aName, buf8); // adjust aName (which may contain more underscores after this line than before)
       
   724 
       
   725     const TInt lengthOfBuf8=buf8.Length();
       
   726     // Pad to end with spaces if not empty.
       
   727     if (lengthOfBuf8>0 && lengthOfBuf8<KVolumeLabelSize)
       
   728         {
       
   729         buf8.SetLength(KVolumeLabelSize);
       
   730         Mem::Fill(&buf8[lengthOfBuf8],KVolumeLabelSize-lengthOfBuf8,' ');
       
   731         }
       
   732 
       
   733     // Write a volume label file
       
   734     WriteVolumeLabelFileL( buf8 );
       
   735 
       
   736     // Write the boot sector volume label
       
   737     // Always pad to full length with spaces
       
   738     if (lengthOfBuf8==0)
       
   739         {
       
   740         buf8.Fill(' ',KVolumeLabelSize);
       
   741         }
       
   742 
       
   743     WriteVolumeLabelL(buf8);
       
   744     }
       
   745 
       
   746 //-----------------------------------------------------------------------------------------
       
   747 
       
   748 /**
       
   749     Make a directory.
       
   750     @param aName full path to the directory to create. Name validity is checked by file server.
       
   751     all trailing dots from the name will be removed
       
   752 */
       
   753 void CFatMountCB::MkDirL(const TDesC& aName)
       
   754     {
       
   755     __PRINT2(_L("CFatMountCB::MkDirL, drv:%d, %S"), DriveNumber(), &aName);
       
   756 
       
   757     CheckStateConsistentL();
       
   758     CheckWritableL();
       
   759 
       
   760     TPtrC dirName = RemoveTrailingDots(aName); //-- remove trailing dots from the name
       
   761 
       
   762     TInt namePos=dirName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
   763     TPtrC name=dirName.Mid(namePos);
       
   764     TLeafDirData leafDir;
       
   765     const TEntryPos dirPos(FindLeafDirL(dirName.Left(namePos), leafDir),0);
       
   766     TEntryPos dumPos=dirPos;
       
   767     TFatDirEntry dumEntry;
       
   768 
       
   769     TBool isOriginalNameLegal = IsLegalDosName(name,EFalse,EFalse,EFalse,EFalse,ETrue);
       
   770     iFileCreationHelper.InitialiseL(name);
       
   771     TFileName fileName;
       
   772     TEntryPos startPos;
       
   773     TFatDirEntry startEntry;
       
   774     
       
   775     TRAPD(ret,DoFindL(name,KEntryAttMaskSupported,
       
   776 			    		startPos,startEntry,dumPos,dumEntry,
       
   777 			    		fileName,KErrNotFound,
       
   778 			    		&iFileCreationHelper,
       
   779 			    		leafDir));
       
   780 
       
   781     if (ret!=KErrNotFound && ret!=KErrNone)
       
   782         User::Leave(ret);
       
   783     if (ret!=KErrNotFound)
       
   784         {
       
   785         if (dumEntry.Attributes()&KEntryAttDir)
       
   786             User::Leave(KErrAlreadyExists);
       
   787         else
       
   788             User::Leave(KErrAccessDenied);
       
   789         }
       
   790     TShortName shortName;
       
   791 
       
   792     if (iFileCreationHelper.GetValidatedShortName(shortName) == KErrNotFound)
       
   793     	{
       
   794     	GenerateShortNameL(dirPos.iCluster,name,shortName,ETrue);
       
   795     	}
       
   796 
       
   797     TInt numEntries=1;
       
   798     if (isOriginalNameLegal==EFalse)
       
   799         numEntries=NumberOfVFatEntries(name.Length());
       
   800     dumPos=dirPos;
       
   801 
       
   802     if (iFileCreationHelper.IsNewEntryPosFound())
       
   803     	{
       
   804     	dumPos = iFileCreationHelper.EntryAddingPos();
       
   805     	}
       
   806 
       
   807     AddDirEntryL(dumPos,numEntries);    //  Directory entry in leaf directory
       
   808     TInt startCluster;
       
   809     FOREVER
       
   810         {
       
   811         //-- FAT().FreeClusterHint() will give us a hint of the last free cluster
       
   812         startCluster=FAT().AllocateSingleClusterL(dumPos.iCluster ? dumPos.iCluster : FAT().FreeClusterHint());
       
   813 
       
   814         FAT().FlushL();
       
   815         TRAPD(r, InitializeFirstDirClusterL(startCluster,dirPos.iCluster));
       
   816         if(r == KErrNone)
       
   817             break;
       
   818         if(r != KErrCorrupt)
       
   819             User::Leave(r);
       
   820         FAT().MarkAsBadClusterL(startCluster);
       
   821         }
       
   822     TFatDirEntry fatDirEntry;
       
   823     fatDirEntry.SetName(shortName);
       
   824     fatDirEntry.SetAttributes(KEntryAttDir);
       
   825     TTime now;
       
   826 	now.UniversalTime();
       
   827     fatDirEntry.SetTime(now, TimeOffset());
       
   828     fatDirEntry.SetCreateTime(now, TimeOffset());
       
   829     fatDirEntry.SetStartCluster(startCluster);
       
   830     fatDirEntry.SetSize(0);
       
   831     if (isOriginalNameLegal)
       
   832         WriteDirEntryL(dumPos,fatDirEntry);
       
   833     else
       
   834         WriteDirEntryL(dumPos,fatDirEntry,name);
       
   835 
       
   836     iFileCreationHelper.Close();
       
   837     }
       
   838 
       
   839 //-----------------------------------------------------------------------------------------
       
   840 
       
   841 /**
       
   842     Setup 1st cluster of the new directory
       
   843 
       
   844     @param  aStartCluster   this entry start cluster number
       
   845     @param  aParentCluster  parent entry start cluster number
       
   846 */
       
   847 void CFatMountCB::InitializeFirstDirClusterL(TInt aStartCluster,TInt aParentCluster)
       
   848     {
       
   849     const TUint32 KClusterSz= 1<<ClusterSizeLog2();
       
   850     const TUint32 KMaxBufSz = KClusterSz;           //-- max. nuffer size is a cluster
       
   851     const TUint32 KMinBufSz = 1<<SectorSizeLog2();  //-- min. buffer size is 1 sector (for OOM case)
       
   852 
       
   853     //-- allocate a buffer for directory file 1st cluster initialisation
       
   854     RBuf8 buf;
       
   855     CleanupClosePushL(buf);
       
   856 
       
   857     if(buf.CreateMax(KMaxBufSz) != KErrNone)
       
   858         buf.CreateMaxL(KMinBufSz); //-- OOM, try to create smaller buffer
       
   859 
       
   860     buf.FillZ();
       
   861 
       
   862     //-- copy "." directory entry to the buffer
       
   863 
       
   864     //-- "." directory entry
       
   865     TFatDirEntry entry;
       
   866     TTime now;
       
   867 	now.UniversalTime();
       
   868     entry.SetTime(now, TimeOffset() );
       
   869     entry.SetAttributes(KEntryAttDir);
       
   870     entry.SetCurrentDirectory();
       
   871     entry.SetStartCluster(aStartCluster);
       
   872     Mem::Copy(&buf[0],&entry,KSizeOfFatDirEntry);
       
   873 
       
   874     //-- append ".." directory entry
       
   875     entry.SetParentDirectory();
       
   876     entry.SetStartCluster(aParentCluster==RootIndicator() ? 0 : aParentCluster);
       
   877     Mem::Copy(&buf[0]+KSizeOfFatDirEntry,&entry,KSizeOfFatDirEntry);
       
   878 
       
   879     TEntryPos entryPos(aStartCluster,0);
       
   880 
       
   881     //-- write buffer to the beginning of the directory file.
       
   882     DirWriteL(entryPos, buf); //-- use special interface to access FAT directory file
       
   883 
       
   884     //-- fill in the rest of the cluster if we used a small buffer
       
   885     if((TUint32)buf.Size() < KClusterSz) //-- use special interface to access FAT directory file
       
   886     {
       
   887         buf.FillZ();
       
   888         const TInt restCnt = SectorsPerCluster() - 1;
       
   889         ASSERT(restCnt >=1);
       
   890 
       
   891         for(TInt i=0; i<restCnt; ++i)
       
   892         {
       
   893             entryPos.iPos += KMinBufSz;
       
   894             DirWriteL(entryPos, buf); //-- use directory cache when dealing with directories
       
   895         }
       
   896 
       
   897     }
       
   898 
       
   899     CleanupStack::PopAndDestroy(&buf);
       
   900 
       
   901     }
       
   902 
       
   903 //-----------------------------------------------------------------------------------------
       
   904 
       
   905 /**
       
   906     Remove a directory.
       
   907     @param aName directory name
       
   908     all trailing dots from the name will be removed
       
   909 */
       
   910 void CFatMountCB::RmDirL(const TDesC& aName)
       
   911     {
       
   912     __PRINT2(_L("CFatMountCB::RmDirL, drv:%d, %S"), DriveNumber(), &aName);
       
   913 
       
   914     CheckStateConsistentL();
       
   915     CheckWritableL();
       
   916 
       
   917     TPtrC dirName = RemoveTrailingDots(aName); //-- remove trailing dots from the name
       
   918 
       
   919     TFatDirEntry dirEntry;
       
   920     TEntryPos dirEntryPos(RootIndicator(),0); // Already checked entry is a directory
       
   921     FindEntryStartL(dirName,KEntryAttMatchMask|KEntryAttMatchExclusive,dirEntry,dirEntryPos);
       
   922     TEntryPos dosEntryPos=dirEntryPos;
       
   923     TFatDirEntry dosEntry=dirEntry;
       
   924     MoveToDosEntryL(dosEntryPos,dosEntry);
       
   925     if (!IsDirectoryEmptyL(StartCluster(dosEntry)))
       
   926         User::Leave(KErrInUse);
       
   927     // Remove the directory from cache before erasing
       
   928     if(iLeafDirCache && iLeafDirCache->CacheCount() > 0)
       
   929     	{
       
   930     	iLeafDirCache->RemoveDirL(StartCluster(dosEntry));
       
   931     	}
       
   932 
       
   933     EraseDirEntryL(dirEntryPos,dirEntry);
       
   934     FAT().FreeClusterListL(StartCluster(dosEntry));
       
   935     FAT().FlushL();
       
   936     }
       
   937 
       
   938 //-----------------------------------------------------------------------------------------
       
   939 
       
   940 /**
       
   941     Delete a file
       
   942     @param aName file name
       
   943     all trailing dots from the name will be removed
       
   944 */
       
   945 void CFatMountCB::DeleteL(const TDesC& aName)
       
   946     {
       
   947     __PRINT2(_L("CFatMountCB::DeleteL, drv:%d, %S"), DriveNumber(), &aName);
       
   948 
       
   949     CheckStateConsistentL();
       
   950     CheckWritableL();
       
   951 
       
   952     TPtrC fullName = RemoveTrailingDots(aName); //-- remove trailing dots from the name
       
   953 
       
   954     TFatDirEntry firstEntry;
       
   955     TEntryPos firstEntryPos(RootIndicator(),0);
       
   956     FindEntryStartL(fullName,KEntryAttMaskSupported,firstEntry,firstEntryPos);
       
   957     TEntryPos dosEntryPos=firstEntryPos;
       
   958     TFatDirEntry dosEntry=firstEntry;
       
   959     MoveToDosEntryL(dosEntryPos,dosEntry);
       
   960     if ((dosEntry.Attributes()&KEntryAttReadOnly) || (dosEntry.Attributes()&KEntryAttDir))
       
   961         User::Leave(KErrAccessDenied);
       
   962     // Can not delete a file if it is clamped
       
   963     CMountCB* basePtr=(CMountCB*)this;
       
   964     TInt startCluster=StartCluster(dosEntry);
       
   965     if(basePtr->IsFileClamped(MAKE_TINT64(0,startCluster)) > 0)
       
   966         User::Leave(KErrInUse);
       
   967     EraseDirEntryL(firstEntryPos,firstEntry);
       
   968     FAT().FreeClusterListL(StartCluster(dosEntry));
       
   969     FAT().FlushL();
       
   970     }
       
   971 
       
   972 //-----------------------------------------------------------------------------------------
       
   973 
       
   974 /**
       
   975 
       
   976     Rename or replace a directory entry.
       
   977     Assumes all files are closed and replace is only passed files.
       
   978     Assumes rename target does not exist or is the source file.
       
   979 
       
   980     --------------- operating mode --------------------------------------------
       
   981 
       
   982     * rename mode
       
   983 
       
   984     aOldName exists  |  aNewName exists |   result
       
   985         N                    N              leave KErrNotFound
       
   986         N                    Y              leave KErrNotFound
       
   987         Y                    N              rename aOldName -> aNewName
       
   988         Y                    Y              leave KErrAlreadyExists if(aOldName!=aNewName); otherwise do nothing
       
   989 
       
   990     * replace mode
       
   991 
       
   992         N                    N              leave KErrNotFound
       
   993         N                    Y              leave KErrNotFound
       
   994         Y                    N              rename aOldName -> aNewName
       
   995         Y                    Y              contents and all file attributes of the "aNewName" are replaced with aOldName's. "aOldName" entries are deleted then.
       
   996 
       
   997 
       
   998     @param   aOldName           entry name to be renamed or replaced
       
   999     @param   aNewName           a new entry name
       
  1000     @param   aMode              specifies renaming / replacing
       
  1001     @param   aNewDosEntryPos    on exit contains new entry Pos.
       
  1002 */
       
  1003 void CFatMountCB::DoRenameOrReplaceL(const TDesC& aOldName, const TDesC& aNewName, TRenMode aMode, TEntryPos& aNewName_DosEntryPos)
       
  1004 	{
       
  1005     __PRINT3(_L("CFatMountCB::DoRenameOrReplaceL() mode:%d old:%S, new:%S"), aMode, &aOldName, &aNewName);
       
  1006 
       
  1007     const TBool namesAreIdentical = FileNamesIdentical(aOldName, aNewName); //-- this is case-insensitive.
       
  1008     const TBool renameMode = (aMode == EModeRename);
       
  1009     const TBool replaceMode = !renameMode;
       
  1010     TInt  nRes;
       
  1011 
       
  1012     if(namesAreIdentical && replaceMode)
       
  1013         return; //-- nothing to do, replacing file with itself
       
  1014 
       
  1015     //---------------------------------------------------------------------------------------------------------------------------
       
  1016     //-- 1. find the entries of 'aOldName' file. It must always succeed, because FileServer firstly tries to locate 'aOldName'
       
  1017 
       
  1018     TFatDirEntry oldName_FirstEntry; //-- first entry of the "aOldName" entryset
       
  1019     TEntryPos    oldName_FirstEntryPos(RootIndicator(), 0); //-- dir. pos of the start "aOldName" VFAT entry set
       
  1020 
       
  1021     FindEntryStartL(aOldName, KEntryAttMaskSupported, oldName_FirstEntry, oldName_FirstEntryPos);
       
  1022 
       
  1023     TFatDirEntry oldName_DosEntry    = oldName_FirstEntry;   //-- "aOldName" entry set DOS entry
       
  1024     TEntryPos    oldName_DosEntryPos = oldName_FirstEntryPos;//-- dir. pos of the "aOldName" DOS entry
       
  1025 
       
  1026     MoveToDosEntryL(oldName_DosEntryPos, oldName_DosEntry);
       
  1027 
       
  1028     const TBool bOldNameIsVFAT = !(oldName_DosEntryPos == oldName_FirstEntryPos); //-- ETrue if "aOldName" is VFAT name, i.e. consists of mode than 1 entry
       
  1029 
       
  1030     //-- check if the file "aOldName" is clamped. In this case it can't be replaced.
       
  1031     if(replaceMode && (IsFileClamped(StartCluster(oldName_DosEntry)) > 0))
       
  1032         User::Leave(KErrInUse);
       
  1033 
       
  1034     //---------------------------------------------------------------------------------------------------------------------------
       
  1035     //-- 2. find the entry of 'aNewName' file. Further behavior depends on rename/replace mode and if this file exists or not
       
  1036 
       
  1037     //-- extract new file name from the full path
       
  1038     TPtrC ptrNewName;
       
  1039     TPtrC ptrNewNameParentDir;
       
  1040     const TInt delimPos = aNewName.LocateReverse(KPathDelimiter);
       
  1041     ptrNewName.Set(aNewName.Mid(delimPos+1));
       
  1042     ptrNewNameParentDir.Set(aNewName.Left(delimPos+1));
       
  1043 
       
  1044     //-- find the parent directory of the "aNewName" and create iterator for it
       
  1045     TLeafDirData leafDir;
       
  1046     const TEntryPos aNewName_ParentDirPos = TEntryPos(FindLeafDirL(ptrNewNameParentDir, leafDir), 0); //-- 'aNewName' parent directory iterator
       
  1047     aNewName_DosEntryPos = aNewName_ParentDirPos;
       
  1048 
       
  1049     TEntryPos    newName_VFatEntryPos; //-- dir. pos of the start "aNewName" VFAT entry set
       
  1050     TFatDirEntry newName_DosEntry;
       
  1051 
       
  1052     TFileName fileName;
       
  1053     iFileCreationHelper.InitialiseL(ptrNewName);
       
  1054     TFatDirEntry startEntry;
       
  1055 
       
  1056     TRAP(nRes, DoFindL(ptrNewName, KEntryAttMaskSupported,
       
  1057 	    		newName_VFatEntryPos, startEntry, aNewName_DosEntryPos, newName_DosEntry,
       
  1058 	    		fileName, KErrNotFound,
       
  1059 	    		&iFileCreationHelper,
       
  1060 	    		leafDir));
       
  1061 
       
  1062     if (nRes!=KErrNone && nRes!=KErrNotFound)
       
  1063         User::Leave(nRes);
       
  1064 
       
  1065     const TBool newFileExists = (nRes == KErrNone); //-- ETrue if 'aNewName' file exists.
       
  1066     const TBool bNewNameIsVFAT = !IsLegalDosName(ptrNewName, EFalse, EFalse, EFalse, EFalse, ETrue);
       
  1067 
       
  1068     if(renameMode && newFileExists)
       
  1069     	{
       
  1070         if(!namesAreIdentical)
       
  1071         {
       
  1072         if ((newName_DosEntry.Attributes()&KEntryAttDir) != (oldName_DosEntry.Attributes()&KEntryAttDir))
       
  1073         	{
       
  1074         	User::Leave(KErrAccessDenied); 	//-- leave with KErrAccessDenied if it is trying to rename a file
       
  1075         									//		to a dir or vice versa.
       
  1076         	}
       
  1077         User::Leave(KErrAlreadyExists); //-- can't rename file if the file with 'aNewName' already exists
       
  1078         }
       
  1079         else
       
  1080         	{
       
  1081             if(!bNewNameIsVFAT && !bOldNameIsVFAT)
       
  1082                 return; //-- renaming DOS name to itself
       
  1083         	}
       
  1084         //-- allow renaming entry to itself. "namesAreIdentical" is case-insensitive. use case: "FILE" -> "File"
       
  1085     	}
       
  1086 
       
  1087     //---------------------------------------------------------------------------------------------------------------------------
       
  1088 
       
  1089     if(replaceMode && newFileExists)
       
  1090     	{
       
  1091         //---------------------------------------------------------------------------------------------------------------------------
       
  1092         //-- replace contents of the 'aNewName' with 'aOldName' and remove 'aOldName' entries.
       
  1093 
       
  1094         //-- check if we are still trying to replace the file with itself, probably using short name alias
       
  1095         if(aNewName_DosEntryPos == oldName_DosEntryPos)
       
  1096             return; //-- nothing to do, it's the same file
       
  1097 
       
  1098         const TInt oldNameStartCluster = StartCluster(oldName_DosEntry);
       
  1099         const TInt newNameStartCluster = StartCluster(newName_DosEntry); //-- store starting cluster of the chain to be unlinked
       
  1100 
       
  1101         newName_DosEntry.SetStartCluster(oldNameStartCluster);
       
  1102         newName_DosEntry.SetSize(oldName_DosEntry.Size());
       
  1103         newName_DosEntry.SetTime(oldName_DosEntry.Time(TTimeIntervalSeconds(0)), TTimeIntervalSeconds(0));
       
  1104         newName_DosEntry.SetAttributes(oldName_DosEntry.Attributes());
       
  1105 
       
  1106             if(IsRuggedFSys())
       
  1107             	{
       
  1108             	//-- Note 1.
       
  1109                 //-- set a special Id in reserved section for old and new entries.
       
  1110                 //-- if write fails before the old entry gets erased, we will have 2 entries pointing to the same clusterchain.
       
  1111                 //-- ScanDrive is responsible for fixing this situation by erasing entry with ID KReservedIdOldEntry.
       
  1112                 //-- note that  SetRuggedFatEntryId() uses "LastAccessTime" DOS FAT entry field to store the ID.
       
  1113                 //-- in normal situation this field isn't used, though Windows checkdisk can chack its validiy.
       
  1114                 //-- KReservedIdNewEntry == 0x0000 that corresponds to year 1980.
       
  1115 
       
  1116 	            newName_DosEntry.SetRuggedFatEntryId(KReservedIdNewEntry);
       
  1117 	            oldName_DosEntry.SetRuggedFatEntryId(KReservedIdOldEntry);
       
  1118 	            WriteDirEntryL(oldName_DosEntryPos, oldName_DosEntry);
       
  1119                 }
       
  1120 
       
  1121         //-- write 'aNewName' DOS dir. entry data back
       
  1122         WriteDirEntryL(aNewName_DosEntryPos, newName_DosEntry);
       
  1123 
       
  1124         //-- erase "oldName" entryset.
       
  1125         EraseDirEntryL(oldName_FirstEntryPos, oldName_FirstEntry);
       
  1126 
       
  1127         //-- free 'aNewName' cluster list
       
  1128         FAT().FreeClusterListL(newNameStartCluster);
       
  1129 
       
  1130         if(IsRuggedFSys())
       
  1131             FAT().FlushL();
       
  1132 
       
  1133     	}
       
  1134     else //if(replaceMode && newFileExists)
       
  1135     	{
       
  1136         //---------------------------------------------------------------------------------------------------------------------------
       
  1137         //-- Renaming 'aOldName' to 'aNewName': add 'aNewName' entry set and remove 'aOldName' entryset
       
  1138 
       
  1139         TFatDirEntry newDosEntry = oldName_DosEntry;
       
  1140         //-- generate short name for the 'aNewName' entryset and make new DOS entry
       
  1141         if(bNewNameIsVFAT)
       
  1142         	{//-- need to generate a short name for VFAT entryset DOS entry
       
  1143             TShortName shortName;
       
  1144 
       
  1145 		    if (iFileCreationHelper.GetValidatedShortName(shortName) == KErrNotFound)
       
  1146 		    	{
       
  1147 		        GenerateShortNameL(aNewName_DosEntryPos.Cluster(), ptrNewName, shortName, ETrue);
       
  1148 		    	}
       
  1149 
       
  1150             newDosEntry.SetName(shortName);
       
  1151         	}
       
  1152         else
       
  1153         	{//-- just use 'aNewName' as DOS name.
       
  1154             TBuf8<KFatDirNameSize+1> tmp; //-- the name may be "XXXXXXXX.YYY"
       
  1155             tmp.Copy(ptrNewName);
       
  1156             newDosEntry.SetName(DosNameToStdFormat(tmp));
       
  1157         	}
       
  1158 
       
  1159         if(IsRuggedFSys())
       
  1160         	{//-- the the note(1) above
       
  1161             newDosEntry.SetRuggedFatEntryId(KReservedIdNewEntry);
       
  1162             oldName_DosEntry.SetRuggedFatEntryId(KReservedIdOldEntry);
       
  1163             WriteDirEntryL(oldName_DosEntryPos, oldName_DosEntry);
       
  1164         	}
       
  1165 
       
  1166         //-- add new entryset to the directory
       
  1167         aNewName_DosEntryPos.iPos = 0;
       
  1168         aNewName_DosEntryPos.iCluster = aNewName_ParentDirPos.Cluster();
       
  1169 
       
  1170 	    if (iFileCreationHelper.IsNewEntryPosFound())
       
  1171 	    	{
       
  1172 	    	aNewName_DosEntryPos = iFileCreationHelper.EntryAddingPos();
       
  1173 	    	}
       
  1174 
       
  1175         if(bNewNameIsVFAT)
       
  1176         	{
       
  1177             const TInt numEntries = NumberOfVFatEntries(ptrNewName.Length());
       
  1178             AddDirEntryL(aNewName_DosEntryPos, numEntries);
       
  1179             WriteDirEntryL(aNewName_DosEntryPos, newDosEntry, ptrNewName);
       
  1180             }
       
  1181         else
       
  1182             {//-- new name is one DOS entry only
       
  1183             AddDirEntryL(aNewName_DosEntryPos, 1);
       
  1184             WriteDirEntryL(aNewName_DosEntryPos, newDosEntry);
       
  1185             }
       
  1186 
       
  1187         //-- erase old entryset.
       
  1188         EraseDirEntryL(oldName_FirstEntryPos, oldName_FirstEntry);
       
  1189 
       
  1190         //-- if we have renamed (moved) a directory, need to update its pointer to parent directory ('..' entry)
       
  1191         if((newDosEntry.Attributes() & KEntryAttDir))
       
  1192         	{
       
  1193             TEntryPos parentPtrEntPos(StartCluster(newDosEntry), 1*KSizeOfFatDirEntry);
       
  1194 
       
  1195             TFatDirEntry chFatEnt;
       
  1196             ReadDirEntryL(parentPtrEntPos, chFatEnt);
       
  1197 
       
  1198             const TUint parentDirStartCluster_Old = StartCluster(chFatEnt);
       
  1199                   TUint parentDirStartCluster_New = aNewName_ParentDirPos.Cluster();
       
  1200 
       
  1201             if(parentDirStartCluster_New == RootClusterNum() && parentDirStartCluster_New != 0)
       
  1202             	{//-- we are in the root directory. for some reason, '..' entries of the directories in the root dir.
       
  1203             	//-- must have starting cluster 0
       
  1204                 parentDirStartCluster_New = 0;
       
  1205             	}
       
  1206 
       
  1207             if(parentDirStartCluster_Old != parentDirStartCluster_New)
       
  1208             	{
       
  1209                 chFatEnt.SetStartCluster(parentDirStartCluster_New);
       
  1210                 WriteDirEntryL(parentPtrEntPos, chFatEnt);
       
  1211             	}
       
  1212             // Invalidate leaf dir cache as it is hard to track the dir structure changes now
       
  1213             if (iLeafDirCache)
       
  1214             	{
       
  1215                 iLeafDirCache->Reset();
       
  1216             	}
       
  1217         	}
       
  1218     	}//else if(replaceMode && newFileExists)
       
  1219 
       
  1220     iFileCreationHelper.Close();
       
  1221 	}
       
  1222 
       
  1223 //-----------------------------------------------------------------------------------------
       
  1224 
       
  1225 /**
       
  1226     Rename 'aOldName' file/directory to 'aNewName'
       
  1227     all trailing dots from the names will be removed
       
  1228 
       
  1229     @param  aOldName        existing object name
       
  1230     @param  aNewName        new object name
       
  1231 */
       
  1232 void CFatMountCB::RenameL(const TDesC& aOldName, const TDesC& aNewName)
       
  1233     {
       
  1234     __PRINT3(_L("CFatMountCB::RenameL, drv:%d, %S %S"), DriveNumber(), &aOldName, &aNewName);
       
  1235 
       
  1236     CheckStateConsistentL();
       
  1237     CheckWritableL();
       
  1238 
       
  1239     TEntryPos newEntryPos;
       
  1240     DoRenameOrReplaceL(RemoveTrailingDots(aOldName), RemoveTrailingDots(aNewName) ,EModeRename, newEntryPos);
       
  1241 
       
  1242     if(!IsRuggedFSys())
       
  1243         FAT().FlushL();
       
  1244     }
       
  1245 
       
  1246 //-----------------------------------------------------------------------------------------
       
  1247 
       
  1248 /**
       
  1249     Replace contents of the 'aNewName' with the contents of 'aOldName'
       
  1250     all trailing dots from the names will be removed
       
  1251 
       
  1252     @param  aOldName        existing object name
       
  1253     @param  aNewName        new object name
       
  1254 */
       
  1255 void CFatMountCB::ReplaceL(const TDesC& aOldName,const TDesC& aNewName)
       
  1256     {
       
  1257 
       
  1258     __PRINT3(_L("CFatMountCB::ReplaceL, drv:%d, %S %S"), DriveNumber(), &aOldName, &aNewName);
       
  1259 
       
  1260     CheckStateConsistentL();
       
  1261     CheckWritableL();
       
  1262 
       
  1263     TEntryPos newEntryPos;
       
  1264     DoRenameOrReplaceL(RemoveTrailingDots(aOldName), RemoveTrailingDots(aNewName), EModeReplace, newEntryPos);
       
  1265     if(!IsRuggedFSys())
       
  1266         FAT().FlushL();
       
  1267     }
       
  1268 
       
  1269 //-----------------------------------------------------------------------------------------
       
  1270 
       
  1271 
       
  1272 /**
       
  1273     Try to find a directory entry by the given name and path.
       
  1274     This method _must_ leave if the entry is not found. See the caller.
       
  1275 
       
  1276     @param  aName   path to the directory object. all trailing dots from the name will be removed.
       
  1277     @param  anEntry on return will contain the entry data
       
  1278 
       
  1279     @leave  KErrPathNotFound if there is no path to the aName
       
  1280             KErrNotFound     if the entry corresponding to the aName is not found
       
  1281             system-wide erorr code of media read failure.
       
  1282 */
       
  1283 void CFatMountCB::EntryL(const TDesC& aName,TEntry& anEntry) const
       
  1284     {
       
  1285     __PRINT2(_L("CFatMountCB::EntryL, drv:%d, %S"), DriveNumber(), &aName);
       
  1286 
       
  1287     CheckStateConsistentL();
       
  1288 
       
  1289     TEntryPos entryPos(RootIndicator(),0);
       
  1290     TFatDirEntry entry;
       
  1291     TPtr fileName(anEntry.iName.Des());
       
  1292 
       
  1293     TPtrC fullName = RemoveTrailingDots(aName);
       
  1294     TInt namePos=fullName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
  1295     TLeafDirData leafDir;
       
  1296     entryPos.iCluster=FindLeafDirL(fullName.Left(namePos), leafDir);
       
  1297     entryPos.iPos=0;
       
  1298     TEntryPos startPos;
       
  1299     TFatDirEntry startEntry;
       
  1300 
       
  1301     DoFindL(fullName.Mid(namePos),KEntryAttMaskSupported,
       
  1302     		startPos,startEntry,entryPos,entry,
       
  1303     		fileName,KErrNotFound,
       
  1304     		NULL,
       
  1305     		leafDir);
       
  1306 
       
  1307 
       
  1308     anEntry.iAtt=entry.Attributes();
       
  1309     anEntry.iSize=entry.Size();
       
  1310     anEntry.iModified=entry.Time(TimeOffset());
       
  1311 
       
  1312 	if (fileName.Length()==0)
       
  1313         {
       
  1314         TBuf8<0x20> dosName(DosNameFromStdFormat(entry.Name()));
       
  1315         LocaleUtils::ConvertToUnicodeL(fileName,dosName);
       
  1316         }
       
  1317     if ((TUint)anEntry.iSize>=sizeof(TCheckedUid))
       
  1318         ReadUidL(StartCluster(entry),anEntry);
       
  1319     }
       
  1320 
       
  1321 //-----------------------------------------------------------------------------------------
       
  1322 
       
  1323 /**
       
  1324     Set directory entry details.
       
  1325     @param  aName           entry name; all trailing dots from the name will be removed
       
  1326     @param  aTime           entry modification time (and last access as well)
       
  1327     @param  aSetAttMask     entry attributes OR mask
       
  1328     @param  aClearAttMask   entry attributes AND mask
       
  1329 
       
  1330 */
       
  1331 void CFatMountCB::SetEntryL(const TDesC& aName,const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
       
  1332     {
       
  1333     __PRINT2(_L("CFatMountCB::SetEntryL, drv:%d, %S"), DriveNumber(), &aName);
       
  1334 
       
  1335     CheckStateConsistentL();
       
  1336     CheckWritableL();
       
  1337 
       
  1338     TEntryPos firstEntryPos(RootIndicator(),0);
       
  1339     TFatDirEntry firstEntry;
       
  1340     FindEntryStartL(RemoveTrailingDots(aName),KEntryAttMaskSupported,firstEntry,firstEntryPos);
       
  1341     MoveToDosEntryL(firstEntryPos,firstEntry);
       
  1342     TUint setAttMask=aSetAttMask&KEntryAttMaskSupported;
       
  1343     if (setAttMask|aClearAttMask)
       
  1344         {
       
  1345         TInt att=firstEntry.Attributes();
       
  1346         att|=setAttMask;
       
  1347         att&=(~aClearAttMask);
       
  1348         firstEntry.SetAttributes(att);
       
  1349         }
       
  1350     if (aSetAttMask&KEntryAttModified)
       
  1351 		{
       
  1352 		firstEntry.SetTime(aTime,TimeOffset());
       
  1353 		}
       
  1354     WriteDirEntryL(firstEntryPos,firstEntry);
       
  1355     }
       
  1356 
       
  1357 //-----------------------------------------------------------------------------------------
       
  1358 
       
  1359 void CFatMountCB::DoCheckFatForLoopsL(TInt aCluster, TInt& aPreviousCluster, TInt& aChangePreviousCluster, TInt& aCount) const
       
  1360 //
       
  1361 // Check one fat cluster for loops.
       
  1362 //
       
  1363     {
       
  1364 
       
  1365     if (aCluster==aPreviousCluster)
       
  1366         User::Leave(KErrCorrupt); // Found loop
       
  1367 
       
  1368     aCount++;
       
  1369     if (aCount==aChangePreviousCluster)
       
  1370         {
       
  1371         aCount=0;
       
  1372         aChangePreviousCluster<<=1;
       
  1373         aPreviousCluster=aCluster;
       
  1374         }
       
  1375     }
       
  1376 
       
  1377 //-----------------------------------------------------------------------------------------
       
  1378 
       
  1379 void CFatMountCB::CheckFatForLoopsL(const TFatDirEntry& anEntry) const
       
  1380 //
       
  1381 // Check for loops
       
  1382 //
       
  1383     {
       
  1384 
       
  1385     TInt cluster=StartCluster(anEntry);
       
  1386     if (cluster==0 && anEntry.Size()==0)
       
  1387         return;
       
  1388 
       
  1389     TInt previousCluster=cluster;
       
  1390     TInt changePreviousCluster=1;
       
  1391     TInt count=0;
       
  1392 
       
  1393 
       
  1394     for(;;)
       
  1395         {
       
  1396         if ((TUint)cluster < KFatFirstSearchCluster || (!IsEndOfClusterCh(cluster) && (TUint)cluster>MaxClusterNumber()))
       
  1397             User::Leave(KErrCorrupt);
       
  1398 
       
  1399          if(!FAT().GetNextClusterL(cluster))
       
  1400             break;
       
  1401 
       
  1402          DoCheckFatForLoopsL(cluster, previousCluster, changePreviousCluster, count);
       
  1403         }
       
  1404 
       
  1405     }
       
  1406 
       
  1407 //-----------------------------------------------------------------------------------------
       
  1408 
       
  1409 /**
       
  1410     Open/Create/Replace a file on the current mount.
       
  1411 
       
  1412     @param  aName   file name; all trailing dots from the name will be removed
       
  1413     @param  aMode   File open mode, See TFileMode
       
  1414     @param  anOpen  specifies action: open, create or replace the file
       
  1415     @param  aFile   pointer to the CFileCB object to populate
       
  1416 
       
  1417 */
       
  1418 void CFatMountCB::FileOpenL(const TDesC& aName,TUint aMode,TFileOpen anOpen,CFileCB* aFile)
       
  1419     {
       
  1420     __PRINT3(_L("CFatMountCB::FileOpenL, drv:%d, mode:%d, name:%S"), DriveNumber(), anOpen, &aName);
       
  1421 
       
  1422     CheckStateConsistentL();
       
  1423 
       
  1424     TPtrC fullName = RemoveTrailingDots(aName); //-- remove trailing dots from the name
       
  1425 
       
  1426     TFatDirEntry firstEntry;
       
  1427     TEntryPos firstEntryPos(RootIndicator(),0);
       
  1428     TInt nPos=fullName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
  1429     TPtrC name(fullName.Mid(nPos));
       
  1430     TInt ret = KErrNone;
       
  1431 
       
  1432     iFileCreationHelper.Close();
       
  1433     if (anOpen == EFileCreate || anOpen == EFileReplace)
       
  1434     	{
       
  1435     	iFileCreationHelper.InitialiseL(name);
       
  1436         TRAP(ret,FindEntryStartL(fullName,KEntryAttMaskSupported,firstEntry,firstEntryPos,&iFileCreationHelper));
       
  1437     	}
       
  1438     else
       
  1439         {
       
  1440         TRAP(ret,FindEntryStartL(fullName,KEntryAttMaskSupported,firstEntry,firstEntryPos));
       
  1441         }
       
  1442 
       
  1443     if (ret!=KErrNone && ret!=KErrNotFound)
       
  1444         User::Leave(ret);
       
  1445 
       
  1446     if (ret==KErrNone)
       
  1447         {
       
  1448         MoveToDosEntryL(firstEntryPos,firstEntry);
       
  1449         if ((firstEntry.Attributes()&KEntryAttDir) || (firstEntry.Attributes()&KEntryAttVolume))
       
  1450             User::Leave(KErrAccessDenied);
       
  1451         if (anOpen==EFileCreate)
       
  1452             User::Leave(KErrAlreadyExists);
       
  1453         if ((firstEntry.Attributes()&KEntryAttReadOnly) && aMode&EFileWrite)
       
  1454             User::Leave(KErrAccessDenied);
       
  1455         if((aMode & EFileWrite) && (IsFileClamped(StartCluster(firstEntry))>0))
       
  1456             User::Leave(KErrInUse);
       
  1457         CheckFatForLoopsL(firstEntry);
       
  1458         }
       
  1459     else
       
  1460         {
       
  1461         if (anOpen==EFileOpen)
       
  1462             User::Leave(KErrNotFound);
       
  1463 
       
  1464         //-- here we try to either create or replace file
       
  1465         CheckWritableL();
       
  1466 
       
  1467     	TLeafDirData leafDir;
       
  1468 
       
  1469         TInt numEntries = iFileCreationHelper.NumOfAddingEntries();
       
  1470         TShortName shortName;
       
  1471         if (iFileCreationHelper.GetValidatedShortName(shortName) == KErrNotFound)
       
  1472         	{
       
  1473             firstEntryPos.iCluster=FindLeafDirL(fullName.Left(nPos), leafDir);
       
  1474             GenerateShortNameL(firstEntryPos.iCluster,name,shortName,ETrue);
       
  1475         	}
       
  1476 
       
  1477         if (iFileCreationHelper.IsNewEntryPosFound())
       
  1478 	    	{
       
  1479 	    	firstEntryPos = iFileCreationHelper.EntryAddingPos();
       
  1480 	    	}
       
  1481         else
       
  1482         	{
       
  1483         	firstEntryPos.iCluster=FindLeafDirL(fullName.Left(nPos), leafDir);
       
  1484         	firstEntryPos.iPos=0;
       
  1485         	}
       
  1486 
       
  1487         AddDirEntryL(firstEntryPos,numEntries);
       
  1488         firstEntry.InitZ();
       
  1489         firstEntry.SetName(shortName);
       
  1490         firstEntry.SetStartCluster(0);
       
  1491 
       
  1492         TTime now;
       
  1493 		now.UniversalTime();
       
  1494         firstEntry.SetCreateTime(now, TimeOffset() );
       
  1495 
       
  1496         if (iFileCreationHelper.IsTrgNameLegalDosName())
       
  1497             WriteDirEntryL(firstEntryPos,firstEntry);
       
  1498         else
       
  1499             WriteDirEntryL(firstEntryPos,firstEntry,name);
       
  1500         }
       
  1501 
       
  1502     CFatFileCB& file=(*((CFatFileCB*)aFile));
       
  1503     file.SetL(firstEntry,(TShare)(aMode&KFileShareMask),firstEntryPos);
       
  1504     if (anOpen==EFileReplace && file.Size())
       
  1505         {
       
  1506         file.SetSizeL(0);
       
  1507         file.SetSize(0);
       
  1508         }
       
  1509     if (file.IsSeekIndex()==EFalse)
       
  1510         file.CreateSeekIndex();
       
  1511     if (anOpen==EFileReplace || anOpen==EFileCreate)
       
  1512         file.SetArchiveAttribute();
       
  1513 
       
  1514     if(!IsRuggedFSys())
       
  1515         FAT().FlushL();
       
  1516 
       
  1517     iFileCreationHelper.Close();
       
  1518     }
       
  1519 
       
  1520 //-----------------------------------------------------------------------------------------
       
  1521 
       
  1522 
       
  1523 /**
       
  1524     Open a directory on the current mount.
       
  1525 
       
  1526     @param  aName   path to the object in the directory we want to open; all trailing dots from the name will be removed
       
  1527     @param  aDir    dir. CB to be filled in.
       
  1528 
       
  1529     If there is no such a path, this method must leave with KErrPathNotFound
       
  1530 
       
  1531     @leave  KErrPathNotFound if thereis no such path
       
  1532     @leave  error code on media read fault
       
  1533 */
       
  1534 void CFatMountCB::DirOpenL(const TDesC& aName,CDirCB* aDir)
       
  1535     {
       
  1536     __PRINT2(_L("CFatMountCB::DirOpenL, drv:%d, %S"), DriveNumber(), &aName);
       
  1537 
       
  1538     CheckStateConsistentL();
       
  1539 
       
  1540     const TPtrC dirName = RemoveTrailingDots(aName); //-- remove trailing dots from the name
       
  1541 
       
  1542     TInt namePos=dirName.LocateReverse(KPathDelimiter);
       
  1543 
       
  1544     TFatDirEntry dosEntry;
       
  1545     TEntryPos dosEntryPos(RootIndicator(),0);
       
  1546     if (namePos==0)
       
  1547         InitializeRootEntry(dosEntry);
       
  1548     else
       
  1549         {
       
  1550         TPtrC dirPath=dirName.Left(namePos);
       
  1551         TInt dirPos=dirPath.LocateReverse(KPathDelimiter)+1;
       
  1552         TLeafDirData leafDir;
       
  1553         dosEntryPos.iCluster=FindLeafDirL(dirPath.Left(dirPos), leafDir); // Find directory before leaf
       
  1554         dosEntryPos.iPos=0;
       
  1555 
       
  1556         TFileName fileName;
       
  1557         TEntryPos startPos;
       
  1558         TFatDirEntry startEntry;
       
  1559         DoFindL(dirPath.Mid(dirPos),
       
  1560         		KEntryAttMatchMask|KEntryAttMatchExclusive,
       
  1561         		startPos, startEntry, dosEntryPos, dosEntry,
       
  1562         		fileName, KErrPathNotFound,
       
  1563         		NULL,
       
  1564         		leafDir);
       
  1565 
       
  1566 
       
  1567         }
       
  1568 
       
  1569     TPtrC matchName(dirName.Mid(namePos+1));
       
  1570     if (matchName.Length()==0)
       
  1571         matchName.Set(_L("*"));
       
  1572 
       
  1573     ((CFatDirCB*)aDir)->SetDirL(dosEntry,matchName);
       
  1574 
       
  1575     }
       
  1576 
       
  1577 //-----------------------------------------------------------------------------------------
       
  1578 
       
  1579 TBool CFatMountCB::IsDirectoryEmptyL(TInt aCluster)
       
  1580 //
       
  1581 // Check aCluster contains no directory entries other than . and ..
       
  1582 //
       
  1583     {
       
  1584 
       
  1585     __PRINT(_L("CFatMountCB::IsDirectoryEmptyL"));
       
  1586     TEntryPos dirEntryPos(aCluster,0);
       
  1587     TFatDirEntry dirEntry;
       
  1588     FOREVER
       
  1589         {
       
  1590         ReadDirEntryL(dirEntryPos,dirEntry);
       
  1591         MoveToDosEntryL(dirEntryPos,dirEntry);
       
  1592         if (dirEntry.IsParentDirectory() || dirEntry.IsCurrentDirectory())
       
  1593             goto LoopEnd;
       
  1594         if (dirEntry.IsEndOfDirectory())
       
  1595             return ETrue;
       
  1596         if (IsRootDir(dirEntryPos)&&(dirEntryPos.iPos+StartOfRootDirInBytes()==RootDirEnd()))
       
  1597             return ETrue;   //  Root Directory has no end of directory marker
       
  1598         if (!dirEntry.IsErased())
       
  1599             return EFalse;
       
  1600 LoopEnd:
       
  1601         MoveToNextEntryL(dirEntryPos);
       
  1602         }
       
  1603     }
       
  1604 
       
  1605 //-----------------------------------------------------------------------------------------
       
  1606 
       
  1607 /**
       
  1608     Overwrite as many contiguous file clusters as possible.
       
  1609 */
       
  1610 void CFatMountCB::DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TInt aLastcluster, TInt &aBadcluster, TInt &aGoodcluster)
       
  1611     {
       
  1612 
       
  1613     __PRINT(_L("CFatMountCB::DoWriteToClusterListL"));
       
  1614     __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
       
  1615 
       
  1616     TInt endCluster=0;
       
  1617 
       
  1618     const TInt clusterRelativePos=ClusterRelativePos(aPos.iPos);
       
  1619     const TInt maxClusters=((aLength+clusterRelativePos-1)>>ClusterSizeLog2())+1;
       
  1620     const TInt clusterListLen=FAT().CountContiguousClustersL(aPos.iCluster,endCluster,maxClusters);
       
  1621     const TInt writeLength=Min(aLength,(clusterListLen<<ClusterSizeLog2())-clusterRelativePos);
       
  1622     TInt64 dataStart=FAT().DataPositionInBytes(aPos.iCluster)+clusterRelativePos;
       
  1623 
       
  1624     TRAPD(r, iRawDisk->WriteL(dataStart,writeLength,aSrc,aMessage,anOffset));
       
  1625 
       
  1626     if(r == KErrNone) // Write succeded
       
  1627         {
       
  1628         aPos.iPos+=writeLength;
       
  1629         aPos.iCluster=endCluster;
       
  1630         return;
       
  1631         }
       
  1632 
       
  1633     if(r != KErrCorrupt) // failure not due to corruption so propogate up
       
  1634         User::Leave(r);
       
  1635 
       
  1636     TErrorInfoBuf errinf;
       
  1637     r = iRawDisk->GetLastErrorInfo(errinf);
       
  1638 
       
  1639     if(r == KErrNone && errinf().iReasonCode == TErrorInfo::EBadSector) // GetLastErrorInfo succeded and Last Error was caused by bad sector
       
  1640         {
       
  1641 
       
  1642         const TInt badcluster = (TInt)(((dataStart + errinf().iErrorPos) - ClusterBasePosition())>>ClusterSizeLog2())+KFatFirstSearchCluster;
       
  1643               TInt goodcluster = FAT().AllocateSingleClusterL(badcluster);
       
  1644 
       
  1645         //Calculate cluster number to check whether this write started at the beginning of new cluster or middle of previous cluster.
       
  1646         TInt cluster = aPos.iCluster;
       
  1647         if ( (aPos.iPos) && ((aPos.iPos)==((aPos.iPos >> ClusterSizeLog2())<<ClusterSizeLog2())))
       
  1648             cluster--;
       
  1649 
       
  1650         if((aPos.iPos != 0) && (badcluster == aPos.iCluster) && (aLastcluster == 0) && (aPos.iCluster == cluster))
       
  1651             { //Copy the contents already present in this cluster to new cluster allocated.
       
  1652             const TInt sizeToRead = aPos.iPos - ((aPos.iPos >> ClusterSizeLog2()) << ClusterSizeLog2());
       
  1653             dataStart = FAT().DataPositionInBytes(aPos.iCluster) + ClusterRelativePos((aPos.iPos - sizeToRead));
       
  1654 
       
  1655 
       
  1656             //-- Allocate the buffer required to copy the contents from bad cluster
       
  1657             RBuf8 clustBuf;
       
  1658             CleanupClosePushL(clustBuf);
       
  1659             if(clustBuf.CreateMax(sizeToRead) != KErrNone)
       
  1660                 {
       
  1661                 FAT().FreeClusterListL(goodcluster);
       
  1662                 User::Leave(KErrNoMemory);
       
  1663                 }
       
  1664 
       
  1665             r = LocalDrive()->Read(dataStart, sizeToRead, clustBuf); //Read the contents into buffer
       
  1666             if(r != KErrNone) //If read fails dont do anything not even marking bad cluster.
       
  1667                 {
       
  1668                 FAT().FreeClusterListL(goodcluster);
       
  1669                 User::Leave(r);
       
  1670                 }
       
  1671 
       
  1672             //Copy the bad and good cluster,required to adjust the start cluster number.
       
  1673             if(aBadcluster == 0)
       
  1674                 aBadcluster = badcluster;
       
  1675 
       
  1676             aGoodcluster = goodcluster;
       
  1677 
       
  1678             FOREVER
       
  1679                 {
       
  1680                 //Calculate and copy the contents to new cluster.
       
  1681                 aPos.iCluster = goodcluster;
       
  1682                 dataStart = FAT().DataPositionInBytes(aPos.iCluster) + ClusterRelativePos(aPos.iPos - sizeToRead);
       
  1683 
       
  1684                 r = LocalDrive()->Write(dataStart, clustBuf);
       
  1685                 if(r == KErrNone)
       
  1686                     { // Copied contents to new cluster so fix up the chain and mark the cluster as bad.
       
  1687                     FAT().WriteL(goodcluster, FAT().ReadL(badcluster));
       
  1688                     FAT().MarkAsBadClusterL(badcluster);
       
  1689                     aGoodcluster = goodcluster;
       
  1690                     CleanupStack::PopAndDestroy(&clustBuf); //-- deallocate a cluster buffer
       
  1691                     return;
       
  1692                     }
       
  1693                 else if(r == KErrCorrupt)
       
  1694                     {
       
  1695                     r = LocalDrive()->GetLastErrorInfo(errinf);
       
  1696                     if(r == KErrNone && errinf().iReasonCode == TErrorInfo::EBadSector)
       
  1697                         { //Allocate new cluster and adjust the cluster list.
       
  1698                         goodcluster = FAT().AllocateSingleClusterL(aPos.iCluster);
       
  1699                         FAT().MarkAsBadClusterL(aPos.iCluster);
       
  1700                         continue;
       
  1701                         }
       
  1702                         r = KErrCorrupt;
       
  1703                     }
       
  1704                     //Not able to write successfully so dont alter the original list.
       
  1705                     aBadcluster = aGoodcluster = 0;
       
  1706                     FAT().FreeClusterListL(goodcluster);
       
  1707                     User::Leave(r);
       
  1708                 }
       
  1709 
       
  1710         }//if((aPos.iPos != 0) && (badcluster == aPos.iCluster) && (aLastcluster == 0) && (aPos.iCluster == cluster))
       
  1711 
       
  1712         if((badcluster == aPos.iCluster) && (aLastcluster == 0)) //bad cluster at beginning of original clusterlist
       
  1713             {
       
  1714             // return bad and good clusters for CFatFileCB to fix up
       
  1715             FAT().WriteL(goodcluster, FAT().ReadL(badcluster));
       
  1716             aBadcluster = badcluster;
       
  1717             aGoodcluster = goodcluster;
       
  1718             aPos.iCluster = goodcluster;
       
  1719             }
       
  1720         else    //fix up chain
       
  1721             {
       
  1722             FAT().WriteL(goodcluster, FAT().ReadL(badcluster));
       
  1723             if(badcluster > aPos.iCluster)  //bad cluster not first in this contiguous list
       
  1724                 FAT().WriteL(badcluster-1, goodcluster);
       
  1725             else    //first cluster of this contigous list bad so update last cluster of previous contiguous list
       
  1726                 FAT().WriteL(aLastcluster, goodcluster);
       
  1727             }
       
  1728 
       
  1729         FAT().MarkAsBadClusterL(badcluster);
       
  1730 
       
  1731 
       
  1732         return;
       
  1733         }
       
  1734     User::Leave(KErrCorrupt);
       
  1735     }
       
  1736 
       
  1737 //-----------------------------------------------------------------------------------------
       
  1738 
       
  1739 void CFatMountCB::WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TInt &aBadcluster, TInt& aGoodcluster)
       
  1740 //
       
  1741 // Overwrite cluster list.
       
  1742 //
       
  1743     {
       
  1744 
       
  1745     __PRINT(_L("CFatMountCB::WriteToClusterListL"));
       
  1746     __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
       
  1747 
       
  1748     const TUint startPos=aPos.iPos;
       
  1749     const TUint temp=startPos>>ClusterSizeLog2();
       
  1750     const TUint length = (TUint)aLength;
       
  1751 
       
  1752     if ( (startPos) && ((startPos)==(temp<<ClusterSizeLog2())) )
       
  1753         {
       
  1754         __ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt));
       
  1755         }
       
  1756 
       
  1757     TUint offset=0;
       
  1758     TInt previouscluster=0;
       
  1759     FOREVER
       
  1760         {
       
  1761         DoWriteToClusterListL(aPos,length-offset,aSrc,aMessage,anOffset+offset, previouscluster, aBadcluster, aGoodcluster);
       
  1762         if (offset == (aPos.iPos-startPos))
       
  1763             continue;
       
  1764         offset=aPos.iPos-startPos;
       
  1765         __ASSERT_ALWAYS(aPos.iPos>startPos,User::Leave(KErrCorrupt));
       
  1766         previouscluster=aPos.iCluster;
       
  1767         if (offset<length)
       
  1768             {__ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt));}
       
  1769         if (offset>=length)
       
  1770             return;
       
  1771         }
       
  1772     }
       
  1773 
       
  1774 //-----------------------------------------------------------------------------------------
       
  1775 
       
  1776 void CFatMountCB::DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const
       
  1777 //
       
  1778 // Read from as many contiguous file clusters as possible
       
  1779 //
       
  1780     {
       
  1781 
       
  1782     __PRINT(_L("CFatMountCB::DoReadFromClusterListL"));
       
  1783 
       
  1784     TInt endCluster=0;
       
  1785 
       
  1786     const TInt clusterRelativePos=ClusterRelativePos(aPos.iPos);
       
  1787     const TInt maxClusters=((aLength+clusterRelativePos-1)>>ClusterSizeLog2())+1;
       
  1788     const TInt clusterListLen=FAT().CountContiguousClustersL(aPos.iCluster,endCluster,maxClusters);
       
  1789     const TInt readLength=Min(aLength,(clusterListLen<<ClusterSizeLog2())-clusterRelativePos);
       
  1790     const TInt64 dataStart=FAT().DataPositionInBytes(aPos.iCluster)+clusterRelativePos;
       
  1791 
       
  1792     TRAPD(r, iRawDisk->ReadL(dataStart,readLength,aTrg,aMessage,anOffset));
       
  1793 
       
  1794     if(r == KErrNone) // Read succeded
       
  1795         {
       
  1796         aPos.iPos+=readLength;
       
  1797         aPos.iCluster=endCluster;
       
  1798         return;
       
  1799         }
       
  1800     if(r != KErrCorrupt) // failure not due to corruption so propogate up
       
  1801         User::Leave(r);
       
  1802 
       
  1803     TErrorInfoBuf errinf;
       
  1804     r = iRawDisk->GetLastErrorInfo(errinf);
       
  1805 
       
  1806     if(r == KErrNone && errinf().iReasonCode == TErrorInfo::EBadSector) // GetLastErrorInfo succeded and Last Error was caused by bad sector
       
  1807         {
       
  1808         TInt badcluster = (TInt)(((dataStart + errinf().iErrorPos) - ClusterBasePosition())>>ClusterSizeLog2())+KFatFirstSearchCluster;
       
  1809         FAT().MarkAsBadClusterL(badcluster);
       
  1810         }
       
  1811 
       
  1812     User::Leave(KErrCorrupt);
       
  1813     }
       
  1814 
       
  1815 //-----------------------------------------------------------------------------------------
       
  1816 
       
  1817 void CFatMountCB::ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const
       
  1818 //
       
  1819 // Read from cluster list
       
  1820 //
       
  1821     {
       
  1822 
       
  1823     __PRINT(_L("CFatMountCB::ReadFromClusterListL"));
       
  1824     __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
       
  1825 
       
  1826     const TInt startPos=aPos.iPos;
       
  1827     const TInt temp=startPos>>ClusterSizeLog2();
       
  1828 
       
  1829     if ( (startPos) && ((startPos)==(temp<<ClusterSizeLog2())) )
       
  1830         {
       
  1831         __ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt));
       
  1832         }
       
  1833 
       
  1834     TInt offset=0;
       
  1835     FOREVER
       
  1836         {
       
  1837         DoReadFromClusterListL(aPos,aLength-offset,aTrg,aMessage,anOffset+offset);
       
  1838         offset=aPos.iPos-startPos;
       
  1839         if ((offset<aLength))
       
  1840             {
       
  1841             __ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt));
       
  1842             }
       
  1843         if (offset>=aLength)
       
  1844             return;
       
  1845         }
       
  1846     }
       
  1847 
       
  1848 //-----------------------------------------------------------------------------------------
       
  1849 
       
  1850 TInt CFatMountCB::FindLeafDirL(const TDesC& aName, TLeafDirData& aLeafDir) const
       
  1851 //
       
  1852 // Navigate the path to find the leaf directory.
       
  1853 // Returns the startcluster of data for the directory found.
       
  1854 //
       
  1855     {
       
  1856 
       
  1857     __PRINT(_L("CFatMountCB::FindLeafDirL"));
       
  1858 
       
  1859     TLex lex(aName);
       
  1860     TInt r;
       
  1861     TEntryPos entryPos(RootIndicator(),0);
       
  1862 
       
  1863     if (iLeafDirCache == NULL)
       
  1864     	{
       
  1865         TInt leaflen=(iLastLeafDir) ? iLastLeafDir->Length() : 0;
       
  1866         TInt namelen=aName.Length();
       
  1867         if (leaflen>1 && namelen>=leaflen && *iLastLeafDir==aName.Left(leaflen))
       
  1868             {
       
  1869             if (leaflen==namelen)
       
  1870                 return(iLastLeafDirCluster);
       
  1871             lex.Inc(leaflen-1);
       
  1872             entryPos.iCluster=iLastLeafDirCluster;
       
  1873             }
       
  1874     	}
       
  1875     else
       
  1876     	{
       
  1877         // Skip root directory
       
  1878         if (iLeafDirCache->CacheCount() > 0 && aName.Length() > 1)
       
  1879         	{
       
  1880         	TInt err = iLeafDirCache->FindInCache(aName, aLeafDir);
       
  1881         	if (err == KErrNone)
       
  1882         		{
       
  1883         		ASSERT(aLeafDir.iClusterNum > 0);
       
  1884         		return aLeafDir.iClusterNum;
       
  1885         		}
       
  1886         	else if (err != KErrNotFound)
       
  1887         		{
       
  1888         		User::LeaveIfError(err);
       
  1889         		}
       
  1890         	}
       
  1891     	}
       
  1892 
       
  1893     FOREVER
       
  1894         {
       
  1895         lex.Inc(); // Skip path delimiter
       
  1896         lex.Mark();
       
  1897         r=lex.Remainder().Locate(KPathDelimiter);
       
  1898         if (r==KErrNotFound)
       
  1899             r=lex.Remainder().Length();
       
  1900         if (r==0) // End of the path
       
  1901             break;
       
  1902         lex.Inc(r); // Set the token length
       
  1903         TFatDirEntry entry;
       
  1904 
       
  1905         TFileName fileName;
       
  1906         TEntryPos startPos;
       
  1907         TFatDirEntry startEntry;
       
  1908         DoFindL(lex.MarkedToken(),
       
  1909         		KEntryAttMatchMask|KEntryAttMatchExclusive,
       
  1910         		startPos, startEntry, entryPos, entry,
       
  1911         		fileName, KErrPathNotFound,
       
  1912         		NULL,
       
  1913         		aLeafDir);
       
  1914 
       
  1915 
       
  1916         entryPos.iCluster=StartCluster(entry);
       
  1917         entryPos.iPos=0;
       
  1918         }
       
  1919 
       
  1920     if (iLeafDirCache == NULL)
       
  1921     	{
       
  1922         AllocBufferL(((CFatMountCB*)this)->iLastLeafDir,aName);
       
  1923         ((CFatMountCB*)this)->iLastLeafDirCluster=entryPos.iCluster;
       
  1924     	}
       
  1925     else
       
  1926     	{
       
  1927         if (aName.Length() > 1)
       
  1928         	{
       
  1929         	aLeafDir = TLeafDirData(entryPos.iCluster);
       
  1930             iLeafDirCache->AddToCacheL(aName, aLeafDir);
       
  1931         	}
       
  1932     	}
       
  1933 
       
  1934     return entryPos.iCluster;
       
  1935     }
       
  1936 
       
  1937 //-----------------------------------------------------------------------------------------
       
  1938 
       
  1939 /**
       
  1940     Search for a specified name winthin directory cache
       
  1941     Works similary to TBool CFatMountCB::DoFindL()
       
  1942 
       
  1943     @param  anAtt           attributes of the object to find
       
  1944     @param  aStartEntryPos  on return in case of VFAT entry will contain start position of the VFAT dir. entry
       
  1945     @param  aStartEntry     on return will contain first VFAT dir entry
       
  1946     @param  aDosEntryPos    the search will start from this position of dir entry, on return it will contain result DOS entry position, last one for VFAT case
       
  1947     @param  aDosEntry       on return will contain DOS dir entry (the last one for VFAT case)
       
  1948     @param  aFileName       in the case of VFAT entry and on success here will be returned a long filename
       
  1949     @param  aAuxParam       some parameters package
       
  1950     @param  aFileCreationHelper       a helper package for file creations
       
  1951 
       
  1952     @return ETrue if the specified name is found in the cache. In this case aStartEntryPos, aStartEntry, aDosEntryPos, aDosEntry, aFileName will contain valid values
       
  1953 */
       
  1954 TBool CFatMountCB::DoRummageDirCacheL(const TUint anAtt, TEntryPos& aStartEntryPos,  
       
  1955 										TFatDirEntry& aStartEntry,	TEntryPos& aDosEntryPos,
       
  1956 										TFatDirEntry& aDosEntry,	TDes& aFileName,
       
  1957 										const TFindHelper& aAuxParam,
       
  1958 										XFileCreationHelper* aFileCreationHelper,
       
  1959 										const TLeafDirData& aLeafDir) const
       
  1960 	{
       
  1961     TBool bCacheMatchFound = EFalse;
       
  1962 
       
  1963     //-- get an interface to the Dir. cache
       
  1964     MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface();
       
  1965     ASSERT(pDirCache);
       
  1966     if(!pDirCache)
       
  1967         return EFalse;
       
  1968 
       
  1969     //-- save original values in order to restore them in the case of negative search results
       
  1970     TEntryPos       StartEntryPos1(aStartEntryPos);
       
  1971     TEntryPos       DosEntryPos1(aDosEntryPos);
       
  1972     TFatDirEntry    StartEntry1(aStartEntry);
       
  1973     TFatDirEntry    DosEntry1(aDosEntry);
       
  1974 
       
  1975     TInt64          nCachedLinPos;
       
  1976 
       
  1977     const TUint32 clSize = 1 << ClusterSizeLog2(); //-- media cluster size
       
  1978     const TUint32 cacheSz = pDirCache->CacheSizeInBytes(); //-- cache size in bytes
       
  1979     const TUint32 maxDirEntries = cacheSz >> KSizeOfFatDirEntryLog2;  //-- maximal number of dir entries that can be in the cache
       
  1980 
       
  1981     const TUint	  pageSzLog2 = pDirCache->PageSizeInBytesLog2();
       
  1982     TBool ScanMRUPageFirst 	= EFalse;
       
  1983 	TBool MRUPageScanned 	= EFalse;
       
  1984 
       
  1985 	// if MRU pos is availale, start with MRU page
       
  1986 	if (aLeafDir.iMRUPos.Cluster())
       
  1987     	{
       
  1988     	ScanMRUPageFirst = ETrue;
       
  1989     	DosEntryPos1 = aLeafDir.iMRUPos;
       
  1990     	}
       
  1991 
       
  1992 	TInt numFound = 0;
       
  1993 	TEntryPos startPos = DosEntryPos1;
       
  1994 	TInt clusterNum = DosEntryPos1.iCluster;
       
  1995 
       
  1996     for(TUint32 entryCnt=0; entryCnt < maxDirEntries; ++entryCnt)
       
  1997         {//-- walk through directory cluster list. The loop is limited by maximal number of dir entries
       
  1998          //-- that can be cached. Helps to avoid problems with infinite (looped) directories
       
  1999 
       
  2000         if (IsEndOfClusterCh(DosEntryPos1.iCluster))
       
  2001         	{
       
  2002         	// refer back to the last stored cluster position
       
  2003         	//  note aFileCreationHelper may not be initialised for file opening operations
       
  2004         	if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && clusterNum != DosEntryPos1.iCluster)
       
  2005         		{
       
  2006         	    TEntryPos dummyPos(clusterNum, clSize - KSizeOfFatDirEntry);
       
  2007         	    aFileCreationHelper->SetEntryAddingPos(dummyPos);
       
  2008         		aFileCreationHelper->SetIsNewEntryPosFound(ETrue);
       
  2009         		}
       
  2010 
       
  2011         	if (ScanMRUPageFirst && !MRUPageScanned)
       
  2012         		{
       
  2013             	DosEntryPos1 = aDosEntryPos;
       
  2014             	MRUPageScanned = ETrue;
       
  2015             	continue;
       
  2016         		}
       
  2017             break; //-- this was the last cluster in this directory
       
  2018         	}
       
  2019 
       
  2020         const TUint32 pageStartPos = CalculatePageOffsetInCluster(DosEntryPos1.iPos, pageSzLog2);
       
  2021     	DosEntryPos1.iPos = pageStartPos;
       
  2022         TBool	PassedPageBoundary = EFalse;
       
  2023 
       
  2024         const TInt64  entryLinPos = MakeLinAddrL(DosEntryPos1); //-- linear media position of the cluster for this directory
       
  2025         const TUint32 cachePageSz = pDirCache->PosCached(entryLinPos, nCachedLinPos); //-- indicates if entryLinPos is cached
       
  2026         if(cachePageSz)
       
  2027             {//-- current page is in the directory cache
       
  2028              //__PRINT2(_L("#-!! CFatMountCB::DoRummageDirCacheL() Searching cl:%d, lin Pos:%X"),DosEntryPos1.iCluster,(TUint32)entryLinPos);
       
  2029 
       
  2030             //-- search to the end of the cached page.
       
  2031             // Note GetDirEntry() will read data beyond cache page boundary
       
  2032             const TUint32 nEntries = (1 << pageSzLog2) >> KSizeOfFatDirEntryLog2;
       
  2033 
       
  2034             TInt nErr;
       
  2035             //-- extract dir entries from the cached page and see if they match given name (aName)
       
  2036             /// until it reaches the next page
       
  2037             for(;;)
       
  2038                 {
       
  2039                 StartEntryPos1 = DosEntryPos1;
       
  2040                 TInt clSave = DosEntryPos1.iCluster; //-- need to save current cluster number because GetDirEntry() & MoveToNextEntryL() can change it
       
  2041 
       
  2042                 //-- get directory entry from the cache. We know that the DosEntryPos1 is cached.
       
  2043                 nErr = GetDirEntry(DosEntryPos1, DosEntry1, StartEntry1, aFileName);
       
  2044                 if(nErr != KErrNone)
       
  2045                     break;
       
  2046 
       
  2047                 if(DosEntry1.IsEndOfDirectory())
       
  2048                 	{
       
  2049                 	if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound())
       
  2050 		            	{
       
  2051 		            	// note it is impossible to be at the end of the cluster chain here.
       
  2052 	            		aFileCreationHelper->SetEntryAddingPos(DosEntryPos1);
       
  2053 	            		aFileCreationHelper->SetIsNewEntryPosFound(ETrue);
       
  2054 		            	}
       
  2055 
       
  2056                 	if (ScanMRUPageFirst && !MRUPageScanned)
       
  2057                 		{
       
  2058                     	break;
       
  2059                 		}
       
  2060 
       
  2061                 	// if (!ScanMRUPageFirst || ScanMRUPageFirst && MRUPageScanned)
       
  2062                     goto Exit; //-- this was the last entry in this directory, no reason to look further
       
  2063                 	}
       
  2064 
       
  2065                 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound())
       
  2066 		        	{
       
  2067 		            if (!DosEntry1.IsErased() && !DosEntry1.IsGarbage())
       
  2068 		            	{
       
  2069 		            	numFound = 0;
       
  2070 		            	}
       
  2071 		            else
       
  2072 		            	{
       
  2073 		            	if (numFound == 0)
       
  2074 		            		{
       
  2075 		            		startPos = DosEntryPos1;
       
  2076 		            		}
       
  2077 		            	numFound++;
       
  2078 		            	if (numFound == aFileCreationHelper->NumOfAddingEntries())
       
  2079 		            		{
       
  2080 		            		aFileCreationHelper->SetEntryAddingPos(startPos);
       
  2081 		            		aFileCreationHelper->SetIsNewEntryPosFound(ETrue);
       
  2082 		            		}
       
  2083 		            	}
       
  2084 		        	}
       
  2085                 if(MatchEntryAtt(DosEntry1.Attributes(),anAtt))
       
  2086                     {//-- FAT or VFAT dir entry is extracted and attributes match. Compare names then.
       
  2087 
       
  2088                     if(StartEntry1.IsVFatEntry())
       
  2089                         {//-- extracted entry is VFAT one, name can be in UNICODE
       
  2090 
       
  2091                         // we only check short name candidates for long file names with VFAT entries,
       
  2092                         //  if it is a valid dos name, it will be checked by default
       
  2093                         // note here target name is always fully specified
       
  2094                         if (aFileCreationHelper && aFileCreationHelper->IsInitialised())
       
  2095                         	{
       
  2096                         	aFileCreationHelper->CheckShortNameCandidates(DosEntry1.Name().Ptr());
       
  2097                         	}
       
  2098 
       
  2099                         TPtrC ptrAssembledName = RemoveTrailingDots(aFileName);
       
  2100 
       
  2101                         if(ptrAssembledName.MatchF(aAuxParam.iTargetName) != KErrNotFound)
       
  2102                             {//-- found match in cache
       
  2103                             bCacheMatchFound = ETrue;
       
  2104                             goto Exit;
       
  2105                             }
       
  2106                         else if(aAuxParam.TrgtNameIsLegalDos())
       
  2107                             {
       
  2108                             if(aAuxParam.MatchDosEntryName(DosEntry1.Name().Ptr()))
       
  2109                                 {
       
  2110                                 bCacheMatchFound = ETrue;
       
  2111                                 goto Exit;
       
  2112                                 }
       
  2113                             }
       
  2114                         }//if(StartEntry1.IsVFatEntry())
       
  2115                     else if(aAuxParam.TrgtNameIsLegalDos())
       
  2116                         {//-- this is an old DOS FAT entry
       
  2117 
       
  2118                           if(aAuxParam.MatchDosEntryName(DosEntry1.Name().Ptr()))
       
  2119                             {
       
  2120                             //-- Here is the trick that helps with the situation when VFAT entry is split into 2 halves
       
  2121                             //-- between 2 clusters (or/and cache pages). I.e. 1st part of this long entry belongs to one cluster and even more might not be cached,
       
  2122                             //-- While the rest of the entry, DOS part of it is the 1st entry in the cluster and cached.
       
  2123                             //-- In this case if we search for short file name, we find it, but the aStartEntryPos will be incorrect, which leads to the directory corruption.
       
  2124                             //-- The simple and quick solution - discard 1st DOS entry and return to old search. It shall be quite rare.
       
  2125                             if(StartEntryPos1.iPos == 0)
       
  2126                                 {//-- this is the 1st FAT entry in the cluster. Discard it, see comments above.
       
  2127                                 __PRINT(_L("#------ CFatMountCB::DoRummageDirCacheL() discarding FAT Entry!!"));
       
  2128                                 goto Exit;
       
  2129                                 }
       
  2130 
       
  2131                             bCacheMatchFound = ETrue;
       
  2132                             goto Exit;
       
  2133                             }
       
  2134                         }
       
  2135 
       
  2136                     }//if(bGotEntry && MatchEntryAtt(DosEntry1.Attributes(),anAtt))
       
  2137 
       
  2138                 // check boundaries after GetDirEntry()
       
  2139                 // if we have cross the cluster boundary, break the for loop
       
  2140                 if(DosEntryPos1.iCluster != clSave)
       
  2141                     {//-- GetDirEntry() has decided to move to the next cluster.
       
  2142                     DosEntryPos1.iCluster = clSave;
       
  2143                     break;
       
  2144                     }
       
  2145 
       
  2146                 // if we are still in the same cluster, check the page boundary by
       
  2147                 /// exam how many entries we have scanned within the cluster
       
  2148                 const TUint entriesLooked =  ((DosEntryPos1.iPos + KSizeOfFatDirEntry)- pageStartPos) >> KSizeOfFatDirEntryLog2;
       
  2149                 if(entriesLooked > nEntries)
       
  2150                 	{
       
  2151                 	PassedPageBoundary = ETrue;
       
  2152                     break;
       
  2153                 	}
       
  2154 
       
  2155 
       
  2156                 // move to next entry before scanning next file
       
  2157                 TRAP(nErr,MoveToNextEntryL(DosEntryPos1));
       
  2158                 if(nErr != KErrNone)
       
  2159                     goto Exit;
       
  2160 
       
  2161                 // check boundaries after MoveToNextEntryL()
       
  2162                 if(DosEntryPos1.iCluster != clSave)
       
  2163                     {
       
  2164                     DosEntryPos1.iCluster = clSave;
       
  2165                     break;
       
  2166                     }
       
  2167 
       
  2168                 if (entriesLooked + 1 > nEntries)
       
  2169                 	{
       
  2170                 	PassedPageBoundary = ETrue;
       
  2171                     break;
       
  2172                 	}
       
  2173 
       
  2174                 } //for(;;)
       
  2175 
       
  2176             } //if(iRawDisk->PosCached(...))
       
  2177 
       
  2178         // scanning did not happen because the page is not cached,
       
  2179         // or
       
  2180         // scanning finished in last page and file is not found
       
  2181 
       
  2182         // if MRU page is not cached or
       
  2183         // we scan MRU page first and it is not scanned yet, then this must be the MRU page,
       
  2184         //  we now start to scan from the beginning
       
  2185         if (ScanMRUPageFirst && !MRUPageScanned)
       
  2186         	{
       
  2187         	MRUPageScanned = ETrue;
       
  2188         	DosEntryPos1 = aDosEntryPos;
       
  2189         	DosEntryPos1.iPos = 0;
       
  2190         	continue;
       
  2191         	}
       
  2192 
       
  2193         // if we just finished scanning a page and still in the same cluster, then we crossed page
       
  2194         // 	boundary, continue with next page.
       
  2195         // note: although we are in the 'next page' already, this page might not be cached, so we need to
       
  2196         //  check it via pDirCache->PosCached(entryLinPos, nCachedLinPos) and scan it properly.
       
  2197         if (PassedPageBoundary)
       
  2198         	{
       
  2199         	DosEntryPos1.iPos = CalculatePageOffsetInCluster(DosEntryPos1.iPos, pageSzLog2);
       
  2200         	PassedPageBoundary = EFalse;
       
  2201         	continue;
       
  2202         	}
       
  2203 
       
  2204         //-- try to move to the next cluster of the directory file
       
  2205 
       
  2206         if(DosEntryPos1.Cluster() < KFatFirstSearchCluster)  //-- small trick to get rid of TRAPping GetNextClusterL()
       
  2207             break;
       
  2208 
       
  2209         // record previous cluster number before move on
       
  2210         clusterNum = DosEntryPos1.iCluster;
       
  2211 
       
  2212         if(! FAT().GetNextClusterL(DosEntryPos1.iCluster))
       
  2213             break;
       
  2214 
       
  2215 
       
  2216     } //for(TUint32 entryCnt=0; entryCnt< maxDirEntries; ++entryCnt)
       
  2217 
       
  2218     //---------------------------------
       
  2219     Exit:
       
  2220 
       
  2221     if(bCacheMatchFound)
       
  2222         {
       
  2223         //-- if the position of the found in cache object is less than given, pretend that we haven't found anything
       
  2224         //-- Return to the old search, because it can be the case of the end of directory, which is quite difficult to
       
  2225         //-- detect in this situation. Note that the old part of DoFindL() leaves when the search reaches the end of dir.
       
  2226         TBool bFallBack=EFalse;
       
  2227 
       
  2228         if(DosEntryPos1.iCluster == aDosEntryPos.iCluster)
       
  2229             {
       
  2230             if(DosEntryPos1.iPos < aDosEntryPos.iPos)
       
  2231                 bFallBack = ETrue;
       
  2232             }
       
  2233         else
       
  2234             {
       
  2235             if(MakeLinAddrL(DosEntryPos1) < MakeLinAddrL(aDosEntryPos))
       
  2236                 bFallBack = ETrue;
       
  2237             }
       
  2238 
       
  2239         if(bFallBack)
       
  2240             {
       
  2241             return EFalse;
       
  2242             }
       
  2243 
       
  2244         //-- Update parameters with new values
       
  2245         aStartEntryPos= StartEntryPos1;
       
  2246         aDosEntryPos  = DosEntryPos1;
       
  2247         aStartEntry   = StartEntry1;
       
  2248         aDosEntry     = DosEntry1;
       
  2249 
       
  2250         const TInt64  mruPos = MakeLinAddrL(aDosEntryPos);
       
  2251         
       
  2252         pDirCache->MakePageMRU(mruPos);
       
  2253 
       
  2254     	// only update the leaf dir cache when the original cache index is provided
       
  2255     	if (aLeafDir.iClusterNum)
       
  2256     		{
       
  2257             iLeafDirCache->UpdateMRUPos(TLeafDirData(aLeafDir.iClusterNum, aStartEntryPos));
       
  2258     		}
       
  2259         }
       
  2260     return bCacheMatchFound;
       
  2261     }
       
  2262 
       
  2263 //-----------------------------------------------------------------------------------------
       
  2264 
       
  2265 /**
       
  2266     initialise find helper with the target file name.
       
  2267     This is a quite expensive operation and initialisation is done only once. After this we know if the name is a legal dos one
       
  2268     and also have the corresponding generated DOS name for it.
       
  2269 
       
  2270     @param aTargetName target file name we are looking for in ::DoFindL()
       
  2271 */
       
  2272 void CFatMountCB::TFindHelper::InitialiseL(const TDesC& aTargetName)
       
  2273     {
       
  2274     if(isInitialised)
       
  2275         return;
       
  2276 
       
  2277      TInt count = 1;
       
  2278 
       
  2279      iTargetName.Set(aTargetName);
       
  2280      isLegalDosName = IsLegalDosName(aTargetName, ETrue, EFalse, EFalse, ETrue, EFalse);
       
  2281 
       
  2282      if(isLegalDosName)
       
  2283         {//-- iShortName will contain generated short DOS name by long filename
       
  2284         iShortName = DoGenerateShortNameL(aTargetName, count, ETrue);
       
  2285         }
       
  2286 
       
  2287      isInitialised = ETrue;
       
  2288     }
       
  2289 
       
  2290 /**
       
  2291     Perform binary comparison between a given the DOS entry name and the DOS name we generated in TFindHelper::Initialise().
       
  2292     @param  apDosEntryName pointer to the DOS entry name in XXXXXXXXYYY format
       
  2293     @return ETrue if the apDosEntryName is the same as generated iShortName
       
  2294 */
       
  2295 TBool CFatMountCB::TFindHelper::MatchDosEntryName(const TUint8* apDosEntryName) const
       
  2296     {
       
  2297     ASSERT(isInitialised);
       
  2298 
       
  2299     if(!isLegalDosName)
       
  2300         return EFalse;
       
  2301 
       
  2302     return (Mem::Compare(iShortName.Ptr(), KFatDirNameSize, apDosEntryName, KFatDirNameSize) == 0);
       
  2303     }
       
  2304 
       
  2305 //-----------------------------------------------------------------------------------------
       
  2306 const TInt KShortNameCandidatesNum = 4;
       
  2307 /**
       
  2308 Constructor of XFileCreationHelper class
       
  2309 */
       
  2310 CFatMountCB::XFileCreationHelper::XFileCreationHelper()
       
  2311 	{
       
  2312     isInitialised = EFalse;
       
  2313 	}
       
  2314 
       
  2315 /**
       
  2316 Destructor of XFileCreationHelper class
       
  2317 */
       
  2318 CFatMountCB::XFileCreationHelper::~XFileCreationHelper()
       
  2319 	{
       
  2320 	Close();
       
  2321 	}
       
  2322 
       
  2323 /**
       
  2324 Initialises a TFileCreationHelper object, generate a short name candidate pool.
       
  2325 
       
  2326 @param	aTargetName	Target file name for the potential new file.
       
  2327 @post	TFileCreationHelper is fully initialised.
       
  2328 */
       
  2329 void CFatMountCB::XFileCreationHelper::InitialiseL(const TDesC& aTargetName)
       
  2330 	{
       
  2331     // close before use, to avoid memory leak
       
  2332 	Close();
       
  2333 
       
  2334     iTargetName.Set(aTargetName);
       
  2335 	// generates short name candidate(s)
       
  2336     TInt count = 1;
       
  2337     while (count <= KShortNameCandidatesNum)
       
  2338 		{
       
  2339 		TShortName shortNameCandidate = DoGenerateShortNameL(aTargetName, count, ETrue);
       
  2340 		TInt err = iShortNameCandidates.Append(shortNameCandidate);
       
  2341 		User::LeaveIfError(err);
       
  2342 
       
  2343 		if (count == -1)	// No tilde and number is needed
       
  2344 			{
       
  2345 			break;
       
  2346 			}
       
  2347 		else
       
  2348 			count++;
       
  2349 		}
       
  2350 
       
  2351     // calculate number of new entries needed
       
  2352     iNumOfAddingEntries = 1;
       
  2353     isTrgNameLegalDosName = IsLegalDosName(aTargetName, EFalse, EFalse, EFalse, EFalse, ETrue);
       
  2354     if (!isTrgNameLegalDosName)
       
  2355     	iNumOfAddingEntries = (TUint16) NumberOfVFatEntries(iTargetName.Length());
       
  2356 
       
  2357     isNewEntryPosFound = EFalse;
       
  2358     isInitialised = ETrue;
       
  2359     }
       
  2360 
       
  2361 /**
       
  2362 Close function of XFileCreationHelper class
       
  2363 */
       
  2364 void CFatMountCB::XFileCreationHelper::Close()
       
  2365 	{
       
  2366 	iShortNameCandidates.Close();
       
  2367 	isInitialised = EFalse;
       
  2368 	}
       
  2369 
       
  2370 /**
       
  2371 Validates short name candidates. If the input dos entry name is found in the short name
       
  2372  candidate pool, the corresponding short name candidate will be removed from the pool.
       
  2373 
       
  2374 @param	apDosEntryName	An existing short name, to compare with the candidates.
       
  2375 @pre 	Object should be initialised
       
  2376 */
       
  2377 void CFatMountCB::XFileCreationHelper::CheckShortNameCandidates(const TUint8* apDosEntryName)
       
  2378     {
       
  2379     ASSERT(isInitialised);
       
  2380     if (!isInitialised)
       
  2381     	return;
       
  2382 
       
  2383     if (iShortNameCandidates.Count() > 0)
       
  2384     	{
       
  2385     	for (TInt i = 0; i < iShortNameCandidates.Count(); i++)
       
  2386     		{
       
  2387     		if (Mem::Compare(iShortNameCandidates[i].Ptr(), KFatDirNameSize, apDosEntryName, KFatDirNameSize) == 0)
       
  2388     			{
       
  2389     			iShortNameCandidates.Remove(i);
       
  2390     			break;
       
  2391     			}
       
  2392     		}
       
  2393     	}
       
  2394     }
       
  2395 
       
  2396 /**
       
  2397 Gets a validated short name from the short name candidate pool.
       
  2398 
       
  2399 @param	aShortName	On return, contains a validated short name if found, otherwise zeroed.
       
  2400 @return	TInt		Returns KErrNone if a validated short name found successfully,
       
  2401  					 else KErrNotFound is returned.
       
  2402  					Returns KErrNotReady if object is not initialised.
       
  2403 @pre 	Object should be initialised
       
  2404 */
       
  2405 TInt CFatMountCB::XFileCreationHelper::GetValidatedShortName(TShortName& aShortName) const
       
  2406 	{
       
  2407 	aShortName.Zero();
       
  2408 
       
  2409 	ASSERT(isInitialised);
       
  2410 	if (!isInitialised)
       
  2411 		return KErrNotReady;
       
  2412 
       
  2413 	if (iShortNameCandidates.Count() > 0)
       
  2414 		{
       
  2415 		aShortName.Copy(iShortNameCandidates[0]);
       
  2416 		return KErrNone;
       
  2417 		}
       
  2418 
       
  2419 	return KErrNotFound;
       
  2420 	}
       
  2421 
       
  2422 //-----------------------------------------------------------------------------------------
       
  2423 
       
  2424 
       
  2425 /**
       
  2426     Scan a directory looking for aName.
       
  2427 
       
  2428     @param  aTrgtName       a name of an object we are looking up in directory
       
  2429     @param  anAtt           attributes of this object
       
  2430     @param  aStartEntryPos  on return in case of VFAT entry will contain start position of the VFAT dir. entry
       
  2431     @param  aStartEntry     on return will contain first VFAT dir entry
       
  2432     @param  aDosEntryPos    the search will start from this position of dir entry, on return it will contain result DOS entry position, last one for VFAT case
       
  2433     @param  aDosEntry       on return will contain DOS dir entry (the last one for VFAT case)
       
  2434     @param  aFileName       in the case of VFAT entry and on success here will be returned a long filename
       
  2435     @param  anError         This function might leave with this given error code
       
  2436 	@param  aFileCreationHelper       a helper package for file creations
       
  2437 
       
  2438     @return ETrue if extracted entry is VFAT one, EFalse, if it's old DOS-style one
       
  2439     @leave  can leave with anError code on error or if the search has reached the end of directory (!)
       
  2440 */
       
  2441 TBool CFatMountCB::DoFindL(const TDesC& aTrgtName,TUint anAtt,
       
  2442 						TEntryPos& aStartEntryPos,TFatDirEntry& aStartEntry,
       
  2443 						TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry,
       
  2444 						TDes& aFileName,TInt anError,
       
  2445 						XFileCreationHelper* aFileCreationHelper,
       
  2446 						const TLeafDirData& aLeafDirData) const
       
  2447 	{
       
  2448     // check that the entry position to be read next is not past the end of the
       
  2449     // root directory. If this is the case then when GetDirEntryL(..) is called
       
  2450     // this will lead to MakeLinAddr(..) leaving with KErrDirFull.
       
  2451 
       
  2452     if (IsRootDir(aDosEntryPos)&&(aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd()))
       
  2453         User::Leave(anError);//Allows maximum number of entries in root directory
       
  2454 
       
  2455     __PRINT2(_L("CFatMountCB::DoFindL() drv:%d, %S"),Drive().DriveNumber(),&aTrgtName);
       
  2456 
       
  2457     TInt previousCluster=aDosEntryPos.iCluster;
       
  2458     TUint previousPosition=aDosEntryPos.iPos;
       
  2459     TInt changePreviousCluster=1;
       
  2460     TInt count=0;
       
  2461 
       
  2462     TBool trgNameIsWildCard     = EFalse; //-- ETrue if the name we are looking for is a wildcard
       
  2463     TBool trgNameFullySpecified = ETrue;  //-- ETrue if the name we are looking for doesn't contain wildcards
       
  2464 
       
  2465 
       
  2466     {
       
  2467     //-- find out if the name we are looking for is a wildcard ("*" or "*.*")
       
  2468     const TInt len = aTrgtName.Length();
       
  2469 
       
  2470     if(len == 1)
       
  2471         trgNameIsWildCard = (aTrgtName[0] == '*');
       
  2472     else if(len == 3)
       
  2473         {
       
  2474         _LIT(KAllFiles, "*.*");
       
  2475         trgNameIsWildCard = (aTrgtName==KAllFiles);
       
  2476         }
       
  2477 
       
  2478     //-- find out if the name we are looking for contains wildcharacters: "*" or "?"
       
  2479     if(trgNameIsWildCard)
       
  2480         trgNameFullySpecified = EFalse;
       
  2481     else
       
  2482         {
       
  2483         for(TInt i=0; i<len; ++i)
       
  2484             {
       
  2485             const TChar ch = aTrgtName[i];
       
  2486             if(ch == (TChar)'*' || ch == (TChar)'?')
       
  2487                 {
       
  2488                 trgNameFullySpecified = EFalse;
       
  2489                 break;
       
  2490                 }
       
  2491             }
       
  2492         }
       
  2493     }
       
  2494 
       
  2495 
       
  2496     TPtrC trgtNameNoDot(aTrgtName);
       
  2497 
       
  2498     TFindHelper findHelper;
       
  2499     //---------------------------------------------------
       
  2500     //-- if we have fully specified name and directory cache is present, try to
       
  2501     //-- locate the name in the cache first to avoid reading from media
       
  2502     //-- 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     //-- while directory cache pages are. For FAT32 it doesn't matter, because root dir is a usual file.
       
  2504     if(iRawDisk->DirCacheInterface() && trgNameFullySpecified && !IsRootDir(aDosEntryPos) && !aFileCreationHelper)
       
  2505         {//-- aName is fully specified, i.e doesn't contain wildcards
       
  2506 
       
  2507         findHelper.InitialiseL(trgtNameNoDot);
       
  2508 
       
  2509         const TBool bMatchFound = DoRummageDirCacheL(anAtt, aStartEntryPos, aStartEntry, aDosEntryPos, aDosEntry, aFileName, findHelper, aFileCreationHelper, aLeafDirData);
       
  2510         if(bMatchFound)
       
  2511             {
       
  2512             return(aStartEntry.IsVFatEntry());
       
  2513             }
       
  2514         }
       
  2515     //---------------------------------------------------
       
  2516 
       
  2517     // we need to scan ahead from the mru pos then come back to beginning, if startcluster is provided
       
  2518     TBool scanAhead = EFalse;
       
  2519     // if we have a starting cluster number (and it's not root directory in FAT16/12 case)&&
       
  2520     //  we found a lastScanned entry's cluster (and it's not root directory in FAT16/12 case)&&
       
  2521     // if we don't have a starting cluster number, we draw back to original scanning algorithm
       
  2522     if (!IsRootDir(aDosEntryPos) 			// we don't do forward scanning for root dir &
       
  2523     		&& aLeafDirData.iClusterNum != 0 	// if we have a starting cluster number &
       
  2524     		&& aLeafDirData.iMRUPos.Cluster() != 0) 	// if we have a starting cluster number &
       
  2525     	{
       
  2526     	scanAhead = ETrue;
       
  2527     	aDosEntryPos = aLeafDirData.iMRUPos;
       
  2528     	}
       
  2529 
       
  2530     TInt numFound = 0;
       
  2531     TEntryPos startPos = aDosEntryPos;
       
  2532     TInt clustNum = aDosEntryPos.Cluster();
       
  2533 
       
  2534     for (TInt scanCnt = 1; scanCnt <= 2; ++scanCnt)
       
  2535     	{
       
  2536     	// if we are not scanning ahead, we don't need this outer for loop
       
  2537     	if (!scanAhead)
       
  2538     		scanCnt++;
       
  2539 
       
  2540     	TBool found = EFalse;
       
  2541 
       
  2542         FOREVER //FOREVER2 -- walk through all directory entries in the current directory until find a match or directory end
       
  2543             {
       
  2544 	        //-- read full directory entry starting from aDosEntryPos. On return aFileName may contain assembled long filename (if the entry is VFAT)
       
  2545 	        //-- aDosEntry will contain a DOS entry of the directory entry we have read.
       
  2546 	        aStartEntryPos=aDosEntryPos;
       
  2547 	        User::LeaveIfError(GetDirEntry(aDosEntryPos, aDosEntry, aStartEntry, aFileName));
       
  2548 
       
  2549 	        if (aDosEntry.IsEndOfDirectory())
       
  2550 	            {//-- the end of directory reached.
       
  2551 
       
  2552 	            // if new entry position for adding has not been found yet.
       
  2553 	            // note aFileCreationHelper may not be initialised for pure file opening operations
       
  2554 	            if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound())
       
  2555 	            	{
       
  2556 	            	// if MoveToNextEntryL have gone to the next cluster which is the end of cluster chain,
       
  2557 	            	//  we pass the last scanned entry position to AddDirEntryL
       
  2558 	            	if (IsEndOfClusterCh(aDosEntryPos.iCluster))
       
  2559 	            		{
       
  2560 	            	    TInt clusterSize=1<<ClusterSizeLog2();
       
  2561 	            	    TEntryPos dummyPos(clustNum, clusterSize - KSizeOfFatDirEntry);
       
  2562 	            	    aFileCreationHelper->SetEntryAddingPos(dummyPos);
       
  2563 	            		aFileCreationHelper->SetIsNewEntryPosFound(ETrue);
       
  2564 	            		}
       
  2565 	            	// or we reached the end of the directory.
       
  2566 	            	else
       
  2567 	            		{
       
  2568 	            		aFileCreationHelper->SetEntryAddingPos(aDosEntryPos);
       
  2569 	            		aFileCreationHelper->SetIsNewEntryPosFound(ETrue);
       
  2570 	            		}
       
  2571 	            	}
       
  2572 
       
  2573 	            // if we are scanning ahead and this is the first scanning, we break out to restart scanning
       
  2574 	            if (scanAhead && scanCnt == 1)
       
  2575 	            	{
       
  2576 	            	break; // from FOREVER, restart scanning
       
  2577 	            	}
       
  2578 
       
  2579 	            // if (!scanAhead || scanAhead && scanCnt == 2)
       
  2580 	            User::Leave(anError);
       
  2581 	            }
       
  2582 
       
  2583 
       
  2584 	        // entry space searching for potential new file/directory creation
       
  2585 	        if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound())
       
  2586 	        	{
       
  2587 	            if (!aDosEntry.IsErased() && !aDosEntry.IsGarbage())
       
  2588 	            	{
       
  2589 	            	numFound = 0;
       
  2590 	            	}
       
  2591 	            else
       
  2592 	            	{
       
  2593 	            	if (numFound == 0)
       
  2594 	            		{
       
  2595 	            		startPos = aDosEntryPos;
       
  2596 	            		}
       
  2597 	            	numFound++;
       
  2598 	            	if (numFound == aFileCreationHelper->NumOfAddingEntries())
       
  2599 	            		{
       
  2600 	            		aFileCreationHelper->SetEntryAddingPos(startPos);
       
  2601 	            		aFileCreationHelper->SetIsNewEntryPosFound(ETrue);
       
  2602 	            		}
       
  2603 	            	}
       
  2604 	        	}
       
  2605 
       
  2606 
       
  2607 	        if (IsRootDir(aDosEntryPos)&&(aDosEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))
       
  2608 	            if (aDosEntry.IsErased())
       
  2609 	                {
       
  2610 	                User::Leave(anError);//Allows maximum number of entries in root directory
       
  2611 	                }
       
  2612 
       
  2613 
       
  2614 	        const TBool bFileNameEntry = !aDosEntry.IsCurrentDirectory() && !aDosEntry.IsParentDirectory() && !aDosEntry.IsErased() && !aDosEntry.IsGarbage();
       
  2615 
       
  2616 	        if (bFileNameEntry && MatchEntryAtt(aDosEntry.Attributes(), anAtt))
       
  2617 	            {//-- we have read a filename entry and entry's attributes match required; compare names then.
       
  2618 
       
  2619 	            if (trgNameIsWildCard)
       
  2620 	            	{
       
  2621 	            	found = ETrue;
       
  2622 	            	break; //-- we were looking for '*' or '*.*', so will be satisfied with any current file name.
       
  2623 	            	}
       
  2624 
       
  2625 
       
  2626 	            if (aStartEntry.IsVFatEntry())
       
  2627 	                {//-- we've read a VFAT entry, aFileName is supposed to contain long filename, aDosEntry - DOS entry for this name.
       
  2628 	                 //-- note: aFileName.Length() may be 0, while DOS entry (short name is OK) in the case of orphaned VFAT entries
       
  2629 
       
  2630 
       
  2631 	                // we only check short name candidates for long file names with VFAT entries,
       
  2632 	                //  if it is a valid dos name, it will be checked by default
       
  2633 	                // note, for file creation cases, target name will be always fully specified
       
  2634 	                if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && trgNameFullySpecified)
       
  2635 		            	 {
       
  2636 		            	 aFileCreationHelper->CheckShortNameCandidates(aDosEntry.Name().Ptr());
       
  2637 		            	 }
       
  2638 
       
  2639 	                //-- discard trailing dots from aFileName if present
       
  2640 	                 TPtrC ptrAssembledName = RemoveTrailingDots(aFileName);
       
  2641 
       
  2642 	                 if(ptrAssembledName.MatchF(trgtNameNoDot) != KErrNotFound)
       
  2643 	                	 {
       
  2644 						 found = ETrue;
       
  2645 	                	 break; //-- OK, found a match.
       
  2646 	                	 }
       
  2647 	                 else if (trgNameFullySpecified)
       
  2648 	                	 {
       
  2649 	                	 //-- long name assembled by GetDirEntry() doesn't match the target. But if he target name is fully specified,
       
  2650 	                	 //-- we need to compare corresponding DOS entries, because VFAT entries may be damaged, while DOS ones are OK.
       
  2651 	                     findHelper.InitialiseL(trgtNameNoDot);
       
  2652 
       
  2653 	                     if(findHelper.MatchDosEntryName(aDosEntry.Name().Ptr()))
       
  2654 	                    	 {
       
  2655 							 found = ETrue;
       
  2656 	                    	 break; //-- DOS entries match, success.
       
  2657 	                    	 }
       
  2658 	                	 }
       
  2659 	                 else if (!trgNameFullySpecified)
       
  2660 	                	 {//-- target name contains wildcards, we need to use MatchF with dos name
       
  2661 	                     TBuf8<0x20> dosName8(DosNameFromStdFormat(aDosEntry.Name()));
       
  2662 	                     TBuf<0x20>  dosName;
       
  2663 	                     LocaleUtils::ConvertToUnicodeL(dosName, dosName8); //-- convert DOS name to unicode (implies locale settings)
       
  2664 	                     if (dosName.MatchF(trgtNameNoDot)!=KErrNotFound)
       
  2665 	                    	 {
       
  2666 							 found = ETrue;
       
  2667 							 break;
       
  2668 	                    	 }
       
  2669 	                	 }
       
  2670 
       
  2671 
       
  2672 	                }
       
  2673 	            else //if (aStartEntry.IsVFatEntry())
       
  2674 	                {//-- we've read a legacy FAT entry, so compare DOS entries
       
  2675 	                findHelper.InitialiseL(trgtNameNoDot);
       
  2676 
       
  2677 	                if(findHelper.TrgtNameIsLegalDos())
       
  2678 	                    {//-- we are looking for a legal DOS name
       
  2679 	                    if(trgNameFullySpecified)
       
  2680 	                        {//-- if the target name is fully specified, we can yse binary comparison of the DOS entries
       
  2681 	                        if(findHelper.MatchDosEntryName(aDosEntry.Name().Ptr()))
       
  2682 	                        	{
       
  2683 								found = ETrue;
       
  2684 	                            break;
       
  2685 	                        	}
       
  2686 	                        }
       
  2687 	                    else
       
  2688 	                        {//-- target name contains wildcards, we neeed to use MatchF
       
  2689 	                        TBuf8<0x20> dosName8(DosNameFromStdFormat(aDosEntry.Name()));
       
  2690 	                        TBuf<0x20>  dosName;
       
  2691 	                        LocaleUtils::ConvertToUnicodeL(dosName, dosName8); //-- convert DOS name to unicode (implies locale settings)
       
  2692 	                        if (dosName.MatchF(trgtNameNoDot)!=KErrNotFound)
       
  2693 	                        	{
       
  2694 								found = ETrue;
       
  2695 	                            break;
       
  2696 	                        	}
       
  2697 
       
  2698 	                        }
       
  2699 	                    } //if(findHelper.TrgtNameIsLegalDos())
       
  2700 
       
  2701 	                } //else if (aStartEntry.IsVFatEntry())
       
  2702 
       
  2703 	            } //if (bFileNameEntry && MatchEntryAtt(aDosEntry.Attributes(),anAtt))
       
  2704 
       
  2705 
       
  2706 	        // record previous cluster number
       
  2707 	        clustNum = aDosEntryPos.iCluster;
       
  2708 
       
  2709 	        // this is the 2nd scanning and we have just passed the pos we started.
       
  2710 	        if (scanAhead && scanCnt == 2)
       
  2711 	        	{
       
  2712 	        	if (aDosEntryPos.Cluster() == aLeafDirData.iMRUPos.Cluster()
       
  2713 	        			&& aDosEntryPos.Pos() >= aLeafDirData.iMRUPos.Pos())
       
  2714 	        		{
       
  2715 	        		User::Leave(anError);
       
  2716 	        		}
       
  2717 	        	}
       
  2718 
       
  2719 
       
  2720 	        MoveToNextEntryL(aDosEntryPos); //-- goto the next entry in the directory
       
  2721 
       
  2722 	        if (IsRootDir(aDosEntryPos)&&(aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd()))
       
  2723 	            {
       
  2724 	            User::Leave(anError);//Allows maximum number of entries in root directory
       
  2725 	            }
       
  2726 
       
  2727 
       
  2728 	        if (!scanAhead || scanCnt == 2)
       
  2729 	        	{
       
  2730 		        if (aDosEntryPos.iCluster && (aDosEntryPos.iPos <= previousPosition))
       
  2731 		            DoCheckFatForLoopsL(aDosEntryPos.iCluster,previousCluster,changePreviousCluster,count);
       
  2732 
       
  2733 		        previousPosition=aDosEntryPos.iPos;
       
  2734 	        	}
       
  2735 	    	}	// FOREVER -- the actual scanning is done inside this loop
       
  2736 
       
  2737 
       
  2738         if (found)
       
  2739         	{
       
  2740         	break;
       
  2741         	}
       
  2742 
       
  2743         // if not found:
       
  2744     	// if we have not found in the first scanning and we are doing scanning ahead,
       
  2745         //  we need to go back to the starting pos of this dir and scan from start until
       
  2746         //  we reach lastscannedPos
       
  2747         if (scanAhead && scanCnt == 1)
       
  2748         	{
       
  2749         	aDosEntryPos = TEntryPos(aLeafDirData.iClusterNum, 0);
       
  2750         	continue;
       
  2751         	}
       
  2752         else
       
  2753         	{
       
  2754         	// there are only two exits: either found or reached end of dir in the 1st scanning
       
  2755         	ASSERT(0);
       
  2756         	break;
       
  2757         	}
       
  2758     	} // for (TInt scanCnt = 1; scanCnt <= 2; ++scanCnt)
       
  2759 
       
  2760     //---------------------------------------------------
       
  2761     if (iRawDisk->DirCacheInterface() && aDosEntryPos.Cluster())
       
  2762     	{
       
  2763     	TInt64 mruPos = MakeLinAddrL(aDosEntryPos);
       
  2764         iRawDisk->DirCacheInterface()->MakePageMRU(mruPos);
       
  2765 
       
  2766     	// only update the leaf dir cache when the original cache index is provided
       
  2767     	if (aLeafDirData.iClusterNum)
       
  2768     		{
       
  2769             iLeafDirCache->UpdateMRUPos(TLeafDirData(aLeafDirData.iClusterNum, aDosEntryPos));
       
  2770             }
       
  2771     	}
       
  2772 
       
  2773     return (aStartEntry.IsVFatEntry());
       
  2774     }
       
  2775 
       
  2776 //-----------------------------------------------------------------------------------------
       
  2777 /**
       
  2778     Locate an directory entry entry from its full path name.
       
  2779 
       
  2780     @param  aName           a name of an object we are looking for
       
  2781     @param  anAtt           attributes of this object
       
  2782     @param  anEntry         on return will contain first VFAT dir entry
       
  2783     @param  anEntryPos      on return in case of VFAT entry will contain start position of the VFAT dir. entry
       
  2784 
       
  2785     @leave  can leave with KErrNotFound if the search has reached the end of directory
       
  2786 */
       
  2787 void CFatMountCB::FindEntryStartL(const TDesC& aName,TUint anAtt,TFatDirEntry& anEntry,TEntryPos& anEntryPos) const
       
  2788     {
       
  2789     __PRINT(_L("CFatMountCB::FindEntryStartL()"));
       
  2790     TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
  2791     TFileName fileName;
       
  2792     TLeafDirData leafDir;
       
  2793     TEntryPos dosEntryPos(FindLeafDirL(aName.Left(namePos),leafDir),0);
       
  2794     TFatDirEntry dosEntry;
       
  2795 
       
  2796     DoFindL(aName.Mid(namePos),anAtt,anEntryPos,anEntry,dosEntryPos,dosEntry,fileName,KErrNotFound,NULL,leafDir);
       
  2797     }
       
  2798 
       
  2799 
       
  2800 //-----------------------------------------------------------------------------------------
       
  2801 
       
  2802 /**
       
  2803     Locate an directory entry entry from its full path name.
       
  2804 
       
  2805     @param  aName           a name of an object we are looking for
       
  2806     @param  anAtt           attributes of this object
       
  2807     @param  anEntry         on return will contain first VFAT dir entry
       
  2808     @param  anEntryPos      on return in case of VFAT entry will contain start position of the VFAT dir. entry
       
  2809 
       
  2810     @leave  can leave with KErrNotFound if the search has reached the end of directory
       
  2811 */
       
  2812 void CFatMountCB::FindEntryStartL(const TDesC& aName,TUint anAtt,TFatDirEntry& anEntry,TEntryPos& anEntryPos,XFileCreationHelper* aFileCreationHelper) const
       
  2813     {
       
  2814     __PRINT(_L("CFatMountCB::FindEntryStartL()"));
       
  2815     TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
  2816     TFileName fileName;
       
  2817     TLeafDirData leafDir;
       
  2818     TEntryPos dosEntryPos(FindLeafDirL(aName.Left(namePos),leafDir),0);
       
  2819     TFatDirEntry dosEntry;
       
  2820     DoFindL(aName.Mid(namePos),anAtt,anEntryPos,anEntry,dosEntryPos,dosEntry,fileName,KErrNotFound,aFileCreationHelper,leafDir);
       
  2821     }
       
  2822 
       
  2823 //-----------------------------------------------------------------------------------------
       
  2824 void CFatMountCB::FindDosNameL(const TDesC& aName,TUint anAtt,TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry,TDes& aFileName,TInt anError) const
       
  2825 //
       
  2826 // Scan a directory looking for aName.
       
  2827 // aCluster and anEntryAddr give the location of the entry.
       
  2828 //
       
  2829     {
       
  2830 
       
  2831     __PRINT(_L("CFatMountCB::FindDosNameL()"));
       
  2832     TEntryPos startPos;
       
  2833     TFatDirEntry startEntry;
       
  2834 
       
  2835     TLeafDirData leafDir;			// leaf dir data is zero initialized, no scannig ahead
       
  2836     DoFindL(aName,anAtt,startPos,startEntry,aDosEntryPos,aDosEntry,aFileName,anError,NULL,leafDir);
       
  2837     }
       
  2838 //-----------------------------------------------------------------------------------------
       
  2839 
       
  2840 void CFatMountCB::AddDirEntryL(TEntryPos& aPos,TInt aNumOfEntries)
       
  2841 //
       
  2842 // Find space for a new directory entry. Leave KErrEof if no space
       
  2843 //
       
  2844     {
       
  2845 
       
  2846     __PRINT(_L("CFatMountCB::AddDirEntryL"));
       
  2847     TInt numFound=0;
       
  2848     TFatDirEntry entry;
       
  2849     TEntryPos startPos(RootIndicator(),0);
       
  2850     TInt clusterNum=aPos.iCluster;
       
  2851     FOREVER
       
  2852         {
       
  2853         ReadDirEntryL(aPos,entry);
       
  2854         if (entry.IsEndOfDirectory())
       
  2855             break;
       
  2856         if (!entry.IsErased() && !entry.IsGarbage())
       
  2857             numFound=0;
       
  2858         else
       
  2859             {
       
  2860             if (numFound==0)
       
  2861                 startPos=aPos;
       
  2862             numFound++;
       
  2863             if (numFound==aNumOfEntries)
       
  2864                 {
       
  2865                 aPos=startPos;
       
  2866                 return;
       
  2867                 }
       
  2868             }
       
  2869         clusterNum=aPos.iCluster;
       
  2870         MoveToNextEntryL(aPos);
       
  2871         if (IsRootDir(aPos)&&(StartOfRootDirInBytes()+aPos.iPos==RootDirEnd()))
       
  2872     //  No end of directory marker at end of root directory
       
  2873             User::Leave(KErrDirFull);
       
  2874         }
       
  2875 
       
  2876     TUint clusterSize=1<<ClusterSizeLog2();
       
  2877     if (IsEndOfClusterCh(aPos.iCluster))
       
  2878         { // End of last cluster in directory
       
  2879         aPos.iCluster=clusterNum;
       
  2880         aPos.iPos=clusterSize;
       
  2881         }
       
  2882 
       
  2883     TEntryPos eofPos(aPos.iCluster,aPos.iPos+KSizeOfFatDirEntry*aNumOfEntries);
       
  2884 
       
  2885     if (IsRootDir(aPos))
       
  2886         { // Special case of root directory
       
  2887         if (eofPos.iPos+StartOfRootDirInBytes()>RootDirEnd())
       
  2888             User::Leave(KErrDirFull);
       
  2889         else
       
  2890             return;
       
  2891         }
       
  2892 
       
  2893     if (eofPos.iPos==clusterSize)
       
  2894         return; // No need to allocate
       
  2895     if (eofPos.iPos>clusterSize)
       
  2896         {
       
  2897         TInt numNeeded=eofPos.iPos>>ClusterSizeLog2();
       
  2898         if(IsRuggedFSys())
       
  2899             {
       
  2900             ExtendClusterListZeroedL(numNeeded,eofPos.iCluster);
       
  2901             }
       
  2902         else
       
  2903             {
       
  2904             FAT().ExtendClusterListL(numNeeded,eofPos.iCluster);
       
  2905             ZeroDirClusterL(eofPos.iCluster);
       
  2906             }
       
  2907 
       
  2908         eofPos.iPos-=numNeeded<<ClusterSizeLog2();
       
  2909         if(aPos.iPos==clusterSize)
       
  2910             {
       
  2911             if (!FAT().GetNextClusterL(aPos.iCluster))
       
  2912                 {
       
  2913                 __PRINT(_L("CFatMountCB::AddDirEntryL corrupt#1"))
       
  2914                 User::Leave(KErrCorrupt);
       
  2915                 }
       
  2916             aPos.iPos=0;
       
  2917             }
       
  2918         }
       
  2919     else if(Drive().IsRemovable())
       
  2920         {
       
  2921         // check if entry is already zeroed
       
  2922         ReadDirEntryL(eofPos,entry);
       
  2923         if(!entry.IsEndOfDirectory())
       
  2924             {
       
  2925             // some removable media may not have directory zeroed
       
  2926             entry.SetEndOfDirectory();
       
  2927             WriteDirEntryL(eofPos,entry);
       
  2928             }
       
  2929         }
       
  2930     }
       
  2931 
       
  2932 /**
       
  2933     Zero fill a cluster
       
  2934     @param  aCluster cluster number to zero-fill
       
  2935 */
       
  2936 void CFatMountCB::ZeroDirClusterL(TInt aCluster)
       
  2937     {
       
  2938 
       
  2939     __PRINT1(_L("CFatMountCB::ZeroDirClusterL %d"),aCluster);
       
  2940 
       
  2941     const TUint32 KClusterSz= 1<<ClusterSizeLog2();
       
  2942     const TUint32 KMaxBufSz = KClusterSz;           //-- max. nuffer size is a cluster
       
  2943     const TUint32 KMinBufSz = 1<<SectorSizeLog2();  //-- min. buffer size is 1 sector (for OOM case)
       
  2944 
       
  2945     //-- allocate a buffer for zero-filling a cluster
       
  2946     RBuf8 buf;
       
  2947     CleanupClosePushL(buf);
       
  2948 
       
  2949     if(buf.CreateMax(KMaxBufSz) != KErrNone)
       
  2950         buf.CreateMaxL(KMinBufSz); //-- OOM, try to create smaller buffer
       
  2951 
       
  2952     buf.FillZ();
       
  2953 
       
  2954     TEntryPos entryPos(aCluster,0);
       
  2955 
       
  2956     //-- write buffer to the beginning of the directory file.
       
  2957     DirWriteL(entryPos, buf); //-- use special interface to access FAT directory file
       
  2958 
       
  2959     //-- fill in the rest of the cluster if we used a small buffer
       
  2960     if((TUint32)buf.Size() < KClusterSz) //--  KMaxBufSz may == KMinBufSz if we have 1 sector per cluster
       
  2961     {
       
  2962         const TInt restCnt = SectorsPerCluster() - 1;
       
  2963         ASSERT(restCnt >=1);
       
  2964 
       
  2965         for(TInt i=0; i<restCnt; ++i)
       
  2966         {
       
  2967             entryPos.iPos += KMinBufSz;
       
  2968             DirWriteL(entryPos, buf); //-- use special interface to access FAT directory file
       
  2969         }
       
  2970 
       
  2971     }
       
  2972 
       
  2973     CleanupStack::PopAndDestroy(&buf);
       
  2974     }
       
  2975 
       
  2976 
       
  2977 /**
       
  2978     Internal method. Retrieves directory entry from given position.
       
  2979 
       
  2980     @param  aPos            on enter shall contain start position, from where the entry will be read. On return contains position of the DOS entry (the last one for object name for the VFAT case)
       
  2981     @param  aDosEntry       On return contains DOS entry for the VFAT case
       
  2982     @param  aStartEntry     On return contains start entry of the directory object for the VFAT case
       
  2983     @param  aLongFileName   On return contains VFAT or long filename
       
  2984 
       
  2985     @return  ETrue  if whole FAT entry is OK: only 1 entry for DOS name or _ALL_ entries for a long name
       
  2986              EFalse if there was an error in assembling entries to the long file name. In this case this entry shall be ignored by upper level.
       
  2987 
       
  2988     can leave because of ReadDirEntryL() and MoveToNextEntryL() [end of dir].
       
  2989 */
       
  2990 TBool CFatMountCB::DoGetDirEntryL(TEntryPos& aPos, TFatDirEntry& aDosEntry, TFatDirEntry& aStartEntry, TDes& aLongFileName) const
       
  2991     {
       
  2992 
       
  2993 //    __PRINT3(_L("CFatMountCB::GetDirEntryL() drv:%d, pos:%d:%d"), Drive().DriveNumber(), aPos.iCluster, aPos.iPos);
       
  2994 
       
  2995     ReadDirEntryL(aPos,aStartEntry);
       
  2996     aDosEntry=aStartEntry;
       
  2997     if (!aDosEntry.IsVFatEntry() || aDosEntry.IsErased() || aDosEntry.IsGarbage())
       
  2998         {//-- This is either a 8.3 FAT entry or garbage
       
  2999         aLongFileName.SetLength(0);
       
  3000         return ETrue;
       
  3001         }
       
  3002 
       
  3003     //-- process VFAT entries
       
  3004 
       
  3005     if(!aDosEntry.IsLongNameStart())
       
  3006         return EFalse; //-- wrong counter in the 1st VFat entry, consider it as orphaned
       
  3007 
       
  3008 
       
  3009     TInt count = aDosEntry.NumFollowing(); //-- count of the following VFat entries
       
  3010 
       
  3011     TBuf16<KMaxVFatEntryName> vBuf(KMaxVFatEntryName);
       
  3012     aDosEntry.ReadVFatEntry(vBuf);
       
  3013 
       
  3014     TInt vLength=vBuf.Locate('\0');
       
  3015     if (vLength==KErrNotFound)
       
  3016         vLength=KMaxVFatEntryName;
       
  3017 
       
  3018     vBuf.SetLength(vLength);
       
  3019 
       
  3020     const TInt nameLen = vLength+KMaxVFatEntryName*(count-1);
       
  3021     if(nameLen <= 0 || nameLen > KMaxFileName)
       
  3022         return EFalse; //--  wrong long file name length, consider VFAT entry as orphaned
       
  3023 
       
  3024     aLongFileName.SetLength(nameLen);
       
  3025 
       
  3026     const TUint8 entryCheckSum = aDosEntry.CheckSum(); //-- check sum from the 1st VFat entry
       
  3027 
       
  3028     while (count--)
       
  3029         {
       
  3030         TPtr fileNamePtr(&aLongFileName[0]+KMaxVFatEntryName*count,aLongFileName.Length()-KMaxVFatEntryName*count);
       
  3031         fileNamePtr.Copy(vBuf);
       
  3032         if (count==0)
       
  3033             break; //-- all VFat entries read, only DOS entry remained
       
  3034 
       
  3035         MoveToNextEntryL(aPos);
       
  3036         ReadDirEntryL(aPos,aDosEntry);
       
  3037 
       
  3038         //-- check if it is correct VFat entry.
       
  3039         //-- if not, this is the "orphaned" entry and will be ignored
       
  3040         if(!aDosEntry.IsVFatEntry() || aDosEntry.IsErased() || entryCheckSum != aDosEntry.CheckSum() || aDosEntry.NumFollowing() != count)
       
  3041             return EFalse;  //-- bad VFAT entry
       
  3042 
       
  3043         aDosEntry.ReadVFatEntry(vBuf);
       
  3044         }
       
  3045 
       
  3046     if (IsRootDir(aPos)&&(aPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))
       
  3047         return ETrue;//Allows maximum number of entries in root directory
       
  3048 
       
  3049     //-- read the last, DOS FAT entry
       
  3050     MoveToNextEntryL(aPos);
       
  3051     ReadDirEntryL(aPos,aDosEntry);
       
  3052 
       
  3053     //-- check if it is corect
       
  3054     if(aDosEntry.IsEndOfDirectory() || aDosEntry.IsErased() || aDosEntry.IsVFatEntry())
       
  3055         return EFalse; //-- Bad DOS entry
       
  3056 
       
  3057     //-- verify ChechSum here if it is incorrect, use DOS name only
       
  3058     const TUint8 calcNameChkSum = CalculateShortNameCheckSum(aDosEntry.Name());
       
  3059     if(calcNameChkSum != entryCheckSum)
       
  3060         {
       
  3061         aLongFileName.SetLength(0);//-- don't use long filename
       
  3062         __PRINT2(_L("CFatMountCB::GetDirEntryL() CheckSum mismatch: VFat:0x%x, DOS:0x%d"),entryCheckSum, calcNameChkSum);
       
  3063         }
       
  3064 
       
  3065     return ETrue;
       
  3066     }
       
  3067 
       
  3068 
       
  3069 /**
       
  3070     Read a number of VFAT entries from the directory file.
       
  3071     for parameters see DoGetDirEntryL()
       
  3072 
       
  3073     @return KErrNone if everything is OK, system wide error code otherwise
       
  3074 
       
  3075 */
       
  3076 TInt CFatMountCB::GetDirEntry(TEntryPos& aPos,TFatDirEntry& aDosEntry,TFatDirEntry& aStartEntry,TDes& aLongFileName) const
       
  3077     {
       
  3078 
       
  3079     TBool bEntryOK=ETrue;
       
  3080     TRAPD(nErr, bEntryOK = DoGetDirEntryL(aPos, aDosEntry, aStartEntry, aLongFileName));
       
  3081 
       
  3082     if(nErr !=KErrNone)
       
  3083         return nErr;
       
  3084 
       
  3085     if(!bEntryOK)
       
  3086         {//-- DoGetDirEntryL could not assemble whole VFat entry, probably some parts of it are damaged.
       
  3087          //-- consider it as an "orphaned" entry and skip
       
  3088         aDosEntry.iData[0] = 0xFF;      // Mark entry as garbage
       
  3089         aLongFileName.SetLength(0);     // No long filename
       
  3090         }
       
  3091 
       
  3092     return KErrNone;
       
  3093     }
       
  3094 
       
  3095 void CFatMountCB::MoveToNextEntryL(TEntryPos& aPos) const
       
  3096 //
       
  3097 // If anEntry is at the end of the cluster, and we are not the root dir,
       
  3098 // move it to the next in the list.
       
  3099 //
       
  3100     {
       
  3101 
       
  3102 //  __PRINT(_L("CFatMountCB::MoveToNextEntryL"));
       
  3103     if (IsEndOfClusterCh(aPos.iCluster))
       
  3104         return;
       
  3105     const TUint temp = 1<<ClusterSizeLog2();
       
  3106     if (aPos.iPos+KSizeOfFatDirEntry!=temp || IsRootDir(aPos))
       
  3107         {
       
  3108         aPos.iPos+=KSizeOfFatDirEntry;
       
  3109         }
       
  3110     else
       
  3111         {
       
  3112         if (FAT().GetNextClusterL(aPos.iCluster)==EFalse)
       
  3113             {
       
  3114             SetEndOfClusterCh(aPos.iCluster);
       
  3115             }
       
  3116         aPos.iPos=0;
       
  3117         }
       
  3118     }
       
  3119 
       
  3120 //-----------------------------------------------------------------------------------------
       
  3121 
       
  3122 /**
       
  3123     Starting from a VFat entry walk down the directory until the associated dos entry is found
       
  3124 
       
  3125     @param aPos     in: VFAT entry position. out: if this is a VFAT entry set, it will be DOS entry position. otherwise not changed
       
  3126     @param anEntry  on return will contain DOS dir. entry contents (if aPos points to the VFAT entry)
       
  3127 */
       
  3128 void CFatMountCB::MoveToDosEntryL(TEntryPos& aPos,TFatDirEntry& anEntry) const
       
  3129     {
       
  3130 
       
  3131     //__PRINT(_L("CFatMountCB::MoveToDosEntryL"));
       
  3132     if (anEntry.IsVFatEntry()==EFalse)
       
  3133         return;
       
  3134     FOREVER
       
  3135         {
       
  3136         MoveToNextEntryL(aPos);
       
  3137         ReadDirEntryL(aPos,anEntry);
       
  3138         if (anEntry.IsVFatEntry()==EFalse)
       
  3139             break;
       
  3140         if (IsRootDir(aPos)&&(aPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))
       
  3141             break;  //  Allows maximum number of entries in root directory
       
  3142         }
       
  3143     }
       
  3144 
       
  3145 //-----------------------------------------------------------------------------------------
       
  3146 
       
  3147 /** Read the Uid of the entry starting at aCluster */
       
  3148 void CFatMountCB::ReadUidL(TInt aCluster,TEntry& anEntry) const
       
  3149     {
       
  3150 
       
  3151     __PRINT1(_L("CFatMountCB::ReadUidL(%d)"), aCluster);
       
  3152 
       
  3153     if((TUint)aCluster < KFatFirstSearchCluster || (TUint)aCluster >= UsableClusters()+KFatFirstSearchCluster)
       
  3154         User::Leave(KErrCorrupt);
       
  3155 
       
  3156     TBuf8<sizeof(TCheckedUid)> uidBuf;
       
  3157     iRawDisk->ReadCachedL(FAT().DataPositionInBytes(aCluster),sizeof(TCheckedUid),uidBuf);
       
  3158     __ASSERT_DEBUG(uidBuf.Length()==sizeof(TCheckedUid),Fault(EFatReadUidFailed));
       
  3159     TCheckedUid uid(uidBuf);
       
  3160     anEntry.iType=uid.UidType();
       
  3161     }
       
  3162 
       
  3163 //-----------------------------------------------------------------------------------------
       
  3164 
       
  3165 /**
       
  3166     Read file section without opening this file on a file server side.
       
  3167 
       
  3168     @param  aName       file name; all trailing dots from the name will be removed
       
  3169     @param  aFilePos    start read position within a file
       
  3170     @param  aLength     how many bytes to read; on return will be how many bytes actually read
       
  3171     @param  aDes        local buffer desctriptor
       
  3172     @param  aMessage    from file server, used to write data to the buffer in different address space.
       
  3173 
       
  3174     @leave on media read error
       
  3175 */
       
  3176 void CFatMountCB::ReadSectionL(const TDesC& aName,TInt aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage)
       
  3177     {
       
  3178     __PRINT4(_L("CFatMountCB::ReadSectionL, drv:%d, pos:%d, len:%d, FN:%S"), DriveNumber(), aPos, aLength, &aName);
       
  3179 
       
  3180     CheckStateConsistentL();
       
  3181 
       
  3182     TEntryPos dosEntryPos(RootIndicator(),0);
       
  3183     TFatDirEntry dosEntry;
       
  3184     TFileName fileName;
       
  3185 
       
  3186 
       
  3187     TInt namePos=RemoveTrailingDots(aName).LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
  3188     TLeafDirData leafDir;
       
  3189     dosEntryPos.iCluster=FindLeafDirL(RemoveTrailingDots(aName).Left(namePos), leafDir);
       
  3190     dosEntryPos.iPos=0;
       
  3191     TEntryPos startPos;
       
  3192     TFatDirEntry startEntry;
       
  3193     DoFindL(RemoveTrailingDots(aName).Mid(namePos),KEntryAttMaskSupported,
       
  3194     		startPos,startEntry,dosEntryPos,dosEntry,
       
  3195     		fileName,KErrNotFound,
       
  3196     		NULL,
       
  3197     		leafDir);
       
  3198 
       
  3199 //  Check that reading from aPos for aLength lies within the file
       
  3200 //  if aPos is within the file, and aLength is too long, read up to EOF
       
  3201 //  If aPos is beyond the end of the file, return a zero length descriptor
       
  3202 
       
  3203 	TUint32 fileSize = dosEntry.Size();
       
  3204 	if ((TUint)aPos>=fileSize)
       
  3205         User::Leave(KErrEof);
       
  3206 
       
  3207     if ((TUint)(aPos+aLength)>fileSize)
       
  3208         aLength=fileSize-aPos;
       
  3209 
       
  3210     TInt cluster=StartCluster(dosEntry);
       
  3211 	TInt pos = aPos;
       
  3212 
       
  3213     TInt endCluster;
       
  3214     TInt clusterSize=1<<ClusterSizeLog2();      //  Size of file clusters
       
  3215 	TInt readTotal = 0;
       
  3216 
       
  3217 	// Total number of clusters in file
       
  3218     TInt maxClusters=((fileSize+clusterSize-1)>>ClusterSizeLog2());
       
  3219 
       
  3220 	// Read data
       
  3221     FOREVER
       
  3222         {
       
  3223 		//  Get the maximum number of clusters that can be read contiguously
       
  3224         TInt clusterListLen=FAT().CountContiguousClustersL(cluster,endCluster,maxClusters);
       
  3225         __ASSERT_DEBUG(clusterListLen>0,Fault(EReadFileSectionFailed));
       
  3226 
       
  3227 		//  If start position within this block, then read some data
       
  3228         if (pos<(clusterListLen<<ClusterSizeLog2()))
       
  3229             {
       
  3230 			//  Read the remaining length or the entire cluster block whichever is smaller
       
  3231 			TInt readLength = Min(aLength-readTotal,(clusterListLen<<ClusterSizeLog2())-pos);
       
  3232 			__ASSERT_DEBUG(readLength>0,Fault(EReadFileSectionFailed));
       
  3233 			TInt64 dataAddress=(FAT().DataPositionInBytes(cluster))+pos;
       
  3234 			iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal);
       
  3235 			readTotal += readLength;
       
  3236 
       
  3237 			if (readTotal == aLength)
       
  3238 				return;
       
  3239 
       
  3240 			pos += readLength;
       
  3241 			}
       
  3242 
       
  3243 		// Get the next cluster in file
       
  3244 		pos-=(clusterListLen<<ClusterSizeLog2());
       
  3245 #if defined(_DEBUG)
       
  3246 		TBool remainingClusters=
       
  3247 #endif
       
  3248 			((CFatMountCB*)this)->FAT().GetNextClusterL(endCluster);
       
  3249 		__ASSERT_DEBUG(remainingClusters,Fault(EReadFileSectionFailed));
       
  3250 		cluster=endCluster;
       
  3251 		}
       
  3252     }
       
  3253 
       
  3254 
       
  3255 //-----------------------------------------------------------------------------------------
       
  3256 
       
  3257 void CFatMountCB::RawReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,TInt anOffset,const RMessagePtr2& aMessage) const
       
  3258 //
       
  3259 // Read aLength of data from disk directly to thread relative descriptor
       
  3260 //
       
  3261     {
       
  3262     iRawDisk->ReadL(aPos,aLength,aTrg,aMessage,anOffset);
       
  3263     }
       
  3264 
       
  3265 //-----------------------------------------------------------------------------------------
       
  3266 
       
  3267 void CFatMountCB::RawWriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,TInt anOffset,const RMessagePtr2& aMessage)
       
  3268 //
       
  3269 // Write aLength of data from thread relative descriptor to disk
       
  3270 //
       
  3271     {
       
  3272     CheckWritableL();
       
  3273 
       
  3274 	//-- check if we are trying to write to the FAT directly and wait until FAT scan thread finishes in this case.
       
  3275     FAT().RequestRawWriteAccess(aPos, aLength);
       
  3276 
       
  3277     iRawDisk->WriteL(aPos,aLength,aSrc,aMessage,anOffset);
       
  3278     //-- Note: FAT directory cache will be invalidated in MountL()
       
  3279     }
       
  3280 
       
  3281 //-----------------------------------------------------------------------------------------
       
  3282 /**
       
  3283     This method must be used when writing to the FAT directory file.
       
  3284     If FAT directory cache is present on this drive, it will be used.
       
  3285     @param  aPos    entry media position
       
  3286     @param  aDes    data descriptor
       
  3287 */
       
  3288 void CFatMountCB::DirWriteL(const TEntryPos& aPos,const TDesC8& aDes)
       
  3289     {
       
  3290         CheckWritableL();
       
  3291         const TInt64 posAddr=MakeLinAddrL(aPos);
       
  3292 
       
  3293         if(!iRawDisk->DirCacheInterface())
       
  3294             {
       
  3295             iRawDisk->WriteCachedL(posAddr,aDes);
       
  3296             }
       
  3297         else
       
  3298             {//-- if there is an interface to the FAT directory cache, use it
       
  3299             iRawDisk->DirCacheInterface()->WriteL(posAddr, aDes);
       
  3300             }
       
  3301     }
       
  3302 
       
  3303 //-----------------------------------------------------------------------------------------
       
  3304 
       
  3305 /**
       
  3306     This method must be used when reading from the FAT directory file.
       
  3307     If FAT directory cache is present on this drive, it will be used.
       
  3308 
       
  3309     @param  aPos    entry media position
       
  3310     @param  aLength how many bytes to read
       
  3311     @param  aDes    input data descriptor
       
  3312 */
       
  3313 void CFatMountCB::DirReadL(const TEntryPos& aPos, TInt aLength, TDes8& aDes) const
       
  3314     {
       
  3315         const TInt64 posAddr=MakeLinAddrL(aPos);
       
  3316 
       
  3317         if(!iRawDisk->DirCacheInterface())
       
  3318             {
       
  3319             iRawDisk->ReadCachedL(posAddr,aLength,aDes);
       
  3320             }
       
  3321         else
       
  3322             {//-- if there is an interface to the FAT directory cache, use it
       
  3323             iRawDisk->DirCacheInterface()->ReadL(posAddr, aLength, aDes);
       
  3324             }
       
  3325     }
       
  3326 
       
  3327 //-----------------------------------------------------------------------------------------
       
  3328 
       
  3329 void CFatMountCB::WriteDirEntryL(const TEntryPos& aPos,const TFatDirEntry& aDirEntry)
       
  3330 //
       
  3331 // Write a FAT directory entry to disk.
       
  3332 // Assumes sufficient space has been created for it by AddDirEntry.
       
  3333 //
       
  3334     {
       
  3335 
       
  3336     __PRINT(_L("CFatMountCB::WriteDirEntryL"));
       
  3337 
       
  3338     //-- use special interface to access FAT directory file
       
  3339     DirWriteL(aPos,TPtrC8((TUint8*)&aDirEntry,KSizeOfFatDirEntry));
       
  3340     }
       
  3341 
       
  3342 //-----------------------------------------------------------------------------------------
       
  3343 
       
  3344 void CFatMountCB::EraseDirEntryL(const TEntryPos& aPos)
       
  3345 //
       
  3346 // Mark a dir entry as erased
       
  3347 //
       
  3348     {
       
  3349 
       
  3350     __PRINT(_L("CFatMountCB::EraseDirEntryL"));
       
  3351     if(!iLeafDirCache && iLastLeafDir)
       
  3352         iLastLeafDir->Des().SetLength(0);
       
  3353 
       
  3354     //-- use special interface to access FAT directory file
       
  3355     DirWriteL(aPos,TPtrC8((TUint8*)&KEntryErasedMarker,sizeof(TUint8)));
       
  3356     }
       
  3357 
       
  3358 //-----------------------------------------------------------------------------------------
       
  3359 
       
  3360 void CFatMountCB::ReadDirEntryL(const TEntryPos& aPos,TFatDirEntry& aDirEntry) const
       
  3361 //
       
  3362 // Read a FAT directory entry to disk
       
  3363 //
       
  3364     {
       
  3365 
       
  3366 //  __PRINT(_L("CFatMountCB::ReadDirEntryL"));
       
  3367     if (IsEndOfClusterCh(aPos.iCluster))
       
  3368         {
       
  3369         aDirEntry.InitZ();
       
  3370         return;
       
  3371         }
       
  3372     TPtr8 buf=TPtr8((TUint8*)&aDirEntry,KSizeOfFatDirEntry);
       
  3373 
       
  3374     //-- use special interface to access FAT directory file
       
  3375     DirReadL(aPos,KSizeOfFatDirEntry,buf);
       
  3376     }
       
  3377 
       
  3378 //-----------------------------------------------------------------------------------------
       
  3379 
       
  3380 /**
       
  3381     Enlarge the disk's size.
       
  3382     This method can be called only for variable size media, i.e. RAM drive
       
  3383 
       
  3384     @param aSize size increment (bytes)
       
  3385 */
       
  3386 void CFatMountCB::EnlargeL(TInt aSize)
       
  3387     {
       
  3388     __PRINT2(_L("CFatMountCB::EnlargeL by 0x%x currentsize=0x%x"),aSize,iSize);
       
  3389 
       
  3390     ASSERT(iRamDrive);
       
  3391 
       
  3392     TInt maxSize;
       
  3393     if (HAL::Get(HAL::EMaxRAMDriveSize, maxSize) == KErrNone && iSize + aSize > maxSize)
       
  3394         User::Leave(KErrDiskFull);
       
  3395     User::LeaveIfError(LocalDrive()->Enlarge(aSize));
       
  3396     iSize+=aSize;
       
  3397 
       
  3398     if (&FAT())
       
  3399         {
       
  3400         FAT().InitializeL();
       
  3401         }
       
  3402 
       
  3403     if (&RawDisk())
       
  3404         {
       
  3405         RawDisk().InitializeL();
       
  3406         }
       
  3407 
       
  3408     }
       
  3409 
       
  3410 //-----------------------------------------------------------------------------------------
       
  3411 
       
  3412 void CFatMountCB::ReduceSizeL(TInt aPos,TInt aLength)
       
  3413 //
       
  3414 // Reduce the disk's size
       
  3415 //
       
  3416     {
       
  3417 
       
  3418     __PRINT2(_L("CFatMountCB::ReduceSizeL aPos=0x%x aLength=0x%x"),aPos,aLength);
       
  3419     User::LeaveIfError(LocalDrive()->ReduceSize(aPos,aLength));
       
  3420     iSize-=aLength;
       
  3421     }
       
  3422 
       
  3423 //-----------------------------------------------------------------------------------------
       
  3424 
       
  3425 TInt64 CFatMountCB::MakeLinAddrL(const TEntryPos& aPos) const
       
  3426 //
       
  3427 // Convert cluster/position into linear address
       
  3428 //
       
  3429     {
       
  3430 
       
  3431     //__PRINT2(_L("CFatMountCB::MakeLinAddrL, cl:%d, pos:%d"), aPos.iCluster, aPos.iPos);
       
  3432     if (!IsRootDir(aPos))
       
  3433         {
       
  3434         TInt relPos=ClusterRelativePos(aPos.iPos);
       
  3435         return FAT().DataPositionInBytes(aPos.iCluster)+relPos;
       
  3436         }
       
  3437     if (aPos.iPos+StartOfRootDirInBytes()>=RootDirEnd())
       
  3438         User::Leave(KErrDirFull); // Past last root dir entry
       
  3439     return StartOfRootDirInBytes()+aPos.iPos;
       
  3440     }
       
  3441 
       
  3442 //-----------------------------------------------------------------------------------------
       
  3443 
       
  3444 void CFatMountCB::GetShortNameL(const TDesC& aLongName,TDes& aShortName)
       
  3445 //
       
  3446 // Get the short name associated with a long file name
       
  3447 //
       
  3448     {
       
  3449     __PRINT(_L("CFatMountCB::GetShortNameL"));
       
  3450     TEntryPos firstEntryPos(RootIndicator(),0);
       
  3451     TFatDirEntry firstEntry;
       
  3452     FindEntryStartL(aLongName,KEntryAttMaskSupported,firstEntry,firstEntryPos);
       
  3453     MoveToDosEntryL(firstEntryPos,firstEntry);
       
  3454     TBuf8<0x20> dosName(DosNameFromStdFormat(firstEntry.Name()));
       
  3455     LocaleUtils::ConvertToUnicodeL(aShortName, dosName);
       
  3456     }
       
  3457 
       
  3458 //-----------------------------------------------------------------------------------------
       
  3459 
       
  3460 void CFatMountCB::GetLongNameL(const TDesC& aShortName,TDes& aLongName)
       
  3461 //
       
  3462 // Get the long name associated with a short file name
       
  3463 //
       
  3464     {
       
  3465     __PRINT(_L("CFatMountCB::GetLongNameL"));
       
  3466     TEntryPos pos(RootIndicator(),0);
       
  3467     TFatDirEntry entry;
       
  3468     const TInt namePos=aShortName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
       
  3469     const TPtrC shortNameWithoutPathDelimiter(aShortName.Mid(namePos));
       
  3470     __ASSERT_ALWAYS(shortNameWithoutPathDelimiter.Length()<=12,User::Leave(KErrBadName));
       
  3471 
       
  3472     TLeafDirData leafDir;
       
  3473     pos.iCluster=FindLeafDirL(aShortName.Left(namePos), leafDir);
       
  3474     FOREVER
       
  3475         {
       
  3476         TFatDirEntry startEntry;
       
  3477         User::LeaveIfError(GetDirEntry(pos,entry,startEntry,aLongName));
       
  3478         if (entry.IsEndOfDirectory())
       
  3479             User::Leave(KErrNotFound);
       
  3480         TBool entryIsVFat=EFalse;
       
  3481         if (startEntry.IsVFatEntry())
       
  3482             entryIsVFat=ETrue;
       
  3483         if (!entry.IsParentDirectory() && !entry.IsCurrentDirectory() && !entry.IsGarbage() && !entry.IsErased())
       
  3484             {
       
  3485             TBuf8<0x20> entryName8(DosNameFromStdFormat(entry.Name()));
       
  3486             TBuf<0x20> entryName;
       
  3487             LocaleUtils::ConvertToUnicodeL(entryName, entryName8);
       
  3488             if (shortNameWithoutPathDelimiter.MatchF(entryName)!=KErrNotFound)
       
  3489                 {
       
  3490                 if (entryIsVFat==EFalse)
       
  3491                     aLongName=shortNameWithoutPathDelimiter;
       
  3492                 return;
       
  3493                 }
       
  3494             }
       
  3495         MoveToNextEntryL(pos);
       
  3496         }
       
  3497     }
       
  3498 
       
  3499 
       
  3500 
       
  3501 //-----------------------------------------------------------------------------------------
       
  3502 
       
  3503 /**
       
  3504     Extend a file or directory, zeroing cluster chain and flushing after every write to FAT.
       
  3505     This method is called for rugged FAT only.
       
  3506     for parameters see CFatTable::ExtendClusterListL
       
  3507 */
       
  3508 void CFatMountCB::ExtendClusterListZeroedL(TInt aNumber,TInt& aCluster)
       
  3509     {
       
  3510     __PRINT(_L("CFatMountCB::ExtendClusterListZeroedL"));
       
  3511     __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
       
  3512 
       
  3513     while(aNumber && FAT().GetNextClusterL(aCluster))
       
  3514         aNumber--;
       
  3515 
       
  3516     //-- request aNumber free clusters from the FAT, this request may wait until FAT scan thread counted enough free clusters if it is running.
       
  3517     if(!FAT().RequestFreeClusters(aNumber))
       
  3518         {
       
  3519         __PRINT(_L("CFatMountCB::ExtendClusterListL - leaving KErrDirFull"));
       
  3520         User::Leave(KErrDiskFull);
       
  3521         }
       
  3522     while (aNumber--)
       
  3523         {
       
  3524         TInt freeCluster=FAT().AllocateSingleClusterL(aCluster);
       
  3525         FAT().FlushL();
       
  3526         ZeroDirClusterL(freeCluster);
       
  3527         FAT().WriteL(aCluster,freeCluster);
       
  3528         FAT().FlushL();
       
  3529         aCluster=freeCluster;
       
  3530         }
       
  3531     }
       
  3532 
       
  3533 //-----------------------------------------------------------------------------------------
       
  3534 
       
  3535 #if defined(_DEBUG)
       
  3536 TInt CFatMountCB::ControlIO(const RMessagePtr2& aMessage,TInt aCommand,TAny* aParam1,TAny* aParam2)
       
  3537 //
       
  3538 // Debug function
       
  3539 //
       
  3540     {
       
  3541     if(aCommand>=EExtCustom)
       
  3542         {
       
  3543         if(LocalDrive())
       
  3544             return LocalDrive()->ControlIO(aMessage,aCommand-EExtCustom,aParam1,aParam2);
       
  3545         else
       
  3546             return KErrNotSupported;
       
  3547         }
       
  3548     switch(aCommand)
       
  3549         {
       
  3550         case ECriticalWriteFailOn:
       
  3551             {
       
  3552             TInt r;
       
  3553             TInt16 args[2];
       
  3554             TPtr8 des((TUint8*)args,4,4);
       
  3555             TRAP(r,aMessage.ReadL(2,des,0));
       
  3556             if(r!=KErrNone)
       
  3557                 return(r);
       
  3558             SetWriteFail(ETrue);
       
  3559             SetWriteFailCount(args[0]);
       
  3560             SetWriteFailError(args[1]);
       
  3561             break;
       
  3562             }
       
  3563         case ECriticalWriteFailOff:SetWriteFail(EFalse);break;
       
  3564         case ERuggedFSysOn: SetRuggedFSys(ETrue);break;
       
  3565         case ERuggedFSysOff: SetRuggedFSys(EFalse);break;
       
  3566         case EIsRuggedFSys:
       
  3567             {
       
  3568             TInt r;
       
  3569             TUint8 val = (IsRuggedFSys()!=0); // val = 0 or 1 for false/true
       
  3570             TPtr8 pVal(&val,1,1);
       
  3571             TRAP(r,aMessage.WriteL(2,pVal,0));
       
  3572             if(r!=KErrNone)
       
  3573                 return(r);
       
  3574             break;
       
  3575             }
       
  3576 		case ELocalTimeForRemovableMediaOn:
       
  3577 			{
       
  3578 			FatFileSystem().SetUseLocalTime(ETrue);
       
  3579 			break;
       
  3580 			}
       
  3581 		case ELocalTimeForRemovableMediaOff:
       
  3582 			{
       
  3583 			FatFileSystem().SetUseLocalTime(EFalse);
       
  3584 			break;
       
  3585 			}
       
  3586 		case ELocalTimeUsedOnRemovableMedia:
       
  3587 			{
       
  3588 			TBool flag = FatFileSystem().GetUseLocalTime();
       
  3589 			TPckgC<TBool> flagPckg(flag);
       
  3590 			TInt r = aMessage.Write(2, flagPckg);
       
  3591 			if(r!=KErrNone)
       
  3592 				return r;
       
  3593 			break;
       
  3594 			}
       
  3595 		case ECreationTime:
       
  3596 			{
       
  3597 			CheckStateConsistentL();
       
  3598 
       
  3599 			TEntryPos firstEntryPos(RootIndicator(),0);
       
  3600 			TFatDirEntry firstEntry;
       
  3601 			//RFs::ControlIO restricts you to use narrow descriptors
       
  3602 			//so convert narrow back to wide.
       
  3603 			TBuf8<KMaxPath> fileNameNarrow;
       
  3604 			aMessage.Read(2, fileNameNarrow);
       
  3605 
       
  3606 			TFileName fileNameWide;
       
  3607 			fileNameWide.Copy(fileNameNarrow);
       
  3608 
       
  3609 			//find the long file name entry
       
  3610 			TRAPD(r, FindEntryStartL(fileNameWide,KEntryAttMaskSupported,firstEntry,firstEntryPos) );
       
  3611 			if(r!=KErrNone)
       
  3612               return(r);
       
  3613 			//Find the corresponding 8.3 short name entry, for metadata
       
  3614 			MoveToDosEntryL(firstEntryPos,firstEntry);
       
  3615 			TTime creationTime=0;
       
  3616 			TPckg<TTime> timePckg(creationTime);
       
  3617 			SFatDirEntry* sEntry = reinterpret_cast<SFatDirEntry*>(firstEntry.iData);
       
  3618 			creationTime = DosTimeToTTime(sEntry->iTimeC, sEntry->iDateC);
       
  3619 			r = aMessage.Write(3, timePckg);
       
  3620 			if(r!=KErrNone)
       
  3621 				return r;
       
  3622 			break;
       
  3623 			}
       
  3624 		case EDisableFATDirCache:
       
  3625 			{
       
  3626 		    MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface();
       
  3627 		    TUint32 KEDisableFATDirCache = CDynamicDirCache::EDisableCache;
       
  3628 		    pDirCache->Control(KEDisableFATDirCache, (TUint32) aParam1, NULL);
       
  3629 			break;
       
  3630 			}
       
  3631 		case EDumpFATDirCache:
       
  3632 			{
       
  3633 		    MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface();
       
  3634 		    TUint32 KEDumpFATDirCache = CDynamicDirCache::EDumpCache;
       
  3635 		    pDirCache->Control(KEDumpFATDirCache, 0, NULL);
       
  3636 			break;
       
  3637 			}
       
  3638 		case EFATDirCacheInfo:
       
  3639 			{
       
  3640 		    MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface();
       
  3641 		    TUint32 KEFATDirCacheInfo = CDynamicDirCache::ECacheInfo;
       
  3642 		    pDirCache->Control(KEFATDirCacheInfo, 0, NULL);
       
  3643 			break;
       
  3644 			}
       
  3645 
       
  3646 
       
  3647         default: return(KErrNotSupported);
       
  3648         }
       
  3649     return(KErrNone);
       
  3650     }
       
  3651 #else
       
  3652 TInt CFatMountCB::ControlIO(const RMessagePtr2& /*aMessage*/,TInt /*aCommand*/,TAny* /*aParam1*/,TAny* /*aParam2*/)
       
  3653     {return(KErrNotSupported);}
       
  3654 #endif
       
  3655 
       
  3656 
       
  3657 //-----------------------------------------------------------------------------------------
       
  3658 
       
  3659 TInt CFatMountCB::Lock(TMediaPassword& aOld,TMediaPassword& aNew,TBool aStore)
       
  3660 //
       
  3661 // lock media device
       
  3662 //
       
  3663     {
       
  3664     __PRINT(_L("CFatMountCB::Lock"));
       
  3665 	TInt r=CreateDrive(Drive().DriveNumber());
       
  3666     if (r!=KErrNone)
       
  3667         return r;
       
  3668 
       
  3669     TBusLocalDrive* local;
       
  3670     r=LocalDrive()->GetLocalDrive(local);
       
  3671     if (r!=KErrNone)
       
  3672         return r;
       
  3673 
       
  3674 #ifdef _LOCKABLE_MEDIA
       
  3675     if(local->Status()==KErrLocked)
       
  3676         local->Status() = KErrNotReady;
       
  3677 #endif
       
  3678     r=local->SetPassword(aOld,aNew,aStore);
       
  3679     if(r==KErrNone&&aStore)
       
  3680         WritePasswordData();
       
  3681     return(r);
       
  3682     }
       
  3683 
       
  3684 //-----------------------------------------------------------------------------------------
       
  3685 
       
  3686 TInt CFatMountCB::Unlock(TMediaPassword& aPassword,TBool aStore)
       
  3687 //
       
  3688 // Unlock media device
       
  3689 //
       
  3690     {
       
  3691     __PRINT(_L("CFatMountCB::Unlock"));
       
  3692 	TInt r=CreateDrive(Drive().DriveNumber());
       
  3693     if (r!=KErrNone)
       
  3694         return r;
       
  3695 
       
  3696     TBusLocalDrive* local;
       
  3697     r=LocalDrive()->GetLocalDrive(local);
       
  3698     if (r!=KErrNone)
       
  3699         return r;
       
  3700 
       
  3701 #ifdef _LOCKABLE_MEDIA
       
  3702     if(local->Status()==KErrLocked)
       
  3703         local->Status() = KErrNotReady;
       
  3704 #endif
       
  3705     r=local->Unlock(aPassword,aStore);
       
  3706     if(r==KErrNone&&aStore)
       
  3707         WritePasswordData();
       
  3708     return(r);
       
  3709     }
       
  3710 
       
  3711 //-----------------------------------------------------------------------------------------
       
  3712 
       
  3713 TInt CFatMountCB::ClearPassword(TMediaPassword& aPassword)
       
  3714 //
       
  3715 // Clear password from media device
       
  3716 //
       
  3717     {
       
  3718     __PRINT(_L("CFatMountCB::ClearPassword"));
       
  3719 	TInt r=CreateDrive(Drive().DriveNumber());
       
  3720     if (r!=KErrNone)
       
  3721         return r;
       
  3722 
       
  3723     TBusLocalDrive* local;
       
  3724     r=LocalDrive()->GetLocalDrive(local);
       
  3725     if (r!=KErrNone)
       
  3726         return r;
       
  3727 
       
  3728 #ifdef _LOCKABLE_MEDIA
       
  3729     if(local->Status()==KErrLocked)
       
  3730         local->Status() = KErrNotReady;
       
  3731 #endif
       
  3732     r=local->Clear(aPassword);
       
  3733     if(r==KErrNone)
       
  3734         WritePasswordData();
       
  3735     return(r);
       
  3736     }
       
  3737 
       
  3738 //-----------------------------------------------------------------------------------------
       
  3739 
       
  3740 TInt CFatMountCB::ErasePassword()
       
  3741 //
       
  3742 // Forcibly erase the password from a media device
       
  3743 //
       
  3744     {
       
  3745     __PRINT(_L("CFatMountCB::ErasePassword"));
       
  3746 
       
  3747 	TInt r=CreateDrive(Drive().DriveNumber());
       
  3748     if (r!=KErrNone)
       
  3749         return r;
       
  3750 
       
  3751     TBusLocalDrive* local;
       
  3752     r=LocalDrive()->GetLocalDrive(local);
       
  3753     if (r!=KErrNone)
       
  3754         return r;
       
  3755 
       
  3756 #ifdef _LOCKABLE_MEDIA
       
  3757     if(local->Status()==KErrLocked)
       
  3758         local->Status() = KErrNotReady;
       
  3759 #endif
       
  3760     r=local->ErasePassword();
       
  3761     if(r==KErrNone)
       
  3762         {
       
  3763         // ...media change to ensure a fresh remount the drive
       
  3764         r = local->ForceRemount(0);
       
  3765         local->Status() = KErrNotReady;
       
  3766         WritePasswordData();
       
  3767         }
       
  3768     return(r);
       
  3769     }
       
  3770 
       
  3771 //-----------------------------------------------------------------------------------------
       
  3772 
       
  3773 TInt CFatMountCB::ForceRemountDrive(const TDesC8* aMountInfo,TInt aMountInfoMessageHandle,TUint aFlags)
       
  3774 //
       
  3775 // Force a remount of the drive
       
  3776 //
       
  3777     {
       
  3778     __PRINT(_L("CFatMountCB::ForceRemountDrive"));
       
  3779 	TInt r=CreateDrive(Drive().DriveNumber());
       
  3780     if (r==KErrNone)
       
  3781 		r=LocalDrive()->SetMountInfo(aMountInfo,aMountInfoMessageHandle);
       
  3782     if (r==KErrNone)
       
  3783         r=LocalDrive()->ForceRemount(aFlags);
       
  3784     return(r);
       
  3785     }
       
  3786 
       
  3787 //-----------------------------------------------------------------------------------------
       
  3788 
       
  3789 void CFatMountCB::WritePasswordData()
       
  3790 //
       
  3791 // Write store password data to disk
       
  3792 //
       
  3793     {
       
  3794     __PRINT(_L("CFatMountCB::WritePasswordData"));
       
  3795     TBuf<sizeof(KMediaPWrdFile)> mediaPWrdFile(KMediaPWrdFile);
       
  3796     mediaPWrdFile[0] = (TUint8) RFs::GetSystemDriveChar();
       
  3797     __PRINT1TEMP(_L("disk file = %S"),mediaPWrdFile);
       
  3798     TBusLocalDrive& local=GetLocalDrive(Drive().DriveNumber());
       
  3799     TInt length=local.PasswordStoreLengthInBytes();
       
  3800     if(length==0)
       
  3801         {
       
  3802         WriteToDisk(mediaPWrdFile,_L8(""));
       
  3803         return;
       
  3804         }
       
  3805     HBufC8* hDes=HBufC8::New(length);
       
  3806     if(hDes==NULL)
       
  3807         return;
       
  3808     TPtr8 pDes=hDes->Des();
       
  3809     TInt r=local.ReadPasswordData(pDes);
       
  3810     if(r==KErrNone)
       
  3811         WriteToDisk(mediaPWrdFile,pDes);
       
  3812     delete hDes;
       
  3813     }
       
  3814 
       
  3815 //-----------------------------------------------------------------------------------------
       
  3816 
       
  3817 /**
       
  3818 Trim trailing spaces of volume label descriptor and adjust its length
       
  3819 */
       
  3820 void CFatMountCB::TrimVolumeLabel(TDes8& aLabel) const
       
  3821     {
       
  3822     // Locate first '\0'
       
  3823     TInt nullPos = aLabel.Locate('\0');
       
  3824     if (nullPos == KErrNotFound)
       
  3825         nullPos = KVolumeLabelSize;
       
  3826 
       
  3827     // Trim trailing spaces
       
  3828     TInt i;
       
  3829     for (i=nullPos-1; i>=0; --i)
       
  3830         if (aLabel[i] != 0x20)
       
  3831             break;
       
  3832     aLabel.SetLength(i+1);
       
  3833     }
       
  3834 
       
  3835 //-----------------------------------------------------------------------------------------
       
  3836 
       
  3837 /**
       
  3838 Searches for the volume label file
       
  3839 
       
  3840 @param aLabel The name of the volume label file returned upon successful search
       
  3841 @return KErrNone if it finds the volume label file, otherwise KErrNotFound
       
  3842 */
       
  3843 TInt CFatMountCB::ReadVolumeLabelFile(TDes8& aLabel)
       
  3844     {
       
  3845     __PRINT(_L("+CFatMountCB::ReadVolumeLabelFile"));
       
  3846     TEntryPos pos(RootIndicator(),0);
       
  3847     TFatDirEntry entry;
       
  3848     TRAPD(r, FindVolumeLabelFileL(aLabel, pos, entry));
       
  3849     __PRINT1(_L("-CFatMountCB::ReadVolumeLabelFile: %d"),r);
       
  3850     return r;
       
  3851     }
       
  3852 
       
  3853 //-----------------------------------------------------------------------------------------
       
  3854 
       
  3855 /**
       
  3856 Creates or updates the volume label file with name aNewName
       
  3857 
       
  3858 @param aNewName The new name for the volume label file
       
  3859 */
       
  3860 void CFatMountCB::WriteVolumeLabelFileL(const TDesC8& aNewName)
       
  3861     {
       
  3862     __PRINT1(_L("+CFatMountCB::WriteVolumeLabelFileL: [%S]"), &aNewName);
       
  3863     TEntryPos pos(RootIndicator(),0);
       
  3864     TFatDirEntry entry;
       
  3865 
       
  3866     TBuf8<KVolumeLabelSize> oldName;
       
  3867     TRAPD(r, FindVolumeLabelFileL(oldName, pos, entry));
       
  3868 
       
  3869     if( KErrNone == r )
       
  3870         {
       
  3871         // Found existing volume label file, rename or delete
       
  3872         if(oldName == aNewName)
       
  3873             {
       
  3874             __PRINT(_L("-CFatMountCB::WriteVolumeLabelFileL: found: names match"));
       
  3875             return;
       
  3876             }
       
  3877         else
       
  3878             {
       
  3879             if(aNewName.Length() == 0)
       
  3880                 {
       
  3881                 // delete the volume label file
       
  3882                 __PRINT(_L("CFatMountCB::WriteVolumeLabelFileL: found: delete"));
       
  3883                 EraseDirEntryL(pos, entry);
       
  3884                 }
       
  3885             else
       
  3886                 {
       
  3887                 __PRINT(_L("CFatMountCB::WriteVolumeLabelFileL: found: replace"));
       
  3888                 entry.SetName(aNewName);
       
  3889                 WriteDirEntryL(pos, entry);
       
  3890                 }
       
  3891             FAT().FlushL();
       
  3892             }
       
  3893         }
       
  3894     else if( KErrNotFound == r )
       
  3895         {
       
  3896         // Not found, need to create if aNewName is not empty
       
  3897         // Windows allows a volume label file to have the same name as
       
  3898         // an existing file or directory
       
  3899         if(aNewName.Length() > 0)
       
  3900             {
       
  3901             __PRINT(_L("CFatMountCB::WriteVolumeLabelFileL: not found: create"));
       
  3902             TEntryPos dirPos(RootIndicator(),0);
       
  3903             AddDirEntryL(dirPos,1);
       
  3904             TFatDirEntry fatDirEntry;
       
  3905             fatDirEntry.SetName(aNewName);
       
  3906             fatDirEntry.SetAttributes(KEntryAttVolume);
       
  3907 
       
  3908             TTime now;
       
  3909 			now.UniversalTime();
       
  3910 			fatDirEntry.SetTime(now, TimeOffset() );
       
  3911             fatDirEntry.SetStartCluster(0);
       
  3912             fatDirEntry.SetSize(0);
       
  3913             WriteDirEntryL(dirPos, fatDirEntry);
       
  3914             FAT().FlushL();
       
  3915             }
       
  3916         }
       
  3917     else
       
  3918         {
       
  3919         // Some other error
       
  3920         User::Leave(r);
       
  3921         }
       
  3922     }
       
  3923 
       
  3924 
       
  3925 //-----------------------------------------------------------------------------------------
       
  3926 
       
  3927 /**
       
  3928 Scans the root directory for a volume label file. Leaves with an error if not found
       
  3929 
       
  3930 @param aLabel Name of the volume label file upon successful search
       
  3931 @param aDosEntryPos Pointer to position of the volume label file upon successful search
       
  3932 @param aDosEntry Contains the entry for the volume label file upon successful search
       
  3933 */
       
  3934 void CFatMountCB::FindVolumeLabelFileL(TDes8& aLabel, TEntryPos& aDosEntryPos, TFatDirEntry& aDosEntry)
       
  3935     {
       
  3936     __PRINT(_L("+CFatMountCB::FindVolumeLabelFileL"));
       
  3937 
       
  3938     if(IsRootDir(aDosEntryPos) && (aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd()))
       
  3939         {
       
  3940         __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: abort, exceeds root"));
       
  3941         User::Leave(KErrNotFound); // Allows maximum number of entries in root directory
       
  3942         }
       
  3943 
       
  3944     TInt previousCluster= aDosEntryPos.iCluster;
       
  3945     TUint previousPosition= aDosEntryPos.iPos;
       
  3946     TInt changePreviousCluster=1;
       
  3947     TInt count=0;
       
  3948 
       
  3949     TFatDirEntry startEntry;
       
  3950     TFileName dummyLongName;
       
  3951 
       
  3952     FOREVER
       
  3953         {
       
  3954 #ifdef _DEBUG
       
  3955         const TInt e= GetDirEntry(aDosEntryPos, aDosEntry, startEntry, dummyLongName);
       
  3956         __PRINT1(_L("CFatMountCB::FindVolumeLabelFileL: GetDir %d"), e);
       
  3957         User::LeaveIfError(e);
       
  3958 #else
       
  3959         User::LeaveIfError(GetDirEntry(aDosEntryPos, aDosEntry, startEntry, dummyLongName));
       
  3960 #endif
       
  3961         if(aDosEntry.IsEndOfDirectory())
       
  3962             {
       
  3963             __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: end of dir"));
       
  3964             User::Leave(KErrNotFound);
       
  3965             }
       
  3966         if(IsRootDir(aDosEntryPos) && (aDosEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))
       
  3967             {
       
  3968             if(aDosEntry.IsErased())
       
  3969                 {
       
  3970                 __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: erased end of root"));
       
  3971                 User::Leave(KErrNotFound); //Allows maximum number of entries in root directory
       
  3972                 }
       
  3973             }
       
  3974         if(!aDosEntry.IsCurrentDirectory() && !aDosEntry.IsParentDirectory() && !aDosEntry.IsErased() && !aDosEntry.IsGarbage())
       
  3975             {
       
  3976             if(aDosEntry.Attributes() & KEntryAttVolume)
       
  3977                 {
       
  3978                 aLabel = aDosEntry.Name();
       
  3979 #ifdef _DEBUG
       
  3980                 dummyLongName.Copy(aLabel);
       
  3981                 __PRINT1(_L("-CFatMountCB::FindVolumeLabelFileL: found [%S]"), &dummyLongName);
       
  3982 #endif
       
  3983                 break;
       
  3984                 }
       
  3985             }
       
  3986         MoveToNextEntryL(aDosEntryPos);
       
  3987         if(IsRootDir(aDosEntryPos) && (aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd()))
       
  3988             {
       
  3989             __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: passed end of root"));
       
  3990             User::Leave(KErrNotFound); //Allows maximum number of entries in root directory
       
  3991             }
       
  3992         if(aDosEntryPos.iCluster && (aDosEntryPos.iPos <= previousPosition))
       
  3993             {
       
  3994             DoCheckFatForLoopsL(aDosEntryPos.iCluster, previousCluster, changePreviousCluster, count);
       
  3995             }
       
  3996         previousPosition=aDosEntryPos.iPos;
       
  3997         }
       
  3998     }
       
  3999 
       
  4000 //-----------------------------------------------------------------------------------------
       
  4001 
       
  4002 /**
       
  4003 Read volume label from disk and trim trailing 0x20 & 0x00 characters
       
  4004 */
       
  4005 void CFatMountCB::GetVolumeLabelFromDiskL(const TFatBootSector& aBootSector)
       
  4006     {
       
  4007     // Read volume label as 8 bit descriptor
       
  4008     TBuf8<KVolumeLabelSize> volName8;
       
  4009     TInt r = ReadVolumeLabelFile(volName8);
       
  4010     if(r != KErrNone)   // No volume label file in root directory
       
  4011         volName8 = aBootSector.VolumeLabel();
       
  4012     TrimVolumeLabel(volName8);
       
  4013 
       
  4014     TBuf16<KVolumeLabelSize> volName16;
       
  4015     LocaleUtils::ConvertToUnicodeL(volName16, volName8);
       
  4016     SetVolumeName(volName16.AllocL());
       
  4017     }
       
  4018 
       
  4019 
       
  4020 //-----------------------------------------------------------------------------------------
       
  4021 
       
  4022 /**
       
  4023 Populates iMap member of aInfo with contiguous block group maps.
       
  4024 
       
  4025 @param aPos     Start position for a desired section of the file.
       
  4026 @param sLength  Length of the desired data to produce the block map for.
       
  4027 @param aInfo    A structure describing a group of block maps.
       
  4028 */
       
  4029 void CFatMountCB::BlockMapReadFromClusterListL(TEntryPos& aPos, TInt aLength, SBlockMapInfo& aInfo)
       
  4030     {
       
  4031     __PRINT(_L("CFatMountCB::BlockMapReadFromClusterListL"));
       
  4032     __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
       
  4033     TBlockMapEntry blockMapEntry;
       
  4034 
       
  4035     TUint i = 0;
       
  4036     TInt clusterRelativePos;
       
  4037     TInt maxClusters;
       
  4038     TInt endCluster;
       
  4039     TInt clusterListLen;
       
  4040     TInt readLength;
       
  4041     TInt temp;
       
  4042     TInt currentPos;
       
  4043     TLocalDriveCapsBuf caps;
       
  4044     TInt r;
       
  4045     TInt64 realPosition = 0;
       
  4046 
       
  4047     do
       
  4048         {
       
  4049         currentPos = aPos.iPos;
       
  4050         temp = currentPos>>ClusterSizeLog2();
       
  4051         if ( (currentPos) && ( (currentPos) == (temp<<ClusterSizeLog2()) ) )
       
  4052             {
       
  4053             if (!FAT().GetNextClusterL(aPos.iCluster))
       
  4054                 {
       
  4055 				__PRINT(_L("CFatMountCB::BlockMapReadFromClusterListL corrupt#1"))
       
  4056                 User::Leave(KErrCorrupt);
       
  4057                 }
       
  4058             }
       
  4059         clusterRelativePos = ClusterRelativePos( aPos.iPos );
       
  4060         maxClusters = ((aLength + clusterRelativePos - 1)>>ClusterSizeLog2())+1;
       
  4061         clusterListLen = FAT().CountContiguousClustersL(aPos.iCluster, endCluster, maxClusters);
       
  4062         readLength = Min( aLength, (clusterListLen<<ClusterSizeLog2()) - clusterRelativePos);
       
  4063 
       
  4064         blockMapEntry.SetNumberOfBlocks( clusterListLen );
       
  4065         if (aPos.iCluster < 2)
       
  4066             User::Leave(KErrCorrupt);
       
  4067         r = LocalDrive()->Caps(caps);
       
  4068         if ( r != KErrNone )
       
  4069             User::LeaveIfError(r);
       
  4070         if ( caps().iType&EMediaRam )
       
  4071             {
       
  4072             realPosition = FAT().DataPositionInBytes( aPos.iCluster );
       
  4073             aPos.iCluster = I64LOW((realPosition - aInfo.iStartBlockAddress)>>ClusterSizeLog2());
       
  4074             blockMapEntry.SetStartBlock( aPos.iCluster );
       
  4075             }
       
  4076         else
       
  4077             blockMapEntry.SetStartBlock( aPos.iCluster - 2);
       
  4078         aInfo.iMap.Append(TPckgC<TBlockMapEntry>(blockMapEntry));
       
  4079         aPos.iPos += readLength;
       
  4080         aPos.iCluster = endCluster;
       
  4081         aLength -= readLength;
       
  4082         }
       
  4083     while( ( aLength > 0 ) && ( ++i < KMaxMapsPerCall ) );
       
  4084     }
       
  4085 
       
  4086 
       
  4087 //-----------------------------------------------------------------------------------------
       
  4088 
       
  4089 TInt CFatMountCB::GetDosEntryFromNameL(const TDesC& aName, TEntryPos& aDosEntryPos, TFatDirEntry& aDosEntry)
       
  4090     {
       
  4091     TFatDirEntry firstEntry;
       
  4092     TEntryPos firstEntryPos(RootIndicator(),0); // Already checked entry is a directory
       
  4093     FindEntryStartL(aName,KEntryAttMaskSupported,firstEntry,firstEntryPos);
       
  4094 
       
  4095     aDosEntryPos=firstEntryPos;
       
  4096     aDosEntry=firstEntry;
       
  4097     MoveToDosEntryL(aDosEntryPos,aDosEntry);
       
  4098 
       
  4099     return KErrNone;
       
  4100     }
       
  4101 
       
  4102 //-----------------------------------------------------------------------------------------
       
  4103 
       
  4104 TInt CFatMountCB::GetFileUniqueId(const TDesC& aName, TInt64& aUniqueId)
       
  4105     {
       
  4106     // Get first cluster of file
       
  4107     TEntryPos dosEntryPos(RootIndicator(),0);
       
  4108     TFatDirEntry dosEntry;
       
  4109     InitializeRootEntry(dosEntry);  // Nugatory initialisation to placate warnings
       
  4110     TRAPD(err,GetDosEntryFromNameL(aName,dosEntryPos,dosEntry));
       
  4111     if(err!=KErrNone)
       
  4112         return err;
       
  4113     TInt startCluster=StartCluster(dosEntry);
       
  4114     // Empty files will return a cluster of zero
       
  4115     if(startCluster==0)
       
  4116         return KErrEof;
       
  4117     aUniqueId=MAKE_TINT64(0,startCluster);
       
  4118     return KErrNone;
       
  4119     }
       
  4120 //-----------------------------------------------------------------------------------------
       
  4121 
       
  4122 
       
  4123 TInt CFatMountCB::Spare3(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
       
  4124     {
       
  4125     return KErrNotSupported;
       
  4126     }
       
  4127 
       
  4128 TInt CFatMountCB::Spare2(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
       
  4129     {
       
  4130     return KErrNotSupported;
       
  4131     }
       
  4132 
       
  4133 TInt CFatMountCB::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
       
  4134     {
       
  4135     return KErrNotSupported;
       
  4136     }
       
  4137 
       
  4138 //-----------------------------------------------------------------------------------------
       
  4139 
       
  4140 //-- maximal level of recursion for the CheckDisk. i.e. the max. number of folded directories to check.
       
  4141 const TInt KCheckDskMaxRecursionLevel = 50;
       
  4142 
       
  4143 //
       
  4144 // Walks a directory cluster list then checks all the entries.
       
  4145 //
       
  4146 void  CFatMountCB::ChkDirL(RBitVector& aFatBitVec, TInt aDirCluster)
       
  4147     {
       
  4148     //__PRINT1(_L("### CFatMountCB::ChkDirL() level:%d"),iChkDiscRecLevel);
       
  4149 
       
  4150     //-- check if we have reached the recursion limit. on hardware the stack is very limited
       
  4151     //-- and its overflow will lead to crash.
       
  4152     if(iChkDiscRecLevel++ >= KCheckDskMaxRecursionLevel)
       
  4153         {
       
  4154          __PRINT1(_L("CFatMountCB::ChkDirL() max recursion level(%d) reached. Leaving!"),iChkDiscRecLevel);
       
  4155          User::Leave(KErrTooBig);
       
  4156         }
       
  4157 
       
  4158     if(/*Is32BitFat() &&*/aDirCluster != 0 && (aDirCluster == RootIndicator()))//the bit in comments maybe required
       
  4159         WalkClusterListL(aFatBitVec, RootIndicator());
       
  4160 
       
  4161     TEntryPos entryPos(aDirCluster,0);
       
  4162     FOREVER
       
  4163         {
       
  4164         TFatDirEntry entry;
       
  4165         ReadDirEntryL(entryPos,entry);
       
  4166         MoveToDosEntryL(entryPos,entry);
       
  4167         if (entry.IsEndOfDirectory())
       
  4168             break;
       
  4169         if (IsRootDir(entryPos)&&(StartOfRootDirInBytes()+entryPos.iPos==(RootDirEnd()-KSizeOfFatDirEntry)))
       
  4170             {
       
  4171             if(!entry.IsErased())
       
  4172                 ChkEntryL(aFatBitVec, entry);
       
  4173             break;  //  Allows maximum number of entries in root directory
       
  4174             }
       
  4175         MoveToNextEntryL(entryPos);
       
  4176         if (entry.IsParentDirectory() || entry.IsCurrentDirectory() || entry.IsErased())
       
  4177             continue;
       
  4178         ChkEntryL(aFatBitVec, entry);
       
  4179         }
       
  4180 
       
  4181     iChkDiscRecLevel--;
       
  4182     }
       
  4183 
       
  4184 //-----------------------------------------------------------------------------------------
       
  4185 
       
  4186 //
       
  4187 // Check FAT is valid for anEntry
       
  4188 //
       
  4189 void  CFatMountCB::ChkEntryL(RBitVector& aFatBitVec, const TFatDirEntry& anEntry)
       
  4190     {
       
  4191     TInt listLength=0;
       
  4192 
       
  4193     if ((anEntry.Attributes()&(KEntryAttDir)) || anEntry.Size())
       
  4194         listLength=WalkClusterListL(aFatBitVec, StartCluster(anEntry));
       
  4195     else if (anEntry.StartCluster() != 0)        // zero length file
       
  4196         User::Leave(EFatChkDskInvalidEntrySize); // shouldn't have clusters
       
  4197 
       
  4198     if (anEntry.Attributes()&KEntryAttDir)
       
  4199         ChkDirL(aFatBitVec, StartCluster(anEntry));
       
  4200 
       
  4201     //  Check that the correct number of clusters have been allocated for the size of the file.
       
  4202 
       
  4203     else if ((anEntry.Attributes()&KEntryAttVolume)==0)
       
  4204         {
       
  4205         TInt clustersForFileSize;
       
  4206         TInt clusterSize=1<<ClusterSizeLog2();
       
  4207         clustersForFileSize = (TInt) ( (TInt64(anEntry.Size()) + TInt64(clusterSize-1)) >> ClusterSizeLog2() );
       
  4208 
       
  4209         if (listLength!=clustersForFileSize)
       
  4210             User::Leave(EFatChkDskInvalidEntrySize);
       
  4211         }
       
  4212     }
       
  4213 
       
  4214 //-----------------------------------------------------------------------------------------
       
  4215 
       
  4216 //
       
  4217 // Walks cluster list from aCluster to EOF
       
  4218 // Reports an error if an invalid cluster is found before EOF or
       
  4219 // a cluster has been visited before.
       
  4220 //
       
  4221 TInt  CFatMountCB::WalkClusterListL(RBitVector& aFatBitVec, TInt aCluster)
       
  4222     {
       
  4223 
       
  4224     TInt i=0;
       
  4225     do  {
       
  4226         i++;
       
  4227         if (!ValidClusterNumber(aCluster))
       
  4228             {
       
  4229             __PRINT1(_L("Bad Cluster number %d"),aCluster);
       
  4230             User::Leave(EFatChkDskIllegalClusterNumber);
       
  4231             }
       
  4232 
       
  4233         if (IsClusterVisited(aFatBitVec, aCluster))
       
  4234             {
       
  4235             __PRINT1(_L("Cluster already in use %d"),aCluster);
       
  4236             User::Leave(EFatChkDskClusterAlreadyInUse);
       
  4237             }
       
  4238 
       
  4239         MarkClusterVisited(aFatBitVec, aCluster);
       
  4240 
       
  4241         } while (FAT().GetNextClusterL(aCluster));
       
  4242 
       
  4243     return(i);
       
  4244     }
       
  4245 
       
  4246 //-----------------------------------------------------------------------------------------
       
  4247 
       
  4248 //
       
  4249 // Checks that all unvisited clusters are marked as free in the FAT
       
  4250 //
       
  4251 void  CFatMountCB::CheckUnvisitedClustersL(const RBitVector& aFatBitVec) const
       
  4252     {
       
  4253 
       
  4254     TInt cluster=2;
       
  4255     TInt maxCluster=cluster + UsableClusters();
       
  4256     while (cluster<maxCluster)
       
  4257         {
       
  4258         cluster=NextUnvisitedCluster(aFatBitVec, cluster); //-- move to the next unvisited cluster
       
  4259         if(cluster < 0 || cluster >= maxCluster)
       
  4260             break;
       
  4261 
       
  4262         TInt clusterVal=FAT().ReadL(cluster);
       
  4263         if (clusterVal!=0 && IsEndOfClusterCh(clusterVal)==EFalse && !IsBadCluster(clusterVal))
       
  4264             {
       
  4265             __PRINT1(_L("\n*****Bad cluster Num = %d"),cluster);
       
  4266             User::Leave(EFatChkDskBadCluster);
       
  4267             }
       
  4268         }
       
  4269     }
       
  4270 
       
  4271 //-----------------------------------------------------------------------------------------
       
  4272 
       
  4273 /**
       
  4274 @param  aCluster cluster number to check for validity
       
  4275 @returns ETrue if aCluster is a valid cluster number
       
  4276 */
       
  4277 TBool CFatMountCB::ValidClusterNumber(TUint32 aCluster) const
       
  4278     {
       
  4279     return (aCluster>=KFatFirstSearchCluster && aCluster<=MaxClusterNumber());
       
  4280     }
       
  4281 
       
  4282 //-----------------------------------------------------------------------------------------
       
  4283 
       
  4284 //
       
  4285 // Walk the FAT, returns error if find an unterminated list or
       
  4286 // lists that merge.
       
  4287 //
       
  4288 TInt CFatMountCB::CheckDisk()
       
  4289 	{
       
  4290 
       
  4291     __PRINT1(_L("CFatMountCB::CheckDisk() drv:%d"), DriveNumber());
       
  4292 
       
  4293     if(!ConsistentState())
       
  4294         return KErrCorrupt;
       
  4295 
       
  4296     //-- create a bit representation of the FAT
       
  4297     const TUint32 MaxClusters = UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers
       
  4298 
       
  4299 
       
  4300     // cluster count may be zero if boot sector failed to be read (e.g. if the media is locked)
       
  4301     // or if TDrive::MountMedia(ETrue) has been called (in which case the boot sector may
       
  4302     if (MaxClusters == 0)
       
  4303         return KErrCorrupt;
       
  4304 
       
  4305     RBitVector bitVec; //-- each bit in this vector represents a FAT cluster
       
  4306 
       
  4307     TInt nRes = bitVec.Create(MaxClusters);
       
  4308     if(nRes != KErrNone)
       
  4309         {
       
  4310         ASSERT(nRes == KErrNoMemory); //-- the only one possible reason.
       
  4311         return KErrNoMemory;
       
  4312         }
       
  4313 
       
  4314     iChkDiscRecLevel = 0; //-- reset CheckDisk recursion counter
       
  4315     TRAPD(r,ChkDirL(bitVec, RootIndicator())); // Check from root directory
       
  4316     if (r==KErrNone)
       
  4317         {
       
  4318         TRAP(r,CheckUnvisitedClustersL(bitVec));
       
  4319         }
       
  4320 
       
  4321 
       
  4322     bitVec.Close();
       
  4323 
       
  4324     switch(r)
       
  4325         {
       
  4326 
       
  4327     case KErrNone:
       
  4328         return KErrNone;
       
  4329 
       
  4330     case EFatChkDskIllegalClusterNumber:
       
  4331         return(1);
       
  4332 
       
  4333     case EFatChkDskClusterAlreadyInUse:
       
  4334         return(2);
       
  4335 
       
  4336     case EFatChkDskBadCluster:
       
  4337         return(3);
       
  4338 
       
  4339     case EFatChkDskInvalidEntrySize:
       
  4340         return(4);
       
  4341 
       
  4342     default:
       
  4343         break;
       
  4344         }
       
  4345 
       
  4346     return(r);
       
  4347     }
       
  4348 
       
  4349 
       
  4350 //-----------------------------------------------------------------------------------------
       
  4351 //  Helper functions for Check Disk functionality
       
  4352 //-----------------------------------------------------------------------------------------
       
  4353 
       
  4354 /**
       
  4355     Find the next unvisited cluster number in the bit array.
       
  4356 
       
  4357     @param  aBitList    bit array, where '0' bits represent unvisited clusters.
       
  4358     @param  aCluster    cluster number to start search with.
       
  4359 
       
  4360     @return positive integer indicating next unvisited cluster number
       
  4361             KErrNotFound (-1) if there are no unvisited clusters
       
  4362 
       
  4363 */
       
  4364 static TInt  NextUnvisitedCluster(const RBitVector& aFatBitVec, TUint32 aCluster)
       
  4365 {
       
  4366     __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved
       
  4367 
       
  4368     TUint32 searchPos = aCluster; //-- bit number to start search with
       
  4369 
       
  4370     //-- look for the unvisited cluster (bit '0') in the bit array from the searchPos to the right
       
  4371     if(aFatBitVec.Find(searchPos, 0, RBitVector::ERight))
       
  4372         return searchPos;
       
  4373 
       
  4374     return KErrNotFound;
       
  4375 }
       
  4376 
       
  4377 
       
  4378 /**
       
  4379     Check if we have visited cluster aCluster
       
  4380 
       
  4381     @param  aFatBitVec  bit array, where '0' bits represent unvisited clusters.
       
  4382     @param  aCluster    cluster number to check
       
  4383     @return ETrue if aCluster has been visited.
       
  4384 */
       
  4385 static TBool IsClusterVisited(const RBitVector& aFatBitVec, TUint32 aCluster)
       
  4386 {
       
  4387     __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved
       
  4388 
       
  4389     return aFatBitVec[aCluster];
       
  4390 }
       
  4391 
       
  4392 /**
       
  4393     Mark aCluster as visited
       
  4394     @param  aFatBitVec  bit array, where '0' bits represent unvisited clusters.
       
  4395     @param  aCluster    cluster number to mark
       
  4396 */
       
  4397 static void MarkClusterVisited(RBitVector& aFatBitVec, TUint32 aCluster)
       
  4398 {
       
  4399     __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved
       
  4400 
       
  4401     aFatBitVec.SetBit(aCluster); //-- '1' bit in a bit array means that the corresponding cluster is visited
       
  4402 }
       
  4403 
       
  4404 
       
  4405 
       
  4406 //-------------------------------------------------------------------------------------------------------------------
       
  4407 
       
  4408 /**
       
  4409     Creates a scan drive object and starts the scan.
       
  4410 */
       
  4411 TInt CFatMountCB::DoRunScanDrive()
       
  4412 {
       
  4413     TInt nRes;
       
  4414 
       
  4415     CScanDrive* pScnDrv = NULL;
       
  4416     TRAP(nRes, pScnDrv=CScanDrive::NewL(this));
       
  4417     if(nRes != KErrNone)
       
  4418         return nRes;
       
  4419 
       
  4420     TRAPD(nScnDrvRes, pScnDrv->StartL());
       
  4421 
       
  4422     const TBool bNeedFatRemount = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered();
       
  4423     delete pScnDrv;
       
  4424 
       
  4425 
       
  4426     if(bNeedFatRemount)
       
  4427         {//-- ScanDrive found and probably fixed some errors.
       
  4428         // ensure cached fat and free cluster count are updated
       
  4429         DoDismount(); //-- dismount
       
  4430         TRAP(nRes, MountL(EFalse)); //-- mount again
       
  4431         }
       
  4432 
       
  4433     if(nScnDrvRes != KErrNone)
       
  4434         return nScnDrvRes;
       
  4435 
       
  4436 
       
  4437     //-- if ScanDrive hasn't found anything wrong or has fixed recoverable erros, mark the volume clean
       
  4438     if(VolCleanFlagSupported())
       
  4439         {
       
  4440         //-- if there is a background FAT scanning thread, we need to wait until it finishes its work.
       
  4441         //-- otherwise it's possible to have incorrect amount of free space on the volume until next remounting.
       
  4442         (void)FAT().NumberOfFreeClusters(ETrue);
       
  4443         TRAP(nRes, FinaliseMountL());
       
  4444         ASSERT(nRes == KErrNone);
       
  4445         }
       
  4446 
       
  4447     return KErrNone;
       
  4448 }
       
  4449 
       
  4450 //-------------------------------------------------------------------------------------------------------------------
       
  4451 
       
  4452 /**
       
  4453     Run scan drive on the given volume.
       
  4454     The ScanDrive may be skipped on the finalised volumes, i.e. those, that had been shut down properly.
       
  4455 
       
  4456 
       
  4457     @return Either  KErrCorrupt if an error was found that is not caused by write failure due to power removal.
       
  4458                     KErrNone if no error was found. One of four positive codes explaining what type of error was rectified
       
  4459 */
       
  4460 TInt CFatMountCB::ScanDrive()
       
  4461 {
       
  4462     __PRINT1(_L("CFatMountCB::ScanDrive() starting on drive %d"), DriveNumber());
       
  4463 
       
  4464     if(!ConsistentState())
       
  4465         return KErrCorrupt;
       
  4466 
       
  4467     TInt nRes;
       
  4468 
       
  4469     if(LockStatus()!=0)
       
  4470         {
       
  4471 		__PRINT(_L("CFatMountCB::ScanDrive() locked!\n"));
       
  4472         return KErrInUse;
       
  4473         }
       
  4474 
       
  4475     if(iRamDrive)
       
  4476         {//-- Do not check internal RAM drive
       
  4477         __PRINT(_L("CFatMountCB::ScanDrive() Skipping Internal RAM drive."));
       
  4478         return KErrNone;
       
  4479         }
       
  4480 
       
  4481     //-- check if the volume is finalised and skip running ScanDrive if this option is enabled in estart.txt
       
  4482     if(VolCleanFlagSupported() && FatConfig().ScanDrvSkipFinalisedVolume())
       
  4483         {
       
  4484         TBool bVolClean = EFalse;
       
  4485         TRAP(nRes, bVolClean = VolumeCleanL());
       
  4486 
       
  4487         if(nRes == KErrNone && bVolClean)
       
  4488             {
       
  4489             __PRINT(_L("Skipping ScanDrive on finalised volume!"));
       
  4490             return KErrNone; //-- skip ScanDrive on a clean volume
       
  4491             }
       
  4492         }
       
  4493 
       
  4494     //-- run ScanDrive
       
  4495     nRes = Open();
       
  4496     if(nRes != KErrNone)
       
  4497         return nRes;
       
  4498 
       
  4499     nRes = DoRunScanDrive();
       
  4500 
       
  4501     Close();
       
  4502 
       
  4503     __PRINT2(_L("~ CFatMountCB::ScanDrive() finished for drive %d with the code %d"),DriveNumber(), nRes);
       
  4504 
       
  4505     return nRes;
       
  4506 
       
  4507 }
       
  4508 
       
  4509 //-----------------------------------------------------------------------------------------
       
  4510 /**
       
  4511 Returns the offset between UTC time and timestamps on the filesystem. This will return User::UTCOffset
       
  4512 if the flag iUseLocalTime has been set in CFatFileSystem and this mount is on a removable drive. If not
       
  4513 a null offset is returned.
       
  4514 
       
  4515 @return The offset in seconds that timestamps on the filesystem have, relative to UTC.
       
  4516 */
       
  4517 TTimeIntervalSeconds CFatMountCB::TimeOffset() const
       
  4518 	{
       
  4519     if((Drive().Att() & KDriveAttRemovable) && FatFileSystem().GetUseLocalTime() )
       
  4520 	    {
       
  4521         return User::UTCOffset();
       
  4522         }
       
  4523 	else
       
  4524         {
       
  4525         return TTimeIntervalSeconds(0);
       
  4526         }
       
  4527 	}
       
  4528 
       
  4529 
       
  4530 
       
  4531 
       
  4532 //-----------------------------------------------------------------------------------------
       
  4533 /** 
       
  4534     Check is this file system can be mounted on the drive at all.
       
  4535     Just read and validate boot region, no real mounting overhead. 
       
  4536     
       
  4537     @return KErrNone    boot region is OK, the file system can be mounted.
       
  4538             KErrLocked  the media is locked on a physical level.
       
  4539             other error codes depending on the implementation
       
  4540 
       
  4541 */
       
  4542 TInt CFatMountCB::MntCtl_DoCheckFileSystemMountable()
       
  4543     {
       
  4544     TInt nRes;
       
  4545     
       
  4546     const TInt driveNo = Drive().DriveNumber();
       
  4547     __PRINT1(_L("CFatMountCB::MntCtl_DoCheckFileSystemMountable() drv:%d"),driveNo);
       
  4548 
       
  4549     nRes = CreateDrive(driveNo);
       
  4550     if(nRes != KErrNone)
       
  4551         {
       
  4552         __PRINT1(_L(" ..CreateDrive() err:%d \n"), nRes);    
       
  4553         return nRes;
       
  4554         }
       
  4555 
       
  4556     //-- try reading boot sector. This doesn't require iDriverInterface setup, it uses LocalDrive()
       
  4557     TFatBootSector bootSector;
       
  4558     nRes = ReadBootSector(bootSector);
       
  4559 
       
  4560     DismountedLocalDrive();
       
  4561 
       
  4562     return nRes;
       
  4563     }
       
  4564 
       
  4565 
       
  4566