diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfile/sf_plugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfile/sf_plugin.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,835 @@ +// 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_plugin.cpp +// +// + +/** + @file + @internalTechnology +*/ + + +#include "sf_std.h" +#include "sf_plugin_priv.h" + + +EXPORT_C CFsPluginFactory::CFsPluginFactory() + {} + +EXPORT_C CFsPluginFactory::~CFsPluginFactory() + {} + +/** + +Uninstalls the plugin factory. + +This is called just before the plugin factory 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 CFsPluginFactory::Remove() + { + return(KErrNone); + } + +/** + +Sets the plugin factory's resource library. +This library represents the loaded plugin factory. +This is called internally by InstallPluginFactory(). + +@param aLib The resource library to be set. +*/ +EXPORT_C void CFsPluginFactory::SetLibrary(RLibrary aLib) + { + iLibrary=aLib; + } + +/** +Gets the plugin factory's resource library. + +@return The plugin factory's resource library. +*/ +EXPORT_C RLibrary CFsPluginFactory::Library() const + { + return(iLibrary); + } + +/** + +*/ +TBool CFsPluginFactory::IsDriveSupported(TInt aDrive) + { + //If this is version 1 of the plugins, then if KPluginAutoAttach was specified at mount + //then it just returned ETrue! This behaviour is preserved here: + if(!(iSupportedDrives & KPluginVersionTwo) && (aDrive == KPluginAutoAttach)) + { + return(ETrue); + } + + //If we're version 2 plugin (or version1 && !KPluginAutoAttach) then check against what's been set in iSupportedDrives + return((iSupportedDrives & (1 << aDrive)) ? (TBool)ETrue : (TBool)EFalse); + } + + +EXPORT_C CFsPlugin::CFsPlugin() + : iReadOnly(0) + { + Mem::FillZ(iRegisteredIntercepts, sizeof(iRegisteredIntercepts)); + } + +EXPORT_C CFsPlugin::~CFsPlugin() + { + } + +/** +Delivers the request to the end of plugin thread's queue. +In certain circumstances, where the request requires priority handling +it adds it to the front of the queue. + +@param aRequest: The request to be delivered +@return KErrNone +*/ +EXPORT_C TInt CFsPlugin::Deliver(TFsPluginRequest& aRequest) + { + __ASSERT_ALWAYS(iThreadP != NULL, User::Panic(_L("CFsPlugin::Dispatch"),999)); + + TInt function = aRequest.Function(); + + if(function == EFsPluginOpen) + { + // Don't dispatch open requests to the plugin thread + return KPluginMessageForward; + } + + if(function == EFsPluginDoRequest || + function == EFsPluginDoControl || + function == EFsPluginDoCancel) + { + iThreadP->DeliverFront(aRequest.Request()); + } + else + { + iThreadP->DeliverBack(aRequest.Request()); + } + + return KErrNone; + } + +/** +Initialises the plugin but setting all registered intercepts to zero. +Derived classes might wish to implement their own InitialiseL to add intercepts +*/ +EXPORT_C void CFsPlugin::InitialiseL() + { + } + +/** +Creates a new pluginconn object +Leaves with KErrNotSupported + +@return NULL +*/ +EXPORT_C CFsPluginConn* CFsPlugin::NewPluginConnL() + { + User::Leave(KErrNotSupported); + return NULL; + } + +/** +Registers a particular function with plugin to be intercepted + +@param aMessage: the message to be intercepted +@param aInterceptAtts: If it is post or pre intercept +@return KErrNone on successful completion + KErrNotSupported if message is invalid +*/ +EXPORT_C TInt CFsPlugin::RegisterIntercept(TInt aMessage, TInterceptAtts aInterceptAtts) + { + if(aMessage >= EMaxClientOperations) + { + return KErrNotSupported; + } + + const TUint32 index = aMessage >> 2; //-- index in the intercepts array + + if(index >= KIntcArrSize) + { + __ASSERT_DEBUG(0,Fault(EArrayIndexOutOfRange)); + return KErrNotSupported; + } + + const TUint8 msk = (TUint8)(aInterceptAtts << ((aMessage & 0x03) << 1)); + iRegisteredIntercepts[index] |= msk; + + return KErrNone; + } + +/** +Unregisters a particular function with plugin + +@param aMessage: the message which should be unregistered +@param aInterceptAtts: If it is post or pre intercept +@return KErrNone on successful completion + KErrNotSupported if message is invalid +*/ +EXPORT_C TInt CFsPlugin::UnregisterIntercept(TInt aMessage, TInterceptAtts aInterceptAtts) + { + if(aMessage >= EMaxClientOperations) + { + return KErrNotSupported; + } + + const TUint32 index = aMessage >> 2; //-- index in the intercepts array + if(index >= KIntcArrSize) + { + __ASSERT_DEBUG(0,Fault(EArrayIndexOutOfRange)); + return KErrNotSupported; + } + + const TUint8 msk = (TUint8)(aInterceptAtts << ((aMessage & 0x03) << 1)); + iRegisteredIntercepts[index] &= ~msk; + + return KErrNone; + } + +/** + @return ETrue if the message aMessage is registered with any TInterceptAtts type +*/ +TBool CFsPlugin::IsRegistered(TInt aMessage) + { + if(IsRegistered(aMessage,(TInterceptAtts)EPreIntercept) || + IsRegistered(aMessage,(TInterceptAtts)EPrePostIntercept) || + IsRegistered(aMessage, (TInterceptAtts)EPostIntercept)) + { + return (TBool)ETrue; + } + return (TBool)EFalse; + } + +/** + @return ETrue if the message aMessage is registered with the given aInterceptAtts attrubutes +*/ +TBool CFsPlugin::IsRegistered(TInt aMessage, TInterceptAtts aInterceptAtts) + { + if(aMessage >= EMaxClientOperations) + { + return EFalse; + } + + const TUint32 index = aMessage >> 2; //-- index in the intercepts array + if(index >= KIntcArrSize) + { + __ASSERT_DEBUG(0,Fault(EArrayIndexOutOfRange)); + return EFalse; + } + + const TUint8 msk = (TUint8)(aInterceptAtts << ((aMessage & 0x03) << 1)); + + return((iRegisteredIntercepts[index] & msk) == msk); + } + +/** + Return ETrue if the calling thread is the plugin thread +*/ +TBool CFsPlugin::IsPluginThread(CFsRequest& aRequest) + { + if(aRequest.iOwnerPlugin == this) + return ETrue; + + if(aRequest.iClientThreadId == iThreadId) + return ETrue; + + // Allow specific requests from the client connection... + if(aRequest.IsPluginSpecific()) + return EFalse; + + // Check the client connections + return FsPluginManager::IsPluginConnThread(aRequest.iClientThreadId, this); + } + +TBool CFsPlugin::IsMounted(TInt aDrive) + { + CFsPluginFactory* pF = FsPluginManager::GetPluginFactory(this->Name()); + TInt supportedDrives = pF->SupportedDrives(); + + //Version1 plugins could not mount on Z Drive as KPluginAutoAttach==0x19==25==EDriveZ + //Drive Z is only supported for version two of the plugins. + //Prevent version 1 plugins here. + if (!(supportedDrives & KPluginVersionTwo) && (aDrive == EDriveZ)) + return EFalse; + + //Some requests have aDrive as -1, so for those requests + // so long as the plugin was registered we shall say it's mounted. + if(aDrive > EDriveZ || aDrive < EDriveA) + return ETrue; + + //Otherwise Check iMountedOn + if(iMountedOn&(1<CachedSize64(); + if (aPos > fileSize) + aPos = fileSize; + TInt len = aDes.Length(); + if (aPos >= fileSize) + len = 0; + if (aPos + len > fileSize) + // filesize - pos shall of TInt size + // Hence to suppress warning + len = (TInt)(fileSize - aPos); + aDes.SetLength(len); + + return DispatchOperation(aRequest, aDes, aPos, EFsFileRead); + } + +/** +@prototype +@deprecated +@see RFilePlugin::Write +*/ +EXPORT_C TInt CFsPlugin::FileWrite(TFsPluginRequest& aRequest, const TDesC8& aDes, TInt64 aPos) + { + return DispatchOperation(aRequest, (TDes8&) aDes, aPos, EFsFileWrite); + } + +/** +@internalTechnology +@prototype +@deprecated + +Pushes a msgop, dispatches it and waits for it to complete +*/ +TInt CFsPlugin::DispatchOperation(TFsPluginRequest& aRequest, TDes8& aDes, TInt64 aPos, TInt aFunction) + { + if (aRequest.Function() != EFsFileRead && aRequest.Function() != EFsFileWrite) + return KErrNotSupported; + if (aFunction != EFsFileRead && aFunction != EFsFileWrite) + return KErrNotSupported; + + CFsMessageRequest& msgRequest = * (CFsMessageRequest*) aRequest.Request(); + + + TInt len = aDes.Length(); + if (len <= 0) + return CFsRequest::EReqActionComplete; + + TUint8* ptr = (TUint8*) aDes.Ptr(); + + TInt r = msgRequest.PushOperation( + aPos, len, ptr, + 0, // aOffset + Complete, // callback + 0, // next state + aFunction); + if (r != KErrNone) + return r; + + + CFsPlugin* plugin = this; + FsPluginManager::NextPlugin(plugin, &msgRequest,(TBool)ETrue); + msgRequest.iCurrentPlugin = plugin; + msgRequest.Dispatch(); + iThreadP->OperationLockWait(); + + aDes.SetLength(len); + + return msgRequest.LastError(); // KErrNone; + } + +TInt CFsPlugin::WaitForRequest() + { + iLastError = KErrNone; + iThreadP->OperationLockWait(); + return iLastError; + } + + +/** @prototype */ +TInt CFsPlugin::Complete(CFsRequest* aRequest, TInt aError) + { + CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest; + + CFsPlugin* plugin = msgRequest.iOwnerPlugin; + if (plugin) + { + plugin->iLastError = aError; + plugin->iThreadP->OperationLockSignal(); + msgRequest.iOwnerPlugin = NULL; + return CFsRequest::EReqActionComplete; + } + + TMsgOperation& currentOperation = msgRequest.CurrentOperation(); + + if (currentOperation.iState == 0) // waiting ? + { + currentOperation.iState = 1; + msgRequest.iCurrentPlugin->iThreadP->OperationLockSignal(); + // DON'T dispatch message again, DON'T complete message + return CFsRequest::EReqActionOwnedByPlugin; + } + else + { + return CFsRequest::EReqActionComplete; + } + } + +/** @prototype */ +TInt CFsPlugin::Complete(CFsRequest* aRequest) + { + return CFsPlugin::Complete(aRequest, KErrNone); + } + +/** @prototype */ +EXPORT_C TInt CFsPlugin::ClientWrite(TFsPluginRequest& aRequest, const TDesC8& aDes, TInt aOffset) + { + CFsMessageRequest& msgRequest = * (CFsMessageRequest*) aRequest.Request(); + TMsgOperation& currentOperation = msgRequest.CurrentOperation(); + + TInt r = KErrNone; + if (currentOperation.iClientRequest) + { + r = msgRequest.Write(0, aDes, aOffset); + } + else + { + TInt len = aDes.Length(); + if (len > (currentOperation.iReadWriteArgs.iTotalLength - aOffset)) + return KErrArgument; + memcpy(((TUint8*) currentOperation.iReadWriteArgs.iData) + aOffset, aDes.Ptr(), len); + currentOperation.iReadWriteArgs.iOffset = aOffset + len; + } + return r; + } + +/** @prototype */ +EXPORT_C TInt CFsPlugin::ClientRead(TFsPluginRequest& aRequest, TDes8& aDes, TInt aOffset) + { + CFsMessageRequest& msgRequest = * (CFsMessageRequest*) aRequest.Request(); + TMsgOperation& currentOperation = msgRequest.CurrentOperation(); + + TInt r = KErrNone; + if (currentOperation.iClientRequest) + { + r = msgRequest.Read(0, aDes, aOffset); + } + else + { + TInt len = aDes.Length(); + if (len > (currentOperation.iReadWriteArgs.iTotalLength - aOffset)) + return KErrArgument; + aDes.Copy ( (TUint8*) currentOperation.iReadWriteArgs.iData + aOffset, len ); + currentOperation.iReadWriteArgs.iOffset = aOffset + len; + } + return r; + } + +/** +Constructs a TFsPluginRequest object +@param aReuqest client's request, to be wrapped by TFsPluginRequest object +*/ +EXPORT_C TFsPluginRequest::TFsPluginRequest(CFsRequest* aRequest) + : iFsRequest(aRequest) + { } + +/** +@return The function of the request +*/ +EXPORT_C TInt TFsPluginRequest::Function() const + { return(iFsRequest->Operation()->Function()); } + +/** +@return The drive number of the request +*/ +EXPORT_C TInt TFsPluginRequest::DriveNumber() const + { return(iFsRequest->DriveNumber()); } + +/** +@return The source of the request (often the filename) +*/ +EXPORT_C TParse& TFsPluginRequest::Src() const + { return(iFsRequest->Src()); } + +/** +@return The destination of the request (often the filename) +*/ +EXPORT_C TParse& TFsPluginRequest::Dest() const + { return(iFsRequest->Dest()); } + +/** +@return The drive of the request +*/ +EXPORT_C TDrive* TFsPluginRequest::Drive() const + { return(iFsRequest->Drive()); } + +/** +@return The substitude drive of the request +*/ +EXPORT_C TDrive* TFsPluginRequest::SubstedDrive() const + { return(iFsRequest->SubstedDrive()); } + +/** +@return The message of the request +*/ +EXPORT_C const RMessage2& TFsPluginRequest::Message() const + { return(iFsRequest->Message()); } + +/** +@return The request itself +*/ +EXPORT_C CFsRequest* TFsPluginRequest::Request() const + { + __ASSERT_DEBUG(iFsRequest != NULL, User::Invariant()); + return iFsRequest; + } + +/** +@return The scratch value of the request +*/ +EXPORT_C TUint TFsPluginRequest::ScratchValue() const + { return iFsRequest->ScratchValue(); } + +/** +@return The scratch value of the request +*/ +EXPORT_C TInt64 TFsPluginRequest::ScratchValue64() const + { return iFsRequest->ScratchValue64(); } + +/** +@return ETrue if the operation is in Post-Intercept +*/ +EXPORT_C TInt TFsPluginRequest::IsPostOperation() const + { return(iFsRequest->IsPostOperation()); } + + +EXPORT_C TInt TFsPluginRequest::Read(TF32ArgType aType, TDes8& aDes, TInt aOffset) + { + return(iFsRequest->Read(aType, aDes, aOffset)); + } + +EXPORT_C TInt TFsPluginRequest::Read(TF32ArgType aType, TDes16& aDes, TInt aOffset) + { + //The following if packaged correctly will never come here + //but just in case someone tries something wrong with a wonky wide descriptor + switch(aType) + { + case (TF32ArgType)EEntryArray: + case (TF32ArgType)EEntry: + case (TF32ArgType)EUid: + case (TF32ArgType)ETime: + return KErrBadDescriptor; + default: + break; + } + return(iFsRequest->Read(aType, aDes, aOffset)); + } + +EXPORT_C TInt TFsPluginRequest::Read(TF32ArgType aType, TInt& aVal) + { + // + // Some messages require special handling... + // + if(aType == (TF32ArgType)EPosition) + { + return KErrArgument; + } + + return iFsRequest->Read(aType, aVal); + } + +EXPORT_C TInt TFsPluginRequest::Read(TF32ArgType aType, TUint& aVal) + { + // + // Some messages require special handling... + // + if(aType == (TF32ArgType)EPosition) + { + return KErrArgument; + } + + return iFsRequest->Read(aType, aVal); + } + +EXPORT_C TInt TFsPluginRequest::Read(TF32ArgType aType, TInt64& aVal) + { + TInt err = iFsRequest->Read(aType, aVal); + if(err != KErrNone) + return err; + + // + // Some messages require special handling... + // + if(aType == (TF32ArgType)EPosition) + { + TInt op = Function(); + if(op == EFsFileRead || op == EFsFileWrite) + { + if (aVal == KCurrentPosition64) + { + CFileShare* share = (CFileShare*)iFsRequest->ScratchValue(); + if(share == NULL) + return KErrBadHandle; + + aVal = share->iPos; + } + } + } + + return KErrNone; + } + +EXPORT_C TInt TFsPluginRequest::Write(TF32ArgType aType, const TDesC8& aDes, TInt aOffset) + { + return(iFsRequest->Write(aType, aDes, aOffset)); + } + + +EXPORT_C TInt TFsPluginRequest::Write(TF32ArgType aType, const TDesC16& aDes, TInt aOffset) + { + return(iFsRequest->Write(aType, aDes, aOffset)); + } + +EXPORT_C TInt TFsPluginRequest::FileName(TDes& aName) + { + //Special handling required for directories. + switch(Function()) + { + case EFsDirOpen: + { + aName.Copy(Request()->Src().FullName()); + break; + } + case EFsDirReadOne: + case EFsDirReadPacked: + case EFsDirSubClose: + { + //Get the name from CDirCB::iName + CDirCB* dir = (CDirCB*) ScratchValue(); + __ASSERT_ALWAYS(dir!= NULL, Fault(EPluginOpError)); + TName name = dir->Name(); + if(name.Size() == 0) + { + return KErrNotFound; + } + aName.Copy(name); + break; + } + default: + { + CFileShare* share; + TInt err = ShareFromClientHandle(share); + if(err != KErrNone || share == NULL) + return(err); + + NameFromShare(*share, aName); + } + } + return KErrNone; + } + +EXPORT_C TInt TFsPluginRequest::SetSharePos(TInt64& aPos) + { + CFileShare* share; + TInt err = ShareFromClientHandle(share); + if(err != KErrNone || share == NULL) + return(KErrBadHandle); + + share->File().Drive().Lock(); + share->iPos = aPos; + share->File().Drive().UnLock(); + + return KErrNone; + } + +TInt TFsPluginRequest::ShareFromClientHandle(CFileShare*& aShare) + { + aShare = NULL; + + TInt handle; + TInt err = ClientSubSessionHandle(handle); + if(err != KErrNone) + return err; + + aShare = GetShareFromHandle(iFsRequest->Session(), handle); + + return aShare ? KErrNone : KErrBadHandle; + } + +TInt TFsPluginRequest::ClientSubSessionHandle(TInt& aHandle) + { + aHandle = 0; + + // Subsession handle is in Arg[3] for read/write etc, but + // when subsession create it's contained in client descriptor + if(iFsRequest->Operation()->IsOpenSubSess()) + { + if(!IsPostOperation()) + return KErrNotSupported; + + TPtr8 handleDes((TUint8*)&aHandle,sizeof(TInt)); + TInt err = iFsRequest->Read(KMsgPtr3,handleDes); + if(err != KErrNone) + return err; + } + else + { + aHandle = iFsRequest->Message().Int3(); + } + + return KErrNone; + } + +/** +@publishedPartner + +Utility function to obtain the file name from a file share object + +@param aFileShare A pointer to the file share +@param aName A reference to the descriptor to contain the file name +*/ +void TFsPluginRequest::NameFromShare(CFileShare& aFileShare, TDes& aName) + { + CFileCB& theFile = aFileShare.File(); + aName = _L("?:"); + aName[0] = TText('A' + theFile.Drive().DriveNumber()); + aName.Append(theFile.FileName()); + } + + +/** +Constructor of plugin connection object +*/ +EXPORT_C CFsPluginConn::CFsPluginConn() + { + } + +/** +Destructor of plugin conn. object +*/ +EXPORT_C CFsPluginConn::~CFsPluginConn() + { + } + +/** +Closes the plugin conn. +*/ +EXPORT_C void CFsPluginConn::Close() + { + iRequestQue.DoCancelAll(KErrCancel); + CFsObject::Close(); + } + +CFsPluginConnRequest::CFsPluginConnRequest(CFsPluginConn* aPluginConn) + : iPluginConn(*aPluginConn) + { + } + +TInt CFsPluginConnRequest::InitControl(CFsRequest* aRequest) + { + iMessage = aRequest->Message(); + const RMessage2& m = aRequest->Message(); + iFunction = m.Int0(); + iParam1 = (TDes8*)m.Ptr1(); + iParam2 = (TDes8*)m.Ptr2(); + return KErrNone; + } + +TInt CFsPluginConnRequest::DoControl() + { + return iPluginConn.DoControl(*this); + } + +TInt CFsPluginConnRequest::InitRequest(CFsRequest* aRequest) + { + InitControl(aRequest); + iPluginConn.iRequestQue.DoAddRequest(this); + return KErrNone; + } + +void CFsPluginConnRequest::DoRequest() + { + iPluginConn.DoRequest(*this); + } + +TPluginConnRequestQue::TPluginConnRequestQue() + { + iHeader.SetOffset(_FOFF(CFsPluginConnRequest,iLink)); + } + +TPluginConnRequestQue::~TPluginConnRequestQue() + { + } + +void TPluginConnRequestQue::DoAddRequest(CFsPluginConnRequest* aRequest) + { + iHeader.AddLast(*aRequest); + } + +/** +Cancels all the requests of plugin connection + +@param aCompletionCode: the code the request are completed +*/ +EXPORT_C void TPluginConnRequestQue::DoCancelAll(TInt aCompletionCode) + { + TDblQueIter q(iHeader); + CFsPluginConnRequest* info; + while((info=q++)!=NULL) + { + info->Complete(aCompletionCode); + } + __ASSERT_DEBUG(iHeader.IsEmpty(),Fault(EBaseQueCancel)); + } + + +/** +*/ +EXPORT_C TDes8& TRawEntryArray::Buf() + { return iBuf; } + +/** +*/ +EXPORT_C void TRawEntryArray::SetBuf(TDes8& aBuf) + { + iCount = KCountNeeded; + iBuf.Copy(aBuf); + } + +/** +*/ +EXPORT_C TInt TRawEntryArray::EntrySize(TInt aIdx) + { return Align4(::EntrySize((*this)[aIdx])); }