os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_mnt32.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 // f32\sfat32\sl_mnt32.cpp
    15 // CFatMountCB code, specific to the EFAT32.FSY
    16 // 
    17 //
    18 
    19 /**
    20  @file 
    21 */
    22 
    23 #include "sl_std.h"
    24 #include "sl_cache.h"
    25 #include "sl_leafdir_cache.h"
    26 
    27 //-------------------------------------------------------------------------------------------------------------------
    28 
    29 
    30 /**
    31     Write aligned members of TFatBootSector to media
    32  
    33     @param  aMediaPos   media position the data will be written to
    34     @param  aBootSector data to write
    35     @return Media write error code
    36 */
    37 TInt CFatMountCB::DoWriteBootSector(TInt64 aMediaPos, const TFatBootSector& aBootSector)  const
    38     {
    39     __PRINT2(_L("#- CFatMountCB::DoWriteBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);   
    40 
    41     ASSERT(aMediaPos>=0);
    42 
    43     TBuf8<KDefaultSectorSize> bootSecBuf(KDefaultSectorSize);
    44     bootSecBuf.FillZ();
    45 
    46     //-- externalize boot sector to the data buffer
    47     aBootSector.Externalize(bootSecBuf);
    48 
    49     //-- put a boot sector signature to the last 2 bytes
    50     bootSecBuf[KDefaultSectorSize-2] = 0x55;
    51     bootSecBuf[KDefaultSectorSize-1] = 0xaa;
    52 
    53     //-- write boot sector to the media
    54     TInt r=LocalDrive()->Write(aMediaPos, bootSecBuf);
    55     if (r!=KErrNone)
    56         {//-- write failure
    57         __PRINT2(_L("CFatMountCB::DoWriteBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
    58         }
    59 
    60     return r;
    61     }
    62 
    63 //-------------------------------------------------------------------------------------------------------------------
    64 
    65 /**
    66     Read non aligned boot data from media into TFatBootSector structure
    67 
    68     @param  aMediaPos   media position the data will be read from
    69     @param  aBootSector refrence to TFatBootSector populate
    70     @return Media read error code
    71 */
    72 TInt CFatMountCB::DoReadBootSector(TInt64 aMediaPos, TFatBootSector& aBootSector)  const
    73     {
    74     __PRINT2(_L("#- CFatMountCB::DoReadBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);   
    75 
    76     ASSERT(aMediaPos>=0);
    77 
    78     TBuf8<KSizeOfFatBootSector> bootSecBuf(KSizeOfFatBootSector);
    79     
    80     //-- read boot sector from the media
    81     TInt r=LocalDrive()->Read(aMediaPos, KSizeOfFatBootSector, bootSecBuf);
    82     
    83     if (r != KErrNone)
    84         {
    85         __PRINT2(_L("CFatMountCB::DoReadBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
    86 
    87 	    //-- fiddling with the error code; taken from MountL()
    88         if (r==KErrNotSupported)
    89 		    return KErrNotReady;
    90     #if defined(_LOCKABLE_MEDIA)
    91 	    else if(r==KErrLocked)
    92 		    return KErrLocked;
    93     #endif
    94 	    else if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown)
    95                 return KErrCorrupt; 
    96 
    97         return r;
    98         }
    99 
   100     ASSERT(r==KErrNone);
   101 
   102     //-- initialise TFatBootSector object
   103     aBootSector.Internalize(bootSecBuf);
   104 
   105     //-- Validate the partition size, and fix up if the out of bounds
   106     TLocalDriveCapsV2Buf localDriveCaps;
   107     r = LocalDrive()->Caps(localDriveCaps);
   108     if (r != KErrNone)
   109         {
   110         //-- fiddling with the error code; taken from MountL()
   111         if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown)
   112             return KErrCorrupt;
   113         else
   114             return r;
   115         }
   116 
   117     if(!(localDriveCaps().iMediaAtt & KMediaAttVariableSize))
   118         {//-- this is not a RAM drive.
   119         const TUint32 maxSectors = I64LOW(localDriveCaps().iSize >> KDefSectorSzLog2);
   120 
   121         if(aBootSector.TotalSectors())
   122             aBootSector.SetTotalSectors(Min(aBootSector.TotalSectors(), maxSectors));
   123         else
   124             aBootSector.SetHugeSectors(Min(aBootSector.HugeSectors(), maxSectors));
   125         }
   126 
   127     return KErrNone;
   128     }
   129 
   130 //-------------------------------------------------------------------------------------------------------------------
   131 
   132 /**
   133     Read and validate the boot sector.
   134     If there is an error in reading the main boot sector (sec:0) or it is invalid, tries to read backup boot sector from sec:6.
   135     Flag iMainBootSecValid indicates the validity of the main boot sector. if it is false, but ret. value is KErrNone, it means that
   136     the backup boot sector was used and it is valid.
   137 
   138     @param      aBootSector reference to the boot sector object to be read.
   139     @param      aDoNotReadBkBootSec if true, there won't be an attempt to read backup sector
   140     @return     standard error code.
   141 
   142 */
   143 TInt CFatMountCB::ReadBootSector(TFatBootSector& aBootSector, TBool aDoNotReadBkBootSec/*=EFalse*/)
   144     {
   145     iMainBootSecValid = EFalse; 
   146 
   147     //-- read main boot sector from the sector 0
   148     TInt nRes = DoReadBootSector(KBootSectorNum << KDefSectorSzLog2, aBootSector); 
   149     if(nRes == KErrNone)
   150         {
   151         if(aBootSector.IsValid())
   152             {
   153             iMainBootSecValid = ETrue; //-- main boot sector is valid, everything is OK
   154             return KErrNone;
   155             }
   156         else
   157             {
   158             __PRINT(_L("MainBoot Sector is invalid! dump:\n"));
   159             aBootSector.PrintDebugInfo();
   160             nRes = KErrCorrupt;
   161             }
   162         }
   163 
   164     ASSERT(nRes!= KErrNone && !iMainBootSecValid);
   165 
   166     if(aDoNotReadBkBootSec)
   167         return nRes;
   168 
   169     //-- main boot sector is invalid, try backup one (it might not present at all) 
   170     __PRINT(_L("Using backup boot sector...\n"));
   171     nRes=DoReadBootSector(KBkBootSectorNum << KDefSectorSzLog2, aBootSector); 
   172     if(nRes == KErrNone )
   173         {
   174         if(aBootSector.IsValid())
   175             return KErrNone; //-- main boot sector is bad, but backup one is OK
   176         else
   177             {//-- backup boot sector is invalid
   178             __PRINT(_L("Backup Sector is invalid! dump:\n"));    
   179             aBootSector.PrintDebugInfo();
   180             nRes = KErrCorrupt;
   181             }
   182         }
   183     
   184     //-- can't read boot sectors, or both are invalid
   185     return nRes;
   186     }
   187 
   188 //-------------------------------------------------------------------------------------------------------------------
   189 
   190 /**
   191 Write a new volume label to BPB in media
   192 
   193 @param aVolumeLabel Descriptor containing the new volume label
   194 @leave 
   195 */
   196 void CFatMountCB::WriteVolumeLabelL(const TDesC8& aVolumeLabel) const
   197     {
   198     if(aVolumeLabel.Length() > KVolumeLabelSize)
   199         User::Leave(KErrArgument);
   200 
   201     const TUint32 posVolLabel = Is32BitFat() ? KFat32VolumeLabelPos : KFat16VolumeLabelPos;
   202     User::LeaveIfError(LocalDrive()->Write(posVolLabel, aVolumeLabel)); 
   203     
   204     }
   205 
   206 
   207 //-------------------------------------------------------------------------------------------------------------------
   208 
   209 const TUint32 KFat32CleanShutDownMask	= 0x08000000; ///< Mask used to indicate test clean/dirty bit for Fat32
   210 const TUint16 KFat16CleanShutDownMask	= 0x08000;    ///< Mask used to indicate test clean/dirty bit for Fat16
   211 
   212 /**
   213 Set or reset "VolumeClean" (ClnShutBitmask) flag.
   214 
   215 @param  aClean if ETrue, marks the volume as clean, otherwise as dirty.
   216 @leave  if write error occured.        
   217 */
   218 void CFatMountCB::SetVolumeCleanL(TBool aClean) 
   219     {
   220 
   221 	//-- The volume can't be set clean if there are objects opened on it. This precondition must be checked before calling this function
   222     if(aClean && LockStatus()!=0)
   223         {
   224         __PRINT1(_L("#- CFatMountCB::SetVolumeCleanL drive:%d isn't free!"),DriveNumber());
   225         ASSERT(0);
   226         User::Leave(KErrInUse);
   227         return;
   228         }
   229     
   230     if(FatType() == EFat12)
   231         {//-- Fat12 doesn't support this feature; do nothing other than notify the underlying drive (ignoring any error for now as there's nothing we can do with it)
   232 		(void)LocalDrive()->Finalise(aClean);
   233         return;
   234         }
   235 
   236     //-- further read and write will be directly from the CProxyDrive, bypassing FAT cache. 
   237     //-- this is because CFatTable doesn't allow access to FAT[0] & FAT[1]
   238     //-- We also need to write data through CProxyDrive, because TDriveInterface has a call back that can call this method
   239 
   240     if(Is32BitFat())
   241         {//-- Fat32
   242 		__PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT32"),DriveNumber(), aClean);
   243 		
   244         TFat32Entry fatEntry;
   245         const TInt  KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
   246         TPtr8       ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize);
   247         
   248         User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT32[1] entry
   249 
   250         const TFat32Entry tmp = fatEntry;
   251         
   252         if(aClean)
   253             fatEntry |= KFat32CleanShutDownMask;  //-- set ClnShutBit flag
   254         else
   255             fatEntry &= ~KFat32CleanShutDownMask; //-- reset ClnShutBit flag
   256 
   257         if(tmp != fatEntry)
   258             {//-- write FAT[1] entry to all available FATs
   259                 for(TInt i=0; i<NumberOfFats(); ++i)
   260                 {
   261                 const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i);
   262                 User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT32[1] entry
   263                 }
   264             }
   265 
   266         __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry:  %x->%x"), tmp, fatEntry);
   267         }
   268     else 
   269     if(Is16BitFat())
   270         {//-- Fat16. 
   271             __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT16"),DriveNumber(), aClean);
   272 
   273             if(FatConfig().FAT16_UseCleanShutDownBit())
   274                 {
   275             TFat16Entry fatEntry;
   276             const TInt  KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
   277             TPtr8       ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize);
   278         
   279             User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry
   280 
   281             const TFat16Entry tmp = fatEntry;
   282         
   283             if(aClean)
   284                 fatEntry |= KFat16CleanShutDownMask;  //-- set ClnShutBit flag
   285             else
   286                 fatEntry &= ~KFat16CleanShutDownMask; //-- reset ClnShutBit flag
   287 
   288             if(tmp != fatEntry)
   289                 {//-- write FAT[1] entry to all available FATs
   290                 for(TInt i=0; i<NumberOfFats(); ++i)
   291                     {
   292                     const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i);
   293                     User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT16[1] entry
   294                     }
   295                 }
   296 		    
   297             __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry:  %x->%x"), tmp, fatEntry);    
   298             }
   299             else
   300             {
   301             __PRINT(_L("#- changing FAT16[1] is disabled in config!"));    
   302             }
   303         }
   304     else
   305         {//-- must never get here
   306         ASSERT(0);
   307         }
   308     
   309 		//-- Notify the underlying media that the mount is consistent  (ignoring any error for now as there's nothing we can do with it)
   310 		(void)LocalDrive()->Finalise(aClean);
   311 
   312 
   313     }
   314 
   315 //-------------------------------------------------------------------------------------------------------------------
   316 
   317 /**
   318 Determine whether "VolumeClean" (ClnShutBitmask) flag is set.
   319 
   320 @return ETrue if the volume is marked as clean and EFalse otherwise.
   321 @leave  if is called for FAT12 or if read error occured.
   322 */
   323 TBool CFatMountCB::VolumeCleanL() 
   324     {
   325 
   326     //-- read access to the FAT is through TDriveInterface, because CFatTable doesn't allow access to FAT[1]
   327     TDriveInterface& drive =DriveInterface();
   328 
   329     if(Is32BitFat())
   330         {//-- Fat32
   331         TFat32Entry fatEntry;
   332         const TInt  KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
   333         TPtr8       ptrFatEntry((TUint8*)&fatEntry, KFatEntrySize);
   334         
   335         User::LeaveIfError(drive.ReadNonCritical(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT32[1] entry
   336         return (fatEntry & KFat32CleanShutDownMask);
   337         }
   338     else 
   339     if(Is16BitFat())
   340         {//-- Fat16
   341         TFat16Entry fatEntry;
   342         const TInt  KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
   343         TPtr8       ptrFatEntry((TUint8*)&fatEntry, KFatEntrySize);
   344         
   345         User::LeaveIfError(drive.ReadNonCritical(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry
   346         return (fatEntry & KFat16CleanShutDownMask);
   347         }
   348     else
   349         {//-- Fat12 doesn't support this feature, shan't get here, actually
   350         ASSERT(0);
   351         User::Leave(KErrNotSupported);
   352         return ETrue; //-- to satisfy the compiler
   353         }
   354     }
   355 
   356 
   357 //-------------------------------------------------------------------------------------------------------------------
   358 
   359 /**
   360 Mount a Fat volume. 
   361 
   362 @param aForceMount Flag to indicate whether mount should be forced to succeed if an error occurs
   363 @leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
   364 */
   365 void CFatMountCB::MountL(TBool aForceMount)
   366 	{
   367 
   368     const TInt driveNo = Drive().DriveNumber();
   369     
   370     __PRINT2(_L("CFatMountCB::MountL() drv:%d, forceMount=%d\n"),driveNo,aForceMount);
   371 
   372     ASSERT(State() == ENotMounted || State() == EDismounted);
   373     SetState(EMounting);
   374     SetReadOnly(EFalse);
   375    
   376 	User::LeaveIfError(CreateDrive(driveNo));
   377 
   378 
   379     //-- read FAT configuration parameters from estart.txt
   380     iFatConfig.ReadConfig(driveNo);
   381 
   382     //-- initialise interface to the low-level drive access
   383     if(!iDriverInterface.Init(this))
   384         User::LeaveIfError(KErrNoMemory);    
   385 
   386 	//-- get drive capabilities
   387     TLocalDriveCapsV2Buf capsBuf;
   388 	User::LeaveIfError(LocalDrive()->Caps(capsBuf));
   389 	
   390 
   391     iSize=capsBuf().iSize;
   392     iRamDrive = EFalse;
   393 
   394     if(capsBuf().iMediaAtt & KMediaAttVariableSize)
   395     {//-- this is a RAM drive
   396         UserSvr::UnlockRamDrive();
   397         iRamDrive = ETrue;
   398     }
   399 
   400 	if(aForceMount)
   401 	{//-- the state is "forcedly mounted", special case. This is an inconsistent state.
   402         SetState(EInit_Forced);  
   403     	return;
   404     }
   405 
   406     //-- read boot sector. If main is damaged, try to use backup one instead if this is not a RAM drive.
   407     TFatBootSector bootSector;
   408     User::LeaveIfError(ReadBootSector(bootSector, iRamDrive));
   409 
   410 
   411     //-- print out boot sector debug information
   412     bootSector.PrintDebugInfo();
   413 
   414     //-- determine FAT type by data from boot sector. This is done by counting number of clusters, not by BPB_RootEntCnt
   415     SetFatType(bootSector.FatType());
   416     ASSERT(iFatType != EInvalid); //-- this shall be checked in ReadBootSector()
   417     
   418 
   419     if(bootSector.RootDirEntries() == 0 && !Is32BitFat())
   420     {//-- FAT types mismatch. BPB_RootEntCnt is 0, which can be only for FAT32, but the number of clusters is less 
   421      //-- than required for FAT32. Probably this is incorrectly FAT32 formatted media. Put the drive into ReadOnly mode, assuming
   422      //-- that is FAT32.
   423         __PRINT(_L("FAT type mismatch! Setting drive to ReadOnly mode for FAT32. \n"));
   424         SetFatType(EFat32); //-- force FAT type to be FAT32
   425         SetReadOnly(ETrue);
   426     }
   427 
   428     //-- store volume UID, it can be checked on Remount
   429     iUniqueID = bootSector.UniqueID();
   430 
   431     //-- populate volume parameters with the values from boot sector. They had been validated in TFatBootSector::IsValid()
   432     iVolParam.Populate(bootSector); 
   433 	
   434     //-- initialize the volume
   435     InitializeL(capsBuf());
   436     ASSERT(State()==EInit_R);
   437 
   438     GetVolumeLabelFromDiskL(bootSector);
   439 
   440 	__PRINT2(_L("CFatMountCB::MountL() Completed, drv: %d, state:%d"), DriveNumber(), State());
   441 	}
   442 
   443 
   444 
   445 //-------------------------------------------------------------------------------------------------------------------
   446 
   447 /**
   448 Initialize the FAT cache and disk access
   449 
   450 @param  aLocDrvCaps local drive capabilities
   451 @param  aIgnoreFSInfo if ETrue, FSInfo sector shall be ignored. Used on volume remount to force FAT free clusters counting.
   452 
   453 @leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
   454 */
   455 void CFatMountCB::InitializeL(const TLocalDriveCaps& aLocDrvCaps, TBool aIgnoreFSInfo/*=EFalse*/) 
   456 	{
   457     __PRINT1(_L("CFatMountCB::InitializeL() drv:%d"), DriveNumber());
   458 
   459     ASSERT(State() == EMounting); //-- we must get here only from MountL()
   460    
   461     //========== Find out number of clusters on the volume
   462 	if(iRamDrive && SectorsPerCluster()!=1)
   463 		{// Align iFirstFreeByte to cluster boundary if internal ram drive
   464 		const TInt sectorsPerClusterLog2=ClusterSizeLog2()-SectorSizeLog2();
   465 		const TInt rootDirEndSector=RootDirEnd()>>SectorSizeLog2();
   466 		const TInt alignedSector=((rootDirEndSector+SectorsPerCluster()-1)>>sectorsPerClusterLog2)<<sectorsPerClusterLog2;
   467 		iFirstFreeByte=alignedSector<<SectorSizeLog2();
   468 		}
   469 	else
   470 		{
   471 		if(Is32BitFat())
   472 			iFirstFreeByte=(NumberOfFats() * FatSizeInBytes()) + (FirstFatSector() << SectorSizeLog2());
   473 		else
   474 			iFirstFreeByte=RootDirEnd();
   475 		}
   476 
   477 
   478 	    {//-- check if volume geometry looks valid
   479         const TInt usableSectors=TotalSectors()-(iFirstFreeByte>>SectorSizeLog2());
   480 	    iUsableClusters=usableSectors>>(ClusterSizeLog2()-SectorSizeLog2());
   481 
   482         const TUint32 KMinClusters = 32; //-- absolute minimum number of clusters on the volume
   483         const TUint32 KMaxClusters=(TotalSectors()-FirstFatSector()-NumberOfFats()*(FatSizeInBytes()>>SectorSizeLog2())) >> (ClusterSizeLog2()-SectorSizeLog2());
   484         
   485         if(usableSectors <=0 || iUsableClusters < KMinClusters || iUsableClusters > KMaxClusters)
   486             {
   487             __PRINT(_L("CFatMountCB::InitializeL() Wrong number of usable cluster/sectors on the volume!"));
   488             User::Leave(KErrCorrupt);
   489             }
   490         }
   491 
   492 	//========== initialise RawDisk interface
   493 	//-- CFatMountCB parameters might have changed, e.g. after formatting. Reconstruct directory cache with new parameters
   494 	
   495     delete iRawDisk;
   496 	iRawDisk=CRawDisk::NewL(*this, aLocDrvCaps);
   497     iRawDisk->InitializeL();
   498 
   499 
   500     //========== Try to read FSInfo and deduct number of free clusters and other information from there
   501     TBool   bUseDataFromFsInfo = !aIgnoreFSInfo && Is32BitFat(); //-- if ETrue, we are going to use data from FSInfo sector (applicable for FAT32 only)
   502     
   503     //-- main boot sector shall be valid, otherwise we can't trust data from FSInfo
   504     bUseDataFromFsInfo = bUseDataFromFsInfo && iMainBootSecValid;
   505 
   506     //-- 1. check if using FSInfo is disabled in config
   507     if(bUseDataFromFsInfo && !FatConfig().FAT32_UseFSInfoOnMount())
   508     {
   509         __PRINT(_L("#- FSInfo using is disabled in config!"));
   510         bUseDataFromFsInfo = EFalse;
   511     }
   512 
   513 #ifdef  _DEBUG
   514     //-- 2. check if FSInfo is disabled by test interface (special debug property). This property is defined and set by the test application.
   515     TInt nMntDebugFlags;
   516     if(bUseDataFromFsInfo && RProperty::Get(KSID_Test1, DriveNumber(), nMntDebugFlags) == KErrNone)
   517         {//-- test property for this drive is defined
   518             if(nMntDebugFlags & KMntDisable_FsInfo)
   519             {
   520             __PRINT(_L("#- FSInfo using is disabled by debug interface."));
   521             bUseDataFromFsInfo = EFalse;
   522             }
   523         }
   524 #endif
   525 
   526     //-- 3. try to read FSInfoSector and its copy if the volume had been properly shut down before (is now clean) 
   527     CFatTable::TMountParams fatMntParams;
   528     bUseDataFromFsInfo = bUseDataFromFsInfo && VolumeCleanL();
   529     if(bUseDataFromFsInfo)
   530         {
   531         bUseDataFromFsInfo = ProcessFSInfoSectors(fatMntParams);
   532         if(!bUseDataFromFsInfo)
   533             { 
   534             __PRINT1(_L("#- CFatMountCB::ProcessFSInfoSectors() failed. drv:%d"), DriveNumber());
   535             }
   536         }
   537 
   538     //========== create and initialise FAT table 
   539 	
   540     delete iFatTable;
   541     iFatTable=CFatTable::NewL(*this, aLocDrvCaps);
   542 
   543     //-- mount the FAT table. Depending on mount parameters and configuration this method 
   544     //-- can do various things, like counting free clusters synchronously if data from FSInfo isn't valid, 
   545     //-- or setting up a FAT backround thread and return immediately etc.
   546     iFatTable->MountL(fatMntParams);
   547    
   548     SetState(EInit_R);  //-- the state is "Initialized, but not writen"
   549 
   550     //-- make a callback, telling FileServer about free space discovered.
   551     const TInt64 freeSpace = ((TInt64)FAT().NumberOfFreeClusters()) << ClusterSizeLog2();
   552     SetDiskSpaceChange(freeSpace);
   553     //========== create and setup leaf direcotry cache if cache limit is set bigger than one 
   554 
   555 	const TUint32 cacheLimit = iFatConfig.LeafDirCacheSize();
   556 	if (cacheLimit > 1)
   557 		{
   558 		// destroy the old leaf dir cache to avoid memory leak.
   559 		delete iLeafDirCache;
   560 		iLeafDirCache = CLeafDirCache::NewL(cacheLimit);
   561 		}
   562 	else
   563 		{
   564 		iLeafDirCache = NULL;
   565 		}
   566     
   567     __PRINT3(_L("#- CFatMountCB::InitializeL() done. drv:%d, Free clusters:%d, 1st Free cluster:%d"),DriveNumber(), FAT().NumberOfFreeClusters(), FAT().FreeClusterHint());
   568 
   569     
   570 	}
   571 
   572 //-------------------------------------------------------------------------------------------------------------------
   573 
   574 /**
   575     Write FSInfo sectors to the media
   576 
   577     @param aMediaPos    Media position to write FSInfo sector to
   578     @param aFSInfo      FSInfo structure to write
   579     @return System wide error code
   580 */
   581 TInt CFatMountCB::WriteFSInfoSector(TInt64 aMediaPos, const TFSInfo& aFSInfo)  const
   582     {
   583     __PRINT2(_L("#- CFatMountCB::WriteFSInfoSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);   
   584 
   585     ASSERT(aMediaPos >= 0 && aMediaPos < FirstFatSector()<<SectorSizeLog2());
   586     ASSERT(Is32BitFat());
   587 
   588     TBuf8<KSizeOfFSInfo> fsInfoSecBuf;
   589 
   590     //-- put data to the sector buffer
   591     aFSInfo.Externalize(fsInfoSecBuf);
   592 
   593 	TInt r=LocalDrive()->Write(aMediaPos, fsInfoSecBuf);
   594 	if (r!=KErrNone)
   595         {
   596         __PRINT2(_L("CFatMountCB::WriteFSInfoSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
   597         }
   598 
   599     return r;
   600     }
   601 
   602 //-------------------------------------------------------------------------------------------------------------------
   603 /**
   604     Read the FSInfo structure from media 
   605 
   606     @param aMediaPos    Media position to read FSInfo sector from
   607     @param aFSInfo      data read from FSInfo structure
   608     @return System wide error code
   609 */
   610 TInt CFatMountCB::ReadFSInfoSector(TInt64 aMediaPos, TFSInfo& aFSInfo)  const
   611     {
   612     __PRINT2(_L("#- CFatMountCB::ReadFSInfoSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);   
   613 
   614     ASSERT(aMediaPos >= 0 && aMediaPos < FirstFatSector()<<SectorSizeLog2());
   615     ASSERT(Is32BitFat());
   616 
   617     TBuf8<KSizeOfFSInfo> fsInfoSecBuf;
   618 
   619     TInt r=LocalDrive()->Read(aMediaPos, KSizeOfFSInfo, fsInfoSecBuf); 
   620 	if (r!=KErrNone)
   621 	{
   622 		__PRINT2(_L("CFatMountCB::ReadFSInfoSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
   623 	    return r;
   624 	}
   625 
   626     //-- take FSInfo data from the buffer
   627     aFSInfo.Internalize(fsInfoSecBuf);
   628     
   629     return KErrNone;
   630     }
   631 
   632 
   633 /**
   634     Initialize data to represent the root directory
   635 
   636     @param anEntry Entry to initialise
   637 */
   638 void CFatMountCB::InitializeRootEntry(TFatDirEntry& anEntry) const
   639 	{
   640 	anEntry.SetName(_L8("ROOT"));
   641 	anEntry.SetAttributes(KEntryAttDir);
   642 	anEntry.SetStartCluster(RootClusterNum()); //--iRootClusterNum is 0 for FAT12/16
   643 	}
   644 
   645 
   646 
   647 /**
   648     Implementation of CMountCB::FileSystemSubType(). Retrieves the sub type of Fat file system
   649     and returns the name as a descriptor.
   650 
   651     @param aName Name of the sub type of Fat file system
   652     @return KErrNone if successful; KErrArgument if aName is not long enough; KErrNotReady if
   653 		    the mount is not ready.
   654 
   655     @see CMountCB::FileSystemSubType()
   656 */
   657 TInt CFatMountCB::SubType(TDes& aName) const
   658 	{
   659 	if(aName.MaxLength() < 5)
   660 		return KErrArgument;
   661 	
   662 	switch (FatType())
   663 		{
   664 		case EFat12:
   665 			{
   666 			aName = KFSSubType_FAT12;
   667 			return KErrNone;
   668 			}
   669 		case EFat16:
   670 			{
   671 			aName = KFSSubType_FAT16;
   672 			return KErrNone;
   673 			}
   674 		case EFat32:
   675 			{
   676 			aName = KFSSubType_FAT32;
   677 			return KErrNone;
   678 			}
   679 		default:
   680 		// case EInvalidFatType
   681 			return KErrNotReady;
   682 		}
   683 	}
   684 
   685 
   686 //-------------------------------------------------------------------------------------------------------------------
   687 
   688 /**
   689     Try to extract useful information from the FSInfo sectors.
   690     The information from FSInfo sectors will be trusted only if there are main and backup sectors,
   691     they are both valid and the same.
   692 
   693     @param  aFatInitParams  on success will contain the number of free clusters on the volume and 1st free cluster number from the FSInfo 
   694     @return ETrue on success.
   695 */
   696 TBool CFatMountCB::ProcessFSInfoSectors(CFatTable::TMountParams& aFatInitParams) const
   697     {
   698 
   699     aFatInitParams.iFreeClusters = 0;
   700     aFatInitParams.iFirstFreeCluster = 0;
   701     aFatInitParams.iFsInfoValid = EFalse;
   702 
   703     const TUint32 currFsInfoSec   = iVolParam.FSInfoSectorNum();    //-- values from the boot sector
   704     const TUint32 currFsInfoBkSec = iVolParam.BkFSInfoSectorNum();                                                                              
   705 
   706     if(!Is32BitFat() || currFsInfoSec < KFSInfoSectorNum || currFsInfoSec >= FirstFatSector())
   707         {
   708         ASSERT(0);  //-- main FSInfo sector must have sensible location
   709         return EFalse;
   710         }
   711 
   712     if(currFsInfoBkSec < KFSInfoSectorNum || currFsInfoBkSec >= FirstFatSector() || currFsInfoBkSec <= currFsInfoSec)
   713         return EFalse; //-- something is wrong with backup copy location
   714 
   715     TFSInfo fsInfo;
   716 	TInt    nRes;
   717 
   718     //-- 1. read and validate main FS Info sector
   719     nRes = ReadFSInfoSector(currFsInfoSec << SectorSizeLog2(), fsInfo);
   720     if(nRes != KErrNone)
   721         return EFalse;
   722 
   723     fsInfo.PrintDebugInfo();
   724 
   725     if(!fsInfo.IsValid())
   726         return EFalse;
   727 
   728     const TUint32 freeCount=fsInfo.FreeClusterCount(); // last known free cluster count
   729 	const TUint32 nextFree =fsInfo.NextFreeCluster();  // hint to file system as to where to start looking for free clusters
   730 
   731     //-- 2. read and check backup FS Info sector, it must be the same as the main one
   732     nRes = ReadFSInfoSector(currFsInfoBkSec << SectorSizeLog2(), fsInfo);
   733     
   734     if(nRes != KErrNone || !fsInfo.IsValid() || freeCount != fsInfo.FreeClusterCount() || nextFree != fsInfo.NextFreeCluster())
   735     {
   736         __PRINT(_L("#- CFatMountCB::ProcessFSInfoSectors(): copies of FSInfo are different!"));
   737         return EFalse;
   738     }
   739 
   740     if(freeCount < 1 || freeCount > UsableClusters())
   741         return EFalse; //-- looks like invalid value
   742     
   743     if(nextFree < KFatFirstSearchCluster || nextFree >= UsableClusters()+KFatFirstSearchCluster)
   744         return EFalse; //-- looks like invalid value
   745 
   746     //-- success
   747     aFatInitParams.iFreeClusters = freeCount;
   748     aFatInitParams.iFirstFreeCluster = nextFree;
   749     aFatInitParams.iFsInfoValid = ETrue;
   750     
   751     return ETrue;
   752     }
   753 
   754 //-------------------------------------------------------------------------------------------------------------------
   755 /**
   756     Internal helper method. Writes FSInfo sector and its backup copy to the volume if necessary. 
   757     
   758     @param  aInvalidateFSInfo if ETrue, FSInfo data (free clusters count) will be invalidated.
   759                               otherwise, data from the CFatTable object will be used
   760                                     
   761     @leave  if disk opertion fails
   762 */
   763 void CFatMountCB::DoUpdateFSInfoSectorsL(TBool aInvalidateFSInfo)
   764     {
   765     __PRINT2(_L("#- CFatMountCB::DoUpdateFSInfoSectorsL(%d) drv:%d"),aInvalidateFSInfo, Drive().DriveNumber());
   766     
   767     ASSERT(Is32BitFat());
   768     
   769     if(!aInvalidateFSInfo)
   770         {
   771         ASSERT(FAT().ConsistentState());
   772         }
   773         
   774     //-- 1. check that FSInfoSector numbers are valid
   775     TBool bCanWriteFSInfo_Main = EFalse;//-- if ETrue, it's OK to write main FSInfo sector
   776     TBool bCanWriteFSInfo_Bk = EFalse;  //-- if ETrue, it's OK to write backup FSInfo sector
   777 
   778     const TUint32 currFsInfoSec   = iVolParam.FSInfoSectorNum();    //-- values from the boot sector
   779     const TUint32 currFsInfoBkSec = iVolParam.BkFSInfoSectorNum();
   780         
   781     if(currFsInfoSec > 0 && currFsInfoSec < FirstFatSector())
   782         {//-- seems to be OK
   783         bCanWriteFSInfo_Main = ETrue;
   784         }
   785     else
   786         {
   787         __PRINT1(_L("#- DoUpdateFSInfoSectorsL() iFSInfoSectorNum is wrong!: sec:%d"), currFsInfoSec);
   788         }
   789 
   790     if(currFsInfoBkSec > 0 && currFsInfoBkSec < FirstFatSector() && currFsInfoBkSec > currFsInfoSec)
   791         {//-- seems to be OK
   792         bCanWriteFSInfo_Bk = bCanWriteFSInfo_Main;
   793         }
   794     else
   795         {
   796         __PRINT1(_L("#- DoUpdateFSInfoSectorsL() iBkFSInfoSectorNum is wrong!: sec:%d"),currFsInfoBkSec);
   797         }
   798 
   799     if(!bCanWriteFSInfo_Main && !bCanWriteFSInfo_Bk)
   800         return; //-- nothing to do
   801 
   802     
   803     const TUint32 KFsInfoSecPos_Main = currFsInfoSec   << SectorSizeLog2();  //-- main FSInfo sector media position
   804     const TUint32 KFsInfoSecPos_Bk   = currFsInfoBkSec << SectorSizeLog2();  //-- backup FSInfo sector media position
   805     
   806     TFSInfo fsInfoSector;
   807 
   808     TBool bNeedWriteFSInfo_Main = EFalse;
   809     TBool bNeedWriteFSInfo_Bk = EFalse;
   810 
   811     
   812     const TUint32 KInvalidVal = 0xFFFFFFFF; //-- invalid value for FSInfo fields, see FAT specs
   813     
   814     //-- we need here _exact_ number of free clusters, so make FAT().NumberOfFreeClusters() operation synchronous
   815     const TUint32 KFreeClusters    = aInvalidateFSInfo ? KInvalidVal : FAT().NumberOfFreeClusters(ETrue); 
   816     const TUint32 KNextFreeCluster = aInvalidateFSInfo ? KInvalidVal : FAT().FreeClusterHint(); 
   817     
   818     //-- check if the main FSInfo sector differs from the FAT information
   819     if(bCanWriteFSInfo_Main)
   820         {
   821         User::LeaveIfError(ReadFSInfoSector(KFsInfoSecPos_Main, fsInfoSector));
   822         bNeedWriteFSInfo_Main = !fsInfoSector.IsValid() ||
   823                                 fsInfoSector.FreeClusterCount() != KFreeClusters || 
   824                                 fsInfoSector.NextFreeCluster()  != KNextFreeCluster; 
   825         }
   826 
   827     //-- check if the backup FSInfo sector differs from the FAT information
   828     if(bCanWriteFSInfo_Bk)
   829         {
   830         User::LeaveIfError(ReadFSInfoSector(KFsInfoSecPos_Bk, fsInfoSector));
   831         bNeedWriteFSInfo_Bk =   !fsInfoSector.IsValid() ||
   832                                 fsInfoSector.FreeClusterCount() != KFreeClusters ||
   833                                 fsInfoSector.NextFreeCluster()  != KNextFreeCluster; 
   834         }
   835 
   836     //-- setup data in FSInfo sector to write
   837     fsInfoSector.Initialise();
   838     fsInfoSector.SetFreeClusterCount(KFreeClusters);
   839     fsInfoSector.SetNextFreeCluster(KNextFreeCluster);
   840 
   841     if(!bNeedWriteFSInfo_Main && !bNeedWriteFSInfo_Bk)
   842         return; //-- nothing to do
   843 
   844     SetVolumeCleanL(EFalse); //-- mark volume dirty, just in case something will happen on FSInfo sectors write
   845 
   846     if(bNeedWriteFSInfo_Main)
   847         User::LeaveIfError(WriteFSInfoSector(KFsInfoSecPos_Main, fsInfoSector));
   848 
   849     if(bNeedWriteFSInfo_Bk)
   850         User::LeaveIfError(WriteFSInfoSector(KFsInfoSecPos_Bk, fsInfoSector));
   851 
   852     }
   853 
   854 //-------------------------------------------------------------------------------------------------------------------
   855 
   856 /**
   857     CFatMountCB control method.
   858     @param  aLevel  specifies the operation to perfrom on the mount
   859     @param  aOption specific option for the given operation
   860     @param  aParam  pointer to generic parameter, its meaning depends on aLevel and aOption
   861 
   862     @return standard error code.
   863 */
   864 TInt CFatMountCB::MountControl(TInt aLevel, TInt aOption, TAny* aParam)
   865     {
   866     __PRINT3(_L("CFatMountCB::MountControl() drv:%d, level:%d, opt:%d"),Drive().DriveNumber(), aLevel, aOption);
   867     
   868     TInt nRes = KErrNotSupported; 
   869     
   870     if(aLevel == ECheckFsMountable)
   871         {
   872         return MntCtl_DoCheckFileSystemMountable();
   873         }
   874     
   875     //-- todo: move these functions code into separate methods ??
   876 
   877     //-- mount state query: check if is in finalised state 
   878     if(aLevel == EMountStateQuery && aOption == ESQ_IsMountFinalised)
   879         {
   880         TBool bFinalised;
   881         nRes = IsFinalised(bFinalised);
   882         if(nRes == KErrNone)
   883             {
   884             *((TBool*)aParam) = bFinalised;
   885             }
   886         
   887         return nRes;
   888         }
   889 
   890     //-- mount-specific volume parameters queries that might not be handled by CFatMountCB::VolumeL
   891     if(aLevel == EMountVolParamQuery)
   892         {
   893         ASSERT(ConsistentState()); //-- volume state shall be consistent, otherwise its parameters do not make sense
   894         switch(aOption)
   895             {
   896             //-- Request a certain amount of free space on the volume.
   897             case ESQ_RequestFreeSpace:
   898                 {
   899                 TUint64* pVal = (TUint64*)aParam; //-- in: number of free bytes on the volume required, out: resulted amount of free space.
   900                 const TUint32 KClustersRequired = (TUint32)((*pVal + ClusterSize() - 1) >> ClusterSizeLog2());
   901                 __PRINT2(_L("MountControl() ReqFreeSpace:%LU, clusters:%d"), *pVal, KClustersRequired);    
   902 
   903                 if(KClustersRequired)
   904                     {//-- actually, this doesn't guarantee that it will finally be KClustersRequired available.
   905                     (void)FAT().RequestFreeClusters(KClustersRequired);  
   906                     }
   907          
   908                 const TUint32 freeClusters = FAT().NumberOfFreeClusters(EFalse); //-- _current_ amount of free clusters  
   909                 *pVal = (TInt64)freeClusters << ClusterSizeLog2();
   910 
   911                 return KErrNone;
   912                 }
   913 
   914             //-- A request to obtain the _current_ amount of free space on the volume asynchronously, without blocking.
   915             case ESQ_GetCurrentFreeSpace:
   916                 {
   917                 TUint64* pVal = (TUint64*)aParam; //-- out: resulted amount of free space.
   918 
   919                 const TUint32 freeClusters = FAT().NumberOfFreeClusters(EFalse); //-- _current_ amount of free clusters  
   920                 *pVal = (TInt64)freeClusters << ClusterSizeLog2();
   921                 __PRINT1(_L("MountControl() Asynch. request; curent amount of free clusters: %d"), freeClusters);
   922 
   923                 return KErrNone;
   924                 }
   925         
   926             //-- A request to obtain size of the mounted volume without blocking (CMountCB::VolumeL() can block).
   927             case ESQ_MountedVolumeSize:
   928                 {
   929                 if(iRamDrive)
   930                     return KErrNotSupported; //-- it requires knowledge of free space on the volume
   931     
   932                 TUint64* pVal = (TUint64*)aParam; 
   933                 *pVal = iSize; //-- physical drive size
   934 
   935                 //-- take into account space occupied by FAT table, etc.
   936                 *pVal -= ClusterBasePosition(); 
   937                 *pVal=(*pVal >> ClusterSizeLog2()) << ClusterSizeLog2();  //-- round down to cluster size
   938 
   939                 __PRINT1(_L("MountControl() MountedVolumeSize:%LU"), *pVal);
   940                 return KErrNone;
   941                 }
   942 
   943             default:
   944             __PRINT1(_L("MountControl() unsupported opt:%d"), aOption);
   945             ASSERT(0);
   946             break;
   947             };
   948 
   949         }
   950 
   951         //-- File System - specific queries 
   952         if(aLevel == EMountFsParamQuery && aOption == ESQ_GetMaxSupportedFileSize)
   953             {//-- this is a query to provide the max. supported file size; aParam is a pointer to TUint64 to return the value
   954             *(TUint64*)aParam = KMaxSupportedFatFileSize;    
   955             return KErrNone;
   956             }
   957 
   958 
   959     
   960     
   961     return KErrNotSupported; 
   962     }
   963 
   964 //-----------------------------------------------------------------------------------------
   965 
   966 /**
   967 Reports whether the specified interface is supported - if it is,
   968 the supplied interface object is modified to it
   969 
   970 @param aInterfaceId     The interface of interest
   971 @param aInterface       The interface object
   972 @return                 KErrNone if the interface is supported, otherwise KErrNotFound 
   973 
   974 @see CMountCB::GetInterface()
   975 */
   976 TInt CFatMountCB::GetInterface(TInt aInterfaceId, TAny*& aInterface,TAny* aInput)
   977     {
   978     switch(aInterfaceId)
   979         {
   980         case (CMountCB::EFileAccessor):
   981             ((CMountCB::MFileAccessor*&) aInterface) = this;
   982             return KErrNone;
   983         
   984         case (CMountCB::EGetFileSystemSubType):
   985             aInterface = (MFileSystemSubType*) (this);
   986             return KErrNone;
   987 
   988         case (CMountCB::EGetClusterSize):
   989             aInterface = (MFileSystemClusterSize*) (this);
   990             return KErrNone;
   991 
   992         case CMountCB::ELocalBufferSupport:
   993             // RAM drives doesn't support local buffers (this results in file caching being disabled)
   994             if (iRamDrive) 
   995                 return KErrNotSupported;
   996             else
   997                 return LocalDrive()->LocalBufferSupport();
   998         
   999 		case EGetProxyDrive:
  1000 			((CProxyDrive*&)aInterface) = LocalDrive();
  1001 			return KErrNone;
  1002         
  1003         case CMountCB::EFileExtendedInterface:
  1004        		// For supporting large file ReadFileSection
  1005        		((CMountCB::MFileExtendedInterface*&) aInterface) = this;
  1006            	return KErrNone;
  1007         
  1008         default:
  1009             return(CMountCB::GetInterface(aInterfaceId, aInterface, aInput));
  1010         }
  1011     }
  1012 
  1013 //-----------------------------------------------------------------------------------------
  1014 void CFatMountCB::ReadSection64L(const TDesC& aName, TInt64 aPos, TAny* aTrg, TInt aLength, const RMessagePtr2& aMessage)
  1015 // From CMountCB::MFileExtendedInterface
  1016 	{
  1017     __PRINT(_L("CFatMountCB::ReadSection64L"));
  1018 	
  1019     CheckStateConsistentL();
  1020     TEntryPos dosEntryPos(RootIndicator(),0);
  1021     TFatDirEntry dosEntry;
  1022     TFileName fileName; 
  1023 
  1024     TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
  1025     TLeafDirData leafDir(0);
  1026     dosEntryPos.iCluster=FindLeafDirL(aName.Left(namePos), leafDir);
  1027     dosEntryPos.iPos=0;
  1028     TEntryPos firstEntryPos;
  1029     TFatDirEntry firstEntry;
  1030     DoFindL(aName.Mid(namePos),KEntryAttMaskSupported,
  1031     		firstEntryPos,firstEntry,dosEntryPos,dosEntry,
  1032     		fileName,KErrNotFound,
  1033     		NULL,
  1034     		leafDir);
  1035     
  1036 //  Check that reading from aPos for aLength lies within the file
  1037 //  if aPos is within the file, and aLength is too long, read up to EOF
  1038 //  If aPos is beyond the end of the file, return a zero length descriptor
  1039 
  1040 	TInt64 fileSize = MAKE_TINT64(0,dosEntry.Size());
  1041 	if (aPos>=fileSize)
  1042         User::Leave(KErrEof);
  1043 	
  1044     if (aPos+aLength>fileSize)
  1045         aLength=(TInt)(fileSize-aPos);
  1046     
  1047     TInt cluster=StartCluster(dosEntry);	
  1048 	TInt64 pos = aPos;
  1049 	
  1050     TInt endCluster;
  1051     TInt clusterSize=1<<ClusterSizeLog2();      //  Size of file clusters
  1052 	TInt readTotal = 0;
  1053 	
  1054 	// Total number of clusters in file
  1055     TInt maxClusters=(TInt)((fileSize+clusterSize-1)>>ClusterSizeLog2());
  1056 
  1057 	// Read data
  1058     FOREVER
  1059         {
  1060 		//  Get the maximum number of clusters that can be read contiguously
  1061         TInt64 clusterListLen=FAT().CountContiguousClustersL(cluster,endCluster,maxClusters);
  1062         __ASSERT_DEBUG(clusterListLen>0,Fault(EReadFileSectionFailed));
  1063 
  1064 		//  If start position within this block, then read some data
  1065         if (pos<(clusterListLen<<ClusterSizeLog2()))
  1066             {
  1067 			//  Read the remaining length or the entire cluster block whichever is smaller
  1068 			TInt readLength = (TInt)Min((TInt64)(aLength-readTotal),(clusterListLen<<ClusterSizeLog2())-pos);
  1069 			__ASSERT_DEBUG(readLength>0,Fault(EReadFileSectionFailed));
  1070 			TInt64 dataAddress=(FAT().DataPositionInBytes(cluster))+pos;
  1071 			iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal);
  1072 			readTotal += readLength;
  1073 
  1074 			if (readTotal == aLength)
  1075 				return;
  1076 
  1077 			pos += readLength;
  1078 			}
  1079 		
  1080 		// Get the next cluster in file
  1081 		pos-=(clusterListLen<<ClusterSizeLog2());
  1082 #if defined(_DEBUG)
  1083 		TBool remainingClusters=
  1084 #endif
  1085 			((CFatMountCB*)this)->FAT().GetNextClusterL(endCluster);
  1086 		__ASSERT_DEBUG(remainingClusters,Fault(EReadFileSectionFailed));		
  1087 		cluster=endCluster;
  1088 		}
  1089     }