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".
 
     8 // Initial Contributors:
 
     9 // Nokia Corporation - initial contribution.
 
    27 #include "filesystem_automounter.h"
 
    28 #include "automounter.h"
 
    31 //-----------------------------------------------------------------------------
 
    33 void Fault(TFault aFault)
 
    35     _LIT(KPanicName, "AutoMounter_fsy");
 
    36     User::Panic(KPanicName, aFault);
 
    40 //-----------------------------------------------------------------------------
 
    43     Factory function, Create a new object of this file system 
 
    47 EXPORT_C CFileSystem* CreateFileSystem()
 
    49     return CAutoMounterFileSystem::New();
 
    54 //#######################################################################################################################################
 
    55 //#  CAutoMounterFileSystem class implementation
 
    56 //#######################################################################################################################################
 
    61 CAutoMounterFileSystem* CAutoMounterFileSystem::New()
 
    63     CAutoMounterFileSystem* pThis = new CAutoMounterFileSystem();
 
    68 CAutoMounterFileSystem::CAutoMounterFileSystem() 
 
    70     __PRINT1(_L("#<<- CAutoMounterFileSystem::CAutoMounterFileSystem() [0x%x]"), this);
 
    75 CAutoMounterFileSystem::~CAutoMounterFileSystem()
 
    77     __PRINT1(_L("#<<- CAutoMounterFileSystem::~CAutoMounterFileSystem() [0x%x]"), this);
 
    80 //-----------------------------------------------------------------------------
 
    83     Install iand initialise file system.
 
    85 TInt CAutoMounterFileSystem::Install()
 
    88     SetState(ENotInitialised);
 
    90     __PRINT1(_L("#<<- CAutoMounterFileSystem::Install() [0x%x]"), this);
 
    92     iVersion=TVersion(KF32MajorVersionNumber,KF32MinorVersionNumber,KF32BuildVersionNumber);
 
    94     InitialiseFileSystem();
 
    96     return SetName(&KFileSystemName_AutoMounter);
 
   100 //-----------------------------------------------------------------------------
 
   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
 
   107 CMountCB* CAutoMounterFileSystem::NewMountL() const
 
   109     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewMountL() [0x%x]"), this);
 
   110     ASSERT(State() == EInitialised);
 
   112     __PRINT1(_L("#<<- producing the _default_ filesystem:%S"), &iFSNames[KDefaultFSNo]);
 
   114     CFileSystem* pFS = GetChildFileSystem(KDefaultFSNo);
 
   117     return pFS->NewMountL();
 
   120 //-----------------------------------------------------------------------------
 
   124 CFileCB* CAutoMounterFileSystem::NewFileL() const
 
   126     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewFileL() [0x%x]"), this);
 
   127     Fault(EMustNotBeCalled);
 
   131 //-----------------------------------------------------------------------------
 
   133     Create a new directory object 
 
   135 CDirCB* CAutoMounterFileSystem::NewDirL() const
 
   137     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewDirL() [0x%x]"), this);
 
   138     Fault(EMustNotBeCalled);
 
   142 //-----------------------------------------------------------------------------
 
   144     Create a new media formatter 
 
   146 CFormatCB* CAutoMounterFileSystem::NewFormatL() const
 
   148     __PRINT1(_L("#<<- CAutoMounterFileSystem::NewFormatL() [0x%x]"), this);
 
   149     Fault(EMustNotBeCalled);
 
   154 //-----------------------------------------------------------------------------
 
   158     Called by File Server before deleting File System object.    
 
   160 TInt CAutoMounterFileSystem::Remove()
 
   162     __PRINT1(_L("#<<- CAutoMounterFileSystem::Remove() [0x%x]"), this);
 
   163     return CFileSystem::Remove();
 
   166 //-----------------------------------------------------------------------------
 
   170 TBool CAutoMounterFileSystem::QueryVersionSupported(const TVersion& aVer) const
 
   172     __PRINT1(_L("#<<- CAutoMounterFileSystem::QueryVersionSupported() [0x%x]"), this);
 
   173     return CFileSystem::QueryVersionSupported(aVer);
 
   178 //-----------------------------------------------------------------------------
 
   181     Find out if drive extensions are supported. In order to have consistent behaviour, _all_ child 
 
   182     file systems shall behave the same way.   
 
   184     @return ETrue if drive extensions are supported.    
 
   186 TBool CAutoMounterFileSystem::IsExtensionSupported() const
 
   188     __PRINT1(_L("#<<- CAutoMounterFileSystem::IsExtensionSupported() [0x%x]"), this);
 
   190     ASSERT(State() == EInitialised && iFSNames.Count() > 1);
 
   193     //-- in debug mode check file systems compatibility: ALL childs must support this feature
 
   194     for(TUint i=0; i<iFSNames.Count(); ++i)
 
   196         if( !(GetChildFileSystem(i)->IsExtensionSupported()))
 
   198             DBG_STATEMENT(Fault(EIncompatibleFileSystems));
 
   199             __PRINT(_L("#<<- ::IsExtensionSupported(): Incompatible file sytems!"));
 
   208 //-----------------------------------------------------------------------------
 
   211     Return the initial default path. 
 
   213 TInt CAutoMounterFileSystem::DefaultPath(TDes& aPath) const
 
   215     __PRINT1(_L("#<<- CAutoMounterFileSystem::DefaultPath() [0x%x]"), this);
 
   218     aPath[0] = (TUint8) RFs::GetSystemDriveChar();
 
   223 //-----------------------------------------------------------------------------
 
   226     Additional interfaces support.    
 
   228 TInt CAutoMounterFileSystem::GetInterface(TInt aInterfaceId, TAny*& aInterface, TAny* aInput)
 
   231     __PRINT2(_L("#<<- CAutoMounterFileSystem::GetInterface(id:%d) [0x%x]"), aInterfaceId, this);
 
   235         //-- It is this filesystem private interface.
 
   236         case EExtendedFunctionality:
 
   237         aInterface = (CFileSystem::MFileSystemExtInterface*)this;
 
   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();
 
   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() 
 
   252         return CFileSystem::GetInterface(aInterfaceId, aInterface, aInput);
 
   258 //-----------------------------------------------------------------------------
 
   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.
 
   264 TInt CAutoMounterFileSystem::DoProcessProxyDriveSupport()
 
   266     __PRINT1(_L("#<<- CAutoMounterFileSystem::DoProcessProxyDriveSupport[0x%x]"), this);
 
   267     ASSERT(State() == EInitialised);
 
   269     const TUint cnt = iFSNames.Count();
 
   273     //-- query the default filesystem #0
 
   274     const TBool bRes = GetChildFileSystem(KDefaultFSNo)->IsProxyDriveSupported();
 
   276     //-- query the rest of child filesystems
 
   277     for(TUint i=1; i<cnt; ++i)
 
   279         const TBool b = GetChildFileSystem(i)->IsProxyDriveSupported();
 
   282             Fault(EIncompatibleFileSystems);
 
   286     return  bRes ? KErrNone : KErrNotSupported;
 
   289 //-----------------------------------------------------------------------------
 
   291     Get the child file system name by its index (enumerator).
 
   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  
 
   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
 
   299 TInt CAutoMounterFileSystem::GetSupportedFileSystemName(TInt aFsNumber, TDes& aFsName) const
 
   301     __PRINT2(_L("#<<- CAutoMounterFileSystem::GetSupportedFileSystemName[0x%x](%d)"), this, aFsNumber);
 
   303     if(aFsNumber == RFs::KRootFileSystem)
 
   304         {//-- this is a name query for "root filesystem" or automounter
 
   305         aFsName = Name(); //-- ourselves
 
   309     //-- this is a query for one of the child filesystems
 
   310     if((TUint)aFsNumber < iFSNames.Count())
 
   312         aFsName = iFSNames[aFsNumber]; 
 
   321 //-----------------------------------------------------------------------------
 
   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.
 
   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"
 
   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.
 
   336 CMountCB* CAutoMounterFileSystem::NewMountExL(TDrive* apDrive, CFileSystem** apFileSystem, TBool aForceMount, TUint32 aFsNameHash)
 
   338     __PRINT4(_L("#<<- CAutoMounterFileSystem::NewMountExL[0x%x] drv:%d, ForceMount:%d, FSNameHash:0x%x"), this, apDrive->DriveNumber(), aForceMount, aFsNameHash);
 
   340     ASSERT(State() == EInitialised && apDrive);
 
   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);
 
   347     if(iFSNames.Count() < 2)
 
   348         Fault(EWrongConfiguration);
 
   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.
 
   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);
 
   363             {//-- try to find appropriate child FS by its name hash
 
   364             CFileSystem *pFS = GetChildFileSysteByNameHash(aFsNameHash);
 
   367                 __PRINT(_L("#<<- no child FS found by its name hash!"));
 
   369                 User::Leave(KErrNotFound);
 
   372             CMountCB* pMount = pFS->NewMountL();
 
   382     //-- try instantiate a new CMountCB depending on the file system on the media
 
   384     CMountCB* pMatchedMount;
 
   385     TInt nRes = TryMountFilesystem(apDrive, &pMatchedMount, apFileSystem);
 
   389         ASSERT(pMatchedMount);
 
   390         return pMatchedMount;
 
   399 //-----------------------------------------------------------------------------
 
   401     Initialise this file system. Reads and processes configuration, fills in file system names container, etc. 
 
   403 void CAutoMounterFileSystem::InitialiseFileSystem()
 
   405     __PRINT1(_L("#<<- CAutoMounterFileSystem::InitialiseFileSystem() [0x%x]"), this);
 
   407     ASSERT(State() == ENotInitialised);
 
   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.
 
   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
 
   426     //-- in debug mode the property will override the estart.txt config
 
   427     if(RProperty::Get(KSID_Test1, KPropKey, buf) == KErrNone)
 
   429         __PRINT(_L("#<<- reading config from the debug propery..."));
 
   434         __PRINT(_L("#<<- reading config from estart.txt..."));
 
   435         _LIT8(KSection,  "AutoMounter");
 
   436         _LIT8(KProperty, "FSNames");
 
   438         nRes = F32Properties::GetString(KSection, KProperty, buf);
 
   440             Fault(EPluginInitialise);
 
   445     __PRINT1(_L("#<<- config:'%S'"), &fsName);
 
   447     //-- parse CSV config line and fill in the file system names array
 
   448     const TChar chDelim = ','; //-- token delimiter, comma
 
   450     TPtrC8 ptrCurrLine(buf);
 
   453         const TInt delimPos = ptrCurrLine.Locate(chDelim);
 
   456             fsName.Copy(ptrCurrLine);
 
   460             TPtrC8 temp(ptrCurrLine.Ptr(), delimPos);
 
   465         __PRINT2(_L("#<<- child FS[%d]: '%S'"), i, &fsName);
 
   468         if(fsName.Length() <= 0) 
 
   469             Fault(EPluginInitialise);
 
   471         //-- check if the FS name being appended is unique
 
   472         for(TUint j=0; j<iFSNames.Count(); ++j)
 
   474             if(iFSNames[j] == fsName)
 
   476                 Fault(EPluginInitialise);
 
   481         nRes = iFSNames.Append(fsName);
 
   482         ASSERT(nRes ==KErrNone);
 
   487         ptrCurrLine.Set(ptrCurrLine.Ptr()+delimPos+1, ptrCurrLine.Length()-delimPos-1);
 
   491     SetState(EInitialised);
 
   493     //-- 2. check that the file server has all filesystems we need instantiated and stored in a global container
 
   494     TUint cnt = iFSNames.Count();
 
   497         __PRINT(_L("#<<- ::InitialiseFileSystem(): too few File Systems bound!"));
 
   498         Fault(EPluginInitialise);
 
   503         GetChildFileSystem(cnt);
 
   511 //-----------------------------------------------------------------------------
 
   513     Tries to find out if some of the child file systems can be mounted on the given volume.
 
   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 
 
   519     @return KErrNone on success, otherwise standard error code.
 
   522 TInt CAutoMounterFileSystem::TryMountFilesystem(TDrive* apDrive, CMountCB** apMount, CFileSystem** apFS)
 
   524     __PRINT1(_L("#<<- CAutoMounterFileSystem::TryMountFilesystem()[0x%x]"), this);
 
   526     const TInt KNumFS = iFSNames.Count();
 
   528     ASSERT(State() == EInitialised && (KNumFS >1));
 
   537     CMountCB*       pMountCB = NULL;
 
   538     CFileSystem*    pMatchedFS = NULL;
 
   540     for(cntFS=0; cntFS < KNumFS; ++cntFS)
 
   543         __PRINT2(_L("#<<-@@ trying FS[%d]:%S"), cntFS, &iFSNames[cntFS]);
 
   545         CFileSystem* pFS = GetChildFileSystem(cntFS); //-- Find current filesystem object in the FileServer's global container
 
   547         //-- 2. create CMountCB instance and set it up
 
   550         TRAP(nRes, pMountCB = pFS->NewMountL());
 
   557         pMountCB->SetDrive(apDrive);
 
   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)
 
   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 
 
   570         //-- 2.3 analyse the result of mounting 
 
   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
 
   579                 __PRINT(_L("#<<-@@ The media is LOCKED !"));
 
   583             //-- failed to mount the file system, most likey it is not recognised
 
   584             pMountCB->Close(); //-- this is a self-destructing object!
 
   586             __PRINT(_L("#<<-@@ Mount FAILED !"));
 
   590             //-- mounted OK, the file system is recognised
 
   591             __PRINT(_L("#<<-@@ Mount OK!"));
 
   597         }//for(cntFS=0; cntFS<KNumFS; ++cntFS)
 
   600         {//-- no one from the FS factories recognised the file system
 
   601         __PRINT1(_L("#<<- ::TryMountFilesystem()[0x%x] No file system recognised!"), this);
 
   603         SetName(&KFileSystemName_AutoMounter); 
 
   607     ASSERT(pMountCB && pMatchedFS); 
 
   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();
 
   620 //-----------------------------------------------------------------------------
 
   622     get the child file system object by the index in file child system names container
 
   624     @param  aIndex  index in the iFSNames
 
   625     @return pointer to the FS object if it is found, NULL otherwise
 
   627 CFileSystem* CAutoMounterFileSystem::GetChildFileSystem(TUint aIndex) const
 
   629     ASSERT(State() == EInitialised && (iFSNames.Count() >1) && aIndex < iFSNames.Count());
 
   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
 
   636         __PRINT1(_L("#<<- CAutoMounterFileSystem::GetChildFileSystem() FileServer doesn't have FS:%S Added!"), &fsName);
 
   637         Fault(EFileSysNotAdded);
 
   643 //-----------------------------------------------------------------------------
 
   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
 
   649 CFileSystem* CAutoMounterFileSystem::GetChildFileSysteByNameHash(TUint32 aFsNameHash) const
 
   651     ASSERT(State() == EInitialised && (iFSNames.Count() >1) && aFsNameHash);
 
   653     for(TUint i=0; i<iFSNames.Count(); ++i)
 
   655         if(aFsNameHash == iFSNames.GetStringHash(i))
 
   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
 
   666     __PRINT1(_L("#<<- ::GetChildFileSysteByNameHash() No FS name found by hash:0x%x"), aFsNameHash);
 
   674 //#######################################################################################################################################
 
   675 //#     XStringArray implementation
 
   676 //#######################################################################################################################################
 
   678 XStringArray::XStringArray()
 
   682 XStringArray::~XStringArray()
 
   688 //-----------------------------------------------------------------------------
 
   689 void XStringArray::Reset()
 
   691     iStrings.ResetAndDestroy();
 
   694 //-----------------------------------------------------------------------------
 
   695 const TDesC& XStringArray::operator[](TUint aIndex) const
 
   697     if(aIndex >= (TUint)iStrings.Count())
 
   698         Panic(EIndexOutOfRange);
 
   700     HBufC* des=iStrings[aIndex];
 
   704 //-----------------------------------------------------------------------------
 
   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
 
   710 TInt XStringArray::Append(const TDesC& aString)
 
   712     HBufC* pBuf = aString.Alloc();
 
   716     //-- string being appended shall be unique
 
   717     for(TUint i=0; i<Count(); ++i)
 
   719         if(operator[](i).CompareF(aString) == 0)
 
   726     pBuf->Des().UpperCase(); //-- convert the FS name to upper-case in order to correctly calculate hash later
 
   727     return iStrings.Append(pBuf);
 
   731 //-----------------------------------------------------------------------------
 
   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)
 
   737 TUint32 XStringArray::GetStringHash(TUint aIndex) const
 
   739     const TDesC& des = operator[](aIndex);
 
   740     return TVolFormatParam::CalcFSNameHash(des);
 
   745 void XStringArray::Panic(TPanicCode aPanicCode) const
 
   747     _LIT(KPanicCat,"XStringArray");
 
   748     User::Panic(KPanicCat, aPanicCode);