os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_sys.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1995-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 // f32\sfile\sf_sys.cpp
    15 // 
    16 //
    17 
    18 #include "sf_std.h"
    19 #include <e32uid.h>
    20 #include "sf_file_cache.h"
    21 #include <kernel\localise.h>
    22 #include <f32file.h>
    23 
    24 typedef CFileSystem*(*TFileSystemNew)();
    25 extern CProxyDriveFactory* GetExtension(const TDesC& aName);
    26 
    27 #ifndef __WINS__
    28 extern TBool gInitCacheCheckDrivesAndAddNotifications;
    29 #endif
    30 
    31 struct TFatUtilityFunctions;
    32 GLREF_D TCodePageUtils TheCodePage;
    33 const TInt KMaxLengthShortNameWithDot = 12;
    34 const TUint8 KLeadingE5Replacement = 0x05;
    35 const TUint8 KEntryErasedMarker=0xE5;           ///< Erased entry marker for a directory entry
    36 
    37 /**
    38 Default constructor.
    39 */
    40 EXPORT_C CFileSystem::CFileSystem()
    41 	{
    42 	TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemConstructor, EF32TraceUidFileSys);
    43 	TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemConstructorReturn, EF32TraceUidFileSys);
    44 	}
    45 
    46 /**
    47 Destructor.
    48 */
    49 EXPORT_C CFileSystem::~CFileSystem()
    50 	{
    51 	TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemDestructor, EF32TraceUidFileSys);
    52 	TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemDestructorReturn, EF32TraceUidFileSys);
    53 	}
    54 
    55 /**
    56 Uninstalls the file system.
    57 
    58 This is called just before the file system object is destroyed, and allows
    59 any clean up to be carried out.
    60 
    61 The default implementation does nothing except return KErrNone.
    62 Implementations should return an error code on error detection.
    63 
    64 @return KErrNone if successful, otherwise one of the other system wide error
    65         codes.
    66 */
    67 EXPORT_C TInt CFileSystem::Remove()
    68 	{
    69 
    70 	return(KErrNone);
    71 	}
    72 
    73 /**
    74 Tests whether a version is supported.
    75 
    76 This is done decided by comparing the supplied version with iVersion.
    77 
    78 The default implementation uses User::QueryVersionSupported() to
    79 determine this.
    80 
    81 @param aVer The version to be tested.
    82 
    83 @return True, if aVer is supported; false otherwise
    84 
    85 @see User::QueryVersionSupported
    86 @see CFileSystem::iVersion
    87 */
    88 EXPORT_C TBool CFileSystem::QueryVersionSupported(const TVersion& aVer) const
    89 	{
    90 
    91 	return(User::QueryVersionSupported(iVersion,aVer));
    92 	}
    93 	
    94 //#ifndef __DATA_CAGING__
    95 /**
    96 Retrieves the default path for the file system.
    97 
    98 Each session with the file server has a current session path.
    99 When a new session is opened, its session path is set to the default path
   100 of the file server.
   101 At file server start-up, this default path is set to the default path returned
   102 by the local file system. 
   103 
   104 The function should return an appropriate error code when the default path
   105 cannot be supplied. 
   106 
   107 The derived class should override this base class function.
   108 
   109 This default implementation raises an "Fserv fault" 31 panic.
   110 
   111 @param aPath On return, contains the default path for the file system for derived classes.
   112 
   113 @return KErrNone if successful, otherwise one of the other system wide error codes.
   114 
   115 @panic Fserv fault 31 if the default implementation
   116        for CFileSystem::DefaultPath() is not overridden. 
   117 */
   118 TInt CFileSystem::DefaultPath(TDes& /*aPath*/) const
   119 	{
   120 
   121 	Fault(ESysDefaultPathNotSupported);
   122 	return(KErrNone);
   123 	}
   124 //#endif
   125 
   126 /**
   127 Sets the file system's resource library.
   128 
   129 This library represents the loaded file system.
   130 
   131 This is called internally by InstallFileSystem().
   132 
   133 @param aLib The resource library to be set.
   134 */
   135 EXPORT_C void CFileSystem::SetLibrary(RLibrary aLib)
   136 	{
   137 
   138 	iLibrary=aLib;
   139 	}
   140 
   141 /**
   142 Gets the file system's resource library.
   143 
   144 @return The file system's resource library.
   145 */
   146 EXPORT_C RLibrary CFileSystem::Library() const
   147 	{
   148 	return(iLibrary);
   149 	}
   150 
   151 /**
   152 Tests whether the file system supports extensions.
   153 
   154 @return True, if the file system supports extensions, false otherwise.
   155         The defualt implementation returns false.
   156 */
   157 EXPORT_C TBool CFileSystem::IsExtensionSupported() const
   158 	{
   159 	return(EFalse);
   160 	}
   161 
   162 EXPORT_C void CFileSystem::DriveInfo(TDriveInfo& aInfo, TInt aDriveNumber) const
   163 	{
   164     GetDriveInfo(aInfo, aDriveNumber);
   165 	}
   166 
   167 
   168 EXPORT_C TInt CFileSystem::GetInterface(TInt /*aInterfaceId*/,TAny*& /*aInterface*/,TAny* /*aInput*/)
   169 	{
   170 	return(KErrNotSupported);
   171 	}
   172 
   173 EXPORT_C TBool CFileSystem::IsProxyDriveSupported()
   174 	{
   175 	TAny* dummyInterface;
   176 	if(GetInterface(EProxyDriveSupport, dummyInterface, NULL) == KErrNone)
   177 		return ETrue;
   178 	
   179 	return EFalse;
   180 	}
   181 
   182 //----------------------------------------------------------------------------- 
   183 /** 
   184     Extended CMountCB factory interface.
   185     Produces the CMountCB object which can be associated with another CFileSystem owner.
   186     Used mostly  with "automounter" file system
   187 
   188     @param  apDrive         in:  pointer to TDrive, producing right CMountCB can require media access ("automounter" recognising the file system)
   189     @param  apFileSystem    out: pointer to the CFileSystem object that actually produced CMountCB instance (might be different from "this")
   190     @param  aForceMount     in:  ETrue if it is necessarily to force mounting (formatting the media, for example)
   191     @param  aFsNameHash     in:  desired file system name hash (optional). Specifies which file system will be used to produce appropriate CMountCB object.
   192                                  The file system that implements NewMountExL() shall decide how to process it. 0 means "default/not specified".
   193 
   194     @return pointer to the instantiated CMountCB object.
   195 */
   196 CMountCB* CFileSystem::NewMountExL(TDrive* apDrive, CFileSystem** apFileSystem, TBool aForceMount, TUint32 aFsNameHash)
   197     {
   198     TAny* pa;
   199 
   200     if(GetInterface(EExtendedFunctionality, pa, NULL) == KErrNone)
   201         {//-- special interface for the case, when CMountCB object will be produced by not _this_ CFileSystem object, but some different.
   202          //-- in this case apFileSystem will contain a pointer to the real factory.
   203         MFileSystemExtInterface* pExtIf = (CFileSystem::MFileSystemExtInterface*)pa;
   204         ASSERT(pExtIf);
   205         
   206         return pExtIf->NewMountExL(apDrive, apFileSystem, aForceMount, aFsNameHash);
   207         }
   208     else
   209         {//--This interface is not supported by current CFileSystem implementation, call normal legacy factory method
   210          //-- and make _this_ object of CFileSystem produce a new CMountCB 
   211             ASSERT(aFsNameHash == 0); //-- it is impossible to specify the particular FS to be used
   212             *apFileSystem = this; 
   213             return NewMountL();
   214         }
   215         
   216     }
   217 
   218 
   219 //----------------------------------------------------------------------------- 
   220 /** 
   221     Get the name of a filesystem from the list of supported on this drive.
   222     Some filesystems (e.g. "automounter" can support more than one real "child" filesystems.
   223     For the normal case, only one filesystem is supported (a mouned one).
   224 
   225     @param  aFsNumber   used to enumerate supported filesystems can be:
   226                         special value KRootFileSystem, or
   227                         0,1,2... - the sequence number of a "child" FS.
   228     
   229     @param  aFsName     out: buffer for the returned file system name
   230 
   231     @return KErrNone        Ok, aFsName contains valid value for the given aFsNumber
   232             KErrNotFound    There is no supported filesystem for the given aFsNumber
   233 */
   234 TInt CFileSystem::GetSupportedFileSystemName(TInt aFsNumber, TDes& aFsName) 
   235     {
   236     TAny* pa;
   237 
   238     //-- we need a special interface to find out the name of the supported file system number "aFsNumber"
   239     if(GetInterface(EExtendedFunctionality, pa, NULL) == KErrNone)
   240         {
   241         MFileSystemExtInterface* pExtIf = (CFileSystem::MFileSystemExtInterface*)pa;
   242         ASSERT(pExtIf);
   243         return pExtIf->GetSupportedFileSystemName(aFsNumber, aFsName);   
   244         }
   245     else
   246         {//--This interface is not supported by current CFileSystem implementation, but in this case "Root" and first "child" filesystem mean
   247          //-- the same and this is "this" filesystem
   248             
   249             if(aFsNumber == RFs::KRootFileSystem || aFsNumber == RFs::KFirstChildFileSystem)
   250                 {
   251                 aFsName = Name();
   252                 return KErrNone;               
   253                 }
   254             else
   255                 {
   256                 return KErrNotFound;
   257                 }
   258         }
   259     }
   260 
   261 //----------------------------------------------------------------------------- 
   262 
   263 TInt InstallFileSystem(CFileSystem* aSys,RLibrary aLib)
   264 //
   265 // Install a file system.
   266 //
   267 	{
   268 
   269 	TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemInstall, EF32TraceUidFileSys, aSys);
   270 	TInt r=aSys->Install();
   271 	TRACERETMULT2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemInstallRet, EF32TraceUidFileSys, r, aSys->Name());
   272 
   273 	__PRINT1TEMP(_L("InstallFileSystem %S"),aSys->Name());
   274 	if (r==KErrNone)
   275 		{TRAP(r,FileSystems->AddL(aSys,ETrue))}
   276 	if (r!=KErrNone)
   277 		{
   278 		TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemove, EF32TraceUidFileSys, aSys);
   279 #ifdef SYMBIAN_FTRACE_ENABLE
   280 		TInt r = 
   281 #endif
   282 			aSys->Remove();
   283 		
   284 		TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemoveRet, EF32TraceUidFileSys, r);
   285 		}
   286 	if (r==KErrNone)
   287 		aSys->SetLibrary(aLib);
   288 	else
   289 		aSys->Close();
   290 	return(r);
   291 	}
   292 
   293 EXPORT_C CFileSystem* GetFileSystem(const TDesC& aName)
   294 //
   295 // Lookup a file system by name.
   296 //
   297 	{
   298 
   299 	TInt h=0;
   300 	TInt r=FileSystems->FindByName(h,aName);
   301 	if (r!=KErrNone)
   302 		return(NULL);
   303 	return((CFileSystem*)FileSystems->At(h));
   304 	}
   305 
   306 TInt TFsAddFileSystem::DoRequestL(CFsRequest* aRequest)
   307 //
   308 // Add a file system.
   309 //
   310 	{
   311 
   312 	__PRINT(_L("TFsAddFileSystem::DoRequestL(CFsRequest* aRequest)"));
   313 	
   314 	RLibrary lib;
   315 	lib.SetHandle(aRequest->Message().Int0()); // Get library handle
   316 	if (lib.Type()[1]!=TUid::Uid(KFileSystemUidValue))
   317 		return KErrNotSupported;
   318 
   319 	TFileSystemNew f=(TFileSystemNew)lib.Lookup(1);
   320 	if (!f)
   321 		return KErrCorrupt;
   322 	
   323 	TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNew, EF32TraceUidFileSys, lib.Handle());
   324 	CFileSystem* pS=(*f)();
   325 	TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewRet, EF32TraceUidFileSys, pS);
   326 	if (!pS)
   327 		return KErrNoMemory;
   328 	TInt r=InstallFileSystem(pS,lib);
   329 	if (r==KErrNone && !LocalFileSystemInitialized)
   330 		{
   331 		_LIT(KLocFSY, "ELOCAL.FSY");
   332 		TFileName fn(lib.FileName());
   333 		TParsePtrC ppc(fn);
   334 
   335 		if (ppc.NameAndExt().CompareF(KLocFSY) == 0)
   336 			r = InitializeLocalFileSystem(pS->Name());
   337 		}
   338 	return r;
   339 	}
   340 
   341 TInt TFsAddFileSystem::Initialise(CFsRequest* aRequest)
   342 //
   343 //
   344 //
   345 	{
   346 	TSecurityPolicy policy(RProcess().SecureId(), ECapabilityTCB);
   347 	if (!policy.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Add File System")))
   348 		return KErrPermissionDenied;
   349 	return KErrNone;
   350 	}
   351 
   352 TInt TFsRemoveFileSystem::DoRequestL(CFsRequest* aRequest)
   353 //
   354 // Remove a file system.
   355 //
   356 	{
   357 
   358 	TFullName name;
   359 	aRequest->ReadL(KMsgPtr0,name);
   360 	CFileSystem* pF=GetFileSystem(name);
   361 	if (pF==NULL)
   362 		return(KErrNotFound);
   363 
   364 	CFileSystem* pFs = NULL;
   365 	for(TInt drvNum=0; drvNum<KMaxDrives; drvNum++)
   366 		{
   367 		FsThreadManager::LockDrive(drvNum);
   368 		pFs=TheDrives[drvNum].GetFSys();
   369 		FsThreadManager::UnlockDrive(drvNum);
   370 		if(!pFs)
   371 			continue;
   372 		
   373         if(name.CompareF(pFs->Name()) == 0)
   374 			return KErrInUse;
   375 		}
   376 	
   377     TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemove, EF32TraceUidFileSys, pF);
   378 	TInt r=pF->Remove();
   379 	TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemoveRet, EF32TraceUidFileSys, r);
   380 	if (r!=KErrNone)
   381 		return(r);
   382 	
   383     RLibrary lib=pF->Library();
   384 	pF->Close();
   385 	lib.Close();
   386 
   387     return KErrNone;
   388 	}
   389 
   390 TInt TFsRemoveFileSystem::Initialise(CFsRequest* aRequest)
   391 //
   392 //
   393 //
   394 	{
   395 	if (!KCapFsRemoveFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Remove File System")))
   396 		return KErrPermissionDenied;
   397 	return KErrNone;
   398 	}
   399 
   400 LOCAL_C TInt DoMountFileSystem(CFsRequest* aRequest)
   401 //
   402 //
   403 //
   404 	{
   405 	TInt r = TFileCacheSettings::ReadPropertiesFile(aRequest->Drive()->DriveNumber());
   406 	if (r != KErrNone)
   407 		return r;
   408 
   409 	return(aRequest->Drive()->CheckMount());
   410 	}
   411 
   412 
   413 LOCAL_C TInt DoMountFsInitialise(CFsRequest* aRequest,TDesC& aFsName,TBool aIsExtension,TBool aIsSync)
   414 //
   415 //
   416 //
   417 	{
   418 	if (!KCapFsMountFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Mount File System")))
   419 		return KErrPermissionDenied;
   420 
   421 	TInt r=ValidateDrive(aRequest->Message().Int1(),aRequest);
   422 	if(r!=KErrNone)
   423 		return(r);
   424 
   425 	TBool driveThreadExists = FsThreadManager::IsDriveAvailable(aRequest->DriveNumber(), ETrue);
   426 	if(driveThreadExists)
   427 		{
   428 		// A drive thread already exists for this drive.This could be because a filesystem
   429 		// is already mounted, or a proxy drive is loaded.  Check the mount to be sure...
   430 		if(aRequest->Drive()->GetFSys())
   431 			{
   432 			// Yes, a mount already exists so we can't mount another one!
   433 			return(KErrAccessDenied);
   434 			}
   435 
   436 		__ASSERT_DEBUG(IsProxyDrive(aRequest->DriveNumber()), User::Panic(_L("Bad thread state - No Mount or Proxy Drive Exists!"), -999));
   437 		}
   438 
   439 	// ...therefore no drive thread can be present
   440 	__ASSERT_DEBUG(!&aRequest->Drive()->FSys(),Fault(EMountFileSystemFSys));
   441 
   442 	if(aRequest->Drive()->IsSubsted())
   443 		return(KErrAccessDenied);
   444 
   445 	CFileSystem* pF = GetFileSystem(aFsName);
   446 	
   447 	if (pF == NULL)
   448 		return(KErrNotFound);
   449 
   450 	// Check that if the drive is a proxy drive (not using TBusLocalDrive) then the filesystem supports these...
   451 	TInt driveNumber = aRequest->DriveNumber();
   452 	if(IsProxyDrive(driveNumber))
   453 		{
   454 		if(!pF->IsProxyDriveSupported())
   455 			return KErrNotSupported;
   456 		
   457 		r = LocalDrives::SetupMediaChange(driveNumber);
   458 		}
   459 
   460 	TDriveInfo driveInfo;
   461 	driveInfo.iDriveAtt=0;
   462 	pF->DriveInfo(driveInfo, driveNumber);
   463 	if(!driveInfo.iDriveAtt)
   464 		r = KErrArgument;
   465 	
   466     if(r == KErrNone && !driveThreadExists)
   467 	    {
   468     	// determine whether file system synchronous or not not by flag passed in
   469 		r=FsThreadManager::InitDrive(driveNumber, aIsSync);
   470         }
   471 
   472 	if(r!=KErrNone)
   473 		return(r);
   474 
   475     
   476     //-- let TDrive object know if the drive is synchronous
   477 	aRequest->Drive()->SetSynchronous(aIsSync);
   478 
   479     if(aIsExtension && aRequest->Message().Ptr2()!=NULL)
   480 		{
   481 		TFullName extName;
   482 		r = aRequest->Read(KMsgPtr2,extName);
   483 		if (r!=KErrNone)
   484 			return r;
   485 		CProxyDriveFactory* pE=GetExtension(extName);
   486 		if(pE==NULL)
   487 			return(KErrNotFound);
   488 		r=aRequest->Drive()->MountExtension(pE,ETrue);
   489 		if(r!=KErrNone)
   490 			return(r);
   491 		}
   492 
   493 	TInt32 newAtt = 0;
   494 	TInt32 oldAtt = 0;
   495 	_LIT8( KAddAtt, "AddDriveAttributes");
   496 	_LIT8( KRemoveAtt, "RemoveDriveAttributes");
   497 	_LIT8( KLogicallyRemovableAtt, "KDRIVEATTLOGICALLYREMOVABLE");
   498 	_LIT8( KHiddenAtt, "KDRIVEATTHIDDEN");
   499 	_LIT8( KLogicallyRemovableAttHex, "0X200");
   500 	_LIT8( KHiddenAttHex, "0X400");
   501 	TBuf8<0x1000> addbuf;
   502 	addbuf.FillZ();
   503 	TBuf8<0x1000> removebuf;
   504 	removebuf.FillZ();
   505 	TInt drive = aRequest->Message().Int1();
   506 	_LIT8(KLitSectionNameDrive,"Drive%C");
   507 	TBuf8<8> sectionName;
   508 	sectionName.Format(KLitSectionNameDrive, 'A' + drive);
   509 	F32Properties::GetString(sectionName, KAddAtt, addbuf);
   510 	F32Properties::GetString(sectionName, KRemoveAtt, removebuf);  //oldAtt now contains value of the attributes to be removed from iDriveAtt.
   511 	
   512 	if(addbuf.Length() != 0)
   513 		{
   514 		TInt pos = 0;
   515 		TInt length = 0;
   516 		TPtrC8 ptr;
   517 		TBool endOfFlag=EFalse; 
   518 
   519 		while(!endOfFlag)
   520 		{
   521 		ptr.Set(addbuf.Mid(pos));
   522 		length = ptr.Locate(',');
   523 	
   524 		if(length == KErrNotFound)
   525 			{
   526 			endOfFlag = ETrue;
   527 			} 
   528 		else{
   529 			ptr.Set(ptr.Left(length));
   530 			pos += (length +1);
   531 			}
   532 		
   533 		if(((ptr.MatchF(KLogicallyRemovableAtt)) != KErrNotFound) || ((ptr.MatchF(KLogicallyRemovableAttHex)) != KErrNotFound))
   534 			newAtt |= KDriveAttLogicallyRemovable;
   535 		if(((ptr.MatchF(KHiddenAtt)) != KErrNotFound)  || ((ptr.MatchF(KHiddenAttHex)) != KErrNotFound))
   536 			newAtt |= KDriveAttHidden;
   537 		
   538 		}
   539 		}
   540 
   541 	if(removebuf.Length() != 0)
   542 		{
   543 		TInt pos = 0;
   544 		TInt length = 0;
   545 		TPtrC8 ptr;
   546 		TBool endOfFlag=EFalse; 
   547 
   548 		while(!endOfFlag)
   549 		{
   550 		ptr.Set(removebuf.Mid(pos));
   551 		length = ptr.Locate(',');
   552 	
   553 		if(length == KErrNotFound)
   554 			{
   555 			endOfFlag = ETrue;
   556 			} 
   557 		else{
   558 			ptr.Set(ptr.Left(length));
   559 			pos += (length +1);
   560 			}
   561 		
   562 		if(((ptr.MatchF(KLogicallyRemovableAtt)) != KErrNotFound) || ((ptr.MatchF(KLogicallyRemovableAttHex)) != KErrNotFound))
   563 			oldAtt |= KDriveAttLogicallyRemovable;
   564 		if(((ptr.MatchF(KHiddenAtt)) != KErrNotFound) || ((ptr.MatchF(KHiddenAttHex)) != KErrNotFound))
   565 			oldAtt |= KDriveAttHidden;
   566 		
   567 		}
   568 		}
   569 	
   570 	if ((newAtt & KDriveAttLogicallyRemovable) && (!(driveInfo.iDriveAtt & KDriveAttRemovable)) && (!(newAtt & KDriveAttRemovable)))
   571 		{
   572 		newAtt |= KDriveAttRemovable; 	//KDriveAttLogicallyRemovale should always set KDriveAttRemovale
   573 		}
   574 	if ((oldAtt & KDriveAttRemovable)  && (!(oldAtt & KDriveAttLogicallyRemovable)))
   575 		{
   576 		oldAtt |= KDriveAttLogicallyRemovable;
   577 		}
   578 	if(newAtt)
   579 		{
   580 		driveInfo.iDriveAtt |= newAtt;
   581 		}
   582 	if(oldAtt)
   583 		{
   584 		if(oldAtt & driveInfo.iDriveAtt)
   585 			{
   586 			driveInfo.iDriveAtt ^= oldAtt;  
   587 			}
   588 		}
   589 	aRequest->Drive()->SetAtt(driveInfo.iDriveAtt);
   590 	aRequest->Drive()->GetFSys()=pF;
   591 
   592 	// empty the closed file queue
   593 	TClosedFileUtils::Remove(aRequest->DriveNumber());
   594 
   595 	return(KErrNone);
   596 	}
   597 
   598 
   599 TInt TFsMountFileSystem::DoRequestL(CFsRequest* aRequest)
   600 //
   601 // Mount a filesystem on a drive.
   602 //
   603 	{
   604 	TInt r=DoMountFileSystem(aRequest);
   605 	if( KErrNone == r )
   606 		{
   607 		FsNotify::DiskChange(aRequest->DriveNumber());
   608 		}
   609 		
   610 	// Refresh the loader cache to ensure that the new drive is monitored.
   611 #ifndef __WINS__
   612 	gInitCacheCheckDrivesAndAddNotifications = EFalse;
   613 #endif 
   614 
   615 	return r;
   616 	}
   617 
   618 
   619 TInt TFsMountFileSystem::Initialise(CFsRequest* aRequest)
   620 //
   621 //	
   622 //
   623 	{
   624 	TFullName name;
   625 	TInt r = aRequest->Read(KMsgPtr0,name);
   626 	if (r == KErrNone)
   627 		r = DoMountFsInitialise(aRequest,name,ETrue,aRequest->Message().Int3());
   628 	return r;
   629 	}
   630 
   631 TInt TFsMountFileSystemScan::DoRequestL(CFsRequest* aRequest)
   632 //
   633 // mount file system and then call scandrive
   634 //
   635 	{
   636 	TInt r=DoMountFileSystem(aRequest);
   637 	// run scandrive if successful mount
   638 	TBool isMountSuccess=(KErrNone==r);
   639 	if(isMountSuccess)
   640 		{
   641 		r=aRequest->Drive()->ScanDrive();
   642 		FsNotify::DiskChange(aRequest->DriveNumber());
   643 		}
   644 	TPtrC8 pMS((TUint8*)&isMountSuccess,sizeof(TBool));
   645 	aRequest->WriteL(KMsgPtr3,pMS);
   646 	return(r);
   647 	}
   648 
   649 
   650 TInt TFsMountFileSystemScan::Initialise(CFsRequest* aRequest)
   651 //
   652 //	
   653 //
   654 	{
   655 	TFullName name;
   656 	TInt r = aRequest->Read(KMsgPtr0,name);
   657 	if (r == KErrNone)
   658 		r = DoMountFsInitialise(aRequest,name,ETrue,EFalse);
   659 	return r;
   660 	}
   661 
   662 LOCAL_C TInt DoDismountFileSystem(const TDesC& aName, TDrive* aDrive, TBool aAllowRom, TBool aForceDismount)
   663 //
   664 // Do file system dismount
   665 //
   666 	{
   667 	TInt drvNumber=aDrive->DriveNumber();
   668 
   669 	FsThreadManager::LockDrive(drvNumber);
   670 	CFileSystem* pF=GetFileSystem(aName);
   671 	if(pF==NULL)
   672 		{
   673 		FsThreadManager::UnlockDrive(drvNumber);
   674 		return(KErrNotFound);
   675 		}
   676 	if(aDrive->IsRom() && !aAllowRom)
   677 		{
   678 		FsThreadManager::UnlockDrive(drvNumber);
   679 		return(KErrAccessDenied);
   680 		}
   681 
   682 	if(!aForceDismount)
   683 		{
   684 		if(aDrive->IsMounted() && aDrive->CurrentMount().LockStatus()!=0)
   685 			{
   686 			FsThreadManager::UnlockDrive(drvNumber);
   687 			return(KErrInUse);
   688 			}
   689 		if(aDrive->ActiveMounts() > 1)
   690 			{
   691 			FsThreadManager::UnlockDrive(drvNumber);
   692 			return(KErrInUse);
   693 			}
   694 		
   695 		aDrive->ReactivateMounts();
   696 		}
   697 
   698 	// ensure that current mount is dismounted
   699 	if(aForceDismount)
   700 		{
   701 		TInt r = aDrive->FlushCachedFileInfo(ETrue);
   702 
   703 		// Dismount the file system even if the flush fails for some reason (media permanently removed, user cancels notifier etc
   704 		if (r!=KErrNone && r!=KErrAbort)
   705 			{
   706 			FsThreadManager::UnlockDrive(drvNumber);
   707 			return(r);
   708 			}
   709 		aDrive->ForceDismount();
   710 		}
   711 	else
   712 		{
   713 		aDrive->Dismount();
   714 		}
   715 
   716 	aDrive->GetFSys()=NULL;
   717 	aDrive->SetAtt(0);
   718 	aDrive->ExtInfo().iCount=0;
   719 
   720 	// no need to cancel requests if synchronous since queued
   721 	if(!FsThreadManager::IsDriveSync(drvNumber,EFalse))
   722 		{
   723 		CDriveThread* pT=NULL;
   724 		TInt r=FsThreadManager::GetDriveThread(drvNumber,&pT);
   725 		__ASSERT_ALWAYS(r==KErrNone && pT,Fault(EDismountFsDriveThread));
   726 		pT->CompleteAllRequests(KErrNotReady);
   727 		}
   728 
   729 	if(!IsProxyDrive(drvNumber))
   730 		{
   731 		// Proxy drives are responsible for managing the drive threads...
   732 		FsThreadManager::CloseDrive(drvNumber);
   733 		}
   734 
   735 	FsThreadManager::UnlockDrive(drvNumber);
   736 	FsNotify::DiskChange(drvNumber);
   737 	return(KErrNone);
   738 	}
   739 
   740 TInt TFsDismountFileSystem::DoRequestL(CFsRequest* aRequest)
   741 //
   742 // Dismount a filesystem from a drive.
   743 //
   744 	{
   745 	TDrive* drive=aRequest->Drive();
   746 	__ASSERT_DEBUG(&aRequest->Drive()->FSys() && !drive->IsSubsted(),Fault(EDisMountFileSystemFSys));
   747 	TFullName name;
   748 	aRequest->ReadL(KMsgPtr0,name);
   749 
   750 	if(drive->DismountDeferred())
   751 		return KErrInUse;
   752 
   753 	return DoDismountFileSystem(name, drive, EFalse, EFalse);
   754 	}
   755 
   756 TInt TFsDismountFileSystem::Initialise(CFsRequest* aRequest)
   757 //
   758 //	
   759 //
   760 	{
   761 	if (!KCapFsDismountFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Dismount File System")))
   762 		return KErrPermissionDenied;
   763 	TInt r = ValidateDrive(aRequest->Message().Int1(),aRequest);
   764 	if(r == KErrNone)
   765 		{
   766 		TInt driveNumber = aRequest->DriveNumber();
   767 		if(IsProxyDrive(driveNumber))
   768 			{
   769 			LocalDrives::NotifyChangeCancel(driveNumber);
   770 			}
   771 		}
   772 	return r;
   773 	}
   774 
   775 /**
   776     Return name of file system mounted on a specified drive or one of the file system names if 
   777     the drive supports several of them.
   778 */
   779 TInt TFsFileSystemName::DoRequestL(CFsRequest* aRequest)
   780 	{
   781 	//-- ipc parameters: 
   782     //-- 0 out: file system name decriptor
   783     //-- 1 drive number
   784     //-- 2 file system enumerator 
   785     
   786     const TInt driveNumber = aRequest->Message().Int1();
   787 	if (driveNumber < 0 || driveNumber >= KMaxDrives)
   788 		return KErrArgument;
   789 	
   790     const TInt fsNumber = aRequest->Message().Int2(); //-- file system number; for RFs::FileSystemName() it is "-1"
   791 
   792     TFullName fsName;
   793 	// lock drive to synchronise with dismounting a file system
   794 	FsThreadManager::LockDrive(driveNumber);
   795 	CFileSystem* pF=TheDrives[driveNumber].GetFSys();
   796 	FsThreadManager::UnlockDrive(driveNumber);
   797     
   798     TInt err = KErrNone;
   799 	
   800     if(pF)
   801         {
   802 		if(fsNumber == -1)
   803             fsName = pF->Name(); //-- this is RFs::FileSystemName() call
   804         else
   805             err = pF->GetSupportedFileSystemName(fsNumber, fsName); //-- this is RFs::SupportedFileSystemName() call
   806 	    }
   807 	else
   808 		{//-- the drive doesn't have file system installed
   809         fsName=_L("");
   810 		err = KErrNotFound;
   811 	    }
   812     
   813     aRequest->WriteL(KMsgPtr0, fsName);
   814 	
   815     return err;
   816 	}
   817 
   818 TInt TFsFileSystemName::Initialise(CFsRequest* /*aRequest*/)
   819 	{
   820 	return KErrNone;
   821 	}
   822 
   823 TInt TFsRemountDrive::DoRequestL(CFsRequest* aRequest)
   824 //
   825 // Force a remount of the specified drive
   826 //
   827 	{	
   828 	const TDesC8 *mountInfo=REINTERPRET_CAST(const TDesC8*,aRequest->Message().Ptr1());
   829 	return(aRequest->Drive()->ForceRemountDrive(mountInfo,aRequest->Message().Handle(),aRequest->Message().Int2()));//changed from thread to message handle
   830 	}
   831 
   832 TInt TFsRemountDrive::Initialise(CFsRequest* aRequest)
   833 //
   834 //	
   835 //
   836 	{
   837 
   838 	TInt r=ValidateDriveDoSubst(aRequest->Message().Int0(),aRequest);
   839 	return(r);
   840 	}
   841 
   842 TInt TFsSetLocalDriveMapping::DoRequestL(CFsRequest* aRequest)
   843 //
   844 // set up drive letter to local drive mapping
   845 //
   846 	{
   847 	return(LocalDrives::SetDriveMappingL(aRequest));
   848 	}
   849 
   850 TInt TFsSetLocalDriveMapping::Initialise(CFsRequest* /*aRequest*/)
   851 //
   852 //
   853 //
   854 	{
   855 	return KErrNone;
   856 	}
   857 	
   858 _LIT(KCompositeFsName,"Composite");
   859 
   860 TInt TFsSwapFileSystem::DoRequestL(CFsRequest* aRequest)
   861 //
   862 // Swap a filesystem on a drive
   863 // Should always leave a filesystem mounted on the drive
   864 //
   865 	{
   866 	TFileName newName;
   867 	aRequest->ReadL(KMsgPtr0,newName);										
   868 	CFileSystem* pF=GetFileSystem(newName);												
   869 	if (pF==NULL)															
   870 		return(KErrNotFound);
   871 	TFileName oldName;			
   872 	aRequest->ReadL(KMsgPtr2,oldName);										
   873 	TInt drvNumber=aRequest->Message().Int1();	
   874 	TBool newFsIsComposite = (newName.CompareF(KCompositeFsName) == 0);	
   875 							
   876 	if (newFsIsComposite)
   877 		{
   878 		if(CompFsMounted)
   879 			return(KErrAlreadyExists);
   880 		if(EDriveZ!=drvNumber)
   881 			return(KErrNotSupported);
   882 		}	
   883 	else
   884 		 // swapping filesystem on z: only allow for romfs + compfs
   885 		if(EDriveZ==drvNumber)
   886 			return(KErrNotSupported);
   887 	
   888 	TDrive& drive=TheDrives[drvNumber];
   889 	
   890 	if(drive.DismountDeferred())
   891 		return KErrInUse;
   892 
   893 	TBool clamps=drive.ClampFlag();
   894 	if(clamps)
   895 		return KErrInUse;
   896 
   897 	// Return an error if the drive is asynchronous.
   898 	// This function is only supported on synchronous drives.
   899 	TBool isSync = FsThreadManager::IsDriveSync(drvNumber,EFalse);
   900 	if(!isSync)
   901 		return KErrNotSupported;
   902 	
   903 	TInt r=DoDismountFileSystem(oldName,&drive,ETrue,EFalse);
   904 	if(r!=KErrNone)
   905 		return(r);
   906 	
   907 	__ASSERT_ALWAYS(drive.GetFSys()==NULL,Fault(ESwapFileSystemNull));
   908 
   909 	r=DoMountFsInitialise(aRequest,newName,EFalse,isSync);
   910 	if(r==KErrNone)
   911 		r=DoMountFileSystem(aRequest);
   912 
   913 	if(drive.GetFSys()==NULL || (newFsIsComposite && r!=KErrNone)) 
   914 		{
   915 		// remounting of the original filesystem should not fail
   916 		if(drive.GetFSys()!=NULL)
   917 			r=DoDismountFileSystem(newName,&drive,ETrue,EFalse);
   918 
   919 		r=DoMountFsInitialise(aRequest,oldName,EFalse,isSync);
   920 		if(r==KErrNone)
   921 			r=DoMountFileSystem(aRequest);
   922 
   923 		__ASSERT_ALWAYS(r==KErrNone && drive.GetFSys()!=NULL,Fault(ESwapFileSystemMount));
   924 		}
   925 	else if (newFsIsComposite)
   926 		{
   927 		FsThreadManager::ChangeSync(drvNumber,CompFsSync);
   928 		CompFsMounted=ETrue;
   929 		}
   930 			
   931 	if(drvNumber==EDriveZ)
   932 		{
   933 		__ASSERT_ALWAYS(r==KErrNone,Fault(ESwapFileSystemRom));
   934 		RefreshZDriveCache=ETrue;
   935 		}
   936 	return(r);
   937 	}
   938 
   939 TInt TFsSwapFileSystem::Initialise(CFsRequest* /*aRequest*/)
   940 //
   941 //	
   942 //
   943 	{
   944 	return KErrNone;
   945 	}	
   946 
   947 
   948 TInt TFsAddCompositeMount::DoRequestL(CFsRequest* aRequest)
   949 //
   950 // Input fsyName, localDriveNUmber, CompositeDriveNumber
   951 // 
   952 //
   953 	{
   954 	__PRINT(_L("TFsAddCompositeMount::DoRequestL"));
   955 
   956 	TFileName fsyName;
   957 	aRequest->ReadL(KMsgPtr0,fsyName);										
   958 	CFileSystem* pNewFileSystem=GetFileSystem(fsyName);
   959 
   960 	if (pNewFileSystem==NULL)
   961 		return KErrNotFound;
   962 	
   963 	const TInt localDriveNumber=aRequest->Message().Int1();								
   964 	const TInt compositeDriveNumber=aRequest->Message().Int2();
   965 	const TInt sync=aRequest->Message().Int3();									
   966 	
   967     __PRINT3(_L("TFsAddCompositeMount::DoRequestL fsy:%S, locDrv:%d, compDrv:%d"),&fsyName, localDriveNumber,compositeDriveNumber);
   968 
   969 	// Currently, compFS assumed its mounting on romfs, on z:
   970 	if (compositeDriveNumber!=EDriveZ)
   971 		return KErrNotSupported;
   972 	
   973 	// Mounts can only be added to the compfs, before it is mounted.
   974 	if (CompFsMounted)
   975 		return KErrInUse;
   976 	
   977 	// The drive is needed, so the new sub mount, can be mounted
   978 	// on it temporarily.  ROMFS doest care if we do this as it
   979 	// has no local mapping.
   980 	FsThreadManager::LockDrive(compositeDriveNumber);
   981 		
   982 	TRAPD(err, AddFsToCompositeMountL(compositeDriveNumber, *pNewFileSystem, localDriveNumber));
   983 	if (err!=KErrNone)
   984 		{
   985 		FsThreadManager::UnlockDrive(compositeDriveNumber);
   986 		return err;
   987 		}
   988 //		Fault(EMountFileSystemFSys);
   989 
   990 	FsThreadManager::UnlockDrive(compositeDriveNumber);
   991 	
   992 	// The drive will end up asynchronous if any sub mounts are.
   993 	if (!sync)
   994 		CompFsSync=EFalse;
   995 
   996 	return KErrNone;
   997 	}
   998 
   999 
  1000 TInt TFsAddCompositeMount::Initialise(CFsRequest* aRequest)
  1001 //
  1002 //	
  1003 //
  1004 	{
  1005 	if (!KCapFsAddCompositeMount.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Add Composite Mount")))
  1006 		return KErrPermissionDenied;
  1007 	return KErrNone;
  1008 	}	
  1009 
  1010 void TFsAddCompositeMount::AddFsToCompositeMountL(TInt aDriveNumber, CFileSystem& aFileSystem, TInt aLocalDriveNumber)
  1011 	{
  1012 	__PRINT3(_L("TFsAddCompositeMount::AddFsToCompositeMountL()  FS:0x%x, drv:%d, local drive:%d"),&aFileSystem, aDriveNumber,aLocalDriveNumber);
  1013 	TInt err;
  1014 
  1015 	TDrive& theDrive=TheDrives[aDriveNumber];
  1016 	CFileSystem* pFs = theDrive.GetFSys();
  1017 	
  1018 	CFileSystem* pCompFS = GetFileSystem(_L("Composite"));
  1019 	if ((pCompFS == NULL) || (pFs==NULL))
  1020 		User::Leave(KErrNotReady);
  1021 	
  1022 	CMountCB* pMount = pCompFS->NewMountL(); //-- pMount is, actually, a singleton.
  1023     pMount->InitL(theDrive, pCompFS);
  1024 
  1025     
  1026 	// invalidate the drive previously used by the local drive just added, and swap with a DriveNumber
  1027 	TInt drv;
  1028 	drv = LocalDrives::GetDriveFromLocalDrive(aLocalDriveNumber);
  1029 	__ASSERT_ALWAYS(drv!=KDriveInvalid, User::Leave(KErrNotSupported));
  1030 	//__PRINT1(_L("TFsAddCompositeMount::AddFsToCompositeMountL : drive to invalidate %d"),drv);
  1031 	LocalDrives::iMapping[drv] = KDriveInvalid;
  1032 	LocalDrives::iMapping[aDriveNumber] = aLocalDriveNumber;
  1033 
  1034 	// Ask the composite mount to mount the new filesystem.
  1035 	TAny* dummy=NULL;
  1036 	err = pMount->GetInterfaceTraced(CMountCB::EAddFsToCompositeMount, dummy, &aFileSystem);
  1037 	if(err != KErrNone)
  1038 		User::Leave(err);
  1039 	}
  1040 
  1041 
  1042 TInt TDrive::DeferredDismount()
  1043 	{
  1044 	// Dismount
  1045 	TInt err = DoDismountFileSystem(GetFSys()->Name(), this, EFalse, ETrue);
  1046 	if (err == CFsRequest::EReqActionBusy)
  1047 		return err;
  1048 
  1049     DoCompleteDismountNotify(err);
  1050 
  1051 	SetDismountDeferred(EFalse);
  1052 
  1053 	return err;
  1054 	}
  1055 
  1056 TInt TFsNotifyDismount::Initialise(CFsRequest* aRequest)
  1057 //
  1058 // Initialise a dismount notifier. 
  1059 // - All clients may register with EFsDismountRegisterClient.
  1060 // - DiskAdmin is required for EFsDismountNotifyClients and EFsDismountForceDismount
  1061 //
  1062 	{
  1063 	const RMessage2& m=aRequest->Message();
  1064 	const TNotifyDismountMode mode = (TNotifyDismountMode)m.Int1();
  1065 
  1066 	switch(mode)
  1067 		{
  1068 		case EFsDismountForceDismount:
  1069 		case EFsDismountNotifyClients:
  1070 			{
  1071 			// Capabilities are required to dismount a file system
  1072 			if(!KCapFsDismountFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Notify Dismount")))
  1073 				return KErrPermissionDenied;
  1074 			break;
  1075 			}
  1076 
  1077 		case EFsDismountRegisterClient:
  1078 			{
  1079 			// No capabilities are required for a client to register for notification
  1080 			break;
  1081 			}
  1082 
  1083 		default:
  1084 			{
  1085 			return KErrArgument;
  1086 			//break;
  1087 			}
  1088 		}
  1089 
  1090 	return ValidateDrive(aRequest->Message().Int0() ,aRequest);
  1091 	}	
  1092 
  1093 TInt TFsNotifyDismount::DoRequestL(CFsRequest* aRequest)
  1094 //
  1095 // Register for notification of pending dismount [EFsDismountRegisterClient]
  1096 // or notify clients of a pending dismount		 [EFsDismountNotifyClients]
  1097 // or forcibly dismount the file system			 [EFsDismountForceDismount]
  1098 //
  1099 	{
  1100 	__ASSERT_DEBUG(&aRequest->Drive()->FSys() && !aRequest->Drive()->IsSubsted(), Fault(ENotifyDismount));
  1101 
  1102 	TInt err = KErrNone;
  1103 
  1104 	const RMessage2& m=aRequest->Message();
  1105 	const TNotifyDismountMode mode = (TNotifyDismountMode)m.Int1();
  1106 	TDrive* theDrive = aRequest->Drive();
  1107 	const TInt driveNumber = theDrive->DriveNumber();
  1108 
  1109 	switch(mode)
  1110 		{
  1111 		case EFsDismountRegisterClient:
  1112 			{
  1113 			err = RegisterNotify(aRequest);
  1114 			break;
  1115 			}
  1116 
  1117 		case EFsDismountNotifyClients:
  1118 			{
  1119 			if(aRequest->Drive()->DismountLocked())
  1120 				{
  1121 				err = RegisterNotify(aRequest);
  1122 				if (err != KErrNone)
  1123 					return err;
  1124 				// Complete outstanding client dismount notifiers and flag the drive as pending dismount.
  1125 				FsNotify::HandleDismount(EFsDismountRegisterClient, driveNumber, EFalse, KErrNone);
  1126 				theDrive->SetDismountDeferred(ETrue);
  1127 				}
  1128 			else
  1129 				{
  1130 				// There are no interested clients, so dismount immediately - if no clamps are present
  1131 				err = theDrive->ClampsOnDrive();
  1132 
  1133 				// If there are no clamps or clamping is not supported, proceed with the enforced dismount
  1134 				// If there are clamps, wait for the clamps to be removed
  1135 				if (err > 0)
  1136 					{
  1137 					err = RegisterNotify(aRequest);
  1138 					theDrive->SetDismountDeferred(ETrue);
  1139 					}
  1140 				else if (err == 0 || err == KErrNotSupported)
  1141 					{
  1142 					// No clamps to worry about, so dismount immediately and complete the request
  1143 					err = DoDismountFileSystem(theDrive->GetFSys()->Name(), theDrive, EFalse, ETrue);
  1144 					if (err == CFsRequest::EReqActionBusy)
  1145 						return err;
  1146 					m.Complete(err);
  1147 					}
  1148 				}
  1149 			break;
  1150 			}
  1151 
  1152 		case EFsDismountForceDismount:
  1153 			{
  1154 			// Prepare for deferred dismount due to the presence of file clamps
  1155 			err = theDrive->ClampsOnDrive();
  1156 
  1157 			// If there are no clamps or clamping is not supported, proceed with the enforced dismount
  1158 			// If there are clamps, wait for the clamps to be removed
  1159 			if(err > 0)
  1160 				{
  1161 				err = RegisterNotify(aRequest);
  1162 				theDrive->SetDismountDeferred(ETrue);
  1163 				}
  1164 			else if (err == 0 || err == KErrNotSupported)
  1165 				{
  1166 				// Forced dismount - notify/remove all client notifiers and complete immediately
  1167 				err = theDrive->DeferredDismount();
  1168 				if (err == CFsRequest::EReqActionBusy)
  1169 					return err;
  1170 				m.Complete(err);
  1171 				}
  1172 			break;
  1173 			}
  1174 
  1175 		default:
  1176 			{
  1177 			// We shouldn't ever get here
  1178 			Fault(ENotifyDismount);
  1179 			break;
  1180 			}
  1181 		}
  1182 
  1183 	return err;
  1184 	}
  1185 
  1186 TInt TFsNotifyDismount::RegisterNotify(CFsRequest* aRequest)
  1187 //
  1188 // Register for notification of pending dismount [EFsDismountRegisterClient]
  1189 // or notify clients of a pending dismount		 [EFsDismountNotifyClients]
  1190 // or forcibly dismount the file system			 [EFsDismountForceDismount]
  1191 //
  1192 	{
  1193 	const RMessage2& m=aRequest->Message();
  1194 	const TNotifyDismountMode mode = (TNotifyDismountMode)m.Int1();
  1195 	TDrive* theDrive = aRequest->Drive();
  1196 	const TInt driveNumber = theDrive->DriveNumber();
  1197 
  1198 	if (mode == EFsDismountNotifyClients && theDrive->DismountDeferred())
  1199 		{
  1200 		return KErrInUse;
  1201 		}
  1202 
  1203 	CDismountNotifyInfo* info = new CDismountNotifyInfo;
  1204 	if(info == NULL)
  1205 		{
  1206 		return KErrNoMemory;
  1207 		}
  1208 
  1209 	info->Initialise(mode, driveNumber, (TRequestStatus*)m.Ptr2(), m, aRequest->Session());
  1210 	TInt err = FsNotify::AddDismountNotify(info);
  1211 	if(err != KErrNone)
  1212 		{
  1213 		delete info;
  1214 		return err;
  1215 		}
  1216 
  1217 	return KErrNone;
  1218 	}
  1219 
  1220 TInt TFsNotifyDismountCancel::DoRequestL(CFsRequest* aRequest)
  1221 //
  1222 // Cancel a pending dismount notifier - Request
  1223 //
  1224 	{
  1225 	CSessionFs* session = aRequest->Session();
  1226 	FsNotify::CancelDismountNotifySession(session, (TRequestStatus*)aRequest->Message().Ptr0());
  1227 	return KErrNone;
  1228 	}
  1229 
  1230 TInt TFsNotifyDismountCancel::Initialise(CFsRequest* /*aRequest*/)
  1231 //
  1232 //	Cancel a pending dismount notifier - Initialise
  1233 //
  1234 	{
  1235 	return KErrNone;
  1236 	}	
  1237 
  1238 TInt TFsAllowDismount::DoRequestL(CFsRequest* aRequest)
  1239 //
  1240 // Notifies the file server that the client is finished with the drive.
  1241 // The last client to allow the dismount signals the dismounting thread.
  1242 //
  1243 	{
  1244 	TDrive* theDrive = aRequest->Drive();
  1245 	const TInt driveNumber = theDrive->DriveNumber();
  1246 
  1247 	// Verify that the client has registered for notification
  1248 	if(!FsNotify::HandlePendingDismount(aRequest->Session(), driveNumber))
  1249 		return KErrNotFound;
  1250 
  1251 	if(theDrive->DismountLocked())
  1252 		return KErrNone;
  1253 
  1254 	TInt clampErr = theDrive->ClampsOnDrive();
  1255 	TInt err = KErrNone;
  1256 
  1257 	if ((theDrive->DismountDeferred()) && (clampErr == 0 || clampErr == KErrNotSupported))
  1258 		{
  1259 		// No clamps to worry about, so dismount immediately and complete the request
  1260 		__ASSERT_DEBUG(aRequest->Drive()->GetFSys(), Fault(EAllowDismount));
  1261 
  1262 		// When the last client has responded, allow the media to be forcibly dismounted
  1263 		err = theDrive->DeferredDismount();
  1264 		}
  1265 
  1266 	return err;
  1267 	}
  1268 
  1269 TInt TFsAllowDismount::Initialise(CFsRequest* aRequest)
  1270 //
  1271 // Notifies the file server that the client is finished with the drive
  1272 //
  1273 	{
  1274 	return ValidateDrive(aRequest->Message().Int0(),aRequest);
  1275 	}	
  1276 
  1277 
  1278 TInt TFsMountProxyDrive::DoRequestL(CFsRequest* aRequest)
  1279 	{
  1280 	return LocalDrives::MountProxyDrive(aRequest);
  1281 	}
  1282 
  1283 TInt TFsMountProxyDrive::Initialise(CFsRequest* aRequest)
  1284 	{
  1285 	if (!KCapFsMountProxyDrive.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Mount Proxy Drive")))
  1286 		return KErrPermissionDenied;
  1287 
  1288     TInt err = LocalDrives::InitProxyDrive(aRequest);
  1289 	if(err == KErrNone)
  1290 	    {
  1291     	// Now create the drive thread - proxy extensions are always asynchronous...
  1292 		err = FsThreadManager::InitDrive(aRequest->DriveNumber(), EFalse);
  1293         }
  1294 
  1295 	return err;
  1296 	}
  1297 
  1298 TInt TFsLoadCodePage::DoRequestL(CFsRequest* aRequest)
  1299 //
  1300 // Installs a code page
  1301 //
  1302 	{
  1303 	__PRINT(_L("TFsLoadCodePage::DoRequestL(CFsRequest* aRequest)"));
  1304 
  1305 	RLibrary lib;
  1306 	lib.SetHandle(aRequest->Message().Int0());
  1307 	if (lib.Type()[1]!=TUid::Uid(KLocaleDllUidValue16))
  1308 		return(KErrNotSupported);
  1309 
  1310 	if(TheCodePage.CodepageLoaded() == TCodePageUtils::ECodePageDll)
  1311 		{
  1312 		return(KErrAlreadyExists);
  1313 		}
  1314 
  1315 	/*
  1316 	// Actual Functions form the Codepage Dll (fatCnvU.def)
  1317 	1	:	void UnicodeConv::ConvertFromUnicodeL(class TDes8 &, class TDesC16 const &)
  1318 	2	:	void UnicodeConv::ConvertToUnicodeL(class TDes16 &, class TDesC8 const &)
  1319 	3	:	int UnicodeConv::IsLegalShortNameCharacter(unsigned int)
  1320 	4	:	int UnicodeConv::ConvertFromUnicodeL(class TDes8 &, class TDesC16 const &, int)
  1321 	5	:	int UnicodeConv::ConvertToUnicodeL(class TDes16 &, class TDesC8 const &, int)
  1322 	*/
  1323 
  1324 	/*
  1325 	Read only the following fns from Codepage Dll ( lib.Lookup(1) and lib.Lookup(2) retained in cpnnn.dll for backward compatibility)
  1326 	3	:	int UnicodeConv::IsLegalShortNameCharacter(unsigned int)
  1327 	4	:	int UnicodeConv::ConvertFromUnicodeL(class TDes8 &, class TDesC16 const &, int)
  1328 	5	:	int UnicodeConv::ConvertToUnicodeL(class TDes16 &, class TDesC8 const &, int)
  1329 	*/
  1330 
  1331 	TheCodePage.iCodePageFunctions.iIsLegalShortNameCharacter = (TCodePageFunctions::TIsLegalShortNameCharacter)(lib.Lookup(3));
  1332 	TheCodePage.iCodePageFunctions.iConvertFromUnicodeL = (TCodePageFunctions::TConvertFromUnicodeL)(lib.Lookup(4));
  1333 	TheCodePage.iCodePageFunctions.iConvertToUnicodeL = (TCodePageFunctions::TConvertToUnicodeL)(lib.Lookup(5));
  1334 
  1335 	if( TheCodePage.iCodePageFunctions.iIsLegalShortNameCharacter == NULL || 
  1336 		TheCodePage.iCodePageFunctions.iConvertFromUnicodeL == NULL ||
  1337 		TheCodePage.iCodePageFunctions.iConvertToUnicodeL == NULL )
  1338 		{
  1339 		return(KErrCorrupt);
  1340 		}
  1341 	TheCodePage.iCodepageLoaded = TCodePageUtils::ECodePageDll;
  1342 
  1343 	return(KErrNone);
  1344 	}
  1345 
  1346 TInt TFsLoadCodePage::Initialise(CFsRequest* aRequest)
  1347 //
  1348 // Installs a code page
  1349 //
  1350 	{
  1351 	__PRINT(_L("TFsLoadCodePage::Initialise(CFsRequest* aRequest)"));
  1352 	
  1353 	// Set the drive
  1354 	TInt drive = aRequest->Session()->CurrentDrive();
  1355 	aRequest->SetDrive(&TheDrives[drive]);
  1356 
  1357 	TSecurityPolicy policy(RProcess().SecureId(), ECapabilityDiskAdmin);
  1358 	if (!policy.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("TFsLoadCodePage::Initialise")))
  1359 		{
  1360 		return KErrPermissionDenied;
  1361 		}
  1362 	
  1363 	return KErrNone;
  1364 	}
  1365 
  1366 // use second half of ISO Latin 1 character set for extended chars
  1367 const TUint KExtendedCharStart=0x80;
  1368 const TUint KExtendedCharEnd=0xff;
  1369 
  1370 _LIT8(KLit8ReplacementForUnconvertibleUnicodeCharacters, "_");
  1371 
  1372 TCodePageUtils::TCodePageUtils()
  1373 //
  1374 // Constructor
  1375 //
  1376   :	iCodePageFunctions(),
  1377 	iLocaleFatUtilityFunctions(NULL),
  1378 	iCodepageLoaded(ENone)
  1379 	{
  1380 	}
  1381 
  1382 TBool TCodePageUtils::IsCodepageLoaded() const
  1383 //
  1384 // Returns ETrue if a codepage is loaded
  1385 //
  1386 	{
  1387 	return(iCodepageLoaded != ENone);
  1388 	}
  1389 
  1390 TCodePageUtils::TCodepageLoaded TCodePageUtils::CodepageLoaded() const
  1391 //
  1392 // Returns the type of active codepage
  1393 //
  1394 	{
  1395 	return(iCodepageLoaded);
  1396 	}
  1397 
  1398 void TCodePageUtils::SetLocaleCodePage(TFatUtilityFunctions* aFunctions)
  1399 //
  1400 // Sets the current codepage to that provided by the current Locale DLL
  1401 //
  1402 	{
  1403 	if(iCodepageLoaded == ENone && aFunctions)
  1404 		{
  1405 		iLocaleFatUtilityFunctions = aFunctions;
  1406 		iCodepageLoaded = ELocaleDll;
  1407 		}
  1408 	}
  1409 
  1410 TFatUtilityFunctions* TCodePageUtils::LocaleFatUtilityFunctions() const
  1411 //
  1412 // Returns function pointer to the read Locale conversions functions
  1413 //
  1414 	{
  1415 	return(iLocaleFatUtilityFunctions);
  1416 	}
  1417 
  1418 TCodePageFunctions TCodePageUtils::CodepageFatUtilityFunctions() const
  1419 //
  1420 // Returns structure to function pointers to the read Codepage conversions functions
  1421 //
  1422 	{
  1423 	return(iCodePageFunctions);
  1424 	}
  1425 
  1426 TBool TCodePageUtils::ConvertFromUnicode(TDes8& aForeign, const TDesC16& aUnicode, TOverflowAction aOverflowAction) const
  1427 /**
  1428 Convert from Unicode, truncating if there is not enough room in the output.
  1429 
  1430 @param aForeign The output is appended here.
  1431 @param aUnicode The input.
  1432 
  1433 @return False if and only if aForeign has not enough space remaining. 
  1434 */
  1435 	{
  1436 	TBool allConverted = ETrue;
  1437 	const TInt maximumLength=aForeign.MaxLength();
  1438 	TInt lengthToCopy=aUnicode.Length();
  1439 	// do not cross the maximum foreign length
  1440 	if (maximumLength<lengthToCopy)
  1441 		{
  1442 		if (aOverflowAction==TCodePageUtils::EOverflowActionLeave)
  1443 			{
  1444 			allConverted = EFalse;
  1445 			return allConverted;
  1446 			}
  1447 		lengthToCopy=maximumLength;
  1448 		}
  1449 
  1450 	aForeign.SetLength(lengthToCopy);
  1451 
  1452 	TInt j=0; // offset for aForeign[]
  1453 	TInt i=0; // offset for aUnicode[]
  1454 	for (i=0; i<lengthToCopy; ++i)
  1455 		{
  1456 		const TDesC8& replacementChar = KLit8ReplacementForUnconvertibleUnicodeCharacters;
  1457 		TUint32 unicodeChar = aUnicode[i];
  1458 
  1459 		// if High Surrogate
  1460 		if (IsHighSurrogate((TText16)unicodeChar))
  1461 			{
  1462 			// check for low surrogate
  1463 			if (!IsLowSurrogate(aUnicode[++i]))
  1464 				{
  1465 				aForeign[j++] = (TUint8)replacementChar[0];
  1466 				continue;
  1467 				}
  1468 			unicodeChar = JoinSurrogate((TText16)unicodeChar, (TText16)aUnicode[i]);
  1469 			}
  1470 
  1471 		// if Low Surrogate
  1472 		if (IsLowSurrogate((TText16)unicodeChar))
  1473 			{
  1474 			aForeign[j++] = (TUint8)replacementChar[0];
  1475 			continue;
  1476 			}
  1477 		// if Supplementary - Non BMP
  1478 		if (IsSupplementary(unicodeChar))
  1479 			{
  1480 			aForeign[j++] = (TUint8)replacementChar[0];
  1481 			}
  1482 		else
  1483 			{
  1484 			// ASCII support
  1485 			if((TUint)unicodeChar>=0x100)
  1486 				{
  1487 				aForeign[j++] = (TUint8)replacementChar[0];
  1488 				}
  1489 			else
  1490 				{
  1491 				aForeign[j++] = (TUint8)unicodeChar;
  1492 				}
  1493 			}
  1494 		}
  1495 
  1496 	// if any replacementChar used, aForeign offset(j) shall be less than 
  1497 	// lengthToCopy aUnicode offset(i)
  1498 	if(j<i)
  1499 		{
  1500 		aForeign.SetLength(j);
  1501 		}
  1502 
  1503 	return(allConverted);
  1504 	}
  1505 
  1506 EXPORT_C void TCodePageUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TOverflowAction aOverflowAction) const
  1507 /**
  1508 Convert from Unicode, truncating if there is not enough room in the output.
  1509 
  1510 @param aForeign The output is appended here.
  1511 @param aUnicode The input.
  1512 
  1513 @leave KErrOverflow if aForeign is too short for the output.
  1514 */
  1515 	{
  1516 	TInt r = KErrNone;
  1517 	TBool LeaveWhenError = (TBool)((aOverflowAction==TCodePageUtils::EOverflowActionLeave)?(TBool)ETrue:(TBool)EFalse);
  1518 	// if CodePage dll
  1519 	if(GetFatUtilityFunctions() && iCodepageLoaded == ECodePageDll && iCodePageFunctions.iConvertFromUnicodeL)
  1520 		{
  1521 		r = (*iCodePageFunctions.iConvertFromUnicodeL)(aForeign, aUnicode, LeaveWhenError);
  1522 		}
  1523 	// if Locale dll
  1524 	else if(GetFatUtilityFunctions() && iCodepageLoaded == ELocaleDll && iLocaleFatUtilityFunctions->iConvertFromUnicodeL)
  1525 		{
  1526 		if(aOverflowAction == TCodePageUtils::EOverflowActionLeave)
  1527 			{
  1528 			(*iLocaleFatUtilityFunctions->iConvertFromUnicodeL)(aForeign, aUnicode, KLit8ReplacementForUnconvertibleUnicodeCharacters, TFatUtilityFunctions::EOverflowActionLeave);
  1529 			}
  1530 		else
  1531 			{
  1532 			(*iLocaleFatUtilityFunctions->iConvertFromUnicodeL)(aForeign, aUnicode, KLit8ReplacementForUnconvertibleUnicodeCharacters, TFatUtilityFunctions::EOverflowActionTruncate);
  1533 			}
  1534 		}
  1535 	// default implementation
  1536 	else if (!ConvertFromUnicode(aForeign, aUnicode, aOverflowAction))
  1537 		{
  1538 		if (aOverflowAction==TCodePageUtils::EOverflowActionLeave)
  1539 			{
  1540 			User::Leave(KErrBadName);
  1541 			}
  1542 		}
  1543 
  1544 	r = r; // remove warning
  1545 	// File Server do not use this error code so do not send this error code right to File Server
  1546 	// rather suppress it. Can be used in future.
  1547 	return;
  1548 	}
  1549 
  1550 TBool TCodePageUtils::ConvertToUnicode(TDes16& aUnicode, const TDesC8& aForeign) const
  1551 /* 
  1552 Convert to Unicode, truncating if there is not enough room in the output.
  1553 
  1554 @param aUnicode The output is appended here.
  1555 @param aForeign The input.
  1556 
  1557 @return False if and only if aUnicode has not enough space remaining.
  1558 */
  1559 	{
  1560 	// A workaround to handle leading 'E5' byte in short file names 
  1561 	TBuf8<KMaxLengthShortNameWithDot> shortFileNameWithLeadingE5;
  1562 	TBool convertedLeading05toE5 = EFalse;
  1563 
  1564 	if (0 < aForeign.Length() && aForeign.Length() <= 12 && aForeign[0] == KLeadingE5Replacement)
  1565 		{
  1566 		shortFileNameWithLeadingE5 = aForeign;
  1567 		shortFileNameWithLeadingE5[0] = KEntryErasedMarker;
  1568 		convertedLeading05toE5 = ETrue;
  1569 		}
  1570 
  1571 	const TInt maximumLength=aUnicode.MaxLength();
  1572 	if (maximumLength>=aForeign.Length())
  1573 		{
  1574 		if (convertedLeading05toE5)
  1575 			{
  1576 			aUnicode.Copy(shortFileNameWithLeadingE5);
  1577 			}
  1578 		else
  1579 			{
  1580 			aUnicode.Copy(aForeign);
  1581 			}
  1582 		return ETrue;
  1583 		}
  1584 	else
  1585 		{
  1586 		if (convertedLeading05toE5)
  1587 			{
  1588 			aUnicode.Copy(shortFileNameWithLeadingE5.Left(maximumLength));
  1589 			}
  1590 		else
  1591 			{
  1592 			aUnicode.Copy(aForeign.Left(maximumLength));
  1593 			}
  1594 		return EFalse;
  1595 		}
  1596 	}
  1597 
  1598 EXPORT_C void TCodePageUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TOverflowAction aOverflowAction) const
  1599 /* 
  1600 Convert to Unicode, leaving if there is not enough room in the output.
  1601 
  1602 @param aUnicode The output is appended here.
  1603 @param aForeign The input.
  1604 
  1605 @leave KErrOverflow if aUnicode is too short for the output.
  1606 */
  1607 	{
  1608 	TInt r = KErrNone;
  1609 	TBool LeaveWhenError = (TBool)((aOverflowAction==TCodePageUtils::EOverflowActionLeave)?(TBool)ETrue:(TBool)EFalse);
  1610 	// if CodePage dll
  1611 	if(GetFatUtilityFunctions() && iCodepageLoaded == ECodePageDll && iCodePageFunctions.iConvertToUnicodeL)
  1612 		{
  1613 		r = (*iCodePageFunctions.iConvertToUnicodeL)(aUnicode, aForeign, LeaveWhenError);
  1614 		}
  1615 	// if Locale dll
  1616 	else if(GetFatUtilityFunctions() && iCodepageLoaded == ELocaleDll && iLocaleFatUtilityFunctions->iConvertToUnicodeL)
  1617 		{
  1618 		if(aOverflowAction == TCodePageUtils::EOverflowActionLeave)
  1619 			{
  1620 			(*iLocaleFatUtilityFunctions->iConvertToUnicodeL)(aUnicode, aForeign, TFatUtilityFunctions::EOverflowActionLeave);
  1621 			}
  1622 		else
  1623 			{
  1624 			(*iLocaleFatUtilityFunctions->iConvertToUnicodeL)(aUnicode, aForeign, TFatUtilityFunctions::EOverflowActionTruncate);
  1625 			}
  1626 		}
  1627 	// default implementation
  1628 	else if (!ConvertToUnicode(aUnicode, aForeign))
  1629 		{
  1630 		if (aOverflowAction==TCodePageUtils::EOverflowActionLeave)
  1631 			{
  1632 			User::Leave(KErrBadName);
  1633 			}
  1634 		}
  1635 
  1636 	r = r; // remove warning
  1637 	// File Server do not use this error code so do not send this error code right to File Server
  1638 	// rather suppress it. Can be used in future.
  1639 	return;
  1640 	}
  1641 
  1642 EXPORT_C TBool TCodePageUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars) const
  1643 /** 
  1644 Returns true if the input character is legal in a short name.
  1645 
  1646 @param aCharacter Character, in the foreign character encoding.
  1647 
  1648 @return true if aCharacter is legal in a FAT short name.
  1649 */
  1650 	{
  1651 	if(GetFatUtilityFunctions() && iCodepageLoaded == ECodePageDll && iCodePageFunctions.iIsLegalShortNameCharacter)
  1652 		{
  1653 		return (*iCodePageFunctions.iIsLegalShortNameCharacter)(aCharacter);
  1654 		}
  1655 
  1656 	if(GetFatUtilityFunctions() && iCodepageLoaded == ELocaleDll && iLocaleFatUtilityFunctions->iIsLegalShortNameCharacter)
  1657 		{
  1658 		return (*iLocaleFatUtilityFunctions->iIsLegalShortNameCharacter)(aCharacter);
  1659 		}
  1660 
  1661 	// For most common cases:
  1662 	// Note: lower case characters are considered legal DOS char here.
  1663 	if ((aCharacter>='a' && aCharacter<='z') ||
  1664 		(aCharacter>='A' && aCharacter<='Z') ||
  1665 		(aCharacter>='0' && aCharacter<='9'))
  1666 		{
  1667 		return ETrue;
  1668 		}
  1669 
  1670 	// Default Implmentation
  1671 	// Checking for illegal chars:
  1672 	// 1. aCharacter <= 0x20
  1673 	// Note: leading 0x05 byte should be guarded by callers of this function
  1674 	//  as the information of the position of the character is required.
  1675 	if (aCharacter < 0x20)
  1676 		return EFalse;
  1677 	// Space (' ') is not considered as a legal DOS char here.
  1678 	if (aCharacter == 0x20)
  1679 		return EFalse;
  1680 
  1681 	// 2. 0x20 < aCharacter < 0x80
  1682 	if (0x20 < aCharacter && aCharacter < KExtendedCharStart)
  1683 		{
  1684 		// According to FAT Spec, "following characters are not legal in any bytes of DIR_Name":
  1685 		switch (aCharacter)
  1686 			{
  1687 			case 0x22:	// '"'
  1688 			case 0x2A:	// '*'
  1689 			case 0x2B:	// '+'
  1690 			case 0x2C:	// ','
  1691 	//		case 0x2E:	// '.'		// Although '.' is not allowed in any bytes of DIR_Name, it 
  1692 									// is a valid character in short file names.
  1693 			case 0x2F:	// '/'
  1694 			case 0x3A:	// ':'
  1695 			case 0x3B:	// ';'
  1696 			case 0x3C:	// '<'
  1697 			case 0x3D:	// '='
  1698 			case 0x3E:	// '>'
  1699 			case 0x3F:	// '?'
  1700 			case 0x5B:	// '['
  1701 			case 0x5C:	// '\'
  1702 			case 0x5D:	// ']'
  1703 			case 0x7C:	// '|'
  1704 				return EFalse;
  1705 			default:
  1706 			    return ETrue;
  1707 			}
  1708 		}
  1709 
  1710 	// 3. 0x80 <= aCharacter <= 0xFF
  1711 	if (KExtendedCharStart <= aCharacter  && aCharacter <= KExtendedCharEnd)
  1712 		{
  1713 		if(aUseExtendedChars)
  1714 			return(ETrue);
  1715 		else
  1716 			return EFalse;
  1717 		}
  1718 
  1719 	// 4. aCharacter => 0xFF
  1720 	return EFalse;
  1721 	}