os/kernelhwsrv/userlibandfileserver/fileserver/automounter/automounter.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 
    15 /**
    16 @file
    17 @internalTechnology
    18 */
    19 
    20 #include <e32cmn.h>
    21 #include <f32ver.h>
    22 #include <u32std.h>
    23 #include <f32file.h>
    24 
    25 
    26 
    27 #include "filesystem_automounter.h"
    28 #include "automounter.h"
    29 
    30 
    31 //-----------------------------------------------------------------------------
    32 
    33 void Fault(TFault aFault)
    34     {
    35     _LIT(KPanicName, "AutoMounter_fsy");
    36     User::Panic(KPanicName, aFault);
    37     }
    38 
    39 
    40 //-----------------------------------------------------------------------------
    41 
    42 /**
    43     Factory function, Create a new object of this file system 
    44 */
    45 extern "C" 
    46 {
    47 EXPORT_C CFileSystem* CreateFileSystem()
    48     {
    49     return CAutoMounterFileSystem::New();
    50     }
    51 }
    52 
    53 
    54 //#######################################################################################################################################
    55 //#  CAutoMounterFileSystem class implementation
    56 //#######################################################################################################################################
    57 
    58 /**
    59     Factory method
    60 */
    61 CAutoMounterFileSystem* CAutoMounterFileSystem::New()
    62     {
    63     CAutoMounterFileSystem* pThis = new CAutoMounterFileSystem();
    64     return pThis;
    65     }
    66 
    67 
    68 CAutoMounterFileSystem::CAutoMounterFileSystem() 
    69     {
    70     __PRINT1(_L("#<<- CAutoMounterFileSystem::CAutoMounterFileSystem() [0x%x]"), this);
    71 
    72     SetState(EInvalid);
    73     }   
    74 
    75 CAutoMounterFileSystem::~CAutoMounterFileSystem()
    76     {
    77     __PRINT1(_L("#<<- CAutoMounterFileSystem::~CAutoMounterFileSystem() [0x%x]"), this);
    78     }
    79 
    80 //-----------------------------------------------------------------------------
    81 
    82 /**
    83     Install iand initialise file system.
    84 */
    85 TInt CAutoMounterFileSystem::Install()
    86     {
    87    
    88     SetState(ENotInitialised);
    89 
    90     __PRINT1(_L("#<<- CAutoMounterFileSystem::Install() [0x%x]"), this);
    91 
    92     iVersion=TVersion(KF32MajorVersionNumber,KF32MinorVersionNumber,KF32BuildVersionNumber);
    93 
    94     InitialiseFileSystem();
    95 
    96     return SetName(&KFileSystemName_AutoMounter);
    97     }
    98 
    99 
   100 //-----------------------------------------------------------------------------
   101 /** 
   102     Create a new mount control block. 
   103     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 
   104     corresponding media driver. E.g. TDrive::ForceRemountDrive()
   105     Produce the _default_ file system mount
   106 */
   107 CMountCB* CAutoMounterFileSystem::NewMountL() const
   108     {
   109     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewMountL() [0x%x]"), this);
   110     ASSERT(State() == EInitialised);
   111 
   112     __PRINT1(_L("#<<- producing the _default_ filesystem:%S"), &iFSNames[KDefaultFSNo]);
   113 
   114     CFileSystem* pFS = GetChildFileSystem(KDefaultFSNo);
   115     ASSERT(pFS);
   116 
   117     return pFS->NewMountL();
   118     }
   119 
   120 //-----------------------------------------------------------------------------
   121 /** 
   122     Create a new file. 
   123 */
   124 CFileCB* CAutoMounterFileSystem::NewFileL() const
   125     {
   126     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewFileL() [0x%x]"), this);
   127     Fault(EMustNotBeCalled);
   128     return NULL;
   129     }
   130 
   131 //-----------------------------------------------------------------------------
   132 /** 
   133     Create a new directory object 
   134 */
   135 CDirCB* CAutoMounterFileSystem::NewDirL() const
   136     {
   137     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewDirL() [0x%x]"), this);
   138     Fault(EMustNotBeCalled);
   139     return NULL;
   140     }
   141 
   142 //-----------------------------------------------------------------------------
   143 /** 
   144     Create a new media formatter 
   145 */
   146 CFormatCB* CAutoMounterFileSystem::NewFormatL() const
   147     {
   148     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewFormatL() [0x%x]"), this);
   149     Fault(EMustNotBeCalled);
   150     return NULL;
   151     }
   152 
   153 
   154 //-----------------------------------------------------------------------------
   155 
   156 #ifdef _DEBUG
   157 /**
   158     Called by File Server before deleting File System object.    
   159 */
   160 TInt CAutoMounterFileSystem::Remove()
   161     {
   162     __PRINT1(_L("#<<- CAutoMounterFileSystem::Remove() [0x%x]"), this);
   163     return CFileSystem::Remove();
   164     }
   165 
   166 //-----------------------------------------------------------------------------
   167 
   168 /**
   169 */
   170 TBool CAutoMounterFileSystem::QueryVersionSupported(const TVersion& aVer) const
   171     {
   172     __PRINT1(_L("#<<- CAutoMounterFileSystem::QueryVersionSupported() [0x%x]"), this);
   173     return CFileSystem::QueryVersionSupported(aVer);
   174     }
   175 
   176 #endif
   177 
   178 //-----------------------------------------------------------------------------
   179 
   180 /**
   181     Find out if drive extensions are supported. In order to have consistent behaviour, _all_ child 
   182     file systems shall behave the same way.   
   183     
   184     @return ETrue if drive extensions are supported.    
   185 */
   186 TBool CAutoMounterFileSystem::IsExtensionSupported() const
   187     {
   188     __PRINT1(_L("#<<- CAutoMounterFileSystem::IsExtensionSupported() [0x%x]"), this);
   189     
   190     ASSERT(State() == EInitialised && iFSNames.Count() > 1);
   191 
   192 
   193     //-- in debug mode check file systems compatibility: ALL childs must support this feature
   194     for(TUint i=0; i<iFSNames.Count(); ++i)
   195         {
   196         if( !(GetChildFileSystem(i)->IsExtensionSupported()))
   197             {
   198             DBG_STATEMENT(Fault(EIncompatibleFileSystems));
   199             __PRINT(_L("#<<- ::IsExtensionSupported(): Incompatible file sytems!"));
   200             return EFalse;
   201             }
   202         }
   203 
   204 
   205     return ETrue; 
   206     }
   207 
   208 //-----------------------------------------------------------------------------
   209 
   210 /** 
   211     Return the initial default path. 
   212 */
   213 TInt CAutoMounterFileSystem::DefaultPath(TDes& aPath) const
   214     {
   215     __PRINT1(_L("#<<- CAutoMounterFileSystem::DefaultPath() [0x%x]"), this);
   216 
   217     aPath=_L("?:\\");
   218     aPath[0] = (TUint8) RFs::GetSystemDriveChar();
   219     return KErrNone;
   220     }
   221 
   222 
   223 //-----------------------------------------------------------------------------
   224 
   225 /**
   226     Additional interfaces support.    
   227 */
   228 TInt CAutoMounterFileSystem::GetInterface(TInt aInterfaceId, TAny*& aInterface, TAny* aInput)
   229     {
   230 
   231     __PRINT2(_L("#<<- CAutoMounterFileSystem::GetInterface(id:%d) [0x%x]"), aInterfaceId, this);
   232 
   233     switch(aInterfaceId)
   234         {
   235         //-- It is this filesystem private interface.
   236         case EExtendedFunctionality:
   237         aInterface = (CFileSystem::MFileSystemExtInterface*)this;
   238         return KErrNone;
   239         
   240         //-- a special case for child filesystems.
   241         //-- ALL of them must respond to this interface query exactly the same way. I.e. It is impossible
   242         //-- to have some of the child FS supporting it and some not.
   243         case EProxyDriveSupport:
   244         return DoProcessProxyDriveSupport();
   245 
   246 
   247         default:
   248         //-- This is the request to other (child file system) from the file server
   249         //-- Actually, this part must never be called. File Server shall query the file system interfaces _after_ mounting the concrete FS 
   250         //-- calling TDrive::iCurrentMount->FileSystem().GetInterface() 
   251         ASSERT(0);
   252         return CFileSystem::GetInterface(aInterfaceId, aInterface, aInput);
   253         
   254         }
   255     }
   256 
   257 
   258 //-----------------------------------------------------------------------------
   259 
   260 /**
   261     Find out if _all_ child file systems support the proxy drive. All childs shall behave exactly the same way.
   262     @return KErrNone if all child file systems support proxy drives, or KErrNotSupported if all of them do not.
   263 */
   264 TInt CAutoMounterFileSystem::DoProcessProxyDriveSupport()
   265     {
   266     __PRINT1(_L("#<<- CAutoMounterFileSystem::DoProcessProxyDriveSupport[0x%x]"), this);
   267     ASSERT(State() == EInitialised);
   268 
   269     const TUint cnt = iFSNames.Count();
   270     ASSERT(cnt > 1);
   271 
   272     
   273     //-- query the default filesystem #0
   274     const TBool bRes = GetChildFileSystem(KDefaultFSNo)->IsProxyDriveSupported();
   275 
   276     //-- query the rest of child filesystems
   277     for(TUint i=1; i<cnt; ++i)
   278         {
   279         const TBool b = GetChildFileSystem(i)->IsProxyDriveSupported();
   280 
   281         if(BoolXOR(b, bRes))
   282             Fault(EIncompatibleFileSystems);
   283         }
   284 
   285 
   286     return  bRes ? KErrNone : KErrNotSupported;
   287     }
   288 
   289 //-----------------------------------------------------------------------------
   290 /**
   291     Get the child file system name by its index (enumerator).
   292     
   293     @param  aFsNumber   index of the child FS 0...KMaxTInt
   294     @param  aFsName     on success the child file system name will be placed into this buffer  
   295 
   296     @return KErrNone        if there is a child FS name with index 'aFsNumber' (child FS 'aFsNumber' is supported by automounter)
   297             KErrNotFound    if child FS 'aFsNumber' is not supported
   298 */
   299 TInt CAutoMounterFileSystem::GetSupportedFileSystemName(TInt aFsNumber, TDes& aFsName) const
   300     {
   301     __PRINT2(_L("#<<- CAutoMounterFileSystem::GetSupportedFileSystemName[0x%x](%d)"), this, aFsNumber);
   302 
   303     if(aFsNumber == RFs::KRootFileSystem)
   304         {//-- this is a name query for "root filesystem" or automounter
   305         aFsName = Name(); //-- ourselves
   306         return KErrNone;
   307         }
   308     
   309     //-- this is a query for one of the child filesystems
   310     if((TUint)aFsNumber < iFSNames.Count())
   311         {
   312         aFsName = iFSNames[aFsNumber]; 
   313         return KErrNone;
   314         }
   315 
   316     
   317     return KErrNotFound;
   318     }
   319 
   320 
   321 //-----------------------------------------------------------------------------
   322 /**
   323     This is the only factory method that can be called by file server for this file system.
   324     In this method the automounter sequentially tries to mount every child and on success produces the corresponding CMountCB object.
   325 
   326     @param  apDrive         pointer to the TDrive, child FS will need this to access media.
   327     @param  apFileSystem    on return will contain the pointer to the CFileSystem that has produced the proped CMountCB if 
   328                             one of the child file system has recognised the volume.
   329     @param  aForceMount     if ETrue the appropriate child FS (designated by aFsNameHash) will be forcedly mounted on the volume. for volume formatting purposes.
   330     @param  aFsNameHash     if !=0 specifies the file system name, see TVolFormatParam::CalcFSNameHash(). 0 means "file system name is not specified"
   331 
   332     @return pointer to the constructed CMountCB by one of the child file systems (and pointer to this child FS in apFileSystem)
   333             NULL if it was impossible to produce proper CMountCB object.
   334 
   335 */
   336 CMountCB* CAutoMounterFileSystem::NewMountExL(TDrive* apDrive, CFileSystem** apFileSystem, TBool aForceMount, TUint32 aFsNameHash)
   337     {
   338     __PRINT4(_L("#<<- CAutoMounterFileSystem::NewMountExL[0x%x] drv:%d, ForceMount:%d, FSNameHash:0x%x"), this, apDrive->DriveNumber(), aForceMount, aFsNameHash);
   339 
   340     ASSERT(State() == EInitialised && apDrive);
   341 
   342     //-- This method is usually called from the appropriate drive thread; this file system is intended to be bound to
   343     //-- removable drives. Having removable drive runnind in the main file server thread means that something is terribly wrongly configured.
   344     if(apDrive->IsSynchronous())
   345         Fault(EWrongDriveAttributes);
   346 
   347     if(iFSNames.Count() < 2)
   348         Fault(EWrongConfiguration);
   349 
   350 
   351     //-- if aForceMount is true, this means that the TDrive tries mount the filesystem by force for formatting because normal mounting has failed before. 
   352     //-- in our case it means that the file system on the volume hadn't been recognised by any child FS.
   353     //-- aFsNameHash shall designate the file system to be forcedly mounted. Depending on this the appropriat CMounCB object will be produced.
   354     //-- if aFsNameHash is 0, i.e. not provided, this method will fail with KErrNotFound because it is impossible to select appropriat child FS.
   355     if(aForceMount)
   356         {
   357         if(aFsNameHash == 0)
   358             {//-- the file system to mount forcedly is not specified
   359             __PRINT(_L("#<<- Unable to select appropriate child FS for formatting!"));
   360             User::Leave(KErrNotFound);
   361             }
   362         else
   363             {//-- try to find appropriate child FS by its name hash
   364             CFileSystem *pFS = GetChildFileSysteByNameHash(aFsNameHash);
   365             if(!pFS)
   366                 {
   367                 __PRINT(_L("#<<- no child FS found by its name hash!"));
   368                 ASSERT(0);
   369                 User::Leave(KErrNotFound);
   370                 }
   371 
   372             CMountCB* pMount = pFS->NewMountL();
   373             ASSERT(pMount);
   374 
   375             *apFileSystem = pFS; 
   376             return pMount;
   377             }
   378         }//if(aForceMount)
   379 
   380 
   381 
   382     //-- try instantiate a new CMountCB depending on the file system on the media
   383 
   384     CMountCB* pMatchedMount;
   385     TInt nRes = TryMountFilesystem(apDrive, &pMatchedMount, apFileSystem);
   386     
   387     if(nRes == KErrNone)
   388         {
   389         ASSERT(pMatchedMount);
   390         return pMatchedMount;
   391         }
   392 
   393 
   394 
   395     User::Leave(nRes);
   396     return NULL;
   397     }
   398 
   399 //-----------------------------------------------------------------------------
   400 /**
   401     Initialise this file system. Reads and processes configuration, fills in file system names container, etc. 
   402 */
   403 void CAutoMounterFileSystem::InitialiseFileSystem()
   404     {
   405     __PRINT1(_L("#<<- CAutoMounterFileSystem::InitialiseFileSystem() [0x%x]"), this);
   406 
   407     ASSERT(State() == ENotInitialised);
   408 
   409     TInt nRes;
   410     
   411 
   412     //-- 1. initialise the array of file system names. These names shall be listed in a config string.
   413     //-- the config string is taken from estart.txt usually and its format is like this: 
   414     //-- section: [AutoMounter] and property "FSNames fat,exfat"
   415     //-- in debug version a special text property can override the config string. This allows controlling automounter from
   416     //-- the test environment.
   417 
   418     TBuf8<0x100> buf(0);   
   419     TBuf<0x100>  fsName;   
   420 
   421 
   422 #ifdef _DEBUG
   423     const TUid KSID_Test1={0x10210EB3}; //-- SID of the test that will define and set test property to control volume mounting
   424     const TUint KPropKey = 0; //-- property key
   425 
   426     //-- in debug mode the property will override the estart.txt config
   427     if(RProperty::Get(KSID_Test1, KPropKey, buf) == KErrNone)
   428         {
   429         __PRINT(_L("#<<- reading config from the debug propery..."));
   430         }
   431     else
   432 #endif
   433         {
   434         __PRINT(_L("#<<- reading config from estart.txt..."));
   435         _LIT8(KSection,  "AutoMounter");
   436         _LIT8(KProperty, "FSNames");
   437 
   438         nRes = F32Properties::GetString(KSection, KProperty, buf);
   439         if(!nRes)
   440             Fault(EPluginInitialise);
   441         }
   442 
   443 
   444     fsName.Copy(buf);
   445     __PRINT1(_L("#<<- config:'%S'"), &fsName);
   446 
   447     //-- parse CSV config line and fill in the file system names array
   448     const TChar chDelim = ','; //-- token delimiter, comma
   449     buf.Trim();
   450     TPtrC8 ptrCurrLine(buf);
   451     for(TInt i=0; ;++i)
   452         {
   453         const TInt delimPos = ptrCurrLine.Locate(chDelim);
   454         if(delimPos <= 0)
   455             {
   456             fsName.Copy(ptrCurrLine);
   457             }
   458         else
   459             {
   460             TPtrC8 temp(ptrCurrLine.Ptr(), delimPos);
   461             fsName.Copy(temp);
   462             }
   463 
   464         fsName.Trim();
   465         __PRINT2(_L("#<<- child FS[%d]: '%S'"), i, &fsName);
   466 
   467         
   468         if(fsName.Length() <= 0) 
   469             Fault(EPluginInitialise);
   470 
   471         //-- check if the FS name being appended is unique
   472         for(TUint j=0; j<iFSNames.Count(); ++j)
   473             {
   474             if(iFSNames[j] == fsName)
   475                 {
   476                 Fault(EPluginInitialise);
   477                 }
   478             }
   479         
   480         
   481         nRes = iFSNames.Append(fsName);
   482         ASSERT(nRes ==KErrNone);
   483         
   484         if(delimPos <=0 )
   485             break;
   486 
   487         ptrCurrLine.Set(ptrCurrLine.Ptr()+delimPos+1, ptrCurrLine.Length()-delimPos-1);
   488         }
   489 
   490 
   491     SetState(EInitialised);
   492 
   493     //-- 2. check that the file server has all filesystems we need instantiated and stored in a global container
   494     TUint cnt = iFSNames.Count();
   495     if(cnt < 2)
   496         {
   497         __PRINT(_L("#<<- ::InitialiseFileSystem(): too few File Systems bound!"));
   498         Fault(EPluginInitialise);
   499         }
   500 
   501     while(cnt--)
   502         {
   503         GetChildFileSystem(cnt);
   504         }
   505 
   506 
   507     }
   508 
   509 
   510 
   511 //-----------------------------------------------------------------------------
   512 /**
   513     Tries to find out if some of the child file systems can be mounted on the given volume.
   514 
   515     @param  apDrive         pointer to the TDrive, child FS will need this to access media.
   516     @param                  on return will contain the pointer to the CMountCB object if some of the childs has decided that it can be mounted.
   517     @param  apFS            on return will contain the pointer to the CFileSystem that has produced the proped CMountCB if 
   518 
   519     @return KErrNone on success, otherwise standard error code.
   520 
   521 */
   522 TInt CAutoMounterFileSystem::TryMountFilesystem(TDrive* apDrive, CMountCB** apMount, CFileSystem** apFS)
   523     {
   524     __PRINT1(_L("#<<- CAutoMounterFileSystem::TryMountFilesystem()[0x%x]"), this);
   525 
   526     const TInt KNumFS = iFSNames.Count();
   527   
   528     ASSERT(State() == EInitialised && (KNumFS >1));
   529 
   530 
   531     *apMount = NULL;
   532     *apFS    = NULL;
   533     
   534     
   535     TInt nRes;
   536     TInt cntFS;
   537     CMountCB*       pMountCB = NULL;
   538     CFileSystem*    pMatchedFS = NULL;
   539 
   540     for(cntFS=0; cntFS < KNumFS; ++cntFS)
   541         {
   542 
   543         __PRINT2(_L("#<<-@@ trying FS[%d]:%S"), cntFS, &iFSNames[cntFS]);
   544 
   545         CFileSystem* pFS = GetChildFileSystem(cntFS); //-- Find current filesystem object in the FileServer's global container
   546 
   547         //-- 2. create CMountCB instance and set it up
   548         pMountCB = NULL;
   549         
   550         TRAP(nRes, pMountCB = pFS->NewMountL());
   551         if(nRes != KErrNone)
   552             {
   553             return KErrNoMemory;
   554             }
   555 
   556         ASSERT(pMountCB);
   557         pMountCB->SetDrive(apDrive);
   558 
   559         
   560         //-- 2.1 Firstly try using special CMountCB interface to find out if current FS can be mounted on this media
   561         nRes = pMountCB->CheckFileSystemMountable();
   562         if(nRes == KErrNotSupported)
   563             {
   564             //-- file system doesn't support this feature,
   565             //-- 2.2 try to check the file system by mounting and dismounting later. It can result in some long activity, like FAT scanning etc.
   566             TRAP(nRes, pMountCB->MountL(EFalse));
   567             pMountCB->Dismounted(); //-- dismount the mountCB, it will be required in dismounted state anyway 
   568             }
   569         
   570         //-- 2.3 analyse the result of mounting 
   571         if(nRes != KErrNone)
   572             {
   573             if(nRes == KErrLocked)
   574                 {//-- this is a special case; The media (SD card for example) is locked. 
   575                 //-- Pretend that everything is OK and return CMountCB instance that is produced by the _default_ file system.
   576                 //-- locked media case will be handled by the file server later.
   577                 ASSERT(cntFS == KDefaultFSNo); //-- the default FS is tried first and must detect the locked media
   578                 pMatchedFS = pFS;
   579                 __PRINT(_L("#<<-@@ The media is LOCKED !"));
   580                 break;
   581                 }
   582 
   583             //-- failed to mount the file system, most likey it is not recognised
   584             pMountCB->Close(); //-- this is a self-destructing object!
   585             pMountCB = NULL;
   586             __PRINT(_L("#<<-@@ Mount FAILED !"));
   587             }
   588         else
   589             {
   590             //-- mounted OK, the file system is recognised
   591             __PRINT(_L("#<<-@@ Mount OK!"));
   592             
   593             pMatchedFS = pFS;
   594             break;
   595             }
   596     
   597         }//for(cntFS=0; cntFS<KNumFS; ++cntFS)
   598 
   599     if(cntFS >= KNumFS)
   600         {//-- no one from the FS factories recognised the file system
   601         __PRINT1(_L("#<<- ::TryMountFilesystem()[0x%x] No file system recognised!"), this);
   602         
   603         SetName(&KFileSystemName_AutoMounter); 
   604         return KErrCorrupt;
   605         }
   606 
   607     ASSERT(pMountCB && pMatchedFS); 
   608     *apMount = pMountCB;
   609     *apFS    = pMatchedFS;
   610     
   611     //-- 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 
   612     //-- successful mounting. This behaviour was considered to be incorrect.
   613     //TPtrC fsName = pMatchedFS->Name();
   614     //SetName(&fsName); 
   615 
   616     return KErrNone;
   617 
   618     }
   619 
   620 //-----------------------------------------------------------------------------
   621 /**
   622     get the child file system object by the index in file child system names container
   623     
   624     @param  aIndex  index in the iFSNames
   625     @return pointer to the FS object if it is found, NULL otherwise
   626 */
   627 CFileSystem* CAutoMounterFileSystem::GetChildFileSystem(TUint aIndex) const
   628     {
   629     ASSERT(State() == EInitialised && (iFSNames.Count() >1) && aIndex < iFSNames.Count());
   630 
   631     const TDesC& fsName = iFSNames[aIndex]; //-- registered child file system name
   632     CFileSystem* pFS = GetFileSystem(fsName); //-- Find filesystem object in the FileServer's global container
   633 
   634     if(!pFS)
   635         {
   636         __PRINT1(_L("#<<- CAutoMounterFileSystem::GetChildFileSystem() FileServer doesn't have FS:%S Added!"), &fsName);
   637         Fault(EFileSysNotAdded);
   638         }
   639 
   640     return pFS;
   641     }
   642 
   643 //-----------------------------------------------------------------------------
   644 /**
   645     Find the child file system object by the file system name name hash. 
   646     @param  aFsNameHash FS name hash
   647     @return pointer to the FS object if it is found, NULL otherwise
   648 */
   649 CFileSystem* CAutoMounterFileSystem::GetChildFileSysteByNameHash(TUint32 aFsNameHash) const
   650     {
   651     ASSERT(State() == EInitialised && (iFSNames.Count() >1) && aFsNameHash);
   652     
   653     for(TUint i=0; i<iFSNames.Count(); ++i)
   654         {
   655         if(aFsNameHash == iFSNames.GetStringHash(i))
   656             {
   657             const TDesC& fsName = iFSNames[i];        //-- registered child file system name
   658             __PRINT2(_L("#<<- ::GetChildFileSysteByNameHash() found FsName:%S by hash:0x%x"), &fsName, aFsNameHash);
   659             CFileSystem* pFS = GetFileSystem(fsName); //-- Find filesystem object in the FileServer's global container
   660             ASSERT(pFS);
   661             return pFS;
   662             }
   663    
   664         }
   665    
   666     __PRINT1(_L("#<<- ::GetChildFileSysteByNameHash() No FS name found by hash:0x%x"), aFsNameHash);
   667    
   668     return NULL;
   669     }
   670 
   671 
   672 
   673 
   674 //#######################################################################################################################################
   675 //#     XStringArray implementation
   676 //#######################################################################################################################################
   677 
   678 XStringArray::XStringArray()
   679     {
   680     }
   681 
   682 XStringArray::~XStringArray()
   683     {
   684     Reset();
   685     iStrings.Close();
   686     }
   687 
   688 //-----------------------------------------------------------------------------
   689 void XStringArray::Reset()
   690     {
   691     iStrings.ResetAndDestroy();
   692     }
   693 
   694 //-----------------------------------------------------------------------------
   695 const TDesC& XStringArray::operator[](TUint aIndex) const
   696     {
   697     if(aIndex >= (TUint)iStrings.Count())
   698         Panic(EIndexOutOfRange);
   699 
   700     HBufC* des=iStrings[aIndex];
   701     return *des;
   702     }
   703 
   704 //-----------------------------------------------------------------------------
   705 /**
   706     Append file system name to the container. The name is converted to upper case.
   707     @param aString name descriptor.
   708     @return standard error code
   709 */
   710 TInt XStringArray::Append(const TDesC& aString)
   711     {
   712     HBufC* pBuf = aString.Alloc();
   713     if(!pBuf) 
   714         return KErrNoMemory;
   715     
   716     //-- string being appended shall be unique
   717     for(TUint i=0; i<Count(); ++i)
   718         {
   719         if(operator[](i).CompareF(aString) == 0)
   720             {
   721             ASSERT(0);
   722             return KErrNone;
   723             }
   724         }
   725 
   726     pBuf->Des().UpperCase(); //-- convert the FS name to upper-case in order to correctly calculate hash later
   727     return iStrings.Append(pBuf);
   728     }
   729 
   730 
   731 //-----------------------------------------------------------------------------
   732 /**
   733     Get child FS name hash by index in the names container.
   734     @param  aIndex name index in the container
   735     @return file system name hash (crc32)
   736 */
   737 TUint32 XStringArray::GetStringHash(TUint aIndex) const
   738     {
   739     const TDesC& des = operator[](aIndex);
   740     return TVolFormatParam::CalcFSNameHash(des);
   741     }
   742 
   743 
   744 
   745 void XStringArray::Panic(TPanicCode aPanicCode) const
   746     {
   747     _LIT(KPanicCat,"XStringArray");
   748     User::Panic(KPanicCat, aPanicCode);
   749     }
   750 
   751 
   752 
   753 
   754 
   755 
   756 
   757 
   758 
   759 
   760 
   761 
   762 
   763 
   764 
   765 
   766 
   767 
   768 
   769 
   770 
   771 
   772 
   773 
   774 
   775 
   776 
   777 
   778 
   779 
   780 
   781