// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32\sfat\inc\sl_std.h
// 
//

/**
 @file
 @internalTechnology
*/

#ifndef SL_STD_H
#define SL_STD_H

//
// #define _DEBUG_RELEASE
//

#include "common.h"
#include <f32ver.h>
#include <e32svr.h>
#include <kernel/localise.h>
#include "filesystem_fat.h"

#include "common_constants.h"
#include "sl_bpb.h"
#include "fat_config.h"
#include "fat_dir_entry.h"

using namespace FileSystem_FAT;

#ifdef _DEBUG
_LIT(KThisFsyName,"EFAT.FSY"); ///< This FSY name
#endif

class CFatMountCB;
class CFatFileSystem;

/**
Represents the position of a directory entery in terms of a cluster and off set into it
*/
class TEntryPos
    {
public:
    TEntryPos() {}
    TEntryPos(TInt aCluster,TUint aPos) : iCluster(aCluster), iPos(aPos) {}

    inline TUint32 Cluster() const;
    inline TUint32 Pos() const;
    inline TBool operator==(const TEntryPos& aRhs) const;

public:
    TInt iCluster;
    TUint iPos;
    };


/**
    Interface class between the file system and the local drive media interface,
    handles incomplete writes to media with the ability to notify the user.
    This class can't be instantinated by user; only CFatMountCB can do this; see CFatMountCB::DriveInterface()

*/
class TFatDriveInterface
    {
public:
    enum TAction {ERetry=1};

public:

    //-- public interface to the local drive. Provides media driver's error handling (critical and non-critical user notifiers)
    //-- and thread-safety if required.
	TInt ReadNonCritical(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const;
	TInt ReadNonCritical(TInt64 aPos,TInt aLength,TDes8& aTrg) const;
    TInt ReadCritical(TInt64 aPos,TInt aLength,TDes8& aTrg) const;
	
    TInt WriteCritical(TInt64 aPos,const TDesC8& aSrc);
    TInt WriteNonCritical(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset);
	
    TInt GetLastErrorInfo(TDes8& aErrorInfo) const;

    //-- lock the mutex guarding CProxyDrive interface in order to be sure that no other thread can access it.
    //-- The thread that calls this method may be suspended until another signals the mutex, i.e. leaves the critical section.
    inline void AcquireLock() const {} //-- dummy
    
    //-- release the mutex guarding CProxyDrive.
    inline void ReleaseLock() const {} //-- dummy


protected:
    TFatDriveInterface();
    TFatDriveInterface(const TFatDriveInterface&);
    TFatDriveInterface& operator=(const TFatDriveInterface&);

    TBool Init(CFatMountCB* aMount);
    void Close(); 

    inline TBool NotifyUser() const;
    TInt HandleRecoverableError(TInt aRes) const;
    TInt HandleCriticalError(TInt aRes) const;
    TInt UnlockAndReMount() const;
    TBool IsDriveWriteProtected() const;
    TBool IsRecoverableRemount() const;

private:
	
	/** 
        An internal class that represents a thread-safe wrapper around raw interface to the CProxyDrive 
        and restricts access to it.
    */
    class XProxyDriveWrapper
        {
        public:
       
        XProxyDriveWrapper();
       ~XProxyDriveWrapper();

        TBool Init(CProxyDrive* aProxyDrive);
            
        inline void EnterCriticalSection() const {} //-- dummy
        inline void LeaveCriticalSection() const {} //-- dummy

        //-- methods' wrappers that are used by TFatDriveInterface
        TInt Read(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const;
        TInt Read(TInt64 aPos,TInt aLength,TDes8& aTrg) const;
        TInt Write(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset);
        TInt Write(TInt64 aPos, const TDesC8& aSrc);
        TInt GetLastErrorInfo(TDes8& aErrorInfo) const;
        TInt Caps(TDes8& anInfo) const;

        private:
        
        CProxyDrive*    iLocalDrive; ///< raw interface to the media operations
        mutable RMutex  iLock;       ///< used for sorting out multithreaded access to the iLocalDrive
        };
    
    CFatMountCB*        iMount;      ///< Pointer to the owning file system mount
    XProxyDriveWrapper  iProxyDrive; ///< wrapper around raw interface to the media operations
    
    };



/**
    Class providing FAT table interface and basic functionality.
*/  
class CFatTable : public CBase
    {
public:
	static CFatTable* NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps);

    virtual ~CFatTable();

	/** Empty and deallocate the cache*/
	virtual void Dismount(TBool /*aDiscardDirtyData*/) {}
    
	/** Flush data cahed data to the media */
	virtual void FlushL() {};
	
    /**
    Invalidate specified region of the FAT cache
    Depending of cache type this may just mark part of the cache invalid with reading on demand later
    or re-read whole cache from the media.

    @param aPos absolute media position where the region being invalidated starts.
    @param aLength length in bytes of region to invalidate / refresh
    */
	virtual void InvalidateCacheL(TInt64 /*aPos*/,TUint32 /*aLength*/) {};

    
    /**
    Invalidate whole FAT cache.
    Depending of cache type this may just mark cache invalid with reading on demand or re-read whole cache from the media
    */
    virtual void InvalidateCacheL() {};
	

    /**
	Gets the next cluster in a cluster chain

	@param aCluster	Cluster number to start lookup. On return contains number of the next cluster.
	@return EFalse if cluster is at the end of a cluster chain
    */
    virtual TBool GetNextClusterL(TInt& aCluster) const;
	
    /**
    Writes end of cluster chain
	@param aFatIndex index in Fat table where EOF will be written to.
    */
	virtual void WriteFatEntryEofL(TUint32 aFatIndex);

    /** 
	Read an entry from the FAT.

	@param aFatIndex aFatIndex index in Fat table
	@return value of the FAT entry number aFatIndex
    */
	virtual TUint32 ReadL(TUint32 aFatIndex) const = 0;
	
    /**
	Write FAT entry to FAT by its index.

	@param aFatIndex index in FAT
    @param aValue value to write
    */
	virtual void WriteL(TUint32 aFatIndex, TUint32 aValue) = 0;
	
    /**
    return the byte position of a cluster in the fat table

    @param aCluster cluster to find position of
    @return byte position of the cluster
    */
	virtual TInt64 DataPositionInBytes(TUint32 aCluster) const = 0;

	virtual void FreeClusterListL(TUint32 aCluster);
	virtual void ExtendClusterListL(TUint32 aNumber,TInt& aCluster);
	virtual TUint32 AllocateSingleClusterL(TUint32 aNearestCluster);
	virtual TUint32 AllocateClusterListL(TUint32 aNumber,TUint32 aNearestCluster);
    virtual void CountFreeClustersL();

    virtual void RequestRawWriteAccess(TInt64 /*aPos*/, TUint32 /*aLen*/) const {};
    

public:

    void MarkAsBadClusterL(TUint32 aCluster);
    TInt CountContiguousClustersL(TUint32 aStartCluster,TInt& anEndCluster, TUint32 aMaxCount) const;

    virtual TUint32 FreeClusterHint() const;
    virtual void SetFreeClusterHint(TUint32 aCluster);
    
    virtual TUint32 NumberOfFreeClusters(TBool aSyncOperation=EFalse) const;
    virtual void SetFreeClusters(TUint32 aFreeClusters);

    virtual TBool RequestFreeClusters(TUint32 aClustersRequired) const; 
    
    inline TUint32 MaxEntries() const;
    virtual void InitializeL();
    virtual TBool ConsistentState() const {return ETrue;} //-- dummy

protected:
    CFatTable(CFatMountCB& aOwner);
    
    //-- outlawed
    CFatTable(); 
    CFatTable(const CFatTable&); 
    CFatTable& operator=(const CFatTable&);

    

    void DecrementFreeClusterCount(TUint32 aCount); 
	void IncrementFreeClusterCount(TUint32 aCount);

    inline TUint32 FreeClusters() const;

    inline TBool IsEof16Bit(TInt aCluster) const;
    inline TBool IsEof12Bit(TInt aCluster) const;
    inline TInt SectorSizeLog2() const;
    inline TFatType FatType() const;

    TUint32 PosInBytes(TUint32 aFatIndex) const;
    TUint32 FindClosestFreeClusterL(TUint32 aCluster);

    inline TBool IsFat12() const;
    inline TBool IsFat16() const;

    inline TBool ClusterNumberValid(TUint32 aClusterNo) const;

    typedef RArray<TUint> RClusterArray;
    void DoFreedClustersNotify(RClusterArray &aFreedClusters);


protected:
    
    CFatMountCB* iOwner;            ///< Owning file system mount
    TUint        iMediaAtt;         ///< Cached copy of TLocalDriveCaps::iMediaAtt

private:   

    TUint32  iFreeClusters;     ///< Number of free cluster in the fat table
	TUint32  iFreeClusterHint;  ///< Next free custer in the fat table, just for use in TFsInfo; This is just a hint, not required to contain exact information.
    TFatType iFatType;          ///< FAT type 12/16/32, cached from the iOwner
    TUint32  iMaxEntries;       ///< maximal number of FAT entries in the table. This value is taken from the CFatMount that calculates it
    
    };


class MWTCacheInterface;


//---------------------------------------------------------------------------------------------------------------------------------

/**
Base class abstraction of a raw media disk
*/
class CRawDisk : public CBase
    {
public:

    static CRawDisk* NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps);

    virtual void InitializeL();
	
    virtual TInt GetLastErrorInfo(TDes8& aErrorInfo) const;
public:
	
    /**
	Read data from the media via simple WT data cache if it is present. Some media types, like RAM do not have caches.
    This method is mostly used to read UIDs of executable modules and store them in the cache.

	@param aPos		Media position in bytes
    @param aLength  Length in bytes of read
    @param aDes     Data from read
    */
	virtual void ReadCachedL(TInt64 aPos,TInt aLength,TDes8& aDes) const = 0;
	
    /**
	Write data to the media via simple WT data cache if it is present. Some media types, like RAM do not have caches.
	@param aPos		Media position in bytes
    @param aDes     Data to write
    */
	virtual void WriteCachedL(TInt64 aPos,const TDesC8& aDes) = 0;
    
    virtual void InvalidateUidCache() {}
    virtual void InvalidateUidCachePage(TUint64 /*aPos*/) {}
    

    /**
	Disk read function
    
	@param aPos		Media position in bytes
    @param aLength  Length in bytes of read
	@param aTrg		Pointer to the data descriptor, i.e. (const TAny*)(&TDes8)
    @param aMessage Refrence to server message from request
    @param anOffset Offset into read data to write
    */
    virtual void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const = 0;

    /**
	Disk write function

	@param aPos		Media position in bytes
    @param aLength  Length in bytes of write
	@param aTrg		Pointer to the data descriptor, i.e. (const TAny*)(&TDes8)
    @param aMessage Refrence to server message from request, contains data
    @param anOffset Offset into write data to use in write
    */
    virtual void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset) = 0;

    
    virtual inline MWTCacheInterface* DirCacheInterface();




protected:

    CRawDisk(CFatMountCB& aOwner);

    //-- outlawed
    CRawDisk(); 
    CRawDisk(const CRawDisk&); 
    CRawDisk& operator=(const CRawDisk&);


protected:

    CFatMountCB* iFatMount; ///< Owning file system mount
    
    

    };

class CFatFileCB;
class RBitVector;

/** 
    A helper class. Holds the FAT volume parameters, which in turn are obtained from the Boot Sector
*/
class TFatVolParam
    {
    public:   
    
    TFatVolParam();
    void Populate(const TFatBootSector& aBootSector);
    TBool operator==(const TFatVolParam& aRhs) const;

    //-- simple getters
	TUint32 ClusterSizeLog2() const     {return iClusterSizeLog2;    }        
	TUint32 SectorSizeLog2() const      {return iSectorSizeLog2;     }        
	TUint32 RootDirEnd() const          {return iRootDirEnd;         }        
	TUint32 SectorsPerCluster() const   {return iSectorsPerCluster;  }        
	TUint32 RootDirectorySector() const {return iRootDirectorySector;}        
	TUint32 FirstFatSector() const      {return iFirstFatSector;     }        
	TUint32 TotalSectors() const        {return iTotalSectors;       }        
	TUint32 NumberOfFats() const        {return iNumberOfFats;       }        
	TUint32 FatSizeInBytes() const      {return iFatSizeInBytes;     }        
	TUint32 RootClusterNum() const      {return iRootClusterNum;     }        
    TUint32 FSInfoSectorNum() const     {return iFSInfoSectorNum;    }        
    TUint32 BkFSInfoSectorNum() const   {return iBkFSInfoSectorNum;  }        
    
    protected:
     TUint32 iClusterSizeLog2;      ///< Log2 of fat file system cluster size
	 TUint32 iSectorSizeLog2;       ///< Log2 of media sector size
	 TUint32 iRootDirEnd;           ///< End position of the root directory for Fat12/16
	 TUint32 iSectorsPerCluster;    ///< Sector per cluster ratio for mounted Fat file system volume 
	 TUint32 iRootDirectorySector;  ///< Start sector of the root directory for Fat12/16
	 TUint32 iFirstFatSector;       ///< Start sector of the first Fat table in volume
	 TUint32 iTotalSectors;         ///< Total sectors on media partition
	 TUint32 iNumberOfFats;         ///< Number of Fats the volume has
	 TUint32 iFatSizeInBytes;       ///< Size of a single Fat table in volume
	 TUint32 iRootClusterNum;       ///< Cluster number for Root directory, for Fat32
     TUint32 iFSInfoSectorNum;      ///< FSInfo Sector number. If 0, this means that corresponding value isn't set in BPB
     TUint32 iBkFSInfoSectorNum;    ///< backup FSInfo Sector number
    };

TUint32 CalculatePageOffsetInCluster(TUint32 aPos, TUint aPageSzLog2);
class CLruCache;
class TLeafDirData;
class CLeafDirCache;
/**
Fat file system mount implmentation, provides all that is required of a plug in
file system mount as well as Fat mount specific functionality
*/
class CFatMountCB : public CLocDrvMountCB, 
                    public MFileSystemSubType,
                    public MFileSystemClusterSize,
                    public CMountCB::MFileAccessor
    {
public:
    static CFatMountCB* NewL();
    ~CFatMountCB();
    void ConstructL();

public:
    
	//-- overrides from the abstract CMountCB
    void MountL(TBool aForceMount);
    TInt ReMount();
    void Dismounted();
    void VolumeL(TVolumeInfo& aVolume) const;
    void SetVolumeL(TDes& aName);
    void MkDirL(const TDesC& aName);
    void RmDirL(const TDesC& aName);
    void DeleteL(const TDesC& aName);
    void RenameL(const TDesC& anOldName,const TDesC& anNewName);
    void ReplaceL(const TDesC& anOldName,const TDesC& anNewName);
    void EntryL(const TDesC& aName,TEntry& anEntry) const;
    void SetEntryL(const TDesC& aName,const TTime& aTime,TUint aMask,TUint aVal);
    void FileOpenL(const TDesC& aName,TUint aMode,TFileOpen anOpen,CFileCB* aFile);
    void DirOpenL(const TDesC& aName,CDirCB* aDir);
    void RawReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,TInt anOffset,const RMessagePtr2& aMessage) const;
    void RawWriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,TInt anOffset,const RMessagePtr2& aMessage);
    void GetShortNameL(const TDesC& aLongName,TDes& aShortName);
    void GetLongNameL(const TDesC& aShortName,TDes& aLongName);
    void ReadSectionL(const TDesC& aName,TInt aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage);
    TInt CheckDisk();
    TInt ScanDrive();
    TInt ControlIO(const RMessagePtr2& aMessage,TInt aCommand,TAny* aParam1,TAny* aParam2);
    TInt Lock(TMediaPassword& aOld,TMediaPassword& aNew,TBool aStore);
    TInt Unlock(TMediaPassword& aPassword,TBool aStore);
    TInt ClearPassword(TMediaPassword& aPassword);
    TInt ErasePassword();
    TInt ForceRemountDrive(const TDesC8* aMountInfo,TInt aMountInfoMessageHandle,TUint aFlags);

    void FinaliseMountL();
    void FinaliseMountL(TInt aOperation, TAny* aParam1=NULL, TAny* aParam2=NULL);
    TInt MountControl(TInt aLevel, TInt aOption, TAny* aParam);
   	TTimeIntervalSeconds TimeOffset() const;

protected:

    /** CFatMountCB states */
    enum  TFatMntState
        {
        ENotMounted = 0, ///< 0, initial state, not mounted     (mount state is inconsistent)
        EMounting,       ///< 1, Mounting started               (mount state is inconsistent)
        EInit_R,         ///< 2, Initialised and not written    (mount state is Consistent)
        EInit_W,         ///< 3, Initialised and written        (mount state is Consistent)
        EFinalised,      ///< 4, Finalised                      (mount state is Consistent)
        EDismounted,     ///< 5, Dismounted                     (mount state is inconsistent)
        EInit_Forced,    ///< 6, forcedly mounted, special case (mount state is inconsistent)
        };

    inline TFatMntState State() const;
    inline void SetState(TFatMntState aState); 
    TInt OpenMountForWrite();
    TInt IsFinalised(TBool& aFinalised);

    /** 
        A wrapper around TFatDriveInterface providing its instantination and destruction.
        You must not create objects of this class, use DriveInterface() instead.
    */
    class XDriveInterface: public TFatDriveInterface
        {
        public:
        XDriveInterface() : TFatDriveInterface() {}
        ~XDriveInterface() {Close();}
        TBool Init(CFatMountCB* aMount) {return TFatDriveInterface::Init(aMount);}
        };

public:

    enum TRenMode {EModeReplace,EModeRename};

    TBool ConsistentState() const; 
    void CheckWritableL() const;
    void CheckStateConsistentL() const;

    inline TBool ReadOnly(void) const;
    inline void  SetReadOnly(TBool aReadOnlyMode);
    inline TInt StartCluster(const TFatDirEntry & anEntry) const;
    inline CRawDisk& RawDisk() const;
    inline CFatFileSystem& FatFileSystem() const;
    inline CFatTable& FAT() const;
    inline TInt ClusterSizeLog2() const;
    inline TInt SectorSizeLog2() const;
    inline TInt TotalSectors() const;
    inline TInt SectorsPerCluster() const;
    inline TInt ClusterBasePosition() const;
    inline TInt RootDirectorySector() const;
    inline TUint RootDirEnd() const;
    inline TUint32 RootClusterNum() const;
    
    inline TFatType FatType() const;
    inline TBool Is16BitFat() const;
    inline TBool Is32BitFat() const {return EFalse;} //-- dummy

    inline TUint32 MaxClusterNumber() const;
    inline TInt StartOfFatInBytes() const;
    inline TUint32 FirstFatSector() const;

    inline TInt NumberOfFats() const;
    inline TInt FatSizeInBytes() const;
    inline TInt ClusterRelativePos(TInt aPos) const;
    inline TUint StartOfRootDirInBytes() const;
	inline TUint32 UsableClusters() const;
    inline TBool IsBadCluster(TInt aCluster) const;
    inline TBool IsRuggedFSys() const;
    inline void SetRuggedFSys(TBool aVal);
	
    inline TInt RootIndicator() const;
    
    inline TBool IsRootDir(const TEntryPos &aEntry) const;
    inline CAsyncNotifier* Notifier() const;
	inline TFatDriveInterface& DriveInterface() const;
    
    void ReadUidL(TInt aCluster,TEntry& anEntry) const;
    
    void ReadDirEntryL(const TEntryPos& aPos,TFatDirEntry& aDirEntry) const;
    void WriteDirEntryL(const TEntryPos& aPos,const TFatDirEntry& aDirEntry);
    
    void DirReadL(const TEntryPos& aPos,TInt aLength,TDes8& aDes) const;
    void DirWriteL(const TEntryPos& aPos,const TDesC8& aDes);

    void ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const;
    void WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TInt& aBadcluster, TInt& aGoodcluster);
    void MoveToNextEntryL(TEntryPos& aPos) const;
    void MoveToDosEntryL(TEntryPos& aPos,TFatDirEntry& anEntry) const;
    void EnlargeL(TInt aSize);
    void ReduceSizeL(TInt aPos,TInt aLength);
    void DoDismount();

    
    
    void CheckIndirectionTableL(TInt& anEndCluster) const;
    void DoRenameOrReplaceL(const TDesC& anOldName,const TDesC& aNewName,TRenMode aMode,TEntryPos& aNewPos);
    void FindDosNameL(const TDesC& aName,TUint anAtt,TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry,TDes& aFileName,TInt anError) const;
    
    void Dismount();
    TBool IsEndOfClusterCh(TInt aCluster) const;
    void SetEndOfClusterCh(TInt &aCluster) const; 
    void InitializeRootEntry(TFatDirEntry & anEntry) const;

    TInt64 MakeLinAddrL(const TEntryPos& aPos) const;
	
    inline const TFatConfig& FatConfig() const;
    TBool CheckVolumeTheSame();
    
    void InvalidateLeafDirCache();
    
    void BlockMapReadFromClusterListL(TEntryPos& aPos, TInt aLength, SBlockMapInfo& aInfo);
    virtual TInt GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput);
    virtual TInt GetFileUniqueId(const TDesC& aName, TInt64& aUniqueId);
    virtual TInt Spare3(TInt aVal, TAny* aPtr1, TAny* aPtr2);
    virtual TInt Spare2(TInt aVal, TAny* aPtr1, TAny* aPtr2);
    virtual TInt Spare1(TInt aVal, TAny* aPtr1, TAny* aPtr2);

public:
    
    // interface extension implementation
    virtual TInt SubType(TDes& aName) const;
    virtual TInt ClusterSize() const;

private:

        /** An ad hoc internal helper object for using in DoFindL() method and its derivatives */
        class TFindHelper
        {
        public:
            TFindHelper() {isInitialised = EFalse;}
            void  InitialiseL(const TDesC&  aTargetName);
            TBool MatchDosEntryName(const TUint8* apDosEntryName) const;
            TBool TrgtNameIsLegalDos() const {ASSERT (isInitialised) ;return isLegalDosName;}   

        private:
            TFindHelper(const TFindHelper&);
            TFindHelper& operator=(const TFindHelper&);
        public:
            TPtrC       iTargetName;        ///< pointer to the aTargetName, used in DoRummageDirCacheL() as a parameter
        private:
            TBool       isInitialised  :1;  ///< ETrue if the object is initialised. It can be done only once.
            TBool       isLegalDosName :1;  ///< ETrue if iTargetName is a legal DOS name
            TShortName  iShortName;         ///< a short DOS name in XXXXXXXXYYY format generated from aTargetName
        };


        /** 
       	An ad hoc internal helper object for entry creations  
        */
	    class XFileCreationHelper
	    {
	    public:
	    	XFileCreationHelper();
	    	~XFileCreationHelper();
	    	void Close();
	    	void InitialiseL(const TDesC&  aTargetName);
	        TInt GetValidatedShortName(TShortName& aShortName) const;
	    	void CheckShortNameCandidates(const TUint8* apDosEntryName);
	
	        // inline functions for sets and gets
	        //  note all the get functions have been checked against initialisation status
	    	inline TBool 	IsInitialised() const;
	        inline TUint16	NumOfAddingEntries() const;
	        inline TEntryPos EntryAddingPos()const;
	        inline TBool 	IsNewEntryPosFound() const;
	    	inline TBool 	IsTrgNameLegalDosName() const;
	
	    	inline void	SetEntryAddingPos(const TEntryPos& aEntryPos);
	    	inline void	SetIsNewEntryPosFound(TBool aFound);
	
	    private:
	    	XFileCreationHelper(const XFileCreationHelper&);
	    	XFileCreationHelper& operator=(const TFindHelper&);
	
	    private:
	        TPtrC       iTargetName;		///< pointer to hold the long file name of the target file
	        TUint16		iNumOfAddingEntries;///< calculated number of entries to add
	        TEntryPos	iEntryAddingPos;	///< contains new entry position for adding if found any
	        TBool		isNewEntryPosFound; ///< flags whether the position for new entries is found
	        TBool       isInitialised	:1;	///< flags whether the object is initialised
	        TBool       isTrgNameLegalDosName	:1;	///< flags whether the target file name is a valid Dos name
	        /**
	        an array that holds short name candidates, prepared on initialisation.
	        */
	        RArray<TShortName>  iShortNameCandidates;
	    };


	TBool DoRummageDirCacheL(TUint anAtt,TEntryPos& aStartEntryPos,TFatDirEntry& aStartEntry,TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry,TDes& aFileName, const TFindHelper& aAuxParam, XFileCreationHelper* aFileCreationHelper, const TLeafDirData& aLeafDirData) const;
    TBool DoFindL(const TDesC& aName,TUint anAtt,TEntryPos& aStartEntryPos,TFatDirEntry& aStartEntry,TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry,TDes& aFileName,TInt anError, XFileCreationHelper* aFileCreationHelper, const TLeafDirData& aLeafDirData) const;
    void FindEntryStartL(const TDesC& aName,TUint anAtt,TFatDirEntry& anEntry,TEntryPos& aPos, XFileCreationHelper* aFileCreationHelper) const;

    void FindEntryStartL(const TDesC& aName,TUint anAtt,TFatDirEntry& anEntry,TEntryPos& aPos) const;

    void CheckFatForLoopsL(const TFatDirEntry& anEntry) const;
    void DoCheckFatForLoopsL(TInt aCluster,TInt& aPreviousCluster,TInt& aChangePreviousCluster,TInt& aCount) const;
	void InitializeL(const TLocalDriveCaps& aLocDrvCaps, TBool aIgnoreFSInfo=EFalse);
    void DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const;
    void DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TInt aLastcluster, TInt& aBadcluster, TInt& aGoodcluster);
    TBool IsUniqueNameL(const TShortName& aName,TInt aDirCluster);
    TBool FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos);
    void ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos);
    TBool GenerateShortNameL(TInt aDirCluster,const TDesC& aLongName,TShortName& aShortName, TBool aForceRandomize=EFalse);
    TInt FindLeafDirL(const TDesC& aName, TLeafDirData& aLeafDir) const;
	
	TInt GetDirEntry(TEntryPos& aPos,TFatDirEntry& aDosEntry,TFatDirEntry& aStartEntry,TDes& aLongFileName) const;
    TBool DoGetDirEntryL(TEntryPos& aPos,TFatDirEntry& aDosEntry,TFatDirEntry& aStartEntry,TDes& aLongFileName) const;

    void WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongFileName);
    void EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& anEntry);
    void EraseDirEntryL(const TEntryPos& aPos);
    void InitializeFirstDirClusterL(TInt aCluster,TInt aParentCluster);
    void AddDirEntryL(TEntryPos& aPos,TInt aNameLength);
    void ZeroDirClusterL(TInt aCluster);
    
    TInt DoWriteBootSector(TInt64 aMediaPos, const TFatBootSector& aBootSector) const;
    TInt DoReadBootSector(TInt64 aMediaPos, TFatBootSector& aBootSector) const;
    TInt ReadBootSector(TFatBootSector& aBootSector, TBool aDoNotReadBkBootSec=EFalse);

    TBool IsDirectoryEmptyL(TInt aCluster);
    void ExtendClusterListZeroedL(TInt aNumber,TInt& aCluster);
    void WritePasswordData();
	
    void WriteVolumeLabelL(const TDesC8& aVolumeLabel) const;
    TInt ReadVolumeLabelFile(TDes8& aLabel);
    void WriteVolumeLabelFileL(const TDesC8& aNewName);
    void FindVolumeLabelFileL(TDes8& aLabel, TEntryPos& aDosEntryPos, TFatDirEntry& aDosEntry);
    void GetVolumeLabelFromDiskL(const TFatBootSector& aBootSector);
    void TrimVolumeLabel(TDes8& aLabel) const;

    TInt    DoRunScanDrive();
    TBool   VolumeCleanL();
    void    SetVolumeCleanL(TBool aClean);
    TBool   VolCleanFlagSupported() const;

    void    DoUpdateFSInfoSectorsL(TBool) {return;} //-- dummy, only FAT32 has FSInfo sector
    void    UnFinaliseMountL();
    void    DoReMountL();

private:
	
    TBool ValidClusterNumber(TUint32 aCluster) const;
    void  CheckUnvisitedClustersL(const RBitVector& aFatBitVec) const;
	TInt  WalkClusterListL(RBitVector& aFatBitVec, TInt aCluster);
	void  ChkEntryL(RBitVector& aFatBitVec, const TFatDirEntry& anEntry);
	void  ChkDirL(RBitVector& aFatBitVec, TInt aDirCluster);

    CFatMountCB();

    TInt GetDosEntryFromNameL(const TDesC& aName, TEntryPos& aDosEntryPos, TFatDirEntry& aDosEntry);
    
    TInt MntCtl_DoCheckFileSystemMountable();

private:

    TBool iReadOnly : 1;        ///< if true, the drive is in read-only mode 
    TBool iRamDrive : 1;        ///< true if this is a RAM drive    

    TFatMntState iState;        ///< this mounnt internal state
    TFatType iFatType;          ///< FAT type, FAT12,16 or 32

    CLeafDirCache* iLeafDirCache;	///< A cache for most recently visited directories, only valid when limit is set bigger than 1
    HBufC* iLastLeafDir;        	///< The last visited directory, only valid when limit of iLeafDirCache is less than 1 
    TInt iLastLeafDirCluster;   	///< Cluster number of the last visited cluster, only valid when limit of iLeafDirCache is less than 1

	TFatVolParam iVolParam;     ///< FAT volume parameters, populated form the boot sector values.
    
    TInt iFirstFreeByte;        ///< First free byte in media (start of the data area on the volume)
    TUint32 iUsableClusters;    ///< Number of usable cluster on the volume 

    CFatTable* iFatTable;       ///< Pointer to the volume Fat 
    CRawDisk* iRawDisk;         ///< Pointer to the raw data interface class
    
    CAsyncNotifier* iNotifier;  ///< Async notifier for notifying user of Fat error conditions 
    CLruCache*      iLruUidCache;   ///< LRU Data cache used for dealing with executable files' UIDs

    XDriveInterface iDriverInterface; ///< the object representing interface to the drive, provides read/write access and notifiers
    TInt            iChkDiscRecLevel; ///< Check disk recursion level counter. A temporary measure. 
	TFatConfig      iFatConfig;       ///< FAT parametrers from estart.txt

	XFileCreationHelper iFileCreationHelper;

#ifdef  _DEBUG
    private:
    //-- debug odds and ends
    inline TBool IsWriteFail()const;
	inline void SetWriteFail(TBool aIsWriteFail);
	inline TInt WriteFailCount()const;
	inline void SetWriteFailCount(TInt aFailCount);
	inline void DecWriteFailCount();
	inline TInt WriteFailError()const;
	inline void SetWriteFailError(TInt aErrorValue);


	TBool   iIsWriteFail : 1; ///< Flag to indicate if write failed used for debugging
    TBool   iCBRecFlag   : 1; ///< in debug mode used for checking unwanted recursion

    TInt    iWriteFailCount;  ///< Write fail count for debug
	TInt    iWriteFailError;  ///< Write fail error to use for debug

#endif

friend class CFatFormatCB;
friend class CScanDrive;
friend class TFatDriveInterface;
    };




/**
Fat file system file subsession implmentation, provides all that is required of a plug in
file system file as well as Fat specific functionality
*/
class CFatFileCB : public CFileCB, public CFileCB::MBlockMapInterface, public CFileCB::MExtendedFileInterface
    {
public:
    CFatFileCB();
    ~CFatFileCB();
public:
    void RenameL(const TDesC& aNewName);
    void ReadL(TInt aPos,TInt& aLength,const TAny* aDes,const RMessagePtr2& aMessage);
    void WriteL(TInt aPos,TInt& aLength,const TAny* aDes,const RMessagePtr2& aMessage);
    void SetSizeL(TInt aSize);
    void SetEntryL(const TTime& aTime,TUint aMask,TUint aVal);
    void FlushDataL();
    void FlushAllL();
public:
    void CheckPosL(TUint aPos);
    void SetL(const TFatDirEntry& aFatDirEntry,TShare aShare,const TEntryPos& aPos);
    void CreateSeekIndex();
	
    inline TBool IsSeekIndex() const;

    // from MBlockMapInterface
	TInt BlockMap(SBlockMapInfo& aInfo, TInt64& aStartPos, TInt64 aEndPos);
	
	// from CFileCB
	virtual TInt GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput);

	// from CFileCB::MExtendedFileInterface
	virtual void ReadL(TInt64 aPos,TInt& aLength,TDes8* aDes,const RMessagePtr2& aMessage, TInt aOffset);
	virtual void WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aDes,const RMessagePtr2& aMessage, TInt aOffset);
	virtual void SetSizeL(TInt64 aSize);

private:
	inline CFatMountCB& FatMount() const;
    inline CFatTable& FAT();
	inline TInt ClusterSizeLog2();
	inline TInt ClusterRelativePos(TInt aPos);


    void FlushStartClusterL();
    TInt SeekToPosition(TInt aNewCluster,TInt aClusterOffset);
    void SetSeekIndexValueL(TInt aFileCluster,TInt aStoredCluster);
    void ResizeIndex(TInt aNewMult,TUint aNewSize);
    TInt CalcSeekIndexSize(TUint aSize);
    TBool IsSeekBackwards(TUint aPos);
    void ClearIndex(TUint aNewSize);
    void DoSetSizeL(TUint aSize,TBool aIsSizeWrite);
    void WriteFileSizeL(TUint aSize);

private:

    TUint32* iSeekIndex;    ///< Seek index into file
    TInt iSeekIndexSize;    ///< size of seek index
    TBool iAttPending;      
    TInt iStartCluster;     ///< Start cluster number of file
    TEntryPos iCurrentPos;  ///< Current position in file data
    TEntryPos iFileDirPos;  ///< File directory entry position
	TBool iFileSizeModified; 
    };
//

/**
Fat file system directory subsession implmentation, provides all that is required of a plug in
file system directory as well as Fat specific functionality
*/
class CFatDirCB : public CDirCB
    {
public:
    static CFatDirCB* NewL();
    ~CFatDirCB();
public:
    void ReadL(TEntry& anEntry);
    void StoreLongEntryNameL(const TDesC& aName);
public:
    void SetDirL(const TFatDirEntry& anEntry,const TDesC& aMatchName);
    inline CFatMountCB& FatMount();
private:
    CFatDirCB();
private:
    TFatDirEntry iEntry;       ///< Current directory entry in this directory
    TEntryPos    iCurrentPos;  ///< Current position in directory
    HBufC*       iMatch;       ///< Current name being searched in directory (Dos Name)
    HBufC*       iLongNameBuf; ///< Long name storage   
    TBool        iMatchUid;    ///< Flag to indicate if UID matches
    };

/**
Fat file system Format subsession implmentation, provides all that is required of a plug in
file system format as well as Fat specific functionality
*/
class CFatFormatCB : public CFormatCB
    {
public:
    CFatFormatCB();
    ~CFatFormatCB();
public:
	
    //-- overrides from CFormatCB
    void DoFormatStepL();

private:
    //-- overrides from CFormatCB
    TInt GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput);

private:	
    
    TInt DoProcessTVolFormatParam(const TVolFormatParam_FAT* apVolFormatParam);

    void CreateBootSectorL();
    void InitializeFormatDataL();
    void DoZeroFillMediaL(TInt64 aStartPos, TInt64 aEndPos);
     
    TInt InitFormatDataForVariableSizeDisk(TInt aDiskSizeInSectors);
    TInt InitFormatDataForFixedSizeDiskNormal(TInt aDiskSizeInSectors, const TLocalDriveCapsV6& aCaps);
    TInt InitFormatDataForFixedSizeDiskCustom(const TLDFormatInfo& aFormatInfo);
    TInt InitFormatDataForFixedSizeDiskUser(TInt aDiskSizeInSectors);
	void AdjustClusterSize(TInt aRecommendedSectorsPerCluster);
	TInt AdjustFirstDataSectorAlignment(TInt aBlockSize);
	TInt FirstDataSector() const;
    
    TInt HandleCorrupt(TInt aError);
    TInt BadSectorToCluster();
    void TranslateL();
    TInt DoTranslate(TPtr8& aBuf, RArray<TInt>& aArray);
    void RecordOldInfoL();
    TInt MaxFat12Sectors() const;
    TInt MaxFat16Sectors() const;
    inline TBool Is16BitFat() const;
    inline CFatMountCB& FatMount();
    inline CProxyDrive* LocalDrive();
    TFatType SuggestFatType() const;

private:
	
    TBool   iVariableSize;      ///< Flag to indicat if we are dealing with a variable size volume
    TInt    iBytesPerSector;    ///< Byte per sector of media
    TInt    iSectorSizeLog2;    ///< Sector size in log2
    TInt    iNumberOfFats;      ///< Number of Fats the volume will contain
    TInt    iReservedSectors;   ///< Number of reserved sectors in the volume
    TInt    iRootDirEntries;    ///< Nummer of root directory entries the root dir will have, specific to Fat12/16 volumes
    TInt    iSectorsPerCluster; ///< Sector per cluster ration the volume will be formatted with
    TInt    iSectorsPerFat;     ///< Number of sectors the Fat uses
    TInt    iMaxDiskSectors;       ///< number of sectors the volume has
    TFormatInfo iFormatInfo;    ///< format information for a custom format
    TBuf8<16>   iFileSystemName;///< Buffer to contain the volume name 
    TInt    iHiddenSectors;     ///< Number of hidden sectors in the volume
    TInt    iNumberOfHeads;     ///< Number of heads the media device has, not used so far as only used on solid state media.
    TInt    iSectorsPerTrack;   ///< Number of sectors the media device has, not used so far as only used on solid state media.
    RArray<TInt> iBadClusters;  ///< Array of bad cluster numbers
    RArray<TInt> iBadSectors;   ///< Array of bad sector numbers
    TBool iDiskCorrupt;         ///< Disk is corrupt when format or not
    TInt iOldFirstFreeSector;
    TInt iOldSectorsPerCluster;
    };


/**
Required file system class used by file server to create the file system objects
*/
class CFatFileSystem : public CFileSystem
    {
public:
    static CFatFileSystem* New();
    ~CFatFileSystem();
public:
    TInt Install();
    CMountCB* NewMountL() const;
    CFileCB* NewFileL() const;
    CDirCB* NewDirL() const;
    CFormatCB* NewFormatL() const;
    void DriveInfo(TDriveInfo& anInfo,TInt aDriveNumber) const;
    TInt DefaultPath(TDes& aPath) const;
    TBool IsExtensionSupported() const;
	TBool GetUseLocalTime() const;
	void SetUseLocalTime(TBool aFlag);
	TInt GetInterface(TInt aInterfaceId, TAny*& aInterface,TAny* aInput);
protected:
    CFatFileSystem();
	/**
	If true, then local time will be used when writing timestamps to FS. When reading,
	timestamps will be assumed local and converted back to UTC.
	At present, this behaviour will also be conditional upon a particular drive being logically removable.
	*/
	TBool iUseLocalTimeIfRemovable;
    };



/**
Locale utilities allows the file system to call into a specific locale for tasks
such as Dos name to unicode conversions and testing the legality of characters for
any given locale.
*/
class LocaleUtils

    {
public:
	static void ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction=TFatUtilityFunctions::EOverflowActionTruncate);
	static void ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction=TFatUtilityFunctions::EOverflowActionTruncate);
	static TBool IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars=EFalse);
    };

//

TPtrC RemoveTrailingDots(const TDesC& aName);

/**
Indicates if a number passed in is a power of two
@return ETrue if aVal is a power of 2 
*/
inline TBool IsPowerOf2(TUint32 aVal);

/**
Calculates the log2 of a number

@param aNum Number to calulate the log two of
@return The log two of the number passed in
*/
TUint32 Log2(TUint32 aVal);

/** @return 2^aVal*/
inline TUint32 Pow2(TUint32 aVal);


/**
Converts Dos time (from a directory entry) to TTime format

@param aDosTime Dos format time
@param aDosDate Dos format Date
@return TTime format of Dos time passed in 
*/
TTime DosTimeToTTime(TInt aDosTime,TInt aDosDate);
/**
Converts TTime format to Dos time format

@param aTime TTime to convert to Dos time
@return Dos time format
*/
TInt DosTimeFromTTime(const TTime& aTime);
/**
Converts TTime format to Dos time format

@param aTime TTime to convert to Dos Date
@return Dos Date format
*/
TInt DosDateFromTTime(const TTime& aTime);
/**
Converts Dos Directory entry format to 8.3 format

@param aDosName Directory entry format with space delimeter
@return 8.3 Dos filename format
*/
TBuf8<12> DosNameToStdFormat(const TDesC8& aDosName);
/**
Converts 8.3 format to Dos Directory entry format 

@param aStdFormatName 8.3 Dos filename format
@return Directory entry format with space delimeter
*/
TBuf8<12> DosNameFromStdFormat(const TDesC8& aStdFormatName);
/**
Fault function calls user panic with a fault reason

@param Enumerated fault reason
*/
void Fault(TFault aFault);
/**
calculates the number of VFat directory entries for a given file/directory name length

@param the length in characters of the name
@return the number of VFat entries required
*/
TInt NumberOfVFatEntries(TInt aNameLength);
/**
Calculates the check sum for a standard directory entry

@param the Dos name for the directory entry
@return the checksum
*/
TUint8 CalculateShortNameCheckSum(const TDesC8& aShortName);


TBool IsLegalDosName(const TDesC&  aName,TBool anAllowWildCards,TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation);
TBool IsLegalDOSNameChar(TChar aCharacter, TBool aUseExtendedChars);



//-----------------------------------------------------------------------------

/**
    This class represents a bit vector i.e. an array of bits. Vector size can be 1..2^32 bits.
*/
class RBitVector
    {
 public:
    
    RBitVector(); //-- Creates an empty vector. see Create() methods for memory allocation
   ~RBitVector(); 
    
    void Close(); 
    
    TInt Create(TUint32 aNumBits);
    void CreateL(TUint32 aNumBits);

    inline TUint32 Size() const;

    //-- single bit manipulation methods
    inline TBool operator[](TUint32 aIndex) const;
    inline void SetBit(TUint32 aIndex);
    inline void ResetBit(TUint32 aIndex);
    inline void InvertBit(TUint32 aIndex);
    inline void SetBitVal(TUint32 aIndex, TBool aVal);
    
    void Fill(TBool aVal);
    void Fill(TUint32 aIndexFrom, TUint32 aIndexTo, TBool aVal);
    void Invert();
   
    TBool operator==(const RBitVector& aRhs) const; 
    TBool operator!=(const RBitVector& aRhs) const;

    //-- logical operations between 2 vectors. 
    void And(const RBitVector& aRhs);
    void Or (const RBitVector& aRhs);
    void Xor(const RBitVector& aRhs);

    TBool Diff(const RBitVector& aRhs, TUint32& aDiffIndex) const;

    /** Bit search specifiers */
    enum TFindDirection
        {
        ELeft,      ///< Search from the given position to the left (towards lower index)
        ERight,     ///< Search from the given position to the right (towards higher index)
        ENearestL,  ///< Search in both directions starting from the given position; in the case of the equal distances return the position to the left
        ENearestR   ///< Search in both directions starting from the given position; in the case of the equal distances return the position to the right

        //-- N.B the current position the search starts with isn't included to the search.
        };

    TBool Find(TUint32& aStartPos, TBool aBitVal, TFindDirection aDir) const;

    /** panic codes */
    enum TPanicCode
        {
        EIndexOutOfRange,       ///< index out of range
        EWrondFindDirection,    ///< a value doesn't belong to TFindDirection
        ESizeMismatch,          ///< Size mismatch for binary operators
        ENotInitialised,        ///< No memory allocated for the array
        ENotImplemented,        ///< functionality isn't implemented
        };

 protected:
    
    //-- these are outlawed. Can't use them because memory allocator can leave and we don't have conthrol on it  in these methods. 
    RBitVector(const RBitVector& aRhs);            
    RBitVector& operator=(const RBitVector& aRhs); 
  
    void Panic(TPanicCode aPanicCode) const;

    inline TUint32 WordNum(TUint32 aBitPos) const;
    inline TUint32 BitInWord(TUint32 aBitPos) const;

 private:
    TBool FindToRight(TUint32& aStartPos, TBool aBitVal) const;
    TBool FindToLeft (TUint32& aStartPos, TBool aBitVal) const;
    TBool FindNearest(TUint32& aStartPos, TBool aBitVal, TBool aToLeft) const;
   
    inline TUint32 MaskLastWord(TUint32 aVal) const; 
    inline TBool ItrLeft(TUint32& aIdx) const;
    inline TBool ItrRight(TUint32& aIdx) const;


 protected:

    TUint32   iNumBits; ///< number of bits in the vector
    TUint32*  ipData;   ///< pointer to the data 
    TUint32   iNumWords;///< number of 32-bit words that store bits
    };


//-----------------------------------------------------------------------------


#include "sl_std.inl"
#include "sl_bpb.inl"
#include "fat_dir_entry.inl"

#endif //SL_STD_H
