userlibandfileserver/fileserver/automounter/automounter.cpp
changeset 0 a41df078684a
child 6 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/automounter/automounter.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,843 @@
+// Copyright (c) 1998-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:
+
+/**
+@file
+@internalTechnology
+*/
+
+#include <e32cmn.h>
+#include <f32ver.h>
+#include <u32std.h>
+#include <f32file.h>
+
+
+
+#include "filesystem_automounter.h"
+#include "automounter.h"
+
+
+//-----------------------------------------------------------------------------
+
+void Fault(TFault aFault)
+    {
+    _LIT(KPanicName, "AutoMounter_fsy");
+    User::Panic(KPanicName, aFault);
+    }
+
+
+//-----------------------------------------------------------------------------
+
+/**
+    Factory function, Create a new object of this file system 
+*/
+extern "C" 
+{
+EXPORT_C CFileSystem* CreateFileSystem()
+    {
+    return CAutoMounterFileSystem::New();
+    }
+}
+
+
+//#######################################################################################################################################
+//#  CAutoMounterFileSystem class implementation
+//#######################################################################################################################################
+
+/**
+    Factory method
+*/
+CAutoMounterFileSystem* CAutoMounterFileSystem::New()
+    {
+    CAutoMounterFileSystem* pThis = new CAutoMounterFileSystem();
+    return pThis;
+    }
+
+
+CAutoMounterFileSystem::CAutoMounterFileSystem() 
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::CAutoMounterFileSystem() [0x%x]"), this);
+
+    SetState(EInvalid);
+    }   
+
+CAutoMounterFileSystem::~CAutoMounterFileSystem()
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::~CAutoMounterFileSystem() [0x%x]"), this);
+    }
+
+//-----------------------------------------------------------------------------
+
+/**
+    Install iand initialise file system.
+*/
+TInt CAutoMounterFileSystem::Install()
+    {
+   
+    SetState(ENotInitialised);
+
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::Install() [0x%x]"), this);
+
+    iVersion=TVersion(KF32MajorVersionNumber,KF32MinorVersionNumber,KF32BuildVersionNumber);
+
+    InitialiseFileSystem();
+
+    return SetName(&KFileSystemName_AutoMounter);
+    }
+
+
+//-----------------------------------------------------------------------------
+/** 
+    Create a new mount control block. 
+    This method migh be called by the file server in some unusual cases, when the actual mount is needed only temporarily to get access to the 
+    corresponding media driver. E.g. TDrive::ForceRemountDrive()
+    Produce the _default_ file system mount
+*/
+CMountCB* CAutoMounterFileSystem::NewMountL() const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::NewMountL() [0x%x]"), this);
+    ASSERT(State() == EInitialised);
+
+    __PRINT1(_L("#<<- producing the _default_ filesystem:%S"), &iFSNames[KDefaultFSNo]);
+
+    CFileSystem* pFS = GetChildFileSystem(KDefaultFSNo);
+    ASSERT(pFS);
+
+    return pFS->NewMountL();
+    }
+
+//-----------------------------------------------------------------------------
+/** 
+    Create a new file. 
+*/
+CFileCB* CAutoMounterFileSystem::NewFileL() const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::NewFileL() [0x%x]"), this);
+    Fault(EMustNotBeCalled);
+    return NULL;
+    }
+
+//-----------------------------------------------------------------------------
+/** 
+    Create a new directory object 
+*/
+CDirCB* CAutoMounterFileSystem::NewDirL() const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::NewDirL() [0x%x]"), this);
+    Fault(EMustNotBeCalled);
+    return NULL;
+    }
+
+//-----------------------------------------------------------------------------
+/** 
+    Create a new media formatter 
+*/
+CFormatCB* CAutoMounterFileSystem::NewFormatL() const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::NewFormatL() [0x%x]"), this);
+    Fault(EMustNotBeCalled);
+    return NULL;
+    }
+
+//-----------------------------------------------------------------------------
+/** 
+    Return the drive info
+*/
+void CAutoMounterFileSystem::DriveInfo(TDriveInfo& anInfo,TInt aDriveNumber) const
+    {
+    //!!!!!!!!!!!! This method shall be made the same as FAT, exFAT etc. 
+    //!! General idea: make all this code common for all filesystems and put it into the file server
+    //!! The problem: need to have another exported method. Actually, the generic code can be placed to CFileSystem::DriveInfo()
+    //!! despite it a pure virtual. 
+
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::DriveInfo() [0x%x]"), this);
+
+    if(!IsValidLocalDriveMapping(aDriveNumber))
+        return;
+
+    TLocalDriveCapsV2Buf localDriveCaps;
+    
+    TInt r = KErrNone;
+
+    // is the drive local?
+    if (!IsProxyDrive(aDriveNumber))
+        {
+        // if not valid local drive, use default values in localDriveCaps
+        // if valid local drive and not locked, use TBusLocalDrive::Caps() values
+        // if valid drive and locked, hard-code attributes
+        r = GetLocalDrive(aDriveNumber).Caps(localDriveCaps);
+        }
+    else  // this need to be made a bit nicer
+        {   
+        CExtProxyDrive* pD = GetProxyDrive(aDriveNumber);
+        if(pD)
+            r = pD->Caps(localDriveCaps);
+        else
+            r = KErrNotReady;   // What should the behaviour really be here?
+        }
+
+    if (r != KErrLocked )
+        {
+        anInfo.iMediaAtt=localDriveCaps().iMediaAtt;
+        }
+    else
+        {
+        anInfo.iMediaAtt = KMediaAttLocked | KMediaAttLockable | KMediaAttHasPassword;
+        }
+
+    anInfo.iType=localDriveCaps().iType;
+    anInfo.iDriveAtt=localDriveCaps().iDriveAtt;
+    }
+
+//-----------------------------------------------------------------------------
+
+#ifdef _DEBUG
+/**
+    Called by File Server before deleting File System object.    
+*/
+TInt CAutoMounterFileSystem::Remove()
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::Remove() [0x%x]"), this);
+    return CFileSystem::Remove();
+    }
+
+//-----------------------------------------------------------------------------
+
+/**
+*/
+TBool CAutoMounterFileSystem::QueryVersionSupported(const TVersion& aVer) const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::QueryVersionSupported() [0x%x]"), this);
+    return CFileSystem::QueryVersionSupported(aVer);
+    }
+
+#endif
+
+//-----------------------------------------------------------------------------
+
+/**
+    Find out if drive extensions are supported. In order to have consistent behaviour, _all_ child 
+    file systems shall behave the same way.   
+    
+    @return ETrue if drive extensions are supported.    
+*/
+TBool CAutoMounterFileSystem::IsExtensionSupported() const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::IsExtensionSupported() [0x%x]"), this);
+    
+    ASSERT(State() == EInitialised && iFSNames.Count() > 1);
+
+
+    //-- in debug mode check file systems compatibility: ALL childs must support this feature
+    for(TUint i=0; i<iFSNames.Count(); ++i)
+        {
+        if( !(GetChildFileSystem(i)->IsExtensionSupported()))
+            {
+            DBG_STATEMENT(Fault(EIncompatibleFileSystems));
+            __PRINT(_L("#<<- ::IsExtensionSupported(): Incompatible file sytems!"));
+            return EFalse;
+            }
+        }
+
+
+    return ETrue; 
+    }
+
+//-----------------------------------------------------------------------------
+
+/** 
+    Return the initial default path. 
+*/
+TInt CAutoMounterFileSystem::DefaultPath(TDes& aPath) const
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::DefaultPath() [0x%x]"), this);
+
+    aPath=_L("?:\\");
+    aPath[0] = (TUint8) RFs::GetSystemDriveChar();
+    return KErrNone;
+    }
+
+
+//-----------------------------------------------------------------------------
+
+/**
+    Additional interfaces support.    
+*/
+TInt CAutoMounterFileSystem::GetInterface(TInt aInterfaceId, TAny*& aInterface, TAny* aInput)
+    {
+
+    __PRINT2(_L("#<<- CAutoMounterFileSystem::GetInterface(id:%d) [0x%x]"), aInterfaceId, this);
+
+    switch(aInterfaceId)
+        {
+        //-- It is this filesystem private interface.
+        case EExtendedFunctionality:
+        aInterface = (CFileSystem::MFileSystemExtInterface*)this;
+        return KErrNone;
+        
+        //-- a special case for child filesystems.
+        //-- ALL of them must respond to this interface query exactly the same way. I.e. It is impossible
+        //-- to have some of the child FS supporting it and some not.
+        case EProxyDriveSupport:
+        return DoProcessProxyDriveSupport();
+
+
+        default:
+        //-- This is the request to other (child file system) from the file server
+        //-- Actually, this part must never be called. File Server shall query the file system interfaces _after_ mounting the concrete FS 
+        //-- calling TDrive::iCurrentMount->FileSystem().GetInterface() 
+        ASSERT(0);
+        return CFileSystem::GetInterface(aInterfaceId, aInterface, aInput);
+        
+        }
+    }
+
+//-----------------------------------------------------------------------------
+/**
+    @return Boolean exclusive OR between a1 and a2
+*/
+TBool BoolXOR(TBool a1, TBool a2)
+    {
+    if(!a1 && !a2)        
+        return EFalse;
+    else if(a1 && a2)
+        return EFalse;
+    else
+        return ETrue;
+    }
+
+//-----------------------------------------------------------------------------
+
+/**
+    Find out if _all_ child file systems support the proxy drive. All childs shall behave exactly the same way.
+    @return KErrNone if all child file systems support proxy drives, or KErrNotSupported if all of them do not.
+*/
+TInt CAutoMounterFileSystem::DoProcessProxyDriveSupport()
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::DoProcessProxyDriveSupport[0x%x]"), this);
+    ASSERT(State() == EInitialised);
+
+    const TUint cnt = iFSNames.Count();
+    ASSERT(cnt > 1);
+
+    
+    //-- query the default filesystem #0
+    const TBool bRes = GetChildFileSystem(KDefaultFSNo)->IsProxyDriveSupported();
+
+    //-- query the rest of child filesystems
+    for(TUint i=1; i<cnt; ++i)
+        {
+        const TBool b = GetChildFileSystem(i)->IsProxyDriveSupported();
+
+        if(BoolXOR(b, bRes))
+            Fault(EIncompatibleFileSystems);
+        }
+
+
+    return  bRes ? KErrNone : KErrNotSupported;
+    }
+
+//-----------------------------------------------------------------------------
+/**
+    Get the child file system name by its index (enumerator).
+    
+    @param  aFsNumber   index of the child FS 0...KMaxTInt
+    @param  aFsName     on success the child file system name will be placed into this buffer  
+
+    @return KErrNone        if there is a child FS name with index 'aFsNumber' (child FS 'aFsNumber' is supported by automounter)
+            KErrNotFound    if child FS 'aFsNumber' is not supported
+*/
+TInt CAutoMounterFileSystem::GetSupportedFileSystemName(TInt aFsNumber, TDes& aFsName) const
+    {
+    __PRINT2(_L("#<<- CAutoMounterFileSystem::GetSupportedFileSystemName[0x%x](%d)"), this, aFsNumber);
+
+    if(aFsNumber == RFs::KRootFileSystem)
+        {//-- this is a name query for "root filesystem" or automounter
+        aFsName = Name(); //-- ourselves
+        return KErrNone;
+        }
+    
+    //-- this is a query for one of the child filesystems
+    if((TUint)aFsNumber < iFSNames.Count())
+        {
+        aFsName = iFSNames[aFsNumber]; 
+        return KErrNone;
+        }
+
+    
+    return KErrNotFound;
+    }
+
+
+//-----------------------------------------------------------------------------
+/**
+    This is the only factory method that can be called by file server for this file system.
+    In this method the automounter sequentially tries to mount every child and on success produces the corresponding CMountCB object.
+
+    @param  apDrive         pointer to the TDrive, child FS will need this to access media.
+    @param  apFileSystem    on return will contain the pointer to the CFileSystem that has produced the proped CMountCB if 
+                            one of the child file system has recognised the volume.
+    @param  aForceMount     if ETrue the appropriate child FS (designated by aFsNameHash) will be forcedly mounted on the volume. for volume formatting purposes.
+    @param  aFsNameHash     if !=0 specifies the file system name, see TVolFormatParam::CalcFSNameHash(). 0 means "file system name is not specified"
+
+    @return pointer to the constructed CMountCB by one of the child file systems (and pointer to this child FS in apFileSystem)
+            NULL if it was impossible to produce proper CMountCB object.
+
+*/
+CMountCB* CAutoMounterFileSystem::NewMountExL(TDrive* apDrive, CFileSystem** apFileSystem, TBool aForceMount, TUint32 aFsNameHash)
+    {
+    __PRINT4(_L("#<<- CAutoMounterFileSystem::NewMountExL[0x%x] drv:%d, ForceMount:%d, FSNameHash:0x%x"), this, apDrive->DriveNumber(), aForceMount, aFsNameHash);
+
+    ASSERT(State() == EInitialised && apDrive);
+
+    //-- This method is usually called from the appropriate drive thread; this file system is intended to be bound to
+    //-- removable drives. Having removable drive runnind in the main file server thread means that something is terribly wrongly configured.
+    if(apDrive->IsSynchronous())
+        Fault(EWrongDriveAttributes);
+
+    if(iFSNames.Count() < 2)
+        Fault(EWrongConfiguration);
+
+
+    //-- if aForceMount is true, this means that the TDrive tries mount the filesystem by force for formatting because normal mounting has failed before. 
+    //-- in our case it means that the file system on the volume hadn't been recognised by any child FS.
+    //-- aFsNameHash shall designate the file system to be forcedly mounted. Depending on this the appropriat CMounCB object will be produced.
+    //-- if aFsNameHash is 0, i.e. not provided, this method will fail with KErrNotFound because it is impossible to select appropriat child FS.
+    if(aForceMount)
+        {
+        if(aFsNameHash == 0)
+            {//-- the file system to mount forcedly is not specified
+            __PRINT(_L("#<<- Unable to select appropriate child FS for formatting!"));
+            User::Leave(KErrNotFound);
+            }
+        else
+            {//-- try to find appropriate child FS by its name hash
+            CFileSystem *pFS = GetChildFileSysteByNameHash(aFsNameHash);
+            if(!pFS)
+                {
+                __PRINT(_L("#<<- no child FS found by its name hash!"));
+                ASSERT(0);
+                User::Leave(KErrNotFound);
+                }
+
+            CMountCB* pMount = pFS->NewMountL();
+            ASSERT(pMount);
+
+            *apFileSystem = pFS; 
+            return pMount;
+            }
+        }//if(aForceMount)
+
+
+
+    //-- try instantiate a new CMountCB depending on the file system on the media
+
+    CMountCB* pMatchedMount;
+    TInt nRes = TryMountFilesystem(apDrive, &pMatchedMount, apFileSystem);
+    
+    if(nRes == KErrNone)
+        {
+        ASSERT(pMatchedMount);
+        return pMatchedMount;
+        }
+
+
+
+    User::Leave(nRes);
+    return NULL;
+    }
+
+//-----------------------------------------------------------------------------
+/**
+    Initialise this file system. Reads and processes configuration, fills in file system names container, etc. 
+*/
+void CAutoMounterFileSystem::InitialiseFileSystem()
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::InitialiseFileSystem() [0x%x]"), this);
+
+    ASSERT(State() == ENotInitialised);
+
+    TInt nRes;
+    
+
+    //-- 1. initialise the array of file system names. These names shall be listed in a config string.
+    //-- the config string is taken from estart.txt usually and its format is like this: 
+    //-- section: [AutoMounter] and property "FSNames fat,exfat"
+    //-- in debug version a special text property can override the config string. This allows controlling automounter from
+    //-- the test environment.
+
+    TBuf8<0x100> buf(0);   
+    TBuf<0x100>  fsName;   
+
+
+#ifdef _DEBUG
+    const TUid KSID_Test1={0x10210EB3}; //-- SID of the test that will define and set test property to control volume mounting
+    const TUint KPropKey = 0; //-- property key
+
+    //-- in debug mode the property will override the estart.txt config
+    if(RProperty::Get(KSID_Test1, KPropKey, buf) == KErrNone)
+        {
+        __PRINT(_L("#<<- reading config from the debug propery..."));
+        }
+    else
+#endif
+        {
+        __PRINT(_L("#<<- reading config from estart.txt..."));
+        _LIT8(KSection,  "AutoMounter");
+        _LIT8(KProperty, "FSNames");
+
+        nRes = F32Properties::GetString(KSection, KProperty, buf);
+        if(!nRes)
+            Fault(EPluginInitialise);
+        }
+
+
+    fsName.Copy(buf);
+    __PRINT1(_L("#<<- config:'%S'"), &fsName);
+
+    //-- parse CSV config line and fill in the file system names array
+    const TChar chDelim = ','; //-- token delimiter, comma
+    buf.Trim();
+    TPtrC8 ptrCurrLine(buf);
+    for(TInt i=0; ;++i)
+        {
+        const TInt delimPos = ptrCurrLine.Locate(chDelim);
+        if(delimPos <= 0)
+            {
+            fsName.Copy(ptrCurrLine);
+            }
+        else
+            {
+            TPtrC8 temp(ptrCurrLine.Ptr(), delimPos);
+            fsName.Copy(temp);
+            }
+
+        fsName.Trim();
+        __PRINT2(_L("#<<- child FS[%d]: '%S'"), i, &fsName);
+
+        
+        if(fsName.Length() <= 0) 
+            Fault(EPluginInitialise);
+
+        //-- check if the FS name being appended is unique
+        for(TUint j=0; j<iFSNames.Count(); ++j)
+            {
+            if(iFSNames[j] == fsName)
+                {
+                Fault(EPluginInitialise);
+                }
+            }
+        
+        
+        nRes = iFSNames.Append(fsName);
+        ASSERT(nRes ==KErrNone);
+        
+        if(delimPos <=0 )
+            break;
+
+        ptrCurrLine.Set(ptrCurrLine.Ptr()+delimPos+1, ptrCurrLine.Length()-delimPos-1);
+        }
+
+
+    SetState(EInitialised);
+
+    //-- 2. check that the file server has all filesystems we need instantiated and stored in a global container
+    TUint cnt = iFSNames.Count();
+    if(cnt < 2)
+        {
+        __PRINT(_L("#<<- ::InitialiseFileSystem(): too few File Systems bound!"));
+        Fault(EPluginInitialise);
+        }
+
+    while(cnt--)
+        {
+        GetChildFileSystem(cnt);
+        }
+
+
+    }
+
+
+
+//-----------------------------------------------------------------------------
+/**
+    Tries to find out if some of the child file systems can be mounted on the given volume.
+
+    @param  apDrive         pointer to the TDrive, child FS will need this to access media.
+    @param                  on return will contain the pointer to the CMountCB object if some of the childs has decided that it can be mounted.
+    @param  apFS            on return will contain the pointer to the CFileSystem that has produced the proped CMountCB if 
+
+    @return KErrNone on success, otherwise standard error code.
+
+*/
+TInt CAutoMounterFileSystem::TryMountFilesystem(TDrive* apDrive, CMountCB** apMount, CFileSystem** apFS)
+    {
+    __PRINT1(_L("#<<- CAutoMounterFileSystem::TryMountFilesystem()[0x%x]"), this);
+
+    const TInt KNumFS = iFSNames.Count();
+  
+    ASSERT(State() == EInitialised && (KNumFS >1));
+
+
+    *apMount = NULL;
+    *apFS    = NULL;
+    
+    
+    TInt nRes;
+    TInt cntFS;
+    CMountCB*       pMountCB = NULL;
+    CFileSystem*    pMatchedFS = NULL;
+
+    for(cntFS=0; cntFS < KNumFS; ++cntFS)
+        {
+
+        __PRINT2(_L("#<<-@@ trying FS[%d]:%S"), cntFS, &iFSNames[cntFS]);
+
+        CFileSystem* pFS = GetChildFileSystem(cntFS); //-- Find current filesystem object in the FileServer's global container
+
+        //-- 2. create CMountCB instance and set it up
+        pMountCB = NULL;
+        
+        TRAP(nRes, pMountCB = pFS->NewMountL());
+        if(nRes != KErrNone)
+            {
+            return KErrNoMemory;
+            }
+
+        ASSERT(pMountCB);
+        pMountCB->SetDrive(apDrive);
+
+        
+        //-- 2.1 Firstly try using special CMountCB interface to find out if current FS can be mounted on this media
+        nRes = pMountCB->CheckFileSystemMountable();
+        if(nRes == KErrNotSupported)
+            {
+            //-- file system doesn't support this feature,
+            //-- 2.2 try to check the file system by mounting and dismounting later. It can result in some long activity, like FAT scanning etc.
+            TRAP(nRes, pMountCB->MountL(EFalse));
+            pMountCB->Dismounted(); //-- dismount the mountCB, it will be required in dismounted state anyway 
+            }
+        
+        //-- 2.3 analyse the result of mounting 
+        if(nRes != KErrNone)
+            {
+            if(nRes == KErrLocked)
+                {//-- this is a special case; The media (SD card for example) is locked. 
+                //-- Pretend that everything is OK and return CMountCB instance that is produced by the _default_ file system.
+                //-- locked media case will be handled by the file server later.
+                ASSERT(cntFS == KDefaultFSNo); //-- the default FS is tried first and must detect the locked media
+                pMatchedFS = pFS;
+                __PRINT(_L("#<<-@@ The media is LOCKED !"));
+                break;
+                }
+
+            //-- failed to mount the file system, most likey it is not recognised
+            pMountCB->Close(); //-- this is a self-destructing object!
+            pMountCB = NULL;
+            __PRINT(_L("#<<-@@ Mount FAILED !"));
+            }
+        else
+            {
+            //-- mounted OK, the file system is recognised
+            __PRINT(_L("#<<-@@ Mount OK!"));
+            
+            pMatchedFS = pFS;
+            break;
+            }
+    
+        }//for(cntFS=0; cntFS<KNumFS; ++cntFS)
+
+    if(cntFS >= KNumFS)
+        {//-- no one from the FS factories recognised the file system
+        __PRINT1(_L("#<<- ::TryMountFilesystem()[0x%x] No file system recognised!"), this);
+        
+        SetName(&KFileSystemName_AutoMounter); 
+        return KErrCorrupt;
+        }
+
+    ASSERT(pMountCB && pMatchedFS); 
+    *apMount = pMountCB;
+    *apFS    = pMatchedFS;
+    
+    //-- set this FS name to the name of recognised FS. In this case the automounter "pretends" to be one of the child file systems on 
+    //-- successful mounting. This behaviour was considered to be incorrect.
+    //TPtrC fsName = pMatchedFS->Name();
+    //SetName(&fsName); 
+
+    return KErrNone;
+
+    }
+
+//-----------------------------------------------------------------------------
+/**
+    get the child file system object by the index in file child system names container
+    
+    @param  aIndex  index in the iFSNames
+    @return pointer to the FS object if it is found, NULL otherwise
+*/
+CFileSystem* CAutoMounterFileSystem::GetChildFileSystem(TUint aIndex) const
+    {
+    ASSERT(State() == EInitialised && (iFSNames.Count() >1) && aIndex < iFSNames.Count());
+
+    const TDesC& fsName = iFSNames[aIndex]; //-- registered child file system name
+    CFileSystem* pFS = GetFileSystem(fsName); //-- Find filesystem object in the FileServer's global container
+
+    if(!pFS)
+        {
+        __PRINT1(_L("#<<- CAutoMounterFileSystem::GetChildFileSystem() FileServer doesn't have FS:%S Added!"), &fsName);
+        Fault(EFileSysNotAdded);
+        }
+
+    return pFS;
+    }
+
+//-----------------------------------------------------------------------------
+/**
+    Find the child file system object by the file system name name hash. 
+    @param  aFsNameHash FS name hash
+    @return pointer to the FS object if it is found, NULL otherwise
+*/
+CFileSystem* CAutoMounterFileSystem::GetChildFileSysteByNameHash(TUint32 aFsNameHash) const
+    {
+    ASSERT(State() == EInitialised && (iFSNames.Count() >1) && aFsNameHash);
+    
+    for(TUint i=0; i<iFSNames.Count(); ++i)
+        {
+        if(aFsNameHash == iFSNames.GetStringHash(i))
+            {
+            const TDesC& fsName = iFSNames[i];        //-- registered child file system name
+            __PRINT2(_L("#<<- ::GetChildFileSysteByNameHash() found FsName:%S by hash:0x%x"), &fsName, aFsNameHash);
+            CFileSystem* pFS = GetFileSystem(fsName); //-- Find filesystem object in the FileServer's global container
+            ASSERT(pFS);
+            return pFS;
+            }
+   
+        }
+   
+    __PRINT1(_L("#<<- ::GetChildFileSysteByNameHash() No FS name found by hash:0x%x"), aFsNameHash);
+   
+    return NULL;
+    }
+
+
+
+
+//#######################################################################################################################################
+//#     XStringArray implementation
+//#######################################################################################################################################
+
+XStringArray::XStringArray()
+    {
+    }
+
+XStringArray::~XStringArray()
+    {
+    Reset();
+    iStrings.Close();
+    }
+
+//-----------------------------------------------------------------------------
+void XStringArray::Reset()
+    {
+    iStrings.ResetAndDestroy();
+    }
+
+//-----------------------------------------------------------------------------
+const TDesC& XStringArray::operator[](TUint aIndex) const
+    {
+    if(aIndex >= (TUint)iStrings.Count())
+        Panic(EIndexOutOfRange);
+
+    HBufC* des=iStrings[aIndex];
+    return *des;
+    }
+
+//-----------------------------------------------------------------------------
+/**
+    Append file system name to the container. The name is converted to upper case.
+    @param aString name descriptor.
+    @return standard error code
+*/
+TInt XStringArray::Append(const TDesC& aString)
+    {
+    HBufC* pBuf = aString.Alloc();
+    if(!pBuf) 
+        return KErrNoMemory;
+    
+    //-- string being appended shall be unique
+    for(TUint i=0; i<Count(); ++i)
+        {
+        if(operator[](i).CompareF(aString) == 0)
+            {
+            ASSERT(0);
+            return KErrNone;
+            }
+        }
+
+    pBuf->Des().UpperCase(); //-- convert the FS name to upper-case in order to correctly calculate hash later
+    return iStrings.Append(pBuf);
+    }
+
+
+//-----------------------------------------------------------------------------
+/**
+    Get child FS name hash by index in the names container.
+    @param  aIndex name index in the container
+    @return file system name hash (crc32)
+*/
+TUint32 XStringArray::GetStringHash(TUint aIndex) const
+    {
+    const TDesC& des = operator[](aIndex);
+    return TVolFormatParam::CalcFSNameHash(des);
+    }
+
+
+
+void XStringArray::Panic(TPanicCode aPanicCode) const
+    {
+    _LIT(KPanicCat,"XStringArray");
+    User::Panic(KPanicCat, aPanicCode);
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+