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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfat32\sl_mnt32.cpp
15 // CFatMountCB code, specific to the EFAT32.FSY
25 #include "sl_leafdir_cache.h"
27 //-------------------------------------------------------------------------------------------------------------------
31 Write aligned members of TFatBootSector to media
33 @param aMediaPos media position the data will be written to
34 @param aBootSector data to write
35 @return Media write error code
37 TInt CFatMountCB::DoWriteBootSector(TInt64 aMediaPos, const TFatBootSector& aBootSector) const
39 __PRINT2(_L("#- CFatMountCB::DoWriteBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);
43 TBuf8<KDefaultSectorSize> bootSecBuf(KDefaultSectorSize);
46 //-- externalize boot sector to the data buffer
47 aBootSector.Externalize(bootSecBuf);
49 //-- put a boot sector signature to the last 2 bytes
50 bootSecBuf[KDefaultSectorSize-2] = 0x55;
51 bootSecBuf[KDefaultSectorSize-1] = 0xaa;
53 //-- write boot sector to the media
54 TInt r=LocalDrive()->Write(aMediaPos, bootSecBuf);
57 __PRINT2(_L("CFatMountCB::DoWriteBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
63 //-------------------------------------------------------------------------------------------------------------------
66 Read non aligned boot data from media into TFatBootSector structure
68 @param aMediaPos media position the data will be read from
69 @param aBootSector refrence to TFatBootSector populate
70 @return Media read error code
72 TInt CFatMountCB::DoReadBootSector(TInt64 aMediaPos, TFatBootSector& aBootSector) const
74 __PRINT2(_L("#- CFatMountCB::DoReadBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);
78 TBuf8<KSizeOfFatBootSector> bootSecBuf(KSizeOfFatBootSector);
80 //-- read boot sector from the media
81 TInt r=LocalDrive()->Read(aMediaPos, KSizeOfFatBootSector, bootSecBuf);
85 __PRINT2(_L("CFatMountCB::DoReadBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
87 //-- fiddling with the error code; taken from MountL()
88 if (r==KErrNotSupported)
90 #if defined(_LOCKABLE_MEDIA)
91 else if(r==KErrLocked)
94 else if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown)
102 //-- initialise TFatBootSector object
103 aBootSector.Internalize(bootSecBuf);
105 //-- Validate the partition size, and fix up if the out of bounds
106 TLocalDriveCapsV2Buf localDriveCaps;
107 r = LocalDrive()->Caps(localDriveCaps);
110 //-- fiddling with the error code; taken from MountL()
111 if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown)
117 if(!(localDriveCaps().iMediaAtt & KMediaAttVariableSize))
118 {//-- this is not a RAM drive.
119 const TUint32 maxSectors = I64LOW(localDriveCaps().iSize >> KDefSectorSzLog2);
121 if(aBootSector.TotalSectors())
122 aBootSector.SetTotalSectors(Min(aBootSector.TotalSectors(), maxSectors));
124 aBootSector.SetHugeSectors(Min(aBootSector.HugeSectors(), maxSectors));
130 //-------------------------------------------------------------------------------------------------------------------
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.
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.
143 TInt CFatMountCB::ReadBootSector(TFatBootSector& aBootSector, TBool aDoNotReadBkBootSec/*=EFalse*/)
145 iMainBootSecValid = EFalse;
147 //-- read main boot sector from the sector 0
148 TInt nRes = DoReadBootSector(KBootSectorNum << KDefSectorSzLog2, aBootSector);
151 if(aBootSector.IsValid())
153 iMainBootSecValid = ETrue; //-- main boot sector is valid, everything is OK
158 __PRINT(_L("MainBoot Sector is invalid! dump:\n"));
159 aBootSector.PrintDebugInfo();
164 ASSERT(nRes!= KErrNone && !iMainBootSecValid);
166 if(aDoNotReadBkBootSec)
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 )
174 if(aBootSector.IsValid())
175 return KErrNone; //-- main boot sector is bad, but backup one is OK
177 {//-- backup boot sector is invalid
178 __PRINT(_L("Backup Sector is invalid! dump:\n"));
179 aBootSector.PrintDebugInfo();
184 //-- can't read boot sectors, or both are invalid
188 //-------------------------------------------------------------------------------------------------------------------
191 Write a new volume label to BPB in media
193 @param aVolumeLabel Descriptor containing the new volume label
196 void CFatMountCB::WriteVolumeLabelL(const TDesC8& aVolumeLabel) const
198 if(aVolumeLabel.Length() > KVolumeLabelSize)
199 User::Leave(KErrArgument);
201 const TUint32 posVolLabel = Is32BitFat() ? KFat32VolumeLabelPos : KFat16VolumeLabelPos;
202 User::LeaveIfError(LocalDrive()->Write(posVolLabel, aVolumeLabel));
207 //-------------------------------------------------------------------------------------------------------------------
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
213 Set or reset "VolumeClean" (ClnShutBitmask) flag.
215 @param aClean if ETrue, marks the volume as clean, otherwise as dirty.
216 @leave if write error occured.
218 void CFatMountCB::SetVolumeCleanL(TBool aClean)
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)
224 __PRINT1(_L("#- CFatMountCB::SetVolumeCleanL drive:%d isn't free!"),DriveNumber());
226 User::Leave(KErrInUse);
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);
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
242 __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT32"),DriveNumber(), aClean);
244 TFat32Entry fatEntry;
245 const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
246 TPtr8 ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize);
248 User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT32[1] entry
250 const TFat32Entry tmp = fatEntry;
253 fatEntry |= KFat32CleanShutDownMask; //-- set ClnShutBit flag
255 fatEntry &= ~KFat32CleanShutDownMask; //-- reset ClnShutBit flag
258 {//-- write FAT[1] entry to all available FATs
259 for(TInt i=0; i<NumberOfFats(); ++i)
261 const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i);
262 User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT32[1] entry
266 __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry: %x->%x"), tmp, fatEntry);
271 __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT16"),DriveNumber(), aClean);
273 if(FatConfig().FAT16_UseCleanShutDownBit())
275 TFat16Entry fatEntry;
276 const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
277 TPtr8 ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize);
279 User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry
281 const TFat16Entry tmp = fatEntry;
284 fatEntry |= KFat16CleanShutDownMask; //-- set ClnShutBit flag
286 fatEntry &= ~KFat16CleanShutDownMask; //-- reset ClnShutBit flag
289 {//-- write FAT[1] entry to all available FATs
290 for(TInt i=0; i<NumberOfFats(); ++i)
292 const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i);
293 User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT16[1] entry
297 __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry: %x->%x"), tmp, fatEntry);
301 __PRINT(_L("#- changing FAT16[1] is disabled in config!"));
305 {//-- must never get here
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);
315 //-------------------------------------------------------------------------------------------------------------------
318 Determine whether "VolumeClean" (ClnShutBitmask) flag is set.
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.
323 TBool CFatMountCB::VolumeCleanL()
326 //-- read access to the FAT is through TDriveInterface, because CFatTable doesn't allow access to FAT[1]
327 TDriveInterface& drive =DriveInterface();
331 TFat32Entry fatEntry;
332 const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
333 TPtr8 ptrFatEntry((TUint8*)&fatEntry, KFatEntrySize);
335 User::LeaveIfError(drive.ReadNonCritical(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT32[1] entry
336 return (fatEntry & KFat32CleanShutDownMask);
341 TFat16Entry fatEntry;
342 const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes
343 TPtr8 ptrFatEntry((TUint8*)&fatEntry, KFatEntrySize);
345 User::LeaveIfError(drive.ReadNonCritical(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry
346 return (fatEntry & KFat16CleanShutDownMask);
349 {//-- Fat12 doesn't support this feature, shan't get here, actually
351 User::Leave(KErrNotSupported);
352 return ETrue; //-- to satisfy the compiler
357 //-------------------------------------------------------------------------------------------------------------------
362 @param aForceMount Flag to indicate whether mount should be forced to succeed if an error occurs
363 @leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
365 void CFatMountCB::MountL(TBool aForceMount)
368 const TInt driveNo = Drive().DriveNumber();
370 __PRINT2(_L("CFatMountCB::MountL() drv:%d, forceMount=%d\n"),driveNo,aForceMount);
372 ASSERT(State() == ENotMounted || State() == EDismounted);
376 User::LeaveIfError(CreateDrive(driveNo));
379 //-- read FAT configuration parameters from estart.txt
380 iFatConfig.ReadConfig(driveNo);
382 //-- initialise interface to the low-level drive access
383 if(!iDriverInterface.Init(this))
384 User::LeaveIfError(KErrNoMemory);
386 //-- get drive capabilities
387 TLocalDriveCapsV2Buf capsBuf;
388 User::LeaveIfError(LocalDrive()->Caps(capsBuf));
391 iSize=capsBuf().iSize;
394 if(capsBuf().iMediaAtt & KMediaAttVariableSize)
395 {//-- this is a RAM drive
396 UserSvr::UnlockRamDrive();
401 {//-- the state is "forcedly mounted", special case. This is an inconsistent state.
402 SetState(EInit_Forced);
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));
411 //-- print out boot sector debug information
412 bootSector.PrintDebugInfo();
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()
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
423 __PRINT(_L("FAT type mismatch! Setting drive to ReadOnly mode for FAT32. \n"));
424 SetFatType(EFat32); //-- force FAT type to be FAT32
428 //-- store volume UID, it can be checked on Remount
429 iUniqueID = bootSector.UniqueID();
431 //-- populate volume parameters with the values from boot sector. They had been validated in TFatBootSector::IsValid()
432 iVolParam.Populate(bootSector);
434 //-- initialize the volume
435 InitializeL(capsBuf());
436 ASSERT(State()==EInit_R);
438 GetVolumeLabelFromDiskL(bootSector);
440 __PRINT2(_L("CFatMountCB::MountL() Completed, drv: %d, state:%d"), DriveNumber(), State());
445 //-------------------------------------------------------------------------------------------------------------------
448 Initialize the FAT cache and disk access
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.
453 @leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
455 void CFatMountCB::InitializeL(const TLocalDriveCaps& aLocDrvCaps, TBool aIgnoreFSInfo/*=EFalse*/)
457 __PRINT1(_L("CFatMountCB::InitializeL() drv:%d"), DriveNumber());
459 ASSERT(State() == EMounting); //-- we must get here only from MountL()
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();
472 iFirstFreeByte=(NumberOfFats() * FatSizeInBytes()) + (FirstFatSector() << SectorSizeLog2());
474 iFirstFreeByte=RootDirEnd();
478 {//-- check if volume geometry looks valid
479 const TInt usableSectors=TotalSectors()-(iFirstFreeByte>>SectorSizeLog2());
480 iUsableClusters=usableSectors>>(ClusterSizeLog2()-SectorSizeLog2());
482 const TUint32 KMinClusters = 32; //-- absolute minimum number of clusters on the volume
483 const TUint32 KMaxClusters=(TotalSectors()-FirstFatSector()-NumberOfFats()*(FatSizeInBytes()>>SectorSizeLog2())) >> (ClusterSizeLog2()-SectorSizeLog2());
485 if(usableSectors <=0 || iUsableClusters < KMinClusters || iUsableClusters > KMaxClusters)
487 __PRINT(_L("CFatMountCB::InitializeL() Wrong number of usable cluster/sectors on the volume!"));
488 User::Leave(KErrCorrupt);
492 //========== initialise RawDisk interface
493 //-- CFatMountCB parameters might have changed, e.g. after formatting. Reconstruct directory cache with new parameters
496 iRawDisk=CRawDisk::NewL(*this, aLocDrvCaps);
497 iRawDisk->InitializeL();
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)
503 //-- main boot sector shall be valid, otherwise we can't trust data from FSInfo
504 bUseDataFromFsInfo = bUseDataFromFsInfo && iMainBootSecValid;
506 //-- 1. check if using FSInfo is disabled in config
507 if(bUseDataFromFsInfo && !FatConfig().FAT32_UseFSInfoOnMount())
509 __PRINT(_L("#- FSInfo using is disabled in config!"));
510 bUseDataFromFsInfo = EFalse;
514 //-- 2. check if FSInfo is disabled by test interface (special debug property). This property is defined and set by the test application.
516 if(bUseDataFromFsInfo && RProperty::Get(KSID_Test1, DriveNumber(), nMntDebugFlags) == KErrNone)
517 {//-- test property for this drive is defined
518 if(nMntDebugFlags & KMntDisable_FsInfo)
520 __PRINT(_L("#- FSInfo using is disabled by debug interface."));
521 bUseDataFromFsInfo = EFalse;
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)
531 bUseDataFromFsInfo = ProcessFSInfoSectors(fatMntParams);
532 if(!bUseDataFromFsInfo)
534 __PRINT1(_L("#- CFatMountCB::ProcessFSInfoSectors() failed. drv:%d"), DriveNumber());
538 //========== create and initialise FAT table
541 iFatTable=CFatTable::NewL(*this, aLocDrvCaps);
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);
548 SetState(EInit_R); //-- the state is "Initialized, but not writen"
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
555 const TUint32 cacheLimit = iFatConfig.LeafDirCacheSize();
558 // destroy the old leaf dir cache to avoid memory leak.
559 delete iLeafDirCache;
560 iLeafDirCache = CLeafDirCache::NewL(cacheLimit);
564 iLeafDirCache = NULL;
567 __PRINT3(_L("#- CFatMountCB::InitializeL() done. drv:%d, Free clusters:%d, 1st Free cluster:%d"),DriveNumber(), FAT().NumberOfFreeClusters(), FAT().FreeClusterHint());
572 //-------------------------------------------------------------------------------------------------------------------
575 Write FSInfo sectors to the media
577 @param aMediaPos Media position to write FSInfo sector to
578 @param aFSInfo FSInfo structure to write
579 @return System wide error code
581 TInt CFatMountCB::WriteFSInfoSector(TInt64 aMediaPos, const TFSInfo& aFSInfo) const
583 __PRINT2(_L("#- CFatMountCB::WriteFSInfoSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);
585 ASSERT(aMediaPos >= 0 && aMediaPos < FirstFatSector()<<SectorSizeLog2());
586 ASSERT(Is32BitFat());
588 TBuf8<KSizeOfFSInfo> fsInfoSecBuf;
590 //-- put data to the sector buffer
591 aFSInfo.Externalize(fsInfoSecBuf);
593 TInt r=LocalDrive()->Write(aMediaPos, fsInfoSecBuf);
596 __PRINT2(_L("CFatMountCB::WriteFSInfoSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
602 //-------------------------------------------------------------------------------------------------------------------
604 Read the FSInfo structure from media
606 @param aMediaPos Media position to read FSInfo sector from
607 @param aFSInfo data read from FSInfo structure
608 @return System wide error code
610 TInt CFatMountCB::ReadFSInfoSector(TInt64 aMediaPos, TFSInfo& aFSInfo) const
612 __PRINT2(_L("#- CFatMountCB::ReadFSInfoSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos);
614 ASSERT(aMediaPos >= 0 && aMediaPos < FirstFatSector()<<SectorSizeLog2());
615 ASSERT(Is32BitFat());
617 TBuf8<KSizeOfFSInfo> fsInfoSecBuf;
619 TInt r=LocalDrive()->Read(aMediaPos, KSizeOfFSInfo, fsInfoSecBuf);
622 __PRINT2(_L("CFatMountCB::ReadFSInfoSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r);
626 //-- take FSInfo data from the buffer
627 aFSInfo.Internalize(fsInfoSecBuf);
634 Initialize data to represent the root directory
636 @param anEntry Entry to initialise
638 void CFatMountCB::InitializeRootEntry(TFatDirEntry& anEntry) const
640 anEntry.SetName(_L8("ROOT"));
641 anEntry.SetAttributes(KEntryAttDir);
642 anEntry.SetStartCluster(RootClusterNum()); //--iRootClusterNum is 0 for FAT12/16
648 Implementation of CMountCB::FileSystemSubType(). Retrieves the sub type of Fat file system
649 and returns the name as a descriptor.
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.
655 @see CMountCB::FileSystemSubType()
657 TInt CFatMountCB::SubType(TDes& aName) const
659 if(aName.MaxLength() < 5)
666 aName = KFSSubType_FAT12;
671 aName = KFSSubType_FAT16;
676 aName = KFSSubType_FAT32;
680 // case EInvalidFatType
686 //-------------------------------------------------------------------------------------------------------------------
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.
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.
696 TBool CFatMountCB::ProcessFSInfoSectors(CFatTable::TMountParams& aFatInitParams) const
699 aFatInitParams.iFreeClusters = 0;
700 aFatInitParams.iFirstFreeCluster = 0;
701 aFatInitParams.iFsInfoValid = EFalse;
703 const TUint32 currFsInfoSec = iVolParam.FSInfoSectorNum(); //-- values from the boot sector
704 const TUint32 currFsInfoBkSec = iVolParam.BkFSInfoSectorNum();
706 if(!Is32BitFat() || currFsInfoSec < KFSInfoSectorNum || currFsInfoSec >= FirstFatSector())
708 ASSERT(0); //-- main FSInfo sector must have sensible location
712 if(currFsInfoBkSec < KFSInfoSectorNum || currFsInfoBkSec >= FirstFatSector() || currFsInfoBkSec <= currFsInfoSec)
713 return EFalse; //-- something is wrong with backup copy location
718 //-- 1. read and validate main FS Info sector
719 nRes = ReadFSInfoSector(currFsInfoSec << SectorSizeLog2(), fsInfo);
723 fsInfo.PrintDebugInfo();
725 if(!fsInfo.IsValid())
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
731 //-- 2. read and check backup FS Info sector, it must be the same as the main one
732 nRes = ReadFSInfoSector(currFsInfoBkSec << SectorSizeLog2(), fsInfo);
734 if(nRes != KErrNone || !fsInfo.IsValid() || freeCount != fsInfo.FreeClusterCount() || nextFree != fsInfo.NextFreeCluster())
736 __PRINT(_L("#- CFatMountCB::ProcessFSInfoSectors(): copies of FSInfo are different!"));
740 if(freeCount < 1 || freeCount > UsableClusters())
741 return EFalse; //-- looks like invalid value
743 if(nextFree < KFatFirstSearchCluster || nextFree >= UsableClusters()+KFatFirstSearchCluster)
744 return EFalse; //-- looks like invalid value
747 aFatInitParams.iFreeClusters = freeCount;
748 aFatInitParams.iFirstFreeCluster = nextFree;
749 aFatInitParams.iFsInfoValid = ETrue;
754 //-------------------------------------------------------------------------------------------------------------------
756 Internal helper method. Writes FSInfo sector and its backup copy to the volume if necessary.
758 @param aInvalidateFSInfo if ETrue, FSInfo data (free clusters count) will be invalidated.
759 otherwise, data from the CFatTable object will be used
761 @leave if disk opertion fails
763 void CFatMountCB::DoUpdateFSInfoSectorsL(TBool aInvalidateFSInfo)
765 __PRINT2(_L("#- CFatMountCB::DoUpdateFSInfoSectorsL(%d) drv:%d"),aInvalidateFSInfo, Drive().DriveNumber());
767 ASSERT(Is32BitFat());
769 if(!aInvalidateFSInfo)
771 ASSERT(FAT().ConsistentState());
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
778 const TUint32 currFsInfoSec = iVolParam.FSInfoSectorNum(); //-- values from the boot sector
779 const TUint32 currFsInfoBkSec = iVolParam.BkFSInfoSectorNum();
781 if(currFsInfoSec > 0 && currFsInfoSec < FirstFatSector())
783 bCanWriteFSInfo_Main = ETrue;
787 __PRINT1(_L("#- DoUpdateFSInfoSectorsL() iFSInfoSectorNum is wrong!: sec:%d"), currFsInfoSec);
790 if(currFsInfoBkSec > 0 && currFsInfoBkSec < FirstFatSector() && currFsInfoBkSec > currFsInfoSec)
792 bCanWriteFSInfo_Bk = bCanWriteFSInfo_Main;
796 __PRINT1(_L("#- DoUpdateFSInfoSectorsL() iBkFSInfoSectorNum is wrong!: sec:%d"),currFsInfoBkSec);
799 if(!bCanWriteFSInfo_Main && !bCanWriteFSInfo_Bk)
800 return; //-- nothing to do
803 const TUint32 KFsInfoSecPos_Main = currFsInfoSec << SectorSizeLog2(); //-- main FSInfo sector media position
804 const TUint32 KFsInfoSecPos_Bk = currFsInfoBkSec << SectorSizeLog2(); //-- backup FSInfo sector media position
806 TFSInfo fsInfoSector;
808 TBool bNeedWriteFSInfo_Main = EFalse;
809 TBool bNeedWriteFSInfo_Bk = EFalse;
812 const TUint32 KInvalidVal = 0xFFFFFFFF; //-- invalid value for FSInfo fields, see FAT specs
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();
818 //-- check if the main FSInfo sector differs from the FAT information
819 if(bCanWriteFSInfo_Main)
821 User::LeaveIfError(ReadFSInfoSector(KFsInfoSecPos_Main, fsInfoSector));
822 bNeedWriteFSInfo_Main = !fsInfoSector.IsValid() ||
823 fsInfoSector.FreeClusterCount() != KFreeClusters ||
824 fsInfoSector.NextFreeCluster() != KNextFreeCluster;
827 //-- check if the backup FSInfo sector differs from the FAT information
828 if(bCanWriteFSInfo_Bk)
830 User::LeaveIfError(ReadFSInfoSector(KFsInfoSecPos_Bk, fsInfoSector));
831 bNeedWriteFSInfo_Bk = !fsInfoSector.IsValid() ||
832 fsInfoSector.FreeClusterCount() != KFreeClusters ||
833 fsInfoSector.NextFreeCluster() != KNextFreeCluster;
836 //-- setup data in FSInfo sector to write
837 fsInfoSector.Initialise();
838 fsInfoSector.SetFreeClusterCount(KFreeClusters);
839 fsInfoSector.SetNextFreeCluster(KNextFreeCluster);
841 if(!bNeedWriteFSInfo_Main && !bNeedWriteFSInfo_Bk)
842 return; //-- nothing to do
844 SetVolumeCleanL(EFalse); //-- mark volume dirty, just in case something will happen on FSInfo sectors write
846 if(bNeedWriteFSInfo_Main)
847 User::LeaveIfError(WriteFSInfoSector(KFsInfoSecPos_Main, fsInfoSector));
849 if(bNeedWriteFSInfo_Bk)
850 User::LeaveIfError(WriteFSInfoSector(KFsInfoSecPos_Bk, fsInfoSector));
854 //-------------------------------------------------------------------------------------------------------------------
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
862 @return standard error code.
864 TInt CFatMountCB::MountControl(TInt aLevel, TInt aOption, TAny* aParam)
866 __PRINT3(_L("CFatMountCB::MountControl() drv:%d, level:%d, opt:%d"),Drive().DriveNumber(), aLevel, aOption);
868 TInt nRes = KErrNotSupported;
870 if(aLevel == ECheckFsMountable)
872 return MntCtl_DoCheckFileSystemMountable();
875 //-- todo: move these functions code into separate methods ??
877 //-- mount state query: check if is in finalised state
878 if(aLevel == EMountStateQuery && aOption == ESQ_IsMountFinalised)
881 nRes = IsFinalised(bFinalised);
884 *((TBool*)aParam) = bFinalised;
890 //-- mount-specific volume parameters queries that might not be handled by CFatMountCB::VolumeL
891 if(aLevel == EMountVolParamQuery)
893 ASSERT(ConsistentState()); //-- volume state shall be consistent, otherwise its parameters do not make sense
896 //-- Request a certain amount of free space on the volume.
897 case ESQ_RequestFreeSpace:
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);
903 if(KClustersRequired)
904 {//-- actually, this doesn't guarantee that it will finally be KClustersRequired available.
905 (void)FAT().RequestFreeClusters(KClustersRequired);
908 const TUint32 freeClusters = FAT().NumberOfFreeClusters(EFalse); //-- _current_ amount of free clusters
909 *pVal = (TInt64)freeClusters << ClusterSizeLog2();
914 //-- A request to obtain the _current_ amount of free space on the volume asynchronously, without blocking.
915 case ESQ_GetCurrentFreeSpace:
917 TUint64* pVal = (TUint64*)aParam; //-- out: resulted amount of free space.
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);
926 //-- A request to obtain size of the mounted volume without blocking (CMountCB::VolumeL() can block).
927 case ESQ_MountedVolumeSize:
930 return KErrNotSupported; //-- it requires knowledge of free space on the volume
932 TUint64* pVal = (TUint64*)aParam;
933 *pVal = iSize; //-- physical drive size
935 //-- take into account space occupied by FAT table, etc.
936 *pVal -= ClusterBasePosition();
937 *pVal=(*pVal >> ClusterSizeLog2()) << ClusterSizeLog2(); //-- round down to cluster size
939 __PRINT1(_L("MountControl() MountedVolumeSize:%LU"), *pVal);
944 __PRINT1(_L("MountControl() unsupported opt:%d"), aOption);
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;
961 return KErrNotSupported;
964 //-----------------------------------------------------------------------------------------
967 Reports whether the specified interface is supported - if it is,
968 the supplied interface object is modified to it
970 @param aInterfaceId The interface of interest
971 @param aInterface The interface object
972 @return KErrNone if the interface is supported, otherwise KErrNotFound
974 @see CMountCB::GetInterface()
976 TInt CFatMountCB::GetInterface(TInt aInterfaceId, TAny*& aInterface,TAny* aInput)
980 case (CMountCB::EFileAccessor):
981 ((CMountCB::MFileAccessor*&) aInterface) = this;
984 case (CMountCB::EGetFileSystemSubType):
985 aInterface = (MFileSystemSubType*) (this);
988 case (CMountCB::EGetClusterSize):
989 aInterface = (MFileSystemClusterSize*) (this);
992 case CMountCB::ELocalBufferSupport:
993 // RAM drives doesn't support local buffers (this results in file caching being disabled)
995 return KErrNotSupported;
997 return LocalDrive()->LocalBufferSupport();
1000 ((CProxyDrive*&)aInterface) = LocalDrive();
1003 case CMountCB::EFileExtendedInterface:
1004 // For supporting large file ReadFileSection
1005 ((CMountCB::MFileExtendedInterface*&) aInterface) = this;
1009 return(CMountCB::GetInterface(aInterfaceId, aInterface, aInput));
1013 //-----------------------------------------------------------------------------------------
1014 void CFatMountCB::ReadSection64L(const TDesC& aName, TInt64 aPos, TAny* aTrg, TInt aLength, const RMessagePtr2& aMessage)
1015 // From CMountCB::MFileExtendedInterface
1017 __PRINT(_L("CFatMountCB::ReadSection64L"));
1019 CheckStateConsistentL();
1020 TEntryPos dosEntryPos(RootIndicator(),0);
1021 TFatDirEntry dosEntry;
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);
1028 TEntryPos firstEntryPos;
1029 TFatDirEntry firstEntry;
1030 DoFindL(aName.Mid(namePos),KEntryAttMaskSupported,
1031 firstEntryPos,firstEntry,dosEntryPos,dosEntry,
1032 fileName,KErrNotFound,
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
1040 TInt64 fileSize = MAKE_TINT64(0,dosEntry.Size());
1042 User::Leave(KErrEof);
1044 if (aPos+aLength>fileSize)
1045 aLength=(TInt)(fileSize-aPos);
1047 TInt cluster=StartCluster(dosEntry);
1051 TInt clusterSize=1<<ClusterSizeLog2(); // Size of file clusters
1054 // Total number of clusters in file
1055 TInt maxClusters=(TInt)((fileSize+clusterSize-1)>>ClusterSizeLog2());
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));
1064 // If start position within this block, then read some data
1065 if (pos<(clusterListLen<<ClusterSizeLog2()))
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;
1074 if (readTotal == aLength)
1080 // Get the next cluster in file
1081 pos-=(clusterListLen<<ClusterSizeLog2());
1083 TBool remainingClusters=
1085 ((CFatMountCB*)this)->FAT().GetNextClusterL(endCluster);
1086 __ASSERT_DEBUG(remainingClusters,Fault(EReadFileSectionFailed));