diff -r 48780e181b38 -r 578be2adaf3e Symbian3/PDK/Source/GUID-00764271-AD6B-5F41-AF72-843107EBF95F.dita --- a/Symbian3/PDK/Source/GUID-00764271-AD6B-5F41-AF72-843107EBF95F.dita Tue Jul 20 12:00:49 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-00764271-AD6B-5F41-AF72-843107EBF95F.dita Fri Aug 13 16:47:46 2010 +0100 @@ -1,501 +1,501 @@ - - - - - - File -Server Plugin implementation tutorialThis document contains guidelines for writing a file server plugin -for Symbian platform. -

This document is split into three sections:

- -
Writing a plug-in

A -file server plug-in is made up of at least two classes:

    -
  • a factory class derived -from the CFspluginFactory base -class,

  • -
  • a plug-in class derived -from the CFsplugin base -class.

  • -

Each plug-in must register -to intercept messages. To make -internal requests call the functions RFilePlugin, RDirPlugin or RFsPlugin.

Each -plug-in DLL must export a plug-in entry point function with the prototype:

CFsPluginFactory* CreateFileSystem();

The -loader calls this function when a client wishes to install a file server plug-in -and creates an instance of the factory class. For example:

extern "C" { - -EXPORT_C CFsPluginFactory* CreateFileSystem() - { - return(new CMyPluginFactory()); - } -}

CFsPluginFactory

The CFsPluginFactory base class follows -the standard factory pattern as used in other file server DLLs. CFsPluginFactory creates CFsPlugin derived objects.

plug-in -authors must provide implementations of the pure virtual functions:

    -
  • Install()

    This -function is called by the file server in response to a call to RFs::AddPlugin() and -installs the plug-in factory.

    This function must set the name of the -plug-in factory with a call to CObject::SetName(). -The plug-in name is used when mounting, dismounting and unloading plug-ins. -Optionally, RFs::AddPlugin() can -perform other plugin specific initialization, for example setting iSupportedDrives to -indicate which drives the plugin will operate on, as required by the plugin -factory. See drive -selection.

  • -
  • NewPluginL()

    This -is called by the file server in response to a call to RFs::MountPlugin(), -this function creates a new CFsPlugin derived -object and returns a pointer to it.

  • -
  • UniquePosition()

    This -function returns the unique ID of the plugin. This is used to identify the -plugin and to specify the location of the plugin in the chain. See unique position.

  • -
  • Remove() (overriding -this virtual function is optional as it is not a pure virtual function)

    This -is called just before the plugin factory object is destroyed and allows any -clean up to be carried out.

    The default implementation just returns KErrNone. -Implementations should return an error code on error detection.

  • -

The CFsPluginfactory base -class also has the following member variables:

    -
  • iSupportedDrives

    This -member holds a bit mask that indicates which drives the plugin created by -this factory supports being mounted on. Bits 0 to 25 correspond to 26 drive -letters lettered from A to Z.

    Plugin authors should use the the SetSupportedDrives() API in order -to correctly set up which drives their plugin should be mounted on. Set the -drive number to KPluginSupportAllDrives to -indicate that the plugin needs to be mounted on all drives.

    If you -are using Symbian platform prior to version 9.5, iSupportedDrives is -assigned to by plugin writers directly. However, this is now discouraged in -favour of using SetSupportedDrives.

  • -
  • iUniquePos

    This -member stores the unique position identifier. If this member is used then -plugin authors should implement the UniquePosition() function -to return the variable.

  • -

An example skeleton implementation of a CFsPluginFactory derived -class is as follows:

class CMyPluginFactory : public CFsPluginFactory - { -public: - CMyPluginFactory(); - virtual TInt Install(); - virtual CFsPlugin* NewPluginL(); - virtual TInt UniquePosition(); - virtual TInt Remove(); - }; - -CMyPluginFactory::CMyPluginFactory() - { - // Constructor for the plugin factory - } - -TInt CMyPluginFactory::Install() - { - // Install function for the plugin factory - iUniquePos = 0x2000001; - // Mount on all drives - SetSupportedDrives(KPluginSupportAllDrives); - return SetName(_L("MyPluginName")); - } - -CFsPlugin* CMyPluginFactory::NewPluginL() - { - // plugin factory function, creates the plugin - return CMyPlugin::NewL(); - } - -TInt CMyPluginFactory::UniquePosition() - { - // Return’s the unique position identifier for plugins created by this factory class. - return iUniquePos; - } - -TInt CMyPluginFactory::Remove() - { - // Clean up function for the plugin factory - return KErrNone; - }

CFsPlugin

This -is the base class for the file server plugin and is defined in f32plugin.h.

Plugins -must register to intercept particular types of file server requests. See Registering -a plugin to intercept messages.

Plugin authors need to provide -an implementation of the pure virtual method DoRequestL() and -can optionally override the virtual functions:

    -
  • SessionDisconnect() - virtual,

  • -
  • InitialiseL() - virtual,

  • -
  • Deliver() - virtual,

  • -
  • NewPluginConnL() - virtual,

  • -
  • DoRequestL() - pure virtual,

  • -

SessionDisconnect()

SessionDisconnect() is called -by the file server when a file server session is disconnected.

The -default implementation just returns KErrNone. Overriding -this function allows plugins to free up any resources prior to the outstanding -operations being cancelled.

InitialiseL()

The -default implementation of InitialiseL() does -nothing. Override this implementation to perform a plugin specific initialisation, -for example registering -intercepts. If the plugin cannot be initialised this function must -leave with a suitable error code.

Deliver()

Deliver() is called in the context -of the previous thread that originated or processed the request (either the -file server main thread or another plugin thread) before the request is dispatched -to the plugin’s thread.

The default implementation delivers the request -to the end of the plugin thread's request queue. Requests that require priority -handling (usually those sent using an RPlugin session) -are delivered to the front of the queue. See Communicating -with plugins.

Overriding this function allows plugins to perform -operations within the context of the original thread (like validation of request -parameters or filtering requests) before the request is sent to the plugin’s -main thread or passed to the next plugin or drive thread.

Deliver() is -called from outside the context of the plugin’s main thread so care must be -taken as the plugin main thread may still be processing the previous request.

    -
  • If KErrNone is -returned then the base class implementation of this function must be called -to ensure that the request is dispatched to the plugin’s thread for further -processing in DoRequestL().

  • -
  • KPluginMessageForward indicates -that the request has been processed synchronously and should be passed down -to the next plugin in the stack (bypassing the current plugin’s DoRequestL() function). -This is used for pre-intercepts.

  • -
  • KPluginMessageComplete indicates -that the request has been processed synchronously and should be passed up -to the previous plugin in the stack (bypassing the current plugin’s DoRequestL() function). -This is used for post-intercepts.

  • -

NewPluginConnL()

The -function NewPluginConnL() is -the default implementation and it returns KErrNotSupported. -Override this implementation to create a CFsPluginConn derived -object to enable direct communication between a client application and a plugin -using RPlugin. See Communicating -with plugins.

DoRequestL()

DoRequestL() is the main entry -point for messages intercepted by a plugin. Individual plugins are usually -single-threaded and must process requests in the order that they arrive. However, -the plugin framework is not single-threaded. While a plugin is handling a -request all other plugins are also able to handle requests. The drive thread -is also able to handle requests forwarded to it by plugins. DoRequestL() is -called in the context of the plugin’s main thread and must be implemented -to intercept file server requests in this context.

The current request -must have finished all processing before DoRequestL() has -completed. If a plugin has multiple threads and the request is handled in -a thread other than the main thread then the DoRequestL() function -must be blocked until the request has been processed. This is because when DoRequestL() exits, -the plugin framework forwards the message to the next plugin in the chain. -Unpredictable behaviour may occur if the plugin has not finished processing -a request before it is passed to the next plugin/file system.

Errors -returned by this function are propagated back to the client. If this function -leaves then the client thread panics. Note: Do not return from this -function until the request has been fully processed. This is because after -returning from this function the request is passed onto the next plugin in -the chain. This means that you cannot pass the request to a separate thread -and return immediately in order to implement a multi-threaded plugin.

KErrCompletion indicates -that all processing for this request has been completed by this plugin. Post-intercept -is then enabled and the flow of execution is up the plugin stack towards the -client, starting at the previous plugin.

When a plugin intercepts -a file read or file write request and does an early completion (i.e. returns KErrCompletion in pre-intercept) -then the plugin author should call TFsPluginRequest::SetSharePos() to -allow share position to be updated after early read/write completion.

TFsPluginRequest

The TFsPluginRequest class encapsulates -the intercepted file server request and is passed as a reference to the plugin's DoRequestL() function. TFsPluginRequest provides -APIs that extract request specific information such as:

    -
  • DriveNumber() - -returns the target drive number. The drive number is in the range of zero -to 25, which corresponds to drive letters A to Z,

  • -
  • Function() - -the type of request as defined in TFsMessage,

  • -
  • IsPostOperation() - -returns ETrue or EFalse to indicate if the -request being intercepted is in post-intercept mode (ETrue) -or pre-intercept.

  • -

TFsPluginRequest acts -as a utility class for plugins. This class has two main functions TFsPluginRequest::Read() and TFsPluginRequest::Write(), which -allow a plugin to read from and write to the message arguments of a request.

TFsPluginRequest::Read() has -various overloads for TInt, TUint, Tint64 and -descriptor data types, all of which take as their first argument a TF32ArgType object.

The TF32ArgType is an enumeration -which defines the type of data that is requested. For example, EPosition, ELength, EData for -getting the position, length and data arguments from the request. TF32ArgType is -defined as follows:

enum TF32ArgType - { - EPosition, - ELength, - EData, - ESize, - EName, - ENewName, - EEntry, - ETime, - ESetAtt, - EClearAtt, - EMode, - EAtt, - EAttMask, - EUid, - EEntryArray, - ENewPosition, - };

TFsPluginRequest::Write() only -has two overloads, both of these take descriptor types and the argument TF32ArgType. Many functions do -not use descriptor types, it will be necessary to package data for these inside -a descriptor.

The following provides an example of how to do this -for Entry:

TPckgC<TEntry> entryPckg(entry); - err = aRequest.Write(EEntry, entryPckg);

Sending internal requests -to the file server

The classes RFilePlugin, RDirPlugin and RFsPlugin, -defined in F32Plugin.h, are the classes that plugin authors -should use to send internal requests to the file server. The APIs for these -classes are mostly identical from their client side (RFile, RDir and RFs) -counter-parts.

Before a plugin can perform any requests on a file -it must first either perform an Open() or AdoptFromClient(). When an AdoptFromClient() is -performed the RFilePlugin instance opens the file associated -with the client request. Open() can be used to open the same -file (potentially with different parameters than those supplied by the client) -and it can be used to open an entirely different file.

RFilePlugin has -the following public functions:

class RFilePlugin : private RFile - { -public: - IMPORT_C RFilePlugin(TFsPluginRequest& aRequest, TBool aDirectToDrive = EFalse); - - // open a NEW file using same session as passed request - IMPORT_C TInt Open(const TDesC& aName,TUint aMode); - IMPORT_C TInt Create(const TDesC& aName,TUint aFileMode); - IMPORT_C TInt Replace(const TDesC& aName,TUint aFileMode); - IMPORT_C TInt Temp(const TDesC& aPath,TFileName& aName,TUint aFileMode); - - // re-open SAME file as client's request - IMPORT_C TInt AdoptFromClient(); - // Transfer the plugin's open file to the client - IMPORT_C TInt TransferToClient(); - - IMPORT_C void Close(); - - // RFile overloads - IMPORT_C TInt Read(TInt64 aPos,TDes8& aDes) const; - IMPORT_C TInt Read(TInt64 aPos,TDes8& aDes,TInt aLength) const; - IMPORT_C TInt Write(TInt64 aPos,const TDesC8& aDes); - IMPORT_C TInt Write(TInt64 aPos,const TDesC8& aDes,TInt aLength); - IMPORT_C TInt Lock(TInt64 aPos,TInt64 aLength) const; - IMPORT_C TInt UnLock(TInt64 aPos,TInt64 aLength) const; - IMPORT_C TInt Seek(TSeek aMode,TInt64& aPos) const; - IMPORT_C TInt Flush(); - IMPORT_C TInt Size(TInt64& aSize) const; - IMPORT_C TInt SetSize(TInt64 aSize); - IMPORT_C TInt Att(TUint& aAttValue) const; - IMPORT_C TInt SetAtt(TUint aSetAttMask,TUint aClearAttMask); - IMPORT_C TInt Modified(TTime& aTime) const; - IMPORT_C TInt SetModified(const TTime& aTime); - IMPORT_C TInt Set(const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask); - IMPORT_C TInt ChangeMode(TFileMode aNewMode); - IMPORT_C TInt Rename(const TDesC& aNewName); - ...

Registering a plugin to -intercept messages

The base class CFsPlugin, -has functions that allow a plugin to register to intercept specific types -of file server request. This is explained in more detail under Interception of file server requests.

RegisterIntercept()

The function RegisterIntercept() registers -a plugin to intercept a specified TFsMessage. -The second parameter of RegisterIntercept() allows plugin -authors to specify whether the intercept is processed before, after or both -before and after the request is processed by the drive thread. See TInterceptAtts.

UnregisterIntercept()

Un-register an intercept with UnregisterIntercept(). UnregisterIntercept() takes TFsMessage, which is the ID of -the message and TInterceptAtts, -which is the type of intercept that you no longer wish to intercept.

-
Loading and -mounting a plugin

A plugin must be loaded and mounted before it -can intercept requests.

Loading and unloading a -plugin

Before a plugin can be used by the file server the library -(.PXT) that contains the plugin needs to be loaded into -the file server process by the loader. Do this using the RFs::AddPlugin() function -defined in f32file.h.

AddPlugin() can -be called by any user side application with the relevant platform security capabilities.

Unload a plugin using the RFs::RemovePlugin() function -also defined in f32file.h.

Note: Refer -to the device manufacturer if you want to load plugins automatically at system -startup time.

Mounting and unmounting -a plugin

File Server plugins are mounted using the RFs::MountPlugin() function -defined in f32file.h. The plug in must have already been -loaded using RFs::AddPlugin().

There -are various overloads of the MountPlugin() function. Those -functions which do not take a drive parameter are mounted using KPluginAutoAttach.

Call RFs::DismountPlugin() to dismount -the file server plugin. Dismount the plugin when you no longer need it to -intercept file server requests.

Before a plugin can be dismounted -all resources owned by the plugin must be closed. A plugin can intercept the -request to dismount it and use this to free resources and close down cleanly. -If the plugin owns resources on behalf of a client (for example, a client -has a file open that is using the decompression plugin) then the plugin can -reject the request to dismount by returning one of the system wide error codes.

-
Communicating -with plugins

The file server provides a standard logical channel -based mechanism that enables a trusted application to communicate with a file -server plugin. For example, a virus scanning plugin can present a user interface -for the device user. Note: DiskAdmin capabilities -are required in order to load a plugin. See platform -security capabilities.

Data transfer

The class CFsPluginConnRequest is -an information container for asynchronous requests that the client application -wants performed. CFsPluginConnRequest also provides functions -that enable data to be transferred between the plugin and the application. -The following examples show how to use CFsPluginConnRequest.

User-side application

A -user-side application uses a class derived from RPlugin to -access the plugin. See plugin -side. The RPlugin class (defined in f32file.h) -provides various functions that must be overridden. The functions DoControl(), DoRequest() and DoCancel() are protected. Plugin authors must provide a public interface of their own -design in the derived class that communicates with the plugin using these -protected functions.

An RPlugin session is opened -by passing in the unique -position identifier of the plugin it wishes to communicate with. When -the file server receives the request it validates the capabilities of the -application before calling the plugin's NewPluginConnL() function. -The plugin must certify that it is expecting the client application before -creating the server side connection object.

Below is a basic example -of an RPlugin derived class:

class RMyPlugin : public RPlugin -{ -public: - inline TInt Enable(); - inline TInt Disable(); - }; - -inline TInt RMyPlugin::Enable() - { - return DoControl(EEnable); - } - -inline TInt RMyPlugin::Disable() - { - return DoControl(EDisable); - } - -void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus) const - { - RPlugin::DoRequest(aReqNo,aStatus); - } - -void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1) const - { - RPlugin::DoRequest(aReqNo,aStatus,a1); - } - -void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1,TDes8& a2) const - { - RPlugin::DoRequest(aReqNo,aStatus,a1,a2); - } - -TInt MyRPlugin::DoControl(TInt aFunction) const - { - return RPlugin::DoControl(aFunction); - } - -

This is used in the following way:

Tint r = KErrNone -r = TheFs.AddPlugin(_L("MyPlugin")); -r = TheFs.MountPlugin(_L("MyPlugin"),KPluginSupportAllDrives); -User::LeaveIfError(r); - -RMyPlugin thePlugin; -r = thePlugin.Open(TheFs, KMyPluginUniquePos); -User::LeaveIfError(r); -r = thePlugin.Enable(); -User::LeaveIfError(r); -... -//Perform communication with plugin here -... -r = thePlugin.Disable(); -User::LeaveIfError(r); -thePlugin.Close(); class RMyPlugin : public RPlugin - { -public: - inline TInt Enable(); - inline TInt Disable(); - }; - -inline TInt RMyPlugin::Enable() - { - return DoControl(EEnable); - } - -inline TInt RMyPlugin::Disable() - { - return DoControl(EDisable); - } - -void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus) const - { - RPlugin::DoRequest(aReqNo,aStatus); - } - -void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1) const - { - RPlugin::DoRequest(aReqNo,aStatus,a1); - } - -void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1,TDes8& a2) const - { - RPlugin::DoRequest(aReqNo,aStatus,a1,a2); - } - -TInt MyRPlugin::DoControl(TInt aFunction) const - { - return RPlugin::DoControl(aFunction); - } - -etc.. -} -

This is used in the following way:

Tint r = KErrNone -r = TheFs.AddPlugin(_L("MyPlugin")); -r = TheFs.MountPlugin(_L("MyPlugin"),KPluginSupportAllDrives); -User::LeaveIfError(r); - -RMyPlugin thePlugin; -r = thePlugin.Open(TheFs, KMyPluginUniquePos); -User::LeaveIfError(r); -r = thePlugin.Enable(); -User::LeaveIfError(r); -... -//Perform communication with plugin here -... -r = thePlugin.Disable(); -User::LeaveIfError(r); -thePlugin.Close();

Plugin side

This -is the plugin side of the communication. This must be implemented in order -to communicate with the application side class RPlugin above. -The plugin side is a class derived from the CFsPluginConn class. -The plugin’s NewPluginConnL() function -is called from the file server when RPlugin::Open() is -called by the client.

Synchronous (DoControl()) -and asynchronous (DoRequest()) -requests sent from the RPlugin class -are routed directly to the associated plugin's CFsPluginConn derived -class. The following code shows a basic implementation:

class CMyPluginConn : public CFsPluginConn - { - virtual TInt DoControl(CFsPluginConnRequest& aRequest); - virtual void DoRequest(CFsPluginConnRequest& aRequest); - virtual void DoCancel(TInt aReqMask); - }; - -// From the CFsPlugin derived class -CFsPluginConn* CMyPlugin::NewPluginConnL() - { - CMyPluginConn* thePluginConn = new(ELeave) CMyPluginConn(); - return thePluginConn; - } - -TInt CMyPluginConn::DoControl(CFsPluginConnRequest& aRequest) - { - TInt r = KErrNotSupported; - CMyPlugin& myPlugin = *(CMyPlugin*)Plugin(); - switch(aRequest.Function()) - { - case RMyPlugin::EEnable: - r = myPlugin.Enable(); - break; - case RLoggerConn::EDisable: - r = myPlugin.Disable(); - break; - default: - break; - } - return r; - } - -void CMyPluginConn::DoRequest(CFsPluginConnRequest& aRequest) - { - return KErrNotSupported; - } - -void DoCancel(TInt aReqMask) - { - // Not required as no asynchronous request support - }
+ + + + + + File +Server Plugin implementation tutorialThis document contains guidelines for writing a file server plugin +for Symbian platform. +

This document is split into three sections:

+
    +
  • Writing a plug-in,

  • +
  • Loading and mounting a plug-in,

  • +
  • Communicating with plug-ins.

  • +
+
Writing a plug-in

A +file server plug-in is made up of at least two classes:

    +
  • a factory class derived +from the CFspluginFactory base +class,

  • +
  • a plug-in class derived +from the CFsplugin base +class.

  • +

Each plug-in must register +to intercept messages. To make +internal requests call the functions RFilePlugin, RDirPlugin or RFsPlugin.

Each +plug-in DLL must export a plug-in entry point function with the prototype:

CFsPluginFactory* CreateFileSystem();

The +loader calls this function when a client wishes to install a file server plug-in +and creates an instance of the factory class. For example:

extern "C" { + +EXPORT_C CFsPluginFactory* CreateFileSystem() + { + return(new CMyPluginFactory()); + } +}

CFsPluginFactory

The CFsPluginFactory base class follows +the standard factory pattern as used in other file server DLLs. CFsPluginFactory creates CFsPlugin derived objects.

plug-in +authors must provide implementations of the pure virtual functions:

    +
  • Install()

    This +function is called by the file server in response to a call to RFs::AddPlugin() and +installs the plug-in factory.

    This function must set the name of the +plug-in factory with a call to CObject::SetName(). +The plug-in name is used when mounting, dismounting and unloading plug-ins. +Optionally, RFs::AddPlugin() can +perform other plugin specific initialization, for example setting iSupportedDrives to +indicate which drives the plugin will operate on, as required by the plugin +factory. See drive +selection.

  • +
  • NewPluginL()

    This +is called by the file server in response to a call to RFs::MountPlugin(), +this function creates a new CFsPlugin derived +object and returns a pointer to it.

  • +
  • UniquePosition()

    This +function returns the unique ID of the plugin. This is used to identify the +plugin and to specify the location of the plugin in the chain. See unique position.

  • +
  • Remove() (overriding +this virtual function is optional as it is not a pure virtual function)

    This +is called just before the plugin factory object is destroyed and allows any +clean up to be carried out.

    The default implementation just returns KErrNone. +Implementations should return an error code on error detection.

  • +

The CFsPluginfactory base +class also has the following member variables:

    +
  • iSupportedDrives

    This +member holds a bit mask that indicates which drives the plugin created by +this factory supports being mounted on. Bits 0 to 25 correspond to 26 drive +letters lettered from A to Z.

    Plugin authors should use the the SetSupportedDrives() API in order +to correctly set up which drives their plugin should be mounted on. Set the +drive number to KPluginSupportAllDrives to +indicate that the plugin needs to be mounted on all drives.

    If you +are using Symbian platform prior to version 9.5, iSupportedDrives is +assigned to by plugin writers directly. However, this is now discouraged in +favour of using SetSupportedDrives.

  • +
  • iUniquePos

    This +member stores the unique position identifier. If this member is used then +plugin authors should implement the UniquePosition() function +to return the variable.

  • +

An example skeleton implementation of a CFsPluginFactory derived +class is as follows:

class CMyPluginFactory : public CFsPluginFactory + { +public: + CMyPluginFactory(); + virtual TInt Install(); + virtual CFsPlugin* NewPluginL(); + virtual TInt UniquePosition(); + virtual TInt Remove(); + }; + +CMyPluginFactory::CMyPluginFactory() + { + // Constructor for the plugin factory + } + +TInt CMyPluginFactory::Install() + { + // Install function for the plugin factory + iUniquePos = 0x2000001; + // Mount on all drives + SetSupportedDrives(KPluginSupportAllDrives); + return SetName(_L("MyPluginName")); + } + +CFsPlugin* CMyPluginFactory::NewPluginL() + { + // plugin factory function, creates the plugin + return CMyPlugin::NewL(); + } + +TInt CMyPluginFactory::UniquePosition() + { + // Return’s the unique position identifier for plugins created by this factory class. + return iUniquePos; + } + +TInt CMyPluginFactory::Remove() + { + // Clean up function for the plugin factory + return KErrNone; + }

CFsPlugin

This +is the base class for the file server plugin and is defined in f32plugin.h.

Plugins +must register to intercept particular types of file server requests. See Registering +a plugin to intercept messages.

Plugin authors need to provide +an implementation of the pure virtual method DoRequestL() and +can optionally override the virtual functions:

    +
  • SessionDisconnect() - virtual,

  • +
  • InitialiseL() - virtual,

  • +
  • Deliver() - virtual,

  • +
  • NewPluginConnL() - virtual,

  • +
  • DoRequestL() - pure virtual,

  • +

SessionDisconnect()

SessionDisconnect() is called +by the file server when a file server session is disconnected.

The +default implementation just returns KErrNone. Overriding +this function allows plugins to free up any resources prior to the outstanding +operations being cancelled.

InitialiseL()

The +default implementation of InitialiseL() does +nothing. Override this implementation to perform a plugin specific initialisation, +for example registering +intercepts. If the plugin cannot be initialised this function must +leave with a suitable error code.

Deliver()

Deliver() is called in the context +of the previous thread that originated or processed the request (either the +file server main thread or another plugin thread) before the request is dispatched +to the plugin’s thread.

The default implementation delivers the request +to the end of the plugin thread's request queue. Requests that require priority +handling (usually those sent using an RPlugin session) +are delivered to the front of the queue. See Communicating +with plugins.

Overriding this function allows plugins to perform +operations within the context of the original thread (like validation of request +parameters or filtering requests) before the request is sent to the plugin’s +main thread or passed to the next plugin or drive thread.

Deliver() is +called from outside the context of the plugin’s main thread so care must be +taken as the plugin main thread may still be processing the previous request.

    +
  • If KErrNone is +returned then the base class implementation of this function must be called +to ensure that the request is dispatched to the plugin’s thread for further +processing in DoRequestL().

  • +
  • KPluginMessageForward indicates +that the request has been processed synchronously and should be passed down +to the next plugin in the stack (bypassing the current plugin’s DoRequestL() function). +This is used for pre-intercepts.

  • +
  • KPluginMessageComplete indicates +that the request has been processed synchronously and should be passed up +to the previous plugin in the stack (bypassing the current plugin’s DoRequestL() function). +This is used for post-intercepts.

  • +

NewPluginConnL()

The +function NewPluginConnL() is +the default implementation and it returns KErrNotSupported. +Override this implementation to create a CFsPluginConn derived +object to enable direct communication between a client application and a plugin +using RPlugin. See Communicating +with plugins.

DoRequestL()

DoRequestL() is the main entry +point for messages intercepted by a plugin. Individual plugins are usually +single-threaded and must process requests in the order that they arrive. However, +the plugin framework is not single-threaded. While a plugin is handling a +request all other plugins are also able to handle requests. The drive thread +is also able to handle requests forwarded to it by plugins. DoRequestL() is +called in the context of the plugin’s main thread and must be implemented +to intercept file server requests in this context.

The current request +must have finished all processing before DoRequestL() has +completed. If a plugin has multiple threads and the request is handled in +a thread other than the main thread then the DoRequestL() function +must be blocked until the request has been processed. This is because when DoRequestL() exits, +the plugin framework forwards the message to the next plugin in the chain. +Unpredictable behaviour may occur if the plugin has not finished processing +a request before it is passed to the next plugin/file system.

Errors +returned by this function are propagated back to the client. If this function +leaves then the client thread panics. Note: Do not return from this +function until the request has been fully processed. This is because after +returning from this function the request is passed onto the next plugin in +the chain. This means that you cannot pass the request to a separate thread +and return immediately in order to implement a multi-threaded plugin.

KErrCompletion indicates +that all processing for this request has been completed by this plugin. Post-intercept +is then enabled and the flow of execution is up the plugin stack towards the +client, starting at the previous plugin.

When a plugin intercepts +a file read or file write request and does an early completion (i.e. returns KErrCompletion in pre-intercept) +then the plugin author should call TFsPluginRequest::SetSharePos() to +allow share position to be updated after early read/write completion.

TFsPluginRequest

The TFsPluginRequest class encapsulates +the intercepted file server request and is passed as a reference to the plugin's DoRequestL() function. TFsPluginRequest provides +APIs that extract request specific information such as:

    +
  • DriveNumber() - +returns the target drive number. The drive number is in the range of zero +to 25, which corresponds to drive letters A to Z,

  • +
  • Function() - +the type of request as defined in TFsMessage,

  • +
  • IsPostOperation() - +returns ETrue or EFalse to indicate if the +request being intercepted is in post-intercept mode (ETrue) +or pre-intercept.

  • +

TFsPluginRequest acts +as a utility class for plugins. This class has two main functions TFsPluginRequest::Read() and TFsPluginRequest::Write(), which +allow a plugin to read from and write to the message arguments of a request.

TFsPluginRequest::Read() has +various overloads for TInt, TUint, Tint64 and +descriptor data types, all of which take as their first argument a TF32ArgType object.

The TF32ArgType is an enumeration +which defines the type of data that is requested. For example, EPosition, ELength, EData for +getting the position, length and data arguments from the request. TF32ArgType is +defined as follows:

enum TF32ArgType + { + EPosition, + ELength, + EData, + ESize, + EName, + ENewName, + EEntry, + ETime, + ESetAtt, + EClearAtt, + EMode, + EAtt, + EAttMask, + EUid, + EEntryArray, + ENewPosition, + };

TFsPluginRequest::Write() only +has two overloads, both of these take descriptor types and the argument TF32ArgType. Many functions do +not use descriptor types, it will be necessary to package data for these inside +a descriptor.

The following provides an example of how to do this +for Entry:

TPckgC<TEntry> entryPckg(entry); + err = aRequest.Write(EEntry, entryPckg);

Sending internal requests +to the file server

The classes RFilePlugin, RDirPlugin and RFsPlugin, +defined in F32Plugin.h, are the classes that plugin authors +should use to send internal requests to the file server. The APIs for these +classes are mostly identical from their client side (RFile, RDir and RFs) +counter-parts.

Before a plugin can perform any requests on a file +it must first either perform an Open() or AdoptFromClient(). When an AdoptFromClient() is +performed the RFilePlugin instance opens the file associated +with the client request. Open() can be used to open the same +file (potentially with different parameters than those supplied by the client) +and it can be used to open an entirely different file.

RFilePlugin has +the following public functions:

class RFilePlugin : private RFile + { +public: + IMPORT_C RFilePlugin(TFsPluginRequest& aRequest, TBool aDirectToDrive = EFalse); + + // open a NEW file using same session as passed request + IMPORT_C TInt Open(const TDesC& aName,TUint aMode); + IMPORT_C TInt Create(const TDesC& aName,TUint aFileMode); + IMPORT_C TInt Replace(const TDesC& aName,TUint aFileMode); + IMPORT_C TInt Temp(const TDesC& aPath,TFileName& aName,TUint aFileMode); + + // re-open SAME file as client's request + IMPORT_C TInt AdoptFromClient(); + // Transfer the plugin's open file to the client + IMPORT_C TInt TransferToClient(); + + IMPORT_C void Close(); + + // RFile overloads + IMPORT_C TInt Read(TInt64 aPos,TDes8& aDes) const; + IMPORT_C TInt Read(TInt64 aPos,TDes8& aDes,TInt aLength) const; + IMPORT_C TInt Write(TInt64 aPos,const TDesC8& aDes); + IMPORT_C TInt Write(TInt64 aPos,const TDesC8& aDes,TInt aLength); + IMPORT_C TInt Lock(TInt64 aPos,TInt64 aLength) const; + IMPORT_C TInt UnLock(TInt64 aPos,TInt64 aLength) const; + IMPORT_C TInt Seek(TSeek aMode,TInt64& aPos) const; + IMPORT_C TInt Flush(); + IMPORT_C TInt Size(TInt64& aSize) const; + IMPORT_C TInt SetSize(TInt64 aSize); + IMPORT_C TInt Att(TUint& aAttValue) const; + IMPORT_C TInt SetAtt(TUint aSetAttMask,TUint aClearAttMask); + IMPORT_C TInt Modified(TTime& aTime) const; + IMPORT_C TInt SetModified(const TTime& aTime); + IMPORT_C TInt Set(const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask); + IMPORT_C TInt ChangeMode(TFileMode aNewMode); + IMPORT_C TInt Rename(const TDesC& aNewName); + ...

Registering a plugin to +intercept messages

The base class CFsPlugin, +has functions that allow a plugin to register to intercept specific types +of file server request. This is explained in more detail under Interception of file server requests.

RegisterIntercept()

The function RegisterIntercept() registers +a plugin to intercept a specified TFsMessage. +The second parameter of RegisterIntercept() allows plugin +authors to specify whether the intercept is processed before, after or both +before and after the request is processed by the drive thread. See TInterceptAtts.

UnregisterIntercept()

Un-register an intercept with UnregisterIntercept(). UnregisterIntercept() takes TFsMessage, which is the ID of +the message and TInterceptAtts, +which is the type of intercept that you no longer wish to intercept.

+
Loading and +mounting a plugin

A plugin must be loaded and mounted before it +can intercept requests.

Loading and unloading a +plugin

Before a plugin can be used by the file server the library +(.PXT) that contains the plugin needs to be loaded into +the file server process by the loader. Do this using the RFs::AddPlugin() function +defined in f32file.h.

AddPlugin() can +be called by any user side application with the relevant platform security capabilities.

Unload a plugin using the RFs::RemovePlugin() function +also defined in f32file.h.

Note: Refer +to the device manufacturer if you want to load plugins automatically at system +startup time.

Mounting and unmounting +a plugin

File Server plugins are mounted using the RFs::MountPlugin() function +defined in f32file.h. The plug in must have already been +loaded using RFs::AddPlugin().

There +are various overloads of the MountPlugin() function. Those +functions which do not take a drive parameter are mounted using KPluginAutoAttach.

Call RFs::DismountPlugin() to dismount +the file server plugin. Dismount the plugin when you no longer need it to +intercept file server requests.

Before a plugin can be dismounted +all resources owned by the plugin must be closed. A plugin can intercept the +request to dismount it and use this to free resources and close down cleanly. +If the plugin owns resources on behalf of a client (for example, a client +has a file open that is using the decompression plugin) then the plugin can +reject the request to dismount by returning one of the system wide error codes.

+
Communicating +with plugins

The file server provides a standard logical channel +based mechanism that enables a trusted application to communicate with a file +server plugin. For example, a virus scanning plugin can present a user interface +for the device user. Note: DiskAdmin capabilities +are required in order to load a plugin. See platform +security capabilities.

Data transfer

The class CFsPluginConnRequest is +an information container for asynchronous requests that the client application +wants performed. CFsPluginConnRequest also provides functions +that enable data to be transferred between the plugin and the application. +The following examples show how to use CFsPluginConnRequest.

User-side application

A +user-side application uses a class derived from RPlugin to +access the plugin. See plugin +side. The RPlugin class (defined in f32file.h) +provides various functions that must be overridden. The functions DoControl(), DoRequest() and DoCancel() are protected. Plugin authors must provide a public interface of their own +design in the derived class that communicates with the plugin using these +protected functions.

An RPlugin session is opened +by passing in the unique +position identifier of the plugin it wishes to communicate with. When +the file server receives the request it validates the capabilities of the +application before calling the plugin's NewPluginConnL() function. +The plugin must certify that it is expecting the client application before +creating the server side connection object.

Below is a basic example +of an RPlugin derived class:

class RMyPlugin : public RPlugin +{ +public: + inline TInt Enable(); + inline TInt Disable(); + }; + +inline TInt RMyPlugin::Enable() + { + return DoControl(EEnable); + } + +inline TInt RMyPlugin::Disable() + { + return DoControl(EDisable); + } + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus) const + { + RPlugin::DoRequest(aReqNo,aStatus); + } + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1) const + { + RPlugin::DoRequest(aReqNo,aStatus,a1); + } + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1,TDes8& a2) const + { + RPlugin::DoRequest(aReqNo,aStatus,a1,a2); + } + +TInt MyRPlugin::DoControl(TInt aFunction) const + { + return RPlugin::DoControl(aFunction); + } + +

This is used in the following way:

Tint r = KErrNone +r = TheFs.AddPlugin(_L("MyPlugin")); +r = TheFs.MountPlugin(_L("MyPlugin"),KPluginSupportAllDrives); +User::LeaveIfError(r); + +RMyPlugin thePlugin; +r = thePlugin.Open(TheFs, KMyPluginUniquePos); +User::LeaveIfError(r); +r = thePlugin.Enable(); +User::LeaveIfError(r); +... +//Perform communication with plugin here +... +r = thePlugin.Disable(); +User::LeaveIfError(r); +thePlugin.Close(); class RMyPlugin : public RPlugin + { +public: + inline TInt Enable(); + inline TInt Disable(); + }; + +inline TInt RMyPlugin::Enable() + { + return DoControl(EEnable); + } + +inline TInt RMyPlugin::Disable() + { + return DoControl(EDisable); + } + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus) const + { + RPlugin::DoRequest(aReqNo,aStatus); + } + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1) const + { + RPlugin::DoRequest(aReqNo,aStatus,a1); + } + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1,TDes8& a2) const + { + RPlugin::DoRequest(aReqNo,aStatus,a1,a2); + } + +TInt MyRPlugin::DoControl(TInt aFunction) const + { + return RPlugin::DoControl(aFunction); + } + +etc.. +} +

This is used in the following way:

Tint r = KErrNone +r = TheFs.AddPlugin(_L("MyPlugin")); +r = TheFs.MountPlugin(_L("MyPlugin"),KPluginSupportAllDrives); +User::LeaveIfError(r); + +RMyPlugin thePlugin; +r = thePlugin.Open(TheFs, KMyPluginUniquePos); +User::LeaveIfError(r); +r = thePlugin.Enable(); +User::LeaveIfError(r); +... +//Perform communication with plugin here +... +r = thePlugin.Disable(); +User::LeaveIfError(r); +thePlugin.Close();

Plugin side

This +is the plugin side of the communication. This must be implemented in order +to communicate with the application side class RPlugin above. +The plugin side is a class derived from the CFsPluginConn class. +The plugin’s NewPluginConnL() function +is called from the file server when RPlugin::Open() is +called by the client.

Synchronous (DoControl()) +and asynchronous (DoRequest()) +requests sent from the RPlugin class +are routed directly to the associated plugin's CFsPluginConn derived +class. The following code shows a basic implementation:

class CMyPluginConn : public CFsPluginConn + { + virtual TInt DoControl(CFsPluginConnRequest& aRequest); + virtual void DoRequest(CFsPluginConnRequest& aRequest); + virtual void DoCancel(TInt aReqMask); + }; + +// From the CFsPlugin derived class +CFsPluginConn* CMyPlugin::NewPluginConnL() + { + CMyPluginConn* thePluginConn = new(ELeave) CMyPluginConn(); + return thePluginConn; + } + +TInt CMyPluginConn::DoControl(CFsPluginConnRequest& aRequest) + { + TInt r = KErrNotSupported; + CMyPlugin& myPlugin = *(CMyPlugin*)Plugin(); + switch(aRequest.Function()) + { + case RMyPlugin::EEnable: + r = myPlugin.Enable(); + break; + case RLoggerConn::EDisable: + r = myPlugin.Disable(); + break; + default: + break; + } + return r; + } + +void CMyPluginConn::DoRequest(CFsPluginConnRequest& aRequest) + { + return KErrNotSupported; + } + +void DoCancel(TInt aReqMask) + { + // Not required as no asynchronous request support + }
\ No newline at end of file