--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_sys.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1715 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32\sfile\sf_sys.cpp
+//
+//
+
+#include "sf_std.h"
+#include <e32uid.h>
+#include "sf_file_cache.h"
+#include <kernel\localise.h>
+#include <f32file.h>
+
+typedef CFileSystem*(*TFileSystemNew)();
+extern CProxyDriveFactory* GetExtension(const TDesC& aName);
+
+#ifndef __WINS__
+extern TBool gInitCacheCheckDrivesAndAddNotifications;
+#endif
+
+struct TFatUtilityFunctions;
+GLREF_D TCodePageUtils TheCodePage;
+const TInt KMaxLengthShortNameWithDot = 12;
+const TUint8 KLeadingE5Replacement = 0x05;
+const TUint8 KEntryErasedMarker=0xE5; ///< Erased entry marker for a directory entry
+
+/**
+Default constructor.
+*/
+EXPORT_C CFileSystem::CFileSystem()
+ {
+ TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemConstructor, EF32TraceUidFileSys);
+ TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemConstructorReturn, EF32TraceUidFileSys);
+ }
+
+/**
+Destructor.
+*/
+EXPORT_C CFileSystem::~CFileSystem()
+ {
+ TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemDestructor, EF32TraceUidFileSys);
+ TRACE0(UTF::EBorder, UTraceModuleFileSys::ECFileSystemDestructorReturn, EF32TraceUidFileSys);
+ }
+
+/**
+Uninstalls the file system.
+
+This is called just before the file system object is destroyed, and allows
+any clean up to be carried out.
+
+The default implementation does nothing except return KErrNone.
+Implementations should return an error code on error detection.
+
+@return KErrNone if successful, otherwise one of the other system wide error
+ codes.
+*/
+EXPORT_C TInt CFileSystem::Remove()
+ {
+
+ return(KErrNone);
+ }
+
+/**
+Tests whether a version is supported.
+
+This is done decided by comparing the supplied version with iVersion.
+
+The default implementation uses User::QueryVersionSupported() to
+determine this.
+
+@param aVer The version to be tested.
+
+@return True, if aVer is supported; false otherwise
+
+@see User::QueryVersionSupported
+@see CFileSystem::iVersion
+*/
+EXPORT_C TBool CFileSystem::QueryVersionSupported(const TVersion& aVer) const
+ {
+
+ return(User::QueryVersionSupported(iVersion,aVer));
+ }
+
+//#ifndef __DATA_CAGING__
+/**
+Retrieves the default path for the file system.
+
+Each session with the file server has a current session path.
+When a new session is opened, its session path is set to the default path
+of the file server.
+At file server start-up, this default path is set to the default path returned
+by the local file system.
+
+The function should return an appropriate error code when the default path
+cannot be supplied.
+
+The derived class should override this base class function.
+
+This default implementation raises an "Fserv fault" 31 panic.
+
+@param aPath On return, contains the default path for the file system for derived classes.
+
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+
+@panic Fserv fault 31 if the default implementation
+ for CFileSystem::DefaultPath() is not overridden.
+*/
+TInt CFileSystem::DefaultPath(TDes& /*aPath*/) const
+ {
+
+ Fault(ESysDefaultPathNotSupported);
+ return(KErrNone);
+ }
+//#endif
+
+/**
+Sets the file system's resource library.
+
+This library represents the loaded file system.
+
+This is called internally by InstallFileSystem().
+
+@param aLib The resource library to be set.
+*/
+EXPORT_C void CFileSystem::SetLibrary(RLibrary aLib)
+ {
+
+ iLibrary=aLib;
+ }
+
+/**
+Gets the file system's resource library.
+
+@return The file system's resource library.
+*/
+EXPORT_C RLibrary CFileSystem::Library() const
+ {
+ return(iLibrary);
+ }
+
+/**
+Tests whether the file system supports extensions.
+
+@return True, if the file system supports extensions, false otherwise.
+ The defualt implementation returns false.
+*/
+EXPORT_C TBool CFileSystem::IsExtensionSupported() const
+ {
+ return(EFalse);
+ }
+
+EXPORT_C TInt CFileSystem::GetInterface(TInt /*aInterfaceId*/,TAny*& /*aInterface*/,TAny* /*aInput*/)
+ {
+ return(KErrNotSupported);
+ }
+
+EXPORT_C TBool CFileSystem::IsProxyDriveSupported()
+ {
+ TAny* dummyInterface;
+ if(GetInterface(EProxyDriveSupport, dummyInterface, NULL) == KErrNone)
+ return ETrue;
+
+ return EFalse;
+ }
+
+//-----------------------------------------------------------------------------
+/**
+ Extended CMountCB factory interface.
+ Produces the CMountCB object which can be associated with another CFileSystem owner.
+ Used mostly with "automounter" file system
+
+ @param apDrive in: pointer to TDrive, producing right CMountCB can require media access ("automounter" recognising the file system)
+ @param apFileSystem out: pointer to the CFileSystem object that actually produced CMountCB instance (might be different from "this")
+ @param aForceMount in: ETrue if it is necessarily to force mounting (formatting the media, for example)
+ @param aFsNameHash in: desired file system name hash (optional). Specifies which file system will be used to produce appropriate CMountCB object.
+ The file system that implements NewMountExL() shall decide how to process it. 0 means "default/not specified".
+
+ @return pointer to the instantiated CMountCB object.
+*/
+CMountCB* CFileSystem::NewMountExL(TDrive* apDrive, CFileSystem** apFileSystem, TBool aForceMount, TUint32 aFsNameHash)
+ {
+ TAny* pa;
+
+ if(GetInterface(EExtendedFunctionality, pa, NULL) == KErrNone)
+ {//-- special interface for the case, when CMountCB object will be produced by not _this_ CFileSystem object, but some different.
+ //-- in this case apFileSystem will contain a pointer to the real factory.
+ MFileSystemExtInterface* pExtIf = (CFileSystem::MFileSystemExtInterface*)pa;
+ ASSERT(pExtIf);
+
+ return pExtIf->NewMountExL(apDrive, apFileSystem, aForceMount, aFsNameHash);
+ }
+ else
+ {//--This interface is not supported by current CFileSystem implementation, call normal legacy factory method
+ //-- and make _this_ object of CFileSystem produce a new CMountCB
+ ASSERT(aFsNameHash == 0); //-- it is impossible to specify the particular FS to be used
+ *apFileSystem = this;
+ return NewMountL();
+ }
+
+ }
+
+
+//-----------------------------------------------------------------------------
+/**
+ Get the name of a filesystem from the list of supported on this drive.
+ Some filesystems (e.g. "automounter" can support more than one real "child" filesystems.
+ For the normal case, only one filesystem is supported (a mouned one).
+
+ @param aFsNumber used to enumerate supported filesystems can be:
+ special value KRootFileSystem, or
+ 0,1,2... - the sequence number of a "child" FS.
+
+ @param aFsName out: buffer for the returned file system name
+
+ @return KErrNone Ok, aFsName contains valid value for the given aFsNumber
+ KErrNotFound There is no supported filesystem for the given aFsNumber
+*/
+TInt CFileSystem::GetSupportedFileSystemName(TInt aFsNumber, TDes& aFsName)
+ {
+ TAny* pa;
+
+ //-- we need a special interface to find out the name of the supported file system number "aFsNumber"
+ if(GetInterface(EExtendedFunctionality, pa, NULL) == KErrNone)
+ {
+ MFileSystemExtInterface* pExtIf = (CFileSystem::MFileSystemExtInterface*)pa;
+ ASSERT(pExtIf);
+ return pExtIf->GetSupportedFileSystemName(aFsNumber, aFsName);
+ }
+ else
+ {//--This interface is not supported by current CFileSystem implementation, but in this case "Root" and first "child" filesystem mean
+ //-- the same and this is "this" filesystem
+
+ if(aFsNumber == RFs::KRootFileSystem || aFsNumber == RFs::KFirstChildFileSystem)
+ {
+ aFsName = Name();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+ }
+
+//-----------------------------------------------------------------------------
+
+TInt InstallFileSystem(CFileSystem* aSys,RLibrary aLib)
+//
+// Install a file system.
+//
+ {
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemInstall, EF32TraceUidFileSys, aSys);
+ TInt r=aSys->Install();
+ TRACERETMULT2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemInstallRet, EF32TraceUidFileSys, r, aSys->Name());
+
+ __PRINT1TEMP(_L("InstallFileSystem %S"),aSys->Name());
+ if (r==KErrNone)
+ {TRAP(r,FileSystems->AddL(aSys,ETrue))}
+ if (r!=KErrNone)
+ {
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemove, EF32TraceUidFileSys, aSys);
+#ifdef SYMBIAN_FTRACE_ENABLE
+ TInt r =
+#endif
+ aSys->Remove();
+
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemoveRet, EF32TraceUidFileSys, r);
+ }
+ if (r==KErrNone)
+ aSys->SetLibrary(aLib);
+ else
+ aSys->Close();
+ return(r);
+ }
+
+EXPORT_C CFileSystem* GetFileSystem(const TDesC& aName)
+//
+// Lookup a file system by name.
+//
+ {
+
+ TInt h=0;
+ TInt r=FileSystems->FindByName(h,aName);
+ if (r!=KErrNone)
+ return(NULL);
+ return((CFileSystem*)FileSystems->At(h));
+ }
+
+TInt TFsAddFileSystem::DoRequestL(CFsRequest* aRequest)
+//
+// Add a file system.
+//
+ {
+
+ __PRINT(_L("TFsAddFileSystem::DoRequestL(CFsRequest* aRequest)"));
+
+ RLibrary lib;
+ lib.SetHandle(aRequest->Message().Int0()); // Get library handle
+ if (lib.Type()[1]!=TUid::Uid(KFileSystemUidValue))
+ return KErrNotSupported;
+
+ TFileSystemNew f=(TFileSystemNew)lib.Lookup(1);
+ if (!f)
+ return KErrCorrupt;
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNew, EF32TraceUidFileSys, lib.Handle());
+ CFileSystem* pS=(*f)();
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewRet, EF32TraceUidFileSys, pS);
+ if (!pS)
+ return KErrNoMemory;
+ TInt r=InstallFileSystem(pS,lib);
+ if (r==KErrNone && !LocalFileSystemInitialized)
+ {
+ _LIT(KLocFSY, "ELOCAL.FSY");
+ TFileName fn(lib.FileName());
+ TParsePtrC ppc(fn);
+
+ if (ppc.NameAndExt().CompareF(KLocFSY) == 0)
+ r = InitializeLocalFileSystem(pS->Name());
+ }
+ return r;
+ }
+
+TInt TFsAddFileSystem::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+ TSecurityPolicy policy(RProcess().SecureId(), ECapabilityTCB);
+ if (!policy.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Add File System")))
+ return KErrPermissionDenied;
+ return KErrNone;
+ }
+
+TInt TFsRemoveFileSystem::DoRequestL(CFsRequest* aRequest)
+//
+// Remove a file system.
+//
+ {
+
+ TFullName name;
+ aRequest->ReadL(KMsgPtr0,name);
+ CFileSystem* pF=GetFileSystem(name);
+ if (pF==NULL)
+ return(KErrNotFound);
+
+ CFileSystem* pFs = NULL;
+ for(TInt drvNum=0; drvNum<KMaxDrives; drvNum++)
+ {
+ FsThreadManager::LockDrive(drvNum);
+ pFs=TheDrives[drvNum].GetFSys();
+ FsThreadManager::UnlockDrive(drvNum);
+ if(!pFs)
+ continue;
+
+ if(name.CompareF(pFs->Name()) == 0)
+ return KErrInUse;
+ }
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemove, EF32TraceUidFileSys, pF);
+ TInt r=pF->Remove();
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemRemoveRet, EF32TraceUidFileSys, r);
+ if (r!=KErrNone)
+ return(r);
+
+ RLibrary lib=pF->Library();
+ pF->Close();
+ lib.Close();
+
+ return KErrNone;
+ }
+
+TInt TFsRemoveFileSystem::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+ if (!KCapFsRemoveFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Remove File System")))
+ return KErrPermissionDenied;
+ return KErrNone;
+ }
+
+LOCAL_C TInt DoMountFileSystem(CFsRequest* aRequest)
+//
+//
+//
+ {
+ TInt r = TFileCacheSettings::ReadPropertiesFile(aRequest->Drive()->DriveNumber());
+ if (r != KErrNone)
+ return r;
+
+ return(aRequest->Drive()->CheckMount());
+ }
+
+
+LOCAL_C TInt DoMountFsInitialise(CFsRequest* aRequest,TDesC& aFsName,TBool aIsExtension,TBool aIsSync)
+//
+//
+//
+ {
+ if (!KCapFsMountFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Mount File System")))
+ return KErrPermissionDenied;
+
+ TInt r=ValidateDrive(aRequest->Message().Int1(),aRequest);
+ if(r!=KErrNone)
+ return(r);
+
+ TBool driveThreadExists = FsThreadManager::IsDriveAvailable(aRequest->DriveNumber(), ETrue);
+ if(driveThreadExists)
+ {
+ // A drive thread already exists for this drive.This could be because a filesystem
+ // is already mounted, or a proxy drive is loaded. Check the mount to be sure...
+ if(aRequest->Drive()->GetFSys())
+ {
+ // Yes, a mount already exists so we can't mount another one!
+ return(KErrAccessDenied);
+ }
+
+ __ASSERT_DEBUG(IsProxyDrive(aRequest->DriveNumber()), User::Panic(_L("Bad thread state - No Mount or Proxy Drive Exists!"), -999));
+ }
+
+ // ...therefore no drive thread can be present
+ __ASSERT_DEBUG(!&aRequest->Drive()->FSys(),Fault(EMountFileSystemFSys));
+
+ if(aRequest->Drive()->IsSubsted())
+ return(KErrAccessDenied);
+
+ CFileSystem* pF = GetFileSystem(aFsName);
+
+ if (pF == NULL)
+ return(KErrNotFound);
+
+ // Check that if the drive is a proxy drive (not using TBusLocalDrive) then the filesystem supports these...
+ TInt driveNumber = aRequest->DriveNumber();
+ if(IsProxyDrive(driveNumber))
+ {
+ if(!pF->IsProxyDriveSupported())
+ return KErrNotSupported;
+
+ r = LocalDrives::SetupMediaChange(driveNumber);
+ }
+
+ TDriveInfo driveInfo;
+ driveInfo.iDriveAtt=0;
+ pF->DriveInfo(driveInfo, driveNumber);
+ if(!driveInfo.iDriveAtt)
+ r = KErrArgument;
+
+ if(r == KErrNone && !driveThreadExists)
+ {
+ // determine whether file system synchronous or not not by flag passed in
+ r=FsThreadManager::InitDrive(driveNumber, aIsSync);
+ }
+
+ if(r!=KErrNone)
+ return(r);
+
+
+ //-- let TDrive object know if the drive is synchronous
+ aRequest->Drive()->SetSynchronous(aIsSync);
+
+ if(aIsExtension && aRequest->Message().Ptr2()!=NULL)
+ {
+ TFullName extName;
+ r = aRequest->Read(KMsgPtr2,extName);
+ if (r!=KErrNone)
+ return r;
+ CProxyDriveFactory* pE=GetExtension(extName);
+ if(pE==NULL)
+ return(KErrNotFound);
+ r=aRequest->Drive()->MountExtension(pE,ETrue);
+ if(r!=KErrNone)
+ return(r);
+ }
+
+ TInt32 newAtt = 0;
+ TInt32 oldAtt = 0;
+ _LIT8( KAddAtt, "AddDriveAttributes");
+ _LIT8( KRemoveAtt, "RemoveDriveAttributes");
+ _LIT8( KLogicallyRemovableAtt, "KDRIVEATTLOGICALLYREMOVABLE");
+ _LIT8( KHiddenAtt, "KDRIVEATTHIDDEN");
+ _LIT8( KLogicallyRemovableAttHex, "0X200");
+ _LIT8( KHiddenAttHex, "0X400");
+ TBuf8<0x1000> addbuf;
+ addbuf.FillZ();
+ TBuf8<0x1000> removebuf;
+ removebuf.FillZ();
+ TInt drive = aRequest->Message().Int1();
+ _LIT8(KLitSectionNameDrive,"Drive%C");
+ TBuf8<8> sectionName;
+ sectionName.Format(KLitSectionNameDrive, 'A' + drive);
+ F32Properties::GetString(sectionName, KAddAtt, addbuf);
+ F32Properties::GetString(sectionName, KRemoveAtt, removebuf); //oldAtt now contains value of the attributes to be removed from iDriveAtt.
+
+ if(addbuf.Length() != 0)
+ {
+ TInt pos = 0;
+ TInt length = 0;
+ TPtrC8 ptr;
+ TBool endOfFlag=EFalse;
+
+ while(!endOfFlag)
+ {
+ ptr.Set(addbuf.Mid(pos));
+ length = ptr.Locate(',');
+
+ if(length == KErrNotFound)
+ {
+ endOfFlag = ETrue;
+ }
+ else{
+ ptr.Set(ptr.Left(length));
+ pos += (length +1);
+ }
+
+ if(((ptr.MatchF(KLogicallyRemovableAtt)) != KErrNotFound) || ((ptr.MatchF(KLogicallyRemovableAttHex)) != KErrNotFound))
+ newAtt |= KDriveAttLogicallyRemovable;
+ if(((ptr.MatchF(KHiddenAtt)) != KErrNotFound) || ((ptr.MatchF(KHiddenAttHex)) != KErrNotFound))
+ newAtt |= KDriveAttHidden;
+
+ }
+ }
+
+ if(removebuf.Length() != 0)
+ {
+ TInt pos = 0;
+ TInt length = 0;
+ TPtrC8 ptr;
+ TBool endOfFlag=EFalse;
+
+ while(!endOfFlag)
+ {
+ ptr.Set(removebuf.Mid(pos));
+ length = ptr.Locate(',');
+
+ if(length == KErrNotFound)
+ {
+ endOfFlag = ETrue;
+ }
+ else{
+ ptr.Set(ptr.Left(length));
+ pos += (length +1);
+ }
+
+ if(((ptr.MatchF(KLogicallyRemovableAtt)) != KErrNotFound) || ((ptr.MatchF(KLogicallyRemovableAttHex)) != KErrNotFound))
+ oldAtt |= KDriveAttLogicallyRemovable;
+ if(((ptr.MatchF(KHiddenAtt)) != KErrNotFound) || ((ptr.MatchF(KHiddenAttHex)) != KErrNotFound))
+ oldAtt |= KDriveAttHidden;
+
+ }
+ }
+
+ if ((newAtt & KDriveAttLogicallyRemovable) && (!(driveInfo.iDriveAtt & KDriveAttRemovable)) && (!(newAtt & KDriveAttRemovable)))
+ {
+ newAtt |= KDriveAttRemovable; //KDriveAttLogicallyRemovale should always set KDriveAttRemovale
+ }
+ if ((oldAtt & KDriveAttRemovable) && (!(oldAtt & KDriveAttLogicallyRemovable)))
+ {
+ oldAtt |= KDriveAttLogicallyRemovable;
+ }
+ if(newAtt)
+ {
+ driveInfo.iDriveAtt |= newAtt;
+ }
+ if(oldAtt)
+ {
+ if(oldAtt & driveInfo.iDriveAtt)
+ {
+ driveInfo.iDriveAtt ^= oldAtt;
+ }
+ }
+ aRequest->Drive()->SetAtt(driveInfo.iDriveAtt);
+ aRequest->Drive()->GetFSys()=pF;
+
+ // empty the closed file queue
+ TClosedFileUtils::Remove(aRequest->DriveNumber());
+
+ return(KErrNone);
+ }
+
+
+TInt TFsMountFileSystem::DoRequestL(CFsRequest* aRequest)
+//
+// Mount a filesystem on a drive.
+//
+ {
+ TInt r=DoMountFileSystem(aRequest);
+ if( KErrNone == r )
+ {
+ FsNotify::DiskChange(aRequest->DriveNumber());
+ }
+
+ // Refresh the loader cache to ensure that the new drive is monitored.
+#ifndef __WINS__
+ gInitCacheCheckDrivesAndAddNotifications = EFalse;
+#endif
+
+ return r;
+ }
+
+
+TInt TFsMountFileSystem::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+ TFullName name;
+ TInt r = aRequest->Read(KMsgPtr0,name);
+ if (r == KErrNone)
+ r = DoMountFsInitialise(aRequest,name,ETrue,aRequest->Message().Int3());
+ return r;
+ }
+
+TInt TFsMountFileSystemScan::DoRequestL(CFsRequest* aRequest)
+//
+// mount file system and then call scandrive
+//
+ {
+ TInt r=DoMountFileSystem(aRequest);
+ // run scandrive if successful mount
+ TBool isMountSuccess=(KErrNone==r);
+ if(isMountSuccess)
+ {
+ r=aRequest->Drive()->ScanDrive();
+ FsNotify::DiskChange(aRequest->DriveNumber());
+ }
+ TPtrC8 pMS((TUint8*)&isMountSuccess,sizeof(TBool));
+ aRequest->WriteL(KMsgPtr3,pMS);
+ return(r);
+ }
+
+
+TInt TFsMountFileSystemScan::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+ TFullName name;
+ TInt r = aRequest->Read(KMsgPtr0,name);
+ if (r == KErrNone)
+ r = DoMountFsInitialise(aRequest,name,ETrue,EFalse);
+ return r;
+ }
+
+LOCAL_C TInt DoDismountFileSystem(const TDesC& aName, TDrive* aDrive, TBool aAllowRom, TBool aForceDismount)
+//
+// Do file system dismount
+//
+ {
+ TInt drvNumber=aDrive->DriveNumber();
+
+ FsThreadManager::LockDrive(drvNumber);
+ CFileSystem* pF=GetFileSystem(aName);
+ if(pF==NULL)
+ {
+ FsThreadManager::UnlockDrive(drvNumber);
+ return(KErrNotFound);
+ }
+ if(aDrive->IsRom() && !aAllowRom)
+ {
+ FsThreadManager::UnlockDrive(drvNumber);
+ return(KErrAccessDenied);
+ }
+
+ if(!aForceDismount)
+ {
+ if(aDrive->IsMounted() && aDrive->CurrentMount().LockStatus()!=0)
+ {
+ FsThreadManager::UnlockDrive(drvNumber);
+ return(KErrInUse);
+ }
+ if(aDrive->ActiveMounts() > 1)
+ {
+ FsThreadManager::UnlockDrive(drvNumber);
+ return(KErrInUse);
+ }
+
+ aDrive->ReactivateMounts();
+ }
+
+ // ensure that current mount is dismounted
+ if(aForceDismount)
+ {
+ TInt r = aDrive->FlushCachedFileInfo(ETrue);
+
+ // Dismount the file system even if the flush fails for some reason (media permanently removed, user cancels notifier etc
+ if (r!=KErrNone && r!=KErrAbort)
+ {
+ FsThreadManager::UnlockDrive(drvNumber);
+ return(r);
+ }
+ aDrive->ForceDismount();
+ }
+ else
+ {
+ aDrive->Dismount();
+ }
+
+ aDrive->GetFSys()=NULL;
+ aDrive->SetAtt(0);
+ aDrive->ExtInfo().iCount=0;
+
+ // no need to cancel requests if synchronous since queued
+ if(!FsThreadManager::IsDriveSync(drvNumber,EFalse))
+ {
+ CDriveThread* pT=NULL;
+ TInt r=FsThreadManager::GetDriveThread(drvNumber,&pT);
+ __ASSERT_ALWAYS(r==KErrNone && pT,Fault(EDismountFsDriveThread));
+ pT->CompleteAllRequests(KErrNotReady);
+ }
+
+ if(!IsProxyDrive(drvNumber))
+ {
+ // Proxy drives are responsible for managing the drive threads...
+ FsThreadManager::CloseDrive(drvNumber);
+ }
+
+ FsThreadManager::UnlockDrive(drvNumber);
+ FsNotify::DiskChange(drvNumber);
+ return(KErrNone);
+ }
+
+TInt TFsDismountFileSystem::DoRequestL(CFsRequest* aRequest)
+//
+// Dismount a filesystem from a drive.
+//
+ {
+ TDrive* drive=aRequest->Drive();
+ __ASSERT_DEBUG(&aRequest->Drive()->FSys() && !drive->IsSubsted(),Fault(EDisMountFileSystemFSys));
+ TFullName name;
+ aRequest->ReadL(KMsgPtr0,name);
+
+ if(drive->DismountDeferred())
+ return KErrInUse;
+
+ return DoDismountFileSystem(name, drive, EFalse, EFalse);
+ }
+
+TInt TFsDismountFileSystem::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+ if (!KCapFsDismountFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Dismount File System")))
+ return KErrPermissionDenied;
+ TInt r = ValidateDrive(aRequest->Message().Int1(),aRequest);
+ if(r == KErrNone)
+ {
+ TInt driveNumber = aRequest->DriveNumber();
+ if(IsProxyDrive(driveNumber))
+ {
+ LocalDrives::NotifyChangeCancel(driveNumber);
+ }
+ }
+ return r;
+ }
+
+/**
+ Return name of file system mounted on a specified drive or one of the file system names if
+ the drive supports several of them.
+*/
+TInt TFsFileSystemName::DoRequestL(CFsRequest* aRequest)
+ {
+ //-- ipc parameters:
+ //-- 0 out: file system name decriptor
+ //-- 1 drive number
+ //-- 2 file system enumerator
+
+ const TInt driveNumber = aRequest->Message().Int1();
+ if (driveNumber < 0 || driveNumber >= KMaxDrives)
+ return KErrArgument;
+
+ const TInt fsNumber = aRequest->Message().Int2(); //-- file system number; for RFs::FileSystemName() it is "-1"
+
+ TFullName fsName;
+ // lock drive to synchronise with dismounting a file system
+ FsThreadManager::LockDrive(driveNumber);
+ CFileSystem* pF=TheDrives[driveNumber].GetFSys();
+ FsThreadManager::UnlockDrive(driveNumber);
+
+ TInt err = KErrNone;
+
+ if(pF)
+ {
+ if(fsNumber == -1)
+ fsName = pF->Name(); //-- this is RFs::FileSystemName() call
+ else
+ err = pF->GetSupportedFileSystemName(fsNumber, fsName); //-- this is RFs::SupportedFileSystemName() call
+ }
+ else
+ {//-- the drive doesn't have file system installed
+ fsName=_L("");
+ err = KErrNotFound;
+ }
+
+ aRequest->WriteL(KMsgPtr0, fsName);
+
+ return err;
+ }
+
+TInt TFsFileSystemName::Initialise(CFsRequest* /*aRequest*/)
+ {
+ return KErrNone;
+ }
+
+TInt TFsRemountDrive::DoRequestL(CFsRequest* aRequest)
+//
+// Force a remount of the specified drive
+//
+ {
+ const TDesC8 *mountInfo=REINTERPRET_CAST(const TDesC8*,aRequest->Message().Ptr1());
+ return(aRequest->Drive()->ForceRemountDrive(mountInfo,aRequest->Message().Handle(),aRequest->Message().Int2()));//changed from thread to message handle
+ }
+
+TInt TFsRemountDrive::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+
+ TInt r=ValidateDriveDoSubst(aRequest->Message().Int0(),aRequest);
+ return(r);
+ }
+
+TInt TFsSetLocalDriveMapping::DoRequestL(CFsRequest* aRequest)
+//
+// set up drive letter to local drive mapping
+//
+ {
+ return(LocalDrives::SetDriveMappingL(aRequest));
+ }
+
+TInt TFsSetLocalDriveMapping::Initialise(CFsRequest* /*aRequest*/)
+//
+//
+//
+ {
+ return KErrNone;
+ }
+
+_LIT(KCompositeFsName,"Composite");
+
+TInt TFsSwapFileSystem::DoRequestL(CFsRequest* aRequest)
+//
+// Swap a filesystem on a drive
+// Should always leave a filesystem mounted on the drive
+//
+ {
+ TFileName newName;
+ aRequest->ReadL(KMsgPtr0,newName);
+ CFileSystem* pF=GetFileSystem(newName);
+ if (pF==NULL)
+ return(KErrNotFound);
+ TFileName oldName;
+ aRequest->ReadL(KMsgPtr2,oldName);
+ TInt drvNumber=aRequest->Message().Int1();
+ TBool newFsIsComposite = (newName.CompareF(KCompositeFsName) == 0);
+
+ if (newFsIsComposite)
+ {
+ if(CompFsMounted)
+ return(KErrAlreadyExists);
+ if(EDriveZ!=drvNumber)
+ return(KErrNotSupported);
+ }
+ else
+ // swapping filesystem on z: only allow for romfs + compfs
+ if(EDriveZ==drvNumber)
+ return(KErrNotSupported);
+
+ TDrive& drive=TheDrives[drvNumber];
+
+ if(drive.DismountDeferred())
+ return KErrInUse;
+
+ TBool clamps=drive.ClampFlag();
+ if(clamps)
+ return KErrInUse;
+
+ // Return an error if the drive is asynchronous.
+ // This function is only supported on synchronous drives.
+ TBool isSync = FsThreadManager::IsDriveSync(drvNumber,EFalse);
+ if(!isSync)
+ return KErrNotSupported;
+
+ TInt r=DoDismountFileSystem(oldName,&drive,ETrue,EFalse);
+ if(r!=KErrNone)
+ return(r);
+
+ __ASSERT_ALWAYS(drive.GetFSys()==NULL,Fault(ESwapFileSystemNull));
+
+ r=DoMountFsInitialise(aRequest,newName,EFalse,isSync);
+ if(r==KErrNone)
+ r=DoMountFileSystem(aRequest);
+
+ if(drive.GetFSys()==NULL || (newFsIsComposite && r!=KErrNone))
+ {
+ // remounting of the original filesystem should not fail
+ if(drive.GetFSys()!=NULL)
+ r=DoDismountFileSystem(newName,&drive,ETrue,EFalse);
+
+ r=DoMountFsInitialise(aRequest,oldName,EFalse,isSync);
+ if(r==KErrNone)
+ r=DoMountFileSystem(aRequest);
+
+ __ASSERT_ALWAYS(r==KErrNone && drive.GetFSys()!=NULL,Fault(ESwapFileSystemMount));
+ }
+ else if (newFsIsComposite)
+ {
+ FsThreadManager::ChangeSync(drvNumber,CompFsSync);
+ CompFsMounted=ETrue;
+ }
+
+ if(drvNumber==EDriveZ)
+ {
+ __ASSERT_ALWAYS(r==KErrNone,Fault(ESwapFileSystemRom));
+ RefreshZDriveCache=ETrue;
+ }
+ return(r);
+ }
+
+TInt TFsSwapFileSystem::Initialise(CFsRequest* /*aRequest*/)
+//
+//
+//
+ {
+ return KErrNone;
+ }
+
+
+TInt TFsAddCompositeMount::DoRequestL(CFsRequest* aRequest)
+//
+// Input fsyName, localDriveNUmber, CompositeDriveNumber
+//
+//
+ {
+ __PRINT(_L("TFsAddCompositeMount::DoRequestL"));
+
+ TFileName fsyName;
+ aRequest->ReadL(KMsgPtr0,fsyName);
+ CFileSystem* pNewFileSystem=GetFileSystem(fsyName);
+
+ if (pNewFileSystem==NULL)
+ return KErrNotFound;
+
+ const TInt localDriveNumber=aRequest->Message().Int1();
+ const TInt compositeDriveNumber=aRequest->Message().Int2();
+ const TInt sync=aRequest->Message().Int3();
+
+ __PRINT3(_L("TFsAddCompositeMount::DoRequestL fsy:%S, locDrv:%d, compDrv:%d"),&fsyName, localDriveNumber,compositeDriveNumber);
+
+ // Currently, compFS assumed its mounting on romfs, on z:
+ if (compositeDriveNumber!=EDriveZ)
+ return KErrNotSupported;
+
+ // Mounts can only be added to the compfs, before it is mounted.
+ if (CompFsMounted)
+ return KErrInUse;
+
+ // The drive is needed, so the new sub mount, can be mounted
+ // on it temporarily. ROMFS doest care if we do this as it
+ // has no local mapping.
+ FsThreadManager::LockDrive(compositeDriveNumber);
+
+ TRAPD(err, AddFsToCompositeMountL(compositeDriveNumber, *pNewFileSystem, localDriveNumber));
+ if (err!=KErrNone)
+ {
+ FsThreadManager::UnlockDrive(compositeDriveNumber);
+ return err;
+ }
+// Fault(EMountFileSystemFSys);
+
+ FsThreadManager::UnlockDrive(compositeDriveNumber);
+
+ // The drive will end up asynchronous if any sub mounts are.
+ if (!sync)
+ CompFsSync=EFalse;
+
+ return KErrNone;
+ }
+
+
+TInt TFsAddCompositeMount::Initialise(CFsRequest* aRequest)
+//
+//
+//
+ {
+ if (!KCapFsAddCompositeMount.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Add Composite Mount")))
+ return KErrPermissionDenied;
+ return KErrNone;
+ }
+
+void TFsAddCompositeMount::AddFsToCompositeMountL(TInt aDriveNumber, CFileSystem& aFileSystem, TInt aLocalDriveNumber)
+ {
+ __PRINT3(_L("TFsAddCompositeMount::AddFsToCompositeMountL() FS:0x%x, drv:%d, local drive:%d"),&aFileSystem, aDriveNumber,aLocalDriveNumber);
+ TInt err;
+
+ TDrive& theDrive=TheDrives[aDriveNumber];
+ CFileSystem* pFs = theDrive.GetFSys();
+
+ CFileSystem* pCompFS = GetFileSystem(_L("Composite"));
+ if ((pCompFS == NULL) || (pFs==NULL))
+ User::Leave(KErrNotReady);
+
+ CMountCB* pMount = pCompFS->NewMountL(); //-- pMount is, actually, a singleton.
+ pMount->InitL(theDrive, pCompFS);
+
+
+ // invalidate the drive previously used by the local drive just added, and swap with a DriveNumber
+ TInt drv;
+ drv = LocalDrives::GetDriveFromLocalDrive(aLocalDriveNumber);
+ __ASSERT_ALWAYS(drv!=KDriveInvalid, User::Leave(KErrNotSupported));
+ //__PRINT1(_L("TFsAddCompositeMount::AddFsToCompositeMountL : drive to invalidate %d"),drv);
+ LocalDrives::iMapping[drv] = KDriveInvalid;
+ LocalDrives::iMapping[aDriveNumber] = aLocalDriveNumber;
+
+ // Ask the composite mount to mount the new filesystem.
+ TAny* dummy=NULL;
+ err = pMount->GetInterfaceTraced(CMountCB::EAddFsToCompositeMount, dummy, &aFileSystem);
+ if(err != KErrNone)
+ User::Leave(err);
+ }
+
+
+TInt TDrive::DeferredDismount()
+ {
+ // Dismount
+ TInt err = DoDismountFileSystem(GetFSys()->Name(), this, EFalse, ETrue);
+ if (err == CFsRequest::EReqActionBusy)
+ return err;
+
+ DoCompleteDismountNotify(err);
+
+ SetDismountDeferred(EFalse);
+
+ return err;
+ }
+
+TInt TFsNotifyDismount::Initialise(CFsRequest* aRequest)
+//
+// Initialise a dismount notifier.
+// - All clients may register with EFsDismountRegisterClient.
+// - DiskAdmin is required for EFsDismountNotifyClients and EFsDismountForceDismount
+//
+ {
+ const RMessage2& m=aRequest->Message();
+ const TNotifyDismountMode mode = (TNotifyDismountMode)m.Int1();
+
+ switch(mode)
+ {
+ case EFsDismountForceDismount:
+ case EFsDismountNotifyClients:
+ {
+ // Capabilities are required to dismount a file system
+ if(!KCapFsDismountFileSystem.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Notify Dismount")))
+ return KErrPermissionDenied;
+ break;
+ }
+
+ case EFsDismountRegisterClient:
+ {
+ // No capabilities are required for a client to register for notification
+ break;
+ }
+
+ default:
+ {
+ return KErrArgument;
+ //break;
+ }
+ }
+
+ return ValidateDrive(aRequest->Message().Int0() ,aRequest);
+ }
+
+TInt TFsNotifyDismount::DoRequestL(CFsRequest* aRequest)
+//
+// Register for notification of pending dismount [EFsDismountRegisterClient]
+// or notify clients of a pending dismount [EFsDismountNotifyClients]
+// or forcibly dismount the file system [EFsDismountForceDismount]
+//
+ {
+ __ASSERT_DEBUG(&aRequest->Drive()->FSys() && !aRequest->Drive()->IsSubsted(), Fault(ENotifyDismount));
+
+ TInt err = KErrNone;
+
+ const RMessage2& m=aRequest->Message();
+ const TNotifyDismountMode mode = (TNotifyDismountMode)m.Int1();
+ TDrive* theDrive = aRequest->Drive();
+ const TInt driveNumber = theDrive->DriveNumber();
+
+ switch(mode)
+ {
+ case EFsDismountRegisterClient:
+ {
+ err = RegisterNotify(aRequest);
+ break;
+ }
+
+ case EFsDismountNotifyClients:
+ {
+ if(aRequest->Drive()->DismountLocked())
+ {
+ err = RegisterNotify(aRequest);
+ if (err != KErrNone)
+ return err;
+ // Complete outstanding client dismount notifiers and flag the drive as pending dismount.
+ FsNotify::HandleDismount(EFsDismountRegisterClient, driveNumber, EFalse, KErrNone);
+ theDrive->SetDismountDeferred(ETrue);
+ }
+ else
+ {
+ // There are no interested clients, so dismount immediately - if no clamps are present
+ err = theDrive->ClampsOnDrive();
+
+ // If there are no clamps or clamping is not supported, proceed with the enforced dismount
+ // If there are clamps, wait for the clamps to be removed
+ if (err > 0)
+ {
+ err = RegisterNotify(aRequest);
+ theDrive->SetDismountDeferred(ETrue);
+ }
+ else if (err == 0 || err == KErrNotSupported)
+ {
+ // No clamps to worry about, so dismount immediately and complete the request
+ err = DoDismountFileSystem(theDrive->GetFSys()->Name(), theDrive, EFalse, ETrue);
+ if (err == CFsRequest::EReqActionBusy)
+ return err;
+ m.Complete(err);
+ }
+ }
+ break;
+ }
+
+ case EFsDismountForceDismount:
+ {
+ // Prepare for deferred dismount due to the presence of file clamps
+ err = theDrive->ClampsOnDrive();
+
+ // If there are no clamps or clamping is not supported, proceed with the enforced dismount
+ // If there are clamps, wait for the clamps to be removed
+ if(err > 0)
+ {
+ err = RegisterNotify(aRequest);
+ theDrive->SetDismountDeferred(ETrue);
+ }
+ else if (err == 0 || err == KErrNotSupported)
+ {
+ // Forced dismount - notify/remove all client notifiers and complete immediately
+ err = theDrive->DeferredDismount();
+ if (err == CFsRequest::EReqActionBusy)
+ return err;
+ m.Complete(err);
+ }
+ break;
+ }
+
+ default:
+ {
+ // We shouldn't ever get here
+ Fault(ENotifyDismount);
+ break;
+ }
+ }
+
+ return err;
+ }
+
+TInt TFsNotifyDismount::RegisterNotify(CFsRequest* aRequest)
+//
+// Register for notification of pending dismount [EFsDismountRegisterClient]
+// or notify clients of a pending dismount [EFsDismountNotifyClients]
+// or forcibly dismount the file system [EFsDismountForceDismount]
+//
+ {
+ const RMessage2& m=aRequest->Message();
+ const TNotifyDismountMode mode = (TNotifyDismountMode)m.Int1();
+ TDrive* theDrive = aRequest->Drive();
+ const TInt driveNumber = theDrive->DriveNumber();
+
+ if (mode == EFsDismountNotifyClients && theDrive->DismountDeferred())
+ {
+ return KErrInUse;
+ }
+
+ CDismountNotifyInfo* info = new CDismountNotifyInfo;
+ if(info == NULL)
+ {
+ return KErrNoMemory;
+ }
+
+ info->Initialise(mode, driveNumber, (TRequestStatus*)m.Ptr2(), m, aRequest->Session());
+ TInt err = FsNotify::AddDismountNotify(info);
+ if(err != KErrNone)
+ {
+ delete info;
+ return err;
+ }
+
+ return KErrNone;
+ }
+
+TInt TFsNotifyDismountCancel::DoRequestL(CFsRequest* aRequest)
+//
+// Cancel a pending dismount notifier - Request
+//
+ {
+ CSessionFs* session = aRequest->Session();
+ FsNotify::CancelDismountNotifySession(session, (TRequestStatus*)aRequest->Message().Ptr0());
+ return KErrNone;
+ }
+
+TInt TFsNotifyDismountCancel::Initialise(CFsRequest* /*aRequest*/)
+//
+// Cancel a pending dismount notifier - Initialise
+//
+ {
+ return KErrNone;
+ }
+
+TInt TFsAllowDismount::DoRequestL(CFsRequest* aRequest)
+//
+// Notifies the file server that the client is finished with the drive.
+// The last client to allow the dismount signals the dismounting thread.
+//
+ {
+ TDrive* theDrive = aRequest->Drive();
+ const TInt driveNumber = theDrive->DriveNumber();
+
+ // Verify that the client has registered for notification
+ if(!FsNotify::HandlePendingDismount(aRequest->Session(), driveNumber))
+ return KErrNotFound;
+
+ if(theDrive->DismountLocked())
+ return KErrNone;
+
+ TInt clampErr = theDrive->ClampsOnDrive();
+ TInt err = KErrNone;
+
+ if ((theDrive->DismountDeferred()) && (clampErr == 0 || clampErr == KErrNotSupported))
+ {
+ // No clamps to worry about, so dismount immediately and complete the request
+ __ASSERT_DEBUG(aRequest->Drive()->GetFSys(), Fault(EAllowDismount));
+
+ // When the last client has responded, allow the media to be forcibly dismounted
+ err = theDrive->DeferredDismount();
+ }
+
+ return err;
+ }
+
+TInt TFsAllowDismount::Initialise(CFsRequest* aRequest)
+//
+// Notifies the file server that the client is finished with the drive
+//
+ {
+ return ValidateDrive(aRequest->Message().Int0(),aRequest);
+ }
+
+
+TInt TFsMountProxyDrive::DoRequestL(CFsRequest* aRequest)
+ {
+ return LocalDrives::MountProxyDrive(aRequest);
+ }
+
+TInt TFsMountProxyDrive::Initialise(CFsRequest* aRequest)
+ {
+ if (!KCapFsMountProxyDrive.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Mount Proxy Drive")))
+ return KErrPermissionDenied;
+
+ TInt err = LocalDrives::InitProxyDrive(aRequest);
+ if(err == KErrNone)
+ {
+ // Now create the drive thread - proxy extensions are always asynchronous...
+ err = FsThreadManager::InitDrive(aRequest->DriveNumber(), EFalse);
+ }
+
+ return err;
+ }
+
+TInt TFsLoadCodePage::DoRequestL(CFsRequest* aRequest)
+//
+// Installs a code page
+//
+ {
+ __PRINT(_L("TFsLoadCodePage::DoRequestL(CFsRequest* aRequest)"));
+
+ RLibrary lib;
+ lib.SetHandle(aRequest->Message().Int0());
+ if (lib.Type()[1]!=TUid::Uid(KLocaleDllUidValue16))
+ return(KErrNotSupported);
+
+ if(TheCodePage.CodepageLoaded() == TCodePageUtils::ECodePageDll)
+ {
+ return(KErrAlreadyExists);
+ }
+
+ /*
+ // Actual Functions form the Codepage Dll (fatCnvU.def)
+ 1 : void UnicodeConv::ConvertFromUnicodeL(class TDes8 &, class TDesC16 const &)
+ 2 : void UnicodeConv::ConvertToUnicodeL(class TDes16 &, class TDesC8 const &)
+ 3 : int UnicodeConv::IsLegalShortNameCharacter(unsigned int)
+ 4 : int UnicodeConv::ConvertFromUnicodeL(class TDes8 &, class TDesC16 const &, int)
+ 5 : int UnicodeConv::ConvertToUnicodeL(class TDes16 &, class TDesC8 const &, int)
+ */
+
+ /*
+ Read only the following fns from Codepage Dll ( lib.Lookup(1) and lib.Lookup(2) retained in cpnnn.dll for backward compatibility)
+ 3 : int UnicodeConv::IsLegalShortNameCharacter(unsigned int)
+ 4 : int UnicodeConv::ConvertFromUnicodeL(class TDes8 &, class TDesC16 const &, int)
+ 5 : int UnicodeConv::ConvertToUnicodeL(class TDes16 &, class TDesC8 const &, int)
+ */
+
+ TheCodePage.iCodePageFunctions.iIsLegalShortNameCharacter = (TCodePageFunctions::TIsLegalShortNameCharacter)(lib.Lookup(3));
+ TheCodePage.iCodePageFunctions.iConvertFromUnicodeL = (TCodePageFunctions::TConvertFromUnicodeL)(lib.Lookup(4));
+ TheCodePage.iCodePageFunctions.iConvertToUnicodeL = (TCodePageFunctions::TConvertToUnicodeL)(lib.Lookup(5));
+
+ if( TheCodePage.iCodePageFunctions.iIsLegalShortNameCharacter == NULL ||
+ TheCodePage.iCodePageFunctions.iConvertFromUnicodeL == NULL ||
+ TheCodePage.iCodePageFunctions.iConvertToUnicodeL == NULL )
+ {
+ return(KErrCorrupt);
+ }
+ TheCodePage.iCodepageLoaded = TCodePageUtils::ECodePageDll;
+
+ return(KErrNone);
+ }
+
+TInt TFsLoadCodePage::Initialise(CFsRequest* aRequest)
+//
+// Installs a code page
+//
+ {
+ __PRINT(_L("TFsLoadCodePage::Initialise(CFsRequest* aRequest)"));
+
+ // Set the drive
+ TInt drive = aRequest->Session()->CurrentDrive();
+ aRequest->SetDrive(&TheDrives[drive]);
+
+ TSecurityPolicy policy(RProcess().SecureId(), ECapabilityDiskAdmin);
+ if (!policy.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("TFsLoadCodePage::Initialise")))
+ {
+ return KErrPermissionDenied;
+ }
+
+ return KErrNone;
+ }
+
+// use second half of ISO Latin 1 character set for extended chars
+const TUint KExtendedCharStart=0x80;
+const TUint KExtendedCharEnd=0xff;
+
+_LIT8(KLit8ReplacementForUnconvertibleUnicodeCharacters, "_");
+
+TCodePageUtils::TCodePageUtils()
+//
+// Constructor
+//
+ : iCodePageFunctions(),
+ iLocaleFatUtilityFunctions(NULL),
+ iCodepageLoaded(ENone)
+ {
+ }
+
+TBool TCodePageUtils::IsCodepageLoaded() const
+//
+// Returns ETrue if a codepage is loaded
+//
+ {
+ return(iCodepageLoaded != ENone);
+ }
+
+TCodePageUtils::TCodepageLoaded TCodePageUtils::CodepageLoaded() const
+//
+// Returns the type of active codepage
+//
+ {
+ return(iCodepageLoaded);
+ }
+
+void TCodePageUtils::SetLocaleCodePage(TFatUtilityFunctions* aFunctions)
+//
+// Sets the current codepage to that provided by the current Locale DLL
+//
+ {
+ if(iCodepageLoaded == ENone && aFunctions)
+ {
+ iLocaleFatUtilityFunctions = aFunctions;
+ iCodepageLoaded = ELocaleDll;
+ }
+ }
+
+TFatUtilityFunctions* TCodePageUtils::LocaleFatUtilityFunctions() const
+//
+// Returns function pointer to the read Locale conversions functions
+//
+ {
+ return(iLocaleFatUtilityFunctions);
+ }
+
+TCodePageFunctions TCodePageUtils::CodepageFatUtilityFunctions() const
+//
+// Returns structure to function pointers to the read Codepage conversions functions
+//
+ {
+ return(iCodePageFunctions);
+ }
+
+TBool TCodePageUtils::ConvertFromUnicode(TDes8& aForeign, const TDesC16& aUnicode, TOverflowAction aOverflowAction) const
+/**
+Convert from Unicode, truncating if there is not enough room in the output.
+
+@param aForeign The output is appended here.
+@param aUnicode The input.
+
+@return False if and only if aForeign has not enough space remaining.
+*/
+ {
+ TBool allConverted = ETrue;
+ const TInt maximumLength=aForeign.MaxLength();
+ TInt lengthToCopy=aUnicode.Length();
+ // do not cross the maximum foreign length
+ if (maximumLength<lengthToCopy)
+ {
+ if (aOverflowAction==TCodePageUtils::EOverflowActionLeave)
+ {
+ allConverted = EFalse;
+ return allConverted;
+ }
+ lengthToCopy=maximumLength;
+ }
+
+ aForeign.SetLength(lengthToCopy);
+
+ TInt j=0; // offset for aForeign[]
+ TInt i=0; // offset for aUnicode[]
+ for (i=0; i<lengthToCopy; ++i)
+ {
+ const TDesC8& replacementChar = KLit8ReplacementForUnconvertibleUnicodeCharacters;
+ TUint32 unicodeChar = aUnicode[i];
+
+ // if High Surrogate
+ if (IsHighSurrogate((TText16)unicodeChar))
+ {
+ // check for low surrogate
+ if (!IsLowSurrogate(aUnicode[++i]))
+ {
+ aForeign[j++] = (TUint8)replacementChar[0];
+ continue;
+ }
+ unicodeChar = JoinSurrogate((TText16)unicodeChar, (TText16)aUnicode[i]);
+ }
+
+ // if Low Surrogate
+ if (IsLowSurrogate((TText16)unicodeChar))
+ {
+ aForeign[j++] = (TUint8)replacementChar[0];
+ continue;
+ }
+ // if Supplementary - Non BMP
+ if (IsSupplementary(unicodeChar))
+ {
+ aForeign[j++] = (TUint8)replacementChar[0];
+ }
+ else
+ {
+ // ASCII support
+ if((TUint)unicodeChar>=0x100)
+ {
+ aForeign[j++] = (TUint8)replacementChar[0];
+ }
+ else
+ {
+ aForeign[j++] = (TUint8)unicodeChar;
+ }
+ }
+ }
+
+ // if any replacementChar used, aForeign offset(j) shall be less than
+ // lengthToCopy aUnicode offset(i)
+ if(j<i)
+ {
+ aForeign.SetLength(j);
+ }
+
+ return(allConverted);
+ }
+
+EXPORT_C void TCodePageUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TOverflowAction aOverflowAction) const
+/**
+Convert from Unicode, truncating if there is not enough room in the output.
+
+@param aForeign The output is appended here.
+@param aUnicode The input.
+
+@leave KErrOverflow if aForeign is too short for the output.
+*/
+ {
+ TInt r = KErrNone;
+ TBool LeaveWhenError = (TBool)((aOverflowAction==TCodePageUtils::EOverflowActionLeave)?(TBool)ETrue:(TBool)EFalse);
+ // if CodePage dll
+ if(GetFatUtilityFunctions() && iCodepageLoaded == ECodePageDll && iCodePageFunctions.iConvertFromUnicodeL)
+ {
+ r = (*iCodePageFunctions.iConvertFromUnicodeL)(aForeign, aUnicode, LeaveWhenError);
+ }
+ // if Locale dll
+ else if(GetFatUtilityFunctions() && iCodepageLoaded == ELocaleDll && iLocaleFatUtilityFunctions->iConvertFromUnicodeL)
+ {
+ if(aOverflowAction == TCodePageUtils::EOverflowActionLeave)
+ {
+ (*iLocaleFatUtilityFunctions->iConvertFromUnicodeL)(aForeign, aUnicode, KLit8ReplacementForUnconvertibleUnicodeCharacters, TFatUtilityFunctions::EOverflowActionLeave);
+ }
+ else
+ {
+ (*iLocaleFatUtilityFunctions->iConvertFromUnicodeL)(aForeign, aUnicode, KLit8ReplacementForUnconvertibleUnicodeCharacters, TFatUtilityFunctions::EOverflowActionTruncate);
+ }
+ }
+ // default implementation
+ else if (!ConvertFromUnicode(aForeign, aUnicode, aOverflowAction))
+ {
+ if (aOverflowAction==TCodePageUtils::EOverflowActionLeave)
+ {
+ User::Leave(KErrBadName);
+ }
+ }
+
+ r = r; // remove warning
+ // File Server do not use this error code so do not send this error code right to File Server
+ // rather suppress it. Can be used in future.
+ return;
+ }
+
+TBool TCodePageUtils::ConvertToUnicode(TDes16& aUnicode, const TDesC8& aForeign) const
+/*
+Convert to Unicode, truncating if there is not enough room in the output.
+
+@param aUnicode The output is appended here.
+@param aForeign The input.
+
+@return False if and only if aUnicode has not enough space remaining.
+*/
+ {
+ // A workaround to handle leading 'E5' byte in short file names
+ TBuf8<KMaxLengthShortNameWithDot> shortFileNameWithLeadingE5;
+ TBool convertedLeading05toE5 = EFalse;
+
+ if (0 < aForeign.Length() && aForeign.Length() <= 12 && aForeign[0] == KLeadingE5Replacement)
+ {
+ shortFileNameWithLeadingE5 = aForeign;
+ shortFileNameWithLeadingE5[0] = KEntryErasedMarker;
+ convertedLeading05toE5 = ETrue;
+ }
+
+ const TInt maximumLength=aUnicode.MaxLength();
+ if (maximumLength>=aForeign.Length())
+ {
+ if (convertedLeading05toE5)
+ {
+ aUnicode.Copy(shortFileNameWithLeadingE5);
+ }
+ else
+ {
+ aUnicode.Copy(aForeign);
+ }
+ return ETrue;
+ }
+ else
+ {
+ if (convertedLeading05toE5)
+ {
+ aUnicode.Copy(shortFileNameWithLeadingE5.Left(maximumLength));
+ }
+ else
+ {
+ aUnicode.Copy(aForeign.Left(maximumLength));
+ }
+ return EFalse;
+ }
+ }
+
+EXPORT_C void TCodePageUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TOverflowAction aOverflowAction) const
+/*
+Convert to Unicode, leaving if there is not enough room in the output.
+
+@param aUnicode The output is appended here.
+@param aForeign The input.
+
+@leave KErrOverflow if aUnicode is too short for the output.
+*/
+ {
+ TInt r = KErrNone;
+ TBool LeaveWhenError = (TBool)((aOverflowAction==TCodePageUtils::EOverflowActionLeave)?(TBool)ETrue:(TBool)EFalse);
+ // if CodePage dll
+ if(GetFatUtilityFunctions() && iCodepageLoaded == ECodePageDll && iCodePageFunctions.iConvertToUnicodeL)
+ {
+ r = (*iCodePageFunctions.iConvertToUnicodeL)(aUnicode, aForeign, LeaveWhenError);
+ }
+ // if Locale dll
+ else if(GetFatUtilityFunctions() && iCodepageLoaded == ELocaleDll && iLocaleFatUtilityFunctions->iConvertToUnicodeL)
+ {
+ if(aOverflowAction == TCodePageUtils::EOverflowActionLeave)
+ {
+ (*iLocaleFatUtilityFunctions->iConvertToUnicodeL)(aUnicode, aForeign, TFatUtilityFunctions::EOverflowActionLeave);
+ }
+ else
+ {
+ (*iLocaleFatUtilityFunctions->iConvertToUnicodeL)(aUnicode, aForeign, TFatUtilityFunctions::EOverflowActionTruncate);
+ }
+ }
+ // default implementation
+ else if (!ConvertToUnicode(aUnicode, aForeign))
+ {
+ if (aOverflowAction==TCodePageUtils::EOverflowActionLeave)
+ {
+ User::Leave(KErrBadName);
+ }
+ }
+
+ r = r; // remove warning
+ // File Server do not use this error code so do not send this error code right to File Server
+ // rather suppress it. Can be used in future.
+ return;
+ }
+
+EXPORT_C TBool TCodePageUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars) const
+/**
+Returns true if the input character is legal in a short name.
+
+@param aCharacter Character, in the foreign character encoding.
+
+@return true if aCharacter is legal in a FAT short name.
+*/
+ {
+ if(GetFatUtilityFunctions() && iCodepageLoaded == ECodePageDll && iCodePageFunctions.iIsLegalShortNameCharacter)
+ {
+ return (*iCodePageFunctions.iIsLegalShortNameCharacter)(aCharacter);
+ }
+
+ if(GetFatUtilityFunctions() && iCodepageLoaded == ELocaleDll && iLocaleFatUtilityFunctions->iIsLegalShortNameCharacter)
+ {
+ return (*iLocaleFatUtilityFunctions->iIsLegalShortNameCharacter)(aCharacter);
+ }
+
+ // For most common cases:
+ // Note: lower case characters are considered legal DOS char here.
+ if ((aCharacter>='a' && aCharacter<='z') ||
+ (aCharacter>='A' && aCharacter<='Z') ||
+ (aCharacter>='0' && aCharacter<='9'))
+ {
+ return ETrue;
+ }
+
+ // Default Implmentation
+ // Checking for illegal chars:
+ // 1. aCharacter <= 0x20
+ // Note: leading 0x05 byte should be guarded by callers of this function
+ // as the information of the position of the character is required.
+ if (aCharacter < 0x20)
+ return EFalse;
+ // Space (' ') is not considered as a legal DOS char here.
+ if (aCharacter == 0x20)
+ return EFalse;
+
+ // 2. 0x20 < aCharacter < 0x80
+ if (0x20 < aCharacter && aCharacter < KExtendedCharStart)
+ {
+ // According to FAT Spec, "following characters are not legal in any bytes of DIR_Name":
+ switch (aCharacter)
+ {
+ case 0x22: // '"'
+ case 0x2A: // '*'
+ case 0x2B: // '+'
+ case 0x2C: // ','
+ // case 0x2E: // '.' // Although '.' is not allowed in any bytes of DIR_Name, it
+ // is a valid character in short file names.
+ case 0x2F: // '/'
+ case 0x3A: // ':'
+ case 0x3B: // ';'
+ case 0x3C: // '<'
+ case 0x3D: // '='
+ case 0x3E: // '>'
+ case 0x3F: // '?'
+ case 0x5B: // '['
+ case 0x5C: // '\'
+ case 0x5D: // ']'
+ case 0x7C: // '|'
+ return EFalse;
+ default:
+ return ETrue;
+ }
+ }
+
+ // 3. 0x80 <= aCharacter <= 0xFF
+ if (KExtendedCharStart <= aCharacter && aCharacter <= KExtendedCharEnd)
+ {
+ if(aUseExtendedChars)
+ return(ETrue);
+ else
+ return EFalse;
+ }
+
+ // 4. aCharacter => 0xFF
+ return EFalse;
+ }